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

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