Skip to content

Commit 5edde2c

Browse files
committed
refactor(server): centralize room variable management and enhance logging
Moves room variable operations into the RoomManager to standardize state access across protocols and adds comprehensive debug logging. - Migrates global variable storage/deletion to RoomManager operations - Adds debug logging to CL2, CL3/4, and Scratch packet handlers - Implements JSON tags for BridgeClient to control field serialization - Removes connection read deadlines and adds rate limit warnings - Updates roomEvents to an unbuffered channel for synchronous processing - Adds RoomOp stringer and centralized response logging helper
1 parent b818817 commit 5edde2c

6 files changed

Lines changed: 118 additions & 45 deletions

File tree

server/cl2.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,8 @@ func (s *CL2) Handler(client *BridgeClient, p *CL2Packet) {
156156
return
157157
}
158158

159+
s.Logger.Debug().Any("packet", p).Any("client", client).Msg("Received CL2 packet")
160+
159161
if client.Conn != nil {
160162
s.classicclientsmu.RLock()
161163
active := s.ClassicClients[client]
@@ -258,9 +260,7 @@ func (s *CL2) Handler(client *BridgeClient, p *CL2Packet) {
258260
}
259261
case "1":
260262
// Mode 1: Standard Global Variable Broadcast
261-
if gv := s.GetRoomGlobalVars(DEFAULT_ROOM); gv != nil {
262-
gv.Store(p.Var, p.Data)
263-
}
263+
s.SetRoomGlobalVar(client, DEFAULT_ROOM, p.Var, p.Data)
264264
s.Broadcast(DEFAULT_ROOM, &Common_Packet{
265265
Command: "gvar",
266266
Name: p.Var,

server/cl4or3.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ func (s CL4_or_CL3) Handler(client *BridgeClient, p *Common_Packet) {
8181
return
8282
}
8383

84+
s.Logger.Debug().Any("packet", p).Any("client", client).Msg("Received CL3/4 packet")
85+
8486
if client.Conn != nil {
8587
s.classicclientsmu.RLock()
8688
active := s.ClassicClients[client]
@@ -153,9 +155,7 @@ func (s CL4_or_CL3) Handler(client *BridgeClient, p *Common_Packet) {
153155

154156
// Store the variable dynamically across all protocols
155157
if p.Command == "gvar" {
156-
if gv := s.GetRoomGlobalVars(room); gv != nil {
157-
gv.Store(p.Name, p.Value)
158-
}
158+
s.SetRoomGlobalVar(client, room, p.Name, p.Value)
159159
}
160160

161161
s.Broadcast(room, &Common_Packet{

server/client.go

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,10 @@ func (c *BridgeClient) Writer() {
2828
}
2929

3030
func (c *BridgeClient) Reader() {
31-
// 1. Set a hard limit of 64KB
31+
// Set a hard limit of 64KB
3232
c.Conn.SetReadLimit(64 * 1024)
33-
34-
// 2. Define a heartbeat/timeout interval
35-
waitTimeout := 60 * time.Second
3633
reader:
3734
for {
38-
// 3. Refresh deadline; If no packets are received within 60 seconds the connection is aborted.
39-
c.Conn.SetReadDeadline(time.Now().Add(waitTimeout))
40-
4135
if msg_type, packet, err := c.Conn.ReadMessage(); err != nil {
4236
c.Server.Logger.Error().AnErr("error", err).Msg("Error reading from client")
4337
c.exit <- true
@@ -68,6 +62,7 @@ reader:
6862
c.exit <- true
6963
break reader
7064
} else {
65+
c.Server.Logger.Warn().Msgf("%s ⚠️ Client exceeding rate limit...", c.GiveName())
7166
// Silently drop new packets
7267
continue
7368
}

server/scratch.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ func (s Scratch_Handler) Handler(client *BridgeClient, p *ScratchPacket) {
6464
return
6565
}
6666

67+
s.Logger.Debug().Any("packet", p).Any("client", client).Msg("Received Scratch packet")
68+
6769
if client.Conn != nil {
6870
s.classicclientsmu.RLock()
6971
active := s.ClassicClients[client]
@@ -131,9 +133,7 @@ func (s Scratch_Handler) Handler(client *BridgeClient, p *ScratchPacket) {
131133
}
132134
projectRoom := client.Rooms[0]
133135

134-
if gv := s.GetRoomGlobalVars(projectRoom); gv != nil {
135-
gv.Store(p.Name, p.Value)
136-
}
136+
s.SetRoomGlobalVar(client, projectRoom, p.Name, p.Value)
137137

138138
s.Broadcast(projectRoom, &ScratchPacket{
139139
Method: p.Method,

server/server.go

Lines changed: 60 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ func New(server_config *Config, duplex_config *duplex.Config) *Server {
5252

5353
self := "bridge@" + server_config.Designation
5454

55+
if server_config.Standalone_Mode {
56+
self += "standalone"
57+
}
58+
5559
// Create bridge manager
5660
server := &Server{
5761
Self: self,
@@ -61,7 +65,7 @@ func New(server_config *Config, duplex_config *duplex.Config) *Server {
6165
DeltaResolverCache: make(map[*duplex.Peer]HelloArgs),
6266
Config: server_config,
6367
RoomsMap: make(map[RoomKey]*Room),
64-
roomEvents: make(chan RoomEvent, 1024),
68+
roomEvents: make(chan RoomEvent),
6569
snowflakeGen: node,
6670
App: fiber.New(fiber.Config{
6771
JSONEncoder: json.Marshal,
@@ -158,14 +162,21 @@ func (s *Server) Run() {
158162
s.Done <- true
159163
}
160164

165+
func (s *Server) make_response(a any, e RoomEvent) {
166+
s.Logger.Debug().Any("response", a).Msg("🚪 replying")
167+
e.Respond <- a
168+
}
169+
161170
func (s *Server) RoomManager() {
162171
for event := range s.roomEvents {
172+
s.Logger.Debug().Str("opcode", event.Op.String()).Any("key", event.Key).Any("value", event.Value).Msg("🚪 processing")
173+
163174
switch event.Op {
164175
case OpJoinRoom:
165176
r, exists := s.RoomsMap[event.Room]
166177
if !exists {
167-
s.Logger.Info().Msgf("%s 🚪 Creating room %s", event.Client.GiveName(), event.Room)
168-
r = &Room{Clients: make(Targets)}
178+
s.Logger.Info().Any("client", event.Client).Any("room", event.Room).Msgf("🚪 creating")
179+
r = &Room{Clients: make(Targets), GlobalVars: &sync.Map{}}
169180
s.RoomsMap[event.Room] = r
170181
}
171182
r.Clients[event.Client] = true
@@ -174,7 +185,7 @@ func (s *Server) RoomManager() {
174185
delete(r.Clients, event.Client)
175186
if len(r.Clients) == 0 {
176187
delete(s.RoomsMap, event.Room)
177-
s.Logger.Info().Msgf("%s 🚪 Destroying vacant room %s", event.Client.GiveName(), event.Room)
188+
s.Logger.Info().Any("client", event.Client).Any("room", event.Room).Msgf("🚪 destroying")
178189
}
179190
}
180191
case OpGetClients:
@@ -185,7 +196,7 @@ func (s *Server) RoomManager() {
185196
clients = append(clients, c)
186197
}
187198
}
188-
event.Respond <- clients
199+
s.make_response(clients, event)
189200
case OpGetTargets:
190201
var targets Targets
191202
if r, exists := s.RoomsMap[event.Room]; exists {
@@ -194,12 +205,12 @@ func (s *Server) RoomManager() {
194205
targets[c] = true
195206
}
196207
}
197-
event.Respond <- targets
208+
s.make_response(targets, event)
198209
case OpDoesRoomExist:
199210
_, exists := s.RoomsMap[event.Room]
200-
event.Respond <- exists
211+
s.make_response(exists, event)
201212
case OpGetActiveRooms:
202-
event.Respond <- len(s.RoomsMap)
213+
s.make_response(len(s.RoomsMap), event)
203214
case OpCanAllocateNRooms:
204215
active_rooms := len(s.RoomsMap)
205216
decrement := 0
@@ -208,20 +219,56 @@ func (s *Server) RoomManager() {
208219
decrement = -1
209220
}
210221
}
211-
event.Respond <- active_rooms+event.N+decrement <= int(s.Config.Maximum_Rooms)
212-
case OpGetRoomForVars:
222+
s.make_response(active_rooms+event.N+decrement <= int(s.Config.Maximum_Rooms), event)
223+
case OpGetRoomVars:
213224
if r, exists := s.RoomsMap[event.Room]; exists {
214-
event.Respond <- &r.GlobalVars
225+
s.make_response(r.GlobalVars, event)
215226
} else {
216-
event.Respond <- (*sync.Map)(nil)
227+
s.make_response((*sync.Map)(nil), event)
228+
}
229+
case OpSetRoomVar:
230+
if r, exists := s.RoomsMap[event.Room]; exists {
231+
232+
if _, ok := r.GlobalVars.Load(event.Key); !ok {
233+
s.Logger.Info().Any("client", event.Client).Any("room", event.Room).Any("gvar", event.Key).Msgf("🚪 creating")
234+
}
235+
236+
r.GlobalVars.Store(event.Key, event.Value)
237+
s.make_response(true, event)
238+
} else {
239+
s.make_response(false, event)
240+
}
241+
case OpDeleteRoomVar:
242+
if r, exists := s.RoomsMap[event.Room]; exists {
243+
244+
if _, ok := r.GlobalVars.Load(event.Key); !ok {
245+
s.Logger.Info().Any("client", event.Client).Any("room", event.Room).Any("gvar", event.Key).Msgf("🚪 deleting")
246+
}
247+
248+
r.GlobalVars.Delete(event.Key)
249+
s.make_response(true, event)
250+
} else {
251+
s.make_response(false, event)
217252
}
218253
}
219254
}
220255
}
221256

257+
func (s *Server) DeleteRoomGlobalVar(room RoomKey, key any) bool {
258+
resp := make(chan any, 1)
259+
s.roomEvents <- RoomEvent{Op: OpDeleteRoomVar, Room: room, Key: key, Respond: resp}
260+
return (<-resp).(bool)
261+
}
262+
263+
func (s *Server) SetRoomGlobalVar(client *BridgeClient, room RoomKey, key any, value any) bool {
264+
resp := make(chan any, 1)
265+
s.roomEvents <- RoomEvent{Op: OpSetRoomVar, Client: client, Room: room, Key: key, Value: value, Respond: resp}
266+
return (<-resp).(bool)
267+
}
268+
222269
func (s *Server) GetRoomGlobalVars(room RoomKey) *sync.Map {
223270
resp := make(chan any, 1)
224-
s.roomEvents <- RoomEvent{Op: OpGetRoomForVars, Room: room, Respond: resp}
271+
s.roomEvents <- RoomEvent{Op: OpGetRoomVars, Room: room, Respond: resp}
225272
return (<-resp).(*sync.Map)
226273
}
227274

server/types.go

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ var (
4545

4646
type Room struct {
4747
Clients Targets
48-
GlobalVars sync.Map // Protocol-agnostic global variable storage
48+
GlobalVars *sync.Map // Protocol-agnostic global variable storage
4949
}
5050

5151
type Targets map[*BridgeClient]bool
@@ -61,14 +61,45 @@ const (
6161
OpDoesRoomExist
6262
OpGetActiveRooms
6363
OpCanAllocateNRooms
64-
OpGetRoomForVars
64+
OpGetRoomVars
65+
OpSetRoomVar
66+
OpDeleteRoomVar
6567
)
6668

69+
func (r RoomOp) String() string {
70+
switch r {
71+
case OpJoinRoom:
72+
return "join room"
73+
case OpLeaveRoom:
74+
return "leave room"
75+
case OpGetClients:
76+
return "get clients"
77+
case OpGetTargets:
78+
return "get targets"
79+
case OpDoesRoomExist:
80+
return "does room exist"
81+
case OpGetActiveRooms:
82+
return "get active rooms"
83+
case OpCanAllocateNRooms:
84+
return "can allocate n rooms"
85+
case OpGetRoomVars:
86+
return "get room vars"
87+
case OpSetRoomVar:
88+
return "set room var"
89+
case OpDeleteRoomVar:
90+
return "delete room var"
91+
default:
92+
return "unknown"
93+
}
94+
}
95+
6796
type RoomEvent struct {
6897
Op RoomOp
6998
Client *BridgeClient
7099
Room RoomKey
71100
N int
101+
Key any
102+
Value any
72103
Respond chan any
73104
}
74105

@@ -270,22 +301,22 @@ type RoomKey string
270301
type RoomKeys []RoomKey
271302

272303
type BridgeClient struct {
273-
Conn *websocket.Conn
274-
ID string
275-
Peer *duplex.Peer
276-
UUID string
277-
Username any
278-
writer chan []byte
279-
exit chan bool
280-
Rooms RoomKeys
281-
room_mux sync.RWMutex
282-
dialect uint
283-
Protocol Protocol
284-
Server *Server
304+
Conn *websocket.Conn `json:"-"`
305+
ID string `json:"id"`
306+
Peer *duplex.Peer `json:"-"`
307+
UUID string `json:"uuid"`
308+
Username any `json:"username,omitempty"`
309+
writer chan []byte `json:"-"`
310+
exit chan bool `json:"-"`
311+
Rooms RoomKeys `json:"rooms"`
312+
room_mux sync.RWMutex `json:"-"`
313+
dialect uint `json:"-"`
314+
Protocol Protocol `json:"-"`
315+
Server *Server `json:"-"`
285316

286317
// Rate limiting
287-
last_msg_time time.Time
288-
msg_count int
318+
last_msg_time time.Time `json:"-"`
319+
msg_count int `json:"-"`
289320
}
290321

291322
type Packet interface {

0 commit comments

Comments
 (0)