Client Connection: [Auto]Retry Once
if Connection is lost or timed out
This commit is contained in:
parent
19eb6660e1
commit
f4db466b37
|
@ -19,7 +19,7 @@ class Connection(val address: InetAddress, val port: Int = 10796) : Closeable {
|
|||
|
||||
@Throws(IOException::class)
|
||||
@Synchronized
|
||||
private fun getStreams(): Pair<DataInputStream, DataOutputStream> {
|
||||
private fun <R> 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<String>): Array<Texture> {
|
||||
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<Array<InternalTexture>>(pkg.content, Array<InternalTexture>::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<Array<InternalTexture>>(
|
||||
pkg.content,
|
||||
Array<InternalTexture>::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<InternalTexture>(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<InternalTexture>(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 : <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<InternalTexture>(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<InternalTexture>(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 : <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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue