Skip to content

Commit

Permalink
Cancel inflight longpoll requests on close and clear buffer on transp…
Browse files Browse the repository at this point in the history
…ort replace
  • Loading branch information
chrismccord committed Jul 8, 2022
1 parent 4af8ac8 commit dcb8b64
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 11 deletions.
8 changes: 5 additions & 3 deletions assets/js/phoenix/ajax.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ export default class Ajax {
static request(method, endPoint, accept, body, timeout, ontimeout, callback){
if(global.XDomainRequest){
let req = new global.XDomainRequest() // IE8, IE9
this.xdomainRequest(req, method, endPoint, body, timeout, ontimeout, callback)
return this.xdomainRequest(req, method, endPoint, body, timeout, ontimeout, callback)
} else {
let req = new global.XMLHttpRequest() // IE7+, Firefox, Chrome, Opera, Safari
this.xhrRequest(req, method, endPoint, accept, body, timeout, ontimeout, callback)
return this.xhrRequest(req, method, endPoint, accept, body, timeout, ontimeout, callback)
}
}

Expand All @@ -28,13 +28,14 @@ export default class Ajax {
req.onprogress = () => { }

req.send(body)
return req
}

static xhrRequest(req, method, endPoint, accept, body, timeout, ontimeout, callback){
req.open(method, endPoint, true)
req.timeout = timeout
req.setRequestHeader("Content-Type", accept)
req.onerror = () => { callback && callback(null) }
req.onerror = () => callback && callback(null)
req.onreadystatechange = () => {
if(req.readyState === XHR_STATES.complete && callback){
let response = this.parseJSON(req.responseText)
Expand All @@ -44,6 +45,7 @@ export default class Ajax {
if(ontimeout){ req.ontimeout = ontimeout }

req.send(body)
return req
}

static parseJSON(resp){
Expand Down
27 changes: 20 additions & 7 deletions assets/js/phoenix/longpoll.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export default class LongPoll {
this.endPoint = null
this.token = null
this.skipHeartbeat = true
this.reqs = new Set()
this.onopen = function (){ } // noop
this.onerror = function (){ } // noop
this.onmessage = function (){ } // noop
Expand Down Expand Up @@ -41,10 +42,10 @@ export default class LongPoll {
this.closeAndRetry(1005, "timeout", false)
}

poll(){
if(!(this.readyState === SOCKET_STATES.open || this.readyState === SOCKET_STATES.connecting)){ return }
isActive(){ return this.readyState === SOCKET_STATES.open || this.readyState === SOCKET_STATES.connecting }

Ajax.request("GET", this.endpointURL(), "application/json", null, this.timeout, this.ontimeout.bind(this), (resp) => {
poll(){
this.ajax("GET", null, () => this.ontimeout(), resp => {
if(resp){
var {status, token, messages} = resp
this.token = token
Expand Down Expand Up @@ -73,9 +74,7 @@ export default class LongPoll {
//
// In order to emulate this behaviour, we need to make sure each
// onmessage handler is run within it's own macrotask.
setTimeout(() => {
this.onmessage({data: msg})
}, 0)
setTimeout(() => this.onmessage({data: msg}), 0)
})
this.poll()
break
Expand All @@ -102,7 +101,7 @@ export default class LongPoll {
}

send(body){
Ajax.request("POST", this.endpointURL(), "application/json", body, this.timeout, this.onerror.bind(this, "timeout"), (resp) => {
this.ajax("POST", body, () => this.onerror("timeout"), resp => {
if(!resp || resp.status !== 200){
this.onerror(resp && resp.status)
this.closeAndRetry(1011, "internal server error", false)
Expand All @@ -111,6 +110,7 @@ export default class LongPoll {
}

close(code, reason, wasClean){
for(let req of this.reqs){ req.abort() }
this.readyState = SOCKET_STATES.closed
let opts = Object.assign({code: 1000, reason: undefined, wasClean: true}, {code, reason, wasClean})
if(typeof(CloseEvent) !== "undefined"){
Expand All @@ -119,4 +119,17 @@ export default class LongPoll {
this.onclose(opts)
}
}

ajax(method, body, onCallerTimeout, callback){
let req
let ontimeout = () => {
this.reqs.delete(req)
onCallerTimeout()
}
req = Ajax.request(method, this.endpointURL(), "application/json", body, this.timeout, ontimeout, resp => {
this.reqs.delete(req)
if(this.isActive()){ callback(resp) }
})
this.reqs.add(req)
}
}
4 changes: 3 additions & 1 deletion assets/js/phoenix/socket.js
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ export default class Socket {
this.connectClock++
this.closeWasClean = true
this.reconnectTimer.reset()
this.sendBuffer = []
if(this.conn){
this.conn.close()
this.conn = null
Expand Down Expand Up @@ -212,12 +213,13 @@ export default class Socket {
* `new Socket("/socket", {params: {user_id: userToken}})`.
*/
connect(params){
this.connectClock++
if(params){
console && console.log("passing params to connect is deprecated. Instead pass :params to the Socket constructor")
this.params = closure(params)
}
if(this.conn){ return }

this.connectClock++
this.closeWasClean = false
this.conn = new this.transport(this.endPointURL())
this.conn.binaryType = this.binaryType
Expand Down

0 comments on commit dcb8b64

Please sign in to comment.