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 72ad1b2..25eb664 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 @@ -19,7 +19,7 @@ class Connection(val address: InetAddress, val port: Int = 10796) : Closeable { @Throws(IOException::class) @Synchronized - private fun getStreams(): Pair { + private fun withStreams(retry: Boolean = true, inner: (DataInputStream, DataOutputStream) -> R): R { val i: DataInputStream val o: DataOutputStream @@ -40,242 +40,253 @@ class Connection(val address: InetAddress, val port: Int = 10796) : Closeable { o = output!! } - return Pair(i, o) + return try { + inner(i, o) + } catch (e: IOException) { + if (retry) { + println("Got IOException; Retry ${e.message}") + close() + withStreams(false, inner) + } else { + throw e + } + } } @Throws(IOException::class, ConnectionException::class) - @Synchronized fun ping() { - val io = getStreams() + return withStreams { i, o -> - val obj = JsonObject() - obj.add("ping", JsonObject()) + val obj = JsonObject() + obj.add("ping", JsonObject()) - JsonPackage(obj).write(io.second) + JsonPackage(obj).write(o) - when (val pkg = Package.read(io.first)) { - is JsonPackage -> return - is BinaryPackage -> throw ConnectionUnexpectedPacketException() - is ErrorPackage -> throw ConnectionErrorException(pkg) - else -> throw RuntimeException("Unreachable") - } + when (val pkg = Package.read(i)) { + is JsonPackage -> return@withStreams + is BinaryPackage -> throw ConnectionUnexpectedPacketException() + is ErrorPackage -> throw ConnectionErrorException(pkg) + else -> throw RuntimeException("Unreachable") + } + }; } @Throws(IOException::class, ConnectionException::class) - @Synchronized fun query(query: Array): Array { - val io = getStreams() + return withStreams { i, o -> - val obj = JsonObject() - obj.add("query", { - val inner = JsonObject() - inner.add("query", { - val array = JsonArray() - for (queryString in query) { - array.add(queryString) - } - array + val obj = JsonObject() + obj.add("query", { + val inner = JsonObject() + inner.add("query", { + val array = JsonArray() + for (queryString in query) { + array.add(queryString) + } + array + }()) + inner }()) - inner - }()) - JsonPackage(obj).write(io.second) + JsonPackage(obj).write(o) - when (val pkg = Package.read(io.first)) { - is JsonPackage -> { - try { - return Gson().fromJson>(pkg.content, Array::class.java) - .map { tex -> - tex.toTexture() - }.toTypedArray() - } catch (e: JsonSyntaxException) { - throw ConnectionInvalidJsonException() + when (val pkg = Package.read(i)) { + is JsonPackage -> { + try { + return@withStreams Gson().fromJson>( + pkg.content, + Array::class.java + ) + .map { tex -> + tex.toTexture() + }.toTypedArray() + } catch (e: JsonSyntaxException) { + throw ConnectionInvalidJsonException() + } } + is BinaryPackage -> throw ConnectionUnexpectedPacketException() + is ErrorPackage -> throw ConnectionErrorException(pkg) + else -> throw RuntimeException("Unreachable") } - is BinaryPackage -> throw ConnectionUnexpectedPacketException() - is ErrorPackage -> throw ConnectionErrorException(pkg) - else -> throw RuntimeException("Unreachable") } } @Throws(IOException::class, ConnectionException::class) - @Synchronized fun getTextureById(id: UUID): Texture? { - val io = getStreams() + return withStreams { i, o -> - val obj = JsonObject() - obj.add("get_texture", { - val inner = JsonObject() - inner.addProperty("id", id.toString()) - inner - }()) - JsonPackage(obj).write(io.second) + val obj = JsonObject() + obj.add("get_texture", { + val inner = JsonObject() + inner.addProperty("id", id.toString()) + inner + }()) - when (val pkg = Package.read(io.first)) { - is JsonPackage -> { - return if (pkg.content.isJsonNull) { - null - } else { - try { - Gson() - .fromJson(pkg.content, InternalTexture::class.java) - .toTexture() - } catch (e: JsonSyntaxException) { - throw ConnectionInvalidJsonException() - } - } - } - is BinaryPackage -> throw ConnectionUnexpectedPacketException() - is ErrorPackage -> throw ConnectionErrorException(pkg) - else -> throw RuntimeException("Unreachable") - } + JsonPackage(obj).write(o) - } - - @Throws(IOException::class, ConnectionException::class) - @Synchronized - fun getTextureByName(name: String): Texture? { - val io = getStreams() - - val obj = JsonObject() - obj.add("get_texture", { - val inner = JsonObject() - inner.addProperty("name", name) - inner - }()) - - JsonPackage(obj).write(io.second) - - when (val pkg = Package.read(io.first)) { - is JsonPackage -> { - return if (pkg.content.isJsonNull) { - null - } else { - try { - Gson() - .fromJson(pkg.content, InternalTexture::class.java) - .toTexture() - } catch (e: JsonSyntaxException) { - throw ConnectionInvalidJsonException() - } - } - } - is BinaryPackage -> throw ConnectionUnexpectedPacketException() - is ErrorPackage -> throw ConnectionErrorException(pkg) - else -> throw RuntimeException("Unreachable") - } - - } - - @Throws(IOException::class, ConnectionException::class) - @Synchronized - fun getTextureFile(hash: Sha256): ByteArray { - val io = getStreams() - - val obj = JsonObject() - obj.add("get_texture_file", { - val inner = JsonObject() - inner.addProperty("texture_hash", hash.toString()) - inner - }()) - - JsonPackage(obj).write(io.second) - - when (val pkg = Package.read(io.first)) { - is JsonPackage -> throw ConnectionUnexpectedPacketException() - is BinaryPackage -> return pkg.content - is ErrorPackage -> throw ConnectionErrorException(pkg) - else -> throw RuntimeException("Unreachable") - } - - } - - @Throws(IOException::class, ConnectionException::class) - @Synchronized - fun getTexturePreview(hash: Sha256): Image { - val io = getStreams() - - val obj = JsonObject() - obj.add("get_texture_preview", { - val inner = JsonObject() - inner.addProperty("texture_hash", hash.toString()) - inner.addProperty("desired_format", "jpeg") - inner - }()) - - JsonPackage(obj).write(io.second) - - when (val pkg = Package.read(io.first)) { - is JsonPackage -> throw ConnectionUnexpectedPacketException() - is BinaryPackage -> { - return Image(ByteArrayInputStream(pkg.content)) - } - is ErrorPackage -> throw ConnectionErrorException(pkg) - else -> throw RuntimeException("Unreachable") - } - } - - @Throws(IOException::class, ConnectionException::class, IllegalArgumentException::class) - @Synchronized - private fun replaceTexture(old: Texture?, new: Texture?, image: ByteArray?) { - val io = getStreams() - - val obj = JsonObject() - obj.add("replace_texture", { - val inner = JsonObject() - if (old != null) { - inner.add("old", Gson().toJsonTree(InternalTexture(old), InternalTexture::class.java)) - } else { - inner.add("old", null) - } - if (new != null) { - inner.add("new", Gson().toJsonTree(InternalTexture(new), InternalTexture::class.java)) - } else { - inner.add("new", null) - } - inner - }()) - - JsonPackage(obj).write(io.second) - - when (val pkg = Package.read(io.first)) { - is JsonPackage -> { - when { - pkg.content == JsonPrimitive(true) -> // everthing is fine! - return - image != null -> { - // should be { "get_texture_file": { texture_hash : }} - // we don't check, since there is no good way to handle it. - - BinaryPackage(image).write(io.second) - when (val ipkg = Package.read(io.first)) { - is JsonPackage -> { - if (ipkg.content != JsonPrimitive(true)) { - // Protokoll Assertion failed - throw ConnectionUnexpectedPacketException() - } - } - is BinaryPackage -> throw ConnectionUnexpectedPacketException() - is ErrorPackage -> throw ConnectionErrorException(ipkg) - else -> throw RuntimeException("Unreachable") + when (val pkg = Package.read(i)) { + is JsonPackage -> { + return@withStreams if (pkg.content.isJsonNull) { + null + } else { + try { + Gson() + .fromJson(pkg.content, InternalTexture::class.java) + .toTexture() + } catch (e: JsonSyntaxException) { + throw ConnectionInvalidJsonException() } } - else -> { - ErrorPackage(404, "Texture not found!").write(io.second) - close() // gets re-opened on next request. - throw IllegalArgumentException("Image Argument was needed.") + } + is BinaryPackage -> throw ConnectionUnexpectedPacketException() + is ErrorPackage -> throw ConnectionErrorException(pkg) + else -> throw RuntimeException("Unreachable") + } + + } + } + + @Throws(IOException::class, ConnectionException::class) + fun getTextureByName(name: String): Texture? { + return withStreams { i, o -> + + val obj = JsonObject() + obj.add("get_texture", { + val inner = JsonObject() + inner.addProperty("name", name) + inner + }()) + + JsonPackage(obj).write(o) + + when (val pkg = Package.read(i)) { + is JsonPackage -> { + return@withStreams if (pkg.content.isJsonNull) { + null + } else { + try { + Gson() + .fromJson(pkg.content, InternalTexture::class.java) + .toTexture() + } catch (e: JsonSyntaxException) { + throw ConnectionInvalidJsonException() + } } } + is BinaryPackage -> throw ConnectionUnexpectedPacketException() + is ErrorPackage -> throw ConnectionErrorException(pkg) + else -> throw RuntimeException("Unreachable") + } + } + } + + @Throws(IOException::class, ConnectionException::class) + fun getTextureFile(hash: Sha256): ByteArray { + return withStreams { i, o -> + + val obj = JsonObject() + obj.add("get_texture_file", { + val inner = JsonObject() + inner.addProperty("texture_hash", hash.toString()) + inner + }()) + + JsonPackage(obj).write(o) + + when (val pkg = Package.read(i)) { + is JsonPackage -> throw ConnectionUnexpectedPacketException() + is BinaryPackage -> return@withStreams pkg.content + is ErrorPackage -> throw ConnectionErrorException(pkg) + else -> throw RuntimeException("Unreachable") + } + } + } + + @Throws(IOException::class, ConnectionException::class) + fun getTexturePreview(hash: Sha256): Image { + return withStreams { i, o -> + val obj = JsonObject() + obj.add("get_texture_preview", { + val inner = JsonObject() + inner.addProperty("texture_hash", hash.toString()) + inner.addProperty("desired_format", "jpeg") + inner + }()) + + JsonPackage(obj).write(o) + + when (val pkg = Package.read(i)) { + is JsonPackage -> throw ConnectionUnexpectedPacketException() + is BinaryPackage -> { + return@withStreams Image(ByteArrayInputStream(pkg.content)) + } + is ErrorPackage -> throw ConnectionErrorException(pkg) + else -> throw RuntimeException("Unreachable") + } + } + } + + @Throws(IOException::class, ConnectionException::class, IllegalArgumentException::class) + private fun replaceTexture(old: Texture?, new: Texture?, image: ByteArray?) { + return withStreams { i, o -> + + + val obj = JsonObject() + obj.add("replace_texture", { + val inner = JsonObject() + if (old != null) { + inner.add("old", Gson().toJsonTree(InternalTexture(old), InternalTexture::class.java)) + } else { + inner.add("old", null) + } + if (new != null) { + inner.add("new", Gson().toJsonTree(InternalTexture(new), InternalTexture::class.java)) + } else { + inner.add("new", null) + } + inner + }()) + + JsonPackage(obj).write(o) + + when (val pkg = Package.read(i)) { + is JsonPackage -> { + when { + pkg.content == JsonPrimitive(true) -> // everthing is fine! + return@withStreams + image != null -> { + // should be { "get_texture_file": { texture_hash : }} + // we don't check, since there is no good way to handle it. + + BinaryPackage(image).write(o) + when (val ipkg = Package.read(i)) { + is JsonPackage -> { + if (ipkg.content != JsonPrimitive(true)) { + // Protokoll Assertion failed + throw ConnectionUnexpectedPacketException() + } + } + is BinaryPackage -> throw ConnectionUnexpectedPacketException() + is ErrorPackage -> throw ConnectionErrorException(ipkg) + else -> throw RuntimeException("Unreachable") + } + } + else -> { + ErrorPackage(404, "Texture not found!").write(o) + close() // gets re-opened on next request. + throw IllegalArgumentException("Image Argument was needed.") + } + } + } + is BinaryPackage -> throw ConnectionUnexpectedPacketException() + is ErrorPackage -> throw ConnectionErrorException(pkg) + else -> throw RuntimeException("Unreachable") } - is BinaryPackage -> throw ConnectionUnexpectedPacketException() - is ErrorPackage -> throw ConnectionErrorException(pkg) - else -> throw RuntimeException("Unreachable") } } @Throws(IOException::class, ConnectionException::class, IllegalArgumentException::class) - @Synchronized fun uploadTexture(texture: Texture, image: ByteArray) { if (texture.textureHash != Sha256(image)) { throw IllegalArgumentException("Sha256 of Image does not Match with Texture.") @@ -285,7 +296,6 @@ class Connection(val address: InetAddress, val port: Int = 10796) : Closeable { } @Throws(IOException::class, ConnectionException::class, IllegalArgumentException::class) - @Synchronized fun updateTexture(old: Texture, new: Texture, image: ByteArray) { if (new.textureHash != Sha256(image)) { throw IllegalArgumentException("Sha256 of Image does not Match with Texture.") @@ -295,25 +305,27 @@ class Connection(val address: InetAddress, val port: Int = 10796) : Closeable { } @Throws(IOException::class, ConnectionException::class, IllegalArgumentException::class) - @Synchronized fun deleteTexture(texture: Texture) { replaceTexture(texture, null, null) } @Throws(IOException::class) - @Synchronized override fun close() { - if (output != null) { - output!!.close() - output = null - } - if (input != null) { - input!!.close() - input = null - } - if (socket != null) { - socket!!.close() - socket = null + try { + if (output != null) { + output!!.close() + output = null + } + if (input != null) { + input!!.close() + input = null + } + if (socket != null) { + socket!!.close() + socket = null + } + } catch (e: IOException) { + // Ignore } }