@pigeonmal/react-native-nitro-fetch 0.1.7 → 0.1.9

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.
@@ -117,7 +117,6 @@ dependencies {
117
117
  // Provide org.chromium.net Java API for CronetEngine in Kotlin
118
118
  // Cronet
119
119
  api "com.google.android.gms:play-services-cronet:18.0.1"
120
- implementation("com.squareup.okio:okio:2.9.0")
121
120
  implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0"
122
121
 
123
122
  }
@@ -29,6 +29,7 @@ class NitroFetch : HybridNitroFetchSpec() {
29
29
  }
30
30
  }
31
31
  }
32
+ val scheduledExecutor = Executors.newSingleThreadScheduledExecutor()
32
33
 
33
34
  fun getEngine(): CronetEngine {
34
35
  engineRef?.let { return it }
@@ -8,12 +8,12 @@ import org.chromium.net.CronetEngine
8
8
  import org.chromium.net.CronetException
9
9
  import org.chromium.net.UrlRequest
10
10
  import org.chromium.net.UrlResponseInfo
11
- import java.io.InterruptedIOException
12
11
  import java.nio.ByteBuffer
12
+ import java.util.concurrent.TimeoutException
13
13
  import java.util.concurrent.Executor
14
+ import java.util.concurrent.ScheduledExecutorService
14
15
  import java.util.concurrent.TimeUnit
15
16
  import java.util.concurrent.atomic.AtomicBoolean
16
- import okio.AsyncTimeout
17
17
 
18
18
  fun ByteBuffer.toByteArray(): ByteArray {
19
19
  // duplicate to avoid modifying the original buffer's position
@@ -30,7 +30,9 @@ class NitroFetchClient(private val engine: CronetEngine, private val executor: E
30
30
  private fun findPrefetchKey(req: NitroRequest): String? {
31
31
  val h = req.headers ?: return null
32
32
  for (pair in h) {
33
- if (pair.key.equals("prefetchKey", ignoreCase = true)) return pair.value
33
+ val k = pair.key
34
+ val v = pair.value
35
+ if (k.equals("prefetchKey", ignoreCase = true)) return v
34
36
  }
35
37
  return null
36
38
  }
@@ -59,112 +61,89 @@ class NitroFetchClient(private val engine: CronetEngine, private val executor: E
59
61
  onFail: (Throwable) -> Unit
60
62
  ) {
61
63
  val url = req.url
62
- val completed = AtomicBoolean(false)
64
+ val timeoutMs = req.timeoutMs?.toLong()
65
+ val isTimedOut = AtomicBoolean(false)
63
66
  var urlRequest: UrlRequest? = null
64
-
65
- // Create timeout handler
66
- val timeout = object : AsyncTimeout() {
67
- override fun timedOut() {
68
- if (completed.compareAndSet(false, true)) {
69
- urlRequest?.cancel()
70
- }
71
- }
72
- }
73
-
74
- // Configure timeout from request
75
- req.timeoutMs?.let { timeoutMs ->
76
- if (timeoutMs > 0) {
77
- timeout.timeout(timeoutMs.toLong(), TimeUnit.MILLISECONDS)
78
- }
79
- }
67
+ var timeoutTask: java.util.concurrent.ScheduledFuture<*>? = null
80
68
 
81
69
  val callback = object : UrlRequest.Callback() {
82
70
  private val buffer = ByteBuffer.allocateDirect(16 * 1024)
83
71
  private val out = java.io.ByteArrayOutputStream()
84
72
 
85
73
  override fun onRedirectReceived(request: UrlRequest, info: UrlResponseInfo, newLocationUrl: String) {
86
- request.followRedirect()
74
+ if (!isTimedOut.get()) {
75
+ request.followRedirect()
76
+ }
87
77
  }
88
78
 
89
79
  override fun onResponseStarted(request: UrlRequest, info: UrlResponseInfo) {
90
- buffer.clear()
91
- request.read(buffer)
80
+ if (!isTimedOut.get()) {
81
+ buffer.clear()
82
+ request.read(buffer)
83
+ }
92
84
  }
93
85
 
94
86
  override fun onReadCompleted(request: UrlRequest, info: UrlResponseInfo, byteBuffer: ByteBuffer) {
95
- byteBuffer.flip()
96
- val bytes = ByteArray(byteBuffer.remaining())
97
- byteBuffer.get(bytes)
98
- out.write(bytes)
99
- byteBuffer.clear()
100
- request.read(byteBuffer)
87
+ if (!isTimedOut.get()) {
88
+ byteBuffer.flip()
89
+ val bytes = ByteArray(byteBuffer.remaining())
90
+ byteBuffer.get(bytes)
91
+ out.write(bytes)
92
+ byteBuffer.clear()
93
+ request.read(byteBuffer)
94
+ }
101
95
  }
102
96
 
103
97
  override fun onSucceeded(request: UrlRequest, info: UrlResponseInfo) {
104
- if (!completed.compareAndSet(false, true)) return
105
- timeout.exit()
106
-
107
- try {
108
- val headersArr: Array<NitroHeader> =
109
- info.allHeadersAsList.map { NitroHeader(it.key, it.value) }.toTypedArray()
110
- val status = info.httpStatusCode
111
- val bytes = out.toByteArray()
112
- val contentType = info.allHeaders["Content-Type"] ?: info.allHeaders["content-type"]
113
- val charset = run {
114
- val ct = contentType ?: ""
115
- val m = Regex("charset=([A-Za-z0-9_\\-:.]+)", RegexOption.IGNORE_CASE).find(ct.toString())
116
- try {
117
- if (m != null) java.nio.charset.Charset.forName(m.groupValues[1]) else Charsets.UTF_8
118
- } catch (_: Throwable) {
119
- Charsets.UTF_8
98
+ if (!isTimedOut.get()) {
99
+ // Cancel timeout task if still pending
100
+ timeoutTask?.cancel(false)
101
+
102
+ try {
103
+ val headersArr: Array<NitroHeader> =
104
+ info.allHeadersAsList.map { NitroHeader(it.key, it.value) }.toTypedArray()
105
+ val status = info.httpStatusCode
106
+ val bytes = out.toByteArray()
107
+ val contentType = info.allHeaders["Content-Type"] ?: info.allHeaders["content-type"]
108
+ val charset = run {
109
+ val ct = contentType ?: ""
110
+ val m = Regex("charset=([A-Za-z0-9_\\-:.]+)", RegexOption.IGNORE_CASE).find(ct.toString())
111
+ try {
112
+ if (m != null) java.nio.charset.Charset.forName(m.groupValues[1]) else Charsets.UTF_8
113
+ } catch (_: Throwable) {
114
+ Charsets.UTF_8
115
+ }
120
116
  }
117
+ val bodyStr = try { String(bytes, charset) } catch (_: Throwable) { String(bytes, Charsets.UTF_8) }
118
+ val res = NitroResponse(
119
+ url = info.url,
120
+ status = status.toDouble(),
121
+ statusText = info.httpStatusText ?: "",
122
+ ok = status in 200..299,
123
+ redirected = info.url != url,
124
+ headers = headersArr,
125
+ bodyString = bodyStr,
126
+ bodyBytes = null
127
+ )
128
+ onSuccess(res)
129
+ } catch (t: Throwable) {
130
+ onFail(t)
121
131
  }
122
- val bodyStr = try {
123
- String(bytes, charset)
124
- } catch (_: Throwable) {
125
- String(bytes, Charsets.UTF_8)
126
- }
127
-
128
- val res = NitroResponse(
129
- url = info.url,
130
- status = status.toDouble(),
131
- statusText = info.httpStatusText ?: "",
132
- ok = status in 200..299,
133
- redirected = info.url != url,
134
- headers = headersArr,
135
- bodyString = bodyStr,
136
- bodyBytes = null
137
- )
138
- onSuccess(res)
139
- } catch (t: Throwable) {
140
- onFail(t)
141
132
  }
142
133
  }
143
134
 
144
135
  override fun onFailed(request: UrlRequest, info: UrlResponseInfo?, error: CronetException) {
145
- if (!completed.compareAndSet(false, true)) return
146
- val timedOut = timeout.exit()
147
-
148
- val exception = if (timedOut) {
149
- InterruptedIOException("Request timeout after ${req.timeoutMs}ms").apply {
150
- initCause(error)
151
- }
152
- } else {
153
- RuntimeException("Cronet failed: ${error.message}", error)
136
+ if (!isTimedOut.get()) {
137
+ timeoutTask?.cancel(false)
138
+ onFail(RuntimeException("Cronet failed: ${error.message}", error))
154
139
  }
155
- onFail(exception)
156
140
  }
157
141
 
158
142
  override fun onCanceled(request: UrlRequest, info: UrlResponseInfo?) {
159
- if (!completed.compareAndSet(false, true)) return
160
- val timedOut = timeout.exit()
161
-
162
- val exception = if (timedOut) {
163
- InterruptedIOException("Request timeout after ${req.timeoutMs}ms")
164
- } else {
165
- RuntimeException("Cronet canceled")
143
+ if (!isTimedOut.get()) {
144
+ timeoutTask?.cancel(false)
145
+ onFail(RuntimeException("Cronet canceled"))
166
146
  }
167
- onFail(exception)
168
147
  }
169
148
  }
170
149
 
@@ -172,7 +151,6 @@ class NitroFetchClient(private val engine: CronetEngine, private val executor: E
172
151
  val method = req.method?.name ?: "GET"
173
152
  builder.setHttpMethod(method)
174
153
  req.headers?.forEach { (k, v) -> builder.addHeader(k, v) }
175
-
176
154
  val bodyBytes = req.bodyBytes
177
155
  val bodyStr = req.bodyString
178
156
  if ((bodyBytes != null) || !bodyStr.isNullOrEmpty()) {
@@ -198,10 +176,21 @@ class NitroFetchClient(private val engine: CronetEngine, private val executor: E
198
176
  }
199
177
  builder.setUploadDataProvider(provider, executor)
200
178
  }
201
-
202
- urlRequest = builder.build()
203
- timeout.enter()
204
- urlRequest.start()
179
+ val request = builder.build()
180
+ urlRequest = request
181
+
182
+ // Set up timeout if specified
183
+ if (timeoutMs != null && timeoutMs > 0) {
184
+ val scheduledExecutor = NitroFetch.scheduledExecutor // You'll need to add this
185
+ timeoutTask = scheduledExecutor.schedule({
186
+ if (isTimedOut.compareAndSet(false, true)) {
187
+ request.cancel()
188
+ onFail(TimeoutException("Request timed out after ${timeoutMs}ms"))
189
+ }
190
+ }, timeoutMs, TimeUnit.MILLISECONDS)
191
+ }
192
+
193
+ request.start()
205
194
  }
206
195
  }
207
196
 
@@ -279,7 +268,6 @@ class NitroFetchClient(private val engine: CronetEngine, private val executor: E
279
268
  return promise
280
269
  }
281
270
  }
282
-
283
271
  fetch(
284
272
  req,
285
273
  onSuccess = { promise.resolve(it) },
@@ -326,6 +314,4 @@ class NitroFetchClient(private val engine: CronetEngine, private val executor: E
326
314
  )
327
315
  return promise
328
316
  }
329
-
330
-
331
317
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pigeonmal/react-native-nitro-fetch",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "Awesome Fetch :)",
5
5
  "main": "./lib/module/index.js",
6
6
  "module": "./lib/module/index.js",