mirror of
https://github.com/PenumbraOS/sdk.git
synced 2026-02-03 17:26:48 -06:00
Server endpoint matching custom paths
This commit is contained in:
parent
e951602aac
commit
ca5dcd4e7b
@ -1,5 +1,6 @@
|
||||
package com.penumbraos.bridge_settings
|
||||
|
||||
import android.os.IBinder
|
||||
import android.util.Log
|
||||
import com.penumbraos.bridge.ISettingsProvider
|
||||
import com.penumbraos.bridge.callback.IHttpEndpointCallback
|
||||
@ -343,6 +344,12 @@ class SettingsProvider(private val settingsRegistry: SettingsRegistry) : ISettin
|
||||
Log.e(TAG, "Cannot register HTTP endpoint - web server not initialized")
|
||||
false
|
||||
} else {
|
||||
callback.asBinder().linkToDeath(object : IBinder.DeathRecipient {
|
||||
override fun binderDied() {
|
||||
server.unregisterEndpoint(providerId, path, method)
|
||||
}
|
||||
}, 0)
|
||||
|
||||
val success = server.registerEndpoint(
|
||||
providerId,
|
||||
path,
|
||||
|
||||
@ -280,13 +280,24 @@ class SettingsWebServer(
|
||||
}
|
||||
|
||||
intercept(ApplicationCallPipeline.Call) {
|
||||
val fullPath =
|
||||
call.request.uri.substringBefore('?') // Remove query params from path
|
||||
val fullPath = call.request.uri.substringBefore('?')
|
||||
val method = call.request.httpMethod.value
|
||||
val endpointKey = "${method}:$fullPath"
|
||||
|
||||
var matchedEndpoint: RegisteredEndpoint? = null
|
||||
var pathParams: Map<String, String>? = null
|
||||
|
||||
for (endpoint in registeredEndpoints.values) {
|
||||
if (endpoint.method.equals(method, ignoreCase = true)) {
|
||||
val match = endpoint.matchesPath(fullPath)
|
||||
if (match != null) {
|
||||
matchedEndpoint = endpoint
|
||||
pathParams = match
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val endpoint = registeredEndpoints[endpointKey]
|
||||
if (endpoint != null) {
|
||||
if (matchedEndpoint != null && pathParams != null) {
|
||||
try {
|
||||
val headers = call.request.headers.toMap()
|
||||
.mapValues { it.value.firstOrNull() ?: "" }
|
||||
@ -303,10 +314,11 @@ class SettingsWebServer(
|
||||
method = method,
|
||||
headers = headers,
|
||||
queryParams = queryParams,
|
||||
pathParams = pathParams,
|
||||
body = body
|
||||
)
|
||||
|
||||
val response = endpoint.callback.handle(request)
|
||||
val response = matchedEndpoint.callback.handle(request)
|
||||
|
||||
response.headers.forEach { (key, value) ->
|
||||
call.response.headers.append(key, value)
|
||||
@ -320,7 +332,7 @@ class SettingsWebServer(
|
||||
)
|
||||
return@intercept finish()
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error handling dynamic endpoint $endpointKey", e)
|
||||
Log.e(TAG, "Error handling dynamic endpoint ${matchedEndpoint.path}", e)
|
||||
call.respond(
|
||||
HttpStatusCode.InternalServerError,
|
||||
mapOf("error" to "Internal server error")
|
||||
@ -335,7 +347,7 @@ class SettingsWebServer(
|
||||
webSocket("/ws/settings") {
|
||||
handleWebSocketConnection(this)
|
||||
}
|
||||
|
||||
|
||||
// REST API endpoints
|
||||
get("/api/settings") {
|
||||
try {
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
package com.penumbraos.bridge_settings.server
|
||||
|
||||
object PathParser {
|
||||
fun matchPath(pattern: String, actualPath: String): Map<String, String>? {
|
||||
val patternSegments = pattern.split('/').filter { it.isNotEmpty() }
|
||||
val actualSegments = actualPath.split('/').filter { it.isNotEmpty() }
|
||||
|
||||
if (patternSegments.size != actualSegments.size) {
|
||||
return null
|
||||
}
|
||||
|
||||
val pathParams = mutableMapOf<String, String>()
|
||||
|
||||
for (i in patternSegments.indices) {
|
||||
val patternSegment = patternSegments[i]
|
||||
val actualSegment = actualSegments[i]
|
||||
|
||||
if (patternSegment.startsWith('{') && patternSegment.endsWith('}')) {
|
||||
val variableName = patternSegment.substring(1, patternSegment.length - 1)
|
||||
pathParams[variableName] = actualSegment
|
||||
} else if (patternSegment != actualSegment) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
return pathParams
|
||||
}
|
||||
}
|
||||
@ -11,6 +11,7 @@ data class EndpointRequest(
|
||||
val method: String,
|
||||
val headers: Map<String, String>,
|
||||
val queryParams: Map<String, String>,
|
||||
val pathParams: Map<String, String>,
|
||||
val body: String?
|
||||
)
|
||||
|
||||
@ -35,7 +36,11 @@ data class RegisteredEndpoint(
|
||||
val method: String,
|
||||
val callback: EndpointCallback,
|
||||
val providerId: String
|
||||
)
|
||||
) {
|
||||
fun matchesPath(requestPath: String): Map<String, String>? {
|
||||
return PathParser.matchPath(this.path, requestPath)
|
||||
}
|
||||
}
|
||||
|
||||
class AidlEndpointCallback(
|
||||
private val aidlCallback: IHttpEndpointCallback
|
||||
@ -64,6 +69,7 @@ class AidlEndpointCallback(
|
||||
aidlCallback.onHttpRequest(
|
||||
request.path,
|
||||
request.method,
|
||||
request.pathParams,
|
||||
request.headers,
|
||||
request.queryParams,
|
||||
request.body,
|
||||
|
||||
@ -3,5 +3,5 @@ package com.penumbraos.bridge.callback;
|
||||
import com.penumbraos.bridge.callback.IHttpResponseCallback;
|
||||
|
||||
interface IHttpEndpointCallback {
|
||||
void onHttpRequest(String path, String method, in Map headers, in Map queryParams, String body, IHttpResponseCallback responseCallback);
|
||||
void onHttpRequest(String path, String method, in Map pathParams, in Map headers, in Map queryParams, String body, IHttpResponseCallback responseCallback);
|
||||
}
|
||||
@ -182,6 +182,7 @@ class SettingsClient(private val settingsProvider: ISettingsProvider) {
|
||||
override fun onHttpRequest(
|
||||
path: String,
|
||||
method: String,
|
||||
pathParams: MutableMap<Any?, Any?>,
|
||||
headers: MutableMap<Any?, Any?>?,
|
||||
queryParams: MutableMap<Any?, Any?>?,
|
||||
body: String?,
|
||||
@ -193,7 +194,15 @@ class SettingsClient(private val settingsProvider: ISettingsProvider) {
|
||||
val queryMap = queryParams?.mapKeys { it.key.toString() }
|
||||
?.mapValues { it.value.toString() } ?: emptyMap()
|
||||
|
||||
val request = HttpRequest(path, method, headerMap, queryMap, body)
|
||||
val request =
|
||||
HttpRequest(
|
||||
path,
|
||||
method,
|
||||
pathParams as Map<String, String>,
|
||||
headerMap,
|
||||
queryMap,
|
||||
body
|
||||
)
|
||||
|
||||
scope.launch {
|
||||
try {
|
||||
|
||||
@ -3,6 +3,7 @@ package com.penumbraos.sdk.api.types
|
||||
data class HttpRequest(
|
||||
val path: String,
|
||||
val method: String,
|
||||
val pathParams: Map<String, String>,
|
||||
val headers: Map<String, String>,
|
||||
val queryParams: Map<String, String>,
|
||||
val body: String?
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user