TextureSync/client/src/main/kotlin/org/hso/texturesyncclient/controller/net/Connection.kt

318 lines
10 KiB
Kotlin
Raw Normal View History

2019-06-02 20:59:05 +02:00
package org.hso.texturesyncclient.controller.net
import com.google.gson.*
import javafx.scene.image.Image
import org.hso.texturesyncclient.model.Sha256
2019-06-02 22:32:19 +02:00
import org.hso.texturesyncclient.model.Texture
2019-06-02 20:59:05 +02:00
import java.io.*
2019-06-03 16:31:04 +02:00
import java.lang.IllegalArgumentException
2019-06-02 22:04:01 +02:00
import java.lang.RuntimeException
2019-06-02 20:59:05 +02:00
import java.net.*
2019-06-03 15:18:42 +02:00
import java.util.*
2019-06-02 20:59:05 +02:00
@Suppress("MemberVisibilityCanBePrivate")
2019-06-03 15:03:25 +02:00
class Connection(val address: InetAddress, val port: Int = 10796) : Closeable {
2019-06-02 20:59:05 +02:00
var socket: Socket? = null
var output: DataOutputStream? = null
var input: DataInputStream? = null
@Throws(IOException::class)
2019-06-03 15:03:25 +02:00
@Synchronized
2019-06-02 20:59:05 +02:00
private fun getStreams(): Pair<DataInputStream, DataOutputStream> {
val i: DataInputStream
val o: DataOutputStream
if (socket == null || !socket!!.isConnected) {
2019-06-03 15:03:25 +02:00
val sock = Socket(address, port)
2019-06-02 20:59:05 +02:00
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)
}
2019-06-03 15:03:25 +02:00
@Throws(IOException::class, ConnectionException::class)
@Synchronized
2019-06-02 20:59:05 +02:00
fun ping() {
val io = getStreams()
val obj = JsonObject()
obj.add("ping", JsonObject())
2019-06-03 15:03:25 +02:00
JsonPackage(obj).write(io.second)
2019-06-02 20:59:05 +02:00
2019-06-03 15:03:25 +02:00
when (val pkg = Package.read(io.first)) {
is JsonPackage -> return
is BinaryPackage -> throw ConnectionUnexpectedPacketException()
2019-06-03 15:03:25 +02:00
is ErrorPackage -> throw ConnectionErrorException(pkg)
2019-06-02 22:04:01 +02:00
else -> throw RuntimeException("Unreachable")
}
}
2019-06-03 15:03:25 +02:00
@Throws(IOException::class, ConnectionException::class)
@Synchronized
2019-06-03 16:33:19 +02:00
fun query(query: Array<String>): Array<Texture> {
2019-06-02 22:04:01 +02:00
val io = getStreams()
val obj = JsonObject()
obj.add("query", {
2019-06-03 15:03:25 +02:00
val inner = JsonObject()
2019-06-02 22:04:01 +02:00
inner.add("query", {
val array = JsonArray()
2019-06-03 16:33:19 +02:00
for (queryString in query) {
2019-06-02 22:04:01 +02:00
array.add(queryString)
}
array
}())
inner
}())
2019-06-03 15:03:25 +02:00
JsonPackage(obj).write(io.second)
2019-06-02 22:04:01 +02:00
2019-06-03 15:03:25 +02:00
when (val pkg = Package.read(io.first)) {
is JsonPackage -> {
2019-06-02 22:04:01 +02:00
try {
2019-06-03 16:33:19 +02:00
return Gson().fromJson<Array<InternalTexture>>(pkg.content, Array<InternalTexture>::class.java)
.map { tex ->
tex.toTexture()
}.toTypedArray()
} catch (e: JsonSyntaxException) {
2019-06-02 22:32:19 +02:00
throw ConnectionInvalidJsonException()
2019-06-02 22:04:01 +02:00
}
}
is BinaryPackage -> throw ConnectionUnexpectedPacketException()
2019-06-03 15:03:25 +02:00
is ErrorPackage -> throw ConnectionErrorException(pkg)
2019-06-02 22:04:01 +02:00
else -> throw RuntimeException("Unreachable")
2019-06-02 20:59:05 +02:00
}
}
2019-06-03 15:18:42 +02:00
@Throws(IOException::class, ConnectionException::class)
@Synchronized
2019-06-03 16:33:19 +02:00
fun getTextureById(id: UUID): Optional<Texture> {
2019-06-03 15:18:42 +02:00
val io = getStreams()
val obj = JsonObject()
obj.add("get_texture", {
val inner = JsonObject()
inner.addProperty("id", id.toString())
inner
}())
JsonPackage(obj).write(io.second)
when (val pkg = Package.read(io.first)) {
is JsonPackage -> {
return if (pkg.content.isJsonNull) {
2019-06-03 16:33:19 +02:00
Optional.empty()
2019-06-03 15:18:42 +02:00
} else {
try {
Optional.of(
Gson()
.fromJson<InternalTexture>(pkg.content, InternalTexture::class.java)
.toTexture()
)
2019-06-03 16:33:19 +02:00
} catch (e: JsonSyntaxException) {
2019-06-03 15:18:42 +02:00
throw ConnectionInvalidJsonException()
}
}
}
is BinaryPackage -> throw ConnectionUnexpectedPacketException()
2019-06-03 15:18:42 +02:00
is ErrorPackage -> throw ConnectionErrorException(pkg)
else -> throw RuntimeException("Unreachable")
}
}
@Throws(IOException::class, ConnectionException::class)
@Synchronized
2019-06-03 16:33:19 +02:00
fun getTextureByName(name: String): Optional<Texture> {
2019-06-03 15:18:42 +02:00
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) {
Optional.empty()
} else {
try {
Optional.of(
Gson()
.fromJson<InternalTexture>(pkg.content, InternalTexture::class.java)
.toTexture()
)
2019-06-03 16:33:19 +02:00
} catch (e: JsonSyntaxException) {
2019-06-03 15:18:42 +02:00
throw ConnectionInvalidJsonException()
}
}
}
is BinaryPackage -> throw ConnectionUnexpectedPacketException()
2019-06-03 15:18:42 +02:00
is ErrorPackage -> throw ConnectionErrorException(pkg)
else -> throw RuntimeException("Unreachable")
}
}
@Throws(IOException::class, ConnectionException::class)
@Synchronized
2019-06-03 16:33:19 +02:00
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
2019-06-03 16:33:19 +02:00
fun getTexturePreview(hash: Sha256): Image {
val io = getStreams()
val obj = JsonObject()
obj.add("get_texture_file", {
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")
}
}
2019-06-03 16:31:04 +02:00
@Throws(IOException::class, ConnectionException::class, IllegalArgumentException::class)
@Synchronized
2019-06-03 16:33:19 +02:00
private fun replaceTexture(old: Texture?, new: Texture?, image: ByteArray?) {
2019-06-03 16:31:04 +02:00
val io = getStreams()
val obj = JsonObject()
obj.add("replace_texture", {
val inner = JsonObject()
2019-06-03 16:33:19 +02:00
if (old != null) {
2019-06-03 16:31:04 +02:00
inner.add("old", Gson().toJsonTree(InternalTexture(old), InternalTexture::class.java))
} else {
inner.add("old", null)
}
2019-06-03 16:33:19 +02:00
if (new != null) {
2019-06-03 16:31:04 +02:00
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 -> {
if (pkg.content == JsonPrimitive(true)) {
// everthing is fine!
return
} else if (image != null) {
// should be { "get_texture_file": { texture_hash : <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 -> {
2019-06-03 16:33:19 +02:00
if (ipkg.content != JsonPrimitive(true)) {
2019-06-03 16:31:04 +02:00
// Protokoll Assertion failed
throw ConnectionUnexpectedPacketException()
2019-06-03 16:31:04 +02:00
}
}
is BinaryPackage -> throw ConnectionUnexpectedPacketException()
2019-06-03 16:31:04 +02:00
is ErrorPackage -> throw ConnectionErrorException(ipkg)
else -> throw RuntimeException("Unreachable")
}
} 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()
2019-06-03 16:31:04 +02:00
is ErrorPackage -> throw ConnectionErrorException(pkg)
else -> throw RuntimeException("Unreachable")
}
}
@Throws(IOException::class, ConnectionException::class, IllegalArgumentException::class)
@Synchronized
2019-06-03 16:33:19 +02:00
fun uploadTexture(texture: Texture, image: ByteArray) {
if (texture.textureHash != Sha256(image)) {
2019-06-03 16:31:04 +02:00
throw IllegalArgumentException("Sha256 of Image does not Match with Texture.")
}
replaceTexture(null, texture, image)
}
@Throws(IOException::class, ConnectionException::class, IllegalArgumentException::class)
@Synchronized
2019-06-03 16:33:19 +02:00
fun updateTexture(old: Texture, new: Texture, image: ByteArray) {
if (new.textureHash != Sha256(image)) {
2019-06-03 16:31:04 +02:00
throw IllegalArgumentException("Sha256 of Image does not Match with Texture.")
}
replaceTexture(old, new, image)
}
@Throws(IOException::class, ConnectionException::class, IllegalArgumentException::class)
@Synchronized
2019-06-03 16:33:19 +02:00
fun deleteTexture(texture: Texture) {
replaceTexture(texture, null, null)
2019-06-03 16:31:04 +02:00
}
2019-06-02 20:59:05 +02:00
@Throws(IOException::class)
2019-06-03 15:03:25 +02:00
@Synchronized
2019-06-02 20:59:05 +02:00
override fun close() {
if (output != null) {
output!!.close()
2019-06-03 16:31:04 +02:00
output = null
2019-06-02 20:59:05 +02:00
}
if (input != null) {
input!!.close()
2019-06-03 16:31:04 +02:00
input = null
2019-06-02 20:59:05 +02:00
}
if (socket != null) {
socket!!.close()
2019-06-03 16:31:04 +02:00
socket = null
2019-06-02 20:59:05 +02:00
}
}
}