@onekeyfe/react-native-network-throttle 3.0.83-alpha.0 → 3.0.84-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
@@ -5,16 +5,13 @@ React Native native network throttle for OneKey iOS and Android development sett
5
5
  Current scope is RN HTTP(S) latency and upload/download throughput. It does not
6
6
  emulate offline mode, WebView traffic, or third-party native networking stacks.
7
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
+ `throttleUrlHosts` is an allowlist: when it is non-empty, only requests whose
9
+ host matches are throttled, and everything else is left untouched. An entry is
10
+ either an exact host or `*.example.com`, which matches sub-domains at any depth
11
+ but not the bare apex. An empty allowlist throttles nothing.
13
12
 
14
- Known limitation: on Android the bypass decision is made once per logical
15
- request (OkHttp application interceptor), so a cross-origin redirect keeps the
16
- initial request's bypass decision; iOS re-evaluates each request. Exact-origin
17
- bypasses target local development servers, which do not redirect across
18
- origins.
13
+ Hosts are registered additively for the lifetime of the native process, so
14
+ independently initialized React Native runtimes cannot clear each other's
15
+ configuration.
19
16
 
20
17
  This package only owns native request throttling. Product settings, persistence, and UI controls should remain in the host app.
@@ -14,7 +14,6 @@ import java.util.concurrent.atomic.AtomicBoolean
14
14
  import java.util.concurrent.atomic.AtomicLong
15
15
  import java.util.concurrent.atomic.AtomicReference
16
16
  import okhttp3.HttpUrl
17
- import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
18
17
  import okhttp3.Interceptor
19
18
  import okhttp3.MediaType
20
19
  import okhttp3.OkHttpClient
