339 lines
8.9 KiB
JavaScript
339 lines
8.9 KiB
JavaScript
var WebSocketLibrary =
|
|
{
|
|
$webSocketManager:
|
|
{
|
|
/*
|
|
* Map of instances
|
|
*
|
|
* Instance structure:
|
|
* {
|
|
* url: string,
|
|
* ws: WebSocket,
|
|
* subProtocols: string[],
|
|
* }
|
|
*/
|
|
instances: {},
|
|
|
|
/* Last instance ID */
|
|
lastId: 0,
|
|
|
|
/* Event listeners */
|
|
onOpen: null,
|
|
onMessage: null,
|
|
onMessageStr: null,
|
|
onError: null,
|
|
onClose: null
|
|
},
|
|
|
|
/**
|
|
* Set onOpen callback
|
|
*
|
|
* @param callback Reference to C# static function
|
|
*/
|
|
WebSocketSetOnOpen: function(callback)
|
|
{
|
|
webSocketManager.onOpen = callback;
|
|
},
|
|
|
|
/**
|
|
* Set onMessage callback
|
|
*
|
|
* @param callback Reference to C# static function
|
|
*/
|
|
WebSocketSetOnMessage: function(callback)
|
|
{
|
|
webSocketManager.onMessage = callback;
|
|
},
|
|
|
|
/**
|
|
* Set onMessageStr callback
|
|
*
|
|
* @param callback Reference to C# static function
|
|
*/
|
|
WebSocketSetOnMessageStr: function(callback)
|
|
{
|
|
webSocketManager.onMessageStr = callback;
|
|
},
|
|
|
|
/**
|
|
* Set onError callback
|
|
*
|
|
* @param callback Reference to C# static function
|
|
*/
|
|
WebSocketSetOnError: function(callback)
|
|
{
|
|
webSocketManager.onError = callback;
|
|
},
|
|
|
|
/**
|
|
* Set onClose callback
|
|
*
|
|
* @param callback Reference to C# static function
|
|
*/
|
|
WebSocketSetOnClose: function(callback)
|
|
{
|
|
webSocketManager.onClose = callback;
|
|
},
|
|
|
|
/**
|
|
* Allocate new WebSocket instance struct
|
|
*
|
|
* @param url Server URL
|
|
*/
|
|
WebSocketAllocate: function(urlPtr)
|
|
{
|
|
var url = UTF8ToString(urlPtr);
|
|
var id = ++webSocketManager.lastId;
|
|
webSocketManager.instances[id] = {
|
|
url: url,
|
|
ws: null,
|
|
};
|
|
|
|
return id;
|
|
},
|
|
|
|
/**
|
|
* Add Sub Protocol
|
|
*
|
|
* @param instanceId Instance ID
|
|
* @param protocol Sub Protocol
|
|
*/
|
|
WebSocketAddSubProtocol: function(instanceId, protocolPtr)
|
|
{
|
|
var instance = webSocketManager.instances[instanceId];
|
|
if (!instance) return -1;
|
|
|
|
var protocol = UTF8ToString(protocolPtr);
|
|
|
|
if (instance.subProtocols == null)
|
|
instance.subProtocols = [];
|
|
|
|
instance.subProtocols.push(protocol);
|
|
|
|
return 0;
|
|
},
|
|
|
|
/**
|
|
* Remove reference to WebSocket instance
|
|
*
|
|
* If socket is not closed function will close it but onClose event will not be emitted because
|
|
* this function should be invoked by C# WebSocket destructor.
|
|
*
|
|
* @param instanceId Instance ID
|
|
*/
|
|
WebSocketFree: function(instanceId)
|
|
{
|
|
var instance = webSocketManager.instances[instanceId];
|
|
if (!instance) return 0;
|
|
|
|
// Close if not closed
|
|
if (instance.ws !== null && instance.ws.readyState < 2)
|
|
instance.ws.close();
|
|
|
|
// Remove reference
|
|
delete webSocketManager.instances[instanceId];
|
|
|
|
return 0;
|
|
},
|
|
|
|
/**
|
|
* Connect WebSocket to the server
|
|
*
|
|
* @param instanceId Instance ID
|
|
*/
|
|
WebSocketConnect: function(instanceId)
|
|
{
|
|
var instance = webSocketManager.instances[instanceId];
|
|
if (!instance) return -1;
|
|
if (instance.ws !== null) return -2;
|
|
|
|
if (instance.subProtocols != null)
|
|
instance.ws = new WebSocket(instance.url, instance.subProtocols);
|
|
else
|
|
instance.ws = new WebSocket(instance.url);
|
|
|
|
instance.ws.onopen = function()
|
|
{
|
|
Module.dynCall_vi(webSocketManager.onOpen, instanceId);
|
|
};
|
|
|
|
instance.ws.onmessage = function(ev)
|
|
{
|
|
if (ev.data instanceof ArrayBuffer)
|
|
{
|
|
var array = new Uint8Array(ev.data);
|
|
var buffer = _malloc(array.length);
|
|
writeArrayToMemory(array, buffer);
|
|
try
|
|
{
|
|
Module.dynCall_viii(webSocketManager.onMessage, instanceId, buffer, array.length);
|
|
}
|
|
finally
|
|
{
|
|
_free(buffer);
|
|
}
|
|
}
|
|
else if (typeof ev.data == 'string')
|
|
{
|
|
var length = lengthBytesUTF8(ev.data) + 1;
|
|
var buffer = _malloc(length);
|
|
stringToUTF8(ev.data, buffer, length);
|
|
try
|
|
{
|
|
Module.dynCall_vii(webSocketManager.onMessageStr, instanceId, buffer);
|
|
}
|
|
finally
|
|
{
|
|
_free(buffer);
|
|
}
|
|
}
|
|
else if (typeof Blob !== 'undefined' && ev.data instanceof Blob)
|
|
{
|
|
var reader = new FileReader();
|
|
reader.onload = function()
|
|
{
|
|
var array = new Uint8Array(reader.result);
|
|
var buffer = _malloc(array.length);
|
|
writeArrayToMemory(array, buffer);
|
|
try
|
|
{
|
|
Module.dynCall_viii(webSocketManager.onMessage, instanceId, buffer, array.length);
|
|
}
|
|
finally
|
|
{
|
|
reader = null;
|
|
_free(buffer);
|
|
}
|
|
};
|
|
reader.readAsArrayBuffer(ev.data);
|
|
}
|
|
else
|
|
{
|
|
console.log("[JSLIB WebSocket] not support message type: ", (typeof ev.data));
|
|
}
|
|
};
|
|
|
|
instance.ws.onerror = function(ev)
|
|
{
|
|
var msg = "WebSocket error.";
|
|
var length = lengthBytesUTF8(msg) + 1;
|
|
var buffer = _malloc(length);
|
|
stringToUTF8(msg, buffer, length);
|
|
try
|
|
{
|
|
Module.dynCall_vii(webSocketManager.onError, instanceId, buffer);
|
|
}
|
|
finally
|
|
{
|
|
_free(buffer);
|
|
}
|
|
};
|
|
|
|
instance.ws.onclose = function(ev)
|
|
{
|
|
var msg = ev.reason;
|
|
var length = lengthBytesUTF8(msg) + 1;
|
|
var buffer = _malloc(length);
|
|
stringToUTF8(msg, buffer, length);
|
|
try
|
|
{
|
|
Module.dynCall_viii(webSocketManager.onClose, instanceId, ev.code, buffer);
|
|
}
|
|
finally
|
|
{
|
|
_free(buffer);
|
|
}
|
|
instance.ws = null;
|
|
};
|
|
|
|
return 0;
|
|
},
|
|
|
|
/**
|
|
* Close WebSocket connection
|
|
*
|
|
* @param instanceId Instance ID
|
|
* @param code Close status code
|
|
* @param reasonPtr Pointer to reason string
|
|
*/
|
|
WebSocketClose: function(instanceId, code, reasonPtr)
|
|
{
|
|
var instance = webSocketManager.instances[instanceId];
|
|
if (!instance) return -1;
|
|
if (instance.ws === null) return -3;
|
|
if (instance.ws.readyState === 2) return -4;
|
|
if (instance.ws.readyState === 3) return -5;
|
|
|
|
var reason = ( reasonPtr ? UTF8ToString(reasonPtr) : undefined );
|
|
try
|
|
{
|
|
instance.ws.close(code, reason);
|
|
}
|
|
catch (err)
|
|
{
|
|
return -7;
|
|
}
|
|
|
|
return 0;
|
|
},
|
|
|
|
/**
|
|
* Send message over WebSocket
|
|
*
|
|
* @param instanceId Instance ID
|
|
* @param bufferPtr Pointer to the message buffer
|
|
* @param length Length of the message in the buffer
|
|
*/
|
|
WebSocketSend: function(instanceId, bufferPtr, length)
|
|
{
|
|
var instance = webSocketManager.instances[instanceId];
|
|
if (!instance) return -1;
|
|
if (instance.ws === null) return -3;
|
|
if (instance.ws.readyState !== 1) return -6;
|
|
|
|
if (typeof HEAPU8 !== 'undefined')
|
|
instance.ws.send(HEAPU8.buffer.slice(bufferPtr, bufferPtr + length));
|
|
else if (typeof buffer !== 'undefined')
|
|
instance.ws.send(buffer.slice(bufferPtr, bufferPtr + length));
|
|
else
|
|
return -8; // not support buffer slice
|
|
|
|
return 0;
|
|
},
|
|
|
|
/**
|
|
* Send message string over WebSocket
|
|
*
|
|
* @param instanceId Instance ID
|
|
* @param stringPtr Pointer to the message string
|
|
*/
|
|
WebSocketSendStr: function(instanceId, stringPtr)
|
|
{
|
|
var instance = webSocketManager.instances[instanceId];
|
|
if (!instance) return -1;
|
|
if (instance.ws === null) return -3;
|
|
if (instance.ws.readyState !== 1) return -6;
|
|
|
|
instance.ws.send(UTF8ToString(stringPtr));
|
|
|
|
return 0;
|
|
},
|
|
|
|
/**
|
|
* Return WebSocket readyState
|
|
*
|
|
* @param instanceId Instance ID
|
|
*/
|
|
WebSocketGetState: function(instanceId)
|
|
{
|
|
var instance = webSocketManager.instances[instanceId];
|
|
if (!instance) return -1;
|
|
if (instance.ws === null) return 3; // socket null as closed
|
|
|
|
return instance.ws.readyState;
|
|
}
|
|
};
|
|
|
|
autoAddDeps(WebSocketLibrary, '$webSocketManager');
|
|
mergeInto(LibraryManager.library, WebSocketLibrary);
|