package com.zecqtwallet.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.Logger import org.slf4j.LoggerFactory import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.TimeUnit private val usermap = ConcurrentHashMap() // Allow maps to be bidirectional fun Map.getKeys(value: V) : List = entries.filter { it.value == value } .map { it.key } val LOG = LoggerFactory.getLogger("Websocket") fun main(args : Array) { Javalin.create().apply { ws("/") { ws -> ws.onConnect { session -> LOG.info("Connected Session") session.idleTimeout = 5 * 60 * 1000 // 5 minutes } ws.onClose { session, status, message -> 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") } //println("Recieved $message") // Parse the message as json try { val j = Parser.default().parse(StringBuilder(message)) as JsonObject if (j.contains("register")) { 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 sendError(session, "Peer is not connected") return@onMessage } if (s.size > 2) { LOG.warn("Warning, multiple sessions matched for ${j["to"].toString()}") } 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}") 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 } LOG.info("Registered $id") usermap[session] = id } fun sendError(session: WsSession, err: String) { if (session.isOpen) { LOG.info("Sending error: ${usermap[session]} -> $err") session.send(json { obj("error" to err) }.toJsonString()) } }