Skip to content

Commit c3b3161

Browse files
committed
Allow passing files across the client - SDK HTTP server bridge
1 parent afbd9cf commit c3b3161

File tree

4 files changed

+59
-14
lines changed

4 files changed

+59
-14
lines changed

bridge-settings/src/main/java/com/penumbraos/bridge_settings/server/types.kt

Lines changed: 52 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
package com.penumbraos.bridge_settings.server
22

3+
import android.os.ParcelFileDescriptor
4+
import android.system.Os
5+
import android.system.OsConstants
36
import com.penumbraos.bridge.callback.IHttpEndpointCallback
47
import com.penumbraos.bridge.callback.IHttpResponseCallback
58
import com.penumbraos.bridge_settings.SettingsWebServer
9+
import kotlinx.coroutines.CancellableContinuation
610
import kotlinx.coroutines.suspendCancellableCoroutine
11+
import java.io.ByteArrayOutputStream
12+
import java.io.FileInputStream
713
import kotlin.coroutines.resume
814

915
data class EndpointRequest(
@@ -100,6 +106,7 @@ class AidlEndpointCallback(
100106
statusCode: Int,
101107
headers: MutableMap<Any?, Any?>?,
102108
body: ByteArray?,
109+
file: ParcelFileDescriptor?,
103110
contentType: String?
104111
) {
105112
val headers = (headers?.mapKeys { it.key.toString() }
@@ -108,13 +115,41 @@ class AidlEndpointCallback(
108115
// Disable CORS
109116
headers["Access-Control-Allow-Origin"] = "*"
110117

111-
val response = EndpointResponse(
112-
statusCode = statusCode,
113-
headers = headers,
114-
body = body,
115-
contentType = contentType ?: "application/json"
116-
)
117-
continuation.resume(response)
118+
if (file != null) {
119+
try {
120+
Os.lseek(
121+
file.fileDescriptor,
122+
0,
123+
OsConstants.SEEK_SET
124+
)
125+
val fileBytes =
126+
FileInputStream(file.fileDescriptor)
127+
val byteArrayOutputStream = ByteArrayOutputStream()
128+
val buffer = ByteArray(4096)
129+
var bytesRead: Int
130+
while (fileBytes.read(buffer).also { bytesRead = it } != -1) {
131+
byteArrayOutputStream.write(buffer, 0, bytesRead)
132+
}
133+
134+
val response = EndpointResponse(
135+
statusCode = statusCode,
136+
headers = headers,
137+
body = byteArrayOutputStream.toByteArray(),
138+
contentType = contentType ?: "application/json"
139+
)
140+
continuation.resume(response)
141+
} catch (e: Exception) {
142+
sendError(continuation, e.message ?: "Unknown error")
143+
}
144+
} else {
145+
val response = EndpointResponse(
146+
statusCode = statusCode,
147+
headers = headers,
148+
body = body,
149+
contentType = contentType ?: "application/json"
150+
)
151+
continuation.resume(response)
152+
}
118153
}
119154
}
120155

@@ -129,13 +164,17 @@ class AidlEndpointCallback(
129164
responseCallback
130165
)
131166
} catch (e: Exception) {
132-
val errorResponse = EndpointResponse(
133-
statusCode = 500,
134-
body = "{\"error\": \"Internal server error: ${e.message}\"}".toByteArray(),
135-
contentType = "application/json"
136-
)
137-
continuation.resume(errorResponse)
167+
sendError(continuation, e.message ?: "Unknown error")
138168
}
139169
}
140170
}
141171
}
172+
173+
fun sendError(continuation: CancellableContinuation<EndpointResponse>, message: String) {
174+
val errorResponse = EndpointResponse(
175+
statusCode = 500,
176+
body = "{\"error\": \"Internal server error: ${message}\"}".toByteArray(),
177+
contentType = "application/json"
178+
)
179+
continuation.resume(errorResponse)
180+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
package com.penumbraos.bridge.callback;
22

33
interface IHttpResponseCallback {
4-
void sendResponse(int statusCode, in Map headers, in byte[] body, String contentType);
4+
void sendResponse(int statusCode, in Map headers, in byte[] body, in ParcelFileDescriptor file, String contentType);
55
}

sdk/src/main/java/com/penumbraos/sdk/api/SettingsClient.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ class SettingsClient(private val settingsProvider: ISettingsProvider) {
211211
response.statusCode,
212212
response.headers,
213213
response.body,
214+
response.file,
214215
response.contentType
215216
)
216217
} catch (e: Exception) {
@@ -219,6 +220,7 @@ class SettingsClient(private val settingsProvider: ISettingsProvider) {
219220
500,
220221
emptyMap<Any?, Any?>(),
221222
"{\"error\": \"Internal server error: ${e.message}\"}".toByteArray(),
223+
null,
222224
"application/json"
223225
)
224226
}
@@ -230,6 +232,7 @@ class SettingsClient(private val settingsProvider: ISettingsProvider) {
230232
500,
231233
emptyMap<Any?, Any?>().toMutableMap(),
232234
"{\"error\": \"Callback error: ${e.message}\"}".toByteArray(),
235+
null,
233236
"application/json"
234237
)
235238
} catch (callbackError: Exception) {

sdk/src/main/java/com/penumbraos/sdk/api/types/settingsTypes.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.penumbraos.sdk.api.types
22

3+
import android.os.ParcelFileDescriptor
4+
35
data class HttpRequest(
46
val path: String,
57
val method: String,
@@ -39,6 +41,7 @@ data class HttpResponse(
3941
val statusCode: Int = 200,
4042
val headers: Map<String, String> = emptyMap(),
4143
val body: ByteArray? = null,
44+
val file: ParcelFileDescriptor? = null,
4245
val contentType: String = "application/json"
4346
) {
4447
override fun equals(other: Any?): Boolean {

0 commit comments

Comments
 (0)