111 lines
3.1 KiB
Go
111 lines
3.1 KiB
Go
package services
|
|
|
|
import (
|
|
"git.saqut.com/saqut/mwse/internal/protocol"
|
|
"git.saqut.com/saqut/mwse/internal/ws"
|
|
)
|
|
|
|
// handshakeResult returns the optional acknowledgement for a relay handler. When
|
|
// the caller did not ask for a handshake the relay is fire-and-forget (nil), so
|
|
// the generic dispatcher sends no reply.
|
|
func handshakeResult(m protocol.Message, success bool) any {
|
|
if !m.Truthy("handshake") {
|
|
return nil
|
|
}
|
|
if success {
|
|
return map[string]any{"type": "success"}
|
|
}
|
|
return map[string]any{"type": "fail"}
|
|
}
|
|
|
|
func registerDataTransfer(hub *ws.Hub) {
|
|
// pack/to: relay a data pack to another peer, honouring both peers' relay
|
|
// flags and the target's pairing policy. When the target does not require
|
|
// pairing, an implicit pairing is established so subsequent traffic flows.
|
|
hub.Register("pack/to", func(c *ws.Client, m protocol.Message) any {
|
|
if !c.PackReadable() {
|
|
return handshakeResult(m, false)
|
|
}
|
|
to := m.Str("to")
|
|
other, ok := hub.Client(to)
|
|
if !ok {
|
|
return handshakeResult(m, false)
|
|
}
|
|
if other.RequiredPair() {
|
|
if !other.HasPair(c.ID) {
|
|
return handshakeResult(m, false)
|
|
}
|
|
} else if !other.HasPair(c.ID) {
|
|
other.AddPair(c.ID)
|
|
c.AddPair(other.ID)
|
|
}
|
|
if !other.PackWriteable() {
|
|
return handshakeResult(m, false)
|
|
}
|
|
other.Signal("pack", map[string]any{"from": c.ID, "pack": m.Get("pack")})
|
|
return handshakeResult(m, true)
|
|
})
|
|
|
|
// request/to: relay a request to a peer. The reply travels back later via
|
|
// response/to, carrying the original request id, so this handler itself does
|
|
// not produce the answer.
|
|
hub.Register("request/to", func(c *ws.Client, m protocol.Message) any {
|
|
other, ok := hub.Client(m.Str("to"))
|
|
if !ok {
|
|
return nil
|
|
}
|
|
if other.RequiredPair() {
|
|
if !other.HasPair(c.ID) {
|
|
return nil
|
|
}
|
|
} else {
|
|
other.AddPair(c.ID)
|
|
c.AddPair(other.ID)
|
|
}
|
|
other.Signal("request", map[string]any{"from": c.ID, "pack": m.Get("pack")})
|
|
return nil
|
|
})
|
|
|
|
// response/to: deliver a peer's response back to the original requester. The
|
|
// frame uses the numeric request id in the signal slot so the requester's
|
|
// event pool resolves the pending promise.
|
|
hub.Register("response/to", func(c *ws.Client, m protocol.Message) any {
|
|
other, ok := hub.Client(m.Str("to"))
|
|
if !ok {
|
|
return nil
|
|
}
|
|
if other.RequiredPair() && !other.HasPair(c.ID) {
|
|
return nil
|
|
}
|
|
other.Send([]any{map[string]any{"from": c.ID, "pack": m.Get("pack")}, m.Get("id")})
|
|
return nil
|
|
})
|
|
|
|
// pack/room: relay a data pack to every writable member of a room the sender
|
|
// belongs to. "wom" (without me) excludes the sender.
|
|
hub.Register("pack/room", func(c *ws.Client, m protocol.Message) any {
|
|
if !c.PackReadable() {
|
|
return handshakeResult(m, false)
|
|
}
|
|
to := m.Str("to")
|
|
room, ok := hub.Room(to)
|
|
if !ok {
|
|
return handshakeResult(m, false)
|
|
}
|
|
if !c.InRoom(to) {
|
|
return handshakeResult(m, false)
|
|
}
|
|
except := ""
|
|
if m.Truthy("wom") {
|
|
except = c.ID
|
|
}
|
|
room.Broadcast(
|
|
"pack/room",
|
|
map[string]any{"from": to, "pack": m.Get("pack"), "sender": c.ID},
|
|
except,
|
|
(*ws.Client).PackWriteable,
|
|
)
|
|
return handshakeResult(m, true)
|
|
})
|
|
}
|