@onekeyfe/react-native-jpush 0.0.0-stage → 6.7.0-22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +56 -2
  3. package/ReactNativeJpush.podspec +66 -0
  4. package/android/CMakeLists.txt +24 -0
  5. package/android/build.gradle +144 -0
  6. package/android/fcm/build.gradle +36 -0
  7. package/android/fcm/consumer-rules.pro +2 -0
  8. package/android/fcm/src/main/AndroidManifest.xml +25 -0
  9. package/android/fcm/src/main/java/com/onekey/jpush/fcm/FcmInitProvider.java +25 -0
  10. package/android/fcm/src/main/java/com/onekey/jpush/fcm/FcmMessagingService.java +84 -0
  11. package/android/fcm/src/main/java/com/onekey/jpush/fcm/FcmPushManager.java +69 -0
  12. package/android/fcm/src/test/java/com/onekey/jpush/fcm/FcmAdapterTest.java +684 -0
  13. package/android/fcm/src/test/java/com/onekey/jpush/fcm/FcmManifestTest.java +54 -0
  14. package/android/gradle.properties +4 -0
  15. package/android/src/main/AndroidManifest.xml +143 -0
  16. package/android/src/main/cpp/cpp-adapter.cpp +6 -0
  17. package/android/src/main/java/cn/android/service/JTransitActivity.java +19 -0
  18. package/android/src/main/java/cn/jiguang/android/BuildConfig.java +10 -0
  19. package/android/src/main/java/cn/jiguang/android/IDataShare.java +190 -0
  20. package/android/src/main/java/cn/jiguang/api/BaseLogger.java +82 -0
  21. package/android/src/main/java/cn/jiguang/api/JAction.java +22 -0
  22. package/android/src/main/java/cn/jiguang/api/JActionExtra.java +21 -0
  23. package/android/src/main/java/cn/jiguang/api/JAnalyticsAction.java +11 -0
  24. package/android/src/main/java/cn/jiguang/api/JCoreInterface.java +228 -0
  25. package/android/src/main/java/cn/jiguang/api/JCoreManager.java +156 -0
  26. package/android/src/main/java/cn/jiguang/api/JDispatchAction.java +66 -0
  27. package/android/src/main/java/cn/jiguang/api/MultiSpHelper.java +114 -0
  28. package/android/src/main/java/cn/jiguang/api/ReportCallBack.java +9 -0
  29. package/android/src/main/java/cn/jiguang/api/SdkType.java +13 -0
  30. package/android/src/main/java/cn/jiguang/api/utils/JCollectionAuth.java +28 -0
  31. package/android/src/main/java/cn/jiguang/core/JCoreCrypto.java +545 -0
  32. package/android/src/main/java/cn/jiguang/core/JCoreStorage.java +737 -0
  33. package/android/src/main/java/cn/jiguang/core/JCoreTcpEngine.java +1395 -0
  34. package/android/src/main/java/cn/jiguang/core/JCoreWireCodec.java +1716 -0
  35. package/android/src/main/java/cn/jiguang/internal/ActionManager.java +63 -0
  36. package/android/src/main/java/cn/jiguang/internal/JConstants.java +61 -0
  37. package/android/src/main/java/cn/jiguang/internal/JCoreHelperAction.java +12 -0
  38. package/android/src/main/java/cn/jiguang/internal/JCoreInternalHelper.java +102 -0
  39. package/android/src/main/java/cn/jiguang/net/DefaultHostVerifier.java +40 -0
  40. package/android/src/main/java/cn/jiguang/net/HttpRequest.java +78 -0
  41. package/android/src/main/java/cn/jiguang/net/HttpResponse.java +48 -0
  42. package/android/src/main/java/cn/jiguang/net/HttpUtils.java +106 -0
  43. package/android/src/main/java/cn/jiguang/plugins/core/JCoreModule.java +91 -0
  44. package/android/src/main/java/cn/jiguang/plugins/core/JCorePackage.java +27 -0
  45. package/android/src/main/java/cn/jiguang/plugins/push/JPushModule.java +773 -0
  46. package/android/src/main/java/cn/jiguang/plugins/push/JPushPackage.java +25 -0
  47. package/android/src/main/java/cn/jiguang/plugins/push/common/JConstants.java +88 -0
  48. package/android/src/main/java/cn/jiguang/plugins/push/common/JLogger.java +122 -0
  49. package/android/src/main/java/cn/jiguang/plugins/push/helper/JPushHelper.java +710 -0
  50. package/android/src/main/java/cn/jiguang/plugins/push/receiver/JPushBroadcastReceiver.java +37 -0
  51. package/android/src/main/java/cn/jiguang/plugins/push/receiver/JPushModuleReceiver.java +264 -0
  52. package/android/src/main/java/cn/jiguang/plugins/service/JCoreModuleService.java +7 -0
  53. package/android/src/main/java/cn/jpush/android/api/BasicPushNotificationBuilder.java +83 -0
  54. package/android/src/main/java/cn/jpush/android/api/CallBackParams.java +50 -0
  55. package/android/src/main/java/cn/jpush/android/api/CmdMessage.java +33 -0
  56. package/android/src/main/java/cn/jpush/android/api/CustomMessage.java +28 -0
  57. package/android/src/main/java/cn/jpush/android/api/CustomPushNotificationBuilder.java +81 -0
  58. package/android/src/main/java/cn/jpush/android/api/DefaultPushNotificationBuilder.java +90 -0
  59. package/android/src/main/java/cn/jpush/android/api/InAppSlotParams.java +65 -0
  60. package/android/src/main/java/cn/jpush/android/api/InstrumentedActivity.java +17 -0
  61. package/android/src/main/java/cn/jpush/android/api/InstrumentedListActivity.java +17 -0
  62. package/android/src/main/java/cn/jpush/android/api/JPushInterface.java +490 -0
  63. package/android/src/main/java/cn/jpush/android/api/JPushMessage.java +121 -0
  64. package/android/src/main/java/cn/jpush/android/api/JThirdPlatFormInterface.java +247 -0
  65. package/android/src/main/java/cn/jpush/android/api/MultiActionsNotificationBuilder.java +72 -0
  66. package/android/src/main/java/cn/jpush/android/api/NotificationCustomButton.java +50 -0
  67. package/android/src/main/java/cn/jpush/android/api/NotificationMessage.java +67 -0
  68. package/android/src/main/java/cn/jpush/android/api/PushNotificationBuilder.java +13 -0
  69. package/android/src/main/java/cn/jpush/android/api/TagAliasCallback.java +8 -0
  70. package/android/src/main/java/cn/jpush/android/data/JPushCollectControl.java +96 -0
  71. package/android/src/main/java/cn/jpush/android/data/JPushConfig.java +79 -0
  72. package/android/src/main/java/cn/jpush/android/data/JPushConfigEx.java +41 -0
  73. package/android/src/main/java/cn/jpush/android/data/JPushLocalNotification.java +155 -0
  74. package/android/src/main/java/cn/jpush/android/helper/JCoreHelper.java +70 -0
  75. package/android/src/main/java/cn/jpush/android/helper/Logger.java +82 -0
  76. package/android/src/main/java/cn/jpush/android/local/ActionHelper.java +1293 -0
  77. package/android/src/main/java/cn/jpush/android/local/ActivityLifeCallBack.java +47 -0
  78. package/android/src/main/java/cn/jpush/android/local/JPushAction.java +67 -0
  79. package/android/src/main/java/cn/jpush/android/local/JPushConstants.java +34 -0
  80. package/android/src/main/java/cn/jpush/android/local/JPushResponse.java +26 -0
  81. package/android/src/main/java/cn/jpush/android/local/ProxyActivityAction.java +34 -0
  82. package/android/src/main/java/cn/jpush/android/service/AlarmReceiver.java +15 -0
  83. package/android/src/main/java/cn/jpush/android/service/BActivity.java +19 -0
  84. package/android/src/main/java/cn/jpush/android/service/DActivity.java +19 -0
  85. package/android/src/main/java/cn/jpush/android/service/DaemonService.java +17 -0
  86. package/android/src/main/java/cn/jpush/android/service/DataProvider.java +136 -0
  87. package/android/src/main/java/cn/jpush/android/service/DataShare.java +129 -0
  88. package/android/src/main/java/cn/jpush/android/service/DownloadProvider.java +139 -0
  89. package/android/src/main/java/cn/jpush/android/service/InitProvider.java +48 -0
  90. package/android/src/main/java/cn/jpush/android/service/JCommonService.java +79 -0
  91. package/android/src/main/java/cn/jpush/android/service/JNotifyActivity.java +28 -0
  92. package/android/src/main/java/cn/jpush/android/service/JPushMessageReceiver.java +94 -0
  93. package/android/src/main/java/cn/jpush/android/service/PushReceiver.java +26 -0
  94. package/android/src/main/java/cn/jpush/android/service/PushService.java +28 -0
  95. package/android/src/main/java/cn/jpush/android/service/SchedulerReceiver.java +17 -0
  96. package/android/src/main/java/cn/jpush/android/service/TagAliasReceiver.java +11 -0
  97. package/android/src/main/java/cn/jpush/android/service/WakedResultReceiver.java +24 -0
  98. package/android/src/main/java/cn/jpush/android/ui/FullScreenView.java +11 -0
  99. package/android/src/main/java/cn/jpush/android/ui/PopWinActivity.java +16 -0
  100. package/android/src/main/java/cn/jpush/android/ui/PushActivity.java +27 -0
  101. package/android/src/main/java/cn/jpush/android/ui/RoundedImageView.java +63 -0
  102. package/android/src/main/java/cn/jpush/android/ui/ShadowViewCard.java +56 -0
  103. package/android/src/main/java/cn/jpush/android/ups/ICallbackResult.java +5 -0
  104. package/android/src/main/java/cn/jpush/android/ups/JPushUPSManager.java +37 -0
  105. package/android/src/main/java/cn/jpush/android/ups/TokenResult.java +47 -0
  106. package/android/src/main/java/cn/jpush/android/ups/UPSRegisterCallBack.java +4 -0
  107. package/android/src/main/java/cn/jpush/android/ups/UPSTurnCallBack.java +4 -0
  108. package/android/src/main/java/cn/jpush/android/ups/UPSUnRegisterCallBack.java +4 -0
  109. package/android/src/main/java/com/margelo/nitro/reactnativejpush/ReactNativeJpush.kt +455 -0
  110. package/android/src/main/java/com/margelo/nitro/reactnativejpush/ReactNativeJpushPackage.kt +50 -0
  111. package/android/src/main/res/values/jpush_string.xml +7 -0
  112. package/android/src/main/res/values/jpush_style.xml +22 -0
  113. package/android/src/test/java/com/margelo/nitro/reactnativejpush/JPushCloudHandshakeTest.java +110 -0
  114. package/android/src/test/java/com/margelo/nitro/reactnativejpush/JPushHandshakeFailureTest.java +73 -0
  115. package/android/src/test/java/com/margelo/nitro/reactnativejpush/ReactNativeJpushProtocolTest.java +908 -0
  116. package/ios/ReactNativeJpush.swift +522 -0
  117. package/ios/bridge/RCTJCoreModule.h +5 -0
  118. package/ios/bridge/RCTJCoreModule.m +31 -0
  119. package/ios/bridge/RCTJPushEventQueue.h +14 -0
  120. package/ios/bridge/RCTJPushEventQueue.m +23 -0
  121. package/ios/bridge/RCTJPushModule.h +37 -0
  122. package/ios/bridge/RCTJPushModule.m +1165 -0
  123. package/ios/include/JCOREService.h +3 -0
  124. package/ios/include/JGCOREAPI.h +14 -0
  125. package/ios/include/JGInforCollectionAuth.h +17 -0
  126. package/ios/include/JGInforCollectionAuthItems.h +2 -0
  127. package/ios/include/JGPushNotificationTrigger.h +2 -0
  128. package/ios/include/JPUSHService.h +359 -0
  129. package/ios/jcore/JCOREConfiguration.h +141 -0
  130. package/ios/jcore/JCOREConfiguration.m +703 -0
  131. package/ios/jcore/JCORECrypto.h +73 -0
  132. package/ios/jcore/JCORECrypto.m +649 -0
  133. package/ios/jcore/JCORESisResolver.h +56 -0
  134. package/ios/jcore/JCORESisResolver.m +525 -0
  135. package/ios/jcore/JCORETcpSession.h +42 -0
  136. package/ios/jcore/JCORETcpSession.m +956 -0
  137. package/ios/jcore/JCOREWireProtocol.h +274 -0
  138. package/ios/jcore/JCOREWireProtocol.m +1453 -0
  139. package/ios/jpush/JPUSHModels.m +214 -0
  140. package/ios/jpush/JPUSHNotificationManager.h +34 -0
  141. package/ios/jpush/JPUSHNotificationManager.m +360 -0
  142. package/ios/jpush/JPUSHService.m +794 -0
  143. package/ios/tests/ReactNativeJpushTests.m +148 -0
  144. package/lib/module/ReactNativeJpush.nitro.js +4 -0
  145. package/lib/module/ReactNativeJpush.nitro.js.map +1 -0
  146. package/lib/module/index.js +801 -0
  147. package/lib/module/index.js.map +1 -0
  148. package/lib/module/package.json +1 -0
  149. package/lib/typescript/package.json +1 -0
  150. package/lib/typescript/src/ReactNativeJpush.nitro.d.ts +60 -0
  151. package/lib/typescript/src/ReactNativeJpush.nitro.d.ts.map +1 -0
  152. package/lib/typescript/src/index.d.ts +235 -0
  153. package/lib/typescript/src/index.d.ts.map +1 -0
  154. package/nitro.json +23 -0
  155. package/nitrogen/generated/android/c++/JFunc_void_bool.hpp +75 -0
  156. package/nitrogen/generated/android/c++/JFunc_void_std__string_std__string.hpp +76 -0
  157. package/nitrogen/generated/android/c++/JHybridReactNativeJpushSpec.cpp +310 -0
  158. package/nitrogen/generated/android/c++/JHybridReactNativeJpushSpec.hpp +115 -0
  159. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativejpush/Func_void_bool.kt +78 -0
  160. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativejpush/Func_void_std__string_std__string.kt +78 -0
  161. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativejpush/HybridReactNativeJpushSpec.kt +274 -0
  162. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativejpush/reactnativejpushOnLoad.kt +35 -0
  163. package/nitrogen/generated/android/reactnativejpush+autolinking.cmake +81 -0
  164. package/nitrogen/generated/android/reactnativejpush+autolinking.gradle +27 -0
  165. package/nitrogen/generated/android/reactnativejpushOnLoad.cpp +58 -0
  166. package/nitrogen/generated/android/reactnativejpushOnLoad.hpp +34 -0
  167. package/nitrogen/generated/ios/ReactNativeJpush+autolinking.rb +62 -0
  168. package/nitrogen/generated/ios/ReactNativeJpush-Swift-Cxx-Bridge.cpp +49 -0
  169. package/nitrogen/generated/ios/ReactNativeJpush-Swift-Cxx-Bridge.hpp +147 -0
  170. package/nitrogen/generated/ios/ReactNativeJpush-Swift-Cxx-Umbrella.hpp +46 -0
  171. package/nitrogen/generated/ios/ReactNativeJpushAutolinking.mm +33 -0
  172. package/nitrogen/generated/ios/ReactNativeJpushAutolinking.swift +26 -0
  173. package/nitrogen/generated/ios/c++/HybridReactNativeJpushSpecSwift.cpp +11 -0
  174. package/nitrogen/generated/ios/c++/HybridReactNativeJpushSpecSwift.hpp +402 -0
  175. package/nitrogen/generated/ios/swift/Func_void_bool.swift +46 -0
  176. package/nitrogen/generated/ios/swift/Func_void_std__string_std__string.swift +46 -0
  177. package/nitrogen/generated/ios/swift/HybridReactNativeJpushSpec.swift +107 -0
  178. package/nitrogen/generated/ios/swift/HybridReactNativeJpushSpec_cxx.swift +723 -0
  179. package/nitrogen/generated/shared/c++/HybridReactNativeJpushSpec.cpp +73 -0
  180. package/nitrogen/generated/shared/c++/HybridReactNativeJpushSpec.hpp +116 -0
  181. package/package.json +174 -4
  182. package/src/ReactNativeJpush.nitro.ts +93 -0
  183. package/src/index.tsx +1090 -0
