Web-based Winamp controller for CarPC � Go backend, mobile-first UI
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

121 rinda
2.6KB

  1. //go:build windows
  2. package server
  3. import (
  4. "log"
  5. "time"
  6. "github.com/gorilla/websocket"
  7. )
  8. const (
  9. writeWait = 10 * time.Second
  10. pongWait = 60 * time.Second
  11. pingPeriod = pongWait * 9 / 10
  12. maxMessageSize = 512
  13. )
  14. // hub maintains the set of active WebSocket clients and broadcasts messages.
  15. type hub struct {
  16. clients map[*wsClient]struct{}
  17. broadcast chan []byte
  18. register chan *wsClient
  19. unregister chan *wsClient
  20. onCmd func([]byte) // called for each message from any client
  21. }
  22. func newHub(onCmd func([]byte)) *hub {
  23. return &hub{
  24. clients: make(map[*wsClient]struct{}),
  25. broadcast: make(chan []byte, 64),
  26. register: make(chan *wsClient, 8),
  27. unregister: make(chan *wsClient, 8),
  28. onCmd: onCmd,
  29. }
  30. }
  31. func (h *hub) run() {
  32. for {
  33. select {
  34. case c := <-h.register:
  35. h.clients[c] = struct{}{}
  36. case c := <-h.unregister:
  37. if _, ok := h.clients[c]; ok {
  38. delete(h.clients, c)
  39. close(c.send)
  40. }
  41. case msg := <-h.broadcast:
  42. for c := range h.clients {
  43. select {
  44. case c.send <- msg:
  45. default:
  46. // Slow client — drop and disconnect.
  47. close(c.send)
  48. delete(h.clients, c)
  49. }
  50. }
  51. }
  52. }
  53. }
  54. // ── wsClient ──────────────────────────────────────────────────────────────────
  55. type wsClient struct {
  56. hub *hub
  57. conn *websocket.Conn
  58. send chan []byte
  59. }
  60. func (c *wsClient) readPump() {
  61. defer func() {
  62. c.hub.unregister <- c
  63. c.conn.Close()
  64. }()
  65. c.conn.SetReadLimit(maxMessageSize)
  66. c.conn.SetReadDeadline(time.Now().Add(pongWait))
  67. c.conn.SetPongHandler(func(string) error {
  68. c.conn.SetReadDeadline(time.Now().Add(pongWait))
  69. return nil
  70. })
  71. for {
  72. _, msg, err := c.conn.ReadMessage()
  73. if err != nil {
  74. if websocket.IsUnexpectedCloseError(err,
  75. websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
  76. log.Printf("ws read: %v", err)
  77. }
  78. break
  79. }
  80. if c.hub.onCmd != nil {
  81. c.hub.onCmd(msg)
  82. }
  83. }
  84. }
  85. func (c *wsClient) writePump() {
  86. ticker := time.NewTicker(pingPeriod)
  87. defer func() {
  88. ticker.Stop()
  89. c.conn.Close()
  90. }()
  91. for {
  92. select {
  93. case msg, ok := <-c.send:
  94. c.conn.SetWriteDeadline(time.Now().Add(writeWait))
  95. if !ok {
  96. c.conn.WriteMessage(websocket.CloseMessage, []byte{})
  97. return
  98. }
  99. if err := c.conn.WriteMessage(websocket.TextMessage, msg); err != nil {
  100. return
  101. }
  102. case <-ticker.C:
  103. c.conn.SetWriteDeadline(time.Now().Add(writeWait))
  104. if err := c.conn.WriteMessage(websocket.PingMessage, nil); err != nil {
  105. return
  106. }
  107. }
  108. }
  109. }