@@ -32,6 +32,7 @@ import (
32
32
"runtime/debug"
33
33
"strconv"
34
34
"strings"
35
+ "sync"
35
36
"time"
36
37
37
38
cert "github.com/arduino/arduino-create-agent/certificates"
@@ -467,9 +468,10 @@ func loop() {
467
468
r .POST ("/update" , updateHandler )
468
469
469
470
// TODO: temporary using a different port for the websocket server
471
+ hub := newHub ()
470
472
go func () {
471
473
http .HandleFunc ("/ws" , func (w http.ResponseWriter , r * http.Request ) {
472
- ServeWS (w , r )
474
+ ServeWS (hub , w , r )
473
475
})
474
476
fmt .Println ("Starting server and websocket on " + * address + ":9001" )
475
477
log .Fatal (http .ListenAndServe (* address + ":9001" , nil ))
@@ -570,21 +572,91 @@ func promptInstallCertsSafari() bool {
570
572
return utilities .UserPrompt ("The Arduino Agent needs a local HTTPS certificate to work correctly with Safari.\n If you use Safari, you need to install it." , "{\" Do not install\" , \" Install the certificate for Safari\" }" , "Install the certificate for Safari" , "Install the certificate for Safari" , "Arduino Agent: Install certificate" )
571
573
}
572
574
573
- var upgrader = websocket.Upgrader {}
574
-
575
- func ServeWS (w http.ResponseWriter , r * http.Request ) {
576
- upgrader .CheckOrigin = func (r * http.Request ) bool {
575
+ var upgrader = websocket.Upgrader {
576
+ CheckOrigin : func (r * http.Request ) bool {
577
577
// TODO: check origin with the list of allowed origins
578
578
return true
579
- }
579
+ },
580
+ }
581
+
582
+ const (
583
+ // Time allowed to write a message to the peer.
584
+ writeWait = 10 * time .Second
585
+
586
+ // Time allowed to read the next pong message from the peer.
587
+ pongWait = 60 * time .Second
588
+
589
+ // Send pings to peer with this period. Must be less than pongWait.
590
+ pingPeriod = (pongWait * 9 ) / 10
591
+
592
+ // Maximum message size allowed from peer.
593
+ maxMessageSize = 512
594
+ )
580
595
581
- ws , err := upgrader .Upgrade (w , r , nil )
596
+ func ServeWS (hub * Hub , w http.ResponseWriter , r * http.Request ) {
597
+ conn , err := upgrader .Upgrade (w , r , nil )
582
598
if err != nil {
583
- log .Println ("upgrade:" , err )
599
+ log .Error ("upgrade:" , err )
584
600
return
585
601
}
602
+ defer hub .unregister (conn )
603
+
604
+ hub .register (conn )
605
+
606
+ read (hub , conn )
607
+ }
608
+
609
+ func read (hub * Hub , conn * websocket.Conn ) {
610
+
611
+ conn .SetReadLimit (maxMessageSize )
612
+ conn .SetReadDeadline (time .Now ().Add (pongWait ))
613
+ conn .SetPongHandler (func (string ) error { conn .SetReadDeadline (time .Now ().Add (pongWait )); return nil })
614
+ for {
615
+ _ , message , err := conn .ReadMessage ()
616
+ if err != nil {
617
+ if websocket .IsUnexpectedCloseError (err , websocket .CloseGoingAway , websocket .CloseAbnormalClosure ) {
618
+ log .Printf ("error: %v" , err )
619
+ }
620
+ break
621
+ }
622
+ log .Info ("Received message from client: " + string (message ))
623
+ hub .broadcast (message )
624
+ }
625
+ }
626
+
627
+ type Hub struct {
628
+ // Registered clients.
629
+ clients map [* websocket.Conn ]bool
630
+ mu sync.Mutex
631
+ }
632
+
633
+ func newHub () * Hub {
634
+ return & Hub {
635
+ clients : make (map [* websocket.Conn ]bool ),
636
+ }
637
+ }
586
638
587
- defer ws .Close ()
588
- fmt .Println ("[WS] Client connected" )
589
- ws .WriteMessage (websocket .TextMessage , []byte ("Hello, client!" ))
639
+ func (h * Hub ) register (conn * websocket.Conn ) {
640
+ defer h .mu .Unlock ()
641
+ h .mu .Lock ()
642
+ h .clients [conn ] = true
643
+ conn .WriteMessage (websocket .TextMessage , []byte ("Hello, client!" ))
644
+ }
645
+
646
+ func (h * Hub ) unregister (conn * websocket.Conn ) {
647
+ defer h .mu .Unlock ()
648
+ h .mu .Lock ()
649
+ delete (h .clients , conn )
650
+ conn .Close ()
651
+ }
652
+
653
+ func (h * Hub ) broadcast (message []byte ) {
654
+ for conn := range h .clients {
655
+ log .Info ("Broadcasting message to client" + conn .RemoteAddr ().String ())
656
+ err := conn .WriteMessage (websocket .TextMessage , message )
657
+ if err != nil {
658
+ // TODO: handle error
659
+ log .Println ("write:" , err )
660
+ }
661
+ }
590
662
}
0 commit comments