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