@@ -40,7 +39,7 @@ internal object NetworkThrottle {
40
39
  private val downloadBps = AtomicLong(DEFAULT_THROUGHPUT_BPS.toLong())
41
40
  private val uploadBps = AtomicLong(DEFAULT_THROUGHPUT_BPS.toLong())
42
41
  private val installed = AtomicBoolean(false)
43
- private val bypassUrlOrigins = AtomicReference<Set<String>>(emptySet())
42
+ private val throttleUrlHosts = AtomicReference<Set<String>>(emptySet())
44
43
 
45
44
  fun install(context: Context) {
46
45
  if (!installed.compareAndSet(false, true)) {
@@ -90,18 +89,18 @@ internal object NetworkThrottle {
90
89
  if (nextUploadBps <= 0) {
91
90
  nextUploadBps = DEFAULT_THROUGHPUT_BPS.toLong()
92
91
  }
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)
92
+ if (config.hasKey("throttleUrlHosts") && !config.isNull("throttleUrlHosts")) {
93
+ val hosts = config.getArray("throttleUrlHosts")
94
+ val normalizedHosts = buildSet {
95
+ if (hosts != null) {
96
+ for (index in 0 until hosts.size()) {
97
+ if (hosts.getType(index) == ReadableType.String) {
98
+ normalizeHost(hosts.getString(index))?.let(::add)
100
99
  }
101
100
  }
102
101
  }
103
102
  }
104
- bypassUrlOrigins.updateAndGet { current -> current + normalizedOrigins }
103
+ throttleUrlHosts.updateAndGet { current -> current + normalizedHosts }
105
104
  }
106
105
 
107
106
  enabled.set(nextEnabled)
@@ -122,9 +121,9 @@ internal object NetworkThrottle {
122
121
  map.putDouble("latencyMs", latencyNanos.get() / 1_000_000.0)
123
122
  map.putDouble("downloadBps", downloadBps.get().toDouble())
124
123
  map.putDouble("uploadBps", uploadBps.get().toDouble())
125
- val origins = Arguments.createArray()
126
- bypassUrlOrigins.get().sorted().forEach(origins::pushString)
127
- map.putArray("bypassUrlOrigins", origins)
124
+ val hosts = Arguments.createArray()
125
+ throttleUrlHosts.get().sorted().forEach(hosts::pushString)
126
+ map.putArray("throttleUrlHosts", hosts)
128
127
  return map
129
128
  }
130
129
 
@@ -132,26 +131,31 @@ internal object NetworkThrottle {
132
131
  private fun getDownloadBps(): Long = if (enabled.get()) downloadBps.get() else 0L
133
132
  private fun getUploadBps(): Long = if (enabled.get()) uploadBps.get() else 0L
134
133
 
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("/")
134
+ private fun normalizeHost(value: String?): String? =
135
+ value?.trim()?.lowercase()?.takeIf { it.isNotEmpty() }
143
136
 
144
- private fun normalizeOrigin(value: String?): String? =
145
- value?.toHttpUrlOrNull()?.let(::canonicalOrigin)
137
+ /**
138
+ * Hosts are matched as exact names, or as `*.example.com` which matches
139
+ * sub-domains at any depth but not the bare apex. This mirrors the URL
140
+ * patterns the desktop app installs, so both platforms throttle the same
141
+ * traffic.
142
+ */
143
+ private fun matchesHost(host: String, pattern: String): Boolean =
144
+ if (pattern.startsWith("*.")) {
145
+ host.endsWith(pattern.substring(1))
146
+ } else {
147
+ host == pattern
148
+ }
146
149
 
147
- private fun shouldBypass(requestUrl: HttpUrl): Boolean {
148
- // The interceptor is installed in every build; skip the per-request
149
- // canonicalization allocation while no origin is registered.
150
- val origins = bypassUrlOrigins.get()
151
- if (origins.isEmpty()) {
150
+ private fun shouldThrottle(requestUrl: HttpUrl): Boolean {
151
+ // The interceptor is installed in every build, so keep the empty case
152
+ // allocation-free. An empty allowlist throttles nothing.
153
+ val hosts = throttleUrlHosts.get()
154
+ if (hosts.isEmpty()) {
152
155
  return false
153
156
  }
154
- return origins.contains(canonicalOrigin(requestUrl))
157
+ val host = requestUrl.host.lowercase()
158
+ return hosts.any { matchesHost(host, it) }
155
159
  }
156
160
 
157
161
  private fun sleepNanos(delayNanos: Long) {
@@ -245,7 +249,7 @@ internal object NetworkThrottle {
245
249
  private class ThrottleInterceptor : Interceptor {
246
250
  override fun intercept(chain: Interceptor.Chain): Response {
247
251
  val request = chain.request()
248
- if (shouldBypass(request.url)) {
252
+ if (!shouldThrottle(request.url)) {
249
253
  return chain.proceed(request)
250
254
  }
251
255
  val requestStartNanos = System.nanoTime()
@@ -10,18 +10,21 @@ 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)
13
+ static NSString *OneKeyNetworkThrottleNormalizedHost(NSString *value)
14
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;
15
+ NSString *host = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]].lowercaseString;
16
+ return host.length > 0 ? host : nil;
17
+ }
18
+
19
+ // Hosts match as exact names, or as `*.example.com` which matches sub-domains
20
+ // at any depth but not the bare apex. This mirrors the URL patterns the
21
+ // desktop app installs, so both platforms throttle the same traffic.
22
+ static BOOL OneKeyNetworkThrottleHostMatches(NSString *host, NSString *pattern)
23
+ {
24
+ if ([pattern hasPrefix:@"*."]) {
25
+ return [host hasSuffix:[pattern substringFromIndex:1]];
19
26
  }
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;
27
+ return [host isEqualToString:pattern];
25
28
  }
26
29
 
27
30
  @interface OneKeyNetworkThrottleState : NSObject
@@ -30,12 +33,12 @@ static NSString *OneKeyNetworkThrottleCanonicalOrigin(NSURL *url)
30
33
  + (NSTimeInterval)latencyMs;
31
34
  + (NSInteger)downloadBps;
32
35
  + (NSInteger)uploadBps;
33
- + (BOOL)shouldBypassURL:(NSURL *)url;
36
+ + (BOOL)shouldThrottleURL:(NSURL *)url;
34
37
  + (NSDictionary *)setEnabled:(BOOL)enabled
35
38
  latencyMs:(NSTimeInterval)latencyMs
36
39
  downloadBps:(NSInteger)downloadBps
37
40
  uploadBps:(NSInteger)uploadBps
38
- bypassUrlOrigins:(NSArray *)bypassUrlOrigins;
41
+ throttleUrlHosts:(NSArray *)throttleUrlHosts;
39
42
  @end
40
43
 
41
44
  @implementation OneKeyNetworkThrottleState
@@ -44,16 +47,16 @@ static atomic_bool _oneKeyNetworkThrottleEnabled = ATOMIC_VAR_INIT(false);
44
47
  static atomic_llong _oneKeyNetworkThrottleLatencyMicros = ATOMIC_VAR_INIT(562500);
45
48
  static atomic_llong _oneKeyNetworkThrottleDownloadBps = ATOMIC_VAR_INIT(102 * 1024);
46
49
  static atomic_llong _oneKeyNetworkThrottleUploadBps = ATOMIC_VAR_INIT(102 * 1024);
47
- static NSSet<NSString *> *_oneKeyNetworkThrottleBypassOrigins;
50
+ static NSSet<NSString *> *_oneKeyNetworkThrottleHosts;
48
51
 
49
52
  + (NSDictionary *)currentConfig
50
53
  {
51
54
  BOOL enabled = atomic_load_explicit(&_oneKeyNetworkThrottleEnabled, memory_order_acquire);
52
55
  NSTimeInterval latencyMs =
53
56
  ((NSTimeInterval)atomic_load_explicit(&_oneKeyNetworkThrottleLatencyMicros, memory_order_relaxed)) / 1000.0;
54
- NSArray<NSString *> *bypassUrlOrigins = nil;
57
+ NSArray<NSString *> *throttleUrlHosts = nil;
55
58
  @synchronized (self) {
56
- bypassUrlOrigins = [[_oneKeyNetworkThrottleBypassOrigins ?: [NSSet set] allObjects]
59
+ throttleUrlHosts = [[_oneKeyNetworkThrottleHosts ?: [NSSet set] allObjects]
57
60
  sortedArrayUsingSelector:@selector(compare:)];
58
61
  }
59
62
  return @{
@@ -62,7 +65,7 @@ static NSSet<NSString *> *_oneKeyNetworkThrottleBypassOrigins;
62
65
  @"latencyMs": @(latencyMs),
63
66
  @"downloadBps": @([self downloadBps]),
64
67
  @"uploadBps": @([self uploadBps]),
65
- @"bypassUrlOrigins": bypassUrlOrigins
68
+ @"throttleUrlHosts": throttleUrlHosts
66
69
  };
67
70
  }
68
71
 
@@ -86,15 +89,23 @@ static NSSet<NSString *> *_oneKeyNetworkThrottleBypassOrigins;
86
89
  return (NSInteger)atomic_load_explicit(&_oneKeyNetworkThrottleUploadBps, memory_order_relaxed);
87
90
  }
88
91
 
89
- + (BOOL)shouldBypassURL:(NSURL *)url
92
+ + (BOOL)shouldThrottleURL:(NSURL *)url
90
93
  {
91
- NSString *origin = OneKeyNetworkThrottleCanonicalOrigin(url);
92
- if (origin == nil) {
94
+ NSString *host = OneKeyNetworkThrottleNormalizedHost(url.host);
95
+ if (host == nil) {
93
96
  return NO;
94
97
  }
98
+ // An empty allowlist throttles nothing.
99
+ NSSet<NSString *> *hosts = nil;
95
100
  @synchronized (self) {
96
- return [_oneKeyNetworkThrottleBypassOrigins containsObject:origin];
101
+ hosts = _oneKeyNetworkThrottleHosts;
97
102
  }
103
+ for (NSString *pattern in hosts) {
104
+ if (OneKeyNetworkThrottleHostMatches(host, pattern)) {
105
+ return YES;
106
+ }
107
+ }
108
+ return NO;
98
109
  }
99
110
 
100
111
  + (NSInteger)normalizeThroughputBps:(NSInteger)throughputBps
@@ -106,27 +117,27 @@ static NSSet<NSString *> *_oneKeyNetworkThrottleBypassOrigins;
106
117
  latencyMs:(NSTimeInterval)latencyMs
107
118
  downloadBps:(NSInteger)downloadBps
108
119
  uploadBps:(NSInteger)uploadBps
109
- bypassUrlOrigins:(NSArray *)bypassUrlOrigins
120
+ throttleUrlHosts:(NSArray *)throttleUrlHosts
110
121
  {
111
122
  NSTimeInterval normalizedLatencyMs = latencyMs > 0 ? latencyMs : OneKeyNetworkThrottleDefaultLatencyMs;
112
123
  NSInteger normalizedDownloadBps = [self normalizeThroughputBps:downloadBps];
113
124
  NSInteger normalizedUploadBps = [self normalizeThroughputBps:uploadBps];
114
- if ([bypassUrlOrigins isKindOfClass:[NSArray class]]) {
115
- NSMutableSet<NSString *> *normalizedOrigins = [NSMutableSet set];
116
- for (id value in bypassUrlOrigins) {
125
+ if ([throttleUrlHosts isKindOfClass:[NSArray class]]) {
126
+ NSMutableSet<NSString *> *normalizedHosts = [NSMutableSet set];
127
+ for (id value in throttleUrlHosts) {
117
128
  if (![value isKindOfClass:[NSString class]]) {
118
129
  continue;
119
130
  }
120
- NSString *origin = OneKeyNetworkThrottleCanonicalOrigin([NSURL URLWithString:(NSString *)value]);
121
- if (origin != nil) {
122
- [normalizedOrigins addObject:origin];
131
+ NSString *host = OneKeyNetworkThrottleNormalizedHost((NSString *)value);
132
+ if (host != nil) {
133
+ [normalizedHosts addObject:host];
123
134
  }
124
135
  }
125
136
  @synchronized (self) {
126
- NSMutableSet<NSString *> *nextOrigins =
127
- [_oneKeyNetworkThrottleBypassOrigins mutableCopy] ?: [NSMutableSet set];
128
- [nextOrigins unionSet:normalizedOrigins];
129
- _oneKeyNetworkThrottleBypassOrigins = [nextOrigins copy];
137
+ NSMutableSet<NSString *> *nextHosts =
138
+ [_oneKeyNetworkThrottleHosts mutableCopy] ?: [NSMutableSet set];
139
+ [nextHosts unionSet:normalizedHosts];
140
+ _oneKeyNetworkThrottleHosts = [nextHosts copy];
130
141
  }
131
142
  }
132
143
  atomic_store_explicit(
@@ -190,7 +201,7 @@ static NSSet<NSString *> *_oneKeyNetworkThrottleBypassOrigins;
190
201
  if ([NSURLProtocol propertyForKey:OneKeyNetworkThrottleHandledKey inRequest:request]) {
191
202
  return NO;
192
203
  }
193
- if ([OneKeyNetworkThrottleState shouldBypassURL:request.URL]) {
204
+ if (![OneKeyNetworkThrottleState shouldThrottleURL:request.URL]) {
194
205
  return NO;
195
206
  }
196
207
  NSString *scheme = request.URL.scheme.lowercaseString;
@@ -573,14 +584,14 @@ RCT_REMAP_METHOD(setConfig, setConfig:(NSDictionary *)config resolver:(RCTPromis
573
584
  uploadBpsValue != nil && uploadBpsValue != [NSNull null]
574
585
  ? [uploadBpsValue integerValue]
575
586
  : [OneKeyNetworkThrottleState uploadBps];
576
- id bypassUrlOriginsValue = config[@"bypassUrlOrigins"];
577
- NSArray *bypassUrlOrigins = [bypassUrlOriginsValue isKindOfClass:[NSArray class]] ? bypassUrlOriginsValue : nil;
587
+ id throttleUrlHostsValue = config[@"throttleUrlHosts"];
588
+ NSArray *throttleUrlHosts = [throttleUrlHostsValue isKindOfClass:[NSArray class]] ? throttleUrlHostsValue : nil;
578
589
  resolve([OneKeyNetworkThrottleState
579
590
  setEnabled:enabled
580
591
  latencyMs:latencyMs
581
592
  downloadBps:downloadBps
582
593
  uploadBps:uploadBps
583
- bypassUrlOrigins:bypassUrlOrigins]);
594
+ throttleUrlHosts:throttleUrlHosts]);
584
595
  }
585
596
 
586
597
  @end
@@ -13,7 +13,7 @@ const nativeModule = NativeModules.OneKeyNetworkThrottle;
13
13
  function normalizeNativeConfig(config) {
14
14
  return {
15
15
  ...config,
16
- bypassUrlOrigins: config.bypassUrlOrigins ?? []
16
+ throttleUrlHosts: config.throttleUrlHosts ?? []
17
17
  };
18
18
  }
19
19
  export const NetworkThrottle = nativeModule ? {
@@ -26,7 +26,7 @@ export const NetworkThrottle = nativeModule ? {
26
26
  latencyMs: config.latencyMs ?? currentConfig.latencyMs,
27
27
  downloadBps: config.downloadBps ?? currentConfig.downloadBps,
28
28
  uploadBps: config.uploadBps ?? currentConfig.uploadBps,
29
- bypassUrlOrigins: config.bypassUrlOrigins ?? currentConfig.bypassUrlOrigins ?? []
29
+ throttleUrlHosts: config.throttleUrlHosts ?? currentConfig.throttleUrlHosts ?? []
30
30
  });
31
31
  return normalizeNativeConfig(nativeConfig);
32
32
  }
@@ -5,7 +5,7 @@ export type NetworkThrottleConfig = {
5
5
  latencyMs: number;
6
6
  downloadBps: number;
7
7
  uploadBps: number;
8
- bypassUrlOrigins: string[];
8
+ throttleUrlHosts: string[];
9
9
  };
10
10
  export declare const NETWORK_THROTTLE_SLOW_4G_LATENCY_MS = 562.5;
11
11
  export declare const NETWORK_THROTTLE_102_KIB_BPS: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/react-native-network-throttle",
3
- "version": "3.0.83-alpha.0",
3
+ "version": "3.0.84-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",
package/src/index.tsx CHANGED
@@ -8,7 +8,7 @@ export type NetworkThrottleConfig = {
8
8
  latencyMs: number;
9
9
  downloadBps: number;
10
10
  uploadBps: number;
11
- bypassUrlOrigins: string[];
11
+ throttleUrlHosts: string[];
12
12
  };
13
13
 
14
14
  export const NETWORK_THROTTLE_SLOW_4G_LATENCY_MS = 562.5;
@@ -19,9 +19,9 @@ export const NETWORK_THROTTLE_SLOW_4G_UPLOAD_BPS = NETWORK_THROTTLE_102_KIB_BPS;
19
19
 
20
20
  type NativeNetworkThrottleConfig = Omit<
21
21
  NetworkThrottleConfig,
22
- 'bypassUrlOrigins'
22
+ 'throttleUrlHosts'
23
23
  > & {
24
- bypassUrlOrigins?: string[];
24
+ throttleUrlHosts?: string[];
25
25
  };
26
26
 
27
27
  type NativeNetworkThrottleModule = {
@@ -52,7 +52,7 @@ function normalizeNativeConfig(
52
52
  ): NetworkThrottleConfig {
53
53
  return {
54
54
  ...config,
55
- bypassUrlOrigins: config.bypassUrlOrigins ?? [],
55
+ throttleUrlHosts: config.throttleUrlHosts ?? [],
56
56
  };
57
57
  }
58
58
 
@@ -70,8 +70,8 @@ export const NetworkThrottle: NetworkThrottleModule = nativeModule
70
70
  latencyMs: config.latencyMs ?? currentConfig.latencyMs,
71
71
  downloadBps: config.downloadBps ?? currentConfig.downloadBps,
72
72
  uploadBps: config.uploadBps ?? currentConfig.uploadBps,
73
- bypassUrlOrigins:
74
- config.bypassUrlOrigins ?? currentConfig.bypassUrlOrigins ?? [],
73
+ throttleUrlHosts:
74
+ config.throttleUrlHosts ?? currentConfig.throttleUrlHosts ?? [],
75
75
  });
76
76
  return normalizeNativeConfig(nativeConfig);
77
77
  },