Skip to content

Commit 2f470bb

Browse files
committed
fix(websocket): 修复 websocket 超时问题
1 parent 8163526 commit 2f470bb

3 files changed

Lines changed: 52 additions & 3 deletions

File tree

js/src/xterm.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ export class GoTTYXterm {
1717
messageTimeout: number;
1818
messageTimer: NodeJS.Timeout;
1919

20-
onResizeHandler: IDisposable;
21-
onDataHandler: IDisposable;
20+
onResizeHandler: IDisposable | undefined;
21+
onDataHandler: IDisposable | undefined;
2222

2323
fitAddOn: FitAddon;
2424
zmodemAddon: ZModemAddon;
@@ -139,9 +139,11 @@ export class GoTTYXterm {
139139
deactivate(): void {
140140
if (this.onDataHandler) {
141141
this.onDataHandler.dispose();
142+
this.onDataHandler = undefined;
142143
}
143144
if (this.onResizeHandler) {
144145
this.onResizeHandler.dispose();
146+
this.onResizeHandler = undefined;
145147
}
146148
this.term.blur();
147149
}

server/handlers.go

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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+
137144
func (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
}

server/ws_wrapper.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,22 @@ package server
22

33
import (
44
"io"
5+
"sync"
6+
"time"
57

68
"github.com/gorilla/websocket"
79
"github.com/pkg/errors"
810
)
911

1012
type wsWrapper struct {
1113
*websocket.Conn
14+
writeMu sync.Mutex
1215
}
1316

1417
func (wsw *wsWrapper) Write(p []byte) (n int, err error) {
18+
wsw.writeMu.Lock()
19+
defer wsw.writeMu.Unlock()
20+
wsw.Conn.SetWriteDeadline(time.Now().Add(30 * time.Second))
1521
writer, err := wsw.Conn.NextWriter(websocket.TextMessage)
1622
if err != nil {
1723
return 0, err
@@ -20,6 +26,13 @@ func (wsw *wsWrapper) Write(p []byte) (n int, err error) {
2026
return writer.Write(p)
2127
}
2228

29+
func (wsw *wsWrapper) WritePing() error {
30+
wsw.writeMu.Lock()
31+
defer wsw.writeMu.Unlock()
32+
wsw.Conn.SetWriteDeadline(time.Now().Add(wsPingTimeout))
33+
return wsw.Conn.WriteMessage(websocket.PingMessage, nil)
34+
}
35+
2336
func (wsw *wsWrapper) Read(p []byte) (n int, err error) {
2437
for {
2538
msgType, reader, err := wsw.Conn.NextReader()

0 commit comments

Comments
 (0)