using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.Net; using System.Xml; using System.Text.RegularExpressions; using System.ComponentModel; using FObjBase; using System.Xml.Serialization; namespace OBJ_FileBus { public class Client : INotifyPropertyChanged { /// <summary> /// 文件系统读写 /// </summary> private FileSystemInfoRW mFileSystemInfo = new FileSystemInfoRW(); private bool hasinit; public bool HasInit { get { return hasinit; } set { if (hasinit != value) { hasinit = value; NotifyPropertyChanged("HasInit"); } } } #region 根路径 /// <summary> /// 根路径 /// </summary> private string m_rootPath; public string RootPath { set { SetRootPath(value); } get { return m_rootPath; } } private bool SetRootPath(string path) { m_rootPath = path; if (!Directory.Exists(m_rootPath)) { try { Directory.CreateDirectory(m_rootPath); } catch { return false; } } Load(); return true; } /// <summary> /// 根文件结构 /// </summary> private FileElement mRootFileElement = new FileElement(); public FileElement Root { get { return mRootFileElement; } } #endregion private void ClearAllEventArgs() { //关掉所有进度 foreach (FileBusEventArgs e in mEventArgs) { e.NoConnect(); } mEventArgs.Clear(); } public Client(string rootPath) { RootPath = @"filebus\"+rootPath; m_service.Add("readinfo", new FuncHandle(CBF_ReadInfo)); m_service.Add("read", new FuncHandle(CBF_Read)); m_service.Add("write", new FuncHandle(CBF_Write)); m_service.Add("addpush", new FuncHandle(CBF_PushRegist)); m_service.Add("rmpush", new FuncHandle(CBF_PushRegist)); m_service.Add("rm", new FuncHandle(CBF_Del)); m_service.Add("push", new FuncHandle(CBF_Push)); PropertyChanged += new PropertyChangedEventHandler(Client_PropertyChanged); PollModule.Current.Poll_Config(PollModule.POLL_CONFIG.ADD, new PollModule.PollHandler(DisposeEvent), TimeSpan.FromMilliseconds(1)); } void Client_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == "HasInit") { if (!HasInit) { ClearAllEventArgs(); } } } /// <summary> /// 获取本地路径 /// </summary> /// <param name="path"></param> /// <returns></returns> public string GetAbsPath(string path) { if (path.StartsWith(@"\")) { return RootPath + path; } else { return RootPath + @"\" + path; } } private string GetFileInfoPath() { return RootPath + @".fileinfo.xml"; } private void Load() { string filePath = GetFileInfoPath(); mRootFileElement = new FileElement(FileAttributes.Directory, @"\"); Root.Load(filePath); Root.BeChanged = false; } private void Save() { if (Root.BeChanged) { string filePath = GetFileInfoPath(); Root.Save(filePath); Root.BeChanged = false; } } public delegate void SendMessageEventHandler(byte[] msg); public event SendMessageEventHandler SendMessageEvent; private void Send(byte[] msg) { if (SendMessageEvent != null) SendMessageEvent(msg); } #region FileBusEventArgs public class FileBusEventArgs : EventArgs { public enum STATE { //客户端自定义 WAIT_SEND,//等待执行 WAIT_REPLY,//等待回复 IDLE//已经处理完 } public STATE mState = STATE.WAIT_SEND;//状态 public ERRNO mErrno;//错误代码 public int mWaitCnt = 0;//等待次数 public EventHandler handler;//事件 public void Handler() { if (handler != null)handler(mClient, this); } public object mClient; public void NoConnect() { if (mState != STATE.IDLE) { mState = STATE.IDLE; mErrno = ERRNO.NOCONNECT; Handler(); } } public override string ToString() { return this.GetType().ToString() + " " + mErrno.ToString() + " " + mState.ToString(); } /// <summary> /// 发起者,用于关闭都为该发起者建立的通信 /// </summary> public object sponsor; } public class ReadInfoEventArgs : FileBusEventArgs { public string mPath; } public class RWEventArgs : FileBusEventArgs { /// <summary> /// 路径 /// </summary> public string mPath; /// <summary> /// 文件 or 文件夹 /// </summary> public FileAttributes mFileAttributes; /// <summary> /// 总文件大小 /// </summary> public UInt32 mFileSize; /// <summary> /// 包大小 /// </summary> public UInt16 mPackageSize = 0x3500;//OBJ 会把大包分为N个小包,小包为0x4000 /// <summary> /// 当前传输的包 /// </summary> public UInt16 mPackageNo = 0; /// <summary> /// 远端,全局唯一标识 /// </summary> public string guid_remote; /// <summary> /// 本地,全局唯一标识 /// </summary> public string guid_local; public string GetFilePath(string path) { if (mFileAttributes == FileAttributes.Normal) return path; else return path + @".fileinfo.xml"; } } public class ReadEventArgs : RWEventArgs { } public class WriteEventArgs : RWEventArgs { } public class PushRegistEventArgs : FileBusEventArgs { public string mPath;//路径 public bool bIsAdd;//是添加 } public class PushEventArgs : FileBusEventArgs { public string mPath;//路径 } public class DelEventArgs : FileBusEventArgs { public string mPath;//路径 } //事件运行列表,运行完,就会从此列表删除 List<FileBusEventArgs> mEventArgs = new List<FileBusEventArgs>(); #endregion #region 发送 private void Send(Message message) { Send(message.ToBytes()); } #endregion #region 功能 private delegate void FuncHandle(Message message); Dictionary<string, FuncHandle> m_service = new Dictionary<string, FuncHandle>(); /// <summary> /// 功能号分发 /// </summary> /// <param name="ADUBuffer"></param> /// <param name="offset"></param> /// <returns></returns> public void RequestService(byte[] order_bytes) { //获取指令 //转换为xml 解码 Message message = Message.Bytes2Message(order_bytes); //获取指令 string order = message.order; DateTime dt2 = DateTime.Now; if (m_service.ContainsKey(order)) { m_service[order](message); } DateTime dt1 = DateTime.Now; Console.WriteLine("Client RequestService " + (dt1 - dt2).TotalMilliseconds.ToString() + " " + (dt1 - dtlast).TotalMilliseconds.ToString()); dtlast = dt1; } /// <summary> /// 放于 OnPoll 中,处理所有任务 /// </summary> private void DisposeEvent() { var waitcnt_list = from _eventargs in mEventArgs where _eventargs.mState == FileBusEventArgs.STATE.WAIT_SEND select _eventargs.mWaitCnt; if (waitcnt_list.Count() == 0) return; var waitcnt_max = waitcnt_list.Max(); var eventargs = (from _eventargs in mEventArgs where (_eventargs.mWaitCnt == waitcnt_max) && (_eventargs.mState == FileBusEventArgs.STATE.WAIT_SEND) select _eventargs).First(); foreach (FileBusEventArgs eargs in mEventArgs) { eargs.mWaitCnt++; } eventargs.mWaitCnt = 0; eventargs.mState = FileBusEventArgs.STATE.WAIT_REPLY; if (eventargs is PushRegistEventArgs) { PushRegistEventArgs e = eventargs as PushRegistEventArgs; Send(new Message() { order = (e.bIsAdd) ? "addpush" : "rmpush", args = new PushParamMessageArgs() { path = e.mPath } }); } else if (eventargs is DelEventArgs) { DelEventArgs e = eventargs as DelEventArgs; Send(new Message() { order = "rm", args = new FileOptMessageArgs() { path = e.mPath } }); } else if (eventargs is ReadInfoEventArgs) { ReadInfoEventArgs e = eventargs as ReadInfoEventArgs; Send(new Message() { order = "readinfo", args = new FileOptMessageArgs() { path = e.mPath } }); } else if (eventargs is ReadEventArgs) { ReadEventArgs e = eventargs as ReadEventArgs; Send(new Message() { order = "read", args = new ReadParamMessageArgs() { path = e.mPath, guid = e.guid_remote, package_size = e.mPackageSize, package_no = e.mPackageNo } }); } else if (eventargs is WriteEventArgs) { WriteEventArgs e = eventargs as WriteEventArgs; byte[] filecontent; mFileSystemInfo.GetContent( GetAbsPath(e.mPath), ref e.guid_local, e.mPackageNo, e.mPackageSize, out filecontent, out e.mFileSize); Send(new Message() { order = "write", args = new WriteParamMessageArgs() { path = e.mPath, guid = e.guid_remote, fileattr = FileAttributes.Normal, filesize = e.mFileSize, package_size = e.mPackageSize, package_no = e.mPackageNo, filecontent = filecontent } }); } } #region 读取文件或文件夹 信息,直接更新根文件结构 public ReadInfoEventArgs ReadInfo(string path, object sponsor, EventHandler handler) { ReadInfoEventArgs eventargs = new ReadInfoEventArgs() { mPath = path, handler = handler, mClient = this, sponsor = sponsor }; if (HasInit) mEventArgs.Add(eventargs); else eventargs.NoConnect(); return eventargs; } private void CBF_ReadInfo(Message message) { ReadInfoRetMessageArgs args = message.args as ReadInfoRetMessageArgs; ERRNO errno = args.errno; string path = args.path; ReadInfoEventArgs ea; { var eal = from _eventargs in mEventArgs where (_eventargs is ReadInfoEventArgs) && ((_eventargs as ReadInfoEventArgs).mPath == path) && (_eventargs.mState == FileBusEventArgs.STATE.WAIT_REPLY) select _eventargs; if (eal.Count() == 0) { //出错,收了不该收到的 //throw new Exception("出错,收了不该收到的"); return; } ea = eal.First() as ReadInfoEventArgs; } ea.mState = FileBusEventArgs.STATE.IDLE; ea.mErrno = errno; if (errno == ERRNO.OK) { FileElement fe = new FileElement( args.fileattr, Path.GetFileName(path)) { LastWriteTime = args.lastwritetime, CreateTime = args.createtime, Size = args.size }; //TODO //只更新一个,不更新内容 Root.ToUpdate(path, fe, false); Save(); } else if (errno == ERRNO.NOEXIST) { } ea.Handler(); mEventArgs.Remove(ea); } #endregion #region 读取 文件夹 或 文件 内容,直接更新根文件结构 和 本地文件 public ReadEventArgs Read(string path, object sponsor, EventHandler handler) { ReadEventArgs eventargs = new ReadEventArgs() { mPath = path, handler = handler, mClient = this, sponsor = sponsor }; if (HasInit) mEventArgs.Add(eventargs); else eventargs.NoConnect(); return eventargs; } DateTime dtlast = DateTime.Now; private void CBF_Read(Message message) { ReadRetMessageArgs args = message.args as ReadRetMessageArgs; ERRNO errno = args.errno; string path = args.path; ReadEventArgs ea; { var eal = from _eventargs in mEventArgs where (_eventargs is ReadEventArgs) && ((_eventargs as ReadEventArgs).mPath == path) && (_eventargs.mState == FileBusEventArgs.STATE.WAIT_REPLY) select _eventargs; if (eal.Count() == 0) { //出错,收了不该收到的 //throw new Exception("出错,收了不该收到的"); return; } ea = eal.First() as ReadEventArgs; } ea.mState = FileBusEventArgs.STATE.IDLE; ea.mErrno = errno; ea.mFileAttributes = args.fileattr; ea.mFileSize = args.filesize; ea.mPackageNo = args.package_no; ea.mPackageSize = args.package_size; ea.guid_remote = args.guid; if ((errno == ERRNO.DOING) || (errno == ERRNO.OK)) { //当为文件时,p就是path //当为文件夹时,p = path+“.fileinfo.xml” string p = ea.GetFilePath(GetAbsPath(path)); FileSystemInfoRW.OptFileContentResult ret = mFileSystemInfo.SetFileContent( p, ref ea.guid_local, args.filesize, args.package_size, args.package_no, args.filecontent); if(errno == ERRNO.DOING) { FileElement fe = new FileElement(args.fileattr, Path.GetFileName(path)) { CreateTime = args.createtime, LastWriteTime = args.lastwritetime, Size = (int)args.filesize, DownloadSize = args.package_size * (args.package_no+1) }; Root.ToUpdate(path, fe, false); //还要继续读 ea.mPackageNo++; ea.mState = FileBusEventArgs.STATE.WAIT_SEND; } else { FileElement fe; if (args.fileattr == FileAttributes.Directory) { fe = new FileElement(); fe.Load(p); File.Delete(p); fe.Size = (int)args.filesize; fe.DownloadSize = (int)args.filesize; } else { fe = new FileElement(FileAttributes.Normal, Path.GetFileName(path)) { CreateTime = args.createtime, LastWriteTime = args.lastwritetime, Size = (int)args.filesize, DownloadSize = (int)args.filesize }; } //把fe更新到Root中 //所有的内容都会被替换 fe = Root.ToUpdate(path, fe, true); Root.SetUpdateFlag(path, false); Save(); DelNoHereFiles(fe); } } else if (errno == ERRNO.NOEXIST) { } ea.Handler(); if (ea.mState == FileBusEventArgs.STATE.IDLE) mEventArgs.Remove(ea); } #endregion #region 写入文件 public WriteEventArgs Write(string path, object sponsor, EventHandler handler) { WriteEventArgs eventargs = new WriteEventArgs() { mPath = path, handler = handler, mClient = this, sponsor = sponsor }; if (HasInit) mEventArgs.Add(eventargs); else eventargs.NoConnect(); return eventargs; } private void CBF_Write(Message message) { WriteRetMessageArgs args = message.args as WriteRetMessageArgs; ERRNO errno = args.errno; string path = args.path; WriteEventArgs ea; { var eal = from _eventargs in mEventArgs where (_eventargs is WriteEventArgs) && ((_eventargs as WriteEventArgs).mPath == path) && (_eventargs.mState == FileBusEventArgs.STATE.WAIT_REPLY) select _eventargs; if (eal.Count() == 0) { //出错,收了不该收到的 //throw new Exception("出错,收了不该收到的"); return; } ea = eal.First() as WriteEventArgs; } ea.mState = FileBusEventArgs.STATE.IDLE; ea.mErrno = errno; ea.guid_remote = args.guid; if (errno == ERRNO.DOING) { FileElement fe = new FileElement( args.fileattr, Path.GetFileName(path)) { LastWriteTime = args.lastwritetime, CreateTime = args.createtime, Size = (int)ea.mFileSize, DownloadSize = (ea.mPackageNo+1) * ea.mPackageSize }; //只更新一个,不更新内容 Root.ToUpdate(path, fe, false); ea.mPackageNo++; ea.mState = FileBusEventArgs.STATE.WAIT_SEND; } else if (errno == ERRNO.OK) { FileElement fe = new FileElement(args.fileattr, Path.GetFileName(path)) { LastWriteTime = args.lastwritetime, CreateTime = args.createtime, Size = (int)ea.mFileSize, DownloadSize = (int)ea.mFileSize }; //只更新一个,不更新内容 Root.ToUpdate(path, fe, false); Root.SetUpdateFlag(path, false); Save(); } else if (errno == ERRNO.ERROR) { } ea.Handler(); if (ea.mState == FileBusEventArgs.STATE.IDLE) mEventArgs.Remove(ea); } #endregion #region 删除文件或文件夹 public DelEventArgs Del(string path, object sponsor, EventHandler handler) { DelEventArgs eventargs = new DelEventArgs() { mPath = path, handler = handler, mClient = this, sponsor = sponsor }; if (HasInit) mEventArgs.Add(eventargs); else eventargs.NoConnect(); return eventargs; } private void CBF_Del(Message message) { //errno 错误代码 //order 指令字符串 //如: //3 rm sysparam.ini RetMessageArgs args = message.args as RetMessageArgs; ERRNO errno = args.errno; string path = args.path; DelEventArgs ea; { var eal = from _eventargs in mEventArgs where (_eventargs is DelEventArgs) && ((_eventargs as DelEventArgs).mPath == path) && (_eventargs.mState == FileBusEventArgs.STATE.WAIT_REPLY) select _eventargs; if (eal.Count() == 0) { //出错,收了不该收到的 //throw new Exception("CBF_Del 出错,收了不该收到的 path" + path); return; } ea = eal.First() as DelEventArgs; } ea.mState = FileBusEventArgs.STATE.IDLE; ea.mErrno = errno; if (errno == ERRNO.OK) { } else if (errno == ERRNO.NOEXIST) { } ea.Handler(); mEventArgs.Remove(ea); } #endregion #region 推送注册 public PushRegistEventArgs PushRegist(string path, object sponsor, bool isAdd, EventHandler handler) { PushRegistEventArgs eventargs = new PushRegistEventArgs() { mPath = path, handler = handler, mClient = this, bIsAdd = isAdd, sponsor = sponsor }; if (HasInit) mEventArgs.Add(eventargs); else eventargs.NoConnect(); return eventargs; } private void CBF_PushRegist(Message message) { //errno = 0 正常 //"addpush" //注册的数量 PushRetMessageArgs args = message.args as PushRetMessageArgs; ERRNO errno = args.errno; string order = message.order; bool isAdd = false; if (order == "addpush") isAdd = true; string path = args.path; PushRegistEventArgs ea; { var eal = from _eventargs in mEventArgs where (_eventargs is PushRegistEventArgs) && ((_eventargs as PushRegistEventArgs).bIsAdd == isAdd) && ((_eventargs as PushRegistEventArgs).mPath.CompareTo(path)==0) && (_eventargs.mState == FileBusEventArgs.STATE.WAIT_REPLY) select _eventargs; if (eal.Count() == 0) { //出错,收了不该收到的 //throw new Exception("出错,收了不该收到的"); if (isAdd) { //本地没有这个推送请求,关闭服务器的推送服务 PushRegist(path, null, false, null); } return; } ea = eal.First() as PushRegistEventArgs; } ea.mState = FileBusEventArgs.STATE.IDLE; ea.mErrno = errno; if (errno == ERRNO.OK) { } else if (errno == ERRNO.NOEXIST) { } ea.Handler(); mEventArgs.Remove(ea); if (ea.bIsAdd) { PushEventArgs pushea = new PushEventArgs(); pushea.mClient = ea.mClient; pushea.mState = FileBusEventArgs.STATE.WAIT_REPLY; pushea.mPath = ea.mPath; pushea.mErrno = ERRNO.PUSH; pushea.handler = ea.handler; pushea.sponsor = ea.sponsor; mEventArgs.Add(pushea); } else { var eal = from pushea in mEventArgs where (pushea is PushEventArgs) && ((pushea as PushEventArgs).mPath == ea.mPath) select pushea; if (eal.Count() > 0) { mEventArgs.Remove(eal.First()); } else { //异常出错 //throw new Exception("不能找到PushEventArgs " + ea.mPath); } } } #endregion #region 发起者已经不存在,关闭它所建立的通信 /// <summary> /// 发起者,已经不存在,关闭它所建立的通信 /// </summary> /// <param name="magic">全局唯一标示,由GetMagic()产生</param> public void FreeComm(object sponsor) { List<FileBusEventArgs> eal = new List<FileBusEventArgs>(); eal.AddRange(from _eventargs in mEventArgs where (_eventargs.sponsor == sponsor) select _eventargs); //删除所有 foreach (var ea in eal) { if (ea is PushEventArgs) //取消注册 { PushEventArgs ea_push = ea as PushEventArgs; PushRegist(ea_push.mPath, null, false, null); } ea.mState = FileBusEventArgs.STATE.IDLE; mEventArgs.Remove(ea); } } #endregion #endregion private void CBF_Push(Message message) { PushMessageArgs args = message.args as PushMessageArgs; string path = args.path; var eal = from _eventargs in mEventArgs where (_eventargs is PushEventArgs) && ((_eventargs as PushEventArgs).mPath == path) select _eventargs; if (eal.Count() == 0) { //出错,收了不该收到的 //throw new Exception("出错,收了不该收到的 path=" + path); //不需要这个推送,关闭服务的推送服务 PushRegist(path, null, false, null); return; } PushEventArgs ea = eal.First() as PushEventArgs; FileElement fe = new FileElement(args.fileattr, Path.GetFileName(path)) { LastWriteTime = args.lastwritetime, CreateTime = args.createtime, Size = args.size }; //只更新一个,不更新内容 Root.ToUpdate(path, fe, false); Save(); ea.Handler(); } private void DelNoHereFiles(FileElement fe) { if (fe.FileAttr == FileAttributes.Directory) { string path=GetAbsPath(fe.FullName); if (Directory.Exists(path)) { string[] filenames = Directory.GetFiles(path); foreach (string filename in filenames) { var cnt = (from _fe in fe.child where _fe.Name.CompareTo(Path.GetFileName(filename)) == 0 select _fe).Count(); if (cnt == 0) { File.Delete(filename); } } filenames = Directory.GetDirectories(path); foreach (string filename in filenames) { var cnt = (from _fe in fe.child where _fe.Name.CompareTo(Path.GetFileName(filename)) == 0 select _fe).Count(); if (cnt == 0) { Directory.Delete(filename); } } } } } #region INotifyPropertyChanged 成员 protected void NotifyPropertyChanged(string propertyName) { if (PropertyChanged != null) PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName)); } public event PropertyChangedEventHandler PropertyChanged; #endregion } }