b54cba86c7
Convert latency test to use include/websock.js instead of direct WebSockets handling. Add support for configuring the maximum bufferedAmount. This allows us to configure it high enough to get around a bug in bufferedAmount reporting in Opera. Add some latency test results for Opera 11 with WebSockets turned on.
236 lines
5.0 KiB
JavaScript
236 lines
5.0 KiB
JavaScript
/*
|
|
* WebSockets IRC client
|
|
* Copyright (C) 2011 Joel Martin
|
|
* Licensed under LGPL-3 (see LICENSE.txt)
|
|
*
|
|
* Includes VT100.js from:
|
|
* http://code.google.com/p/sshconsole
|
|
* Which was modified from:
|
|
* http://fzort.org/bi/o.php#vt100_js
|
|
|
|
* IRC Client protocol:
|
|
* http://www.faqs.org/rfcs/rfc2812.html
|
|
*/
|
|
|
|
|
|
function IRC(target, connect_callback, disconnect_callback) {
|
|
|
|
var that = {}, // Public API interface
|
|
vt100, ws, sQ = [],
|
|
state = "unconnected",
|
|
irc_nick, irc_channel,
|
|
termType = "VT100";
|
|
|
|
|
|
Array.prototype.pushStr = function (str) {
|
|
var n = str.length;
|
|
for (var i=0; i < n; i++) {
|
|
this.push(str.charCodeAt(i));
|
|
}
|
|
}
|
|
|
|
function do_send() {
|
|
if (sQ.length > 0) {
|
|
Util.Debug("Sending " + sQ);
|
|
ws.send(sQ);
|
|
sQ = [];
|
|
}
|
|
}
|
|
|
|
function do_recv() {
|
|
console.log(">> do_recv");
|
|
var rQ, rQi, i;
|
|
|
|
while (ws.rQlen() > 1) {
|
|
rQ = ws.get_rQ();
|
|
rQi = ws.get_rQi();
|
|
for (i = rQi; i < rQ.length; i++) {
|
|
if (rQ[i] === 10) {
|
|
break;
|
|
}
|
|
}
|
|
if (i >= rQ.length) {
|
|
// No line break found
|
|
break;
|
|
}
|
|
recvMsg(ws.rQshiftStr((i-rQi) + 1));
|
|
}
|
|
//console.log("<< do_recv");
|
|
}
|
|
|
|
// Handle an IRC message
|
|
function recvMsg(msg) {
|
|
Util.Debug(">> recvMsg('" + msg + "')");
|
|
|
|
var tokens = msg.split(' '), in_params = true,
|
|
prefix, command, params = [], trailing = [];
|
|
|
|
Util.Info(" tokens: " + tokens);
|
|
|
|
if (tokens[0].charAt(0) === ":") {
|
|
prefix = tokens.shift();
|
|
}
|
|
|
|
command = tokens.shift();
|
|
|
|
while (tokens.length > 0) {
|
|
if (tokens[0].charAt(0) === ":") {
|
|
in_params = false;
|
|
}
|
|
if (in_params) {
|
|
params.push(tokens.shift());
|
|
} else {
|
|
trailing.push(tokens.shift());
|
|
}
|
|
}
|
|
|
|
Util.Info(" prefix: " + prefix);
|
|
Util.Info(" command: " + command);
|
|
Util.Info(" params: " + params);
|
|
Util.Info(" trailing: " + trailing);
|
|
|
|
// Show raw received
|
|
vt100.write(msg);
|
|
|
|
switch (command) {
|
|
case "004":
|
|
state = "registered";
|
|
vt100.write("Joining channel #" + irc_channel);
|
|
sendCmd("JOIN #" + irc_channel);
|
|
break;
|
|
case "JOIN":
|
|
state = "joined";
|
|
vt100.write("Joined channel #" + irc_channel);
|
|
break;
|
|
|
|
}
|
|
|
|
Util.Debug("<< recvMsg('" + msg + "')");
|
|
}
|
|
|
|
function sendCmd(msg) {
|
|
Util.Info("Sending: " + msg);
|
|
sQ.pushStr(msg + "\r\n");
|
|
do_send();
|
|
}
|
|
|
|
that.sendMsg = function(msg) {
|
|
// TODO parse into message
|
|
sendCmd("PRIVMSG #" + irc_channel + " :" + msg);
|
|
}
|
|
|
|
|
|
that.connect = function(host, port, encrypt, nick, channel) {
|
|
var host = host,
|
|
port = port,
|
|
scheme = "ws://", uri;
|
|
|
|
irc_nick = nick;
|
|
irc_channel = channel;
|
|
|
|
Util.Debug(">> connect");
|
|
if ((!host) || (!port)) {
|
|
alert("must set host and port");
|
|
return false;
|
|
}
|
|
|
|
if (ws) {
|
|
ws.close();
|
|
}
|
|
|
|
if (encrypt) {
|
|
scheme = "wss://";
|
|
}
|
|
uri = scheme + host + ":" + port;
|
|
Util.Info("connecting to " + uri);
|
|
|
|
ws.open(uri);
|
|
|
|
Util.Debug("<< connect");
|
|
|
|
return true;
|
|
}
|
|
|
|
that.disconnect = function() {
|
|
Util.Debug(">> disconnect");
|
|
if (ws) {
|
|
ws.close();
|
|
}
|
|
|
|
disconnect_callback();
|
|
Util.Debug("<< disconnect");
|
|
}
|
|
|
|
|
|
function constructor() {
|
|
/* Initialize Websock object */
|
|
ws = new Websock();
|
|
|
|
ws.on('message', do_recv);
|
|
ws.on('open', function(e) {
|
|
Util.Info(">> WebSockets.onopen");
|
|
// Send registration commands
|
|
state = "connected";
|
|
sendCmd("NICK " + irc_nick);
|
|
// TODO: how to determine this?
|
|
sendCmd("USER joelm 0 * :Joel Martin");
|
|
connect_callback();
|
|
Util.Info("<< WebSockets.onopen");
|
|
});
|
|
ws.on('close', function(e) {
|
|
Util.Info(">> WebSockets.onclose");
|
|
that.disconnect();
|
|
Util.Info("<< WebSockets.onclose");
|
|
});
|
|
ws.on('error', function(e) {
|
|
Util.Info(">> WebSockets.onerror");
|
|
that.disconnect();
|
|
Util.Info("<< WebSockets.onerror");
|
|
});
|
|
|
|
/* Initialize the terminal emulator/renderer */
|
|
|
|
vt100 = new VT100(80, 24, target);
|
|
|
|
// Show cursor
|
|
vt100.curs_set(true, false);
|
|
|
|
/*
|
|
* Override VT100 I/O routines
|
|
*/
|
|
|
|
// Set handler for sending characters
|
|
vt100.getch(
|
|
function send_chr(chr, vt) {
|
|
var i;
|
|
Util.Debug(">> send_chr: " + chr);
|
|
for (i = 0; i < chr.length; i++) {
|
|
sQ.push(chr.charCodeAt(i));
|
|
}
|
|
do_send();
|
|
vt100.getch(send_chr);
|
|
}
|
|
);
|
|
|
|
vt100.debug = function(message) {
|
|
Util.Debug(message + "\n");
|
|
}
|
|
|
|
vt100.warn = function(message) {
|
|
Util.Warn(message + "\n");
|
|
}
|
|
|
|
vt100.curs_set = function(vis, grab, eventist)
|
|
{
|
|
this.debug("curs_set:: vis: " + vis + ", grab: " + grab);
|
|
if (vis !== undefined)
|
|
this.cursor_vis_ = (vis > 0);
|
|
}
|
|
|
|
return that;
|
|
}
|
|
|
|
return constructor(); // Return the public API interface
|
|
|
|
} // End of Telnet()
|