Skip to content

Commit 1ac4624

Browse files
authored
feat: add networking (#2)
1 parent 2a2682e commit 1ac4624

11 files changed

Lines changed: 1152 additions & 274 deletions

File tree

android/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,5 @@ dependencies {
105105
implementation "com.facebook.react:react-android"
106106
implementation "com.facebook.react:hermes-android"
107107
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
108+
implementation "com.squareup.okhttp3:okhttp:4.9.2"
108109
}

android/src/main/java/com/webworker/WebWorkerNative.kt

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,19 @@ object WebWorkerNative {
3535

3636
/** Called for worker console output (log, error, warn, info) */
3737
fun onConsole(workerId: String, level: String, message: String)
38+
39+
/** Called for worker network requests */
40+
fun onFetch(
41+
workerId: String,
42+
requestId: String,
43+
url: String,
44+
method: String,
45+
headerKeys: Array<String>,
46+
headerValues: Array<String>,
47+
body: ByteArray?,
48+
timeout: Double,
49+
redirect: String
50+
)
3851
}
3952

4053
/**
@@ -100,6 +113,21 @@ object WebWorkerNative {
100113
return nativeIsWorkerRunning(workerId)
101114
}
102115

116+
/**
117+
* Send fetch response back to C++
118+
*/
119+
fun handleFetchResponse(
120+
workerId: String,
121+
requestId: String,
122+
status: Int,
123+
headerKeys: Array<String>,
124+
headerValues: Array<String>,
125+
body: ByteArray?,
126+
error: String?
127+
) {
128+
nativeHandleFetchResponse(workerId, requestId, status, headerKeys, headerValues, body, error)
129+
}
130+
103131
/**
104132
* Clean up all workers and release resources.
105133
*/
@@ -119,4 +147,13 @@ object WebWorkerNative {
119147
private external fun nativeHasWorker(workerId: String): Boolean
120148
private external fun nativeIsWorkerRunning(workerId: String): Boolean
121149
private external fun nativeCleanup()
122-
}
150+
private external fun nativeHandleFetchResponse(
151+
workerId: String,
152+
requestId: String,
153+
status: Int,
154+
headerKeys: Array<String>,
155+
headerValues: Array<String>,
156+
body: ByteArray?,
157+
error: String?
158+
)
159+
}

android/src/main/java/com/webworker/WebworkerModule.kt

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,17 @@ import com.facebook.react.bridge.Arguments
55
import com.facebook.react.bridge.Promise
66
import com.facebook.react.bridge.ReactApplicationContext
77
import com.facebook.react.module.annotations.ReactModule
8+
import okhttp3.Call
9+
import okhttp3.Callback
10+
import okhttp3.MediaType
11+
import okhttp3.MediaType.Companion.toMediaTypeOrNull
12+
import okhttp3.OkHttpClient
13+
import okhttp3.Request
14+
import okhttp3.RequestBody
15+
import okhttp3.RequestBody.Companion.toRequestBody
16+
import okhttp3.Response
17+
import java.io.IOException
18+
import java.util.concurrent.TimeUnit
819

920
/**
1021
* React Native TurboModule for WebWorker support.
@@ -16,6 +27,8 @@ import com.facebook.react.module.annotations.ReactModule
1627
class WebworkerModule(reactContext: ReactApplicationContext) :
1728
NativeWebworkerSpec(reactContext), WebWorkerNative.WorkerCallback {
1829

30+
private val client = OkHttpClient()
31+
1932
init {
2033
// Initialize the native core with this module as the callback receiver
2134
WebWorkerNative.initialize(this)
@@ -52,6 +65,91 @@ class WebworkerModule(reactContext: ReactApplicationContext) :
5265
})
5366
}
5467

68+
override fun onFetch(
69+
workerId: String,
70+
requestId: String,
71+
url: String,
72+
method: String,
73+
headerKeys: Array<String>,
74+
headerValues: Array<String>,
75+
body: ByteArray?,
76+
timeout: Double,
77+
redirect: String
78+
) {
79+
val requestBuilder = Request.Builder()
80+
.url(url)
81+
82+
// Headers
83+
var contentType: MediaType? = null
84+
for (i in headerKeys.indices) {
85+
val key = headerKeys[i]
86+
val value = headerValues[i]
87+
requestBuilder.addHeader(key, value)
88+
if (key.equals("Content-Type", ignoreCase = true)) {
89+
contentType = value.toMediaTypeOrNull()
90+
}
91+
}
92+
93+
// Body
94+
val requestBody = if (body != null && body.isNotEmpty()) {
95+
body.toRequestBody(contentType)
96+
} else if (method.equals("POST", ignoreCase = true) || method.equals("PUT", ignoreCase = true) || method.equals("PATCH", ignoreCase = true)) {
97+
ByteArray(0).toRequestBody(null)
98+
} else {
99+
null
100+
}
101+
102+
requestBuilder.method(method, requestBody)
103+
104+
// Configure client based on options
105+
val requestClient = if (timeout > 0 || redirect != "follow") {
106+
val builder = client.newBuilder()
107+
if (timeout > 0) {
108+
val timeoutMs = timeout.toLong()
109+
builder.callTimeout(timeoutMs, TimeUnit.MILLISECONDS)
110+
builder.readTimeout(timeoutMs, TimeUnit.MILLISECONDS)
111+
builder.connectTimeout(timeoutMs, TimeUnit.MILLISECONDS)
112+
}
113+
if (redirect == "error" || redirect == "manual") {
114+
builder.followRedirects(false)
115+
builder.followSslRedirects(false)
116+
}
117+
builder.build()
118+
} else {
119+
client
120+
}
121+
122+
requestClient.newCall(requestBuilder.build()).enqueue(object : Callback {
123+
override fun onFailure(call: Call, e: IOException) {
124+
WebWorkerNative.handleFetchResponse(
125+
workerId, requestId, 0, emptyArray(), emptyArray(), null, e.message
126+
)
127+
}
128+
129+
override fun onResponse(call: Call, response: Response) {
130+
val responseBody = response.body?.bytes()
131+
val headers = response.headers
132+
val keys = mutableListOf<String>()
133+
val values = mutableListOf<String>()
134+
135+
for (i in 0 until headers.size) {
136+
keys.add(headers.name(i))
137+
values.add(headers.value(i))
138+
}
139+
140+
WebWorkerNative.handleFetchResponse(
141+
workerId,
142+
requestId,
143+
response.code,
144+
keys.toTypedArray(),
145+
values.toTypedArray(),
146+
responseBody,
147+
null
148+
)
149+
}
150+
})
151+
}
152+
55153
// ============================================================================
56154
// TurboModule Methods - mirror iOS implementation
57155
// ============================================================================

0 commit comments

Comments
 (0)