;; ported-from: src/connect.ts @ v1.3.0
;;
;; The one-call entry: join a game room as a headless peer. Installs the origin
;; shims, resolves the app definition, and wires createNet into a small
;; event-emitting surface.
(ns ardegazu.peer.connect
(:require ["node:events" :refer (EventEmitter)]
[ardegazu.peer.apps :as apps]
[ardegazu.peer.core.net :as net]
[ardegazu.peer.node.env :as env]
[shadow.cljs.modern :refer (defclass js-await)]))
(defclass RoomPeer
(extends EventEmitter)
(constructor [this n app]
(super)
(unchecked-set this "net" n)
(unchecked-set this "app" app)))
(let [proto (.-prototype RoomPeer)]
(js/Object.defineProperty
proto "myId"
#js {:get (fn [] (this-as self (unchecked-get (unchecked-get self "net") "myId")))
:configurable true})
(unchecked-set proto "send"
(fn [to frame]
(this-as self ((unchecked-get (unchecked-get self "net") "send") to frame))))
(unchecked-set proto "broadcast"
(fn [frame]
(this-as self ((unchecked-get (unchecked-get self "net") "broadcast") frame))))
(unchecked-set proto "identityOf"
(fn [id]
(this-as self ((unchecked-get (unchecked-get self "net") "identityOf") id))))
(unchecked-set proto "close"
(fn [] (this-as self ((unchecked-get (unchecked-get self "net") "close"))))))
(defn connect
"opts = #js {:app :roomSecret :identity? :origin? :webrtc?}"
[opts]
(-> (js/Promise.resolve nil)
(.then
(fn [_]
(let [app-name (unchecked-get opts "app")
app (unchecked-get apps/GAMES app-name)]
(when-not ^boolean (js* "!!(~{})" app)
(throw (js/Error. (str "unknown app: " app-name))))
(let [origin (unchecked-get opts "origin")]
(env/install-origin (if ^boolean (js* "~{} == null" origin) apps/DEFAULT-ORIGIN origin)))
;; `let peer!: RoomPeer` — the callbacks fire before the peer exists
;; during createNet, and `peer?.emit(...)` swallows those
(let [holder (volatile! nil)
emit (fn [& args]
(let [p @holder]
(when (some? p) (.apply (.-emit ^js p) p (into-array args))))
js/undefined)]
(js-await [n (net/create-net
(js-obj "secret" (unchecked-get opts "roomSecret")
"appSalt" (unchecked-get app "salt")
"protocolPrefix" (unchecked-get app "protocolPrefix")
"descriptorUrl" (unchecked-get apps/SIGNAL "descriptorUrl")
"turnUrl" (unchecked-get apps/SIGNAL "turnUrl")
"relayFallback" (unchecked-get apps/SIGNAL "relayFallback")
"identity" (let [i (unchecked-get opts "identity")]
(if ^boolean (js* "~{} == null" i) nil i))
"webrtc" (unchecked-get opts "webrtc"))
(js-obj
"onRoomRoster" (fn [peers] (emit "roster" peers))
"onPeerOpen" (fn [id] (emit "peerOpen" id))
"onPeerGone" (fn [id] (emit "peerGone" id))
"onMessage" (fn [from payload] (emit "message" from payload))
"onStatus" (fn [] (emit "status"))
"onPeerIdentity" (fn [id ident] (emit "peerIdentity" id ident))))]
(let [p (RoomPeer. n app-name)]
(vreset! holder p)
p))))))))