2019-06-02 20:59:05 +02:00
package org.hso.texturesyncclient.controller.net
import com.google.gson.*
2019-06-03 15:50:09 +02:00
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
2019-06-03 16:32:06 +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-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
}
}
2019-06-03 16:32:06 +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 ( )
}
}
}
2019-06-03 16:32:06 +02:00
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 ( )
}
}
}
2019-06-03 16:32:06 +02:00
is BinaryPackage -> throw ConnectionUnexpectedPacketException ( )
2019-06-03 15:18:42 +02:00
is ErrorPackage -> throw ConnectionErrorException ( pkg )
else -> throw RuntimeException ( " Unreachable " )
}
}
2019-06-03 15:50:09 +02:00
@Throws ( IOException :: class , ConnectionException :: class )
@Synchronized
2019-06-03 16:33:19 +02:00
fun getTextureFile ( hash : Sha256 ) : ByteArray {
2019-06-03 15:50:09 +02:00
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 ) ) {
2019-06-03 16:32:06 +02:00
is JsonPackage -> throw ConnectionUnexpectedPacketException ( )
2019-06-03 15:50:09 +02:00
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 {
2019-06-03 15:50:09 +02:00
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 ) ) {
2019-06-03 16:32:06 +02:00
is JsonPackage -> throw ConnectionUnexpectedPacketException ( )
2019-06-03 15:50:09 +02:00
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
2019-06-03 16:32:06 +02:00
throw ConnectionUnexpectedPacketException ( )
2019-06-03 16:31:04 +02:00
}
}
2019-06-03 16:32:06 +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. " )
}
}
2019-06-03 16:32:06 +02:00
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
}
}
}