Client Connection: [Auto]Retry Once

if Connection is lost or timed out
This commit is contained in:
CodeSteak 2019-06-08 21:25:56 +02:00
parent 19eb6660e1
commit f4db466b37

View File

@ -19,7 +19,7 @@ class Connection(val address: InetAddress, val port: Int = 10796) : Closeable {
@Throws(IOException::class) @Throws(IOException::class)
@Synchronized @Synchronized
private fun getStreams(): Pair<DataInputStream, DataOutputStream> { private fun <R> withStreams(retry: Boolean = true, inner: (DataInputStream, DataOutputStream) -> R): R {
val i: DataInputStream val i: DataInputStream
val o: DataOutputStream val o: DataOutputStream
@ -40,31 +40,40 @@ class Connection(val address: InetAddress, val port: Int = 10796) : Closeable {
o = output!! 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) @Throws(IOException::class, ConnectionException::class)
@Synchronized
fun ping() { fun ping() {
val io = getStreams() return withStreams { i, o ->
val obj = JsonObject() val obj = JsonObject()
obj.add("ping", JsonObject()) obj.add("ping", JsonObject())
JsonPackage(obj).write(io.second) JsonPackage(obj).write(o)
when (val pkg = Package.read(io.first)) { when (val pkg = Package.read(i)) {
is JsonPackage -> return is JsonPackage -> return@withStreams
is BinaryPackage -> throw ConnectionUnexpectedPacketException() is BinaryPackage -> throw ConnectionUnexpectedPacketException()
is ErrorPackage -> throw ConnectionErrorException(pkg) is ErrorPackage -> throw ConnectionErrorException(pkg)
else -> throw RuntimeException("Unreachable") else -> throw RuntimeException("Unreachable")
} }
};
} }
@Throws(IOException::class, ConnectionException::class) @Throws(IOException::class, ConnectionException::class)
@Synchronized
fun query(query: Array<String>): Array<Texture> { fun query(query: Array<String>): Array<Texture> {
val io = getStreams() return withStreams { i, o ->
val obj = JsonObject() val obj = JsonObject()
obj.add("query", { obj.add("query", {
@ -79,12 +88,15 @@ class Connection(val address: InetAddress, val port: Int = 10796) : Closeable {
inner inner
}()) }())
JsonPackage(obj).write(io.second) JsonPackage(obj).write(o)
when (val pkg = Package.read(io.first)) { when (val pkg = Package.read(i)) {
is JsonPackage -> { is JsonPackage -> {
try { try {
return Gson().fromJson<Array<InternalTexture>>(pkg.content, Array<InternalTexture>::class.java) return@withStreams Gson().fromJson<Array<InternalTexture>>(
pkg.content,
Array<InternalTexture>::class.java
)
.map { tex -> .map { tex ->
tex.toTexture() tex.toTexture()
}.toTypedArray() }.toTypedArray()
@ -97,11 +109,12 @@ class Connection(val address: InetAddress, val port: Int = 10796) : Closeable {
else -> throw RuntimeException("Unreachable") else -> throw RuntimeException("Unreachable")
} }
} }
}
@Throws(IOException::class, ConnectionException::class) @Throws(IOException::class, ConnectionException::class)
@Synchronized
fun getTextureById(id: UUID): Texture? { fun getTextureById(id: UUID): Texture? {
val io = getStreams() return withStreams { i, o ->
val obj = JsonObject() val obj = JsonObject()
obj.add("get_texture", { obj.add("get_texture", {
@ -110,11 +123,11 @@ class Connection(val address: InetAddress, val port: Int = 10796) : Closeable {
inner inner
}()) }())
JsonPackage(obj).write(io.second) JsonPackage(obj).write(o)
when (val pkg = Package.read(io.first)) { when (val pkg = Package.read(i)) {
is JsonPackage -> { is JsonPackage -> {
return if (pkg.content.isJsonNull) { return@withStreams if (pkg.content.isJsonNull) {
null null
} else { } else {
try { try {
@ -132,11 +145,11 @@ class Connection(val address: InetAddress, val port: Int = 10796) : Closeable {
} }
} }
}
@Throws(IOException::class, ConnectionException::class) @Throws(IOException::class, ConnectionException::class)
@Synchronized
fun getTextureByName(name: String): Texture? { fun getTextureByName(name: String): Texture? {
val io = getStreams() return withStreams { i, o ->
val obj = JsonObject() val obj = JsonObject()
obj.add("get_texture", { obj.add("get_texture", {
@ -145,11 +158,11 @@ class Connection(val address: InetAddress, val port: Int = 10796) : Closeable {
inner inner
}()) }())
JsonPackage(obj).write(io.second) JsonPackage(obj).write(o)
when (val pkg = Package.read(io.first)) { when (val pkg = Package.read(i)) {
is JsonPackage -> { is JsonPackage -> {
return if (pkg.content.isJsonNull) { return@withStreams if (pkg.content.isJsonNull) {
null null
} else { } else {
try { try {
@ -165,13 +178,12 @@ class Connection(val address: InetAddress, val port: Int = 10796) : Closeable {
is ErrorPackage -> throw ConnectionErrorException(pkg) is ErrorPackage -> throw ConnectionErrorException(pkg)
else -> throw RuntimeException("Unreachable") else -> throw RuntimeException("Unreachable")
} }
}
} }
@Throws(IOException::class, ConnectionException::class) @Throws(IOException::class, ConnectionException::class)
@Synchronized
fun getTextureFile(hash: Sha256): ByteArray { fun getTextureFile(hash: Sha256): ByteArray {
val io = getStreams() return withStreams { i, o ->
val obj = JsonObject() val obj = JsonObject()
obj.add("get_texture_file", { obj.add("get_texture_file", {
@ -180,22 +192,20 @@ class Connection(val address: InetAddress, val port: Int = 10796) : Closeable {
inner inner
}()) }())
JsonPackage(obj).write(io.second) JsonPackage(obj).write(o)
when (val pkg = Package.read(io.first)) { when (val pkg = Package.read(i)) {
is JsonPackage -> throw ConnectionUnexpectedPacketException() is JsonPackage -> throw ConnectionUnexpectedPacketException()
is BinaryPackage -> return pkg.content is BinaryPackage -> return@withStreams pkg.content
is ErrorPackage -> throw ConnectionErrorException(pkg) is ErrorPackage -> throw ConnectionErrorException(pkg)
else -> throw RuntimeException("Unreachable") else -> throw RuntimeException("Unreachable")
} }
}
} }
@Throws(IOException::class, ConnectionException::class) @Throws(IOException::class, ConnectionException::class)
@Synchronized
fun getTexturePreview(hash: Sha256): Image { fun getTexturePreview(hash: Sha256): Image {
val io = getStreams() return withStreams { i, o ->
val obj = JsonObject() val obj = JsonObject()
obj.add("get_texture_preview", { obj.add("get_texture_preview", {
val inner = JsonObject() val inner = JsonObject()
@ -204,22 +214,23 @@ class Connection(val address: InetAddress, val port: Int = 10796) : Closeable {
inner inner
}()) }())
JsonPackage(obj).write(io.second) JsonPackage(obj).write(o)
when (val pkg = Package.read(io.first)) { when (val pkg = Package.read(i)) {
is JsonPackage -> throw ConnectionUnexpectedPacketException() is JsonPackage -> throw ConnectionUnexpectedPacketException()
is BinaryPackage -> { is BinaryPackage -> {
return Image(ByteArrayInputStream(pkg.content)) return@withStreams Image(ByteArrayInputStream(pkg.content))
} }
is ErrorPackage -> throw ConnectionErrorException(pkg) is ErrorPackage -> throw ConnectionErrorException(pkg)
else -> throw RuntimeException("Unreachable") else -> throw RuntimeException("Unreachable")
} }
} }
}
@Throws(IOException::class, ConnectionException::class, IllegalArgumentException::class) @Throws(IOException::class, ConnectionException::class, IllegalArgumentException::class)
@Synchronized
private fun replaceTexture(old: Texture?, new: Texture?, image: ByteArray?) { private fun replaceTexture(old: Texture?, new: Texture?, image: ByteArray?) {
val io = getStreams() return withStreams { i, o ->
val obj = JsonObject() val obj = JsonObject()
obj.add("replace_texture", { obj.add("replace_texture", {
@ -237,19 +248,19 @@ class Connection(val address: InetAddress, val port: Int = 10796) : Closeable {
inner inner
}()) }())
JsonPackage(obj).write(io.second) JsonPackage(obj).write(o)
when (val pkg = Package.read(io.first)) { when (val pkg = Package.read(i)) {
is JsonPackage -> { is JsonPackage -> {
when { when {
pkg.content == JsonPrimitive(true) -> // everthing is fine! pkg.content == JsonPrimitive(true) -> // everthing is fine!
return return@withStreams
image != null -> { image != null -> {
// should be { "get_texture_file": { texture_hash : <Hash> }} // should be { "get_texture_file": { texture_hash : <Hash> }}
// we don't check, since there is no good way to handle it. // we don't check, since there is no good way to handle it.
BinaryPackage(image).write(io.second) BinaryPackage(image).write(o)
when (val ipkg = Package.read(io.first)) { when (val ipkg = Package.read(i)) {
is JsonPackage -> { is JsonPackage -> {
if (ipkg.content != JsonPrimitive(true)) { if (ipkg.content != JsonPrimitive(true)) {
// Protokoll Assertion failed // Protokoll Assertion failed
@ -262,7 +273,7 @@ class Connection(val address: InetAddress, val port: Int = 10796) : Closeable {
} }
} }
else -> { else -> {
ErrorPackage(404, "Texture not found!").write(io.second) ErrorPackage(404, "Texture not found!").write(o)
close() // gets re-opened on next request. close() // gets re-opened on next request.
throw IllegalArgumentException("Image Argument was needed.") throw IllegalArgumentException("Image Argument was needed.")
} }
@ -273,9 +284,9 @@ class Connection(val address: InetAddress, val port: Int = 10796) : Closeable {
else -> throw RuntimeException("Unreachable") else -> throw RuntimeException("Unreachable")
} }
} }
}
@Throws(IOException::class, ConnectionException::class, IllegalArgumentException::class) @Throws(IOException::class, ConnectionException::class, IllegalArgumentException::class)
@Synchronized
fun uploadTexture(texture: Texture, image: ByteArray) { fun uploadTexture(texture: Texture, image: ByteArray) {
if (texture.textureHash != Sha256(image)) { if (texture.textureHash != Sha256(image)) {
throw IllegalArgumentException("Sha256 of Image does not Match with Texture.") 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) @Throws(IOException::class, ConnectionException::class, IllegalArgumentException::class)
@Synchronized
fun updateTexture(old: Texture, new: Texture, image: ByteArray) { fun updateTexture(old: Texture, new: Texture, image: ByteArray) {
if (new.textureHash != Sha256(image)) { if (new.textureHash != Sha256(image)) {
throw IllegalArgumentException("Sha256 of Image does not Match with Texture.") throw IllegalArgumentException("Sha256 of Image does not Match with Texture.")
@ -295,14 +305,13 @@ class Connection(val address: InetAddress, val port: Int = 10796) : Closeable {
} }
@Throws(IOException::class, ConnectionException::class, IllegalArgumentException::class) @Throws(IOException::class, ConnectionException::class, IllegalArgumentException::class)
@Synchronized
fun deleteTexture(texture: Texture) { fun deleteTexture(texture: Texture) {
replaceTexture(texture, null, null) replaceTexture(texture, null, null)
} }
@Throws(IOException::class) @Throws(IOException::class)
@Synchronized
override fun close() { override fun close() {
try {
if (output != null) { if (output != null) {
output!!.close() output!!.close()
output = null output = null
@ -315,6 +324,9 @@ class Connection(val address: InetAddress, val port: Int = 10796) : Closeable {
socket!!.close() socket!!.close()
socket = null socket = null
} }
} catch (e: IOException) {
// Ignore
}
} }
} }