@@ -25,15 +25,18 @@ import (
25
25
"os"
26
26
"strings"
27
27
"sync"
28
+ "time"
28
29
29
30
mapset "github.com/deckarep/golang-set"
30
31
"github.com/ethereum/go-ethereum/log"
31
32
"github.com/gorilla/websocket"
32
33
)
33
34
34
35
const (
35
- wsReadBuffer = 1024
36
- wsWriteBuffer = 1024
36
+ wsReadBuffer = 1024
37
+ wsWriteBuffer = 1024
38
+ wsPingInterval = 60 * time .Second
39
+ wsPingWriteTimeout = 5 * time .Second
37
40
)
38
41
39
42
var wsBufferPool = new (sync.Pool )
@@ -168,7 +171,64 @@ func wsClientHeaders(endpoint, origin string) (string, http.Header, error) {
168
171
return endpointURL .String (), header , nil
169
172
}
170
173
174
+ type websocketCodec struct {
175
+ * jsonCodec
176
+ conn * websocket.Conn
177
+
178
+ wg sync.WaitGroup
179
+ pingReset chan struct {}
180
+ }
181
+
171
182
func newWebsocketCodec (conn * websocket.Conn ) ServerCodec {
172
183
conn .SetReadLimit (maxRequestContentLength )
173
- return NewFuncCodec (conn , conn .WriteJSON , conn .ReadJSON )
184
+ wc := & websocketCodec {
185
+ jsonCodec : NewFuncCodec (conn , conn .WriteJSON , conn .ReadJSON ).(* jsonCodec ),
186
+ conn : conn ,
187
+ pingReset : make (chan struct {}, 1 ),
188
+ }
189
+ wc .wg .Add (1 )
190
+ go wc .pingLoop ()
191
+ return wc
192
+ }
193
+
194
+ func (wc * websocketCodec ) close () {
195
+ wc .jsonCodec .close ()
196
+ wc .wg .Wait ()
197
+ }
198
+
199
+ func (wc * websocketCodec ) writeJSON (ctx context.Context , v interface {}) error {
200
+ err := wc .jsonCodec .writeJSON (ctx , v )
201
+ if err == nil {
202
+ // Notify pingLoop to delay the next idle ping.
203
+ select {
204
+ case wc .pingReset <- struct {}{}:
205
+ default :
206
+ }
207
+ }
208
+ return err
209
+ }
210
+
211
+ // pingLoop sends periodic ping frames when the connection is idle.
212
+ func (wc * websocketCodec ) pingLoop () {
213
+ var timer = time .NewTimer (wsPingInterval )
214
+ defer wc .wg .Done ()
215
+ defer timer .Stop ()
216
+
217
+ for {
218
+ select {
219
+ case <- wc .closed ():
220
+ return
221
+ case <- wc .pingReset :
222
+ if ! timer .Stop () {
223
+ <- timer .C
224
+ }
225
+ timer .Reset (wsPingInterval )
226
+ case <- timer .C :
227
+ wc .jsonCodec .encMu .Lock ()
228
+ wc .conn .SetWriteDeadline (time .Now ().Add (wsPingWriteTimeout ))
229
+ wc .conn .WriteMessage (websocket .PingMessage , nil )
230
+ wc .jsonCodec .encMu .Unlock ()
231
+ timer .Reset (wsPingInterval )
232
+ }
233
+ }
174
234
}
0 commit comments