@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.
package/android/build.gradle
CHANGED
|
@@ -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
|
}
|
|
@@ -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
|
-
|
|
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
|
|
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
|
-
|
|
73
|
+
if (!isTimedOut.get()) {
|
|
74
|
+
request.followRedirect()
|
|
75
|
+
}
|
|
87
76
|
}
|
|
88
77
|
|
|
89
78
|
override fun onResponseStarted(request: UrlRequest, info: UrlResponseInfo) {
|
|
90
|
-
|
|
91
|
-
|
|
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
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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 (!
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
val
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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 (!
|
|
146
|
-
|
|
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 (!
|
|
160
|
-
|
|
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 =
|
|
203
|
-
|
|
204
|
-
|
|
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
|
}
|