Author: dylan
Date: 2006-05-21 22:11:59 -0400 (Sun, 21 May 2006)
New Revision: 980
Added:
trunk/python/
trunk/python/client/
trunk/python/client/haver/
trunk/python/client/haver/__init__.py
trunk/python/client/haver/client.py
trunk/python/client/haver/factory.py
trunk/python/client/haver/format.py
trunk/python/client/haver/protocol.py
trunk/python/client/haver/qtui.py
trunk/python/client/proclaimer
trunk/python/client/proclaimer.tac
trunk/python/server/
trunk/python/server/.todo
trunk/python/server/TODO
trunk/python/server/haver.tac
trunk/python/server/haver/
trunk/python/server/haver/__init__.py
trunk/python/server/haver/server/
trunk/python/server/haver/server/__init__.py
trunk/python/server/haver/server/entity.py
trunk/python/server/haver/server/errors.py
trunk/python/server/haver/server/factory.py
trunk/python/server/haver/server/states.py
trunk/python/server/haver/server/talker.py
trunk/python/server/test/
Modified:
trunk/
Log:
[EMAIL PROTECTED]: dylan | 2006-03-25 13:47:04 -0500
adding python client. It sort of works!
[EMAIL PROTECTED]: dylan | 2006-05-21 18:48:23 -0400
Adding python haver server.
[EMAIL PROTECTED]: dylan | 2006-05-21 22:11:41 -0400
Some fixes, TODO and .todo file listing what I need to do.
Property changes on: trunk
___________________________________________________________________
Name: svk:merge
- 1f59643a-e6e5-0310-bc24-f7d4c744f460:/haver/havercurs-objc:43089
1f59643a-e6e5-0310-bc24-f7d4c744f460:/haver/local/trunk:11166
1f59643a-e6e5-0310-bc24-f7d4c744f460:/haver/local/trunk-merge-10131:11178
1f59643a-e6e5-0310-bc24-f7d4c744f460:/haver/winch/trunk:43192
27e50396-46e3-0310-8b22-ae223a1f35ce:/local:212
ca0be05d-e60e-0410-9596-96133d777aec:/haver/local:1380
e9404bb1-7af0-0310-a7ff-e22194cd388b:/haver/local:2455
edfcd8bd-4ce7-0310-a97e-bb1efd40edf3:/local:238
+ 1f59643a-e6e5-0310-bc24-f7d4c744f460:/haver/havercurs-objc:43089
1f59643a-e6e5-0310-bc24-f7d4c744f460:/haver/local/trunk:11166
1f59643a-e6e5-0310-bc24-f7d4c744f460:/haver/local/trunk-merge-10131:11178
1f59643a-e6e5-0310-bc24-f7d4c744f460:/haver/winch/trunk:43192
27e50396-46e3-0310-8b22-ae223a1f35ce:/local:212
ca0be05d-e60e-0410-9596-96133d777aec:/haver/local:3259
e9404bb1-7af0-0310-a7ff-e22194cd388b:/haver/local:2455
edfcd8bd-4ce7-0310-a97e-bb1efd40edf3:/local:238
Added: trunk/python/client/haver/__init__.py
===================================================================
Added: trunk/python/client/haver/client.py
===================================================================
--- trunk/python/client/haver/client.py 2006-03-20 21:04:28 UTC (rev 979)
+++ trunk/python/client/haver/client.py 2006-05-22 02:11:59 UTC (rev 980)
@@ -0,0 +1,99 @@
+from twisted.internet.protocol import ReconnectingClientFactory
+from twisted.protocols.basic import LineReceiver
+
+class Factory(ReconnectingClientFactory):
+ def __init__(self, ui, version = "haver.client/0.10"):
+ self.ui = ui
+ self.version = version
+
+ def getVersion(self):
+ return self.version
+
+ def getUserName(self):
+ return "dylan" # ui.getUserName()
+
+ def startedConnecting(self, connector):
+ self.ui.display('net.connect')
+
+ def buildProtocol(self, addr):
+ self.ui.display('net.connected', host = addr.host, port =
addr.port)
+ print 'Resetting reconnection delay'
+ self.resetDelay()
+ prot = self.protocol(addr, self.ui)
+ self.ui.protocol = prot
+ prot.factory = self;
+ return prot
+
+ def clientConnectionLost(self, connector, reason):
+ self.ui.display('net.connectionLost', reason = reason)
+ ReconnectingClientFactory.clientConnectionLost(self, connector,
reason)
+
+ def clientConnectionFailed(self, connector, reason):
+ self.ui.display('net.connectionFailed', reason = reason)
+ ReconnectingClientFactory.clientConnectionFailed(self,
connector, reason)
+
+
+class Formatter:
+ Formats = {
+ 'msg.hello': "Logged in as %(name)s",
+ 'msg.from': "<%(user)s> %(msg)s",
+ 'msg.in': "%(channel)s: <%(user)s> %(msg)s",
+ }
+
+ def __init__(self, formats = None):
+ if formats is None:
+ self.formats = Formatter.Formats.copy()
+ else:
+ self.formats = formats
+
+ def format(self, fmtname, params):
+ if self.formats.has_key(fmtname):
+ return self.formats[fmtname] % params
+ else:
+ return "%s %r" % (fmtname, params)
+
+ def addFormat(self, fmtname, string):
+ self.formats[fmtname] = string
+
+class Protocol(LineReceiver):
+ def __init__(self, addr, ui):
+ self.addr = addr
+ self.ui = ui
+
+ def lineReceived(self, line):
+
+ msg = line.split("\t")
+ method = "msg_" + msg[0]
+
+ if hasattr(self, method):
+ f = getattr(self, method)
+ f(msg[1:])
+ else:
+ self.default_msg(msg[0], msg[1:])
+
+ # HAVER host version supports
+ def msg_HAVER(self, args):
+ h, ver = args[0:2]
+ # FIXME: make this raise a different exception.
+ assert h == self.addr.host
+ self.ui.display('msg.haver', version = ver, host = h)
+ self.sendMsg('IDENT', self.factory.getUserName())
+
+ def msg_HELLO(self, args):
+ self.ui.display('msg.hello', name = args[0])
+
+ def msg_FROM(self, args):
+ self.ui.display('msg.from', user = args[0], kind = args[1], msg
= args[2])
+
+ def msg_IN(self, args):
+ self.ui.display('msg.in', channel = args[0], user = args[1],
kind = args[2], msg = args[3])
+
+
+ def default_msg(self, n, a):
+ self.ui.display('unknown.msg', name = n, args = a)
+
+ def sendMsg(self, *msg):
+ self.sendLine("\t".join(msg))
+
+ def connectionMade(self):
+ self.sendMsg('HAVER', self.factory.getVersion())
Added: trunk/python/client/haver/factory.py
===================================================================
--- trunk/python/client/haver/factory.py 2006-03-20 21:04:28 UTC (rev
979)
+++ trunk/python/client/haver/factory.py 2006-05-22 02:11:59 UTC (rev
980)
@@ -0,0 +1,34 @@
+from twisted.internet.protocol import ReconnectingClientFactory
+
+class Factory(ReconnectingClientFactory):
+ def __init__(self, ui, version = "haver.client/0.10"):
+ self.ui = ui
+ self.version = version
+
+ def getVersion(self):
+ return self.version
+
+ def getUserName(self):
+ return "dylan" # ui.getUserName()
+
+ def startedConnecting(self, connector):
+ self.ui.display('net.connect')
+
+ def buildProtocol(self, addr):
+ self.ui.display('net.connected', host = addr.host, port =
addr.port)
+ print 'Resetting reconnection delay'
+ self.resetDelay()
+ prot = self.protocol(addr, self.ui)
+ self.ui.protocol = prot
+ prot.factory = self;
+ return prot
+
+ def clientConnectionLost(self, connector, reason):
+ self.ui.display('net.connectionLost', reason = reason)
+ ReconnectingClientFactory.clientConnectionLost(self, connector,
reason)
+
+ def clientConnectionFailed(self, connector, reason):
+ self.ui.display('net.connectionFailed', reason = reason)
+ ReconnectingClientFactory.clientConnectionFailed(self,
connector, reason)
+
+
Added: trunk/python/client/haver/format.py
===================================================================
--- trunk/python/client/haver/format.py 2006-03-20 21:04:28 UTC (rev 979)
+++ trunk/python/client/haver/format.py 2006-05-22 02:11:59 UTC (rev 980)
@@ -0,0 +1,22 @@
+class Formatter:
+ Formats = {
+ 'msg.hello': "Logged in as %(name)s",
+ 'msg.from': "<%(user)s> %(msg)s",
+ 'msg.in': "%(channel)s: <%(user)s> %(msg)s",
+ }
+
+ def __init__(self, formats = None):
+ if formats is None:
+ self.formats = Formatter.Formats.copy()
+ else:
+ self.formats = formats
+
+ def format(self, fmtname, params):
+ if self.formats.has_key(fmtname):
+ return self.formats[fmtname] % params
+ else:
+ return "%s %r" % (fmtname, params)
+
+ def addFormat(self, fmtname, string):
+ self.formats[fmtname] = string
+
Added: trunk/python/client/haver/protocol.py
===================================================================
--- trunk/python/client/haver/protocol.py 2006-03-20 21:04:28 UTC (rev
979)
+++ trunk/python/client/haver/protocol.py 2006-05-22 02:11:59 UTC (rev
980)
@@ -0,0 +1,44 @@
+from twisted.protocols.basic import LineReceiver
+
+class Protocol(LineReceiver):
+ def __init__(self, addr, ui):
+ self.addr = addr
+ self.ui = ui
+
+ def lineReceived(self, line):
+
+ msg = line.split("\t")
+ method = "msg_" + msg[0]
+
+ if hasattr(self, method):
+ f = getattr(self, method)
+ f(msg[1:])
+ else:
+ self.default_msg(msg[0], msg[1:])
+
+ # HAVER host version supports
+ def msg_HAVER(self, args):
+ h, ver = args[0:2]
+ # FIXME: make this raise a different exception.
+ assert h == self.addr.host
+ self.ui.display('msg.haver', version = ver, host = h)
+ self.sendMsg('IDENT', self.factory.getUserName())
+
+ def msg_HELLO(self, args):
+ self.ui.display('msg.hello', name = args[0])
+
+ def msg_FROM(self, args):
+ self.ui.display('msg.from', user = args[0], kind = args[1], msg
= args[2])
+
+ def msg_IN(self, args):
+ self.ui.display('msg.in', channel = args[0], user = args[1],
kind = args[2], msg = args[3])
+
+
+ def default_msg(self, n, a):
+ self.ui.display('unknown.msg', name = n, args = a)
+
+ def sendMsg(self, *msg):
+ self.sendLine("\t".join(msg))
+
+ def connectionMade(self):
+ self.sendMsg('HAVER', self.factory.getVersion())
Added: trunk/python/client/haver/qtui.py
===================================================================
--- trunk/python/client/haver/qtui.py 2006-03-20 21:04:28 UTC (rev 979)
+++ trunk/python/client/haver/qtui.py 2006-05-22 02:11:59 UTC (rev 980)
@@ -0,0 +1,62 @@
+from qt import *
+
+class HaverWindow(QMainWindow):
+ def __init__(self, *args):
+ QMainWindow.__init__(self, *args)
+
+ self.setCaption("Haver")
+
+ vbox = QVBox(self)
+ vbox.setMargin(2)
+ vbox.setSpacing(3)
+
+ self.tabs = QTabWidget(vbox)
+ self.views = dict()
+ self.views['status'] = QTextView(None)
+ self.tabs.addTab(self.views['status'], 'status')
+
+ hbox = QHBox(vbox)
+ label = QLabel("Chat: ", hbox)
+
+ self.line = QLineEdit("", hbox)
+
+ self.setCentralWidget(vbox)
+
+ def foobar(self):
+ self.views['status2'] = QTextView(None)
+ self.tabs.addTab(self.views['status2'], 'status2')
+
+class HaverQt:
+ def __init__(self, name, formatter):
+ win = HaverWindow()
+ win.setCaption(name)
+
+ win.connect(win.line, SIGNAL('returnPressed()'), self.sendLine)
+
+ self.win = win
+ self.formatter = formatter
+
+ def sendLine(self):
+ line = self.win.line.text()
+ self.protocol.sendMsg('TO', '&echo', 'say', str(line))
+ self.win.foobar()
+ self.win.line.clear()
+
+ def displayLine(self, line):
+ # self.win.edit.append(line + "\n")
+ print line
+
+ def display(self, fmtname, **kwargs):
+ self.displayLine(self.formatter.format(fmtname, kwargs))
+
+ def setup(self, reactor):
+ self.win.show()
+
+ app = reactor.qApp
+ # make sure stopping twisted event also shuts down QT
+ reactor.addSystemEventTrigger('after', 'shutdown', app.quit )
+
+ # shutdown twisted when window is closed
+ app.connect(app, SIGNAL("lastWindowClosed()"), reactor.stop)
+
+
Added: trunk/python/client/proclaimer
===================================================================
--- trunk/python/client/proclaimer 2006-03-20 21:04:28 UTC (rev 979)
+++ trunk/python/client/proclaimer 2006-05-22 02:11:59 UTC (rev 980)
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec twistd2.4 --reactor qt -ny proclaimer.tac
Property changes on: trunk/python/client/proclaimer
___________________________________________________________________
Name: svn:executable
+ *
Added: trunk/python/client/proclaimer.tac
===================================================================
--- trunk/python/client/proclaimer.tac 2006-03-20 21:04:28 UTC (rev 979)
+++ trunk/python/client/proclaimer.tac 2006-05-22 02:11:59 UTC (rev 980)
@@ -0,0 +1,27 @@
+#!/usr/bin/python2.4
+
+from haver.client import *
+from haver.qtui import HaverQt
+from twisted.application import service, internet
+
+application = service.Application("proclaimer")
+app = service.IService(application)
+#sc = service.IServiceCollection(application)
+#proc = service.IProcess(application)
+#per = sob.IPersistable(application)
+
+formatter = Formatter()
+ui = HaverQt("Proclaimer", formatter)
+import twisted.internet.reactor
+ui.setup(twisted.internet.reactor)
+# Create the protocol factory
+client = QtClient("Proclaimer")
+factory.protocol = Protocol
+
+# Create the (sole) client
+# Normally, the echo protocol lives on port 7, but since that
+# is a privileged port, for this example we'll use port 7001
+client = internet.TCPClient("hardison.net", 7575, factory)
+
+# Tie the service to the application
+client.setServiceParent(app)
Property changes on: trunk/python/client/proclaimer.tac
___________________________________________________________________
Name: svn:mime-type
+ text/script
Added: trunk/python/server/.todo
===================================================================
--- trunk/python/server/.todo 2006-03-20 21:04:28 UTC (rev 979)
+++ trunk/python/server/.todo 2006-05-22 02:11:59 UTC (rev 980)
@@ -0,0 +1,11 @@
+<todo version="0.1.19">
+ <note priority="high" time="1148263802">
+ Bug: when a client connection crashes (raises an exception), make sure
to remove a user from all joined channels...
+ </note>
+ <note priority="high" time="1148263853">
+ Bug: PART main shows unknown.user main...
+ </note>
+ <note priority="medium" time="1148263612">
+ Add a command to list groups a user belongs to.
+ </note>
+</todo>
Added: trunk/python/server/TODO
===================================================================
--- trunk/python/server/TODO 2006-03-20 21:04:28 UTC (rev 979)
+++ trunk/python/server/TODO 2006-05-22 02:11:59 UTC (rev 980)
@@ -0,0 +1,9 @@
+- Bug: when a client connection crashes (raises an exception), make sure to
remove a user from all joined channels...
+ (added Sun May 21 22:10:02 2006, incomplete, priority high)
+
+- Bug: PART main shows unknown.user main...
+ (added Sun May 21 22:10:53 2006, incomplete, priority high)
+
+- Add a command to list groups a user belongs to.
+ (added Sun May 21 22:06:52 2006, incomplete, priority medium)
+
Added: trunk/python/server/haver/__init__.py
===================================================================
Added: trunk/python/server/haver/server/__init__.py
===================================================================
Added: trunk/python/server/haver/server/entity.py
===================================================================
--- trunk/python/server/haver/server/entity.py 2006-03-20 21:04:28 UTC (rev
979)
+++ trunk/python/server/haver/server/entity.py 2006-05-22 02:11:59 UTC (rev
980)
@@ -0,0 +1,156 @@
+from haver.server.errors import Fail, Bork
+import time, re
+
+namepattern = re.compile("^&?[A-Za-z][A-Za-z0-9_.'[EMAIL PROTECTED]")
+
+def assert_name(n):
+ if not namepattern.match(n):
+ raise Fail('invalid.name', n)
+
+def mask_ip(ip):
+ parts = ip.split('.')
+ assert len(parts) == 4
+ parts[3] = '*'
+ return '.'.join(parts)
+
+class Entity(object):
+ def __init__(self, name):
+ assert_name(name)
+ self.attr = {}
+ self.__name = name
+
+ def __str__(self):
+ return self.__name
+
+ def getName(self): return self.__name
+ def delName(self): del self.__name
+ def setName(self, name):
+ assert_name(name)
+ self.__name = name
+
+ def getInfo(self): return [ ]
+ name = property(getName, setName, delName, "I'm the 'name' property.")
+ info = property(lambda self: self.getInfo())
+
+class Avatar(Entity):
+ def __init__(self, name, address = '0.0.0.0', version = None, talker =
None):
+ Entity.__init__(self, name)
+
+ self.address = mask_ip(address)
+ self.real_address = address
+ self.version = version
+ self.talker = talker
+
+ def getInfo(self):
+ return [
+ 'version', self.version,
+ 'address', self.address,
+ ]
+
+ def sendMsg(self, *msg):
+ self.talker.sendMsg(*msg)
+
+class User(Avatar):
+ namespace = 'user'
+
+ def __init__(self, *args, **kwargs):
+ Avatar.__init__(self, *args, **kwargs)
+ self.email = None
+ self.lastActivity = int(time.time())
+ self.groups = set()
+
+ def joinGroup(self, group):
+ name = group.name.lower()
+ if name in self.groups:
+ raise Fail('already.joined', group.name)
+ else:
+ self.groups.add(name)
+ group.add(self)
+
+ def partGroup(self, group):
+ name = group.name.lower()
+ if name in self.groups:
+ self.groups.remove(name)
+ group.remove('user', name)
+ else:
+ raise Fail('already.parted', group.name)
+
+ def updateIdle(self):
+ self.lastActivity = int(time.time())
+
+ def getIdle(self):
+ return int(time.time()) - self.lastActivity
+
+ def getInfo(self):
+ infos = Avatar.getInfo(self)
+ if self.email is not None:
+ infos.extend(['email', self.email])
+
+ infos.extend([ 'idle', str( self.getIdle() )])
+
+ return infos
+
+ idle = property(getIdle)
+
+class Group(Entity):
+ namespace = 'group'
+
+ def __init__(self, name, owner = '&root'):
+ Entity.__init__(self, name)
+ self.owner = owner
+ self.__users = dict()
+ self.__members = dict(user = {}, group = {})
+
+ def getInfo(self):
+ infos = Entity.getInfo(self)
+ return infos + [ 'owner', self.owner ]
+
+ def sendMsg(self, *msg):
+ for user in self.members('user'):
+ user.sendMsg(*msg)
+
+ def _get_ns(self, ns):
+ try:
+ return self.__members[ns]
+ except KeyError:
+ raise Fail('invalid.namespace', ns)
+
+ def lookup(self, ns, name):
+ assert_name(name)
+ ents = self._get_ns(ns)
+ try:
+ return ents[ name.lower() ]
+ except KeyError:
+ raise Fail('unknown.%s' % ns, name)
+
+ def add(self, entity):
+ ns, name = (entity.namespace, entity.name.lower())
+
+ ents = self._get_ns(ns)
+ if ents.has_key(name):
+ raise Fail('exists.%s' % ns, entity.name)
+ ents[name] = entity
+
+ def remove(self, ns, name):
+ assert_name(name)
+ lname = name.lower()
+ ents = self._get_ns(ns)
+ try:
+ del ents[lname]
+ except KeyError:
+ raise Fail('unknown.%s' % ns, name)
+
+ def members(self, ns):
+ ents = self._get_ns(ns)
+ return ents.values()
+
+class Lobby(Group):
+ def __init__(self):
+ Group.__init__(self, '&lobby')
+
+ def lookup(self, ns, name):
+ if name == '&lobby':
+ return self
+ else:
+ return Group.lookup(self, ns, name)
+
Added: trunk/python/server/haver/server/errors.py
===================================================================
--- trunk/python/server/haver/server/errors.py 2006-03-20 21:04:28 UTC (rev
979)
+++ trunk/python/server/haver/server/errors.py 2006-05-22 02:11:59 UTC (rev
980)
@@ -0,0 +1,11 @@
+
+class Fail(Exception):
+ def __init__(self, name, *args):
+ self.name = name
+ self.args = args
+
+class Bork(Exception):
+ def __init__(self, msg):
+ self.msg = msg
+
+
Added: trunk/python/server/haver/server/factory.py
===================================================================
--- trunk/python/server/haver/server/factory.py 2006-03-20 21:04:28 UTC (rev
979)
+++ trunk/python/server/haver/server/factory.py 2006-05-22 02:11:59 UTC (rev
980)
@@ -0,0 +1,4 @@
+from twisted.internet.protocol import ReconnectingClientFactory
+from qt import *
+
+
Added: trunk/python/server/haver/server/states.py
===================================================================
--- trunk/python/server/haver/server/states.py 2006-03-20 21:04:28 UTC (rev
979)
+++ trunk/python/server/haver/server/states.py 2006-05-22 02:11:59 UTC (rev
980)
@@ -0,0 +1,152 @@
+from haver.server.entity import User, Group
+from haver.server.errors import Fail, Bork
+
+class State:
+ def __init__(self, talker):
+ self.talker = talker
+ self.factory = talker.factory
+
+ def sendMsg(self, *args):
+ self.talker.sendMsg(*args)
+
+ def switchState(self, stateClass):
+ print "Switching state to %s" % stateClass.__name__
+ state = stateClass(self.talker)
+ self.talker.state = state
+
+ def default_msg(self, name, args):
+ print "unknown message: %s" % name
+
+class ConnectedState(State):
+
+ def msg_HAVER(self, args):
+ self.sendMsg('HAVER', "hardison.net", 'Twisted Haver/0.1')
+ self.talker.version = args[0]
+ try:
+ self.talker.supports = args[1].split(',')
+ except IndexError:
+ self.talker.supports = []
+
+
+ self.switchState(LoginState)
+
+ def default_msg(self, name, args):
+ self.talker.transport.loseConnection()
+
+class LoginState(State):
+
+ def msg_IDENT(self, args):
+ name = args[0]
+ lobby = self.factory.lobby
+
+ user = User(name,
+ version = self.talker.version,
+ address = self.talker.addr.host,
+ talker = self)
+ lobby.add(user)
+
+ self.talker.user = user
+
+ self.sendMsg('HELLO', name)
+ self.switchState(NormalState)
+
+
+
+class NormalState(State):
+
+ def msg_TO(self, args):
+ target, kind = args[0:2]
+ msg = args[2:]
+ lobby = self.factory.lobby
+ self.talker.user.updateIdle()
+ user = lobby.lookup('user', target)
+ user.sendMsg('FROM', self.talker.user.name, kind, *msg)
+
+ def msg_IN(self, args):
+ target, kind = args[0:2]
+ msg = args[2:]
+ lobby = self.factory.lobby
+ self.talker.user.updateIdle()
+ group = lobby.lookup('group', target)
+ group.sendMsg('IN', group.name, self.talker.user.name, kind,
*msg)
+
+ def msg_JOIN(self, args):
+ name = args[0]
+ lobby = self.factory.lobby
+ user = self.talker.user
+ user.updateIdle()
+ group = lobby.lookup('group', name)
+ user.joinGroup(group)
+ group.sendMsg('JOIN', name, user.name)
+
+ def msg_PART(self, args):
+ name = args[0]
+ lobby = self.factory.lobby
+ user = self.talker.user
+ user.updateIdle()
+ group = lobby.lookup('group', name)
+ user = user.partGroup(group)
+
+ for x in [user, group]:
+ x.sendMsg('PART', name, user.name)
+
+ def msg_OPEN(self, args):
+ name = args[0]
+ lobby = self.factory.lobby
+ user = self.talker.user
+ group = Group(name, owner = user.name)
+
+ lobby.add(group)
+ user.sendMsg('OPEN', name)
+
+ def msg_INFO(self, args):
+ ns, name = args[0:2]
+ if ns == 'channel':
+ ns = 'group'
+
+ self.talker.user.updateIdle()
+ entity = self.factory.lobby.lookup(ns, name)
+ infos = entity.info
+
+ self.sendMsg('INFO', ns, name, *infos)
+
+ def msg_LIST(self, args):
+ name, ns = args
+ if ns == 'channel':
+ ns = 'group'
+
+ if ns == 'user':
+ msg = 'You might want to try USERS %s' % name
+ elif ns == 'group':
+ msg = 'You might want to try GROUPS' % name
+
+ group = self.factory.lobby.lookup('group', name)
+ self.talker.sendMsg('FROM', '&', 'say', msg)
+ names = [ x.name for x in group.members(ns) ]
+ self.talker.sendMsg('LIST', name, ns, *names)
+
+ def msg_USERS(self, args):
+ name = args[0]
+ group = self.factory.lobby.lookup('group', name)
+ names = [ x.name for x in group.members('user') ]
+ self.talker.sendMsg('USERS', *names)
+
+ def msg_GROUPS(self, args):
+ lobby = self.factory.lobby
+ names = [ x.name for x in lobby.members('group') ]
+ self.talker.sendMsg('GROUPS', *names)
+
+ def msg_SERVICES(self, args):
+ lobby = self.factory.lobby
+ names = [ x.name for x in lobby.members('service') ]
+ self.talker.sendMsg('SERVICES', *names)
+
+ def msg_POKE(self, args):
+ self.sendMsg('OUCH', *args)
+
+ def msg_BYE(self, args):
+ if args: detail = args[0]
+ else: detail = None
+
+ self.talker.quit('bye', detail)
+
Added: trunk/python/server/haver/server/talker.py
===================================================================
--- trunk/python/server/haver/server/talker.py 2006-03-20 21:04:28 UTC (rev
979)
+++ trunk/python/server/haver/server/talker.py 2006-05-22 02:11:59 UTC (rev
980)
@@ -0,0 +1,90 @@
+import re
+
+from twisted.python import log
+from twisted.protocols.basic import LineReceiver
+from twisted.internet.protocol import Factory
+from haver.server.errors import Fail, Bork
+from haver.server.states import *
+
+class HaverServerFactory(Factory):
+
+ def __init__(self, lobby):
+ self.lobby = lobby
+
+ def buildProtocol(self, addr):
+ p = self.protocol(addr)
+ p.factory = self
+ return p
+
+
+class HaverServer(LineReceiver):
+ def __init__(self, addr):
+ self.addr = addr
+ self.cmdpat = re.compile('^[A-Z][A-Z:_-]+$')
+
+
+ def lineReceived(self, line):
+ try:
+ if len(line) == 0:
+ print "Got empty line"
+ raise Bork('Your line is empty')
+
+ msg = line.split("\t")
+ name = msg[0]
+ method = "msg_" + name
+ state = self.state
+
+ if not self.cmdpat.match(name):
+ print "This is an example of a badly formed
command: %s" % name
+ raise Bork("You're not the man I married!")
+
+ self.cmd = name
+ if hasattr(state, method):
+ f = getattr(state, method)
+ f(msg[1:])
+ else:
+ state.default_msg(msg[0], msg[1:])
+
+ except Fail, failure:
+ log.msg('Command %s failed with failure %s' %
(self.cmd, failure.name))
+ self.sendMsg('FAIL', self.cmd, failure.name,
*failure.args)
+ except Bork, bork:
+ log.msg('Borking client: %s' % bork.msg)
+ if not isinstance(self.state, ConnectedState):
+ self.sendMsg('BORK', bork.msg)
+ self.transport.loseConnection()
+
+ def sendMsg(self, *msg):
+ self.sendLine("\t".join(msg))
+
+ def quit(self, reason, detail = None):
+ log.msg("Client quits, reason = %s" % reason)
+ user = self.user
+ if detail is None:
+ args = [reason]
+ else:
+ args = [reason, detail]
+
+ self.sendMsg('BYE', *args)
+ name = user.name
+ for group in user.members('group'):
+ user.partGroup(group)
+ group.sendMsg('QUIT', name, *args)
+
+ def connectionMade(self):
+ log.msg('New client from ' + str(self.addr))
+ self.state = ConnectedState(self)
+
+ def connectionLost(self, reason):
+ log.msg('Lost client from ' + str(self.addr))
+
+ try:
+ user = self.user
+ lobby = self.factory.lobby
+ lobby.remove(user.namespace, user.name)
+ del self.user
+ except AttributeError:
+ pass
+
+ del self.state
+
Added: trunk/python/server/haver.tac
===================================================================
--- trunk/python/server/haver.tac 2006-03-20 21:04:28 UTC (rev 979)
+++ trunk/python/server/haver.tac 2006-05-22 02:11:59 UTC (rev 980)
@@ -0,0 +1,30 @@
+#!/usr/bin/python2.4
+from haver.server.talker import HaverServerFactory, HaverServer
+from haver.server.entity import Lobby, Group
+from twisted.application import service, internet
+from twisted.persisted import sob
+
+application = service.Application("haverd")
+service = service.IService(application)
+#sc = service.IServiceCollection(application)
+#proc = service.IProcess(application)
+applicationper = sob.IPersistable(application)
+
+
+lobby = Lobby()
+main = Group('main')
+lobby.add(main)
+factory = HaverServerFactory(lobby)
+factory.protocol = HaverServer
+
+# Create the (sole) client
+# Normally, the echo protocol lives on port 7, but since that
+# is a privileged port, for this example we'll use port 7001
+
+servers = [
+ internet.TCPServer(7575, factory)
+]
+
+# Tie the service to the application
+for server in servers:
+ server.setServiceParent(service)
Property changes on: trunk/python/server/haver.tac
___________________________________________________________________
Name: svn:mime-type
+ text/script
_______________________________________________
Haver-commits mailing list
[email protected]
https://mail.gna.org/listinfo/haver-commits