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

5 years ago
package com.zecqtwallet.wormhole
5 years ago
import com.beust.klaxon.JsonObject
import com.beust.klaxon.Parser
import com.beust.klaxon.json
5 years ago
import io.javalin.Javalin
5 years ago
import io.javalin.websocket.WsSession
5 years ago
import org.slf4j.LoggerFactory
5 years ago
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 }
5 years ago
5 years ago
val LOG = LoggerFactory.getLogger("Websocket")
5 years ago
fun main(args : Array<String>) {
Javalin.create().apply {
ws("/") { ws ->
ws.onConnect { session ->
5 years ago
LOG.info("Connected Session")
session.idleTimeout = 5 * 60 * 1000 // 5 minutes
5 years ago
}
5 years ago
5 years ago
ws.onClose { session, _, _ ->
5 years ago
LOG.info("Closed session ${usermap[session]}")
5 years ago
usermap.remove(session)
5 years ago
}
5 years ago
5 years ago
ws.onMessage { session, message ->
5 years ago
// Limit message size to 50kb of hex encoded text
if (message.length > 2 * 50 * 1024) {
sendError(session, "Message too big")
return@onMessage
5 years ago
}
5 years ago
//println("Recieved $message")
5 years ago
5 years ago
// Parse the message as json
try {
val j = Parser.default().parse(StringBuilder(message)) as JsonObject
5 years ago
if (j.contains("ping")) {
// Ignore, this is a keep-alive ping
5 years ago
// Just send the ping back
session.send(message)
5 years ago
return@onMessage
}
5 years ago
if (j.contains("register")) {
5 years ago
logInfo("Register ${j["register"].toString()}", j)
5 years ago
doRegister(session, j["register"].toString())
return@onMessage
}
if (j.contains("to")) {
val s = usermap.getKeys(j["to"].toString()).filter { it.id != session.id }
5 years ago
if (s.isEmpty()) {
// Not connected
5 years ago
logInfo("Error: Peer is not connected", j)
5 years ago
sendError(session, "Peer is not connected")
return@onMessage
}
5 years ago
if (s.size > 2) {
LOG.warn("Warning, multiple sessions matched for ${j["to"].toString()}")
}
5 years ago
logInfo("Routed message for ${j["to"].toString()}", j)
5 years ago
s[0].send(message)
return@onMessage
5 years ago
} else {
5 years ago
LOG.warn("There was no 'to' in the message: $message")
5 years ago
sendError(session,"Missing 'to' field")
return@onMessage
5 years ago
}
} catch (e: Throwable) {
5 years ago
LOG.error("Exception: ${e.localizedMessage}, Message was: $message")
5 years ago
session.close(1000, "Invalid json")
}
5 years ago
}
5 years ago
ws.onError { session, t ->
5 years ago
LOG.error("Something went wrong with session ${t.toString()}")
5 years ago
usermap.remove(session)
}
5 years ago
}
}.start(7070)
}
5 years ago
fun doRegister(session: WsSession, id: String) {
5 years ago
if (usermap.containsKey(session)) {
5 years ago
LOG.warn("Already registered a session $id")
return
5 years ago
}
usermap[session] = id
}
fun sendError(session: WsSession, err: String) {
if (session.isOpen) {
session.send(json { obj("error" to err) }.toJsonString())
}
5 years ago
}
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)
5 years ago
}