@@ -49,6 +49,17 @@ type Server struct {
49
49
IDGenerator IDGenerator
50
50
StackExchange StackExchange
51
51
52
+ // If `StackExchange` is set then this field is ignored.
53
+ //
54
+ // It overrides the default behavior(when no StackExchange is not used)
55
+ // which publishes a message independently.
56
+ // In short the default behavior doesn't wait for a message to be published to all clients
57
+ // before any next broadcast call.
58
+ //
59
+ // Therefore, if set to true,
60
+ // each broadcast call will publish its own message(s) by order.
61
+ SyncBroadcaster bool
62
+
52
63
mu sync.RWMutex
53
64
namespaces Namespaces
54
65
@@ -58,14 +69,16 @@ type Server struct {
58
69
59
70
count uint64
60
71
61
- connections map [* Conn ]struct {}
62
- connect chan * Conn
63
- disconnect chan * Conn
64
- actions chan action
72
+ connections map [* Conn ]struct {}
73
+ connect chan * Conn
74
+ disconnect chan * Conn
75
+ actions chan action
76
+ broadcastMessages chan []Message
77
+
65
78
broadcaster * broadcaster
79
+
66
80
// messages that this server must waits
67
- // for a reply from one of its own connections(see `waitMessage`)
68
- // or TODO: from cloud (see `StackExchange.PublishAndWait`).
81
+ // for a reply from one of its own connections(see `waitMessages`).
69
82
waitingMessages map [string ]chan Message
70
83
waitingMessagesMutex sync.RWMutex
71
84
@@ -94,22 +107,21 @@ func New(upgrader Upgrader, connHandler ConnHandler) *Server {
94
107
readTimeout , writeTimeout := getTimeouts (connHandler )
95
108
namespaces := connHandler .GetNamespaces ()
96
109
s := & Server {
97
- uuid : uuid .Must (uuid .NewV4 ()).String (),
98
- upgrader : upgrader ,
99
- namespaces : namespaces ,
100
- readTimeout : readTimeout ,
101
- writeTimeout : writeTimeout ,
102
- connections : make (map [* Conn ]struct {}),
103
- connect : make (chan * Conn , 1 ),
104
- disconnect : make (chan * Conn ),
105
- actions : make (chan action ),
106
- broadcaster : newBroadcaster (),
107
- waitingMessages : make (map [string ]chan Message ),
108
- IDGenerator : DefaultIDGenerator ,
110
+ uuid : uuid .Must (uuid .NewV4 ()).String (),
111
+ upgrader : upgrader ,
112
+ namespaces : namespaces ,
113
+ readTimeout : readTimeout ,
114
+ writeTimeout : writeTimeout ,
115
+ connections : make (map [* Conn ]struct {}),
116
+ connect : make (chan * Conn , 1 ),
117
+ disconnect : make (chan * Conn ),
118
+ actions : make (chan action ),
119
+ broadcastMessages : make (chan []Message ),
120
+ broadcaster : newBroadcaster (),
121
+ waitingMessages : make (map [string ]chan Message ),
122
+ IDGenerator : DefaultIDGenerator ,
109
123
}
110
124
111
- // s.broadcastCond = sync.NewCond(&s.broadcastMu)
112
-
113
125
go s .start ()
114
126
115
127
return s
@@ -171,6 +183,10 @@ func (s *Server) start() {
171
183
s .StackExchange .OnDisconnect (c )
172
184
}
173
185
}
186
+ case msgs := <- s .broadcastMessages :
187
+ for c := range s .connections {
188
+ publishMessages (c , msgs )
189
+ }
174
190
case act := <- s .actions :
175
191
for c := range s .connections {
176
192
act .call (c )
@@ -312,9 +328,9 @@ func (s *Server) Upgrade(
312
328
c .ReconnectTries , _ = strconv .Atoi (retriesHeaderValue )
313
329
}
314
330
315
- if ! s .usesStackExchange () {
331
+ if ! s .usesStackExchange () && ! s . SyncBroadcaster {
316
332
go func (c * Conn ) {
317
- for s .waitMessage (c ) {
333
+ for s .waitMessages (c ) {
318
334
}
319
335
}(c )
320
336
}
@@ -380,34 +396,6 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
380
396
s .Upgrade (w , r , nil , nil )
381
397
}
382
398
383
- func (s * Server ) waitMessage (c * Conn ) bool {
384
- s .broadcaster .mu .Lock ()
385
- defer s .broadcaster .mu .Unlock ()
386
-
387
- msg , ok := s .broadcaster .waitUntilClosed (c .closeCh )
388
- if ! ok {
389
- return false
390
- }
391
-
392
- if msg .from == c .ID () {
393
- // if the message is not supposed to return back to any connection with this ID.
394
- return true
395
- }
396
-
397
- // if "To" field is given then send to a specific connection.
398
- if msg .To != "" && msg .To != c .ID () {
399
- return true
400
- }
401
-
402
- // c.Write may fail if the message is not supposed to end to this client
403
- // but the connection should be still open in order to continue.
404
- if ! c .Write (msg ) && c .IsClosed () {
405
- return false
406
- }
407
-
408
- return true
409
- }
410
-
411
399
// GetTotalConnections returns the total amount of the connected connections to the server, it's fast
412
400
// and can be used as frequently as needed.
413
401
func (s * Server ) GetTotalConnections () uint64 {
@@ -438,6 +426,41 @@ func (s *Server) Do(fn func(*Conn), async bool) {
438
426
}
439
427
}
440
428
429
+ func publishMessages (c * Conn , msgs []Message ) bool {
430
+ for _ , msg := range msgs {
431
+ if msg .from == c .ID () {
432
+ // if the message is not supposed to return back to any connection with this ID.
433
+
434
+ return true
435
+ }
436
+
437
+ // if "To" field is given then send to a specific connection.
438
+ if msg .To != "" && msg .To != c .ID () {
439
+ return true
440
+ }
441
+
442
+ // c.Write may fail if the message is not supposed to end to this client
443
+ // but the connection should be still open in order to continue.
444
+ if ! c .Write (msg ) && c .IsClosed () {
445
+ return false
446
+ }
447
+ }
448
+
449
+ return true
450
+ }
451
+
452
+ func (s * Server ) waitMessages (c * Conn ) bool {
453
+ s .broadcaster .mu .Lock ()
454
+ defer s .broadcaster .mu .Unlock ()
455
+
456
+ msgs , ok := s .broadcaster .waitUntilClosed (c .closeCh )
457
+ if ! ok {
458
+ return false
459
+ }
460
+
461
+ return publishMessages (c , msgs )
462
+ }
463
+
441
464
type stringerValue struct { v string }
442
465
443
466
func (s stringerValue ) String () string { return s .v }
@@ -452,7 +475,7 @@ func (s stringerValue) String() string { return s.v }
452
475
// neffos.Message{Namespace: "default", Room: "roomName or empty", Event: "chat", Body: [...]})
453
476
func Exclude (connID string ) fmt.Stringer { return stringerValue {connID } }
454
477
455
- // Broadcast method is fast and does not block any new incoming connection,
478
+ // Broadcast method is fast and does not block any new incoming connection by-default ,
456
479
// it can be used as frequently as needed. Use the "msg"'s Namespace, or/and Event or/and Room to broadcast
457
480
// to a specific type of connection collectives.
458
481
//
@@ -465,34 +488,45 @@ func Exclude(connID string) fmt.Stringer { return stringerValue{connID} }
465
488
// nsConn.Conn.Server().Broadcast(
466
489
// nsConn OR nil,
467
490
// neffos.Message{Namespace: "default", Room: "roomName or empty", Event: "chat", Body: [...]})
468
- func (s * Server ) Broadcast (exceptSender fmt.Stringer , msg Message ) {
491
+ //
492
+ // Note that it if `StackExchange` is nil then its default behavior
493
+ // doesn't wait for a publish to complete to all clients before any
494
+ // next broadcast call. To change that behavior set the `Server.SyncBroadcaster` to true
495
+ // before server start.
496
+ func (s * Server ) Broadcast (exceptSender fmt.Stringer , msgs ... Message ) {
497
+
469
498
if exceptSender != nil {
499
+ var fromExplicit , from string
500
+
470
501
switch c := exceptSender .(type ) {
471
502
case * Conn :
472
- msg . FromExplicit = c .serverConnID
503
+ fromExplicit = c .serverConnID
473
504
case * NSConn :
474
- msg . FromExplicit = c .Conn .serverConnID
505
+ fromExplicit = c .Conn .serverConnID
475
506
default :
476
- msg . from = exceptSender .String ()
507
+ from = exceptSender .String ()
477
508
}
478
509
479
- // msg.from = exceptSender.String()
510
+ for i := range msgs {
511
+ if from != "" {
512
+ msgs [i ].from = from
513
+ } else {
514
+ msgs [i ].FromExplicit = fromExplicit
515
+ }
516
+ }
480
517
}
481
518
482
- // s.broadcast <- msg
483
-
484
- // s.broadcastMu.Lock()
485
- // s.broadcastMessage = msg
486
- // s.broadcastMu.Unlock()
487
-
488
- // s.broadcastCond.Broadcast()
489
-
490
519
if s .usesStackExchange () {
491
- s .StackExchange .Publish (msg )
520
+ s .StackExchange .Publish (msgs )
521
+ return
522
+ }
523
+
524
+ if s .SyncBroadcaster {
525
+ s .broadcastMessages <- msgs
492
526
return
493
527
}
494
528
495
- s .broadcaster .broadcast (msg )
529
+ s .broadcaster .broadcast (msgs )
496
530
}
497
531
498
532
// Ask is like `Broadcast` but it blocks until a response
0 commit comments