PageRenderTime 54ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/source/Core/MessageImpl.cs

#
C# | 561 lines | 443 code | 81 blank | 37 comment | 62 complexity | 0d3c488b9a27fe566ad7881851e6c4c0 MD5 | raw file
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Web;
  5. using System.Configuration;
  6. using System.Web.Configuration;
  7. using System.Data;
  8. using System.Text;
  9. using System.Text.RegularExpressions;
  10. using System.Xml;
  11. using System.Threading;
  12. using Microsoft.JScript;
  13. using System.Reflection;
  14. using Core.IO;
  15. namespace Core
  16. {
  17. /// <summary>
  18. ///MessageManagement 的摘要说明
  19. /// </summary>
  20. public class MessageImpl
  21. {
  22. static MessageImpl m_Instance = new MessageImpl();
  23. static public MessageImpl Instance
  24. {
  25. get { return m_Instance; }
  26. }
  27. static MessageImpl()
  28. {
  29. Instance.Initialize(HttpContext.Current);
  30. }
  31. private MessageImpl()
  32. {
  33. m_Timer = new Timer(this.TimerProc);
  34. m_Timer.Change(0, 2 * 60 * 1000);
  35. }
  36. Timer m_Timer = null;
  37. private void TimerProc(object state)
  38. {
  39. WriteCache();
  40. }
  41. Object m_Lock = new Object();
  42. Int64 m_MaxKey = 1;
  43. DateTime m_MaxCreatedTime = DateTime.Now;
  44. # if DEBUG
  45. const Int32 MAX_CACHE_COUNT = 4;
  46. # else
  47. const Int32 MAX_CACHE_COUNT = 1024;
  48. # endif
  49. IMessageStorage m_IMessageStorage = null;
  50. public void Initialize(HttpContext context)
  51. {
  52. lock (m_Lock)
  53. {
  54. Configuration config = WebConfigurationManager.OpenWebConfiguration(
  55. HttpContext.Current.Request.ApplicationPath == "/" ? "/Lesktop" : HttpContext.Current.Request.ApplicationPath + "/Lesktop"
  56. );
  57. string accStorage = config.AppSettings.Settings["MessageStorageImpl"].Value;
  58. String[] accStorageInfo = accStorage.Split(new char[] { ' ' });
  59. Type type = Assembly.Load(accStorageInfo[0]).GetType(accStorageInfo[1]);
  60. ConstructorInfo ctor = type.GetConstructor(new Type[] { });
  61. m_IMessageStorage = ctor.Invoke(new object[] { }) as IMessageStorage;
  62. m_MaxKey = m_IMessageStorage.GetMaxKey();
  63. m_MaxCreatedTime = m_IMessageStorage.GetCreatedTime();
  64. }
  65. }
  66. public void Dispose()
  67. {
  68. }
  69. public List<Message> FindInDatabase(String receiver, String sender, Nullable<DateTime> from)
  70. {
  71. lock (m_Lock)
  72. {
  73. return m_IMessageStorage.Find(
  74. receiver == "*" ? 0 : AccountImpl.Instance.GetUserInfo(receiver).ID,
  75. sender == "*" ? 0 : AccountImpl.Instance.GetUserInfo(sender).ID,
  76. from
  77. );
  78. }
  79. }
  80. /// <summary>
  81. /// 插入新的消息,插入消息后将查询m_Listeners中是否有符合条件的监听器,如存在,同时将消息发送出去
  82. /// </summary>
  83. public Message NewMessage(String receiver, String sender, String content, Hashtable data)
  84. {
  85. lock (m_Lock)
  86. {
  87. Int64 key = ++m_MaxKey;
  88. content = HtmlUtil.ReplaceHtml(content);
  89. MsgAccessoryEval eval = new MsgAccessoryEval(key, receiver, sender, data);
  90. Regex reg = new Regex("{Accessory [^\f\n\r\t\v<>]+}");
  91. content = reg.Replace(content, eval.Replace);
  92. Message message = new Message(
  93. AccountImpl.Instance.GetUserInfo(sender),
  94. AccountImpl.Instance.GetUserInfo(receiver),
  95. content, new DateTime((DateTime.Now.Ticks / 10000) * 10000), key
  96. );
  97. List<Message> messages = new List<Message>();
  98. messages.Add(message);
  99. if (AccountImpl.Instance.GetUserInfo(receiver).Type == 0)
  100. {
  101. if (SessionManagement.Instance.IsOnline(receiver))
  102. {
  103. try
  104. {
  105. AccountState state = SessionManagement.Instance.GetAccountState(receiver);
  106. Hashtable config = state.GetConfig("message.conf");
  107. lock (config)
  108. {
  109. DateTime lrt = (DateTime)config["LastReceivedTime"];
  110. if (lrt < message.CreatedTime) config["LastReceivedTime"] = message.CreatedTime;
  111. }
  112. string cmdData = Utility.RenderHashJson(
  113. "Peer", sender,
  114. "Message", message
  115. );
  116. SessionManagement.Instance.Send(receiver, "GLOBAL:IM_MESSAGE_NOTIFY", cmdData);
  117. }
  118. catch
  119. {
  120. }
  121. }
  122. }
  123. else
  124. {
  125. AccountInfo groupInfo = AccountImpl.Instance.GetUserInfo(receiver);
  126. AccountInfo senderInfo = AccountImpl.Instance.GetUserInfo(sender);
  127. foreach (string member in groupInfo.Friends)
  128. {
  129. try
  130. {
  131. AccountInfo memberInfo = AccountImpl.Instance.GetUserInfo(member);
  132. if (senderInfo.Name.ToLower() != "administrator" && memberInfo.ID == senderInfo.ID) continue;
  133. if (SessionManagement.Instance.IsOnline(member))
  134. {
  135. AccountState state = SessionManagement.Instance.GetAccountState(memberInfo.Name);
  136. Hashtable config = state.GetConfig("message.conf");
  137. lock (config)
  138. {
  139. DateTime lrt = (DateTime)config["LastReceivedTime"];
  140. if (lrt < message.CreatedTime) config["LastReceivedTime"] = message.CreatedTime;
  141. }
  142. string cmdData = Utility.RenderHashJson(
  143. "Peer", groupInfo.Name,
  144. "Message", message
  145. );
  146. SessionManagement.Instance.Send(member, "GLOBAL:IM_MESSAGE_NOTIFY", cmdData);
  147. }
  148. }
  149. catch
  150. {
  151. }
  152. }
  153. }
  154. MessageCacheManagement.Instance.Insert(receiver, message);
  155. if (MessageCacheManagement.Instance.Count >= MAX_CACHE_COUNT)
  156. {
  157. WriteCache();
  158. }
  159. return message;
  160. }
  161. }
  162. public void WriteCache()
  163. {
  164. if (MessageCacheManagement.Instance.Count > 0)
  165. {
  166. List<Message> cacheMsgs = MessageCacheManagement.Instance.GetAll();
  167. m_IMessageStorage.Write(cacheMsgs);
  168. MessageCacheManagement.Instance.Clear();
  169. }
  170. }
  171. public List<Message> FindHistory(String receiver, String sender, DateTime from, DateTime to)
  172. {
  173. return m_IMessageStorage.FindHistory(
  174. AccountImpl.Instance.GetUserInfo(receiver).ID,
  175. AccountImpl.Instance.GetUserInfo(sender).ID,
  176. from, to
  177. );
  178. }
  179. /// <summary>
  180. /// 添加消息监听器,如果查找到符合监听器条件的消息,返回false,此时不会添加监听器
  181. /// 如果没有查找到符合监听器条件的消息,返回true,此时监听器将被添加到m_Listeners中
  182. /// </summary>
  183. public List<Message> Find(String receiver, String sender, Nullable<DateTime> from)
  184. {
  185. lock (m_Lock)
  186. {
  187. //获取用户receiver缓存的消息的最小发送时间
  188. Nullable<DateTime> min = MessageCacheManagement.Instance.GetMinCreatedTime(receiver);
  189. List<Message> messages = new List<Message>();
  190. //当from >= 缓存在内存中的消息的最小时间时,不必查询数据库
  191. if (min == null || from == null || from.Value < min.Value)
  192. {
  193. //查询数据库
  194. messages.AddRange(FindInDatabase(receiver, sender, from));
  195. if (AccountImpl.Instance.GetUserInfo(receiver).Type == 0)
  196. {
  197. messages.AddRange(FindInDatabase(sender, receiver, from));
  198. }
  199. }
  200. //在缓存中查询
  201. messages.AddRange(MessageCacheManagement.Instance.Find(receiver, sender, from.Value));
  202. if (AccountImpl.Instance.GetUserInfo(receiver).Type == 0)
  203. {
  204. messages.AddRange(MessageCacheManagement.Instance.Find(sender, receiver, from.Value));
  205. }
  206. return messages;
  207. }
  208. }
  209. }
  210. public class MessageCacheManagement
  211. {
  212. static MessageCacheManagement m_Instance = new MessageCacheManagement();
  213. static public MessageCacheManagement Instance
  214. {
  215. get { return m_Instance; }
  216. }
  217. private MessageCacheManagement()
  218. {
  219. }
  220. Int32 m_Count = 0;
  221. Hashtable m_Cache = new Hashtable();
  222. List<Message> GetUserMessageCache(String user)
  223. {
  224. if (!m_Cache.ContainsKey(user))
  225. {
  226. m_Cache.Add(user, new List<Message>());
  227. }
  228. return m_Cache[user] as List<Message>;
  229. }
  230. /// <summary>
  231. /// 清除缓存
  232. /// </summary>
  233. public void Clear()
  234. {
  235. lock (m_Cache)
  236. {
  237. List<Message> msgs = new List<Message>();
  238. foreach (DictionaryEntry ent in m_Cache)
  239. {
  240. (ent.Value as List<Message>).Clear();
  241. }
  242. m_Count = 0;
  243. }
  244. }
  245. /// <summary>
  246. /// 获取所有缓存的消息
  247. /// </summary>
  248. /// <returns></returns>
  249. public List<Message> GetAll()
  250. {
  251. lock (m_Cache)
  252. {
  253. List<Message> msgs = new List<Message>();
  254. foreach (DictionaryEntry ent in m_Cache)
  255. {
  256. foreach (Message msg in ent.Value as List<Message>)
  257. {
  258. msgs.Add(msg);
  259. }
  260. }
  261. return msgs;
  262. }
  263. }
  264. /// <summary>
  265. /// 获取某一用户缓存的消息的最小时间
  266. /// </summary>
  267. public Nullable<DateTime> GetMinCreatedTime(string user)
  268. {
  269. lock (m_Cache)
  270. {
  271. List<Message> userMsgs = GetUserMessageCache(user);
  272. return userMsgs.Count == 0 ? null : new Nullable<DateTime>(userMsgs[0].CreatedTime);
  273. }
  274. }
  275. /// <summary>
  276. /// 在缓存中插入一条消息
  277. /// </summary>
  278. /// <param name="user"></param>
  279. /// <param name="msg"></param>
  280. public void Insert(String user, Message msg)
  281. {
  282. List<Message> userMsgs = null;
  283. lock (m_Cache)
  284. {
  285. userMsgs = GetUserMessageCache(user);
  286. }
  287. lock (userMsgs)
  288. {
  289. userMsgs.Add(msg);
  290. m_Count++;
  291. }
  292. }
  293. /// <summary>
  294. /// 查找缓存中接受者为user,发送时间大于from的消息
  295. /// </summary>
  296. public List<Message> Find(String user, String sender, DateTime from)
  297. {
  298. List<Message> msgs = new List<Message>();
  299. {
  300. List<Message> userMsgs = null;
  301. lock (m_Cache)
  302. {
  303. userMsgs = GetUserMessageCache(user);
  304. }
  305. lock (userMsgs)
  306. {
  307. int i = 0;
  308. while (i < userMsgs.Count && userMsgs[i].CreatedTime <= from) i++;
  309. while (i < userMsgs.Count)
  310. {
  311. if (sender == null || sender == "*" || sender == userMsgs[i].Sender.Name) msgs.Add(userMsgs[i]);
  312. i++;
  313. }
  314. }
  315. }
  316. if (sender == null || sender == "*")
  317. {
  318. //在缓冲中查找群消息
  319. AccountInfo userInfo = AccountImpl.Instance.GetUserInfo(user);
  320. foreach (string groupName in userInfo.Groups)
  321. {
  322. AccountInfo groupInfo = AccountImpl.Instance.GetUserInfo(groupName);
  323. List<Message> groupMsgs = null;
  324. lock (m_Cache)
  325. {
  326. groupMsgs = GetUserMessageCache(groupName);
  327. }
  328. lock (groupMsgs)
  329. {
  330. if (from < groupInfo.GetGroupMemberRenewTime(user))
  331. {
  332. from = groupInfo.GetGroupMemberRenewTime(user);
  333. }
  334. int i = 0;
  335. while (i < groupMsgs.Count && groupMsgs[i].CreatedTime <= from) i++;
  336. while (i < groupMsgs.Count)
  337. {
  338. msgs.Add(groupMsgs[i]);
  339. i++;
  340. }
  341. }
  342. }
  343. }
  344. return msgs;
  345. }
  346. /// <summary>
  347. /// 获取消息总量
  348. /// </summary>
  349. public Int32 Count
  350. {
  351. get { return m_Count; }
  352. }
  353. }
  354. internal class MsgAccessoryEval
  355. {
  356. string m_Receiver, m_Sender;
  357. string m_ReceiverMsgDir, m_SenderMsgDir, m_MsgDir;
  358. Hashtable m_Data;
  359. public MsgAccessoryEval(Int64 key, String receiver, String sender, Hashtable data)
  360. {
  361. m_Receiver = receiver;
  362. m_Sender = sender;
  363. m_Data = data;
  364. m_ReceiverMsgDir = string.Format("/{0}/Message/MSG{1:00000000}", receiver, key);
  365. m_SenderMsgDir = string.Format("/{0}/Message/MSG{1:00000000}", sender, key);
  366. m_MsgDir = AccountImpl.Instance.GetUserInfo(receiver).Type == 1 ? string.Format("/{1}/Message/MSG{0:00000000}", key, receiver) : string.Format("Message/MSG{0:00000000}", key);
  367. }
  368. public string Replace(Match match)
  369. {
  370. XmlDocument xml = new XmlDocument();
  371. string value = match.Value;
  372. xml.LoadXml(string.Format("<{0} />", value.Substring(1, value.Length - 2)));
  373. string src = GlobalObject.unescape(xml.DocumentElement.GetAttribute("src"));
  374. string type = xml.DocumentElement.GetAttribute("type").ToLower();
  375. string data = xml.DocumentElement.GetAttribute("data");
  376. bool isPublic = ServerImpl.Instance.IsPublic(src);
  377. if (isPublic)
  378. {
  379. //公共资源不拷贝
  380. return String.Format("{0}", Path.GetRelativePath(src));
  381. }
  382. else
  383. {
  384. if (!Directory.Exists(m_ReceiverMsgDir)) Directory.CreateDirectory(m_ReceiverMsgDir);
  385. if (AccountImpl.Instance.GetUserInfo(m_Receiver).Type == 0)
  386. {
  387. if (!Directory.Exists(m_SenderMsgDir)) Directory.CreateDirectory(m_SenderMsgDir);
  388. }
  389. string fileOwnerName = Path.GetUser(src);
  390. if (String.IsNullOrEmpty(fileOwnerName))
  391. {
  392. fileOwnerName = m_Sender;
  393. src = String.Format("/{0}/{1}", fileOwnerName, src);
  394. }
  395. bool allowRead=true;
  396. try
  397. {
  398. ServerImpl.Instance.CheckPermission(HttpContext.Current, src, IOPermission.Read);
  399. }
  400. catch
  401. {
  402. allowRead = false;
  403. }
  404. if (data != "" || allowRead)
  405. {
  406. Hashtable _files = new Hashtable();
  407. string fileName;
  408. if (!_files.ContainsKey(src))
  409. {
  410. fileName = Path.GetFileName(src);
  411. int i = 1;
  412. while (_files.ContainsValue(fileName))
  413. {
  414. fileName = string.Format("{0}({1}){2}", System.IO.Path.GetFileNameWithoutExtension(fileName), i.ToString(), System.IO.Path.GetExtension(fileName));
  415. i++;
  416. }
  417. _files.Add(src, fileName);
  418. try
  419. {
  420. if (AccountImpl.Instance.GetUserInfo(m_Receiver).Type == 0)
  421. {
  422. if (data == "")
  423. {
  424. File.Copy(src, m_SenderMsgDir + "/" + fileName);
  425. }
  426. else
  427. {
  428. String dataBase64 = m_Data[data] as String;
  429. Byte[] buffer = System.Convert.FromBase64String(dataBase64);
  430. using (System.IO.Stream stream = File.Open(m_SenderMsgDir + "/" + fileName, System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.None))
  431. {
  432. try
  433. {
  434. stream.Write(buffer, 0, buffer.Length);
  435. }
  436. finally
  437. {
  438. stream.Close();
  439. }
  440. }
  441. }
  442. }
  443. if (data == "")
  444. {
  445. File.Copy(src, m_ReceiverMsgDir + "/" + fileName);
  446. }
  447. else
  448. {
  449. String dataBase64 = m_Data[data] as String;
  450. Byte[] buffer = System.Convert.FromBase64String(dataBase64);
  451. using (System.IO.Stream stream = File.Open(m_ReceiverMsgDir + "/" + fileName, System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.None))
  452. {
  453. try
  454. {
  455. stream.Write(buffer, 0, buffer.Length);
  456. }
  457. finally
  458. {
  459. stream.Close();
  460. }
  461. }
  462. }
  463. }
  464. catch
  465. {
  466. }
  467. }
  468. else
  469. fileName = _files[src] as string;
  470. string newUrl = GlobalObject.escape(string.Format("{0}/{1}", m_MsgDir, fileName));
  471. return newUrl;
  472. }
  473. else
  474. {
  475. return src;
  476. }
  477. }
  478. }
  479. }
  480. }