From 2c064fe15cf2cb48f72581bbb827303c76e61998 Mon Sep 17 00:00:00 2001 From: CodeSteak Date: Sun, 2 Jun 2019 20:58:21 +0200 Subject: [PATCH 1/5] add GSON dependency --- client/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/client/build.gradle b/client/build.gradle index f368093..e3b66ee 100644 --- a/client/build.gradle +++ b/client/build.gradle @@ -28,6 +28,7 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "no.tornado:tornadofx:$tornadofx_version" implementation "com.jfoenix:jfoenix:8.0.8" + implementation 'com.google.code.gson:gson:2.8.5' } compileKotlin { From d907ff138ac15312a9acd28edfb3e2c44ff28c56 Mon Sep 17 00:00:00 2001 From: CodeSteak Date: Sun, 2 Jun 2019 20:59:05 +0200 Subject: [PATCH 2/5] implement PING Netop --- .../controller/net/Connection.kt | 65 +++++++ .../controller/net/Packet.kt | 167 ++++++++++++++++++ .../texturesyncclient/controller/net/test.kt | 13 ++ 3 files changed, 245 insertions(+) create mode 100644 client/src/main/kotlin/org/hso/texturesyncclient/controller/net/Connection.kt create mode 100644 client/src/main/kotlin/org/hso/texturesyncclient/controller/net/Packet.kt create mode 100644 client/src/main/kotlin/org/hso/texturesyncclient/controller/net/test.kt diff --git a/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/Connection.kt b/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/Connection.kt new file mode 100644 index 0000000..f6c2c6a --- /dev/null +++ b/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/Connection.kt @@ -0,0 +1,65 @@ +package org.hso.texturesyncclient.controller.net + +import com.google.gson.* +import java.io.* +import java.lang.Exception +import java.net.* + +@Suppress("MemberVisibilityCanBePrivate") +class Connection(val addr: InetAddress, val port: Int = 10796) : Closeable { + + var socket: Socket? = null + var output: DataOutputStream? = null + var input: DataInputStream? = null + + @Throws(IOException::class) + private fun getStreams(): Pair { + val i: DataInputStream + val o: DataOutputStream + + if (socket == null || !socket!!.isConnected) { + val sock = Socket(addr, port) + i = DataInputStream(BufferedInputStream(sock.getInputStream())) + o = DataOutputStream(BufferedOutputStream(sock.getOutputStream())) + + input = i + output = o + socket = sock + } else { + i = input!! + o = output!! + } + + return Pair(i, o) + } + + @Throws(IOException::class) + fun ping() { + val io = getStreams() + + val obj = JsonObject() + obj.add("ping", JsonObject()) + + JsonPacket(obj).write(io.second) + + when (Packet.read(io.first)) { + is JsonPacket -> return + is ErrorPacket -> throw Exception("TODO") + is BinaryPacket -> throw Exception("TODO") + } + } + + @Throws(IOException::class) + override fun close() { + if (output != null) { + output!!.close() + } + if (input != null) { + input!!.close() + } + if (socket != null) { + socket!!.close() + } + } + +} \ No newline at end of file diff --git a/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/Packet.kt b/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/Packet.kt new file mode 100644 index 0000000..4b6b531 --- /dev/null +++ b/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/Packet.kt @@ -0,0 +1,167 @@ +package org.hso.texturesyncclient.controller.net + +import com.google.gson.JsonObject +import com.google.gson.JsonParseException +import com.google.gson.JsonParser +import java.io.DataInputStream +import java.io.DataOutputStream +import java.io.IOException +import java.lang.Exception + +open class PacketException(msg: String) : Exception(msg) +class PacketTooLongException : PacketException("The Package is too long.") +class PacketInvalidType : PacketException("The Package has an Invalid Type.") +class PacketInvalidData : PacketException("The Package has an Invalid Data. (e.g. Invalid Json.)") + +abstract class Packet { + + @Throws(IOException::class) + abstract fun write(out: DataOutputStream) + + companion object { + + const val TYPE_ERROR: Byte = 0 + protected const val TYPE_ERROR_MAX_PAYLOAD: Int = 1024 + + const val TYPE_JSON: Byte = 1 + protected const val TYPE_JSON_MAX_PAYLOAD: Int = 16 * 1024 * 1024 + + const val TYPE_BINARY: Byte = 2 + protected const val TYPE_BINARY_MAX_PAYLOAD: Int = 512 * 1024 * 1024 + + @Throws(PacketException::class, IOException::class) + fun read(input: DataInputStream): Packet { + // Type Byte + val type = input.readByte() + + // 3 Reserved Bytes + input.readByte() + input.readByte() + input.readByte() + + // 4 Len Bytes + val length = input.readInt() + + when (type) { + TYPE_ERROR -> if (length > TYPE_ERROR_MAX_PAYLOAD) { + throw PacketTooLongException() + } + + TYPE_JSON -> if (length > TYPE_JSON_MAX_PAYLOAD) { + throw PacketTooLongException() + } + + TYPE_BINARY -> if (length > TYPE_BINARY_MAX_PAYLOAD) { + throw PacketTooLongException() + } + + else -> throw PacketInvalidType() + } + + val payload = ByteArray(length) + input.readFully(payload) + + when (type) { + TYPE_ERROR -> { + val msg = String(payload) + val results = msg.split(' ', ignoreCase = false, limit = 2) + + return if (results.size == 2) { + val code = results[0].toIntOrNull() + + if (code == null) { + ErrorPacket(0, msg) + } else { + ErrorPacket(code, results[1]) + } + } else { + ErrorPacket(0, msg) + } + } + + TYPE_JSON -> { + try { + val obj = JsonParser().parse(String(payload)).asJsonObject + + return JsonPacket(obj) + } catch (e: JsonParseException) { + throw PacketInvalidData() + } + } + + TYPE_BINARY -> { + return BinaryPacket(payload) + } + + else -> { + // Unreachable + throw PacketInvalidType() + } + } + } + } + +} + +data class JsonPacket(val content: JsonObject) : Packet() { + override fun write(out: DataOutputStream) { + val payload = content.toString().toByteArray() + // Tag Byte + out.writeByte(TYPE_JSON.toInt()) + + // 3 Reserved Bytes + out.writeByte(0x42) + out.writeByte(0x42) + out.writeByte(0x42) + + // Length of Payload + out.writeInt(payload.size) + + // Payload + out.write(payload) + + out.flush() + } +} + +@Suppress("MemberVisibilityCanBePrivate") +class BinaryPacket(val content: ByteArray) : Packet() { + override fun write(out: DataOutputStream) { + // Tag Byte + out.writeByte(TYPE_BINARY.toInt()) + + // 3 Reserved Bytes + out.writeByte(0x42) + out.writeByte(0x42) + out.writeByte(0x42) + + // Length of Payload + out.writeInt(content.size) + + // Payload + out.write(content) + + out.flush() + } +} + +data class ErrorPacket(val code: Int, val message: String) : Packet() { + override fun write(out: DataOutputStream) { + val payload = "$code $message".toByteArray() + // Tag Byte + out.writeByte(TYPE_ERROR.toInt()) + + // 3 Reserved Bytes + out.writeByte(0x42) + out.writeByte(0x42) + out.writeByte(0x42) + + // Length of Payload + out.writeInt(payload.size) + + // Payload + out.write(payload) + + out.flush() + } +} \ No newline at end of file diff --git a/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/test.kt b/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/test.kt new file mode 100644 index 0000000..1a1f0c9 --- /dev/null +++ b/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/test.kt @@ -0,0 +1,13 @@ +package org.hso.texturesyncclient.controller.net + +import java.net.* + +fun main() { + // Just some test code. + + val con = Connection(InetAddress.getByName("::1")) + + con.ping() + + con.close() +} \ No newline at end of file From 2e344da2f4e77b74e8f4cf408e8aa09499f0565b Mon Sep 17 00:00:00 2001 From: CodeSteak Date: Sun, 2 Jun 2019 22:04:01 +0200 Subject: [PATCH 3/5] implement query ; fix error handling --- .../controller/net/Connection.kt | 46 +++++++++++++++++-- .../controller/net/InternalDataModel.kt | 14 ++++++ .../controller/net/Packet.kt | 16 ++----- .../texturesyncclient/controller/net/error.kt | 16 +++++++ .../texturesyncclient/controller/net/test.kt | 9 ++++ 5 files changed, 86 insertions(+), 15 deletions(-) create mode 100644 client/src/main/kotlin/org/hso/texturesyncclient/controller/net/InternalDataModel.kt create mode 100644 client/src/main/kotlin/org/hso/texturesyncclient/controller/net/error.kt diff --git a/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/Connection.kt b/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/Connection.kt index f6c2c6a..d4a7eb8 100644 --- a/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/Connection.kt +++ b/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/Connection.kt @@ -2,9 +2,10 @@ package org.hso.texturesyncclient.controller.net import com.google.gson.* import java.io.* -import java.lang.Exception +import java.lang.RuntimeException import java.net.* + @Suppress("MemberVisibilityCanBePrivate") class Connection(val addr: InetAddress, val port: Int = 10796) : Closeable { @@ -42,10 +43,47 @@ class Connection(val addr: InetAddress, val port: Int = 10796) : Closeable { JsonPacket(obj).write(io.second) - when (Packet.read(io.first)) { + val pkg = Packet.read(io.first) + + when (pkg) { is JsonPacket -> return - is ErrorPacket -> throw Exception("TODO") - is BinaryPacket -> throw Exception("TODO") + is BinaryPacket -> throw ConnectionUnexpectedPacket() + is ErrorPacket -> throw ConnectionErrorException(pkg) + else -> throw RuntimeException("Unreachable") + } + } + + fun query(query : Array) : Array { + val io = getStreams() + + val obj = JsonObject() + obj.add("query", { + val inner = JsonObject(); + inner.add("query", { + val array = JsonArray() + for(queryString in query) { + array.add(queryString) + } + array + }()) + inner + }()) + + JsonPacket(obj).write(io.second) + + val pkg = Packet.read(io.first) + + when (pkg) { + is JsonPacket -> { + try { + return Gson().fromJson>(pkg.content, Array::class.java) + } catch (e : JsonSyntaxException ){ + throw ConnectionInvalidJsonException(e) + } + } + is BinaryPacket -> throw ConnectionUnexpectedPacket() + is ErrorPacket -> throw ConnectionErrorException(pkg) + else -> throw RuntimeException("Unreachable") } } diff --git a/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/InternalDataModel.kt b/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/InternalDataModel.kt new file mode 100644 index 0000000..787788c --- /dev/null +++ b/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/InternalDataModel.kt @@ -0,0 +1,14 @@ +package org.hso.texturesyncclient.controller.net + +// These types will be converted to the model.DataModel + +@Suppress("ArrayInDataClass") +data class InternalTexture( + val id : String, + val name : String, + val tags : Array, + val format : String, + val resolution: Array, + val added_on : String, + val texture_hash: String +) \ No newline at end of file diff --git a/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/Packet.kt b/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/Packet.kt index 4b6b531..9be0562 100644 --- a/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/Packet.kt +++ b/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/Packet.kt @@ -1,17 +1,11 @@ package org.hso.texturesyncclient.controller.net -import com.google.gson.JsonObject +import com.google.gson.JsonElement import com.google.gson.JsonParseException import com.google.gson.JsonParser import java.io.DataInputStream import java.io.DataOutputStream import java.io.IOException -import java.lang.Exception - -open class PacketException(msg: String) : Exception(msg) -class PacketTooLongException : PacketException("The Package is too long.") -class PacketInvalidType : PacketException("The Package has an Invalid Type.") -class PacketInvalidData : PacketException("The Package has an Invalid Data. (e.g. Invalid Json.)") abstract class Packet { @@ -81,7 +75,7 @@ abstract class Packet { TYPE_JSON -> { try { - val obj = JsonParser().parse(String(payload)).asJsonObject + val obj = JsonParser().parse(String(payload)) return JsonPacket(obj) } catch (e: JsonParseException) { @@ -103,7 +97,7 @@ abstract class Packet { } -data class JsonPacket(val content: JsonObject) : Packet() { +data class JsonPacket(val content: JsonElement) : Packet() { override fun write(out: DataOutputStream) { val payload = content.toString().toByteArray() // Tag Byte @@ -124,8 +118,8 @@ data class JsonPacket(val content: JsonObject) : Packet() { } } -@Suppress("MemberVisibilityCanBePrivate") -class BinaryPacket(val content: ByteArray) : Packet() { +@Suppress("ArrayInDataClass") +data class BinaryPacket(val content: ByteArray) : Packet() { override fun write(out: DataOutputStream) { // Tag Byte out.writeByte(TYPE_BINARY.toInt()) diff --git a/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/error.kt b/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/error.kt new file mode 100644 index 0000000..7804f55 --- /dev/null +++ b/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/error.kt @@ -0,0 +1,16 @@ +package org.hso.texturesyncclient.controller.net + +import com.google.gson.JsonSyntaxException +import java.lang.Exception + + + +sealed class ConnectionException(val msg : String) : Exception(msg) +class ConnectionErrorException(val error : ErrorPacket) : ConnectionException("${error.code} ${error.message}") +class ConnectionUnexpectedPacket() : ConnectionException("Got Unexpected Type of Packet") +class ConnectionInvalidJsonException(val jsonError : JsonSyntaxException) : ConnectionException("The Format of the Json Received is Unexpected.") + +sealed class PacketException(msg: String) : ConnectionException(msg) +class PacketTooLongException : PacketException("The Package is too long.") +class PacketInvalidType : PacketException("The Package has an Invalid Type.") +class PacketInvalidData : PacketException("The Package has an Invalid Data. (e.g. Invalid Json.)") diff --git a/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/test.kt b/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/test.kt index 1a1f0c9..6f3a6a0 100644 --- a/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/test.kt +++ b/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/test.kt @@ -9,5 +9,14 @@ fun main() { con.ping() + + println("Query:") + for (tex in con.query( + arrayOf("Red", "Food") + )) { + println(tex.toString()) + } + println() + con.close() } \ No newline at end of file From d7dd858d42377aa8c1a237e1659f71dbfd710e54 Mon Sep 17 00:00:00 2001 From: CodeSteak Date: Sun, 2 Jun 2019 22:32:19 +0200 Subject: [PATCH 4/5] Match DataModel On Query --- .../controller/net/Connection.kt | 9 ++- .../controller/net/InternalDataModel.kt | 70 +++++++++++++++++-- .../texturesyncclient/controller/net/error.kt | 7 +- .../hso/texturesyncclient/model/DataModel.kt | 2 +- 4 files changed, 76 insertions(+), 12 deletions(-) diff --git a/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/Connection.kt b/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/Connection.kt index d4a7eb8..3ad9e78 100644 --- a/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/Connection.kt +++ b/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/Connection.kt @@ -1,6 +1,7 @@ package org.hso.texturesyncclient.controller.net import com.google.gson.* +import org.hso.texturesyncclient.model.Texture import java.io.* import java.lang.RuntimeException import java.net.* @@ -53,7 +54,7 @@ class Connection(val addr: InetAddress, val port: Int = 10796) : Closeable { } } - fun query(query : Array) : Array { + fun query(query : Array) : Array { val io = getStreams() val obj = JsonObject() @@ -76,9 +77,11 @@ class Connection(val addr: InetAddress, val port: Int = 10796) : Closeable { when (pkg) { is JsonPacket -> { try { - return Gson().fromJson>(pkg.content, Array::class.java) + return Gson().fromJson>(pkg.content, Array::class.java).map { + tex -> tex.toTexture() + }.toTypedArray() } catch (e : JsonSyntaxException ){ - throw ConnectionInvalidJsonException(e) + throw ConnectionInvalidJsonException() } } is BinaryPacket -> throw ConnectionUnexpectedPacket() diff --git a/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/InternalDataModel.kt b/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/InternalDataModel.kt index 787788c..8f7dacf 100644 --- a/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/InternalDataModel.kt +++ b/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/InternalDataModel.kt @@ -1,14 +1,72 @@ package org.hso.texturesyncclient.controller.net +import org.hso.texturesyncclient.model.Texture +import org.hso.texturesyncclient.model.TextureFormat +import java.lang.Exception +import java.util.* + // These types will be converted to the model.DataModel +private fun bytes2hexString(bytes: ByteArray): String { + val s = StringBuilder(64) + for (byte in bytes) { + s.append(String.format("%02X"), byte) + } + return s.toString() +} + +private fun hexString2Bytes(bytes: String): ByteArray { + return ByteArray(bytes.length / 2) { i -> + bytes.substring(i * 2, i * 2 + 2).toInt(16).toByte() + } +} + @Suppress("ArrayInDataClass") data class InternalTexture( - val id : String, - val name : String, - val tags : Array, - val format : String, + val id: String, + val name: String, + val tags: Array, + val format: String, val resolution: Array, - val added_on : String, + val added_on: Array, val texture_hash: String -) \ No newline at end of file +) { + constructor(tex: Texture) : this( + id = tex.id.toString(), + name = tex.name, + tags = tex.tags.clone(), + format = when (tex.format) { + TextureFormat.PNG -> "png" + TextureFormat.JPEG -> "jpeg" + }, + resolution = arrayOf(tex.resolution.first, tex.resolution.second), + added_on = arrayOf( + tex.addedOn.get(Calendar.YEAR), // + tex.addedOn.get(Calendar.MONTH), // + tex.addedOn.get(Calendar.DAY_OF_MONTH) + ), + texture_hash = bytes2hexString(tex.textureHash) + ) + + @Throws(ConnectionException::class) + fun toTexture(): Texture { + try { + return Texture( + id = UUID.fromString(id), + name = name, + tags = tags.clone(), + format = when (format.toLowerCase()) { + "jpeg" -> TextureFormat.JPEG + "jpg" -> TextureFormat.JPEG + "png" -> TextureFormat.PNG + else -> throw ConnectionInvalidJsonException() + }, + resolution = Pair(resolution[0], resolution[1]), + addedOn = GregorianCalendar(added_on[0], added_on[1], added_on[2]), + textureHash = hexString2Bytes(texture_hash) + ) + } catch (e: Exception) { // i Know, but no time :[] + throw ConnectionInvalidJsonException() + } + } +} \ No newline at end of file diff --git a/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/error.kt b/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/error.kt index 7804f55..93679f0 100644 --- a/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/error.kt +++ b/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/error.kt @@ -6,9 +6,12 @@ import java.lang.Exception sealed class ConnectionException(val msg : String) : Exception(msg) + class ConnectionErrorException(val error : ErrorPacket) : ConnectionException("${error.code} ${error.message}") -class ConnectionUnexpectedPacket() : ConnectionException("Got Unexpected Type of Packet") -class ConnectionInvalidJsonException(val jsonError : JsonSyntaxException) : ConnectionException("The Format of the Json Received is Unexpected.") +class ConnectionUnexpectedPacket : ConnectionException("Got Unexpected Type of Packet") +class ConnectionInvalidJsonException : ConnectionException("The Format of the Json Received is Unexpected.") + + sealed class PacketException(msg: String) : ConnectionException(msg) class PacketTooLongException : PacketException("The Package is too long.") diff --git a/client/src/main/kotlin/org/hso/texturesyncclient/model/DataModel.kt b/client/src/main/kotlin/org/hso/texturesyncclient/model/DataModel.kt index 089a425..7957335 100644 --- a/client/src/main/kotlin/org/hso/texturesyncclient/model/DataModel.kt +++ b/client/src/main/kotlin/org/hso/texturesyncclient/model/DataModel.kt @@ -16,6 +16,6 @@ data class Texture( val tags : Array, val format : TextureFormat, val resolution : Pair, - val addedOn : Date, + val addedOn : Calendar, val textureHash : ByteArray ) From 872fc6c289b1705dea5996b711e38cb2e4637c61 Mon Sep 17 00:00:00 2001 From: CodeSteak Date: Mon, 3 Jun 2019 15:03:25 +0200 Subject: [PATCH 5/5] restructure & rename all things in Net --- .../controller/net/Connection.kt | 38 +++++++++---------- ...ernalDataModel.kt => InternalJsonModel.kt} | 35 ++++++++--------- .../controller/net/{Packet.kt => Package.kt} | 20 +++++----- .../texturesyncclient/controller/net/error.kt | 14 +++---- .../hso/texturesyncclient/model/DataModel.kt | 3 +- 5 files changed, 55 insertions(+), 55 deletions(-) rename client/src/main/kotlin/org/hso/texturesyncclient/controller/net/{InternalDataModel.kt => InternalJsonModel.kt} (98%) rename client/src/main/kotlin/org/hso/texturesyncclient/controller/net/{Packet.kt => Package.kt} (87%) diff --git a/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/Connection.kt b/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/Connection.kt index 3ad9e78..3511810 100644 --- a/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/Connection.kt +++ b/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/Connection.kt @@ -6,21 +6,21 @@ import java.io.* import java.lang.RuntimeException import java.net.* - @Suppress("MemberVisibilityCanBePrivate") -class Connection(val addr: InetAddress, val port: Int = 10796) : Closeable { +class Connection(val address: InetAddress, val port: Int = 10796) : Closeable { var socket: Socket? = null var output: DataOutputStream? = null var input: DataInputStream? = null @Throws(IOException::class) + @Synchronized private fun getStreams(): Pair { val i: DataInputStream val o: DataOutputStream if (socket == null || !socket!!.isConnected) { - val sock = Socket(addr, port) + val sock = Socket(address, port) i = DataInputStream(BufferedInputStream(sock.getInputStream())) o = DataOutputStream(BufferedOutputStream(sock.getOutputStream())) @@ -35,31 +35,32 @@ class Connection(val addr: InetAddress, val port: Int = 10796) : Closeable { return Pair(i, o) } - @Throws(IOException::class) + @Throws(IOException::class, ConnectionException::class) + @Synchronized fun ping() { val io = getStreams() val obj = JsonObject() obj.add("ping", JsonObject()) - JsonPacket(obj).write(io.second) + JsonPackage(obj).write(io.second) - val pkg = Packet.read(io.first) - - when (pkg) { - is JsonPacket -> return - is BinaryPacket -> throw ConnectionUnexpectedPacket() - is ErrorPacket -> throw ConnectionErrorException(pkg) + when (val pkg = Package.read(io.first)) { + is JsonPackage -> return + is BinaryPackage -> throw ConnectionUnexpecedPacketException() + is ErrorPackage -> throw ConnectionErrorException(pkg) else -> throw RuntimeException("Unreachable") } } + @Throws(IOException::class, ConnectionException::class) + @Synchronized fun query(query : Array) : Array { val io = getStreams() val obj = JsonObject() obj.add("query", { - val inner = JsonObject(); + val inner = JsonObject() inner.add("query", { val array = JsonArray() for(queryString in query) { @@ -70,12 +71,10 @@ class Connection(val addr: InetAddress, val port: Int = 10796) : Closeable { inner }()) - JsonPacket(obj).write(io.second) + JsonPackage(obj).write(io.second) - val pkg = Packet.read(io.first) - - when (pkg) { - is JsonPacket -> { + when (val pkg = Package.read(io.first)) { + is JsonPackage -> { try { return Gson().fromJson>(pkg.content, Array::class.java).map { tex -> tex.toTexture() @@ -84,13 +83,14 @@ class Connection(val addr: InetAddress, val port: Int = 10796) : Closeable { throw ConnectionInvalidJsonException() } } - is BinaryPacket -> throw ConnectionUnexpectedPacket() - is ErrorPacket -> throw ConnectionErrorException(pkg) + is BinaryPackage -> throw ConnectionUnexpecedPacketException() + is ErrorPackage -> throw ConnectionErrorException(pkg) else -> throw RuntimeException("Unreachable") } } @Throws(IOException::class) + @Synchronized override fun close() { if (output != null) { output!!.close() diff --git a/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/InternalDataModel.kt b/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/InternalJsonModel.kt similarity index 98% rename from client/src/main/kotlin/org/hso/texturesyncclient/controller/net/InternalDataModel.kt rename to client/src/main/kotlin/org/hso/texturesyncclient/controller/net/InternalJsonModel.kt index 8f7dacf..f48b84f 100644 --- a/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/InternalDataModel.kt +++ b/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/InternalJsonModel.kt @@ -1,28 +1,14 @@ package org.hso.texturesyncclient.controller.net +// These types will be converted to the model.DataModel + import org.hso.texturesyncclient.model.Texture import org.hso.texturesyncclient.model.TextureFormat import java.lang.Exception import java.util.* -// These types will be converted to the model.DataModel - -private fun bytes2hexString(bytes: ByteArray): String { - val s = StringBuilder(64) - for (byte in bytes) { - s.append(String.format("%02X"), byte) - } - return s.toString() -} - -private fun hexString2Bytes(bytes: String): ByteArray { - return ByteArray(bytes.length / 2) { i -> - bytes.substring(i * 2, i * 2 + 2).toInt(16).toByte() - } -} - @Suppress("ArrayInDataClass") -data class InternalTexture( +internal data class InternalTexture( val id: String, val name: String, val tags: Array, @@ -31,6 +17,7 @@ data class InternalTexture( val added_on: Array, val texture_hash: String ) { + constructor(tex: Texture) : this( id = tex.id.toString(), name = tex.name, @@ -69,4 +56,18 @@ data class InternalTexture( throw ConnectionInvalidJsonException() } } +} + +private fun bytes2hexString(bytes: ByteArray): String { + val s = StringBuilder(64) + for (byte in bytes) { + s.append(String.format("%02X"), byte) + } + return s.toString() +} + +private fun hexString2Bytes(bytes: String): ByteArray { + return ByteArray(bytes.length / 2) { i -> + bytes.substring(i * 2, i * 2 + 2).toInt(16).toByte() + } } \ No newline at end of file diff --git a/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/Packet.kt b/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/Package.kt similarity index 87% rename from client/src/main/kotlin/org/hso/texturesyncclient/controller/net/Packet.kt rename to client/src/main/kotlin/org/hso/texturesyncclient/controller/net/Package.kt index 9be0562..e9f3bab 100644 --- a/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/Packet.kt +++ b/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/Package.kt @@ -7,7 +7,7 @@ import java.io.DataInputStream import java.io.DataOutputStream import java.io.IOException -abstract class Packet { +internal abstract class Package { @Throws(IOException::class) abstract fun write(out: DataOutputStream) @@ -24,7 +24,7 @@ abstract class Packet { protected const val TYPE_BINARY_MAX_PAYLOAD: Int = 512 * 1024 * 1024 @Throws(PacketException::class, IOException::class) - fun read(input: DataInputStream): Packet { + fun read(input: DataInputStream): Package { // Type Byte val type = input.readByte() @@ -64,12 +64,12 @@ abstract class Packet { val code = results[0].toIntOrNull() if (code == null) { - ErrorPacket(0, msg) + ErrorPackage(0, msg) } else { - ErrorPacket(code, results[1]) + ErrorPackage(code, results[1]) } } else { - ErrorPacket(0, msg) + ErrorPackage(0, msg) } } @@ -77,14 +77,14 @@ abstract class Packet { try { val obj = JsonParser().parse(String(payload)) - return JsonPacket(obj) + return JsonPackage(obj) } catch (e: JsonParseException) { throw PacketInvalidData() } } TYPE_BINARY -> { - return BinaryPacket(payload) + return BinaryPackage(payload) } else -> { @@ -97,7 +97,7 @@ abstract class Packet { } -data class JsonPacket(val content: JsonElement) : Packet() { +internal data class JsonPackage(val content: JsonElement) : Package() { override fun write(out: DataOutputStream) { val payload = content.toString().toByteArray() // Tag Byte @@ -119,7 +119,7 @@ data class JsonPacket(val content: JsonElement) : Packet() { } @Suppress("ArrayInDataClass") -data class BinaryPacket(val content: ByteArray) : Packet() { +internal data class BinaryPackage(val content: ByteArray) : Package() { override fun write(out: DataOutputStream) { // Tag Byte out.writeByte(TYPE_BINARY.toInt()) @@ -139,7 +139,7 @@ data class BinaryPacket(val content: ByteArray) : Packet() { } } -data class ErrorPacket(val code: Int, val message: String) : Packet() { +internal data class ErrorPackage(val code: Int, val message: String) : Package() { override fun write(out: DataOutputStream) { val payload = "$code $message".toByteArray() // Tag Byte diff --git a/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/error.kt b/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/error.kt index 93679f0..10dfd02 100644 --- a/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/error.kt +++ b/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/error.kt @@ -1,18 +1,18 @@ +@file:Suppress("MemberVisibilityCanBePrivate") + package org.hso.texturesyncclient.controller.net -import com.google.gson.JsonSyntaxException import java.lang.Exception +sealed class ConnectionException(override val message : String) : Exception(message) - -sealed class ConnectionException(val msg : String) : Exception(msg) - -class ConnectionErrorException(val error : ErrorPacket) : ConnectionException("${error.code} ${error.message}") -class ConnectionUnexpectedPacket : ConnectionException("Got Unexpected Type of Packet") +class ConnectionErrorException(val errorCode : Int, val errorMessage : String) : ConnectionException("${errorCode} ${errorMessage}") { + internal constructor(err : ErrorPackage) : this(err.code, err.message) +} +class ConnectionUnexpecedPacketException : ConnectionException("Got Unexpected Type of Packet") class ConnectionInvalidJsonException : ConnectionException("The Format of the Json Received is Unexpected.") - sealed class PacketException(msg: String) : ConnectionException(msg) class PacketTooLongException : PacketException("The Package is too long.") class PacketInvalidType : PacketException("The Package has an Invalid Type.") diff --git a/client/src/main/kotlin/org/hso/texturesyncclient/model/DataModel.kt b/client/src/main/kotlin/org/hso/texturesyncclient/model/DataModel.kt index 7957335..e473889 100644 --- a/client/src/main/kotlin/org/hso/texturesyncclient/model/DataModel.kt +++ b/client/src/main/kotlin/org/hso/texturesyncclient/model/DataModel.kt @@ -2,8 +2,7 @@ package org.hso.texturesyncclient.model import java.util.* -class DataModel { -} +class DataModel enum class TextureFormat { PNG, JPEG,