diff options
Diffstat (limited to 'lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/words/service.py')
-rwxr-xr-x | lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/words/service.py | 1223 |
1 files changed, 0 insertions, 1223 deletions
diff --git a/lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/words/service.py b/lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/words/service.py deleted file mode 100755 index 0e4f8b6a..00000000 --- a/lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/words/service.py +++ /dev/null @@ -1,1223 +0,0 @@ -# -*- test-case-name: twisted.words.test.test_service -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -A module that needs a better name. - -Implements new cred things for words. - -How does this thing work? - - - Network connection on some port expecting to speak some protocol - - - Protocol-specific authentication, resulting in some kind of credentials object - - - twisted.cred.portal login using those credentials for the interface - IUser and with something implementing IChatClient as the mind - - - successful login results in an IUser avatar the protocol can call - methods on, and state added to the realm such that the mind will have - methods called on it as is necessary - - - protocol specific actions lead to calls onto the avatar; remote events - lead to calls onto the mind - - - protocol specific hangup, realm is notified, user is removed from active - play, the end. -""" - -from time import time, ctime - -from zope.interface import implements - -from twisted.words import iwords, ewords - -from twisted.python.components import registerAdapter -from twisted.cred import portal, credentials, error as ecred -from twisted.spread import pb -from twisted.words.protocols import irc -from twisted.internet import defer, protocol -from twisted.python import log, failure, reflect -from twisted import copyright - - -class Group(object): - implements(iwords.IGroup) - - def __init__(self, name): - self.name = name - self.users = {} - self.meta = { - "topic": "", - "topic_author": "", - } - - - def _ebUserCall(self, err, p): - return failure.Failure(Exception(p, err)) - - - def _cbUserCall(self, results): - for (success, result) in results: - if not success: - user, err = result.value # XXX - self.remove(user, err.getErrorMessage()) - - - def add(self, user): - assert iwords.IChatClient.providedBy(user), "%r is not a chat client" % (user,) - if user.name not in self.users: - additions = [] - self.users[user.name] = user - for p in self.users.itervalues(): - if p is not user: - d = defer.maybeDeferred(p.userJoined, self, user) - d.addErrback(self._ebUserCall, p=p) - additions.append(d) - defer.DeferredList(additions).addCallback(self._cbUserCall) - return defer.succeed(None) - - - def remove(self, user, reason=None): - assert reason is None or isinstance(reason, unicode) - try: - del self.users[user.name] - except KeyError: - pass - else: - removals = [] - for p in self.users.itervalues(): - if p is not user: - d = defer.maybeDeferred(p.userLeft, self, user, reason) - d.addErrback(self._ebUserCall, p=p) - removals.append(d) - defer.DeferredList(removals).addCallback(self._cbUserCall) - return defer.succeed(None) - - - def size(self): - return defer.succeed(len(self.users)) - - - def receive(self, sender, recipient, message): - assert recipient is self - receives = [] - for p in self.users.itervalues(): - if p is not sender: - d = defer.maybeDeferred(p.receive, sender, self, message) - d.addErrback(self._ebUserCall, p=p) - receives.append(d) - defer.DeferredList(receives).addCallback(self._cbUserCall) - return defer.succeed(None) - - - def setMetadata(self, meta): - self.meta = meta - sets = [] - for p in self.users.itervalues(): - d = defer.maybeDeferred(p.groupMetaUpdate, self, meta) - d.addErrback(self._ebUserCall, p=p) - sets.append(d) - defer.DeferredList(sets).addCallback(self._cbUserCall) - return defer.succeed(None) - - - def iterusers(self): - # XXX Deferred? - return iter(self.users.values()) - - -class User(object): - implements(iwords.IUser) - - realm = None - mind = None - - def __init__(self, name): - self.name = name - self.groups = [] - self.lastMessage = time() - - - def loggedIn(self, realm, mind): - self.realm = realm - self.mind = mind - self.signOn = time() - - - def join(self, group): - def cbJoin(result): - self.groups.append(group) - return result - return group.add(self.mind).addCallback(cbJoin) - - - def leave(self, group, reason=None): - def cbLeave(result): - self.groups.remove(group) - return result - return group.remove(self.mind, reason).addCallback(cbLeave) - - - def send(self, recipient, message): - self.lastMessage = time() - return recipient.receive(self.mind, recipient, message) - - - def itergroups(self): - return iter(self.groups) - - - def logout(self): - for g in self.groups[:]: - self.leave(g) - - -NICKSERV = 'NickServ!NickServ@services' - - -class IRCUser(irc.IRC): - """ - Protocol instance representing an IRC user connected to the server. - """ - implements(iwords.IChatClient) - - # A list of IGroups in which I am participating - groups = None - - # A no-argument callable I should invoke when I go away - logout = None - - # An IUser we use to interact with the chat service - avatar = None - - # To whence I belong - realm = None - - # How to handle unicode (TODO: Make this customizable on a per-user basis) - encoding = 'utf-8' - - # Twisted callbacks - def connectionMade(self): - self.irc_PRIVMSG = self.irc_NICKSERV_PRIVMSG - self.realm = self.factory.realm - self.hostname = self.realm.name - - - def connectionLost(self, reason): - if self.logout is not None: - self.logout() - self.avatar = None - - - # Make sendMessage a bit more useful to us - def sendMessage(self, command, *parameter_list, **kw): - if 'prefix' not in kw: - kw['prefix'] = self.hostname - if 'to' not in kw: - kw['to'] = self.name.encode(self.encoding) - - arglist = [self, command, kw['to']] + list(parameter_list) - irc.IRC.sendMessage(*arglist, **kw) - - - # IChatClient implementation - def userJoined(self, group, user): - self.join( - "%s!%s@%s" % (user.name, user.name, self.hostname), - '#' + group.name) - - - def userLeft(self, group, user, reason=None): - assert reason is None or isinstance(reason, unicode) - self.part( - "%s!%s@%s" % (user.name, user.name, self.hostname), - '#' + group.name, - (reason or u"leaving").encode(self.encoding, 'replace')) - - - def receive(self, sender, recipient, message): - #>> :glyph!glyph@adsl-64-123-27-108.dsl.austtx.swbell.net PRIVMSG glyph_ :hello - - # omg??????????? - if iwords.IGroup.providedBy(recipient): - recipientName = '#' + recipient.name - else: - recipientName = recipient.name - - text = message.get('text', '<an unrepresentable message>') - for L in text.splitlines(): - self.privmsg( - '%s!%s@%s' % (sender.name, sender.name, self.hostname), - recipientName, - L) - - - def groupMetaUpdate(self, group, meta): - if 'topic' in meta: - topic = meta['topic'] - author = meta.get('topic_author', '') - self.topic( - self.name, - '#' + group.name, - topic, - '%s!%s@%s' % (author, author, self.hostname) - ) - - # irc.IRC callbacks - starting with login related stuff. - nickname = None - password = None - - def irc_PASS(self, prefix, params): - """Password message -- Register a password. - - Parameters: <password> - - [REQUIRED] - - Note that IRC requires the client send this *before* NICK - and USER. - """ - self.password = params[-1] - - - def irc_NICK(self, prefix, params): - """Nick message -- Set your nickname. - - Parameters: <nickname> - - [REQUIRED] - """ - try: - nickname = params[0].decode(self.encoding) - except UnicodeDecodeError: - self.privmsg( - NICKSERV, - nickname, - 'Your nickname is cannot be decoded. Please use ASCII or UTF-8.') - self.transport.loseConnection() - return - - self.nickname = nickname - self.name = nickname - - for code, text in self._motdMessages: - self.sendMessage(code, text % self.factory._serverInfo) - - if self.password is None: - self.privmsg( - NICKSERV, - nickname, - 'Password?') - else: - password = self.password - self.password = None - self.logInAs(nickname, password) - - - def irc_USER(self, prefix, params): - """User message -- Set your realname. - - Parameters: <user> <mode> <unused> <realname> - """ - # Note: who gives a crap about this? The IUser has the real - # information we care about. Save it anyway, I guess, just - # for fun. - self.realname = params[-1] - - - def irc_NICKSERV_PRIVMSG(self, prefix, params): - """Send a (private) message. - - Parameters: <msgtarget> <text to be sent> - """ - target = params[0] - password = params[-1] - - if self.nickname is None: - # XXX Send an error response here - self.transport.loseConnection() - elif target.lower() != "nickserv": - self.privmsg( - NICKSERV, - self.nickname, - "Denied. Please send me (NickServ) your password.") - else: - nickname = self.nickname - self.nickname = None - self.logInAs(nickname, password) - - - def logInAs(self, nickname, password): - d = self.factory.portal.login( - credentials.UsernamePassword(nickname, password), - self, - iwords.IUser) - d.addCallbacks(self._cbLogin, self._ebLogin, errbackArgs=(nickname,)) - - - _welcomeMessages = [ - (irc.RPL_WELCOME, - ":connected to Twisted IRC"), - (irc.RPL_YOURHOST, - ":Your host is %(serviceName)s, running version %(serviceVersion)s"), - (irc.RPL_CREATED, - ":This server was created on %(creationDate)s"), - - # "Bummer. This server returned a worthless 004 numeric. - # I'll have to guess at all the values" - # -- epic - (irc.RPL_MYINFO, - # w and n are the currently supported channel and user modes - # -- specify this better - "%(serviceName)s %(serviceVersion)s w n") - ] - - _motdMessages = [ - (irc.RPL_MOTDSTART, - ":- %(serviceName)s Message of the Day - "), - (irc.RPL_ENDOFMOTD, - ":End of /MOTD command.") - ] - - def _cbLogin(self, (iface, avatar, logout)): - assert iface is iwords.IUser, "Realm is buggy, got %r" % (iface,) - - # Let them send messages to the world - del self.irc_PRIVMSG - - self.avatar = avatar - self.logout = logout - for code, text in self._welcomeMessages: - self.sendMessage(code, text % self.factory._serverInfo) - - - def _ebLogin(self, err, nickname): - if err.check(ewords.AlreadyLoggedIn): - self.privmsg( - NICKSERV, - nickname, - "Already logged in. No pod people allowed!") - elif err.check(ecred.UnauthorizedLogin): - self.privmsg( - NICKSERV, - nickname, - "Login failed. Goodbye.") - else: - log.msg("Unhandled error during login:") - log.err(err) - self.privmsg( - NICKSERV, - nickname, - "Server error during login. Sorry.") - self.transport.loseConnection() - - - # Great, now that's out of the way, here's some of the interesting - # bits - def irc_PING(self, prefix, params): - """Ping message - - Parameters: <server1> [ <server2> ] - """ - if self.realm is not None: - self.sendMessage('PONG', self.hostname) - - - def irc_QUIT(self, prefix, params): - """Quit - - Parameters: [ <Quit Message> ] - """ - self.transport.loseConnection() - - - def _channelMode(self, group, modes=None, *args): - if modes: - self.sendMessage( - irc.ERR_UNKNOWNMODE, - ":Unknown MODE flag.") - else: - self.channelMode(self.name, '#' + group.name, '+') - - - def _userMode(self, user, modes=None): - if modes: - self.sendMessage( - irc.ERR_UNKNOWNMODE, - ":Unknown MODE flag.") - elif user is self.avatar: - self.sendMessage( - irc.RPL_UMODEIS, - "+") - else: - self.sendMessage( - irc.ERR_USERSDONTMATCH, - ":You can't look at someone else's modes.") - - - def irc_MODE(self, prefix, params): - """User mode message - - Parameters: <nickname> - *( ( "+" / "-" ) *( "i" / "w" / "o" / "O" / "r" ) ) - - """ - try: - channelOrUser = params[0].decode(self.encoding) - except UnicodeDecodeError: - self.sendMessage( - irc.ERR_NOSUCHNICK, params[0], - ":No such nickname (could not decode your unicode!)") - return - - if channelOrUser.startswith('#'): - def ebGroup(err): - err.trap(ewords.NoSuchGroup) - self.sendMessage( - irc.ERR_NOSUCHCHANNEL, params[0], - ":That channel doesn't exist.") - d = self.realm.lookupGroup(channelOrUser[1:]) - d.addCallbacks( - self._channelMode, - ebGroup, - callbackArgs=tuple(params[1:])) - else: - def ebUser(err): - self.sendMessage( - irc.ERR_NOSUCHNICK, - ":No such nickname.") - - d = self.realm.lookupUser(channelOrUser) - d.addCallbacks( - self._userMode, - ebUser, - callbackArgs=tuple(params[1:])) - - - def irc_USERHOST(self, prefix, params): - """Userhost message - - Parameters: <nickname> *( SPACE <nickname> ) - - [Optional] - """ - pass - - - def irc_PRIVMSG(self, prefix, params): - """Send a (private) message. - - Parameters: <msgtarget> <text to be sent> - """ - try: - targetName = params[0].decode(self.encoding) - except UnicodeDecodeError: - self.sendMessage( - irc.ERR_NOSUCHNICK, params[0], - ":No such nick/channel (could not decode your unicode!)") - return - - messageText = params[-1] - if targetName.startswith('#'): - target = self.realm.lookupGroup(targetName[1:]) - else: - target = self.realm.lookupUser(targetName).addCallback(lambda user: user.mind) - - def cbTarget(targ): - if targ is not None: - return self.avatar.send(targ, {"text": messageText}) - - def ebTarget(err): - self.sendMessage( - irc.ERR_NOSUCHNICK, targetName, - ":No such nick/channel.") - - target.addCallbacks(cbTarget, ebTarget) - - - def irc_JOIN(self, prefix, params): - """Join message - - Parameters: ( <channel> *( "," <channel> ) [ <key> *( "," <key> ) ] ) - """ - try: - groupName = params[0].decode(self.encoding) - except UnicodeDecodeError: - self.sendMessage( - irc.ERR_NOSUCHCHANNEL, params[0], - ":No such channel (could not decode your unicode!)") - return - - if groupName.startswith('#'): - groupName = groupName[1:] - - def cbGroup(group): - def cbJoin(ign): - self.userJoined(group, self) - self.names( - self.name, - '#' + group.name, - [user.name for user in group.iterusers()]) - self._sendTopic(group) - return self.avatar.join(group).addCallback(cbJoin) - - def ebGroup(err): - self.sendMessage( - irc.ERR_NOSUCHCHANNEL, '#' + groupName, - ":No such channel.") - - self.realm.getGroup(groupName).addCallbacks(cbGroup, ebGroup) - - - def irc_PART(self, prefix, params): - """Part message - - Parameters: <channel> *( "," <channel> ) [ <Part Message> ] - """ - try: - groupName = params[0].decode(self.encoding) - except UnicodeDecodeError: - self.sendMessage( - irc.ERR_NOTONCHANNEL, params[0], - ":Could not decode your unicode!") - return - - if groupName.startswith('#'): - groupName = groupName[1:] - - if len(params) > 1: - reason = params[1].decode('utf-8') - else: - reason = None - - def cbGroup(group): - def cbLeave(result): - self.userLeft(group, self, reason) - return self.avatar.leave(group, reason).addCallback(cbLeave) - - def ebGroup(err): - err.trap(ewords.NoSuchGroup) - self.sendMessage( - irc.ERR_NOTONCHANNEL, - '#' + groupName, - ":" + err.getErrorMessage()) - - self.realm.lookupGroup(groupName).addCallbacks(cbGroup, ebGroup) - - - def irc_NAMES(self, prefix, params): - """Names message - - Parameters: [ <channel> *( "," <channel> ) [ <target> ] ] - """ - #<< NAMES #python - #>> :benford.openprojects.net 353 glyph = #python :Orban ... @glyph ... Zymurgy skreech - #>> :benford.openprojects.net 366 glyph #python :End of /NAMES list. - try: - channel = params[-1].decode(self.encoding) - except UnicodeDecodeError: - self.sendMessage( - irc.ERR_NOSUCHCHANNEL, params[-1], - ":No such channel (could not decode your unicode!)") - return - - if channel.startswith('#'): - channel = channel[1:] - - def cbGroup(group): - self.names( - self.name, - '#' + group.name, - [user.name for user in group.iterusers()]) - - def ebGroup(err): - err.trap(ewords.NoSuchGroup) - # No group? Fine, no names! - self.names( - self.name, - '#' + channel, - []) - - self.realm.lookupGroup(channel).addCallbacks(cbGroup, ebGroup) - - - def irc_TOPIC(self, prefix, params): - """Topic message - - Parameters: <channel> [ <topic> ] - """ - try: - channel = params[0].decode(self.encoding) - except UnicodeDecodeError: - self.sendMessage( - irc.ERR_NOSUCHCHANNEL, - ":That channel doesn't exist (could not decode your unicode!)") - return - - if channel.startswith('#'): - channel = channel[1:] - - if len(params) > 1: - self._setTopic(channel, params[1]) - else: - self._getTopic(channel) - - - def _sendTopic(self, group): - """ - Send the topic of the given group to this user, if it has one. - """ - topic = group.meta.get("topic") - if topic: - author = group.meta.get("topic_author") or "<noone>" - date = group.meta.get("topic_date", 0) - self.topic(self.name, '#' + group.name, topic) - self.topicAuthor(self.name, '#' + group.name, author, date) - - - def _getTopic(self, channel): - #<< TOPIC #python - #>> :benford.openprojects.net 332 glyph #python :<churchr> I really did. I sprained all my toes. - #>> :benford.openprojects.net 333 glyph #python itamar|nyc 994713482 - def ebGroup(err): - err.trap(ewords.NoSuchGroup) - self.sendMessage( - irc.ERR_NOSUCHCHANNEL, '=', channel, - ":That channel doesn't exist.") - - self.realm.lookupGroup(channel).addCallbacks(self._sendTopic, ebGroup) - - - def _setTopic(self, channel, topic): - #<< TOPIC #divunal :foo - #>> :glyph!glyph@adsl-64-123-27-108.dsl.austtx.swbell.net TOPIC #divunal :foo - - def cbGroup(group): - newMeta = group.meta.copy() - newMeta['topic'] = topic - newMeta['topic_author'] = self.name - newMeta['topic_date'] = int(time()) - - def ebSet(err): - self.sendMessage( - irc.ERR_CHANOPRIVSNEEDED, - "#" + group.name, - ":You need to be a channel operator to do that.") - - return group.setMetadata(newMeta).addErrback(ebSet) - - def ebGroup(err): - err.trap(ewords.NoSuchGroup) - self.sendMessage( - irc.ERR_NOSUCHCHANNEL, '=', channel, - ":That channel doesn't exist.") - - self.realm.lookupGroup(channel).addCallbacks(cbGroup, ebGroup) - - - def list(self, channels): - """Send a group of LIST response lines - - @type channel: C{list} of C{(str, int, str)} - @param channel: Information about the channels being sent: - their name, the number of participants, and their topic. - """ - for (name, size, topic) in channels: - self.sendMessage(irc.RPL_LIST, name, str(size), ":" + topic) - self.sendMessage(irc.RPL_LISTEND, ":End of /LIST") - - - def irc_LIST(self, prefix, params): - """List query - - Return information about the indicated channels, or about all - channels if none are specified. - - Parameters: [ <channel> *( "," <channel> ) [ <target> ] ] - """ - #<< list #python - #>> :orwell.freenode.net 321 exarkun Channel :Users Name - #>> :orwell.freenode.net 322 exarkun #python 358 :The Python programming language - #>> :orwell.freenode.net 323 exarkun :End of /LIST - if params: - # Return information about indicated channels - try: - channels = params[0].decode(self.encoding).split(',') - except UnicodeDecodeError: - self.sendMessage( - irc.ERR_NOSUCHCHANNEL, params[0], - ":No such channel (could not decode your unicode!)") - return - - groups = [] - for ch in channels: - if ch.startswith('#'): - ch = ch[1:] - groups.append(self.realm.lookupGroup(ch)) - - groups = defer.DeferredList(groups, consumeErrors=True) - groups.addCallback(lambda gs: [r for (s, r) in gs if s]) - else: - # Return information about all channels - groups = self.realm.itergroups() - - def cbGroups(groups): - def gotSize(size, group): - return group.name, size, group.meta.get('topic') - d = defer.DeferredList([ - group.size().addCallback(gotSize, group) for group in groups]) - d.addCallback(lambda results: self.list([r for (s, r) in results if s])) - return d - groups.addCallback(cbGroups) - - - def _channelWho(self, group): - self.who(self.name, '#' + group.name, - [(m.name, self.hostname, self.realm.name, m.name, "H", 0, m.name) for m in group.iterusers()]) - - - def _userWho(self, user): - self.sendMessage(irc.RPL_ENDOFWHO, - ":User /WHO not implemented") - - - def irc_WHO(self, prefix, params): - """Who query - - Parameters: [ <mask> [ "o" ] ] - """ - #<< who #python - #>> :x.opn 352 glyph #python aquarius pc-62-31-193-114-du.blueyonder.co.uk y.opn Aquarius H :3 Aquarius - # ... - #>> :x.opn 352 glyph #python foobar europa.tranquility.net z.opn skreech H :0 skreech - #>> :x.opn 315 glyph #python :End of /WHO list. - ### also - #<< who glyph - #>> :x.opn 352 glyph #python glyph adsl-64-123-27-108.dsl.austtx.swbell.net x.opn glyph H :0 glyph - #>> :x.opn 315 glyph glyph :End of /WHO list. - if not params: - self.sendMessage(irc.RPL_ENDOFWHO, ":/WHO not supported.") - return - - try: - channelOrUser = params[0].decode(self.encoding) - except UnicodeDecodeError: - self.sendMessage( - irc.RPL_ENDOFWHO, params[0], - ":End of /WHO list (could not decode your unicode!)") - return - - if channelOrUser.startswith('#'): - def ebGroup(err): - err.trap(ewords.NoSuchGroup) - self.sendMessage( - irc.RPL_ENDOFWHO, channelOrUser, - ":End of /WHO list.") - d = self.realm.lookupGroup(channelOrUser[1:]) - d.addCallbacks(self._channelWho, ebGroup) - else: - def ebUser(err): - err.trap(ewords.NoSuchUser) - self.sendMessage( - irc.RPL_ENDOFWHO, channelOrUser, - ":End of /WHO list.") - d = self.realm.lookupUser(channelOrUser) - d.addCallbacks(self._userWho, ebUser) - - - - def irc_WHOIS(self, prefix, params): - """Whois query - - Parameters: [ <target> ] <mask> *( "," <mask> ) - """ - def cbUser(user): - self.whois( - self.name, - user.name, user.name, self.realm.name, - user.name, self.realm.name, 'Hi mom!', False, - int(time() - user.lastMessage), user.signOn, - ['#' + group.name for group in user.itergroups()]) - - def ebUser(err): - err.trap(ewords.NoSuchUser) - self.sendMessage( - irc.ERR_NOSUCHNICK, - params[0], - ":No such nick/channel") - - try: - user = params[0].decode(self.encoding) - except UnicodeDecodeError: - self.sendMessage( - irc.ERR_NOSUCHNICK, - params[0], - ":No such nick/channel") - return - - self.realm.lookupUser(user).addCallbacks(cbUser, ebUser) - - - # Unsupported commands, here for legacy compatibility - def irc_OPER(self, prefix, params): - """Oper message - - Parameters: <name> <password> - """ - self.sendMessage(irc.ERR_NOOPERHOST, ":O-lines not applicable") - - -class IRCFactory(protocol.ServerFactory): - """ - IRC server that creates instances of the L{IRCUser} protocol. - - @ivar _serverInfo: A dictionary mapping: - "serviceName" to the name of the server, - "serviceVersion" to the copyright version, - "creationDate" to the time that the server was started. - """ - protocol = IRCUser - - def __init__(self, realm, portal): - self.realm = realm - self.portal = portal - self._serverInfo = { - "serviceName": self.realm.name, - "serviceVersion": copyright.version, - "creationDate": ctime() - } - - - -class PBMind(pb.Referenceable): - def __init__(self): - pass - - def jellyFor(self, jellier): - return reflect.qual(PBMind), jellier.invoker.registerReference(self) - - def remote_userJoined(self, user, group): - pass - - def remote_userLeft(self, user, group, reason): - pass - - def remote_receive(self, sender, recipient, message): - pass - - def remote_groupMetaUpdate(self, group, meta): - pass - - -class PBMindReference(pb.RemoteReference): - implements(iwords.IChatClient) - - def receive(self, sender, recipient, message): - if iwords.IGroup.providedBy(recipient): - rec = PBGroup(self.realm, self.avatar, recipient) - else: - rec = PBUser(self.realm, self.avatar, recipient) - return self.callRemote( - 'receive', - PBUser(self.realm, self.avatar, sender), - rec, - message) - - def groupMetaUpdate(self, group, meta): - return self.callRemote( - 'groupMetaUpdate', - PBGroup(self.realm, self.avatar, group), - meta) - - def userJoined(self, group, user): - return self.callRemote( - 'userJoined', - PBGroup(self.realm, self.avatar, group), - PBUser(self.realm, self.avatar, user)) - - def userLeft(self, group, user, reason=None): - assert reason is None or isinstance(reason, unicode) - return self.callRemote( - 'userLeft', - PBGroup(self.realm, self.avatar, group), - PBUser(self.realm, self.avatar, user), - reason) -pb.setUnjellyableForClass(PBMind, PBMindReference) - - -class PBGroup(pb.Referenceable): - def __init__(self, realm, avatar, group): - self.realm = realm - self.avatar = avatar - self.group = group - - - def processUniqueID(self): - return hash((self.realm.name, self.avatar.name, self.group.name)) - - - def jellyFor(self, jellier): - return reflect.qual(self.__class__), self.group.name.encode('utf-8'), jellier.invoker.registerReference(self) - - - def remote_leave(self, reason=None): - return self.avatar.leave(self.group, reason) - - - def remote_send(self, message): - return self.avatar.send(self.group, message) - - -class PBGroupReference(pb.RemoteReference): - implements(iwords.IGroup) - - def unjellyFor(self, unjellier, unjellyList): - clsName, name, ref = unjellyList - self.name = name.decode('utf-8') - return pb.RemoteReference.unjellyFor(self, unjellier, [clsName, ref]) - - def leave(self, reason=None): - return self.callRemote("leave", reason) - - def send(self, message): - return self.callRemote("send", message) -pb.setUnjellyableForClass(PBGroup, PBGroupReference) - -class PBUser(pb.Referenceable): - def __init__(self, realm, avatar, user): - self.realm = realm - self.avatar = avatar - self.user = user - - def processUniqueID(self): - return hash((self.realm.name, self.avatar.name, self.user.name)) - - -class ChatAvatar(pb.Referenceable): - implements(iwords.IChatClient) - - def __init__(self, avatar): - self.avatar = avatar - - - def jellyFor(self, jellier): - return reflect.qual(self.__class__), jellier.invoker.registerReference(self) - - - def remote_join(self, groupName): - assert isinstance(groupName, unicode) - def cbGroup(group): - def cbJoin(ignored): - return PBGroup(self.avatar.realm, self.avatar, group) - d = self.avatar.join(group) - d.addCallback(cbJoin) - return d - d = self.avatar.realm.getGroup(groupName) - d.addCallback(cbGroup) - return d -registerAdapter(ChatAvatar, iwords.IUser, pb.IPerspective) - -class AvatarReference(pb.RemoteReference): - def join(self, groupName): - return self.callRemote('join', groupName) - - def quit(self): - d = defer.Deferred() - self.broker.notifyOnDisconnect(lambda: d.callback(None)) - self.broker.transport.loseConnection() - return d - -pb.setUnjellyableForClass(ChatAvatar, AvatarReference) - - -class WordsRealm(object): - implements(portal.IRealm, iwords.IChatService) - - _encoding = 'utf-8' - - def __init__(self, name): - self.name = name - - - def userFactory(self, name): - return User(name) - - - def groupFactory(self, name): - return Group(name) - - - def logoutFactory(self, avatar, facet): - def logout(): - # XXX Deferred support here - getattr(facet, 'logout', lambda: None)() - avatar.realm = avatar.mind = None - return logout - - - def requestAvatar(self, avatarId, mind, *interfaces): - if isinstance(avatarId, str): - avatarId = avatarId.decode(self._encoding) - - def gotAvatar(avatar): - if avatar.realm is not None: - raise ewords.AlreadyLoggedIn() - for iface in interfaces: - facet = iface(avatar, None) - if facet is not None: - avatar.loggedIn(self, mind) - mind.name = avatarId - mind.realm = self - mind.avatar = avatar - return iface, facet, self.logoutFactory(avatar, facet) - raise NotImplementedError(self, interfaces) - - return self.getUser(avatarId).addCallback(gotAvatar) - - - # IChatService, mostly. - createGroupOnRequest = False - createUserOnRequest = True - - def lookupUser(self, name): - raise NotImplementedError - - - def lookupGroup(self, group): - raise NotImplementedError - - - def addUser(self, user): - """Add the given user to this service. - - This is an internal method intented to be overridden by - L{WordsRealm} subclasses, not called by external code. - - @type user: L{IUser} - - @rtype: L{twisted.internet.defer.Deferred} - @return: A Deferred which fires with C{None} when the user is - added, or which fails with - L{twisted.words.ewords.DuplicateUser} if a user with the - same name exists already. - """ - raise NotImplementedError - - - def addGroup(self, group): - """Add the given group to this service. - - @type group: L{IGroup} - - @rtype: L{twisted.internet.defer.Deferred} - @return: A Deferred which fires with C{None} when the group is - added, or which fails with - L{twisted.words.ewords.DuplicateGroup} if a group with the - same name exists already. - """ - raise NotImplementedError - - - def getGroup(self, name): - assert isinstance(name, unicode) - if self.createGroupOnRequest: - def ebGroup(err): - err.trap(ewords.DuplicateGroup) - return self.lookupGroup(name) - return self.createGroup(name).addErrback(ebGroup) - return self.lookupGroup(name) - - - def getUser(self, name): - assert isinstance(name, unicode) - if self.createUserOnRequest: - def ebUser(err): - err.trap(ewords.DuplicateUser) - return self.lookupUser(name) - return self.createUser(name).addErrback(ebUser) - return self.lookupUser(name) - - - def createUser(self, name): - assert isinstance(name, unicode) - def cbLookup(user): - return failure.Failure(ewords.DuplicateUser(name)) - def ebLookup(err): - err.trap(ewords.NoSuchUser) - return self.userFactory(name) - - name = name.lower() - d = self.lookupUser(name) - d.addCallbacks(cbLookup, ebLookup) - d.addCallback(self.addUser) - return d - - - def createGroup(self, name): - assert isinstance(name, unicode) - def cbLookup(group): - return failure.Failure(ewords.DuplicateGroup(name)) - def ebLookup(err): - err.trap(ewords.NoSuchGroup) - return self.groupFactory(name) - - name = name.lower() - d = self.lookupGroup(name) - d.addCallbacks(cbLookup, ebLookup) - d.addCallback(self.addGroup) - return d - - -class InMemoryWordsRealm(WordsRealm): - def __init__(self, *a, **kw): - super(InMemoryWordsRealm, self).__init__(*a, **kw) - self.users = {} - self.groups = {} - - - def itergroups(self): - return defer.succeed(self.groups.itervalues()) - - - def addUser(self, user): - if user.name in self.users: - return defer.fail(failure.Failure(ewords.DuplicateUser())) - self.users[user.name] = user - return defer.succeed(user) - - - def addGroup(self, group): - if group.name in self.groups: - return defer.fail(failure.Failure(ewords.DuplicateGroup())) - self.groups[group.name] = group - return defer.succeed(group) - - - def lookupUser(self, name): - assert isinstance(name, unicode) - name = name.lower() - try: - user = self.users[name] - except KeyError: - return defer.fail(failure.Failure(ewords.NoSuchUser(name))) - else: - return defer.succeed(user) - - - def lookupGroup(self, name): - assert isinstance(name, unicode) - name = name.lower() - try: - group = self.groups[name] - except KeyError: - return defer.fail(failure.Failure(ewords.NoSuchGroup(name))) - else: - return defer.succeed(group) - -__all__ = [ - 'Group', 'User', - - 'WordsRealm', 'InMemoryWordsRealm', - ] |