implement PING Netop
This commit is contained in:
		@ -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<DataInputStream, DataOutputStream> {
 | 
			
		||||
        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()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -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()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -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()
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user