@@ -0,0 +1,956 @@
1
+ #import "JCORETcpSession.h"
2
+ #import "JCOREConfiguration.h"
3
+ #import "JCORESisResolver.h"
4
+ #if __has_include("JPUSHService.h")
5
+ #import "JPUSHService.h"
6
+ #else
7
+ #import "../include/JPUSHService.h"
8
+ #endif
9
+ #import <Network/Network.h>
10
+ #if __has_include(<UIKit/UIKit.h>)
11
+ #import <UIKit/UIKit.h>
12
+ #endif
13
+
14
+ NSString *const kJPFNetworkIsConnectingNotification = @"kJPFNetworkIsConnectingNotification";
15
+ NSString *const kJPFNetworkDidSetupNotification = @"kJPFNetworkDidSetupNotification";
16
+ NSString *const kJPFNetworkDidCloseNotification = @"kJPFNetworkDidCloseNotification";
17
+ NSString *const kJPFNetworkDidRegisterNotification = @"kJPFNetworkDidRegisterNotification";
18
+ NSString *const kJPFNetworkFailedRegisterNotification = @"kJPFNetworkFailedRegisterNotification";
19
+ NSString *const kJPFNetworkDidLoginNotification = @"kJPFNetworkDidLoginNotification";
20
+ NSString *const kJPFNetworkDidReceiveMessageNotification = @"kJPFNetworkDidReceiveMessageNotification";
21
+ NSString *const kJPFServiceErrorNotification = @"kJPFServiceErrorNotification";
22
+
23
+ @interface JCOREQueuedWireRequest : NSObject
24
+ @property (nonatomic, assign) uint8_t command;
25
+ @property (nonatomic, assign) uint8_t version;
26
+ @property (nonatomic, strong) NSData *bodyData;
27
+ @property (nonatomic, copy, nullable) JCORETcpResponseHandler completion;
28
+ @end
29
+
30
+ @implementation JCOREQueuedWireRequest
31
+ @end
32
+
33
+ @interface JCOREInFlightRequest : NSObject
34
+ @property (nonatomic, assign) uint16_t requestId;
35
+ @property (nonatomic, assign) uint8_t command;
36
+ @property (nonatomic, assign) uint8_t version;
37
+ @property (nonatomic, strong) NSData *packetData;
38
+ @property (nonatomic, copy, nullable) JCORETcpResponseHandler completion;
39
+ @property (nonatomic, strong, nullable) dispatch_source_t resendTimer;
40
+ @property (nonatomic, strong, nullable) dispatch_source_t timeoutTimer;
41
+ - (void)cancelTimers;
42
+ @end
43
+
44
+ @implementation JCOREInFlightRequest
45
+ - (void)cancelTimers {
46
+ if (_resendTimer != nil) {
47
+ dispatch_source_cancel(_resendTimer);
48
+ _resendTimer = nil;
49
+ }
50
+ if (_timeoutTimer != nil) {
51
+ dispatch_source_cancel(_timeoutTimer);
52
+ _timeoutTimer = nil;
53
+ }
54
+ }
55
+ @end
56
+
57
+ @interface JCORETcpSession () {
58
+ dispatch_queue_t _sessionQueue;
59
+ nw_connection_t _connection;
60
+ nw_path_monitor_t _pathMonitor;
61
+ dispatch_source_t _heartbeatTimer;
62
+ dispatch_source_t _connectTimeoutTimer;
63
+ dispatch_source_t _reconnectTimer;
64
+ NSMutableData *_receiveBuffer;
65
+ NSMutableDictionary<NSNumber *, JCOREInFlightRequest *> *_inFlightRequests;
66
+ NSMutableArray<JCOREQueuedWireRequest *> *_queuedRequests;
67
+ NSArray<JCORESisEndpoint *> *_candidateEndpoints;
68
+ NSUInteger _currentEndpointIndex;
69
+ NSUInteger _reconnectAttempt;
70
+ uint32_t _sessionId;
71
+ uint16_t _serverVersion;
72
+ uint32_t _serverTimestamp;
73
+ BOOL _connecting;
74
+ BOOL _connected;
75
+ BOOL _loggedIn;
76
+ BOOL _userDisconnected;
77
+ NSString *_lastReportedDeviceTokenHex;
78
+ NSString *_lastReportedVoipTokenHex;
79
+ }
80
+ @end
81
+
82
+ @implementation JCORETcpSession
83
+
84
+ + (instancetype)shared {
85
+ static JCORETcpSession *instance = nil;
86
+ static dispatch_once_t onceToken;
87
+ dispatch_once(&onceToken, ^{
88
+ instance = [[JCORETcpSession alloc] init];
89
+ });
90
+ return instance;
91
+ }
92
+
93
+ - (instancetype)init {
94
+ self = [super init];
95
+ if (self) {
96
+ _sessionQueue = dispatch_queue_create("cn.jiguang.jcore.tcp.session", DISPATCH_QUEUE_SERIAL);
97
+ _receiveBuffer = [NSMutableData data];
98
+ _inFlightRequests = [NSMutableDictionary dictionary];
99
+ _queuedRequests = [NSMutableArray array];
100
+ [self setupNetworkAndLifecycleMonitors];
101
+ }
102
+ return self;
103
+ }
104
+
105
+ - (void)setupNetworkAndLifecycleMonitors {
106
+ nw_path_monitor_t monitor = nw_path_monitor_create();
107
+ if (monitor != nil) {
108
+ _pathMonitor = monitor;
109
+ nw_path_monitor_set_queue(monitor, _sessionQueue);
110
+ __weak typeof(self) weakSelf = self;
111
+ nw_path_monitor_set_update_handler(monitor, ^(nw_path_t path) {
112
+ __strong typeof(weakSelf) strongSelf = weakSelf;
113
+ if (!strongSelf) {
114
+ return;
115
+ }
116
+ if (nw_path_get_status(path) == nw_path_status_satisfied) {
117
+ if (!strongSelf->_userDisconnected &&
118
+ !strongSelf->_connected &&
119
+ !strongSelf->_connecting &&
120
+ [JCOREConfiguration shared].appKey.length > 0 &&
121
+ ![JCOREConfiguration shared].pushStopped) {
122
+ strongSelf->_reconnectAttempt = 0;
123
+ [strongSelf startLockedForceReconnect:NO];
124
+ }
125
+ }
126
+ });
127
+ nw_path_monitor_start(monitor);
128
+ }
129
+
130
+ #if __has_include(<UIKit/UIKit.h>)
131
+ [[NSNotificationCenter defaultCenter] addObserver:self
132
+ selector:@selector(handleAppWillEnterForeground:)
133
+ name:UIApplicationWillEnterForegroundNotification
134
+ object:nil];
135
+ #endif
136
+ }
137
+
138
+ - (void)handleAppWillEnterForeground:(NSNotification *)note {
139
+ (void)note;
140
+ dispatch_async(_sessionQueue, ^{
141
+ if (self->_userDisconnected || [JCOREConfiguration shared].pushStopped) {
142
+ return;
143
+ }
144
+ if (!self->_connected && !self->_connecting) {
145
+ self->_reconnectAttempt = 0;
146
+ [self startLockedForceReconnect:NO];
147
+ } else if (self->_connected && self->_loggedIn) {
148
+ NSData *hb = [JCOREWireProtocol buildHeartbeatPayloadWithPushStopped:[JCOREConfiguration shared].pushStopped];
149
+ [self sendRawCommandLocked:JCOREWireCommandHeartbeat version:8 bodyData:hb completion:nil];
150
+ }
151
+ });
152
+ }
153
+
154
+ - (BOOL)isConnected {
155
+ return _connected;
156
+ }
157
+
158
+ - (BOOL)isLoggedIn {
159
+ return _loggedIn;
160
+ }
161
+
162
+ - (uint32_t)sessionId {
163
+ return _sessionId;
164
+ }
165
+
166
+ - (uint16_t)serverVersion {
167
+ return _serverVersion;
168
+ }
169
+
170
+ - (uint32_t)serverTimestamp {
171
+ return _serverTimestamp;
172
+ }
173
+
174
+ - (NSUInteger)reconnectAttemptCount {
175
+ return _reconnectAttempt;
176
+ }
177
+
178
+ - (void)setCustomConnectHost:(NSString *)host
179
+ port:(uint16_t)port
180
+ useSSL:(BOOL)useSSL {
181
+ [[JCOREConfiguration shared] setCustomConnectHost:host port:port useSSL:useSSL];
182
+ }
183
+
184
+ - (void)postNotificationOnMain:(NSString *)name userInfo:(nullable NSDictionary *)userInfo {
185
+ dispatch_async(dispatch_get_main_queue(), ^{
186
+ [[NSNotificationCenter defaultCenter] postNotificationName:name object:userInfo userInfo:userInfo];
187
+ });
188
+ }
189
+
190
+ - (void)startIfNeeded {
191
+ dispatch_async(_sessionQueue, ^{
192
+ self->_userDisconnected = NO;
193
+ [self startLockedForceReconnect:NO];
194
+ });
195
+ }
196
+
197
+ - (void)reconnect {
198
+ dispatch_async(_sessionQueue, ^{
199
+ self->_userDisconnected = NO;
200
+ self->_reconnectAttempt = 0;
201
+ [self startLockedForceReconnect:YES];
202
+ });
203
+ }
204
+
205
+ - (void)startLockedForceReconnect:(BOOL)forceReconnect {
206
+ JCOREConfiguration *config = [JCOREConfiguration shared];
207
+ if (config.appKey.length == 0 || config.pushStopped) {
208
+ return;
209
+ }
210
+ [self cancelReconnectTimerLocked];
211
+ if (forceReconnect) {
212
+ [self tearDownConnectionLocked];
213
+ _connecting = NO;
214
+ }
215
+ if (_connected || _connecting) {
216
+ return;
217
+ }
218
+ _connecting = YES;
219
+ _lastReportedDeviceTokenHex = nil;
220
+ _lastReportedVoipTokenHex = nil;
221
+ [self postNotificationOnMain:kJPFNetworkIsConnectingNotification userInfo:nil];
222
+
223
+ [[JCORESisResolver shared] resolveEndpointsWithCompletion:^(NSArray<JCORESisEndpoint *> *endpoints) {
224
+ dispatch_async(self->_sessionQueue, ^{
225
+ if (self->_userDisconnected || [JCOREConfiguration shared].pushStopped) {
226
+ self->_connecting = NO;
227
+ return;
228
+ }
229
+ if (endpoints.count == 0) {
230
+ self->_connecting = NO;
231
+ [self scheduleReconnectLocked];
232
+ return;
233
+ }
234
+ self->_candidateEndpoints = [endpoints copy];
235
+ self->_currentEndpointIndex = 0;
236
+ [self connectToCurrentCandidateLocked];
237
+ });
238
+ }];
239
+ }
240
+
241
+ - (void)connectToCurrentCandidateLocked {
242
+ if (_currentEndpointIndex >= _candidateEndpoints.count) {
243
+ _connecting = NO;
244
+ [self tearDownConnectionLocked];
245
+ [self scheduleReconnectLocked];
246
+ return;
247
+ }
248
+ JCORESisEndpoint *endpoint = _candidateEndpoints[_currentEndpointIndex];
249
+ [self connectToEndpoint:endpoint];
250
+ }
251
+
252
+ - (void)advanceToNextCandidateAfterFailureOfEndpoint:(JCORESisEndpoint *)failedEndpoint {
253
+ if (failedEndpoint.host.length > 0 && failedEndpoint.port > 0) {
254
+ NSString *ipPort = [NSString stringWithFormat:@"%@:%u", failedEndpoint.host, failedEndpoint.port];
255
+ [[JCOREConfiguration shared] addFailedIp:ipPort];
256
+ }
257
+ [self tearDownConnectionLocked];
258
+
259
+ _currentEndpointIndex++;
260
+ if (_currentEndpointIndex < _candidateEndpoints.count) {
261
+ _connecting = YES;
262
+ [self connectToCurrentCandidateLocked];
263
+ } else {
264
+ _connecting = NO;
265
+ [self scheduleReconnectLocked];
266
+ }
267
+ }
268
+
269
+ - (void)connectToEndpoint:(JCORESisEndpoint *)endpoint {
270
+ [self tearDownConnectionLocked];
271
+ _connecting = YES;
272
+
273
+ const char *hostStr = endpoint.host.UTF8String;
274
+ NSString *portString = [NSString stringWithFormat:@"%u", endpoint.port];
275
+ const char *portStr = portString.UTF8String;
276
+ if (hostStr == NULL || portStr == NULL) {
277
+ [self advanceToNextCandidateAfterFailureOfEndpoint:endpoint];
278
+ return;
279
+ }
280
+
281
+ nw_endpoint_t nwEndpoint = nw_endpoint_create_host(hostStr, portStr);
282
+ nw_parameters_configure_protocol_block_t tlsConfig = endpoint.useSSL
283
+ ? NW_PARAMETERS_DEFAULT_CONFIGURATION
284
+ : NW_PARAMETERS_DISABLE_PROTOCOL;
285
+ nw_parameters_t parameters = nw_parameters_create_secure_tcp(tlsConfig, NW_PARAMETERS_DEFAULT_CONFIGURATION);
286
+ nw_connection_t connection = nw_connection_create(nwEndpoint, parameters);
287
+ _connection = connection;
288
+ nw_connection_set_queue(connection, _sessionQueue);
289
+
290
+ [self startConnectTimeoutTimerLockedForConnection:connection endpoint:endpoint];
291
+
292
+ __weak typeof(self) weakSelf = self;
293
+ nw_connection_set_state_changed_handler(connection, ^(nw_connection_state_t state, nw_error_t error) {
294
+ (void)error;
295
+ __strong typeof(weakSelf) strongSelf = weakSelf;
296
+ if (!strongSelf || strongSelf->_connection != connection) {
297
+ return;
298
+ }
299
+ if (state == nw_connection_state_ready) {
300
+ [strongSelf cancelConnectTimeoutTimerLocked];
301
+ strongSelf->_connecting = NO;
302
+ strongSelf->_connected = YES;
303
+ [strongSelf postNotificationOnMain:kJPFNetworkDidSetupNotification userInfo:nil];
304
+ [strongSelf receiveLoopForConnection:connection];
305
+ [strongSelf performHandshakeLocked];
306
+ } else if (state == nw_connection_state_waiting || state == nw_connection_state_failed) {
307
+ BOOL wasConnected = strongSelf->_connected;
308
+ if (!wasConnected) {
309
+ [strongSelf advanceToNextCandidateAfterFailureOfEndpoint:endpoint];
310
+ } else {
311
+ strongSelf->_connecting = NO;
312
+ [strongSelf tearDownConnectionLocked];
313
+ [strongSelf postNotificationOnMain:kJPFNetworkDidCloseNotification userInfo:nil];
314
+ if (!strongSelf->_userDisconnected && ![JCOREConfiguration shared].pushStopped && !strongSelf->_connecting) {
315
+ [strongSelf scheduleReconnectLocked];
316
+ }
317
+ }
318
+ } else if (state == nw_connection_state_cancelled) {
319
+ BOOL wasConnected = strongSelf->_connected;
320
+ strongSelf->_connected = NO;
321
+ strongSelf->_loggedIn = NO;
322
+ [strongSelf stopHeartbeatLocked];
323
+ if (strongSelf->_inFlightRequests.count > 0) {
324
+ NSError *closeErr = [NSError errorWithDomain:@"cn.jiguang.jpush"
325
+ code:6002
326
+ userInfo:@{NSLocalizedDescriptionKey: @"Connection closed"}];
327
+ [strongSelf failAllInFlightRequestsLockedWithError:closeErr];
328
+ }
329
+ if (wasConnected && strongSelf->_connection == connection) {
330
+ [strongSelf postNotificationOnMain:kJPFNetworkDidCloseNotification userInfo:nil];
331
+ }
332
+ }
333
+ });
334
+
335
+ nw_connection_start(connection);
336
+ }
337
+
338
+ - (void)startConnectTimeoutTimerLockedForConnection:(nw_connection_t)connection
339
+ endpoint:(JCORESisEndpoint *)endpoint {
340
+ [self cancelConnectTimeoutTimerLocked];
341
+ NSTimeInterval timeout = [JCOREConfiguration shared].connectTimeoutInterval;
342
+ if (timeout <= 0) {
343
+ timeout = (_candidateEndpoints.count > 1) ? 1.5 : 5.0;
344
+ } else if (_candidateEndpoints.count > 1 && timeout > 1.5) {
345
+ timeout = 1.5;
346
+ }
347
+ uint64_t timeoutNs = (uint64_t)(timeout * (double)NSEC_PER_SEC);
348
+ dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, _sessionQueue);
349
+ dispatch_source_set_timer(timer,
350
+ dispatch_time(DISPATCH_TIME_NOW, (int64_t)timeoutNs),
351
+ DISPATCH_TIME_FOREVER,
352
+ (uint64_t)(0.05 * NSEC_PER_SEC));
353
+ __weak typeof(self) weakSelf = self;
354
+ dispatch_source_set_event_handler(timer, ^{
355
+ __strong typeof(weakSelf) strongSelf = weakSelf;
356
+ if (!strongSelf || strongSelf->_connection != connection || strongSelf->_connected) {
357
+ return;
358
+ }
359
+ [strongSelf advanceToNextCandidateAfterFailureOfEndpoint:endpoint];
360
+ });
361
+ _connectTimeoutTimer = timer;
362
+ dispatch_resume(timer);
363
+ }
364
+
365
+ - (void)cancelConnectTimeoutTimerLocked {
366
+ if (_connectTimeoutTimer != nil) {
367
+ dispatch_source_cancel(_connectTimeoutTimer);
368
+ _connectTimeoutTimer = nil;
369
+ }
370
+ }
371
+
372
+ - (void)scheduleReconnectLocked {
373
+ [self cancelReconnectTimerLocked];
374
+ if (_userDisconnected || [JCOREConfiguration shared].pushStopped || [JCOREConfiguration shared].appKey.length == 0) {
375
+ return;
376
+ }
377
+ NSTimeInterval base = [JCOREConfiguration shared].reconnectBaseInterval;
378
+ if (base <= 0) {
379
+ base = 3.0;
380
+ }
381
+ double multiplier = pow(2.0, (double)MIN(_reconnectAttempt, (NSUInteger)6));
382
+ NSTimeInterval delay = MIN(base * multiplier, 120.0);
383
+ _reconnectAttempt++;
384
+
385
+ uint64_t delayNs = (uint64_t)(delay * (double)NSEC_PER_SEC);
386
+ dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, _sessionQueue);
387
+ dispatch_source_set_timer(timer,
388
+ dispatch_time(DISPATCH_TIME_NOW, (int64_t)delayNs),
389
+ DISPATCH_TIME_FOREVER,
390
+ (uint64_t)(0.05 * NSEC_PER_SEC));
391
+ __weak typeof(self) weakSelf = self;
392
+ dispatch_source_set_event_handler(timer, ^{
393
+ __strong typeof(weakSelf) strongSelf = weakSelf;
394
+ if (!strongSelf) {
395
+ return;
396
+ }
397
+ strongSelf->_reconnectTimer = nil;
398
+ if (!strongSelf->_userDisconnected && !strongSelf->_connected && !strongSelf->_connecting) {
399
+ [strongSelf startLockedForceReconnect:NO];
400
+ }
401
+ });
402
+ _reconnectTimer = timer;
403
+ dispatch_resume(timer);
404
+ }
405
+
406
+ - (void)cancelReconnectTimerLocked {
407
+ if (_reconnectTimer != nil) {
408
+ dispatch_source_cancel(_reconnectTimer);
409
+ _reconnectTimer = nil;
410
+ }
411
+ }
412
+
413
+ - (void)performHandshakeLocked {
414
+ JCOREConfiguration *config = [JCOREConfiguration shared];
415
+ if (config.uid == 0 || config.password.length == 0 || config.registrationID.length == 0) {
416
+ [self sendRegisterRequestLocked];
417
+ } else {
418
+ // Registered Device Fast-Login: skip Register (cmd=0) and send Login (cmd=1) directly
419
+ [self sendLoginRequestLocked];
420
+ }
421
+ }
422
+
423
+ - (void)sendRegisterRequestLocked {
424
+ JCOREConfiguration *config = [JCOREConfiguration shared];
425
+ NSString *bundleId = [config bundleIdentifierString];
426
+ NSData *regBody = [JCOREWireProtocol buildRegisterPayloadWithAppKey:config.appKey ?: @""
427
+ channel:config.channel
428
+ bundleIdHash:bundleId];
429
+ nw_connection_t activeConnection = _connection;
430
+ __weak typeof(self) weakSelf = self;
431
+ [self sendRawCommandLocked:JCOREWireCommandRegister
432
+ version:30
433
+ bodyData:regBody
434
+ completion:^(JCOREWireFrame *responseFrame, NSError *error) {
435
+ __strong typeof(weakSelf) strongSelf = weakSelf;
436
+ if (!strongSelf || strongSelf->_connection != activeConnection) {
437
+ return;
438
+ }
439
+ JCORERegisterResponse *parsed = [JCOREWireProtocol parseRegisterResponse:responseFrame];
440
+ if (error == nil && parsed != nil && parsed.statusCode == 0 && parsed.uid > 0 && parsed.registrationID.length > 0) {
441
+ [config updateRegistrationWithUid:parsed.uid
442
+ password:parsed.password ?: @""
443
+ registrationID:parsed.registrationID
444
+ deviceID:parsed.deviceID];
445
+ [JCOREConfiguration logInfo:[NSString stringWithFormat:@"TCP register success uid=%llu registrationId=%@",
446
+ parsed.uid, parsed.registrationID]];
447
+ [strongSelf postNotificationOnMain:kJPFNetworkDidRegisterNotification
448
+ userInfo:@{
449
+ @"registrationID": parsed.registrationID,
450
+ @"uid": @(parsed.uid),
451
+ }];
452
+ [strongSelf sendLoginRequestLocked];
453
+ } else {
454
+ uint16_t errCode = parsed != nil ? parsed.statusCode : 1011;
455
+ [JCOREConfiguration logWarn:[NSString stringWithFormat:@"TCP register failed code=%u", errCode]];
456
+ [strongSelf postNotificationOnMain:kJPFNetworkFailedRegisterNotification
457
+ userInfo:@{@"code": @(errCode)}];
458
+ JCORESisEndpoint *currentEndpoint = (strongSelf->_currentEndpointIndex < strongSelf->_candidateEndpoints.count)
459
+ ? strongSelf->_candidateEndpoints[strongSelf->_currentEndpointIndex]
460
+ : nil;
461
+ [strongSelf advanceToNextCandidateAfterFailureOfEndpoint:currentEndpoint];
462
+ }
463
+ }];
464
+ }
465
+
466
+ - (void)sendLoginRequestLocked {
467
+ JCOREConfiguration *config = [JCOREConfiguration shared];
468
+ NSData *loginBody = [JCOREWireProtocol buildLoginPayloadWithPassword:config.password ?: @""
469
+ appKey:config.appKey ?: @""];
470
+ nw_connection_t activeConnection = _connection;
471
+ __weak typeof(self) weakSelf = self;
472
+ [self sendRawCommandLocked:JCOREWireCommandLogin
473
+ version:27
474
+ bodyData:loginBody
475
+ completion:^(JCOREWireFrame *responseFrame, NSError *error) {
476
+ __strong typeof(weakSelf) strongSelf = weakSelf;
477
+ if (!strongSelf || strongSelf->_connection != activeConnection) {
478
+ return;
479
+ }
480
+ JCORESisEndpoint *currentEndpoint = (strongSelf->_currentEndpointIndex < strongSelf->_candidateEndpoints.count)
481
+ ? strongSelf->_candidateEndpoints[strongSelf->_currentEndpointIndex]
482
+ : nil;
483
+ if (error != nil || responseFrame == nil) {
484
+ [strongSelf advanceToNextCandidateAfterFailureOfEndpoint:currentEndpoint];
485
+ return;
486
+ }
487
+ JCORELoginResponse *login = [JCOREWireProtocol parseLoginResponse:responseFrame];
488
+ if (login != nil && login.statusCode == 108) {
489
+ // Status 108: uid unregistered/invalid on server -> clear credentials and re-register immediately
490
+ [config resetRegistration];
491
+ [strongSelf sendRegisterRequestLocked];
492
+ return;
493
+ }
494
+ if (login != nil && login.statusCode == 1012) {
495
+ // Status 1012: server requests SIS cache reset and re-resolution
496
+ [config resetSisCache];
497
+ [strongSelf startLockedForceReconnect:YES];
498
+ return;
499
+ }
500
+ if (login != nil && login.statusCode != 0) {
501
+ [strongSelf postNotificationOnMain:kJPFServiceErrorNotification
502
+ userInfo:@{@"code": @(login.statusCode)}];
503
+ [strongSelf advanceToNextCandidateAfterFailureOfEndpoint:currentEndpoint];
504
+ return;
505
+ }
506
+
507
+ if (login != nil) {
508
+ strongSelf->_sessionId = login.sessionId;
509
+ strongSelf->_serverVersion = login.serverVersion;
510
+ strongSelf->_serverTimestamp = login.serverTimestamp;
511
+ }
512
+ strongSelf->_loggedIn = YES;
513
+ strongSelf->_reconnectAttempt = 0;
514
+ [config clearFailedIps];
515
+ [JCOREConfiguration logInfo:[NSString stringWithFormat:@"TCP login success uid=%llu sid=%u registrationId=%@",
516
+ config.uid,
517
+ strongSelf->_sessionId,
518
+ config.registrationID ?: @""]];
519
+ [strongSelf startHeartbeatLocked];
520
+ [strongSelf reportDeviceTokenLocked];
521
+ [strongSelf reportVoipTokenLocked];
522
+ [strongSelf flushQueuedRequestsLocked];
523
+ [strongSelf postNotificationOnMain:kJPFNetworkDidLoginNotification
524
+ userInfo:@{
525
+ @"registrationID": config.registrationID ?: @"",
526
+ @"sessionId": @(strongSelf->_sessionId),
527
+ @"serverVersion": @(strongSelf->_serverVersion),
528
+ @"serverTimestamp": @(strongSelf->_serverTimestamp),
529
+ }];
530
+ }];
531
+ }
532
+
533
+ - (void)startHeartbeatLocked {
534
+ [self stopHeartbeatLocked];
535
+ NSTimeInterval interval = [JCOREConfiguration shared].heartbeatInterval;
536
+ if (interval <= 0) {
537
+ interval = 240.0;
538
+ }
539
+ uint64_t intervalNs = (uint64_t)(interval * (double)NSEC_PER_SEC);
540
+ dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, _sessionQueue);
541
+ dispatch_source_set_timer(timer,
542
+ dispatch_time(DISPATCH_TIME_NOW, (int64_t)intervalNs),
543
+ intervalNs,
544
+ (uint64_t)(1 * NSEC_PER_SEC));
545
+ __weak typeof(self) weakSelf = self;
546
+ dispatch_source_set_event_handler(timer, ^{
547
+ __strong typeof(weakSelf) strongSelf = weakSelf;
548
+ if (!strongSelf || !strongSelf->_connected || !strongSelf->_loggedIn) {
549
+ return;
550
+ }
551
+ NSData *hb = [JCOREWireProtocol buildHeartbeatPayloadWithPushStopped:[JCOREConfiguration shared].pushStopped];
552
+ [strongSelf sendRawCommandLocked:JCOREWireCommandHeartbeat version:8 bodyData:hb completion:nil];
553
+ });
554
+ _heartbeatTimer = timer;
555
+ dispatch_resume(timer);
556
+ }
557
+
558
+ - (void)stopHeartbeatLocked {
559
+ if (_heartbeatTimer != nil) {
560
+ dispatch_source_cancel(_heartbeatTimer);
561
+ _heartbeatTimer = nil;
562
+ }
563
+ }
564
+
565
+ - (void)sendHeartbeatNowWithCompletion:(JCORETcpResponseHandler)completion {
566
+ dispatch_async(_sessionQueue, ^{
567
+ NSData *hb = [JCOREWireProtocol buildHeartbeatPayloadWithPushStopped:[JCOREConfiguration shared].pushStopped];
568
+ [self sendRawCommandLocked:JCOREWireCommandHeartbeat version:8 bodyData:hb completion:completion];
569
+ });
570
+ }
571
+
572
+ - (void)receiveLoopForConnection:(nw_connection_t)connection {
573
+ __weak typeof(self) weakSelf = self;
574
+ nw_connection_receive(connection, 1, 65536, ^(dispatch_data_t content, nw_content_context_t context, bool is_complete, nw_error_t error) {
575
+ (void)context;
576
+ __strong typeof(weakSelf) strongSelf = weakSelf;
577
+ if (!strongSelf || strongSelf->_connection != connection) {
578
+ return;
579
+ }
580
+ if (content != nil) {
581
+ NSData *chunk = (NSData *)content;
582
+ if (chunk.length > 0) {
583
+ [strongSelf->_receiveBuffer appendData:chunk];
584
+ NSArray<JCOREWireFrame *> *frames = [JCOREWireProtocol decodeServerFramesFromStreamBuffer:strongSelf->_receiveBuffer
585
+ defaultUid:[JCOREConfiguration shared].uid];
586
+ for (JCOREWireFrame *frame in frames) {
587
+ [strongSelf handleDecodedFrameLocked:frame];
588
+ }
589
+ }
590
+ }
591
+ if (error == nil && !is_complete) {
592
+ [strongSelf receiveLoopForConnection:connection];
593
+ } else if (is_complete || error != nil) {
594
+ BOOL wasConnected = strongSelf->_connected;
595
+ strongSelf->_connecting = NO;
596
+ strongSelf->_connected = NO;
597
+ strongSelf->_loggedIn = NO;
598
+ [strongSelf stopHeartbeatLocked];
599
+ if (strongSelf->_inFlightRequests.count > 0) {
600
+ NSError *closeErr = [NSError errorWithDomain:@"cn.jiguang.jpush"
601
+ code:6002
602
+ userInfo:@{NSLocalizedDescriptionKey: @"Connection closed"}];
603
+ [strongSelf failAllInFlightRequestsLockedWithError:closeErr];
604
+ }
605
+ if (wasConnected && strongSelf->_connection == connection) {
606
+ [strongSelf postNotificationOnMain:kJPFNetworkDidCloseNotification userInfo:nil];
607
+ if (!strongSelf->_userDisconnected && ![JCOREConfiguration shared].pushStopped && !strongSelf->_connecting) {
608
+ [strongSelf scheduleReconnectLocked];
609
+ }
610
+ }
611
+ }
612
+ });
613
+ }
614
+
615
+ - (void)handleDecodedFrameLocked:(JCOREWireFrame *)frame {
616
+ if (frame.command == JCOREWireCommandPushMessage) {
617
+ JCOREPushEnvelope *envelope = [JCOREWireProtocol parsePushEnvelope:frame];
618
+ if (envelope != nil) {
619
+ [JCOREConfiguration logInfo:[NSString stringWithFormat:@"TCP push message received msgType=%u msgId=%llu",
620
+ envelope.messageType, envelope.messageId]];
621
+ [self sendReceiptLockedForMessageType:envelope.messageType
622
+ messageId:envelope.messageId
623
+ requestId:frame.requestId];
624
+ NSMutableDictionary *payload = [NSMutableDictionary dictionary];
625
+ if ([envelope.jsonPayload isKindOfClass:[NSDictionary class]]) {
626
+ [payload addEntriesFromDictionary:envelope.jsonPayload];
627
+ }
628
+ if (payload[@"_j_msgid"] == nil) {
629
+ payload[@"_j_msgid"] = @(envelope.messageId);
630
+ }
631
+ if (payload[@"content"] == nil && envelope.content != nil) {
632
+ payload[@"content"] = envelope.content;
633
+ }
634
+ [self postNotificationOnMain:kJPFNetworkDidReceiveMessageNotification userInfo:[payload copy]];
635
+ }
636
+ return;
637
+ }
638
+
639
+ if (frame.command == JCOREWireCommandCtrlCommand) {
640
+ JCORECtrlEnvelope *ctrl = [JCOREWireProtocol parseCtrlEnvelope:frame];
641
+ if (ctrl != nil) {
642
+ NSData *ackBody = [JCOREWireProtocol buildCtrlAckPayloadWithStatusCode:0 requestId:ctrl.requestId];
643
+ [self sendPacketWithExplicitRequestIdLocked:(frame.requestId != 0 ? frame.requestId : [[JCOREConfiguration shared] nextRequestId])
644
+ command:JCOREWireCommandCtrlCommand
645
+ version:1
646
+ bodyData:ackBody];
647
+ NSMutableDictionary *info = [NSMutableDictionary dictionary];
648
+ info[@"requestId"] = @(ctrl.requestId);
649
+ if (ctrl.jsonPayload != nil) {
650
+ info[@"payload"] = ctrl.jsonPayload;
651
+ }
652
+ [self postNotificationOnMain:@"kJPFNetworkDidReceiveCtrlCommandNotification" userInfo:info];
653
+ }
654
+ return;
655
+ }
656
+
657
+ NSNumber *key = @(frame.requestId);
658
+ JCOREInFlightRequest *inFlight = _inFlightRequests[key];
659
+ if (inFlight != nil) {
660
+ [inFlight cancelTimers];
661
+ [_inFlightRequests removeObjectForKey:key];
662
+ if (inFlight.completion != nil) {
663
+ inFlight.completion(frame, nil);
664
+ }
665
+ }
666
+ }
667
+
668
+ - (void)reportDeviceTokenIfNeeded {
669
+ dispatch_async(_sessionQueue, ^{
670
+ [self reportDeviceTokenLocked];
671
+ });
672
+ }
673
+
674
+ - (void)reportDeviceTokenLocked {
675
+ NSString *tokenHex = [JCOREConfiguration shared].deviceTokenHex;
676
+ if (tokenHex.length == 0) {
677
+ return;
678
+ }
679
+ if (!_connected || !_loggedIn) {
680
+ return;
681
+ }
682
+ if ([_lastReportedDeviceTokenHex isEqualToString:tokenHex]) {
683
+ return;
684
+ }
685
+ _lastReportedDeviceTokenHex = [tokenHex copy];
686
+ NSData *body = [JCOREWireProtocol buildDeviceTokenPayloadWithTokenHex:tokenHex];
687
+ [self sendRawCommandLocked:JCOREWireCommandDeviceToken version:3 bodyData:body completion:nil];
688
+ }
689
+
690
+ - (void)reportVoipTokenIfNeeded {
691
+ dispatch_async(_sessionQueue, ^{
692
+ [self reportVoipTokenLocked];
693
+ });
694
+ }
695
+
696
+ - (void)reportVoipTokenLocked {
697
+ NSString *voipHex = [JCOREConfiguration shared].voipTokenHex;
698
+ if (voipHex.length == 0) {
699
+ return;
700
+ }
701
+ if (!_connected || !_loggedIn) {
702
+ return;
703
+ }
704
+ if ([_lastReportedVoipTokenHex isEqualToString:voipHex]) {
705
+ return;
706
+ }
707
+ _lastReportedVoipTokenHex = [voipHex copy];
708
+ NSData *body = [JCOREWireProtocol buildVoipTokenPayloadWithTokenHex:voipHex];
709
+ [self sendRawCommandLocked:JCOREWireCommandVoipToken version:2 bodyData:body completion:nil];
710
+ }
711
+
712
+ - (void)sendReceiptForMessageType:(uint8_t)messageType messageId:(uint64_t)messageId {
713
+ dispatch_async(_sessionQueue, ^{
714
+ [self sendReceiptLockedForMessageType:messageType messageId:messageId requestId:0];
715
+ });
716
+ }
717
+
718
+ - (void)sendReceiptLockedForMessageType:(uint8_t)messageType
719
+ messageId:(uint64_t)messageId
720
+ requestId:(uint16_t)requestId {
721
+ if (!_connected || messageId == 0) {
722
+ return;
723
+ }
724
+ NSData *body = [JCOREWireProtocol buildMessageAckPayloadWithMessageType:messageType messageId:messageId];
725
+ uint16_t rid = (requestId != 0) ? requestId : [[JCOREConfiguration shared] nextRequestId];
726
+ [self sendPacketWithExplicitRequestIdLocked:rid
727
+ command:JCOREWireCommandMessageAck
728
+ version:3
729
+ bodyData:body];
730
+ }
731
+
732
+ - (void)sendPacketWithExplicitRequestIdLocked:(uint16_t)rid
733
+ command:(uint8_t)command
734
+ version:(uint8_t)version
735
+ bodyData:(NSData *)bodyData {
736
+ if (!_connected || _connection == nil) {
737
+ return;
738
+ }
739
+ JCOREConfiguration *config = [JCOREConfiguration shared];
740
+ NSData *packet = [JCOREWireProtocol encodeFrameWithCommand:command
741
+ version:version
742
+ requestId:rid
743
+ sessionId:_sessionId
744
+ uid:config.uid
745
+ bodyData:bodyData];
746
+ if (packet.length == 0) {
747
+ return;
748
+ }
749
+ dispatch_data_t dispatchPacket = dispatch_data_create(packet.bytes,
750
+ packet.length,
751
+ _sessionQueue,
752
+ DISPATCH_DATA_DESTRUCTOR_DEFAULT);
753
+ nw_connection_send(_connection, dispatchPacket, NW_CONNECTION_DEFAULT_MESSAGE_CONTEXT, true, ^(nw_error_t error) {
754
+ (void)error;
755
+ });
756
+ }
757
+
758
+ - (void)sendCommand:(uint8_t)command
759
+ version:(uint8_t)version
760
+ bodyData:(NSData *)bodyData
761
+ completion:(JCORETcpResponseHandler)completion {
762
+ dispatch_async(_sessionQueue, ^{
763
+ if (command != JCOREWireCommandRegister &&
764
+ command != JCOREWireCommandLogin &&
765
+ (!self->_connected || !self->_loggedIn)) {
766
+ JCOREQueuedWireRequest *queued = [[JCOREQueuedWireRequest alloc] init];
767
+ queued.command = command;
768
+ queued.version = version;
769
+ queued.bodyData = bodyData ?: [NSData data];
770
+ queued.completion = completion;
771
+ [self->_queuedRequests addObject:queued];
772
+ if (!self->_connected && !self->_connecting && !self->_userDisconnected) {
773
+ [self startLockedForceReconnect:NO];
774
+ }
775
+ return;
776
+ }
777
+ [self sendRawCommandLocked:command version:version bodyData:bodyData completion:completion];
778
+ });
779
+ }
780
+
781
+ - (void)flushQueuedRequestsLocked {
782
+ if (_queuedRequests.count == 0) {
783
+ return;
784
+ }
785
+ NSArray<JCOREQueuedWireRequest *> *toSend = [_queuedRequests copy];
786
+ [_queuedRequests removeAllObjects];
787
+ for (JCOREQueuedWireRequest *item in toSend) {
788
+ [self sendRawCommandLocked:item.command
789
+ version:item.version
790
+ bodyData:item.bodyData
791
+ completion:item.completion];
792
+ }
793
+ }
794
+
795
+ - (void)sendRawCommandLocked:(uint8_t)command
796
+ version:(uint8_t)version
797
+ bodyData:(NSData *)bodyData
798
+ completion:(JCORETcpResponseHandler)completion {
799
+ JCOREConfiguration *config = [JCOREConfiguration shared];
800
+ if (!_connected || _connection == nil) {
801
+ if (completion != nil) {
802
+ NSError *err = [NSError errorWithDomain:@"cn.jiguang.jpush"
803
+ code:6002
804
+ userInfo:@{NSLocalizedDescriptionKey: @"Not connected"}];
805
+ completion(nil, err);
806
+ }
807
+ return;
808
+ }
809
+
810
+ uint16_t rid = [config nextRequestId];
811
+ uint64_t packetUid = (command == JCOREWireCommandRegister) ? 0ULL : config.uid;
812
+ NSData *packet = [JCOREWireProtocol encodeFrameWithCommand:command
813
+ version:version
814
+ requestId:rid
815
+ sessionId:_sessionId
816
+ uid:packetUid
817
+ bodyData:bodyData];
818
+ if (packet.length == 0) {
819
+ if (completion != nil) {
820
+ NSError *err = [NSError errorWithDomain:@"cn.jiguang.jcore" code:-1002 userInfo:nil];
821
+ completion(nil, err);
822
+ }
823
+ return;
824
+ }
825
+
826
+ if (completion != nil) {
827
+ NSNumber *ridKey = @(rid);
828
+ JCOREInFlightRequest *inFlight = [[JCOREInFlightRequest alloc] init];
829
+ inFlight.requestId = rid;
830
+ inFlight.command = command;
831
+ inFlight.version = version;
832
+ inFlight.packetData = packet;
833
+ inFlight.completion = completion;
834
+
835
+ NSTimeInterval timeoutSec = config.requestTimeoutInterval > 0 ? config.requestTimeoutInterval : 20.0;
836
+ NSTimeInterval resendSec = config.requestResendInterval > 0 ? config.requestResendInterval : 10.0;
837
+
838
+ if (resendSec > 0 && resendSec < timeoutSec) {
839
+ uint64_t resendNs = (uint64_t)(resendSec * (double)NSEC_PER_SEC);
840
+ dispatch_source_t rTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, _sessionQueue);
841
+ dispatch_source_set_timer(rTimer,
842
+ dispatch_time(DISPATCH_TIME_NOW, (int64_t)resendNs),
843
+ DISPATCH_TIME_FOREVER,
844
+ (uint64_t)(0.05 * NSEC_PER_SEC));
845
+ __weak typeof(self) weakSelf = self;
846
+ dispatch_source_set_event_handler(rTimer, ^{
847
+ __strong typeof(weakSelf) strongSelf = weakSelf;
848
+ if (!strongSelf) {
849
+ return;
850
+ }
851
+ JCOREInFlightRequest *req = strongSelf->_inFlightRequests[ridKey];
852
+ if (req != nil && strongSelf->_connected && strongSelf->_connection != nil) {
853
+ dispatch_data_t resendData = dispatch_data_create(req.packetData.bytes,
854
+ req.packetData.length,
855
+ strongSelf->_sessionQueue,
856
+ DISPATCH_DATA_DESTRUCTOR_DEFAULT);
857
+ nw_connection_send(strongSelf->_connection, resendData, NW_CONNECTION_DEFAULT_MESSAGE_CONTEXT, true, ^(nw_error_t error) {
858
+ (void)error;
859
+ });
860
+ }
861
+ });
862
+ inFlight.resendTimer = rTimer;
863
+ dispatch_resume(rTimer);
864
+ }
865
+
866
+ uint64_t timeoutNs = (uint64_t)(timeoutSec * (double)NSEC_PER_SEC);
867
+ dispatch_source_t tTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, _sessionQueue);
868
+ dispatch_source_set_timer(tTimer,
869
+ dispatch_time(DISPATCH_TIME_NOW, (int64_t)timeoutNs),
870
+ DISPATCH_TIME_FOREVER,
871
+ (uint64_t)(0.05 * NSEC_PER_SEC));
872
+ __weak typeof(self) weakSelf = self;
873
+ dispatch_source_set_event_handler(tTimer, ^{
874
+ __strong typeof(weakSelf) strongSelf = weakSelf;
875
+ if (!strongSelf) {
876
+ return;
877
+ }
878
+ JCOREInFlightRequest *timedOut = strongSelf->_inFlightRequests[ridKey];
879
+ if (timedOut != nil) {
880
+ [timedOut cancelTimers];
881
+ [strongSelf->_inFlightRequests removeObjectForKey:ridKey];
882
+ if (timedOut.completion != nil) {
883
+ NSError *timeoutErr = [NSError errorWithDomain:@"cn.jiguang.jpush"
884
+ code:6002
885
+ userInfo:@{NSLocalizedDescriptionKey: @"Request timed out"}];
886
+ timedOut.completion(nil, timeoutErr);
887
+ }
888
+ }
889
+ });
890
+ inFlight.timeoutTimer = tTimer;
891
+ dispatch_resume(tTimer);
892
+
893
+ _inFlightRequests[ridKey] = inFlight;
894
+ }
895
+
896
+ dispatch_data_t dispatchPacket = dispatch_data_create(packet.bytes,
897
+ packet.length,
898
+ _sessionQueue,
899
+ DISPATCH_DATA_DESTRUCTOR_DEFAULT);
900
+ nw_connection_send(_connection, dispatchPacket, NW_CONNECTION_DEFAULT_MESSAGE_CONTEXT, true, ^(nw_error_t error) {
901
+ (void)error;
902
+ });
903
+ }
904
+
905
+ - (void)failAllInFlightRequestsLockedWithError:(NSError *)error {
906
+ NSDictionary<NSNumber *, JCOREInFlightRequest *> *snapshot = [_inFlightRequests copy];
907
+ [_inFlightRequests removeAllObjects];
908
+ [snapshot enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, JCOREInFlightRequest *req, BOOL *stop) {
909
+ (void)key;
910
+ (void)stop;
911
+ [req cancelTimers];
912
+ if (req.completion != nil) {
913
+ req.completion(nil, error);
914
+ }
915
+ }];
916
+ }
917
+
918
+ - (void)tearDownConnectionLocked {
919
+ [self cancelConnectTimeoutTimerLocked];
920
+ [self stopHeartbeatLocked];
921
+ if (_connection != nil) {
922
+ nw_connection_cancel(_connection);
923
+ _connection = nil;
924
+ }
925
+ [_receiveBuffer setLength:0];
926
+ _connected = NO;
927
+ _loggedIn = NO;
928
+ if (_inFlightRequests.count > 0) {
929
+ NSError *err = [NSError errorWithDomain:@"cn.jiguang.jpush"
930
+ code:6002
931
+ userInfo:@{NSLocalizedDescriptionKey: @"Connection closed"}];
932
+ [self failAllInFlightRequestsLockedWithError:err];
933
+ }
934
+ }
935
+
936
+ - (void)disconnect {
937
+ dispatch_async(_sessionQueue, ^{
938
+ self->_userDisconnected = YES;
939
+ [self cancelReconnectTimerLocked];
940
+ BOOL wasConnected = self->_connected;
941
+ self->_connecting = NO;
942
+ [self tearDownConnectionLocked];
943
+ NSError *err = [NSError errorWithDomain:@"cn.jiguang.jpush"
944
+ code:6002
945
+ userInfo:@{NSLocalizedDescriptionKey: @"Disconnected"}];
946
+ [self failAllInFlightRequestsLockedWithError:err];
947
+ if (wasConnected) {
948
+ [self postNotificationOnMain:kJPFNetworkDidCloseNotification userInfo:nil];
949
+ }
950
+ });
951
+ }
952
+
953
+ @end
954
+
955
+ @implementation JCORETcpClient
956
+ @end