-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
20 changed files
with
455 additions
and
33 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
22 changes: 22 additions & 0 deletions
22
progreso-api/src/main/kotlin/org/progreso/api/irc/IRCClient.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package org.progreso.api.irc | ||
|
||
import org.java_websocket.client.WebSocketClient | ||
import org.java_websocket.handshake.ServerHandshake | ||
import org.progreso.api.irc.packet.IRCPacket | ||
import java.net.URI | ||
|
||
open class IRCClient(serverUri: URI) : WebSocketClient(serverUri) { | ||
open fun onPacket(packet: IRCPacket) {} | ||
|
||
override fun onOpen(handshakedata: ServerHandshake) { } | ||
override fun onClose(code: Int, reason: String, remote: Boolean) { } | ||
override fun onError(ex: Exception) { } | ||
|
||
override fun onMessage(message: String) { | ||
onPacket(IRCPacket.GSON.fromJson(message, IRCPacket::class.java)) | ||
} | ||
|
||
fun send(packet: IRCPacket) { | ||
send(IRCPacket.GSON.toJson(packet, IRCPacket::class.java)) | ||
} | ||
} |
28 changes: 28 additions & 0 deletions
28
progreso-api/src/main/kotlin/org/progreso/api/irc/IRCServer.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package org.progreso.api.irc | ||
|
||
import org.java_websocket.WebSocket | ||
import org.java_websocket.handshake.ClientHandshake | ||
import org.java_websocket.server.WebSocketServer | ||
import org.progreso.api.irc.packet.IRCPacket | ||
import java.net.InetSocketAddress | ||
|
||
open class IRCServer(address: InetSocketAddress) : WebSocketServer(address) { | ||
open fun onPacket(socket: WebSocket, packet: IRCPacket) {} | ||
|
||
override fun onOpen(conn: WebSocket, handshake: ClientHandshake) {} | ||
override fun onClose(conn: WebSocket, code: Int, reason: String, remote: Boolean) {} | ||
override fun onError(conn: WebSocket?, ex: Exception) {} | ||
override fun onStart() {} | ||
|
||
override fun onMessage(conn: WebSocket, message: String) { | ||
onPacket(conn, IRCPacket.GSON.fromJson(message, IRCPacket::class.java)) | ||
} | ||
|
||
fun send(packet: IRCPacket) { | ||
connections.forEach { it.send(packet) } | ||
} | ||
|
||
fun WebSocket.send(packet: IRCPacket) { | ||
send(IRCPacket.GSON.toJson(packet, IRCPacket::class.java)) | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
progreso-api/src/main/kotlin/org/progreso/api/irc/packet/IRCPacket.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package org.progreso.api.irc.packet | ||
|
||
import com.google.gson.GsonBuilder | ||
import org.progreso.api.irc.packet.packets.IRCAuthFailedPacket | ||
import org.progreso.api.irc.packet.packets.IRCAuthPacket | ||
import org.progreso.api.irc.packet.packets.IRCMessagePacket | ||
import org.progreso.api.irc.typeadapters.RuntimeTypeAdapterFactory | ||
|
||
interface IRCPacket { | ||
companion object { | ||
private val GSON_FACTORY = RuntimeTypeAdapterFactory.of(IRCPacket::class.java) | ||
.registerSubtype(IRCAuthFailedPacket::class.java) | ||
.registerSubtype(IRCAuthPacket::class.java) | ||
.registerSubtype(IRCMessagePacket::class.java) | ||
|
||
val GSON = GsonBuilder() | ||
.registerTypeAdapterFactory(GSON_FACTORY) | ||
.create() | ||
} | ||
} |
5 changes: 5 additions & 0 deletions
5
progreso-api/src/main/kotlin/org/progreso/api/irc/packet/packets/IRCAuthFailedPacket.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package org.progreso.api.irc.packet.packets | ||
|
||
import org.progreso.api.irc.packet.IRCPacket | ||
|
||
data class IRCAuthFailedPacket(val reason: String) : IRCPacket |
5 changes: 5 additions & 0 deletions
5
progreso-api/src/main/kotlin/org/progreso/api/irc/packet/packets/IRCAuthPacket.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package org.progreso.api.irc.packet.packets | ||
|
||
import org.progreso.api.irc.packet.IRCPacket | ||
|
||
data class IRCAuthPacket(val username: String) : IRCPacket |
5 changes: 5 additions & 0 deletions
5
progreso-api/src/main/kotlin/org/progreso/api/irc/packet/packets/IRCMessagePacket.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package org.progreso.api.irc.packet.packets | ||
|
||
import org.progreso.api.irc.packet.IRCPacket | ||
|
||
data class IRCMessagePacket(val author: String, val message: String) : IRCPacket |
174 changes: 174 additions & 0 deletions
174
progreso-api/src/main/kotlin/org/progreso/api/irc/typeadapters/RuntimeTypeAdapterFactory.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
/* | ||
* Copyright (C) 2011 Google Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package org.progreso.api.irc.typeadapters | ||
|
||
import com.google.gson.* | ||
import com.google.gson.reflect.TypeToken | ||
import com.google.gson.stream.JsonReader | ||
import com.google.gson.stream.JsonWriter | ||
import java.io.IOException | ||
|
||
/** | ||
* Adapts values whose runtime type may differ from their declaration type. This | ||
* is necessary when a field's type is not the same type that GSON should create | ||
* when deserializing that field. | ||
*/ | ||
@Suppress("UNCHECKED_CAST", "unused", "MemberVisibilityCanBePrivate") | ||
class RuntimeTypeAdapterFactory<T> private constructor( | ||
baseType: Class<*>?, | ||
typeFieldName: String?, | ||
maintainType: Boolean | ||
) : TypeAdapterFactory { | ||
private val baseType: Class<*> | ||
private val typeFieldName: String | ||
private val labelToSubtype: MutableMap<String, Class<*>> = LinkedHashMap() | ||
private val subtypeToLabel: MutableMap<Class<*>, String> = LinkedHashMap() | ||
private val maintainType: Boolean | ||
private var recognizeSubtypes = false | ||
|
||
init { | ||
if (typeFieldName == null || baseType == null) { | ||
throw NullPointerException() | ||
} | ||
|
||
this.baseType = baseType | ||
this.typeFieldName = typeFieldName | ||
this.maintainType = maintainType | ||
} | ||
|
||
/** | ||
* Ensures that this factory will handle not just the given `baseType`, but any subtype | ||
* of that type. | ||
*/ | ||
fun recognizeSubtypes(): RuntimeTypeAdapterFactory<T> { | ||
recognizeSubtypes = true | ||
return this | ||
} | ||
|
||
/** | ||
* Registers `type` identified by `label`. Labels are case | ||
* sensitive. | ||
* | ||
* @throws IllegalArgumentException if either `type` or `label` | ||
* have already been registered on this type adapter. | ||
*/ | ||
fun registerSubtype(type: Class<out T>?, label: String?): RuntimeTypeAdapterFactory<T> { | ||
if (type == null || label == null) { | ||
throw NullPointerException() | ||
} | ||
if (subtypeToLabel.containsKey(type) || labelToSubtype.containsKey(label)) { | ||
throw IllegalArgumentException("types and labels must be unique") | ||
} | ||
labelToSubtype[label] = type | ||
subtypeToLabel[type] = label | ||
return this | ||
} | ||
|
||
/** | ||
* Registers `type` identified by its [simple][Class.getSimpleName]. Labels are case sensitive. | ||
* | ||
* @throws IllegalArgumentException if either `type` or its simple name | ||
* have already been registered on this type adapter. | ||
*/ | ||
fun registerSubtype(type: Class<out T>): RuntimeTypeAdapterFactory<T> { | ||
return registerSubtype(type, type.simpleName) | ||
} | ||
|
||
override fun <R : Any> create(gson: Gson, type: TypeToken<R>): TypeAdapter<R>? { | ||
val rawType: Class<*> = type.rawType | ||
val handle = if (recognizeSubtypes) baseType.isAssignableFrom(rawType) else baseType == rawType | ||
if (!handle) return null | ||
val jsonElementAdapter = gson.getAdapter(JsonElement::class.java) | ||
val labelToDelegate: MutableMap<String, TypeAdapter<*>> = LinkedHashMap() | ||
val subtypeToDelegate: MutableMap<Class<*>, TypeAdapter<*>> = LinkedHashMap() | ||
|
||
for (entry: Map.Entry<String, Class<*>> in labelToSubtype.entries) { | ||
val delegate = gson.getDelegateAdapter(this, TypeToken.get(entry.value)) | ||
labelToDelegate[entry.key] = delegate | ||
subtypeToDelegate[entry.value] = delegate | ||
} | ||
|
||
return object : TypeAdapter<R>() { | ||
@Throws(IOException::class) | ||
override fun read(`in`: JsonReader): R { | ||
val jsonElement = jsonElementAdapter.read(`in`) | ||
val labelJsonElement = if (maintainType) { | ||
jsonElement.asJsonObject[typeFieldName] | ||
} else { | ||
jsonElement.asJsonObject.remove(typeFieldName) | ||
} | ||
|
||
if (labelJsonElement == null) { | ||
throw JsonParseException("Cannot deserialize $baseType because it does not define a field named $typeFieldName") | ||
} | ||
|
||
val label = labelJsonElement.asString | ||
val delegate = labelToDelegate[label] as TypeAdapter<R>? | ||
?: throw JsonParseException("Cannot deserialize $baseType subtype named $label; did you forget to register a subtype?") | ||
|
||
return delegate.fromJsonTree(jsonElement) | ||
} | ||
|
||
@Throws(IOException::class) | ||
override fun write(out: JsonWriter, value: R) { | ||
val srcType: Class<*> = value.javaClass | ||
val label = subtypeToLabel[srcType] | ||
val delegate = subtypeToDelegate[srcType] as TypeAdapter<R>? | ||
?: throw JsonParseException("cannot serialize ${srcType.name}; did you forget to register a subtype?") | ||
val jsonObject = delegate.toJsonTree(value).asJsonObject | ||
if (maintainType) { | ||
jsonElementAdapter.write(out, jsonObject) | ||
return | ||
} | ||
val clone = JsonObject() | ||
if (jsonObject.has(typeFieldName)) { | ||
throw JsonParseException("cannot serialize ${srcType.name} because it already defines a field named $typeFieldName") | ||
} | ||
clone.add(typeFieldName, JsonPrimitive(label)) | ||
for (e: Map.Entry<String?, JsonElement?> in jsonObject.entrySet()) { | ||
clone.add(e.key, e.value) | ||
} | ||
jsonElementAdapter.write(out, clone) | ||
} | ||
}.nullSafe() | ||
} | ||
|
||
companion object { | ||
/** | ||
* Creates a new runtime type adapter using for `baseType` using `typeFieldName` as the type field name. Type field names are case sensitive. | ||
* | ||
* @param maintainType true if the type field should be included in deserialized objects | ||
*/ | ||
fun <T> of(baseType: Class<T>?, typeFieldName: String?, maintainType: Boolean): RuntimeTypeAdapterFactory<T> { | ||
return RuntimeTypeAdapterFactory(baseType, typeFieldName, maintainType) | ||
} | ||
|
||
/** | ||
* Creates a new runtime type adapter using for `baseType` using `typeFieldName` as the type field name. Type field names are case sensitive. | ||
*/ | ||
fun <T> of(baseType: Class<T>?, typeFieldName: String?): RuntimeTypeAdapterFactory<T> { | ||
return RuntimeTypeAdapterFactory(baseType, typeFieldName, false) | ||
} | ||
|
||
/** | ||
* Creates a new runtime type adapter for `baseType` using `"type"` as | ||
* the type field name. | ||
*/ | ||
fun <T> of(baseType: Class<T>?): RuntimeTypeAdapterFactory<T> { | ||
return RuntimeTypeAdapterFactory(baseType, "type", false) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.