I was following the http-kit websockets example and later got stuck trying to find an idiomatic way to map WS channels to users on the backend.
I've tried to inspect org.httpkit.server.AsyncChannel object using Java reflection and got the following attributes:
| :name | :return-type | :declaring-class | :parameter-types | :exception-types | :flags |
|---------------------------------+----------------------+---------------------------------+----------------------------------------------------------------+-----------------------+---------------------|
| chunkSize | java.nio.ByteBuffer | org.httpkit.server.AsyncChannel | [int] | [] | #{:private :static} |
| firstWrite | void | org.httpkit.server.AsyncChannel | [java.lang.Object boolean] | [java.io.IOException] | #{:private} |
| isClosed | boolean | org.httpkit.server.AsyncChannel | [] | [] | #{:public} |
| isWebSocket | boolean | org.httpkit.server.AsyncChannel | [] | [] | #{:public} |
| messageReceived | void | org.httpkit.server.AsyncChannel | [java.lang.Object] | [] | #{:public} |
| onClose | void | org.httpkit.server.AsyncChannel | [int] | [] | #{:public} |
| org.httpkit.server.AsyncChannel | | org.httpkit.server.AsyncChannel | [java.nio.channels.SelectionKey org.httpkit.server.HttpServer] | [] | #{:public} |
| pingReceived | void | org.httpkit.server.AsyncChannel | [byte<>] | [] | #{:public} |
| readable | clojure.lang.Keyword | org.httpkit.server.AsyncChannel | [int] | [] | #{:private :static} |
| reset | void | org.httpkit.server.AsyncChannel | [org.httpkit.server.HttpRequest] | [] | #{:public} |
| send | boolean | org.httpkit.server.AsyncChannel | [java.lang.Object boolean] | [java.io.IOException] | #{:public} |
| sendHandshake | void | org.httpkit.server.AsyncChannel | [java.util.Map] | [] | #{:public} |
| serverClose | boolean | org.httpkit.server.AsyncChannel | [int] | [] | #{:public} |
| setCloseHandler | void | org.httpkit.server.AsyncChannel | [clojure.lang.IFn] | [] | #{:public} |
| setPingHandler | void | org.httpkit.server.AsyncChannel | [clojure.lang.IFn] | [] | #{:public} |
| setReceiveHandler | void | org.httpkit.server.AsyncChannel | [clojure.lang.IFn] | [] | #{:public} |
| toString | java.lang.String | org.httpkit.server.AsyncChannel | [] | [] | #{:public} |
| writeChunk | void | org.httpkit.server.AsyncChannel | [java.lang.Object boolean] | [java.io.IOException] | #{:private} |
nil
which doesn't seem to contain any clear identifiers, including .toString
:
user=> (.toString ch)
"/0:0:0:0:0:0:0:1:3000<->/0:0:0:0:0:0:0:1:54538"
The only idea I could come up with is this:
1) Keep connect!
function as is:
(defonce channels (atom #{}))
(defn connect! [channel]
(log/info "channel open" channel)
(swap! channels conj channel))
2) Update WebSocket client to send JWT or ring session id as first message right after establishing a WS connection which allows mapping of that(already established) channel to an identifier(JWT or ring session id) which can identify a user.
Does it make sense at all? Or is it a big antipattern and violation of WS RFCs? Sorry, I didn't work with WebSockets on such a low level before.