forked from hush/SilentDragonWormhole
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
118 lines
3.9 KiB
118 lines
3.9 KiB
package com.silentdragon.wormhole
|
|
|
|
import com.beust.klaxon.JsonObject
|
|
import com.beust.klaxon.Parser
|
|
import com.beust.klaxon.json
|
|
import io.javalin.Javalin
|
|
import io.javalin.websocket.WsSession
|
|
import org.slf4j.LoggerFactory
|
|
import java.util.concurrent.ConcurrentHashMap
|
|
|
|
|
|
private val usermap = ConcurrentHashMap<WsSession, String>()
|
|
|
|
// Allow maps to be bidirectional
|
|
fun <K, V> Map<K, V>.getKeys(value: V) : List<K> =
|
|
entries.filter { it.value == value } .map { it.key }
|
|
|
|
val LOG = LoggerFactory.getLogger("Websocket")
|
|
|
|
fun main(args : Array<String>) {
|
|
|
|
Javalin.create().apply {
|
|
ws("/") { ws ->
|
|
ws.onConnect { session ->
|
|
LOG.info("Connected Session")
|
|
session.idleTimeout = 5 * 60 * 1000 // 5 minutes
|
|
}
|
|
|
|
ws.onClose { session, _, _ ->
|
|
LOG.info("Closed session ${usermap[session]}")
|
|
usermap.remove(session)
|
|
}
|
|
|
|
ws.onMessage { session, message ->
|
|
// Limit message size to 50kb of hex encoded text
|
|
if (message.length > 2 * 50 * 1024) {
|
|
sendError(session, "Message too big")
|
|
return@onMessage
|
|
}
|
|
|
|
//println("Recieved $message")
|
|
|
|
// Parse the message as json
|
|
try {
|
|
val j = Parser.default().parse(StringBuilder(message)) as JsonObject
|
|
|
|
if (j.contains("ping")) {
|
|
// Ignore, this is a keep-alive ping
|
|
// Just send the ping back
|
|
session.send(message)
|
|
return@onMessage
|
|
}
|
|
|
|
if (j.contains("register")) {
|
|
logInfo("Register ${j["register"].toString()}", j)
|
|
doRegister(session, j["register"].toString())
|
|
return@onMessage
|
|
}
|
|
|
|
if (j.contains("to")) {
|
|
val s = usermap.getKeys(j["to"].toString()).filter { it.id != session.id }
|
|
if (s.isEmpty()) {
|
|
// Not connected
|
|
logInfo("Error: Peer is not connected", j)
|
|
sendError(session, "Peer is not connected")
|
|
return@onMessage
|
|
}
|
|
|
|
if (s.size > 2) {
|
|
LOG.warn("Warning, multiple sessions matched for ${j["to"].toString()}")
|
|
}
|
|
|
|
logInfo("Routed message for ${j["to"].toString()}", j)
|
|
s[0].send(message)
|
|
return@onMessage
|
|
} else {
|
|
LOG.warn("There was no 'to' in the message: $message")
|
|
sendError(session,"Missing 'to' field")
|
|
return@onMessage
|
|
}
|
|
} catch (e: Throwable) {
|
|
LOG.error("Exception: ${e.localizedMessage}, Message was: $message")
|
|
session.close(1000, "Invalid json")
|
|
}
|
|
}
|
|
|
|
ws.onError { session, t ->
|
|
LOG.error("Something went wrong with session ${t.toString()}")
|
|
usermap.remove(session)
|
|
}
|
|
}
|
|
}.start(7070)
|
|
|
|
}
|
|
|
|
fun doRegister(session: WsSession, id: String) {
|
|
if (usermap.containsKey(session)) {
|
|
LOG.warn("Already registered a session $id")
|
|
return
|
|
}
|
|
|
|
usermap[session] = id
|
|
}
|
|
|
|
fun sendError(session: WsSession, err: String) {
|
|
if (session.isOpen) {
|
|
session.send(json { obj("error" to err) }.toJsonString())
|
|
}
|
|
}
|
|
|
|
fun logInfo(t: String, j: JsonObject) {
|
|
val l = j.map {
|
|
val s = it.value.toString()
|
|
it.key to if (s.length > 10) s.take(10) + "...{" + s.length + "}" else s
|
|
}.toString().replace("\n", "").trim()
|
|
|
|
LOG.info(t + l)
|
|
}
|
|
|