From: Chris Porter Date: Thu, 10 Jul 2008 22:26:00 +0000 (+0100) Subject: Add connection dialog. X-Git-Url: https://jfr.im/git/irc/quakenet/qwebirc.git/commitdiff_plain/8dc46dfa15e0a2392cd0c61e240cd6267b9f00f6?hp=eb9b087b8088d289a759c263de54898a299800d1 Add connection dialog. Handle disconnects more gracefully in the JS and Python backend. Move config example to correct location. Default run script now hides tracebacks. --- diff --git a/qwebirc/config.py.example b/config.py.example similarity index 82% rename from qwebirc/config.py.example rename to config.py.example index 1b93404..8532cc1 100644 --- a/qwebirc/config.py.example +++ b/config.py.example @@ -2,3 +2,4 @@ IRCSERVER, IRCPORT = "moo.com", 6667 HMACKEY = "mrmoo" HMACTEMPORAL = 30 UPDATE_FREQ = 0.5 +MAXBUFSIZE = 10000 diff --git a/js/irc/baseirc.js b/js/irc/baseirc.js index 0912c65..e53e357 100644 --- a/js/irc/baseirc.js +++ b/js/irc/baseirc.js @@ -29,14 +29,19 @@ var BaseIRCClient = new Class({ this.send = this.connection.send.bind(this.connection); this.connect = this.connection.connect.bind(this.connection); - this.disconnect = this.connection.disconnect; + this.disconnect = this.connection.disconnect.bind(this.connection); }, dispatch: function(data) { var message = data[0]; if(message == "connect") { this.connected(); } else if(message == "disconnect") { - this.disconnected(); + if(data.length == 0) { + this.disconnected("No error!"); + } else { + this.disconnected(data[1]); + } + this.disconnect(); } else if(message == "c") { var command = data[1].toUpperCase(); diff --git a/js/irc/ircclient.js b/js/irc/ircclient.js index b63b832..328accd 100644 --- a/js/irc/ircclient.js +++ b/js/irc/ircclient.js @@ -341,13 +341,13 @@ var IRCClient = new Class({ }, this); }, this); }, - disconnected: function() { + disconnected: function(message) { for(var x in this.parent.channels) this.ui.closeWindow(x); this.tracker = undefined; - this.newServerLine("DISCONNECT"); + this.newServerLine("DISCONNECT", {"m": message}); }, supported: function(key, value) { if(key == "PREFIX") { diff --git a/js/irc/ircconnection.js b/js/irc/ircconnection.js index 0d121e8..fc88942 100644 --- a/js/irc/ircconnection.js +++ b/js/irc/ircconnection.js @@ -12,33 +12,44 @@ var IRCConnection = new Class({ this.disconnected = false; }, send: function(data) { + if(this.disconnected) + return; var r = new Request.JSON({url: "/e/p/" + this.sessionid + "?c=" + encodeURIComponent(data) + "&t=" + this.counter++, onComplete: function(o) { - if(o[0] == false) - alert("An error occured: " + o[1]); - }}); + if(!o || (o[0] == false)) { + if(!this.disconnected) { + this.disconnected = true; + alert("An error occured: " + o[1]); + } + } + }.bind(this)}); r.get(); }, - x: function() { - this.fireEvent("recv", [[false, "moo"]]); - }, recv: function() { - if(this.disconnected) - return; - var r = new Request.JSON({url: "/e/s/" + this.sessionid + "?t=" + this.counter++, onComplete: function(o) { if(o) { if(o[0] == false) { - alert("An error occured: " + o[1]); + if(!this.disconnected) { + this.disconnected = true; + + alert("An error occured: " + o[1]); + } return; } o.each(function(x) { this.fireEvent("recv", [x]); }, this); + } else { + if(!this.disconnected) { + this.disconnected = true; + + alert("An unknown error occured."); + } + return; } this.recv(); - }.bind(this)}); + }.bind(this)}); r.get(); }, connect: function() { diff --git a/js/ui/theme.js b/js/ui/theme.js index 9e5ffc2..806a93e 100644 --- a/js/ui/theme.js +++ b/js/ui/theme.js @@ -11,7 +11,7 @@ var DefaultTheme = { "SIGNON": ["Signed on!", true], "CONNECT": ["Connected to server.", true], "RAW": ["$m", true], - "DISCONNECT": ["Disconnected from server.", true], + "DISCONNECT": ["Disconnected from server: $m", true], "ERROR": ["ERROR: $m", true], "SERVERNOTICE": ["$m", true], "JOIN": ["$n [$h] has joined $c", true], diff --git a/qwebirc/ajaxengine.py b/qwebirc/ajaxengine.py index 3dc3da5..4f91466 100644 --- a/qwebirc/ajaxengine.py +++ b/qwebirc/ajaxengine.py @@ -1,13 +1,17 @@ from twisted.web import resource, server, static from twisted.names import client from twisted.internet import reactor -import simplejson, md5, sys, os, ircclient, time, config +import traceback +import simplejson, md5, sys, os, ircclient, time, config, weakref Sessions = {} def get_session_id(): - return md5.md5(os.urandom(16)).hexdigest() - + return md5.md5(os.urandom(16)).hexdigest()[:10] + +class BufferOverflowException(Exception): + pass + def jsondump(fn): def decorator(*args, **kwargs): x = fn(*args, **kwargs) @@ -16,6 +20,12 @@ def jsondump(fn): return x return decorator +def cleanupSession(id): + try: + del Sessions[id] + except KeyError: + pass + class IRCSession: def __init__(self, id): self.id = id @@ -23,7 +33,9 @@ class IRCSession: self.buffer = [] self.throttle = 0 self.schedule = None - + self.closed = False + self.cleanupschedule = None + def subscribe(self, channel): self.subscriptions.append(channel) self.flush() @@ -59,14 +71,30 @@ class IRCSession: newsubs.append(x) self.subscriptions = newsubs - + if self.closed and not self.subscriptions: + cleanupSession(self.id) + def event(self, data): + bufferlen = sum(map(len, self.buffer)) + if bufferlen + len(data) > config.MAXBUFLEN: + self.buffer = [] + self.client.error("Buffer overflow") + return + self.buffer.append(data) self.flush() def push(self, data): - self.client.write(data) - + if not self.closed: + self.client.write(data) + + def disconnect(self): + # keep the session hanging around for a few seconds so the + # client has a chance to see what the issue was + self.closed = True + + reactor.callLater(5, cleanupSession, self.id) + class Channel: def __init__(self, request): self.request = request @@ -141,7 +169,17 @@ class AJAXEngine(resource.Resource): decoded = command.decode("utf-8") except UnicodeDecodeError: decoded = command.decode("iso-8859-1", "ignore") - session.push(decoded) + + try: + session.push(decoded) + except AttributeError: # occurs when we haven't noticed an error + session.disconnect() + return [False, "Connection closed by server."] + except Exception, e: # catch all + session.disconnect() + traceback.print_exc(file=sys.stderr) + return [False, "Unknown error."] + return [True] return [False, "404"] diff --git a/qwebirc/ircclient.py b/qwebirc/ircclient.py index 06589a4..e5b88a5 100644 --- a/qwebirc/ircclient.py +++ b/qwebirc/ircclient.py @@ -15,7 +15,7 @@ def hmacfn(*args): class QWebIRCClient(basic.LineReceiver): delimiter = "\n" - + def dataReceived(self, data): basic.LineReceiver.dataReceived(self, data.replace("\r", "")) @@ -47,6 +47,7 @@ class QWebIRCClient(basic.LineReceiver): def connectionMade(self): basic.LineReceiver.connectionMade(self) + self.lastError = None f = self.factory.ircinit nick, ident, ip, realname = f["nick"], f["ident"], f["ip"], f["realname"] @@ -58,9 +59,21 @@ class QWebIRCClient(basic.LineReceiver): self("connect") def connectionLost(self, reason): + if self.lastError: + self.disconnect("Connection to IRC server lost: %s" % self.lastError) + else: + self.disconnect("Connection to IRC server lost.") self.factory.client = None basic.LineReceiver.connectionLost(self, reason) - self("disconnect") + + def error(self, message): + self.lastError = message + self.write("QUIT :qwebirc exception: %s" % message) + self.transport.loseConnection() + + def disconnect(self, reason): + self("disconnect", reason) + self.factory.publisher.disconnect() class QWebIRCFactory(protocol.ClientFactory): protocol = QWebIRCClient @@ -71,7 +84,14 @@ class QWebIRCFactory(protocol.ClientFactory): def write(self, data): self.client.write(data) - + + def error(self, reason): + self.client.error(reason) + + def clientConnectionFailed(self, reason): + protocol.ClientFactory.clientConnectionFailed(reason) + self.client.disconnect("Connection to IRC server failed.") + def createIRC(*args, **kwargs): f = QWebIRCFactory(*args, **kwargs) reactor.connectTCP(config.IRCSERVER, config.IRCPORT, f) @@ -79,4 +99,4 @@ def createIRC(*args, **kwargs): if __name__ == "__main__": e = createIRC(lambda x: 2, nick="slug__moo", ident="mooslug", ip="1.2.3.6", realname="mooooo") - reactor.run() \ No newline at end of file + reactor.run() diff --git a/run.bat b/run.bat index 2f9809e..52a51a9 100644 --- a/run.bat +++ b/run.bat @@ -1,3 +1,3 @@ set PYTHONPATH=. -c:\python25\scripts\twistd.py qwebirc -pause \ No newline at end of file +c:\python25\scripts\twistd.py qwebirc -n +pause diff --git a/run.sh b/run.sh index 78ee921..75e08a1 100755 --- a/run.sh +++ b/run.sh @@ -1,3 +1,3 @@ #!/bin/sh export PYTHONPATH=.:${PYTHONPATH} -twistd qwebirc +twistd qwebirc -n