@@ -12,6 +12,20 @@ import (
1212
1313var wsCon = websocket.Upgrader {}
1414
15+ const (
16+ // wsMaxMessageSize caps a single inbound websocket message so one large
17+ // frame cannot exhaust process memory.
18+ wsMaxMessageSize = 1 << 20 // 1 MiB
19+ // wsReadTimeout is how long the server waits for the next client message or
20+ // pong before closing an idle connection.
21+ wsReadTimeout = 60 * time .Second
22+ // wsWriteTimeout bounds a single write so a slow reader cannot block forever.
23+ wsWriteTimeout = 10 * time .Second
24+ // wsPingInterval is how often the server pings the client to keep the
25+ // connection alive and detect dead peers; it must be shorter than wsReadTimeout.
26+ wsPingInterval = 30 * time .Second
27+ )
28+
1529// EchoWS godoc
1630// @Summary Echo over websockets
1731// @Description echos content via websockets
@@ -24,11 +38,18 @@ var wsCon = websocket.Upgrader{}
2438func (s * Server ) echoWsHandler (w http.ResponseWriter , r * http.Request ) {
2539 c , err := wsCon .Upgrade (w , r , nil )
2640 if err != nil {
27- if err != nil {
28- s .logger .Warn ("websocket upgrade error" , zap .Error (err ))
29- return
30- }
41+ s .logger .Warn ("websocket upgrade error" , zap .Error (err ))
42+ return
3143 }
44+
45+ // Bound per-message size and idle time; refresh the read deadline whenever
46+ // the client responds to a ping so live connections stay open.
47+ c .SetReadLimit (wsMaxMessageSize )
48+ _ = c .SetReadDeadline (time .Now ().Add (wsReadTimeout ))
49+ c .SetPongHandler (func (string ) error {
50+ return c .SetReadDeadline (time .Now ().Add (wsReadTimeout ))
51+ })
52+
3253 var wg sync.WaitGroup
3354 wg .Add (1 )
3455
@@ -84,15 +105,23 @@ func (s *Server) sendHostWs(ws *websocket.Conn, in chan interface{}, done chan s
84105}
85106
86107func (s * Server ) writeWs (ws * websocket.Conn , in chan interface {}) {
108+ ping := time .NewTicker (wsPingInterval )
109+ defer ping .Stop ()
87110 for {
88111 select {
89112 case msg := <- in :
113+ _ = ws .SetWriteDeadline (time .Now ().Add (wsWriteTimeout ))
90114 if err := ws .WriteJSON (msg ); err != nil {
91115 if ! strings .Contains (err .Error (), "close" ) {
92116 s .logger .Warn ("websocket write error" , zap .Error (err ))
93117 }
94118 return
95119 }
120+ case <- ping .C :
121+ _ = ws .SetWriteDeadline (time .Now ().Add (wsWriteTimeout ))
122+ if err := ws .WriteMessage (websocket .PingMessage , nil ); err != nil {
123+ return
124+ }
96125 }
97126 }
98127}
0 commit comments