Skip to content

Instantly share code, notes, and snippets.

@hotstu
Last active December 26, 2022 01:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hotstu/ce655e592792bed8e4e6dc1c89b2addc to your computer and use it in GitHub Desktop.
Save hotstu/ce655e592792bed8e4e6dc1c89b2addc to your computer and use it in GitHub Desktop.
NanoHttpd wrapper for jsonrpc4j
import com.google.gson.Gson
import com.googlecode.jsonrpc4j.JsonRpcBasicServer.*
import com.googlecode.jsonrpc4j.JsonRpcServer
import fi.iki.elonen.NanoHTTPD
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.IOException
import java.io.InputStream
import java.nio.charset.StandardCharsets
class Server(
private val services: Map<String, JsonRpcServer>,
private val desc: Map<String, String>,
host: String,
port: Int
) : NanoHTTPD(host, port) {
val mapper = Gson()
override fun serve(session: IHTTPSession): Response {
val uri = session.uri
println("${session.remoteIpAddress}<---$uri")
if (uri == "/") {
return newFixedLengthResponse(
Response.Status.OK,
"text/json",
mapper.toJson(desc)
)
}
var model = uri
if (model.startsWith("/")) {
model = model.substring(1)
}
if (model.contains("/")) {
model = model.substring(0, model.lastIndexOf("/"))
}
val rpc = services.get(model)
?: return newFixedLengthResponse(
Response.Status.NOT_FOUND,
"text/json",
"{\"error\": \"访问的服务不存在\"}",
)
return if (session.method == Method.POST) {
val input: InputStream = session.inputStream
val output: ByteArrayOutputStream = ByteArrayOutputStream()
rpc.handleRequest(input, output)
val byteArrayInputStream = ByteArrayInputStream(output.toByteArray())
return newFixedLengthResponse(
Response.Status.OK,
"text/json",
byteArrayInputStream,
byteArrayInputStream.available().toLong()
)
} else if (session.method == Method.GET) {
val parameters = session.parms
val input: InputStream =
createInputStream(parameters[METHOD], parameters[ID], parameters[PARAMS])
val output: ByteArrayOutputStream = ByteArrayOutputStream()
rpc.handleRequest(input, output)
val byteArrayInputStream = ByteArrayInputStream(output.toByteArray())
return newFixedLengthResponse(
Response.Status.OK,
"text/json",
byteArrayInputStream,
byteArrayInputStream.available().toLong()
)
} else {
throw IOException("Invalid request method, only POST and GET is supported")
}
}
companion object {
/**
* Returns parameters into an [InputStream] of JSON data.
*
* @param method the method
* @param id the id
* @param params the base64 encoded params
* @return the [InputStream]
* @throws IOException on error
*/
fun createInputStream(method: String?, id: String?, params: String?): InputStream {
val envelope = StringBuilder()
envelope.append("{\"")
envelope.append(JSONRPC)
envelope.append("\":\"")
envelope.append(VERSION)
envelope.append("\",\"")
envelope.append(ID)
envelope.append("\":")
// the 'id' value is assumed to be numerical.
if (null != id && !id.isEmpty()) {
envelope.append(id)
} else {
envelope.append("null")
}
envelope.append(",\"")
envelope.append(METHOD)
envelope.append("\":")
if (null != method && !method.isEmpty()) {
envelope.append('"')
envelope.append(method)
envelope.append('"')
} else {
envelope.append("null")
}
envelope.append(",\"")
envelope.append(PARAMS)
envelope.append("\":")
if (null != params && !params.isEmpty()) {
val decodedParams = when (params[0]) {
'[', '{' -> params
else -> throw IOException("badly formed 'param' parameter starting with; [" + params[0] + "]")
}
envelope.append(decodedParams)
} else {
envelope.append("[]")
}
envelope.append('}')
return ByteArrayInputStream(envelope.toString().toByteArray(StandardCharsets.UTF_8))
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment