@@ -11,6 +11,7 @@ import (
1111 "net/url"
1212 "strings"
1313 "sync/atomic"
14+ "time"
1415
1516 "github.com/gorilla/websocket"
1617 "github.com/pkg/errors"
@@ -134,7 +135,40 @@ func (server *Server) generateHandleWS(ctx context.Context, cancel context.Cance
134135 }
135136}
136137
138+ const (
139+ wsPingInterval = 30 * time .Second
140+ wsPingTimeout = 10 * time .Second
141+ wsPongWait = 60 * time .Second
142+ )
143+
137144func (server * Server ) processWSConn (ctx context.Context , conn * websocket.Conn , headers map [string ][]string ) error {
145+ // Set up WebSocket protocol-level ping/pong to keep the connection alive
146+ // through proxies, load balancers, and firewalls that have idle timeouts.
147+ conn .SetReadDeadline (time .Now ().Add (wsPongWait ))
148+ conn .SetPongHandler (func (string ) error {
149+ conn .SetReadDeadline (time .Now ().Add (wsPongWait ))
150+ return nil
151+ })
152+
153+ wrapper := & wsWrapper {Conn : conn }
154+
155+ pingCtx , pingCancel := context .WithCancel (ctx )
156+ defer pingCancel ()
157+ go func () {
158+ ticker := time .NewTicker (wsPingInterval )
159+ defer ticker .Stop ()
160+ for {
161+ select {
162+ case <- ticker .C :
163+ if err := wrapper .WritePing (); err != nil {
164+ return
165+ }
166+ case <- pingCtx .Done ():
167+ return
168+ }
169+ }
170+ }()
171+
138172 typ , initLine , err := conn .ReadMessage ()
139173 if err != nil {
140174 return errors .Wrapf (err , "failed to authenticate websocket connection" )
@@ -209,7 +243,7 @@ func (server *Server) processWSConn(ctx context.Context, conn *websocket.Conn, h
209243 if server .options .Height > 0 {
210244 opts = append (opts , webtty .WithFixedRows (server .options .Height ))
211245 }
212- tty , err := webtty .New (& wsWrapper { conn } , slave , opts ... )
246+ tty , err := webtty .New (wrapper , slave , opts ... )
213247 if err != nil {
214248 return errors .Wrapf (err , "failed to create webtty" )
215249 }
0 commit comments