NTESSubscribeManager.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. //
  2. // NTESSubscribeManager.m
  3. // NIM
  4. //
  5. // Created by chris on 2017/4/5.
  6. // Copyright © 2017年 Netease. All rights reserved.
  7. //
  8. #import "NTESSubscribeManager.h"
  9. #import "NTESSubscribeDefine.h"
  10. #import "NTESDevice.h"
  11. #import "NIMExtensionHelper.h"
  12. #define NTESSubscribeExpiry 60 * 60 * 24 * 1 //订阅有效期为 1 天
  13. #define NTESSubscribeEnable [NIMSDK sharedSDK].isUsingDemoAppKey //仅在使用 Demo App 的时候,将订阅能力开启,开发者可以根据自身应用订阅功能开启状态控制此开关。
  14. NSString *const NTESSubscribeNetState = @"net_state";
  15. NSString *const NTESSubscribeOnlineState = @"online_state";
  16. @interface NTESSubscribeManager()<NIMEventSubscribeManagerDelegate,NIMConversationManagerDelegate,NIMLoginManagerDelegate,NIMUserManagerDelegate>
  17. @property (nonatomic,strong) NSMutableDictionary *events;
  18. @property (nonatomic,strong) NSMutableSet *subscribeIds;
  19. @property (nonatomic,strong) NSMutableSet *tempSubscribeIds;
  20. @end
  21. @implementation NTESSubscribeManager
  22. + (instancetype)sharedManager
  23. {
  24. if (NTESSubscribeEnable)
  25. {
  26. static NTESSubscribeManager *instance;
  27. static dispatch_once_t onceToken;
  28. dispatch_once(&onceToken, ^{
  29. instance = [[NTESSubscribeManager alloc] init];
  30. });
  31. return instance;
  32. }
  33. else
  34. {
  35. return nil;
  36. }
  37. }
  38. - (instancetype)init
  39. {
  40. self = [super init];
  41. if (self)
  42. {
  43. _events = [[NSMutableDictionary alloc] init];
  44. _subscribeIds = [[NSMutableSet alloc] init];
  45. _tempSubscribeIds = [[NSMutableSet alloc] init];
  46. [[NIMSDK sharedSDK].subscribeManager addDelegate:self];
  47. [[NIMSDK sharedSDK].conversationManager addDelegate:self];
  48. [[NIMSDK sharedSDK].loginManager addDelegate:self];
  49. [[NIMSDK sharedSDK].userManager addDelegate:self];
  50. }
  51. return self;
  52. }
  53. - (void)start
  54. {
  55. DDLogInfo(@"SubscribeManager Center Setup");
  56. }
  57. - (void)dealloc
  58. {
  59. [[NIMSDK sharedSDK].subscribeManager removeDelegate:self];
  60. [[NIMSDK sharedSDK].conversationManager removeDelegate:self];
  61. [[NIMSDK sharedSDK].userManager removeDelegate:self];
  62. }
  63. - (NSDictionary<NIMSubscribeEvent *,NSString *> *)eventsForType:(NSInteger)type
  64. {
  65. return [self.events objectForKey:@(type)];
  66. }
  67. - (void)subscribeTempUserOnlineState:(NSString *)userId
  68. {
  69. BOOL isRobot = [[NIMSDK sharedSDK].robotManager isValidRobot:userId];
  70. BOOL isMe = [[NIMSDK sharedSDK].loginManager.currentAccount isEqualToString:userId];
  71. if (isRobot || isMe) {
  72. DDLogInfo(@"user can not subscribe temp publisher: %@",userId);
  73. //自己或者机器人,则不需要订阅
  74. return;
  75. }
  76. NIMSubscribeRequest *request = [self generateRequest];
  77. request.publishers = @[userId];
  78. [self.tempSubscribeIds addObject:userId];
  79. [[NIMSDK sharedSDK].subscribeManager subscribeEvent:request completion:^(NSError * _Nullable error, NSArray * _Nullable failedPublishers) {
  80. DDLogInfo(@"subscribe temp publisher:%@ error: %@ failed publishers: %@",request.publishers,error,failedPublishers);
  81. }];
  82. }
  83. - (void)unsubscribeTempUserOnlineState:(NSString *)userId
  84. {
  85. if (![_subscribeIds containsObject:userId])
  86. {
  87. //如果这个人没有订阅
  88. NIMSubscribeRequest *request = [self generateRequest];
  89. request.publishers = @[userId];
  90. [[NIMSDK sharedSDK].subscribeManager unSubscribeEvent:request completion:^(NSError * _Nullable error, NSArray * _Nullable failedPublishers) {
  91. DDLogInfo(@"unSubscribe temp publisher:%@ error: %@ failed publishers: %@",request.publishers,error,failedPublishers);
  92. }];
  93. [self.tempSubscribeIds removeObject:userId];
  94. }
  95. }
  96. - (void)cleanCache
  97. {
  98. [_subscribeIds removeAllObjects];
  99. [_tempSubscribeIds removeAllObjects];
  100. [_events removeAllObjects];
  101. }
  102. - (void)publishOnlineState
  103. {
  104. NIMSubscribeEvent *event = [[NIMSubscribeEvent alloc] init];
  105. event.type = NIMSubscribeSystemEventTypeOnline;
  106. event.value = NTESCustomStateValueOnlineExt;
  107. event.sendToOnlineUsersOnly = NO; //必须要让后登录的用户也能拿到
  108. NSDictionary *ext = @{
  109. NTESSubscribeNetState : @([NTESDevice currentDevice].currentNetworkType),
  110. NTESSubscribeOnlineState : @(NTESOnlineStateNormal), //移动端永远在线
  111. };
  112. [event setExt:[ext nimkit_jsonString]];
  113. [[NIMSDK sharedSDK].subscribeManager publishEvent:event completion:^(NSError * _Nullable error, NIMSubscribeEvent * _Nullable event) {
  114. DDLogInfo(@"publish online state error %@ ext %@ time %.2f",error,ext,event.timestamp);
  115. }];
  116. }
  117. - (void)subscribeOnlineState
  118. {
  119. [_subscribeIds addObjectsFromArray:self.recentSessionUserIds.allObjects];
  120. [_subscribeIds addObjectsFromArray:self.contactUserIds.allObjects];
  121. [self subscribeNextMembers:_subscribeIds.allObjects];
  122. }
  123. - (void)subscribeNextMembers:(NSArray *)ids
  124. {
  125. if (!ids.count) {
  126. return;
  127. }
  128. NIMSubscribeRequest *request = [self generateRequest];
  129. NSInteger maxRequestCount = 100;
  130. NSArray *publishers;
  131. NSRange remove = ids.count > maxRequestCount? NSMakeRange(0, maxRequestCount): NSMakeRange(0, ids.count);
  132. publishers = [ids subarrayWithRange:remove];
  133. request.publishers = publishers;
  134. __weak typeof(self) weakSelf = self;
  135. [[NIMSDK sharedSDK].subscribeManager subscribeEvent:request completion:^(NSError * _Nullable error, NSArray * _Nullable failedPublishers) {
  136. DDLogInfo(@"subscribe publisher:%@ error: %@ failed publishers: %@",request.publishers,error,failedPublishers);
  137. NSMutableArray *members = [ids mutableCopy];
  138. [members removeObjectsInRange:remove];
  139. if (members.count) {
  140. [weakSelf subscribeNextMembers:members];
  141. }
  142. }];
  143. }
  144. #pragma mark - NIMLoginManagerDelegate
  145. - (void)onLogin:(NIMLoginStep)step
  146. {
  147. if (step == NIMLoginStepLinking)
  148. {
  149. [self cleanCache];
  150. }
  151. if (step == NIMLoginStepSyncOK)
  152. {
  153. [self publishOnlineState];
  154. [self subscribeOnlineState];
  155. }
  156. }
  157. #pragma mark - NIMUserManagerDelegate
  158. - (void)onFriendChanged:(NIMUser *)user
  159. {
  160. BOOL isMyFriend = [[NIMSDK sharedSDK].userManager isMyFriend:user.userId];
  161. if (isMyFriend && ![self.subscribeIds containsObject:user.userId])
  162. {
  163. //是好友却没订阅,订阅一下
  164. NIMSubscribeRequest *request = [self generateRequest];
  165. request.publishers = @[user.userId];
  166. [[NIMSDK sharedSDK].subscribeManager subscribeEvent:request completion:^(NSError * _Nullable error, NSArray * _Nullable failedPublishers) {
  167. if (!error) {
  168. [self.subscribeIds addObject:user.userId];
  169. }
  170. DDLogInfo(@"subscribe publisher: %@ error: %@",request.publishers,error);
  171. }];
  172. }
  173. if (!isMyFriend && ![self.recentSessionUserIds containsObject:user.userId]) {
  174. //不再是好友,从订阅集里删掉,等到下次服务器下发订阅事件,再反订阅即可
  175. [self.subscribeIds removeObject:user.userId];
  176. }
  177. }
  178. #pragma mark - NIMEventSubscribeManagerDelegate
  179. - (void)onRecvSubscribeEvents:(NSArray *)events
  180. {
  181. NSMutableArray *unSubscribeUsers = [[NSMutableArray alloc] init];
  182. for (NIMSubscribeEvent *event in events) {
  183. if ([self.subscribeIds containsObject:event.from] || [self.tempSubscribeIds containsObject:event.from])
  184. {
  185. NSInteger type = event.type;
  186. NSMutableDictionary *eventsDict = [self.events objectForKey:@(type)];
  187. if (!eventsDict) {
  188. eventsDict = [[NSMutableDictionary alloc] init];
  189. [self.events setObject:eventsDict forKey:@(type)];
  190. }
  191. NIMSubscribeEvent *oldEvent = [eventsDict objectForKey:event.from];
  192. if (oldEvent.timestamp > event.timestamp)
  193. {
  194. //服务器不保证事件的顺序,如果发现是同类型的过期事件,根据自身业务情况决定是否过滤。
  195. DDLogInfo(@"event id %@ from %@ is out of date, ingore...",event.eventId,event.from);
  196. }
  197. else
  198. {
  199. [eventsDict setObject:event forKey:event.from];
  200. DDLogInfo(@"receive event id %@ from %@ time %.2f",event.eventId,event.from,event.timestamp);
  201. }
  202. }
  203. else
  204. {
  205. //删掉了或者是以前订阅的没有干掉,这里反订阅一下
  206. [unSubscribeUsers addObject:event.from];
  207. }
  208. }
  209. //反订阅
  210. if (unSubscribeUsers.count)
  211. {
  212. NIMSubscribeRequest *request = [self generateRequest];
  213. request.publishers = [NSArray arrayWithArray:unSubscribeUsers];
  214. [[NIMSDK sharedSDK].subscribeManager unSubscribeEvent:request completion:^(NSError * _Nullable error, NSArray * _Nullable failedPublishers) {
  215. DDLogInfo(@"unSubscribe publisher:%@ error: %@ failed publishers: %@",request.publishers,error,failedPublishers);
  216. }];
  217. }
  218. }
  219. #pragma mark - NIMConversationManagerDelegate
  220. - (void)didAddRecentSession:(NIMRecentSession *)recentSession
  221. totalUnreadCount:(NSInteger)totalUnreadCount
  222. {
  223. if (recentSession.session.sessionType == NIMSessionTypeP2P) {
  224. [self.subscribeIds addObject:recentSession.session.sessionId];
  225. NIMSubscribeRequest *request = [self generateRequest];
  226. request.publishers = @[recentSession.session.sessionId];
  227. [[NIMSDK sharedSDK].subscribeManager subscribeEvent:request completion:^(NSError * _Nullable error, NSArray * _Nullable failedPublishers) {
  228. DDLogInfo(@"subscribe publisher: %@ error: %@",request.publishers,error);
  229. }];
  230. }
  231. }
  232. - (void)didRemoveRecentSession:(NIMRecentSession *)recentSession
  233. totalUnreadCount:(NSInteger)totalUnreadCount
  234. {
  235. if (recentSession.session.sessionType == NIMSessionTypeP2P && ![self.contactUserIds containsObject:recentSession.session.sessionId]) {
  236. [self.subscribeIds removeObject:recentSession.session.sessionId];
  237. }
  238. }
  239. #pragma mark - Private
  240. - (NIMSubscribeRequest *)generateRequest
  241. {
  242. NIMSubscribeRequest *request = [[NIMSubscribeRequest alloc] init];
  243. request.type = NIMSubscribeSystemEventTypeOnline;
  244. request.expiry = NTESSubscribeExpiry;
  245. request.syncEnabled = YES;
  246. return request;
  247. }
  248. - (NSSet *)recentSessionUserIds
  249. {
  250. NSMutableSet *ids = [[NSMutableSet alloc] init];
  251. NSString *me = [NIMSDK sharedSDK].loginManager.currentAccount;
  252. for (NIMRecentSession *recent in [NIMSDK sharedSDK].conversationManager.allRecentSessions) {
  253. BOOL isRobot = [[NIMSDK sharedSDK].robotManager isValidRobot:recent.session.sessionId];
  254. if (recent.session.sessionType == NIMSessionTypeP2P && !isRobot && ![recent.session.sessionId isEqualToString:me])
  255. {
  256. [ids addObject:recent.session.sessionId];
  257. }
  258. }
  259. return [NSSet setWithSet:ids];
  260. }
  261. - (NSSet *)contactUserIds
  262. {
  263. NSMutableSet *ids = [[NSMutableSet alloc] init];
  264. for (NIMUser *user in [NIMSDK sharedSDK].userManager.myFriends) {
  265. [ids addObject:user.userId];
  266. }
  267. return [NSSet setWithSet:ids];
  268. }
  269. @end