Place to store the code and config used for the next-Iterations live event. https://iterations.space/live/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

481 lines
15 KiB

_kiwi.model.Gateway = Backbone.Model.extend({
initialize: function () {
// For ease of access. The socket.io object
this.socket = this.get('socket');
// Used to check if a disconnection was unplanned
this.disconnect_requested = false;
},
reconnect: function (callback) {
this.disconnect_requested = true;
this.socket.close();
this.socket = null;
this.connect(callback);
},
/**
* Connects to the server
* @param {Function} callback A callback function to be invoked once Kiwi's server has connected to the IRC server
*/
connect: function (callback) {
var that = this;
this.connect_callback = callback;
this.socket = new EngineioTools.ReconnectingSocket(this.get('kiwi_server'), {
transports: _kiwi.app.server_settings.transports || ['polling', 'websocket'],
path: _kiwi.app.get('base_path') + '/transport',
reconnect_max_attempts: 5,
reconnect_delay: 2000
});
// If we have an existing RPC object, clean it up before replacing it
if (this.rpc) {
rpc.dispose();
}
this.rpc = new EngineioTools.Rpc(this.socket);
this.socket.on('connect_failed', function (reason) {
this.socket.disconnect();
this.trigger("connect_fail", {reason: reason});
});
this.socket.on('error', function (e) {
console.log("_kiwi.gateway.socket.on('error')", {reason: e});
if (that.connect_callback) {
that.connect_callback(e);
delete that.connect_callback;
}
that.trigger("connect_fail", {reason: e});
});
this.socket.on('connecting', function (transport_type) {
console.log("_kiwi.gateway.socket.on('connecting')");
that.trigger("connecting");
});
/**
* Once connected to the kiwi server send the IRC connect command along
* with the IRC server details.
* A `connect` event is sent from the kiwi server once connected to the
* IRCD and the nick has been accepted.
*/
this.socket.on('open', function () {
// Reset the disconnect_requested flag
that.disconnect_requested = false;
// Each minute we need to trigger a heartbeat. Server expects 2min, but to be safe we do it every 1min
var heartbeat = function() {
if (!that.rpc) return;
that.rpc('kiwi.heartbeat');
that._heartbeat_tmr = setTimeout(heartbeat, 60000);
};
heartbeat();
console.log("_kiwi.gateway.socket.on('open')");
});
this.rpc.on('too_many_connections', function () {
that.trigger("connect_fail", {reason: 'too_many_connections'});
});
this.rpc.on('irc', function (response, data) {
that.parse(data.command, data.data);
});
this.rpc.on('kiwi', function (response, data) {
that.parseKiwi(data.command, data.data);
});
this.socket.on('close', function () {
that.trigger("disconnect", {});
console.log("_kiwi.gateway.socket.on('close')");
});
this.socket.on('reconnecting', function (status) {
console.log("_kiwi.gateway.socket.on('reconnecting')");
that.trigger("reconnecting", {delay: status.delay, attempts: status.attempts});
});
this.socket.on('reconnecting_failed', function () {
console.log("_kiwi.gateway.socket.on('reconnect_failed')");
});
},
/**
* Return a new network object with the new connection details
*/
newConnection: function(connection_info, callback_fn) {
var that = this;
// If not connected, connect first then re-call this function
if (!this.isConnected()) {
this.connect(function(err) {
if (err) {
callback_fn(err);
return;
}
that.newConnection(connection_info, callback_fn);
});
return;
}
this.makeIrcConnection(connection_info, function(err, server_num) {
var connection;
if (!err) {
if (!_kiwi.app.connections.getByConnectionId(server_num)){
var inf = {
connection_id: server_num,
nick: connection_info.nick,
address: connection_info.host,
port: connection_info.port,
ssl: connection_info.ssl,
password: connection_info.password
};
connection = new _kiwi.model.Network(inf);
_kiwi.app.connections.add(connection);
}
console.log("_kiwi.gateway.socket.on('connect')", connection);
callback_fn && callback_fn(err, connection);
} else {
console.log("_kiwi.gateway.socket.on('error')", {reason: err});
callback_fn && callback_fn(err);
}
});
},
/**
* Make a new IRC connection and return its connection ID
*/
makeIrcConnection: function(connection_info, callback_fn) {
var server_info = {
nick: connection_info.nick,
hostname: connection_info.host,
port: connection_info.port,
ssl: connection_info.ssl,
password: connection_info.password
};
connection_info.options = connection_info.options || {};
// A few optional parameters
if (connection_info.options.encoding)
server_info.encoding = connection_info.options.encoding;
this.rpc('kiwi.connect_irc', server_info, function (err, server_num) {
if (!err) {
callback_fn && callback_fn(err, server_num);
} else {
callback_fn && callback_fn(err);
}
});
},
isConnected: function () {
// TODO: Check this. Might want to use .readyState
return this.socket;
},
parseKiwi: function (command, data) {
var args;
switch (command) {
case 'connected':
// Send some info on this client to the server
args = {
build_version: _kiwi.global.build_version
};
this.rpc('kiwi.client_info', args);
this.connect_callback && this.connect_callback();
delete this.connect_callback;
break;
}
this.trigger('kiwi:' + command, data);
this.trigger('kiwi', data);
},
/**
* Parses the response from the server
*/
parse: function (command, data) {
var network_trigger = '';
// Trigger the connection specific events (used by Network objects)
if (typeof data.connection_id !== 'undefined') {
network_trigger = 'connection:' + data.connection_id.toString();
this.trigger(network_trigger, {
event_name: command,
event_data: data
});
// Some events trigger a more in-depth event name
if (command == 'message' && data.type) {
this.trigger('connection ' + network_trigger, {
event_name: 'message:' + data.type,
event_data: data
});
}
if (command == 'channel' && data.type) {
this.trigger('connection ' + network_trigger, {
event_name: 'channel:' + data.type,
event_data: data
});
}
}
// Trigger the global events
this.trigger('connection', {event_name: command, event_data: data});
this.trigger('connection:' + command, data);
},
/**
* Make an RPC call with the connection_id as the first argument
* @param {String} method RPC method name
* @param {Number} connection_id Connection ID this call relates to
*/
rpcCall: function(method, connection_id) {
var args = Array.prototype.slice.call(arguments, 0);
if (typeof args[1] === 'undefined' || args[1] === null)
args[1] = _kiwi.app.connections.active_connection.get('connection_id');
return this.rpc.apply(this.rpc, args);
},
/**
* Sends a PRIVMSG message
* @param {String} target The target of the message (e.g. a channel or nick)
* @param {String} msg The message to send
* @param {Function} callback A callback function
*/
privmsg: function (connection_id, target, msg, callback) {
var args = {
target: target,
msg: msg
};
this.rpcCall('irc.privmsg', connection_id, args, callback);
},
/**
* Sends a NOTICE message
* @param {String} target The target of the message (e.g. a channel or nick)
* @param {String} msg The message to send
* @param {Function} callback A callback function
*/
notice: function (connection_id, target, msg, callback) {
var args = {
target: target,
msg: msg
};
this.rpcCall('irc.notice', connection_id, args, callback);
},
/**
* Sends a CTCP message
* @param {Boolean} request Indicates whether this is a CTCP request (true) or reply (false)
* @param {String} type The type of CTCP message, e.g. 'VERSION', 'TIME', 'PING' etc.
* @param {String} target The target of the message, e.g a channel or nick
* @param {String} params Additional paramaters
* @param {Function} callback A callback function
*/
ctcp: function (connection_id, is_request, type, target, params, callback) {
var args = {
is_request: is_request,
type: type,
target: target,
params: params
};
this.rpcCall('irc.ctcp', connection_id, args, callback);
},
ctcpRequest: function (connection_id, type, target, params, callback) {
this.ctcp(connection_id, true, type, target, params, callback);
},
ctcpResponse: function (connection_id, type, target, params, callback) {
this.ctcp(connection_id, false, type, target, params, callback);
},
/**
* @param {String} target The target of the message (e.g. a channel or nick)
* @param {String} msg The message to send
* @param {Function} callback A callback function
*/
action: function (connection_id, target, msg, callback) {
this.ctcp(connection_id, true, 'ACTION', target, msg, callback);
},
/**
* Joins a channel
* @param {String} channel The channel to join
* @param {String} key The key to the channel
* @param {Function} callback A callback function
*/
join: function (connection_id, channel, key, callback) {
var args = {
channel: channel,
key: key
};
this.rpcCall('irc.join', connection_id, args, callback);
},
/**
* Retrieves channel information
*/
channelInfo: function (connection_id, channel, callback) {
var args = {
channel: channel
};
this.rpcCall('irc.channel_info', connection_id, args, callback);
},
/**
* Leaves a channel
* @param {String} channel The channel to part
* @param {String} message Optional part message
* @param {Function} callback A callback function
*/
part: function (connection_id, channel, message, callback) {
"use strict";
// The message param is optional, so juggle args if it is missing
if (typeof arguments[2] === 'function') {
callback = arguments[2];
message = undefined;
}
var args = {
channel: channel,
message: message
};
this.rpcCall('irc.part', connection_id, args, callback);
},
/**
* Queries or modifies a channell topic
* @param {String} channel The channel to query or modify
* @param {String} new_topic The new topic to set
* @param {Function} callback A callback function
*/
topic: function (connection_id, channel, new_topic, callback) {
var args = {
channel: channel,
topic: new_topic
};
this.rpcCall('irc.topic', connection_id, args, callback);
},
/**
* Kicks a user from a channel
* @param {String} channel The channel to kick the user from
* @param {String} nick The nick of the user to kick
* @param {String} reason The reason for kicking the user
* @param {Function} callback A callback function
*/
kick: function (connection_id, channel, nick, reason, callback) {
var args = {
channel: channel,
nick: nick,
reason: reason
};
this.rpcCall('irc.kick', connection_id, args, callback);
},
/**
* Disconnects us from the server
* @param {String} msg The quit message to send to the IRC server
* @param {Function} callback A callback function
*/
quit: function (connection_id, msg, callback) {
msg = msg || "";
var args = {
message: msg
};
this.rpcCall('irc.quit', connection_id, args, callback);
},
/**
* Sends a string unmodified to the IRC server
* @param {String} data The data to send to the IRC server
* @param {Function} callback A callback function
*/
raw: function (connection_id, data, callback) {
var args = {
data: data
};
this.rpcCall('irc.raw', connection_id, args, callback);
},
/**
* Changes our nickname
* @param {String} new_nick Our new nickname
* @param {Function} callback A callback function
*/
changeNick: function (connection_id, new_nick, callback) {
var args = {
nick: new_nick
};
this.rpcCall('irc.nick', connection_id, args, callback);
},
/**
* Sets a mode for a target
*/
mode: function (connection_id, target, mode_string, callback) {
var args = {
data: 'MODE ' + target + ' ' + mode_string
};
this.rpcCall('irc.raw', connection_id, args, callback);
},
/**
* Sends ENCODING change request to server.
* @param {String} new_encoding The new proposed encode
* @param {Fucntion} callback A callback function
*/
setEncoding: function (connection_id, new_encoding, callback) {
var args = {
encoding: new_encoding
};
this.rpcCall('irc.encoding', connection_id, args, callback);
}
});