@onekeyfe/react-native-network-throttle 3.0.81-alpha.8 → 3.0.82-alpha.0
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,8 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
React Native native network throttle for OneKey iOS and Android development settings.
|
|
4
4
|
|
|
5
|
-
Current scope is
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
Current scope is RN HTTP(S) latency and upload/download throughput. It does not
|
|
6
|
+
emulate offline mode, WebView traffic, or third-party native networking stacks.
|
|
7
|
+
|
|
8
|
+
`bypassUrlOrigins` excludes exact HTTP(S) origins from all throttling. Origins
|
|
9
|
+
are canonicalized with their effective port and registered additively for the
|
|
10
|
+
lifetime of the native process. This allows independently initialized React
|
|
11
|
+
Native runtimes to register local development servers without clearing each
|
|
12
|
+
other's configuration.
|
|
8
13
|
|
|
9
14
|
This package only owns native request throttling. Product settings, persistence, and UI controls should remain in the host app.
|
|
@@ -4,6 +4,7 @@ import android.content.Context
|
|
|
4
4
|
import android.util.Log
|
|
5
5
|
import com.facebook.react.bridge.Arguments
|
|
6
6
|
import com.facebook.react.bridge.ReadableMap
|
|
7
|
+
import com.facebook.react.bridge.ReadableType
|
|
7
8
|
import com.facebook.react.bridge.WritableMap
|
|
8
9
|
import com.facebook.react.modules.network.OkHttpClientProvider
|
|
9
10
|
import java.io.IOException
|
|
@@ -11,6 +12,9 @@ import java.io.InterruptedIOException
|
|
|
11
12
|
import java.util.concurrent.TimeUnit
|
|
12
13
|
import java.util.concurrent.atomic.AtomicBoolean
|
|
13
14
|
import java.util.concurrent.atomic.AtomicLong
|
|
15
|
+
import java.util.concurrent.atomic.AtomicReference
|
|
16
|
+
import okhttp3.HttpUrl
|
|
17
|
+
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
|
14
18
|
import okhttp3.Interceptor
|
|
15
19
|
import okhttp3.MediaType
|
|
16
20
|
import okhttp3.OkHttpClient
|
|
@@ -36,6 +40,7 @@ internal object NetworkThrottle {
|
|
|
36
40
|
private val downloadBps = AtomicLong(DEFAULT_THROUGHPUT_BPS.toLong())
|
|
37
41
|
private val uploadBps = AtomicLong(DEFAULT_THROUGHPUT_BPS.toLong())
|
|
38
42
|
private val installed = AtomicBoolean(false)
|
|
43
|
+
private val bypassUrlOrigins = AtomicReference<Set<String>>(emptySet())
|
|
39
44
|
|
|
40
45
|
fun install(context: Context) {
|
|
41
46
|
if (!installed.compareAndSet(false, true)) {
|
|
@@ -85,6 +90,19 @@ internal object NetworkThrottle {
|
|
|
85
90
|
if (nextUploadBps <= 0) {
|
|
86
91
|
nextUploadBps = DEFAULT_THROUGHPUT_BPS.toLong()
|
|
87
92
|
}
|
|
93
|
+
if (config.hasKey("bypassUrlOrigins") && !config.isNull("bypassUrlOrigins")) {
|
|
94
|
+
val origins = config.getArray("bypassUrlOrigins")
|
|
95
|
+
val normalizedOrigins = buildSet {
|
|
96
|
+
if (origins != null) {
|
|
97
|
+
for (index in 0 until origins.size()) {
|
|
98
|
+
if (origins.getType(index) == ReadableType.String) {
|
|
99
|
+
normalizeOrigin(origins.getString(index))?.let(::add)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
bypassUrlOrigins.updateAndGet { current -> current + normalizedOrigins }
|
|
105
|
+
}
|
|
88
106
|
|
|
89
107
|
enabled.set(nextEnabled)
|
|
90
108
|
latencyNanos.set((nextLatencyMs * 1_000_000.0).toLong())
|
|
@@ -104,6 +122,9 @@ internal object NetworkThrottle {
|
|
|
104
122
|
map.putDouble("latencyMs", latencyNanos.get() / 1_000_000.0)
|
|
105
123
|
map.putDouble("downloadBps", downloadBps.get().toDouble())
|
|
106
124
|
map.putDouble("uploadBps", uploadBps.get().toDouble())
|
|
125
|
+
val origins = Arguments.createArray()
|
|
126
|
+
bypassUrlOrigins.get().sorted().forEach(origins::pushString)
|
|
127
|
+
map.putArray("bypassUrlOrigins", origins)
|
|
107
128
|
return map
|
|
108
129
|
}
|
|
109
130
|
|
|
@@ -111,6 +132,21 @@ internal object NetworkThrottle {
|
|
|
111
132
|
private fun getDownloadBps(): Long = if (enabled.get()) downloadBps.get() else 0L
|
|
112
133
|
private fun getUploadBps(): Long = if (enabled.get()) uploadBps.get() else 0L
|
|
113
134
|
|
|
135
|
+
private fun canonicalOrigin(url: HttpUrl): String =
|
|
136
|
+
HttpUrl.Builder()
|
|
137
|
+
.scheme(url.scheme)
|
|
138
|
+
.host(url.host)
|
|
139
|
+
.port(url.port)
|
|
140
|
+
.build()
|
|
141
|
+
.toString()
|
|
142
|
+
.removeSuffix("/")
|
|
143
|
+
|
|
144
|
+
private fun normalizeOrigin(value: String?): String? =
|
|
145
|
+
value?.toHttpUrlOrNull()?.let(::canonicalOrigin)
|
|
146
|
+
|
|
147
|
+
private fun shouldBypass(requestUrl: HttpUrl): Boolean =
|
|
148
|
+
bypassUrlOrigins.get().contains(canonicalOrigin(requestUrl))
|
|
149
|
+
|
|
114
150
|
private fun sleepNanos(delayNanos: Long) {
|
|
115
151
|
if (delayNanos <= 0) {
|
|
116
152
|
return
|
|
@@ -201,9 +237,12 @@ internal object NetworkThrottle {
|
|
|
201
237
|
|
|
202
238
|
private class ThrottleInterceptor : Interceptor {
|
|
203
239
|
override fun intercept(chain: Interceptor.Chain): Response {
|
|
240
|
+
val request = chain.request()
|
|
241
|
+
if (shouldBypass(request.url)) {
|
|
242
|
+
return chain.proceed(request)
|
|
243
|
+
}
|
|
204
244
|
val requestStartNanos = System.nanoTime()
|
|
205
245
|
val delayNanos = getLatencyNanos()
|
|
206
|
-
val request = chain.request()
|
|
207
246
|
val requestBody = request.body
|
|
208
247
|
val activeUploadBps = getUploadBps()
|
|
209
248
|
val throttledRequest =
|
|
@@ -10,16 +10,32 @@ static const NSTimeInterval OneKeyNetworkThrottleDefaultLatencyMs = 562.5;
|
|
|
10
10
|
static const NSInteger OneKeyNetworkThrottleDefaultThroughputBps = 102 * 1024;
|
|
11
11
|
static const NSUInteger OneKeyNetworkThrottleMaxPendingDownloadBytes = 256 * 1024;
|
|
12
12
|
|
|
13
|
+
static NSString *OneKeyNetworkThrottleCanonicalOrigin(NSURL *url)
|
|
14
|
+
{
|
|
15
|
+
NSString *scheme = url.scheme.lowercaseString;
|
|
16
|
+
NSString *host = url.host.lowercaseString;
|
|
17
|
+
if ((!([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"])) || host.length == 0) {
|
|
18
|
+
return nil;
|
|
19
|
+
}
|
|
20
|
+
NSURLComponents *components = [[NSURLComponents alloc] init];
|
|
21
|
+
components.scheme = scheme;
|
|
22
|
+
components.host = host;
|
|
23
|
+
components.port = url.port ?: @([scheme isEqualToString:@"https"] ? 443 : 80);
|
|
24
|
+
return components.string;
|
|
25
|
+
}
|
|
26
|
+
|
|
13
27
|
@interface OneKeyNetworkThrottleState : NSObject
|
|
14
28
|
+ (NSDictionary *)currentConfig;
|
|
15
29
|
+ (BOOL)isEnabled;
|
|
16
30
|
+ (NSTimeInterval)latencyMs;
|
|
17
31
|
+ (NSInteger)downloadBps;
|
|
18
32
|
+ (NSInteger)uploadBps;
|
|
33
|
+
+ (BOOL)shouldBypassURL:(NSURL *)url;
|
|
19
34
|
+ (NSDictionary *)setEnabled:(BOOL)enabled
|
|
20
35
|
latencyMs:(NSTimeInterval)latencyMs
|
|
21
36
|
downloadBps:(NSInteger)downloadBps
|
|
22
|
-
uploadBps:(NSInteger)uploadBps
|
|
37
|
+
uploadBps:(NSInteger)uploadBps
|
|
38
|
+
bypassUrlOrigins:(NSArray *)bypassUrlOrigins;
|
|
23
39
|
@end
|
|
24
40
|
|
|
25
41
|
@implementation OneKeyNetworkThrottleState
|
|
@@ -28,18 +44,25 @@ static atomic_bool _oneKeyNetworkThrottleEnabled = ATOMIC_VAR_INIT(false);
|
|
|
28
44
|
static atomic_llong _oneKeyNetworkThrottleLatencyMicros = ATOMIC_VAR_INIT(562500);
|
|
29
45
|
static atomic_llong _oneKeyNetworkThrottleDownloadBps = ATOMIC_VAR_INIT(102 * 1024);
|
|
30
46
|
static atomic_llong _oneKeyNetworkThrottleUploadBps = ATOMIC_VAR_INIT(102 * 1024);
|
|
47
|
+
static NSSet<NSString *> *_oneKeyNetworkThrottleBypassOrigins;
|
|
31
48
|
|
|
32
49
|
+ (NSDictionary *)currentConfig
|
|
33
50
|
{
|
|
34
51
|
BOOL enabled = atomic_load_explicit(&_oneKeyNetworkThrottleEnabled, memory_order_acquire);
|
|
35
52
|
NSTimeInterval latencyMs =
|
|
36
53
|
((NSTimeInterval)atomic_load_explicit(&_oneKeyNetworkThrottleLatencyMicros, memory_order_relaxed)) / 1000.0;
|
|
54
|
+
NSArray<NSString *> *bypassUrlOrigins = nil;
|
|
55
|
+
@synchronized (self) {
|
|
56
|
+
bypassUrlOrigins = [[_oneKeyNetworkThrottleBypassOrigins ?: [NSSet set] allObjects]
|
|
57
|
+
sortedArrayUsingSelector:@selector(compare:)];
|
|
58
|
+
}
|
|
37
59
|
return @{
|
|
38
60
|
@"enabled": @(enabled),
|
|
39
61
|
@"profile": OneKeyNetworkThrottleProfileSlow4G,
|
|
40
62
|
@"latencyMs": @(latencyMs),
|
|
41
63
|
@"downloadBps": @([self downloadBps]),
|
|
42
|
-
@"uploadBps": @([self uploadBps])
|
|
64
|
+
@"uploadBps": @([self uploadBps]),
|
|
65
|
+
@"bypassUrlOrigins": bypassUrlOrigins
|
|
43
66
|
};
|
|
44
67
|
}
|
|
45
68
|
|
|
@@ -63,6 +86,17 @@ static atomic_llong _oneKeyNetworkThrottleUploadBps = ATOMIC_VAR_INIT(102 * 1024
|
|
|
63
86
|
return (NSInteger)atomic_load_explicit(&_oneKeyNetworkThrottleUploadBps, memory_order_relaxed);
|
|
64
87
|
}
|
|
65
88
|
|
|
89
|
+
+ (BOOL)shouldBypassURL:(NSURL *)url
|
|
90
|
+
{
|
|
91
|
+
NSString *origin = OneKeyNetworkThrottleCanonicalOrigin(url);
|
|
92
|
+
if (origin == nil) {
|
|
93
|
+
return NO;
|
|
94
|
+
}
|
|
95
|
+
@synchronized (self) {
|
|
96
|
+
return [_oneKeyNetworkThrottleBypassOrigins containsObject:origin];
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
66
100
|
+ (NSInteger)normalizeThroughputBps:(NSInteger)throughputBps
|
|
67
101
|
{
|
|
68
102
|
return throughputBps > 0 ? throughputBps : OneKeyNetworkThrottleDefaultThroughputBps;
|
|
@@ -72,10 +106,29 @@ static atomic_llong _oneKeyNetworkThrottleUploadBps = ATOMIC_VAR_INIT(102 * 1024
|
|
|
72
106
|
latencyMs:(NSTimeInterval)latencyMs
|
|
73
107
|
downloadBps:(NSInteger)downloadBps
|
|
74
108
|
uploadBps:(NSInteger)uploadBps
|
|
109
|
+
bypassUrlOrigins:(NSArray *)bypassUrlOrigins
|
|
75
110
|
{
|
|
76
111
|
NSTimeInterval normalizedLatencyMs = latencyMs > 0 ? latencyMs : OneKeyNetworkThrottleDefaultLatencyMs;
|
|
77
112
|
NSInteger normalizedDownloadBps = [self normalizeThroughputBps:downloadBps];
|
|
78
113
|
NSInteger normalizedUploadBps = [self normalizeThroughputBps:uploadBps];
|
|
114
|
+
if ([bypassUrlOrigins isKindOfClass:[NSArray class]]) {
|
|
115
|
+
NSMutableSet<NSString *> *normalizedOrigins = [NSMutableSet set];
|
|
116
|
+
for (id value in bypassUrlOrigins) {
|
|
117
|
+
if (![value isKindOfClass:[NSString class]]) {
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
NSString *origin = OneKeyNetworkThrottleCanonicalOrigin([NSURL URLWithString:(NSString *)value]);
|
|
121
|
+
if (origin != nil) {
|
|
122
|
+
[normalizedOrigins addObject:origin];
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
@synchronized (self) {
|
|
126
|
+
NSMutableSet<NSString *> *nextOrigins =
|
|
127
|
+
[_oneKeyNetworkThrottleBypassOrigins mutableCopy] ?: [NSMutableSet set];
|
|
128
|
+
[nextOrigins unionSet:normalizedOrigins];
|
|
129
|
+
_oneKeyNetworkThrottleBypassOrigins = [nextOrigins copy];
|
|
130
|
+
}
|
|
131
|
+
}
|
|
79
132
|
atomic_store_explicit(
|
|
80
133
|
&_oneKeyNetworkThrottleLatencyMicros,
|
|
81
134
|
(long long)llround(normalizedLatencyMs * 1000.0),
|
|
@@ -137,6 +190,9 @@ static atomic_llong _oneKeyNetworkThrottleUploadBps = ATOMIC_VAR_INIT(102 * 1024
|
|
|
137
190
|
if ([NSURLProtocol propertyForKey:OneKeyNetworkThrottleHandledKey inRequest:request]) {
|
|
138
191
|
return NO;
|
|
139
192
|
}
|
|
193
|
+
if ([OneKeyNetworkThrottleState shouldBypassURL:request.URL]) {
|
|
194
|
+
return NO;
|
|
195
|
+
}
|
|
140
196
|
NSString *scheme = request.URL.scheme.lowercaseString;
|
|
141
197
|
return [scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"];
|
|
142
198
|
}
|
|
@@ -517,7 +573,14 @@ RCT_REMAP_METHOD(setConfig, setConfig:(NSDictionary *)config resolver:(RCTPromis
|
|
|
517
573
|
uploadBpsValue != nil && uploadBpsValue != [NSNull null]
|
|
518
574
|
? [uploadBpsValue integerValue]
|
|
519
575
|
: [OneKeyNetworkThrottleState uploadBps];
|
|
520
|
-
|
|
576
|
+
id bypassUrlOriginsValue = config[@"bypassUrlOrigins"];
|
|
577
|
+
NSArray *bypassUrlOrigins = [bypassUrlOriginsValue isKindOfClass:[NSArray class]] ? bypassUrlOriginsValue : nil;
|
|
578
|
+
resolve([OneKeyNetworkThrottleState
|
|
579
|
+
setEnabled:enabled
|
|
580
|
+
latencyMs:latencyMs
|
|
581
|
+
downloadBps:downloadBps
|
|
582
|
+
uploadBps:uploadBps
|
|
583
|
+
bypassUrlOrigins:bypassUrlOrigins]);
|
|
521
584
|
}
|
|
522
585
|
|
|
523
586
|
@end
|
package/lib/module/index.js
CHANGED
|
@@ -10,17 +10,25 @@ const LINKING_ERROR = `The package '@onekeyfe/react-native-network-throttle' doe
|
|
|
10
10
|
default: ''
|
|
11
11
|
}) + '- rebuild the app after installing the package';
|
|
12
12
|
const nativeModule = NativeModules.OneKeyNetworkThrottle;
|
|
13
|
+
function normalizeNativeConfig(config) {
|
|
14
|
+
return {
|
|
15
|
+
...config,
|
|
16
|
+
bypassUrlOrigins: config.bypassUrlOrigins ?? []
|
|
17
|
+
};
|
|
18
|
+
}
|
|
13
19
|
export const NetworkThrottle = nativeModule ? {
|
|
14
|
-
getConfig: () => nativeModule.getConfig(),
|
|
20
|
+
getConfig: async () => normalizeNativeConfig(await nativeModule.getConfig()),
|
|
15
21
|
setConfig: async config => {
|
|
16
|
-
const currentConfig = await nativeModule.getConfig();
|
|
17
|
-
|
|
22
|
+
const currentConfig = normalizeNativeConfig(await nativeModule.getConfig());
|
|
23
|
+
const nativeConfig = await nativeModule.setConfig({
|
|
18
24
|
enabled: config.enabled ?? currentConfig.enabled,
|
|
19
25
|
profile: config.profile ?? currentConfig.profile,
|
|
20
26
|
latencyMs: config.latencyMs ?? currentConfig.latencyMs,
|
|
21
27
|
downloadBps: config.downloadBps ?? currentConfig.downloadBps,
|
|
22
|
-
uploadBps: config.uploadBps ?? currentConfig.uploadBps
|
|
28
|
+
uploadBps: config.uploadBps ?? currentConfig.uploadBps,
|
|
29
|
+
bypassUrlOrigins: config.bypassUrlOrigins ?? currentConfig.bypassUrlOrigins ?? []
|
|
23
30
|
});
|
|
31
|
+
return normalizeNativeConfig(nativeConfig);
|
|
24
32
|
}
|
|
25
33
|
} : new Proxy({}, {
|
|
26
34
|
get() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/react-native-network-throttle",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.82-alpha.0",
|
|
4
4
|
"description": "react-native-network-throttle",
|
|
5
5
|
"main": "./lib/module/index.js",
|
|
6
6
|
"types": "./lib/typescript/src/index.d.ts",
|
|
@@ -143,5 +143,5 @@
|
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
145
|
},
|
|
146
|
-
"stableVersion": "3.0.
|
|
146
|
+
"stableVersion": "3.0.81"
|
|
147
147
|
}
|
package/src/index.tsx
CHANGED
|
@@ -8,6 +8,7 @@ export type NetworkThrottleConfig = {
|
|
|
8
8
|
latencyMs: number;
|
|
9
9
|
downloadBps: number;
|
|
10
10
|
uploadBps: number;
|
|
11
|
+
bypassUrlOrigins: string[];
|
|
11
12
|
};
|
|
12
13
|
|
|
13
14
|
export const NETWORK_THROTTLE_SLOW_4G_LATENCY_MS = 562.5;
|
|
@@ -16,9 +17,18 @@ export const NETWORK_THROTTLE_SLOW_4G_DOWNLOAD_BPS =
|
|
|
16
17
|
NETWORK_THROTTLE_102_KIB_BPS;
|
|
17
18
|
export const NETWORK_THROTTLE_SLOW_4G_UPLOAD_BPS = NETWORK_THROTTLE_102_KIB_BPS;
|
|
18
19
|
|
|
20
|
+
type NativeNetworkThrottleConfig = Omit<
|
|
21
|
+
NetworkThrottleConfig,
|
|
22
|
+
'bypassUrlOrigins'
|
|
23
|
+
> & {
|
|
24
|
+
bypassUrlOrigins?: string[];
|
|
25
|
+
};
|
|
26
|
+
|
|
19
27
|
type NativeNetworkThrottleModule = {
|
|
20
|
-
getConfig: () => Promise<
|
|
21
|
-
setConfig: (
|
|
28
|
+
getConfig: () => Promise<NativeNetworkThrottleConfig>;
|
|
29
|
+
setConfig: (
|
|
30
|
+
config: NativeNetworkThrottleConfig
|
|
31
|
+
) => Promise<NativeNetworkThrottleConfig>;
|
|
22
32
|
};
|
|
23
33
|
|
|
24
34
|
export type NetworkThrottleModule = {
|
|
@@ -37,18 +47,33 @@ const nativeModule = NativeModules.OneKeyNetworkThrottle as
|
|
|
37
47
|
| NativeNetworkThrottleModule
|
|
38
48
|
| undefined;
|
|
39
49
|
|
|
50
|
+
function normalizeNativeConfig(
|
|
51
|
+
config: NativeNetworkThrottleConfig
|
|
52
|
+
): NetworkThrottleConfig {
|
|
53
|
+
return {
|
|
54
|
+
...config,
|
|
55
|
+
bypassUrlOrigins: config.bypassUrlOrigins ?? [],
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
40
59
|
export const NetworkThrottle: NetworkThrottleModule = nativeModule
|
|
41
60
|
? {
|
|
42
|
-
getConfig: () =>
|
|
61
|
+
getConfig: async () =>
|
|
62
|
+
normalizeNativeConfig(await nativeModule.getConfig()),
|
|
43
63
|
setConfig: async (config) => {
|
|
44
|
-
const currentConfig =
|
|
45
|
-
|
|
64
|
+
const currentConfig = normalizeNativeConfig(
|
|
65
|
+
await nativeModule.getConfig()
|
|
66
|
+
);
|
|
67
|
+
const nativeConfig = await nativeModule.setConfig({
|
|
46
68
|
enabled: config.enabled ?? currentConfig.enabled,
|
|
47
69
|
profile: config.profile ?? currentConfig.profile,
|
|
48
70
|
latencyMs: config.latencyMs ?? currentConfig.latencyMs,
|
|
49
71
|
downloadBps: config.downloadBps ?? currentConfig.downloadBps,
|
|
50
72
|
uploadBps: config.uploadBps ?? currentConfig.uploadBps,
|
|
73
|
+
bypassUrlOrigins:
|
|
74
|
+
config.bypassUrlOrigins ?? currentConfig.bypassUrlOrigins ?? [],
|
|
51
75
|
});
|
|
76
|
+
return normalizeNativeConfig(nativeConfig);
|
|
52
77
|
},
|
|
53
78
|
}
|
|
54
79
|
: (new Proxy(
|