@ -37186,211 +37186,6 @@ Internal.SessionLock.queueJobForNumber = function queueJobForNumber(number, runJ
loadProtoBufs ( 'DeviceMessages.proto' ) ;
} ) ( ) ;
/ *
* vim : ts = 4 : sw = 4 : expandtab
* /
; ( function ( ) {
'use strict' ;
/ *
* WebSocket - Resources
*
* Create a request - response interface over websockets using the
* WebSocket - Resources sub - protocol [ 1 ] .
*
* var client = new WebSocketResource ( socket , function ( request ) {
* request . respond ( 200 , 'OK' ) ;
* } ) ;
*
* client . sendRequest ( {
* verb : 'PUT' ,
* path : '/v1/messages' ,
* body : '{ some: "json" }' ,
* success : function ( message , status , request ) { ... } ,
* error : function ( message , status , request ) { ... }
* } ) ;
*
* 1. https : //github.com/WhisperSystems/WebSocket-Resources
*
* /
var Request = function ( options ) {
this . verb = options . verb || options . type ;
this . path = options . path || options . url ;
this . body = options . body || options . data ;
this . success = options . success ;
this . error = options . error ;
this . id = options . id ;
if ( this . id === undefined ) {
var bits = new Uint32Array ( 2 ) ;
window . crypto . getRandomValues ( bits ) ;
this . id = dcodeIO . Long . fromBits ( bits [ 0 ] , bits [ 1 ] , true ) ;
}
if ( this . body === undefined ) {
this . body = null ;
}
} ;
var IncomingWebSocketRequest = function ( options ) {
var request = new Request ( options ) ;
var socket = options . socket ;
this . verb = request . verb ;
this . path = request . path ;
this . body = request . body ;
this . respond = function ( status , message ) {
socket . send (
new textsecure . protobuf . WebSocketMessage ( {
type : textsecure . protobuf . WebSocketMessage . Type . RESPONSE ,
response : { id : request . id , message : message , status : status }
} ) . encode ( ) . toArrayBuffer ( )
) ;
} ;
} ;
var outgoing = { } ;
var OutgoingWebSocketRequest = function ( options , socket ) {
var request = new Request ( options ) ;
outgoing [ request . id ] = request ;
socket . send (
new textsecure . protobuf . WebSocketMessage ( {
type : textsecure . protobuf . WebSocketMessage . Type . REQUEST ,
request : {
verb : request . verb ,
path : request . path ,
body : request . body ,
id : request . id
}
} ) . encode ( ) . toArrayBuffer ( )
) ;
} ;
window . WebSocketResource = function ( socket , opts ) {
opts = opts || { } ;
var handleRequest = opts . handleRequest ;
if ( typeof handleRequest !== 'function' ) {
handleRequest = function ( request ) {
request . respond ( 404 , 'Not found' ) ;
} ;
}
this . sendRequest = function ( options ) {
return new OutgoingWebSocketRequest ( options , socket ) ;
} ;
socket . onmessage = function ( socketMessage ) {
var blob = socketMessage . data ;
var handleArrayBuffer = function ( buffer ) {
var message = textsecure . protobuf . WebSocketMessage . decode ( buffer ) ;
if ( message . type === textsecure . protobuf . WebSocketMessage . Type . REQUEST ) {
handleRequest (
new IncomingWebSocketRequest ( {
verb : message . request . verb ,
path : message . request . path ,
body : message . request . body ,
id : message . request . id ,
socket : socket
} )
) ;
}
else if ( message . type === textsecure . protobuf . WebSocketMessage . Type . RESPONSE ) {
var response = message . response ;
var request = outgoing [ response . id ] ;
if ( request ) {
request . response = response ;
var callback = request . error ;
if ( response . status >= 200 && response . status < 300 ) {
callback = request . success ;
}
if ( typeof callback === 'function' ) {
callback ( response . message , response . status , request ) ;
}
} else {
throw 'Received response for unknown request ' + message . response . id ;
}
}
} ;
if ( blob instanceof ArrayBuffer ) {
handleArrayBuffer ( blob ) ;
} else {
var reader = new FileReader ( ) ;
reader . onload = function ( ) {
handleArrayBuffer ( reader . result ) ;
} ;
reader . readAsArrayBuffer ( blob ) ;
}
} ;
if ( opts . keepalive ) {
var keepalive = new KeepAlive ( this , {
path : opts . keepalive . path ,
disconnect : opts . keepalive . disconnect
} ) ;
var resetKeepAliveTimer = keepalive . reset . bind ( keepalive ) ;
socket . addEventListener ( 'open' , resetKeepAliveTimer ) ;
socket . addEventListener ( 'message' , resetKeepAliveTimer ) ;
socket . addEventListener ( 'close' , keepalive . stop . bind ( keepalive ) ) ;
}
this . close = function ( code , reason ) {
if ( ! code ) { code = 3000 ; }
socket . close ( code , reason ) ;
} ;
} ;
function KeepAlive ( websocketResource , opts ) {
if ( websocketResource instanceof WebSocketResource ) {
opts = opts || { } ;
this . path = opts . path ;
if ( this . path === undefined ) {
this . path = '/' ;
}
this . disconnect = opts . disconnect ;
if ( this . disconnect === undefined ) {
this . disconnect = true ;
}
this . wsr = websocketResource ;
} else {
throw new TypeError ( 'KeepAlive expected a WebSocketResource' ) ;
}
}
KeepAlive . prototype = {
constructor : KeepAlive ,
stop : function ( ) {
clearTimeout ( this . keepAliveTimer ) ;
clearTimeout ( this . disconnectTimer ) ;
} ,
reset : function ( ) {
clearTimeout ( this . keepAliveTimer ) ;
clearTimeout ( this . disconnectTimer ) ;
this . keepAliveTimer = setTimeout ( function ( ) {
console . log ( 'Sending a keepalive message' ) ;
this . wsr . sendRequest ( {
verb : 'GET' ,
path : this . path ,
success : this . reset . bind ( this )
} ) ;
if ( this . disconnect ) {
// automatically disconnect if server doesn't ack
this . disconnectTimer = setTimeout ( function ( ) {
clearTimeout ( this . keepAliveTimer ) ;
this . wsr . close ( 3001 , 'No response to keepalive request' ) ;
} . bind ( this ) , 1000 ) ;
} else {
this . reset ( ) ;
}
} . bind ( this ) , 55000 ) ;
} ,
} ;
} ( ) ) ;
/ *
* vim : ts = 4 : sw = 4 : expandtab
* /
@ -38365,6 +38160,244 @@ var TextSecureServer = (function() {
} ( ) ) ;
/ *
* vim : ts = 4 : sw = 4 : expandtab
* /
; ( function ( ) {
'use strict' ;
/ *
* WebSocket - Resources
*
* Create a request - response interface over websockets using the
* WebSocket - Resources sub - protocol [ 1 ] .
*
* var client = new WebSocketResource ( socket , function ( request ) {
* request . respond ( 200 , 'OK' ) ;
* } ) ;
*
* client . sendRequest ( {
* verb : 'PUT' ,
* path : '/v1/messages' ,
* body : '{ some: "json" }' ,
* success : function ( message , status , request ) { ... } ,
* error : function ( message , status , request ) { ... }
* } ) ;
*
* 1. https : //github.com/WhisperSystems/WebSocket-Resources
*
* /
var Request = function ( options ) {
this . verb = options . verb || options . type ;
this . path = options . path || options . url ;
this . body = options . body || options . data ;
this . success = options . success ;
this . error = options . error ;
this . id = options . id ;
if ( this . id === undefined ) {
var bits = new Uint32Array ( 2 ) ;
window . crypto . getRandomValues ( bits ) ;
this . id = dcodeIO . Long . fromBits ( bits [ 0 ] , bits [ 1 ] , true ) ;
}
if ( this . body === undefined ) {
this . body = null ;
}
} ;
var IncomingWebSocketRequest = function ( options ) {
var request = new Request ( options ) ;
var socket = options . socket ;
this . verb = request . verb ;
this . path = request . path ;
this . body = request . body ;
this . respond = function ( status , message ) {
socket . send (
new textsecure . protobuf . WebSocketMessage ( {
type : textsecure . protobuf . WebSocketMessage . Type . RESPONSE ,
response : { id : request . id , message : message , status : status }
} ) . encode ( ) . toArrayBuffer ( )
) ;
} ;
} ;
var outgoing = { } ;
var OutgoingWebSocketRequest = function ( options , socket ) {
var request = new Request ( options ) ;
outgoing [ request . id ] = request ;
socket . send (
new textsecure . protobuf . WebSocketMessage ( {
type : textsecure . protobuf . WebSocketMessage . Type . REQUEST ,
request : {
verb : request . verb ,
path : request . path ,
body : request . body ,
id : request . id
}
} ) . encode ( ) . toArrayBuffer ( )
) ;
} ;
window . WebSocketResource = function ( socket , opts ) {
opts = opts || { } ;
var handleRequest = opts . handleRequest ;
if ( typeof handleRequest !== 'function' ) {
handleRequest = function ( request ) {
request . respond ( 404 , 'Not found' ) ;
} ;
}
this . sendRequest = function ( options ) {
return new OutgoingWebSocketRequest ( options , socket ) ;
} ;
socket . onmessage = function ( socketMessage ) {
var blob = socketMessage . data ;
var handleArrayBuffer = function ( buffer ) {
var message = textsecure . protobuf . WebSocketMessage . decode ( buffer ) ;
if ( message . type === textsecure . protobuf . WebSocketMessage . Type . REQUEST ) {
handleRequest (
new IncomingWebSocketRequest ( {
verb : message . request . verb ,
path : message . request . path ,
body : message . request . body ,
id : message . request . id ,
socket : socket
} )
) ;
}
else if ( message . type === textsecure . protobuf . WebSocketMessage . Type . RESPONSE ) {
var response = message . response ;
var request = outgoing [ response . id ] ;
if ( request ) {
request . response = response ;
var callback = request . error ;
if ( response . status >= 200 && response . status < 300 ) {
callback = request . success ;
}
if ( typeof callback === 'function' ) {
callback ( response . message , response . status , request ) ;
}
} else {
throw 'Received response for unknown request ' + message . response . id ;
}
}
} ;
if ( blob instanceof ArrayBuffer ) {
handleArrayBuffer ( blob ) ;
} else {
var reader = new FileReader ( ) ;
reader . onload = function ( ) {
handleArrayBuffer ( reader . result ) ;
} ;
reader . readAsArrayBuffer ( blob ) ;
}
} ;
if ( opts . keepalive ) {
this . keepalive = new KeepAlive ( this , {
path : opts . keepalive . path ,
disconnect : opts . keepalive . disconnect
} ) ;
var resetKeepAliveTimer = this . keepalive . reset . bind ( this . keepalive ) ;
socket . addEventListener ( 'open' , resetKeepAliveTimer ) ;
socket . addEventListener ( 'message' , resetKeepAliveTimer ) ;
socket . addEventListener ( 'close' , this . keepalive . stop . bind ( this . keepalive ) ) ;
}
socket . addEventListener ( 'close' , function ( ) {
this . closed = true ;
} . bind ( this ) )
this . close = function ( code , reason ) {
if ( this . closed ) {
return ;
}
console . log ( 'WebSocketResource.close()' ) ;
if ( ! code ) {
code = 3000 ;
}
if ( this . keepalive ) {
this . keepalive . stop ( ) ;
}
socket . close ( code , reason ) ;
socket . onmessage = null ;
// On linux the socket can wait a long time to emit its close event if we've
// lost the internet connection. On the order of minutes. This speeds that
// process up.
setTimeout ( function ( ) {
if ( this . closed ) {
return ;
}
this . closed = true ;
console . log ( 'Dispatching our own socket close event' ) ;
var ev = new Event ( 'close' ) ;
ev . code = code ;
ev . reason = reason ;
this . dispatchEvent ( ev ) ;
} . bind ( this ) , 10000 ) ;
} ;
} ;
window . WebSocketResource . prototype = new textsecure . EventTarget ( ) ;
function KeepAlive ( websocketResource , opts ) {
if ( websocketResource instanceof WebSocketResource ) {
opts = opts || { } ;
this . path = opts . path ;
if ( this . path === undefined ) {
this . path = '/' ;
}
this . disconnect = opts . disconnect ;
if ( this . disconnect === undefined ) {
this . disconnect = true ;
}
this . wsr = websocketResource ;
} else {
throw new TypeError ( 'KeepAlive expected a WebSocketResource' ) ;
}
}
KeepAlive . prototype = {
constructor : KeepAlive ,
stop : function ( ) {
clearTimeout ( this . keepAliveTimer ) ;
clearTimeout ( this . disconnectTimer ) ;
} ,
reset : function ( ) {
clearTimeout ( this . keepAliveTimer ) ;
clearTimeout ( this . disconnectTimer ) ;
this . keepAliveTimer = setTimeout ( function ( ) {
if ( this . disconnect ) {
// automatically disconnect if server doesn't ack
this . disconnectTimer = setTimeout ( function ( ) {
clearTimeout ( this . keepAliveTimer ) ;
this . wsr . close ( 3001 , 'No response to keepalive request' ) ;
} . bind ( this ) , 1000 ) ;
} else {
this . reset ( ) ;
}
console . log ( 'Sending a keepalive message' ) ;
this . wsr . sendRequest ( {
verb : 'GET' ,
path : this . path ,
success : this . reset . bind ( this )
} ) ;
} . bind ( this ) , 55000 ) ;
} ,
} ;
} ( ) ) ;
/ *
* vim : ts = 4 : sw = 4 : expandtab
* /
@ -38395,8 +38428,11 @@ MessageReceiver.prototype = new textsecure.EventTarget();
MessageReceiver . prototype . extend ( {
constructor : MessageReceiver ,
connect : function ( ) {
this . hasConnected = true ;
if ( this . socket && this . socket . readyState !== WebSocket . CLOSED ) {
this . socket . close ( ) ;
this . wsr . close ( ) ;
}
// initialize the socket and start listening for messages
this . socket = this . server . getMessageSocket ( ) ;
@ -38405,16 +38441,45 @@ MessageReceiver.prototype.extend({
this . socket . onopen = this . onopen . bind ( this ) ;
this . wsr = new WebSocketResource ( this . socket , {
handleRequest : this . handleRequest . bind ( this ) ,
keepalive : { path : '/v1/keepalive' , disconnect : true }
keepalive : {
path : '/v1/keepalive' ,
disconnect : true
}
} ) ;
// Because sometimes the socket doesn't properly emit its close event
this . _onClose = this . onclose . bind ( this )
this . wsr . addEventListener ( 'close' , this . _onClose ) ;
// Ensures that an immediate 'empty' event from the websocket will fire only after
// all cached envelopes are processed.
this . incoming = [ this . pending ] ;
} ,
shutdown : function ( ) {
if ( this . socket ) {
this . socket . onclose = null ;
this . socket . onerror = null ;
this . socket . onopen = null ;
this . socket = null ;
}
if ( this . wsr ) {
this . wsr . removeEventListener ( 'close' , this . _onClose ) ;
this . wsr = null ;
}
} ,
close : function ( ) {
console . log ( 'MessageReceiver.close()' ) ;
this . calledClose = true ;
this . socket . close ( 3000 , 'called close' ) ;
// Our WebSocketResource instance will close the socket and emit a 'close' event
// if the socket doesn't emit one quickly enough.
if ( this . wsr ) {
this . wsr . close ( 3000 , 'called close' ) ;
}
this . shutdown ( ) ;
return this . drain ( ) ;
} ,
onopen : function ( ) {
@ -38435,6 +38500,8 @@ MessageReceiver.prototype.extend({
this . calledClose
) ;
this . shutdown ( ) ;
if ( this . calledClose ) {
return ;
}
@ -38699,6 +38766,8 @@ MessageReceiver.prototype.extend({
getStatus : function ( ) {
if ( this . socket ) {
return this . socket . readyState ;
} else if ( this . hasConnected ) {
return WebSocket . CLOSED ;
} else {
return - 1 ;
}