@@ -17,6 +17,36 @@ export class PeerFetch {
17
17
// Requests are processed in FIFO order.
18
18
this . _nextTicketInLine = 0
19
19
this . _configureDataConnection ( )
20
+ this . _schedulePing ( )
21
+ }
22
+
23
+ /**
24
+ * Schedule periodic pings to keep the datachannel alive.
25
+ * Some routers and firewalls close open ports within seconds
26
+ * without data packets flowing through.
27
+ */
28
+ _schedulePing ( ) {
29
+ this . _keepAlive = setInterval (
30
+ async ( ) => {
31
+ // check if there are any pending requests
32
+ // no ping needed as long as there is traffic on the channel
33
+ if ( ! this . _pendingRequests ( ) ) {
34
+ // request top page
35
+ const request = {
36
+ url : 'ping'
37
+ }
38
+ await this . get ( request )
39
+ }
40
+ } ,
41
+ 1000 // every second
42
+ )
43
+ }
44
+
45
+ /**
46
+ * Stop keepalive pings.
47
+ */
48
+ _stopPing ( ) {
49
+ clearInterval ( this . _keepAlive )
20
50
}
21
51
22
52
/**
@@ -46,28 +76,48 @@ export class PeerFetch {
46
76
// Handle incoming data (messages only since this is the signal sender)
47
77
const peerFetch = this
48
78
this . _dataConnection . on ( 'data' , function ( data ) {
49
- console . debug ( 'Remote 11111 Peer Data message received (type %s): %s ' ,
50
- typeof ( data ) , data )
79
+ console . debug ( 'Remote Peer Data message received (type %s)' ,
80
+ typeof ( data ) , { data } )
51
81
// we expect data to be a response to a previously sent request message
52
- const response = data
53
82
const ticket = peerFetch . _nextTicketInLine
54
- console . debug ( peerFetch , peerFetch . _requestMap , ticket , response )
55
- // const blah = {
56
- // url: 'http://localhost:8778/?from=_dataConnection.on_data'
57
- // }
58
- // const msg = JSON.stringify(blah)
59
- // const dc = peerFetch._dataConnection
60
- // console.error('>>>>>>>>>>>>>>>>>> Sending msg', { dc, msg })
61
- // peerFetch._dataConnection.send(msg)
62
- // update request map entry with this response
83
+ console . debug ( peerFetch , peerFetch . _requestMap , ticket , data )
84
+ // update request-response map entry with this response
63
85
const pair = peerFetch . _requestMap . get ( ticket )
64
86
if ( pair ) {
65
- pair . response = response
87
+ if ( ! pair . response ) {
88
+ console . debug ( 'Processing response header' )
89
+ // this is the first data message from the responses
90
+ const header = peerFetch . jsonify ( data )
91
+ if ( header . status === 202 ) {
92
+ console . debug ( 'Received keepalive ping' )
93
+ // server accepted the request but still working
94
+ // ignore and keep waiting until result or timeout
95
+ } else {
96
+ console . debug ( 'Received web server final response header' )
97
+ // save header part of the response
98
+ // and wait for the p2p data messages with the content body
99
+ const receivedAll = false
100
+ pair . response = { header, receivedAll }
101
+ }
102
+ } else {
103
+ console . debug ( 'Processing response content' )
104
+ // response content body arrived
105
+ pair . response . content = data
106
+ // assume for now that all response content can fit
107
+ // in a single 64KB data message
108
+ pair . response . receivedAll = true
109
+ }
66
110
} else {
67
111
console . error ( 'No entry found in pending requestMap for ticket' ,
68
112
{ ticket } )
69
113
}
70
114
} )
115
+ this . _dataConnection . on ( 'open' , function ( ) {
116
+ peerFetch . _schedulePing ( )
117
+ } )
118
+ this . _dataConnection . on ( 'close' , function ( ) {
119
+ peerFetch . _stopPing ( )
120
+ } )
71
121
}
72
122
73
123
/**
@@ -133,11 +183,20 @@ export class PeerFetch {
133
183
const ticket = this . _nextTicketInLine
134
184
// check if there is a pending ticket
135
185
// and process it
136
- if ( this . _nextTicketInLine < this . _nextAvailableTicket ) {
186
+ if ( this . _pendingRequests ( ) ) {
137
187
this . _sendNextRequest ( ticket )
138
188
}
139
189
}
140
190
191
+ /**
192
+ * Check if there are any pending requests waiting in line.
193
+ */
194
+ _pendingRequests ( ) {
195
+ if ( this . _nextTicketInLine < this . _nextAvailableTicket ) {
196
+ return true
197
+ }
198
+ }
199
+
141
200
textDecode ( arrayBuffer ) {
142
201
let decodedString
143
202
if ( 'TextDecoder' in window ) {
@@ -154,8 +213,13 @@ export class PeerFetch {
154
213
return decodedString
155
214
}
156
215
157
- jsonify ( arrayBuffer ) {
158
- const decodedString = this . textDecode ( arrayBuffer )
216
+ jsonify ( data ) {
217
+ let decodedString
218
+ if ( typeof data === 'string' ) {
219
+ decodedString = data
220
+ } else {
221
+ decodedString = this . textDecode ( data )
222
+ }
159
223
const response = JSON . parse ( decodedString )
160
224
return response
161
225
}
@@ -167,18 +231,16 @@ export class PeerFetch {
167
231
let request , response
168
232
do {
169
233
( { request, response } = this . _requestMap . get ( ticket ) )
170
- if ( response ) {
234
+ if ( response && response . receivedAll ) {
171
235
// if (typeof(response) === 'string') {
172
236
this . _ticketProcessed ( ticket )
173
237
console . debug ( 'Received response' , { ticket, request, response } )
174
238
// schedule processing of next request shortly
175
239
setTimeout ( ( ) => this . _processNextTicketInLine ( ) , 50 )
176
240
return response
177
- } else {
178
- console . debug ( 'Waiting for response' , { ticket, request } )
179
- // this._processNextTicketInLine()
180
241
}
181
242
timeElapsed = Date . now ( ) - timerStart
243
+ console . debug ( 'Waiting for response' , { ticket, request, timeElapsed } )
182
244
await sleep ( 3000 )
183
245
} while ( ! response && timeElapsed < timeout )
184
246
throw Error ( 'PeerFetch Timeout while waiting for response.' )
0 commit comments