2016-08-02 00:49:34 -07:00
// Communicate with the Scratch Device Manager through Socket.IO
window . ScratchDeviceManager = new ( function ( ) {
2016-10-07 12:09:17 -07:00
var instance = this ;
var sockets = [ ] ;
// Assume it's OK until we find out otherwise
var isConnected = true ;
2016-08-02 00:49:34 -07:00
// device-manager.scratch.mit.edu = 127.0.0.1
2016-10-07 12:09:17 -07:00
instance . deviceManagerHost = 'https://device-manager.scratch.mit.edu:3030' ;
2016-08-02 00:49:34 -07:00
// work around https://github.com/socketio/socket.io-client/issues/812
function connectNamespace ( namespace ) {
2016-10-07 12:09:17 -07:00
return io ( instance . deviceManagerHost + namespace , { forceNew : true } ) ;
}
function onClose ( ) {
for ( var i = 0 ; i < sockets . length ; i ++ ) {
sockets [ i ] . disconnect ( ) ;
}
2016-08-02 00:49:34 -07:00
}
2016-10-07 12:09:17 -07:00
window . onbeforeunload = onClose ;
instance . device _list = function ( ext _type , ext _name , device _spec , callback ) {
var url = instance . deviceManagerHost + '/' + ext _type + '/list' ;
var data = {
name : ext _name ,
spec : device _spec
} ;
$ . ajax ( url , {
data : { data : JSON . stringify ( data ) } ,
dataType : 'json' ,
2016-08-02 00:49:34 -07:00
success : function ( data , textStatus , jqXHR ) {
2016-10-07 12:09:17 -07:00
isConnected = true ;
if ( data . constructor == Array ) {
callback ( data , ext _type , ext _name ) ;
2016-08-02 00:49:34 -07:00
}
2016-10-07 12:09:17 -07:00
} ,
error : function ( jqXHR , textStatus , errorThrown ) {
isConnected = false ;
2016-08-02 00:49:34 -07:00
}
} ) ;
} ;
2016-10-07 12:09:17 -07:00
// Attempt to open a device-specific socket connection to the Device Manager.
// This must call `callback` exactly once no matter what.
// The callback will receive a connected socket on success or `null` on failure.
instance . socket _open = function ( ext _name , deviceType , deviceId , callback ) {
function onDeviceWasOpened ( ) {
// If this is the first event on this socket then respond with success.
if ( clearOpenTimeout ( ) ) {
callback ( socket ) ;
}
}
2016-08-02 00:49:34 -07:00
2016-10-07 12:09:17 -07:00
function onDisconnect ( ) {
var socketIndex = sockets . indexOf ( socket ) ;
if ( socketIndex >= 0 ) {
sockets . splice ( socketIndex , 1 ) ;
}
// If this is the first event on this socket then respond with failure.
if ( clearOpenTimeout ( ) ) {
callback ( null ) ;
}
}
2016-08-02 00:49:34 -07:00
2016-10-07 12:09:17 -07:00
function onTimeout ( ) {
// This will trigger `onDisconnect()`
socket . disconnect ( ) ;
}
2016-08-02 00:49:34 -07:00
2016-10-07 12:09:17 -07:00
// If the timeout is still pending, clear it and return true. Otherwise, return false.
// Callers can use the return value to determine whether they are the first to respond on this socket.
function clearOpenTimeout ( ) {
if ( openTimeout !== null ) {
clearTimeout ( openTimeout ) ;
openTimeout = null ;
return true ;
2016-08-02 00:49:34 -07:00
}
2016-10-07 12:09:17 -07:00
else {
return false ;
2016-08-02 00:49:34 -07:00
}
}
2016-10-07 12:09:17 -07:00
var socket = connectNamespace ( '/' + deviceType ) ;
sockets . push ( socket ) ;
2016-08-02 00:49:34 -07:00
2016-10-07 12:09:17 -07:00
socket . on ( 'deviceWasOpened' , onDeviceWasOpened ) ;
socket . on ( 'disconnect' , onDisconnect ) ;
var openTimeout = setTimeout ( onTimeout , 10 * 1000 ) ;
socket . emit ( 'open' , { deviceId : deviceId , name : ext _name } ) ;
} ;
instance . isConnected = function ( ) {
return isConnected ;
} ;
2016-08-02 00:49:34 -07:00
} ) ( ) ;