From 7fa80ec0486d8f471a7ec44c3efb7b8a31348c2a Mon Sep 17 00:00:00 2001 From: Kelvin <kelvin@futo.org> Date: Thu, 16 Nov 2023 17:13:23 +0100 Subject: [PATCH] Fix communication issues devportal --- .../api/http/server/HttpContext.kt | 74 +++++++++++++++---- .../api/http/server/ManagedHttpServer.kt | 13 ++-- .../developer/DeveloperEndpoints.kt | 2 +- .../stores/db/ManagedDBIndex.kt | 5 ++ .../stores/db/ManagedDBStore.kt | 5 ++ 5 files changed, 75 insertions(+), 24 deletions(-) create mode 100644 app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBIndex.kt create mode 100644 app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBStore.kt diff --git a/app/src/main/java/com/futo/platformplayer/api/http/server/HttpContext.kt b/app/src/main/java/com/futo/platformplayer/api/http/server/HttpContext.kt index 537ac7a2..5b7740c8 100644 --- a/app/src/main/java/com/futo/platformplayer/api/http/server/HttpContext.kt +++ b/app/src/main/java/com/futo/platformplayer/api/http/server/HttpContext.kt @@ -7,13 +7,15 @@ import com.futo.platformplayer.api.media.Serializer import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json +import java.io.BufferedInputStream import java.io.BufferedReader import java.io.OutputStream import java.io.StringWriter import java.net.SocketTimeoutException +import java.nio.ByteBuffer class HttpContext : AutoCloseable { - private val _stream: BufferedReader; + private val _stream: BufferedInputStream; private var _responseStream: OutputStream? = null; var id: String? = null; @@ -38,14 +40,40 @@ class HttpContext : AutoCloseable { private val _responseHeaders: HttpHeaders = HttpHeaders(); + private val newLineByte = "\n"[0]; + private fun readStreamLine(): String { + //TODO: This is not ideal.. + var twoByteArray = ByteBuffer.allocate(2); + var lastChar: Char = Char.MIN_VALUE; + val builder = StringBuilder(); + do { + val firstByte = _stream.read(); + if(firstByte == -1) + break; + if(isCharacter2Bytes(firstByte)) { + twoByteArray.put(0, firstByte.toByte()); + val secondByte = _stream.read(); + if(secondByte == -1) + break; + twoByteArray.put(1, secondByte.toByte()); + } + else + lastChar = firstByte.toChar(); + builder.append(lastChar); + if(lastChar == newLineByte) + break; + } + while(lastChar != Char.MIN_VALUE); + return builder.toString(); + } - constructor(stream: BufferedReader, responseStream: OutputStream? = null, requestId: String? = null, timeout: Int? = null) { + constructor(stream: BufferedInputStream, responseStream: OutputStream? = null, requestId: String? = null, timeout: Int? = null) { _stream = stream; _responseStream = responseStream; this.id = requestId; try { - head = stream.readLine() ?: throw EmptyRequestException("No head found"); + head = readStreamLine() ?: throw EmptyRequestException("No head found"); } catch(ex: SocketTimeoutException) { if((timeout ?: 0) > 0) @@ -78,7 +106,7 @@ class HttpContext : AutoCloseable { } while (true) { - val line = stream.readLine(); + val line = readStreamLine(); val headerEndIndex = line.indexOf(":"); if (headerEndIndex == -1) break; @@ -172,27 +200,37 @@ class HttpContext : AutoCloseable { statusCode = status; } - fun readContentBytes(buffer: CharArray, length: Int) : Int { - val reading = Math.min(length, (contentLength - _totalRead).toInt()); + fun readContentBytes(buffer: ByteArray, length: Int) : Int { + val reading = if(contentLength - _totalRead < length) + (contentLength - _totalRead).toInt(); + else + length; val read = _stream.read(buffer, 0, reading); _totalRead += read; - - //TODO: Fix this properly - if(contentLength - _totalRead < 400 && read < length) { - _totalRead = contentLength; - } return read; } fun readContentString() : String{ val writer = StringWriter(); var read = 0; - val buffer = CharArray(4096); + val buffer = ByteArray(8192); + val twoByteArray = ByteArray(2); do { read = readContentBytes(buffer, buffer.size); - writer.write(buffer, 0, read); - } while(read > 0);// && _stream.ready()); - //if(!_stream.ready()) - // _totalRead = contentLength; + + if(read > 0) { + if (isCharacter2Bytes(buffer[read - 1].toInt())) { + //Fixes overlapping buffers + writer.write(String(buffer, 0, read - 1)); + twoByteArray[0] = buffer[read - 1]; + val secondByte = _stream.read(); + if (secondByte < 0) + break; + twoByteArray[1] = secondByte.toByte(); + writer.write(String(twoByteArray)); + } else + writer.write(String(buffer, 0, read)); + } + } while(read > 0); return writer.toString(); } inline fun <reified T> readContentJson() : T { @@ -210,6 +248,10 @@ class HttpContext : AutoCloseable { } } + private fun isCharacter2Bytes(firstByte: Int): Boolean { + return firstByte and 0xE0 == 0xC0 + } + companion object { private val TAG = "HttpRequest"; private val statusCodeMap = mapOf( diff --git a/app/src/main/java/com/futo/platformplayer/api/http/server/ManagedHttpServer.kt b/app/src/main/java/com/futo/platformplayer/api/http/server/ManagedHttpServer.kt index 2579cf60..df695ed1 100644 --- a/app/src/main/java/com/futo/platformplayer/api/http/server/ManagedHttpServer.kt +++ b/app/src/main/java/com/futo/platformplayer/api/http/server/ManagedHttpServer.kt @@ -5,8 +5,7 @@ import com.futo.platformplayer.api.http.ManagedHttpClient import com.futo.platformplayer.api.http.server.exceptions.EmptyRequestException import com.futo.platformplayer.api.http.server.handlers.HttpFuntionHandler import com.futo.platformplayer.api.http.server.handlers.HttpHandler -import java.io.BufferedReader -import java.io.InputStreamReader +import java.io.BufferedInputStream import java.io.OutputStream import java.lang.reflect.Field import java.lang.reflect.Method @@ -76,12 +75,12 @@ class ManagedHttpServer(private val _requestedPort: Int = 0) { private fun handleClientRequest(socket: Socket) { _workerPool?.submit { - val requestReader = BufferedReader(InputStreamReader(socket.getInputStream())) + val requestStream = BufferedInputStream(socket.getInputStream()); val responseStream = socket.getOutputStream(); val requestId = UUID.randomUUID().toString().substring(0, 5); try { - keepAliveLoop(requestReader, responseStream, requestId) { req -> + keepAliveLoop(requestStream, responseStream, requestId) { req -> req.use { httpContext -> if(!httpContext.path.startsWith("/plugin/")) Logger.i(TAG, "[${req.id}] ${httpContext.method}: ${httpContext.path}") @@ -107,7 +106,7 @@ class ManagedHttpServer(private val _requestedPort: Int = 0) { Logger.e(TAG, "Failed to handle client request.", e); } finally { - requestReader.close(); + requestStream.close(); responseStream.close(); } }; @@ -188,7 +187,7 @@ class ManagedHttpServer(private val _requestedPort: Int = 0) { } } - private fun keepAliveLoop(requestReader: BufferedReader, responseStream: OutputStream, requestId: String, handler: (HttpContext)->Unit) { + private fun keepAliveLoop(requestReader: BufferedInputStream, responseStream: OutputStream, requestId: String, handler: (HttpContext)->Unit) { val stopCount = _stopCount; var keepAlive = false; var requestsMax = 0; @@ -200,7 +199,7 @@ class ManagedHttpServer(private val _requestedPort: Int = 0) { handler(req); requestsTotal++; - if(req.keepAlive){// && requestReader.ready()) { + if(req.keepAlive) { keepAlive = true; if(req.keepAliveMax > 0) requestsMax = req.keepAliveMax; diff --git a/app/src/main/java/com/futo/platformplayer/developer/DeveloperEndpoints.kt b/app/src/main/java/com/futo/platformplayer/developer/DeveloperEndpoints.kt index 99cd4de7..95502b6d 100644 --- a/app/src/main/java/com/futo/platformplayer/developer/DeveloperEndpoints.kt +++ b/app/src/main/java/com/futo/platformplayer/developer/DeveloperEndpoints.kt @@ -301,7 +301,7 @@ class DeveloperEndpoints(private val context: Context) { if(method != "isLoggedIn") Logger.i(TAG, "Remote Call [${objId}].${method}(...)"); - val parameters = context.readContentString(); //TODO: Temporary + val parameters = context.readContentString(); val remoteObj = getRemoteObject(objId); val paras = JsonParser.parseString(parameters); diff --git a/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBIndex.kt b/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBIndex.kt new file mode 100644 index 00000000..d67bde96 --- /dev/null +++ b/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBIndex.kt @@ -0,0 +1,5 @@ +package com.futo.platformplayer.stores.db + +class ManagedDBIndex { + +} \ No newline at end of file diff --git a/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBStore.kt b/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBStore.kt new file mode 100644 index 00000000..9d24c04f --- /dev/null +++ b/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBStore.kt @@ -0,0 +1,5 @@ +package com.futo.platformplayer.stores.db + +class ManagedDBStore { + +} \ No newline at end of file -- GitLab