@onekeyfe/react-native-network-throttle 3.0.69 → 3.0.73
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.
package/README.md
CHANGED
|
@@ -2,4 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
React Native native network throttle for OneKey iOS and Android development settings.
|
|
4
4
|
|
|
5
|
+
Current scope is an RN HTTP response latency gate. It does not emulate download
|
|
6
|
+
throughput, upload throughput, offline mode, WebView traffic, or third-party
|
|
7
|
+
native networking stacks.
|
|
8
|
+
|
|
5
9
|
This package only owns native request throttling. Product settings, persistence, and UI controls should remain in the host app.
|
|
@@ -38,9 +38,16 @@ internal object NetworkThrottle {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
fun setConfig(config: ReadableMap): WritableMap {
|
|
41
|
-
val
|
|
41
|
+
val hasEnabled = config.hasKey("enabled") && !config.isNull("enabled")
|
|
42
|
+
val hasLatencyMs = config.hasKey("latencyMs") && !config.isNull("latencyMs")
|
|
43
|
+
val nextEnabled =
|
|
44
|
+
if (hasEnabled) config.getBoolean("enabled") else enabled.get()
|
|
42
45
|
var nextLatencyMs =
|
|
43
|
-
if (
|
|
46
|
+
if (hasLatencyMs) {
|
|
47
|
+
config.getDouble("latencyMs")
|
|
48
|
+
} else {
|
|
49
|
+
latencyNanos.get() / 1_000_000.0
|
|
50
|
+
}
|
|
44
51
|
if (nextLatencyMs <= 0) {
|
|
45
52
|
nextLatencyMs = DEFAULT_LATENCY_MS
|
|
46
53
|
}
|
|
@@ -66,19 +73,27 @@ internal object NetworkThrottle {
|
|
|
66
73
|
|
|
67
74
|
private class LatencyInterceptor : Interceptor {
|
|
68
75
|
override fun intercept(chain: Interceptor.Chain): Response {
|
|
76
|
+
val requestStartNanos = System.nanoTime()
|
|
69
77
|
val delayNanos = getLatencyNanos()
|
|
78
|
+
val response = chain.proceed(chain.request())
|
|
70
79
|
if (delayNanos > 0) {
|
|
71
80
|
try {
|
|
72
|
-
val
|
|
81
|
+
val elapsedNanos = System.nanoTime() - requestStartNanos
|
|
82
|
+
val remainingDelayNanos = delayNanos - elapsedNanos
|
|
83
|
+
if (remainingDelayNanos <= 0) {
|
|
84
|
+
return response
|
|
85
|
+
}
|
|
86
|
+
val delayMs = TimeUnit.NANOSECONDS.toMillis(remainingDelayNanos)
|
|
73
87
|
val remainingNanos =
|
|
74
|
-
(
|
|
88
|
+
(remainingDelayNanos - TimeUnit.MILLISECONDS.toNanos(delayMs)).toInt()
|
|
75
89
|
Thread.sleep(delayMs, remainingNanos)
|
|
76
90
|
} catch (error: InterruptedException) {
|
|
91
|
+
response.close()
|
|
77
92
|
Thread.currentThread().interrupt()
|
|
78
93
|
throw IOException("Interrupted while applying OneKey network throttle", error)
|
|
79
94
|
}
|
|
80
95
|
}
|
|
81
|
-
return
|
|
96
|
+
return response
|
|
82
97
|
}
|
|
83
98
|
}
|
|
84
99
|
}
|
|
@@ -66,6 +66,16 @@ static atomic_llong _oneKeyNetworkThrottleLatencyMicros = ATOMIC_VAR_INIT(562500
|
|
|
66
66
|
@property (nonatomic, strong) NSURLSessionDataTask *task;
|
|
67
67
|
@property (nonatomic, strong) NSURLSession *session;
|
|
68
68
|
@property (atomic, assign) BOOL stopped;
|
|
69
|
+
@property (nonatomic, assign) CFAbsoluteTime requestStartTime;
|
|
70
|
+
@property (nonatomic, assign) NSTimeInterval latencySeconds;
|
|
71
|
+
@property (atomic, assign) BOOL responseDelivered;
|
|
72
|
+
@property (nonatomic, strong) NSMutableArray<NSData *> *pendingData;
|
|
73
|
+
@property (nonatomic, copy) void (^pendingResponseCompletionHandler)(NSURLSessionResponseDisposition disposition);
|
|
74
|
+
- (NSTimeInterval)remainingLatencyDelay;
|
|
75
|
+
- (void)deliverResponse:(NSURLResponse *)response;
|
|
76
|
+
- (void)flushPendingData;
|
|
77
|
+
- (void)cancelPendingResponseCompletionHandler;
|
|
78
|
+
- (void)invalidateSessionAndClearTaskWithCancel:(BOOL)cancel;
|
|
69
79
|
@end
|
|
70
80
|
|
|
71
81
|
@implementation OneKeyNetworkThrottleURLProtocol
|
|
@@ -92,28 +102,100 @@ static atomic_llong _oneKeyNetworkThrottleLatencyMicros = ATOMIC_VAR_INIT(562500
|
|
|
92
102
|
NSMutableURLRequest *request = [self.request mutableCopy];
|
|
93
103
|
[NSURLProtocol setProperty:@YES forKey:OneKeyNetworkThrottleHandledKey inRequest:request];
|
|
94
104
|
|
|
95
|
-
|
|
96
|
-
|
|
105
|
+
self.requestStartTime = CFAbsoluteTimeGetCurrent();
|
|
106
|
+
self.latencySeconds = [OneKeyNetworkThrottleState latencyMs] / 1000.0;
|
|
107
|
+
self.pendingData = [NSMutableArray array];
|
|
108
|
+
|
|
109
|
+
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
|
|
110
|
+
NSNumber *useWifiOnly = [[NSBundle mainBundle].infoDictionary objectForKey:@"ReactNetworkForceWifiOnly"];
|
|
111
|
+
if (useWifiOnly) {
|
|
112
|
+
configuration.allowsCellularAccess = ![useWifiOnly boolValue];
|
|
113
|
+
}
|
|
114
|
+
configuration.HTTPShouldSetCookies = YES;
|
|
115
|
+
configuration.HTTPCookieAcceptPolicy = NSHTTPCookieAcceptPolicyAlways;
|
|
116
|
+
configuration.HTTPCookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
|
|
117
|
+
self.session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
|
|
118
|
+
self.task = [self.session dataTaskWithRequest:request];
|
|
119
|
+
[self.task resume];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
- (void)stopLoading
|
|
123
|
+
{
|
|
124
|
+
self.stopped = YES;
|
|
125
|
+
[self cancelPendingResponseCompletionHandler];
|
|
126
|
+
[self invalidateSessionAndClearTaskWithCancel:YES];
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
- (NSTimeInterval)remainingLatencyDelay
|
|
130
|
+
{
|
|
131
|
+
NSTimeInterval elapsed = CFAbsoluteTimeGetCurrent() - self.requestStartTime;
|
|
132
|
+
NSTimeInterval remainingDelay = self.latencySeconds - elapsed;
|
|
133
|
+
return remainingDelay > 0 ? remainingDelay : 0;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
- (void)deliverResponse:(NSURLResponse *)response
|
|
137
|
+
{
|
|
138
|
+
void (^completionHandler)(NSURLSessionResponseDisposition disposition) = nil;
|
|
139
|
+
@synchronized (self) {
|
|
140
|
+
completionHandler = self.pendingResponseCompletionHandler;
|
|
141
|
+
self.pendingResponseCompletionHandler = nil;
|
|
142
|
+
}
|
|
143
|
+
if (!completionHandler) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
if (self.stopped) {
|
|
147
|
+
completionHandler(NSURLSessionResponseCancel);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
self.responseDelivered = YES;
|
|
151
|
+
[self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
|
|
152
|
+
[self flushPendingData];
|
|
153
|
+
completionHandler(NSURLSessionResponseAllow);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
- (void)flushPendingData
|
|
157
|
+
{
|
|
158
|
+
NSArray<NSData *> *pendingData = nil;
|
|
159
|
+
@synchronized (self) {
|
|
160
|
+
pendingData = [self.pendingData copy];
|
|
161
|
+
[self.pendingData removeAllObjects];
|
|
162
|
+
}
|
|
163
|
+
for (NSData *data in pendingData) {
|
|
97
164
|
if (self.stopped) {
|
|
98
165
|
return;
|
|
99
166
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
configuration.HTTPCookieAcceptPolicy = NSHTTPCookieAcceptPolicyAlways;
|
|
103
|
-
configuration.HTTPCookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
|
|
104
|
-
self.session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
|
|
105
|
-
self.task = [self.session dataTaskWithRequest:request];
|
|
106
|
-
[self.task resume];
|
|
107
|
-
});
|
|
167
|
+
[self.client URLProtocol:self didLoadData:data];
|
|
168
|
+
}
|
|
108
169
|
}
|
|
109
170
|
|
|
110
|
-
- (void)
|
|
171
|
+
- (void)cancelPendingResponseCompletionHandler
|
|
111
172
|
{
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
173
|
+
void (^completionHandler)(NSURLSessionResponseDisposition disposition) = nil;
|
|
174
|
+
@synchronized (self) {
|
|
175
|
+
completionHandler = self.pendingResponseCompletionHandler;
|
|
176
|
+
self.pendingResponseCompletionHandler = nil;
|
|
177
|
+
}
|
|
178
|
+
if (completionHandler) {
|
|
179
|
+
completionHandler(NSURLSessionResponseCancel);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
- (void)invalidateSessionAndClearTaskWithCancel:(BOOL)cancel
|
|
184
|
+
{
|
|
185
|
+
NSURLSessionDataTask *task = nil;
|
|
186
|
+
NSURLSession *session = nil;
|
|
187
|
+
@synchronized (self) {
|
|
188
|
+
task = self.task;
|
|
189
|
+
session = self.session;
|
|
190
|
+
self.task = nil;
|
|
191
|
+
self.session = nil;
|
|
192
|
+
}
|
|
193
|
+
if (cancel) {
|
|
194
|
+
[task cancel];
|
|
195
|
+
[session invalidateAndCancel];
|
|
196
|
+
} else {
|
|
197
|
+
[session finishTasksAndInvalidate];
|
|
198
|
+
}
|
|
117
199
|
}
|
|
118
200
|
|
|
119
201
|
- (void)URLSession:(NSURLSession *)session
|
|
@@ -131,22 +213,46 @@ static atomic_llong _oneKeyNetworkThrottleLatencyMicros = ATOMIC_VAR_INIT(562500
|
|
|
131
213
|
didReceiveResponse:(NSURLResponse *)response
|
|
132
214
|
completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
|
|
133
215
|
{
|
|
134
|
-
|
|
135
|
-
|
|
216
|
+
@synchronized (self) {
|
|
217
|
+
self.pendingResponseCompletionHandler = completionHandler;
|
|
218
|
+
}
|
|
219
|
+
NSTimeInterval delay = [self remainingLatencyDelay];
|
|
220
|
+
if (delay <= 0) {
|
|
221
|
+
[self deliverResponse:response];
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{
|
|
225
|
+
[self deliverResponse:response];
|
|
226
|
+
});
|
|
136
227
|
}
|
|
137
228
|
|
|
138
229
|
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
|
|
139
230
|
{
|
|
140
|
-
|
|
231
|
+
if (self.stopped) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
if (self.responseDelivered) {
|
|
235
|
+
[self.client URLProtocol:self didLoadData:data];
|
|
236
|
+
} else {
|
|
237
|
+
@synchronized (self) {
|
|
238
|
+
[self.pendingData addObject:data];
|
|
239
|
+
}
|
|
240
|
+
}
|
|
141
241
|
}
|
|
142
242
|
|
|
143
243
|
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
|
|
144
244
|
{
|
|
145
|
-
if (
|
|
146
|
-
[self
|
|
147
|
-
} else {
|
|
148
|
-
[self.client URLProtocolDidFinishLoading:self];
|
|
245
|
+
if (!self.responseDelivered) {
|
|
246
|
+
[self cancelPendingResponseCompletionHandler];
|
|
149
247
|
}
|
|
248
|
+
if (!self.stopped) {
|
|
249
|
+
if (error) {
|
|
250
|
+
[self.client URLProtocol:self didFailWithError:error];
|
|
251
|
+
} else {
|
|
252
|
+
[self.client URLProtocolDidFinishLoading:self];
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
[self invalidateSessionAndClearTaskWithCancel:NO];
|
|
150
256
|
}
|
|
151
257
|
|
|
152
258
|
@end
|
|
@@ -197,9 +303,12 @@ RCT_REMAP_METHOD(getConfig, getConfigWithResolver:(RCTPromiseResolveBlock)resolv
|
|
|
197
303
|
|
|
198
304
|
RCT_REMAP_METHOD(setConfig, setConfig:(NSDictionary *)config resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
|
199
305
|
{
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
306
|
+
id enabledValue = config[@"enabled"];
|
|
307
|
+
BOOL enabled =
|
|
308
|
+
enabledValue != nil && enabledValue != [NSNull null] ? [enabledValue boolValue] : [OneKeyNetworkThrottleState isEnabled];
|
|
309
|
+
id latencyValue = config[@"latencyMs"];
|
|
310
|
+
NSTimeInterval latencyMs =
|
|
311
|
+
latencyValue != nil && latencyValue != [NSNull null] ? [latencyValue doubleValue] : [OneKeyNetworkThrottleState latencyMs];
|
|
203
312
|
resolve([OneKeyNetworkThrottleState setEnabled:enabled latencyMs:latencyMs]);
|
|
204
313
|
}
|
|
205
314
|
|
package/lib/module/index.js
CHANGED
|
@@ -7,7 +7,17 @@ const LINKING_ERROR = `The package '@onekeyfe/react-native-network-throttle' doe
|
|
|
7
7
|
default: ''
|
|
8
8
|
}) + '- rebuild the app after installing the package';
|
|
9
9
|
const nativeModule = NativeModules.OneKeyNetworkThrottle;
|
|
10
|
-
export const NetworkThrottle = nativeModule ?
|
|
10
|
+
export const NetworkThrottle = nativeModule ? {
|
|
11
|
+
getConfig: () => nativeModule.getConfig(),
|
|
12
|
+
setConfig: async config => {
|
|
13
|
+
const currentConfig = await nativeModule.getConfig();
|
|
14
|
+
return nativeModule.setConfig({
|
|
15
|
+
enabled: config.enabled ?? currentConfig.enabled,
|
|
16
|
+
profile: config.profile ?? currentConfig.profile,
|
|
17
|
+
latencyMs: config.latencyMs ?? currentConfig.latencyMs
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
} : new Proxy({}, {
|
|
11
21
|
get() {
|
|
12
22
|
throw new Error(LINKING_ERROR);
|
|
13
23
|
}
|
|
@@ -5,10 +5,10 @@ export type NetworkThrottleConfig = {
|
|
|
5
5
|
latencyMs: number;
|
|
6
6
|
};
|
|
7
7
|
export declare const NETWORK_THROTTLE_SLOW_4G_LATENCY_MS = 562.5;
|
|
8
|
-
type
|
|
8
|
+
export type NetworkThrottleModule = {
|
|
9
9
|
getConfig: () => Promise<NetworkThrottleConfig>;
|
|
10
10
|
setConfig: (config: Partial<NetworkThrottleConfig>) => Promise<NetworkThrottleConfig>;
|
|
11
11
|
};
|
|
12
|
-
export declare const NetworkThrottle:
|
|
12
|
+
export declare const NetworkThrottle: NetworkThrottleModule;
|
|
13
13
|
export default NetworkThrottle;
|
|
14
14
|
//# sourceMappingURL=index.d.ts.map
|
package/package.json
CHANGED
package/src/index.tsx
CHANGED
|
@@ -11,6 +11,11 @@ export type NetworkThrottleConfig = {
|
|
|
11
11
|
export const NETWORK_THROTTLE_SLOW_4G_LATENCY_MS = 562.5;
|
|
12
12
|
|
|
13
13
|
type NativeNetworkThrottleModule = {
|
|
14
|
+
getConfig: () => Promise<NetworkThrottleConfig>;
|
|
15
|
+
setConfig: (config: NetworkThrottleConfig) => Promise<NetworkThrottleConfig>;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type NetworkThrottleModule = {
|
|
14
19
|
getConfig: () => Promise<NetworkThrottleConfig>;
|
|
15
20
|
setConfig: (
|
|
16
21
|
config: Partial<NetworkThrottleConfig>
|
|
@@ -26,8 +31,18 @@ const nativeModule = NativeModules.OneKeyNetworkThrottle as
|
|
|
26
31
|
| NativeNetworkThrottleModule
|
|
27
32
|
| undefined;
|
|
28
33
|
|
|
29
|
-
export const NetworkThrottle:
|
|
30
|
-
?
|
|
34
|
+
export const NetworkThrottle: NetworkThrottleModule = nativeModule
|
|
35
|
+
? {
|
|
36
|
+
getConfig: () => nativeModule.getConfig(),
|
|
37
|
+
setConfig: async (config) => {
|
|
38
|
+
const currentConfig = await nativeModule.getConfig();
|
|
39
|
+
return nativeModule.setConfig({
|
|
40
|
+
enabled: config.enabled ?? currentConfig.enabled,
|
|
41
|
+
profile: config.profile ?? currentConfig.profile,
|
|
42
|
+
latencyMs: config.latencyMs ?? currentConfig.latencyMs,
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
}
|
|
31
46
|
: (new Proxy(
|
|
32
47
|
{},
|
|
33
48
|
{
|
|
@@ -35,6 +50,6 @@ export const NetworkThrottle: NativeNetworkThrottleModule = nativeModule
|
|
|
35
50
|
throw new Error(LINKING_ERROR);
|
|
36
51
|
},
|
|
37
52
|
}
|
|
38
|
-
) as
|
|
53
|
+
) as NetworkThrottleModule);
|
|
39
54
|
|
|
40
55
|
export default NetworkThrottle;
|