@@ -32,6 +32,7 @@ import (
3232 "runtime/debug"
3333 "strconv"
3434 "strings"
35+ "sync"
3536 "time"
3637
3738 cert "github.com/arduino/arduino-create-agent/certificates"
@@ -467,9 +468,10 @@ func loop() {
467468 r .POST ("/update" , updateHandler )
468469
469470 // TODO: temporary using a different port for the websocket server
471+ hub := newHub ()
470472 go func () {
471473 http .HandleFunc ("/ws" , func (w http.ResponseWriter , r * http.Request ) {
472- ServeWS (w , r )
474+ ServeWS (hub , w , r )
473475 })
474476 fmt .Println ("Starting server and websocket on " + * address + ":9001" )
475477 log .Fatal (http .ListenAndServe (* address + ":9001" , nil ))
@@ -570,21 +572,91 @@ func promptInstallCertsSafari() bool {
570572 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" )
571573}
572574
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 {
577577 // TODO: check origin with the list of allowed origins
578578 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+ )
580595
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 )
582598 if err != nil {
583- log .Println ("upgrade:" , err )
599+ log .Error ("upgrade:" , err )
584600 return
585601 }
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+ }
586638
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+ }
590662}
0 commit comments