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
{
///
/// 文件系统读写
///
private FileSystemInfoRW mFileSystemInfo = new FileSystemInfoRW();
private bool hasinit;
public bool HasInit
{
get
{
return hasinit;
}
set
{
if (hasinit != value)
{
hasinit = value;
NotifyPropertyChanged("HasInit");
}
}
}
#region 根路径
///
/// 根路径
///
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;
}
///
/// 根文件结构
///
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();
}
}
}
///
/// 获取本地路径
///
///
///
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();
}
///
/// 发起者,用于关闭都为该发起者建立的通信
///
public object sponsor;
}
public class ReadInfoEventArgs : FileBusEventArgs
{
public string mPath;
}
public class RWEventArgs : FileBusEventArgs
{
///
/// 路径
///
public string mPath;
///
/// 文件 or 文件夹
///
public FileAttributes mFileAttributes;
///
/// 总文件大小
///
public UInt32 mFileSize;
///
/// 包大小
///
public UInt16 mPackageSize = 0x3500;//OBJ 会把大包分为N个小包,小包为0x4000
///
/// 当前传输的包
///
public UInt16 mPackageNo = 0;
///
/// 远端,全局唯一标识
///
public string guid_remote;
///
/// 本地,全局唯一标识
///
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 mEventArgs = new List();
#endregion
#region 发送
private void Send(Message message)
{
Send(message.ToBytes());
}
#endregion
#region 功能
private delegate void FuncHandle(Message message);
Dictionary m_service =
new Dictionary();
///
/// 功能号分发
///
///
///
///
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;
}
///
/// 放于 OnPoll 中,处理所有任务
///
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 发起者已经不存在,关闭它所建立的通信
///
/// 发起者,已经不存在,关闭它所建立的通信
///
/// 全局唯一标示,由GetMagic()产生
public void FreeComm(object sponsor)
{
List eal = new List();
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
}
}