GroupProcess.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  1. unit GroupProcess;
  2. interface
  3. uses
  4. superobject, GroupUtility, GroupClient, RealICQModel, Classes, SysUtils;
  5. type
  6. TBaseProcess = class
  7. private
  8. FClient: TGroupClient;
  9. public
  10. constructor Create(AClient: TGroupClient);
  11. procedure Excute(AData: ISuperObject); virtual;
  12. procedure Send(AData: string);
  13. property Client: TGroupClient read FClient;
  14. end;
  15. TGetMyGroupsResponse = class(TBaseProcess)
  16. public
  17. procedure Excute(AData: ISuperObject); override;
  18. end;
  19. TGroupCreateResponse = class(TBaseProcess)
  20. public
  21. procedure Excute(AData: ISuperObject); override;
  22. end;
  23. TGroupDeleteResponse = class(TBaseProcess)
  24. public
  25. procedure Excute(AData: ISuperObject); override;
  26. end;
  27. TGroupUpdateResponse = class(TBaseProcess)
  28. public
  29. procedure Excute(AData: ISuperObject); override;
  30. end;
  31. TGroupSearchResponse = class(TBaseProcess)
  32. public
  33. procedure Excute(AData: ISuperObject); override;
  34. end;
  35. TGroupAsynResponse = class(TBaseProcess)
  36. public
  37. procedure Excute(AData: ISuperObject); override;
  38. end;
  39. TMemberAddResponse = class(TBaseProcess)
  40. public
  41. procedure Excute(AData: ISuperObject); override;
  42. end;
  43. TMemberDelResponse = class(TBaseProcess)
  44. public
  45. procedure Excute(AData: ISuperObject); override;
  46. end;
  47. /// <summary>
  48. /// 群管理员收到加入群的申请
  49. /// </summary>
  50. TMemberApplyP = class(TBaseProcess)
  51. public
  52. procedure Excute(AData: ISuperObject); override;
  53. end;
  54. TMemberReplyP = class(TBaseProcess)
  55. public
  56. procedure Excute(AData: ISuperObject); override;
  57. end;
  58. TMessageBroadcast = class(TBaseProcess)
  59. public
  60. procedure Excute(AData: ISuperObject); override;
  61. end;
  62. TFileDownloadBroadcast = class(TBaseProcess)
  63. public
  64. procedure Excute(AData: ISuperObject); override;
  65. end;
  66. TOfflineMessageResponse = class(TBaseProcess)
  67. public
  68. procedure Excute(AData: ISuperObject); override;
  69. end;
  70. TNewOfflineMessageResponse = class(TBaseProcess)
  71. public
  72. procedure Excute(AData: ISuperObject); override;
  73. end;
  74. // {
  75. // id: <String>,
  76. // group:[<{id: <String>, ts: <Number>}>]
  77. // }
  78. TMessageMiscBroadcast = class(TBaseProcess)
  79. public
  80. procedure Excute(AData: ISuperObject); override;
  81. end;
  82. function ManagersConvertToStr(AManagers: TSuperArray): string;
  83. function MembersConvertToStr(AJoUser: ISuperObject): string;
  84. implementation
  85. uses
  86. LoggerImport, GroupService, DataProviderImport, DateUtils,
  87. InterfaceDataProvider, GroupConfig;
  88. function ManagersConvertToStr(AManagers: TSuperArray): string;
  89. var
  90. iLoop: Integer;
  91. begin
  92. iLoop := 0;
  93. Result := '';
  94. while iLoop < AManagers.Length - 1 do
  95. begin
  96. Result := Result + AManagers[iLoop].AsString + Chr(10);
  97. Inc(iLoop);
  98. end;
  99. Result := Result + AManagers[iLoop].AsString
  100. end;
  101. function MembersConvertToStr(AJoUser: ISuperObject): string;
  102. var
  103. AItem: TSuperAvlEntry;
  104. begin
  105. Result := '';
  106. for AItem in AJoUser.AsObject do
  107. Result := Result + AItem.Value['id'].AsString + Chr(10);
  108. Result := Copy(Result, 0, Length(Result) - 1);
  109. end;
  110. function ToTeam(AJo: ISuperObject): TRealICQTeam;
  111. begin
  112. try
  113. Result := nil;
  114. if AJo = nil then
  115. Exit;
  116. Result := TRealICQTeam.Create;
  117. Result.TeamID := AJo.S['id'];
  118. Result.TeamCaption := AJo.S['name'];
  119. Result.TeamCreater := AJo.S['creator'];
  120. Result.TeamIntro := AJo.S['intro'];
  121. Result.TeamCallBoard := AJo.S['notice'];
  122. Result.TeamValidate := TRealICQTeamValidateType(AJo.I['auth']);
  123. Result.TeamManagers := ManagersConvertToStr(AJo.A['managers']);
  124. Result.TeamMembers := MembersConvertToStr(AJo.O['members']);
  125. except
  126. on Ex: Exception do
  127. begin
  128. Error(Ex.Message, 'ToTeam');
  129. Result.Free;
  130. end;
  131. end;
  132. end;
  133. function GetWaitingTeam(ATeamID: string): TRealICQTeam;
  134. begin
  135. try
  136. Result := TRealICQTeam.Create;
  137. Result.TeamID := ATeamID;
  138. Result.TeamCaption := '群信息正在努力加载中...';
  139. // Result.TeamCreater := '加载中...';
  140. Result.TeamIntro := '加载中...';
  141. Result.TeamCallBoard := '加载中...';
  142. // Result.TeamManagers := '加载中...';
  143. // Result.TeamMembers := '加载中...';
  144. except
  145. on Ex: Exception do
  146. begin
  147. Error(Ex.Message, 'GetWaitingTeam');
  148. Result.Free;
  149. end;
  150. end;
  151. end;
  152. { TNoProcess }
  153. constructor TBaseProcess.Create(AClient: TGroupClient);
  154. begin
  155. FClient := AClient;
  156. end;
  157. procedure TBaseProcess.Excute(AData: ISuperObject);
  158. begin
  159. Warning(AData.AsJSon(), 'TBaseProcess.Excute');
  160. end;
  161. procedure TBaseProcess.Send(AData: string);
  162. begin
  163. if FClient <> nil then
  164. FClient.Send(AData);
  165. end;
  166. { TGroupCreateResponse }
  167. procedure TGroupCreateResponse.Excute(AData: ISuperObject);
  168. var
  169. ATeam: TRealICQTeam;
  170. begin
  171. try
  172. ATeam := ToTeam(AData.O['group']);
  173. if ATeam = nil then
  174. Exit;
  175. except
  176. on Ex: Exception do
  177. begin
  178. Error(Ex.Message, 'TGroupCreateResponse.Excute');
  179. ATeam.Free;
  180. end;
  181. end;
  182. TGroupService.GetService.OnAddedTeam(ATeam);
  183. GetMapTeamUsersProvider.Insert(AData.S['group.id'], AData.O['group'].AsJSon(), AData.I['group.ver']);
  184. end;
  185. { TGroupDeleteResponse }
  186. procedure TGroupDeleteResponse.Excute(AData: ISuperObject);
  187. var
  188. ATeamID: string;
  189. begin
  190. try
  191. ATeamID := AData.S['group.id'];
  192. TGroupService.GetService.OnDeletedTeam(ATeamID);
  193. except
  194. on Ex: Exception do
  195. begin
  196. Error(Ex.Message, 'TGroupDeleteResponse.Excute');
  197. end;
  198. end;
  199. end;
  200. { TGroupUpdateResponse }
  201. procedure TGroupUpdateResponse.Excute(AData: ISuperObject);
  202. var
  203. ATeam: TRealICQTeam;
  204. begin
  205. try
  206. ATeam := TRealICQTeam.Create;
  207. ATeam.TeamID := AData.S['group.id'];
  208. ATeam.TeamCaption := AData.S['group.name'];
  209. ATeam.TeamIntro := AData.S['group.intro'];
  210. ATeam.TeamCallBoard := AData.S['group.notice'];
  211. ATeam.TeamValidate := TRealICQTeamValidateType(AData.I['group.auth']);
  212. TGroupService.GetService.OnTeamInfoChange(ATeam);
  213. except
  214. on Ex: Exception do
  215. begin
  216. Error(Ex.Message, 'TGroupCreateResponse.Excute');
  217. ATeam.Free;
  218. end;
  219. end;
  220. ATeam.Free;
  221. // GetMapTeamUsersProvider.Insert(AData.S['group.id'], AData.O['group'].AsJSon(), AData.I['group.ver']);
  222. end;
  223. { TGroupSearchResponse }
  224. procedure TGroupSearchResponse.Excute(AData: ISuperObject);
  225. var
  226. ARecord: TSearchTeamResultRecord;
  227. ARecords: TStringList;
  228. iLoop: Integer;
  229. jaGroups: TSuperArray;
  230. begin
  231. ARecords := TStringList.Create;
  232. try
  233. jaGroups := AData.A['groups'];
  234. for iLoop := 0 to jaGroups.Length - 1 do
  235. begin
  236. ARecord := TSearchTeamResultRecord.Create;
  237. ARecord.TeamID := jaGroups[iLoop]['id'].AsString;
  238. ARecord.TeamCaption := jaGroups[iLoop]['name'].AsString;
  239. ARecord.TeamCreater := jaGroups[iLoop]['creator'].AsString;
  240. ARecords.AddObject(IntToStr(iLoop), ARecord);
  241. end;
  242. TGroupService.GetService.OnSearched(ARecords, AData.I['skip'], AData.I['limit']);
  243. finally
  244. ARecords.Free;
  245. end;
  246. end;
  247. { TGroupAsynResponse }
  248. procedure TGroupAsynResponse.Excute(AData: ISuperObject);
  249. var
  250. ATeam: TRealICQTeam;
  251. AJo: ISuperObject;
  252. AMessageRep: TMessageBroadcast;
  253. begin
  254. try
  255. AJo := AData.O['group'];
  256. ATeam := ToTeam(AJo);
  257. if ATeam = nil then
  258. Exit;
  259. except
  260. on Ex: Exception do
  261. begin
  262. Error(Ex.Message, 'TGroupCreateResponse.Excute');
  263. ATeam.Free;
  264. end;
  265. end;
  266. TGroupService.GetService.OnAddedTeam(ATeam);
  267. GetMapTeamUsersProvider.Insert(AJo.S['id'], AJo.AsJSon(), AJo.I['ver']);
  268. end;
  269. { TBaseProcess }
  270. //42["m.add.b",{"id":"","group":{"id":"0fde0aa744384f2e8b4973e17ca9b79a","members":["1000+002682BECE10-lqq"],"managers":[]},"operator":"1000+002682BECE10-test02"}]
  271. procedure TMemberAddResponse.Excute(AData: ISuperObject);
  272. var
  273. ATeamID: string;
  274. AMembers, AManagers: TStringList;
  275. jaMembers, jaManagers: TSuperArray;
  276. iLoop: Integer;
  277. begin
  278. try
  279. ATeamID := AData.S['group.id'];
  280. if Trim(ATeamID) = '' then
  281. Exit;
  282. AMembers := TStringList.Create;
  283. AManagers := TStringList.Create;
  284. jaMembers := AData.A['group.members'];
  285. jaManagers := AData.A['group.managers'];
  286. if jaMembers <> nil then
  287. for iLoop := 0 to jaMembers.Length - 1 do
  288. AMembers.Add(jaMembers.S[iLoop]);
  289. if jaManagers <> nil then
  290. for iLoop := 0 to jaManagers.Length - 1 do
  291. AManagers.Add(jaManagers.S[iLoop]);
  292. if (AMembers.Count > 0) then
  293. TGroupService.GetService.OnAddedMembers(ATeamID, AMembers);
  294. if (AManagers.Count > 0) then
  295. TGroupService.GetService.OnAddedManagers(ATeamID, AManagers);
  296. except
  297. on Ex: Exception do
  298. begin
  299. Error(Ex.Message, 'TMemberAddResponse.Excute');
  300. FreeAndNil(AMembers);
  301. FreeAndNil(AManagers);
  302. end;
  303. end;
  304. FreeAndNil(AMembers);
  305. FreeAndNil(AManagers);
  306. end;
  307. { TMemberDelResponse }
  308. procedure TMemberDelResponse.Excute(AData: ISuperObject);
  309. var
  310. ATeamID: string;
  311. AMembers, AManagers: TStringList;
  312. jaMembers, jaManagers: TSuperArray;
  313. iLoop: Integer;
  314. begin
  315. try
  316. ATeamID := AData.S['group.id'];
  317. if Trim(ATeamID) = '' then
  318. Exit;
  319. AMembers := TStringList.Create;
  320. AManagers := TStringList.Create;
  321. jaMembers := AData.A['group.members'];
  322. jaManagers := AData.A['group.managers'];
  323. if jaMembers <> nil then
  324. for iLoop := 0 to jaMembers.Length - 1 do
  325. AMembers.Add(jaMembers.S[iLoop]);
  326. if jaManagers <> nil then
  327. for iLoop := 0 to jaManagers.Length - 1 do
  328. AManagers.Add(jaManagers.S[iLoop]);
  329. if (AMembers.Count > 0) then
  330. TGroupService.GetService.OnDeletedMembers(ATeamID, AMembers);
  331. if (AManagers.Count > 0) then
  332. TGroupService.GetService.OnDeletedManagers(ATeamID, AManagers);
  333. except
  334. on Ex: Exception do
  335. begin
  336. Error(Ex.Message, 'TMemberAddResponse.Excute');
  337. FreeAndNil(AMembers);
  338. FreeAndNil(AManagers);
  339. end;
  340. end;
  341. FreeAndNil(AMembers);
  342. FreeAndNil(AManagers);
  343. end;
  344. { TMemberApplyP }
  345. procedure TMemberApplyP.Excute(AData: ISuperObject);
  346. var
  347. ATeamID: string;
  348. joApply: ISuperObject;
  349. begin
  350. ATeamID := AData.S['group.id'];
  351. joApply := AData.O['group.apply'];
  352. TGroupService.GetService.OnReceivedApplyBoardcast(ATeamID, joApply.S['uid'], joApply.S['msg']);
  353. end;
  354. { TMemberReplyP }
  355. //42["m.reply.p",
  356. //{"group":
  357. {"id":"5ebbdeeed099442e88980a4512227656",
  358. "apply":{"uid":"0578+0-lslinlh","msg":"","id":"a1e782d74bfd45e785dcb9ce85750a24"}
  359. // },
  360. // "id":"6d773f668b8d4811b990254396f0eb7e",
  361. //"reply":{"id":"6d773f668b8d4811b990254396f0eb7e","ret":1}}]
  362. procedure TMemberReplyP.Excute(AData: ISuperObject);
  363. var
  364. ATeamID, ALoginName, AMsg: string;
  365. ARet: Integer;
  366. begin
  367. ATeamID := AData.S['group.id'];
  368. ALoginName := AData.S['group.apply.uid'];
  369. AMsg := AData.S['group.reply.msg'];
  370. ARet := AData.I['group.reply.ret'];
  371. TGroupService.GetService.OnReceivedReplyBoardcast(ATeamID, ALoginName, AMsg, ARet);
  372. end;
  373. { TMessageBroadcast }
  374. //{id:'', group:{id:[id...]}, message:{message}}
  375. procedure TMessageBroadcast.Excute(AData: ISuperObject);
  376. var
  377. ATeamID: string;
  378. ASender: string;
  379. AStyle: string;
  380. AContent: string;
  381. TimesTamp: Int64;
  382. ASendTime: TDateTime;
  383. jaImgs: TSuperArray;
  384. iLoop: Integer;
  385. begin
  386. ATeamID := AData.S['group.id'];
  387. if TGroupService.GetService.GetTeam(ATeamID) = nil then
  388. begin
  389. FClient.AsynTeam(ATeamID);
  390. end;
  391. if AData.S['content'] <> '' then
  392. AContent := AData.S['content']
  393. else
  394. AContent := AData.S['txt'];
  395. AContent := StringReplace(AContent, '\r\n', #13#10, [rfReplaceAll]);
  396. AContent := StringReplace(AContent, '[\r][\n]', '\r\n', [rfReplaceAll]);
  397. ASender := AData.S['sender'];
  398. ASendTime := UnixToDateTime(Round(AData.I['ts'] / 1000) + 8 * 60 * 60);
  399. AStyle := JsonToFont(AData.O['style']);
  400. // case AData.I['msgType'] of
  401. //
  402. // end;
  403. // jaImgs := AData.A['img'];
  404. // if jaImgs <> nil then
  405. // for ILoop := 0 to jaImgs.Length - 1 do
  406. // if jaImgs.O[iLoop].I['ret'] = 1 then
  407. // TGroupService.GetService.OnUploaded(jaImgs.O[iLoop].S['hash'], jaImgs.O[iLoop].S['file']);
  408. TGroupService.GetService.OnMessage(ATeamID, ASender, AContent, AStyle, ASendTime, AData.I['msgType'], AData.I['length']);
  409. // Client.MessageMisc(ATeamID);
  410. end;
  411. { TGetMyGroupsResponse }
  412. procedure TGetMyGroupsResponse.Excute(AData: ISuperObject);
  413. var
  414. AJa: TSuperArray;
  415. iLoop, ARemoteVer, ALocalVer: Integer;
  416. AJson, ATeamID: string;
  417. AKeyValue: TKeyValue;
  418. ATeam: TRealICQTeam;
  419. begin
  420. AJa := AData.A['user.groups'];
  421. if AJa = nil then
  422. Exit;
  423. for iLoop := 0 to AJa.Length - 1 do
  424. begin
  425. ATeamID := AJa.O[iLoop].S['id'];
  426. ARemoteVer := AJa.O[iLoop].I['ver'];
  427. AKeyValue := GetMapTeamUsersProvider.FindKeyValue(ATeamID);
  428. ALocalVer := StrToIntDef(AKeyValue[2], -1);
  429. AJson := AKeyValue[1];
  430. try
  431. if (ALocalVer < 0) or (ALocalVer <> ARemoteVer) or (AJson = '') then
  432. begin
  433. ATeam := GetWaitingTeam(ATeamID);
  434. FClient.AsynTeam(ATeamID)
  435. end
  436. else
  437. ATeam := ToTeam(SO(AJson));
  438. if ATeam <> nil then
  439. TGroupService.GetService.OnAddedTeam(ATeam, AJa.O[iLoop].I['as']);
  440. except
  441. on Ex: Exception do
  442. begin
  443. Error(AJson, 'TGetMyGroupsResponse.Excute');
  444. FreeAndNil(ATeam);
  445. end;
  446. end;
  447. FreeAndNil(ATeam);
  448. end;
  449. // FClient.GetOffineMessage;
  450. end;
  451. { TOfflineMessageResponse }
  452. procedure TOfflineMessageResponse.Excute(AData: ISuperObject);
  453. var
  454. ATeamID: string;
  455. ASender: string;
  456. AStyle: string;
  457. AContent, AURL: string;
  458. TimesTamp: Int64;
  459. ASendTime: TDateTime;
  460. jaImgs, jaMsgs: TSuperArray;
  461. iLoop, jLoop, iCount: Integer;
  462. AItem: ISuperObject;
  463. config: TGroupConfig;
  464. service: TGroupService;
  465. begin
  466. jaMsgs := AData.AsArray;
  467. iCount := jaMsgs.Length;
  468. config := TGroupConfig.GetConfig;
  469. service := TGroupService.GetService;
  470. for iLoop := 0 to iCount - 1 do
  471. begin
  472. try
  473. AItem := jaMsgs.O[iLoop];
  474. ATeamID := AItem.S['group.id'];
  475. if AItem.S['content'] <> '' then
  476. AContent := AItem.S['content']
  477. else
  478. AContent := AItem.S['txt'];
  479. AContent := StringReplace(AContent, '\r\n', #13#10, [rfReplaceAll]);
  480. AContent := StringReplace(AContent, '[\r][\n]', '\r\n', [rfReplaceAll]);
  481. ASender := AItem.S['sender'];
  482. ASendTime := UnixToDateTime(Round(AItem.I['ts'] / 1000) + 8 * 60 * 60);
  483. AStyle := JsonToFont(AItem.O['style']);
  484. TGroupService.GetService.OnMessage(ATeamID, ASender, AContent, AStyle, ASendTime, AItem.I['msgType'], AItem.I['length']);
  485. finally
  486. // Client.MessageMisc(ATeamID);
  487. end;
  488. end;
  489. end;
  490. { TFileDownloadBroadcast }
  491. procedure TFileDownloadBroadcast.Excute(AData: ISuperObject);
  492. var
  493. AURL: string;
  494. jaFiles: TSuperArray;
  495. iLoop: Integer;
  496. joFile: ISuperObject;
  497. config: TGroupConfig;
  498. service: TGroupService;
  499. begin
  500. jaFiles := AData.A['hashs'];
  501. config := TGroupConfig.GetConfig;
  502. service := TGroupService.GetService;
  503. for iLoop := 0 to jaFiles.Length - 1 do
  504. begin
  505. joFile := jaFiles.O[iLoop];
  506. AURL := Format(DOWNLOAD_URL, [config.ImageIP, config.ImagePort, joFile.S['hash']]);
  507. service.OnUploaded(AURL, joFile.S['file']);
  508. end;
  509. end;
  510. { TNewOfflineMessageResponse }
  511. procedure TNewOfflineMessageResponse.Excute(AData: ISuperObject);
  512. var
  513. ATeamID: string;
  514. ASender: string;
  515. AStyle: string;
  516. AContent, AURL: string;
  517. TimesTamp: Int64;
  518. ASendTime: TDateTime;
  519. jaImgs, jaMsgs: TSuperArray;
  520. iLoop, jLoop, iCount: Integer;
  521. AItem: ISuperObject;
  522. config: TGroupConfig;
  523. service: TGroupService;
  524. begin
  525. jaMsgs := AData.A['data'];
  526. iCount := jaMsgs.Length;
  527. config := TGroupConfig.GetConfig;
  528. service := TGroupService.GetService;
  529. for iLoop := 0 to iCount - 1 do
  530. begin
  531. try
  532. AItem := jaMsgs.O[iLoop];
  533. ATeamID := AItem.S['group.id'];
  534. if AItem.S['content'] <> '' then
  535. AContent := AItem.S['content']
  536. else
  537. AContent := AItem.S['txt'];
  538. AContent := StringReplace(AContent, '\r\n', #13#10, [rfReplaceAll]);
  539. AContent := StringReplace(AContent, '[\r][\n]', '\r\n', [rfReplaceAll]);
  540. ASender := AItem.S['sender'];
  541. ASendTime := UnixToDateTime(Round(AItem.I['ts'] / 1000) + 8 * 60 * 60);
  542. AStyle := JsonToFont(AItem.O['style']);
  543. TGroupService.GetService.OnMessage(ATeamID, ASender, AContent, AStyle, ASendTime, AItem.I['msgType'], AItem.I['length']);
  544. finally
  545. // Client.MessageMisc(ATeamID);
  546. end;
  547. end;
  548. end;
  549. { TMessageMiscBroadcast }
  550. procedure TMessageMiscBroadcast.Excute(AData: ISuperObject);
  551. var
  552. ja: TSuperArray;
  553. jo: ISuperObject;
  554. i: Integer;
  555. begin
  556. ja := AData.A['group'];
  557. if ja <> nil then
  558. for I := 0 to ja.Length - 1 do
  559. TGroupService.GetService.OnMessageReaded(ja[i].S['id'],ja[i].I['ts'])
  560. else
  561. begin
  562. jo := AData.O['group'];
  563. if jo = nil then Exit;
  564. TGroupService.GetService.OnMessageReaded(jo.S['id'],jo.I['ts']);
  565. end;
  566. end;
  567. end.