Create websockets module

This commit is contained in:
David Cormier 2014-02-08 10:46:58 -05:00
parent 4f6d8d12e0
commit d4a4f1bd7f
4 changed files with 193 additions and 96 deletions

View file

@ -23,6 +23,7 @@
<script type="text/javascript" src="js/weechat.js"></script> <script type="text/javascript" src="js/weechat.js"></script>
<script type="text/javascript" src="js/irc-utils.js"></script> <script type="text/javascript" src="js/irc-utils.js"></script>
<script type="text/javascript" src="js/glowingbear.js"></script> <script type="text/javascript" src="js/glowingbear.js"></script>
<script type="text/javascript" src="js/websockets.js"></script>
<script type="text/javascript" src="js/models.js"></script> <script type="text/javascript" src="js/models.js"></script>
<script type="text/javascript" src="js/plugins.js"></script> <script type="text/javascript" src="js/plugins.js"></script>
<script type="text/javascript" src="3rdparty/bindonce.min.js"></script> <script type="text/javascript" src="3rdparty/bindonce.min.js"></script>

View file

@ -1,4 +1,4 @@
var weechat = angular.module('weechat', ['ngRoute', 'localStorage', 'weechatModels', 'plugins', 'ngSanitize', 'pasvaz.bindonce']); var weechat = angular.module('weechat', ['ngRoute', 'localStorage', 'weechatModels', 'plugins', 'ngSanitize', 'ngWebsockets', 'pasvaz.bindonce']);
weechat.filter('toArray', function () { weechat.filter('toArray', function () {
'use strict'; 'use strict';
@ -176,6 +176,14 @@ weechat.factory('handlers', ['$rootScope', 'models', 'plugins', function($rootSc
_nicklist_diff: handleNicklistDiff _nicklist_diff: handleNicklistDiff
}; };
$rootScope.$on('onMessage', function(event, message) {
if (_.has(eventHandlers, message.id)) {
eventHandlers[message.id](message);
}
});
var handleEvent = function(event) { var handleEvent = function(event) {
if (_.has(eventHandlers, event.id)) { if (_.has(eventHandlers, event.id)) {
eventHandlers[event.id](event); eventHandlers[event.id](event);
@ -191,101 +199,25 @@ weechat.factory('handlers', ['$rootScope', 'models', 'plugins', function($rootSc
}]); }]);
weechat.factory('connection', ['$q', '$rootScope', '$log', '$store', 'handlers', 'models', function($q, $rootScope, $log, storage, handlers, models) { weechat.factory('connection', ['$q', '$rootScope', '$log', '$store', 'handlers', 'models', 'conn', function($q, $rootScope, $log, storage, handlers, models, conn) {
protocol = new weeChat.Protocol(); protocol = new weeChat.Protocol();
var websocket = null;
var callbacks = {};
var currentCallBackId = 0;
/*
* Returns the current callback id
*/
var getCurrentCallBackId = function() {
currentCallBackId += 1;
if (currentCallBackId > 1000) {
currentCallBackId = 0;
}
return currentCallBackId;
};
/*
* Create a callback, adds it to the callback list
* and return it.
*/
var createCallback = function() {
var defer = $q.defer();
var cbId = getCurrentCallBackId();
callbacks[cbId] = {
time: new Date(),
cb: defer
};
defer.id = cbId;
return defer;
};
/*
* Fails every currently subscribed callback for the
* given reason
*
* @param reason reason for failure
*/
failCallbacks = function(reason) {
for (var i in callbacks) {
callbacks[i].cb.reject(reason);
}
};
/* Send a message to the websocket and returns a promise.
* See: http://docs.angularjs.org/api/ng.$q
*
* @param message message to send
* @returns a promise
*/
var send = function(message) {
message.replace(/[\r\n]+$/g, "").split("\n");
var cb = createCallback(message);
websocket.send("(" + cb.id + ") " + message);
return cb.promise;
};
/*
* Send all messages to the websocket and returns a promise that is resolved
* when all message are resolved.
*
* @param messages list of messages
* @returns a promise
*/
var sendAll = function(messages) {
var promises = [];
for (var i in messages) {
var promise = send(messages[i]);
promises.push(promise);
}
return $q.all(promises);
};
// Takes care of the connection and websocket hooks // Takes care of the connection and websocket hooks
var connect = function (host, port, passwd, ssl, noCompression) { var connect = function (host, port, passwd, ssl, noCompression) {
var proto = ssl ? 'wss' : 'ws'; var proto = ssl ? 'wss' : 'ws';
websocket = new WebSocket(proto + "://" + host + ':' + port + "/weechat"); var url = proto + "://" + host + ":" + port + "/weechat";
websocket.binaryType = "arraybuffer"; var binaryType = "arraybuffer";
websocket.onopen = function () { var onopen = function () {
$log.info("Connected to relay"); $log.info("Connected to relay");
// First command asks for the password and issues // First command asks for the password and issues
// a version command. If it fails, it means the we // a version command. If it fails, it means the we
// did not provide the proper password. // did not provide the proper password.
sendAll([ conn.sendAll([
weeChat.Protocol.formatInit({ weeChat.Protocol.formatInit({
password: passwd, password: passwd,
compression: noCompression ? 'off' : 'zlib' compression: noCompression ? 'off' : 'zlib'
@ -301,7 +233,7 @@ weechat.factory('connection', ['$q', '$rootScope', '$log', '$store', 'handlers',
} }
); );
send( conn.send(
weeChat.Protocol.formatHdata({ weeChat.Protocol.formatHdata({
path: 'buffer:gui_buffers(*)', path: 'buffer:gui_buffers(*)',
keys: ['local_variables,notify,number,full_name,short_name,title'] keys: ['local_variables,notify,number,full_name,short_name,title']
@ -321,7 +253,7 @@ weechat.factory('connection', ['$q', '$rootScope', '$log', '$store', 'handlers',
// Send all the other commands required for initialization // Send all the other commands required for initialization
send( conn.send(
weeChat.Protocol.formatHdata({ weeChat.Protocol.formatHdata({
path: "buffer:gui_buffers(*)/own_lines/last_line(-"+storage.get('lines')+")/data", path: "buffer:gui_buffers(*)/own_lines/last_line(-"+storage.get('lines')+")/data",
keys: [] keys: []
@ -330,7 +262,7 @@ weechat.factory('connection', ['$q', '$rootScope', '$log', '$store', 'handlers',
handlers.handleLineInfo(lineinfo); handlers.handleLineInfo(lineinfo);
}); });
send( conn.send(
weeChat.Protocol.formatHdata({ weeChat.Protocol.formatHdata({
path: "hotlist:gui_hotlist(*)", path: "hotlist:gui_hotlist(*)",
keys: [] keys: []
@ -340,14 +272,14 @@ weechat.factory('connection', ['$q', '$rootScope', '$log', '$store', 'handlers',
}); });
send( conn.send(
weeChat.Protocol.formatNicklist({ weeChat.Protocol.formatNicklist({
}) })
).then(function(nicklist) { ).then(function(nicklist) {
handlers.handleNicklist(nicklist); handlers.handleNicklist(nicklist);
}); });
send( conn.send(
weeChat.Protocol.formatSync({}) weeChat.Protocol.formatSync({})
); );
@ -355,14 +287,16 @@ weechat.factory('connection', ['$q', '$rootScope', '$log', '$store', 'handlers',
}; };
websocket.onclose = function () {
var onclose = function () {
$log.info("Disconnected from relay"); $log.info("Disconnected from relay");
$rootScope.connected = false; $rootScope.connected = false;
failCallbacks('disconnection'); failCallbacks('disconnection');
$rootScope.$apply(); $rootScope.$apply();
}; };
websocket.onmessage = function (evt) { var onmessage = function (evt) {
message = protocol.parse(evt.data); message = protocol.parse(evt.data);
if (_.has(callbacks, message.id)) { if (_.has(callbacks, message.id)) {
var promise = callbacks[message.id]; var promise = callbacks[message.id];
@ -375,23 +309,36 @@ weechat.factory('connection', ['$q', '$rootScope', '$log', '$store', 'handlers',
$rootScope.$apply(); $rootScope.$apply();
}; };
websocket.onerror = function (evt) { var onerror = function (evt) {
// on error it means the connection problem // on error it means the connection problem
// come from the relay not from the password. // come from the relay not from the password.
if (evt.type === "error" && websocket.readyState !== 1) { if (evt.type === "error" && this.readyState !== 1) {
failCallbacks('error'); failCallbacks('error');
$rootScope.errorMessage = true; $rootScope.errorMessage = true;
} }
$log.error("Relay error " + evt.data); $log.error("Relay error " + evt.data);
}; };
this.websocket = websocket; protocol.setId = function(id, message) {
return '(' + id + ') ' + message;
}
conn.connect(url,
protocol,
{
'binaryType': "arraybuffer",
'onopen': onopen,
'onclose': onclose,
'onmessage': onmessage,
'onerror': onerror,
})
}; };
var disconnect = function() { var disconnect = function() {
/* TODO: Send protocol disconnect */ /* TODO: Send protocol disconnect */
this.websocket.close(); conn.disconnect();
}; };
/* /*
@ -400,14 +347,14 @@ weechat.factory('connection', ['$q', '$rootScope', '$log', '$store', 'handlers',
* @returns the angular promise * @returns the angular promise
*/ */
var sendMessage = function(message) { var sendMessage = function(message) {
return send(weeChat.Protocol.formatInput({ conn.send(weeChat.Protocol.formatInput({
buffer: models.getActiveBuffer().fullName, buffer: models.getActiveBuffer().fullName,
data: message data: message
})); }));
}; };
var sendCoreCommand = function(command) { var sendCoreCommand = function(command) {
send(weeChat.Protocol.formatInput({ conn.send(weeChat.Protocol.formatInput({
buffer: 'core.weechat', buffer: 'core.weechat',
data: command data: command
})); }));
@ -415,7 +362,7 @@ weechat.factory('connection', ['$q', '$rootScope', '$log', '$store', 'handlers',
return { return {
send: send, // send: send,
connect: connect, connect: connect,
disconnect: disconnect, disconnect: disconnect,
sendMessage: sendMessage, sendMessage: sendMessage,

137
js/websockets.js Normal file
View file

@ -0,0 +1,137 @@
var websockets = angular.module('ngWebsockets', []);
websockets.factory('conn',
['$rootScope','$q',
function($rootScope, $q) {
var ws = null;
this.protocol = null;
var callbacks = {};
var currentCallBackId = 0;
/*
* Fails every currently subscribed callback for the
* given reason
*
* @param reason reason for failure
*/
failCallbacks = function(reason) {
for (var i in callbacks) {
callbacks[i].cb.reject(reason);
}
};
/*
* Returns the current callback id
*/
var getCurrentCallBackId = function() {
currentCallBackId += 1;
if (currentCallBackId > 1000) {
currentCallBackId = 0;
}
return currentCallBackId;
};
/* Send a message to the websocket and returns a promise.
* See: http://docs.angularjs.org/api/ng.$q
*
* @param message message to send
* @returns a promise
*/
var send = function(message) {
var cb = createCallback(message);
message = protocol.setId(cb.id,
message);
ws.send(message);
return cb.promise;
};
/*
* Create a callback, adds it to the callback list
* and return it.
*/
var createCallback = function() {
var defer = $q.defer();
var cbId = getCurrentCallBackId();
callbacks[cbId] = {
time: new Date(),
cb: defer
};
defer.id = cbId;
return defer;
};
/*
* Send all messages to the websocket and returns a promise that is resolved
* when all message are resolved.
*
* @param messages list of messages
* @returns a promise
*/
var sendAll = function(messages) {
var promises = [];
for (var i in messages) {
var promise = send(messages[i]);
promises.push(promise);
}
return $q.all(promises);
};
var onmessage = function (evt) {
/*
* Receives a message on the websocket
*/
var message = protocol.parse(evt.data)
if (_.has(callbacks, message.id)) {
// see if it's bound to one of the callbacks
var promise = callbacks[message.id];
promise.cb.resolve(message)
delete(callbacks[message.id]);
} else {
// otherwise emit it
$rootScope.$emit('onMessage', message)
//handlers.handleEvent(message);
}
$rootScope.commands.push("RECV: " + evt.data + " TYPE:" + evt.type);
$rootScope.$apply();
}
var connect = function(url,
protocol,
properties) {
ws = new WebSocket(url);
protocol = protocol;
for (var property in properties) {
ws[property] = properties[property];
}
ws.onmessage = onmessage;
}
var disconnect = function() {
ws.close();
}
return {
send: send,
sendAll: sendAll,
connect: connect,
disconnect: disconnect
}
}]);

View file

@ -596,6 +596,16 @@
return defaults; return defaults;
}; };
/**
* Add the ID to the previously formatted command
*
* @param id Command ID
* @param command previously formatted command
*/
WeeChatProtocol.setId = function(id, command) {
return '(' + id + ') ' + command;
}
/** /**
* Formats a command. * Formats a command.
* *
@ -614,6 +624,8 @@
cmd = parts.join(' '); cmd = parts.join(' ');
cmd += '\n'; cmd += '\n';
cmd.replace(/[\r\n]+$/g, "").split("\n");
return cmd; return cmd;
}; };