demo/3d_demo/resources/src/js/gos_ws_data_api.js

/**
*
*/
var GosWsDataApi = function () {
// Exported module
var lib = {}
/** -----------------------------
* Private variables
*/
var ws = WebsocketMsgPack()
var STATUS_CODE = {
SUCCESS: 1,
ERROR: 2,
NOT_LISTENING_FOR_STREAM: 3,
MISSING_REQUIRED_FIELD: 4,
UNKNOWN_METHOD: 5,
NO_ROOM: 6
}
var streams = {}
var nextRequestId = 0
var pendingRequests = {}
var logger = Logger('[WSAPI] ')
/** -----------------------------
* Public variables
*/
lib.onConnected = null
lib.onDisconnected = null
/** -----------------------------
* Public methods
*/
/**
* Return if the connection is opened
*/
lib.isConnected = function() {
return ws.isConnected()
}
/**
* Return if the connection is attempting to be opened
*/
lib.isConnecting = function() {
return ws.isConnecting()
}
/**
* Open connection
*/
lib.open = function(host) {
if(!ws.isConnected()) {
logger.info('Opening connection to ' + host + ' ...')
ws.open(host + '/appdata')
}
}
/**
* Close connection
*/
lib.close = function() {
logger.info('Closing connection ...')
ws.close()
}
/**
* Register stream handler
*/
lib.register = function(name, handler) {
logger.info('Registering stream: ' + name)
if(!handler) {
throw new Error('Null stream handler provided')
}
streams[name] = handler
}
/**
* Unregister stream handler
*/
lib.unregister = function(name) {
if(name in streams) {
logger.info('Unregistering stream: ' + name)
delete streams[name]
}
}
/**
* List the streams for which the device is listening
*/
lib.list = function(handler, timeout) {
logger.debug('Listing device streams ...')
sendMessage('list', null, null, handler, timeout)
}
/**
* Read stream data from device
*/
lib.read = function(name, handler, timeout) {
sendMessage('get', name, null, handler, timeout)
}
/**
* Write stream data to device
*/
lib.write = function(name, data, handler, timeout) {
if(!handler) {
handler = function(){}
}
if(timeout === undefined || timeout === null) {
timeout = 0
}
sendMessage('put', name, data, handler, timeout)
}
/**
* Set the websocket reconnect period in milliseconds
*/
lib.setReconnectPeriod = function(periodMs) {
ws.reconnectPeriod = periodMs
}
/**
* Set the logger
*/
lib.setLogger = function(l) {
logger.setLogger(l)
}
/**
* Set the logger
*/
lib.setMsgpackLogger = function(l) {
ws.setLogger(l)
}
/** -----------------------------
* Private methods
*/
/**
*
*/
var sendMessage = function(method, stream, data, handler, timeout) {
if(timeout === undefined || timeout === null) {
timeout = 7000
}
var request = {
id: getNextRequestId(),
method: method
}
if(stream) {
request.stream = stream
}
if(data) {
request.data = data
}
if(timeout) {
request.acknowledge = true
}
logger.debug('TX request: ' + JSON.stringify(request))
try {
ws.send(request)
if(timeout) {
addPendingRequest(request, handler, timeout)
} else {
handler(request.method)
}
} catch(e) {
handler(false, new Error('Failed to send request, err: ' + e.message))
}
}
/**
*
*/
var getNextRequestId = function() {
var retval = nextRequestId
nextRequestId++
return retval
}
/**
*
*/
var addPendingRequest = function(request, handler, timeout) {
var onPendingRequestTimeout = function() {
popPendingRequest(request.id)
handler(false, new Error('Timed-out waiting for response from device'))
}
request.timer = setTimeout(onPendingRequestTimeout, timeout)
request.handler = handler
pendingRequests[request.id] = request
}
/**
*
*/
var popPendingRequest = function(msgId) {
var request = null
if(msgId in pendingRequests) {
request = pendingRequests[msgId]
delete pendingRequests[msgId]
if(request.timer) {
clearTimeout(request.timer)
request.timer = null
}
}
return request
}
/**
*
*/
var returnResponse = function(msgId, status, data) {
var response = {
id: msgId,
status: status
}
if(data) {
response.data = data
}
try {
ws.send(response)
} catch(e) {
logger.warn('Failed to return response, err:' + e.message)
}
}
/**
*
*/
ws.onMessage = function(msg) {
if(msg.status) {
request = popPendingRequest(msg.id)
if(request) {
if(msg.status === STATUS_CODE.SUCCESS) {
request.handler(request.method, msg.data)
} else {
var msg
if(msg.status === STATUS_CODE.ERROR) {
msg = 'Device error while processing request'
} else if(msg.status === STATUS_CODE.NOT_LISTENING_FOR_STREAM) {
msg = 'Device not listening for stream: ' + request.stream
} else if(msg.status === STATUS_CODE.MISSING_REQUIRED_FIELD) {
msg = 'Request is missing required fields'
} else if(msg.status === STATUS_CODE.UNKNOWN_METHOD) {
msg = 'Request has unknown method'
} else if(msg.status === STATUS_CODE.NO_ROOM) {
msg = 'Not enough room to handle request'
} else {
msg = 'Unknown error while processing request'
}
request.handler(false, new Error(msg))
}
} else {
logger.debug('No pending request found for received response')
}
} else {
if(!msg.method) {
returnResponse(msg.id, STATUS_CODE.MISSING_REQUIRED_FIELD)
} else if(msg.method === 'list') {
returnResponse(msg.id, STATUS_CODE.SUCCESS, Object.keys(streams))
} else if(!msg.stream) {
returnResponse(msg.id, STATUS_CODE.MISSING_REQUIRED_FIELD)
} else if(!(msg.stream in streams)) {
returnResponse(msg.id, STATUS_CODE.NOT_LISTENING_FOR_STREAM)
} else {
var writeData = null
var streamHandler = streams[msg.stream]
if(msg.method === 'put') {
writeData = msg.data
if(writeData === undefined || writeData === null) {
returnResponse(msg.id, STATUS_CODE.MISSING_REQUIRED_FIELD)
return
}
if(msg.acknowledge) {
returnResponse(msg.id, STATUS_CODE.SUCCESS)
}
}
var responseData = null
try{
responseData = streamHandler(msg.stream, msg.method, writeData)
} catch(e) {
logger.warn('Uncaught error while processing stream request, err: ' + e.message)
}
if(msg.method === 'get') {
if(!responseData) {
returnResponse(msg.id, STATUS_CODE.ERROR)
} else {
returnResponse(msg.id, STATUS_CODE.SUCCESS, responseData)
}
}
}
}
}
/**
*
*/
ws.onConnected = function() {
logger.info('Connected')
if(lib.onConnected) {
lib.onConnected()
}
}
/**
*
*/
ws.onDisconnected = function() {
logger.info('Disconnected')
while(Object.keys(pendingRequests).length > 0) {
var msgId = Object.keys(pendingRequests)[0]
var request = popPendingRequest(msgId)
request.handler(false, new Error('Connection closed, dropping request'))
}
if(lib.onDisconnected) {
lib.onDisconnected()
}
}
return lib
}