| 1 | # -*- test-case-name: twisted.words.test -*- |
|---|
| 2 | # Copyright (c) Twisted Matrix Laboratories. |
|---|
| 3 | # See LICENSE for details. |
|---|
| 4 | |
|---|
| 5 | from zope.interface import Interface, Attribute, implements |
|---|
| 6 | |
|---|
| 7 | class IProtocolPlugin(Interface): |
|---|
| 8 | """Interface for plugins providing an interface to a Words service |
|---|
| 9 | """ |
|---|
| 10 | |
|---|
| 11 | name = Attribute("A single word describing what kind of interface this is (eg, irc or web)") |
|---|
| 12 | |
|---|
| 13 | def getFactory(realm, portal): |
|---|
| 14 | """Retrieve a C{twisted.internet.interfaces.IServerFactory} provider |
|---|
| 15 | |
|---|
| 16 | @param realm: An object providing C{twisted.cred.portal.IRealm} and |
|---|
| 17 | C{IChatService}, with which service information should be looked up. |
|---|
| 18 | |
|---|
| 19 | @param portal: An object providing C{twisted.cred.portal.IPortal}, |
|---|
| 20 | through which logins should be performed. |
|---|
| 21 | """ |
|---|
| 22 | |
|---|
| 23 | |
|---|
| 24 | class IGroup(Interface): |
|---|
| 25 | name = Attribute("A short string, unique among groups.") |
|---|
| 26 | |
|---|
| 27 | def add(user): |
|---|
| 28 | """Include the given user in this group. |
|---|
| 29 | |
|---|
| 30 | @type user: L{IUser} |
|---|
| 31 | """ |
|---|
| 32 | |
|---|
| 33 | def remove(user, reason=None): |
|---|
| 34 | """Remove the given user from this group. |
|---|
| 35 | |
|---|
| 36 | @type user: L{IUser} |
|---|
| 37 | @type reason: C{unicode} |
|---|
| 38 | """ |
|---|
| 39 | |
|---|
| 40 | def size(): |
|---|
| 41 | """Return the number of participants in this group. |
|---|
| 42 | |
|---|
| 43 | @rtype: L{twisted.internet.defer.Deferred} |
|---|
| 44 | @return: A Deferred which fires with an C{int} representing the the |
|---|
| 45 | number of participants in this group. |
|---|
| 46 | """ |
|---|
| 47 | |
|---|
| 48 | def receive(sender, recipient, message): |
|---|
| 49 | """ |
|---|
| 50 | Broadcast the given message from the given sender to other |
|---|
| 51 | users in group. |
|---|
| 52 | |
|---|
| 53 | The message is not re-transmitted to the sender. |
|---|
| 54 | |
|---|
| 55 | @param sender: L{IUser} |
|---|
| 56 | |
|---|
| 57 | @type recipient: L{IGroup} |
|---|
| 58 | @param recipient: This is probably a wart. Maybe it will be removed |
|---|
| 59 | in the future. For now, it should be the group object the message |
|---|
| 60 | is being delivered to. |
|---|
| 61 | |
|---|
| 62 | @param message: C{dict} |
|---|
| 63 | |
|---|
| 64 | @rtype: L{twisted.internet.defer.Deferred} |
|---|
| 65 | @return: A Deferred which fires with None when delivery has been |
|---|
| 66 | attempted for all users. |
|---|
| 67 | """ |
|---|
| 68 | |
|---|
| 69 | def setMetadata(meta): |
|---|
| 70 | """Change the metadata associated with this group. |
|---|
| 71 | |
|---|
| 72 | @type meta: C{dict} |
|---|
| 73 | """ |
|---|
| 74 | |
|---|
| 75 | def iterusers(): |
|---|
| 76 | """Return an iterator of all users in this group. |
|---|
| 77 | """ |
|---|
| 78 | |
|---|
| 79 | |
|---|
| 80 | class IChatClient(Interface): |
|---|
| 81 | """Interface through which IChatService interacts with clients. |
|---|
| 82 | """ |
|---|
| 83 | |
|---|
| 84 | name = Attribute("A short string, unique among users. This will be set by the L{IChatService} at login time.") |
|---|
| 85 | |
|---|
| 86 | def receive(sender, recipient, message): |
|---|
| 87 | """ |
|---|
| 88 | Callback notifying this user of the given message sent by the |
|---|
| 89 | given user. |
|---|
| 90 | |
|---|
| 91 | This will be invoked whenever another user sends a message to a |
|---|
| 92 | group this user is participating in, or whenever another user sends |
|---|
| 93 | a message directly to this user. In the former case, C{recipient} |
|---|
| 94 | will be the group to which the message was sent; in the latter, it |
|---|
| 95 | will be the same object as the user who is receiving the message. |
|---|
| 96 | |
|---|
| 97 | @type sender: L{IUser} |
|---|
| 98 | @type recipient: L{IUser} or L{IGroup} |
|---|
| 99 | @type message: C{dict} |
|---|
| 100 | |
|---|
| 101 | @rtype: L{twisted.internet.defer.Deferred} |
|---|
| 102 | @return: A Deferred which fires when the message has been delivered, |
|---|
| 103 | or which fails in some way. If the Deferred fails and the message |
|---|
| 104 | was directed at a group, this user will be removed from that group. |
|---|
| 105 | """ |
|---|
| 106 | |
|---|
| 107 | def groupMetaUpdate(group, meta): |
|---|
| 108 | """ |
|---|
| 109 | Callback notifying this user that the metadata for the given |
|---|
| 110 | group has changed. |
|---|
| 111 | |
|---|
| 112 | @type group: L{IGroup} |
|---|
| 113 | @type meta: C{dict} |
|---|
| 114 | |
|---|
| 115 | @rtype: L{twisted.internet.defer.Deferred} |
|---|
| 116 | """ |
|---|
| 117 | |
|---|
| 118 | def userJoined(group, user): |
|---|
| 119 | """ |
|---|
| 120 | Callback notifying this user that the given user has joined |
|---|
| 121 | the given group. |
|---|
| 122 | |
|---|
| 123 | @type group: L{IGroup} |
|---|
| 124 | @type user: L{IUser} |
|---|
| 125 | |
|---|
| 126 | @rtype: L{twisted.internet.defer.Deferred} |
|---|
| 127 | """ |
|---|
| 128 | |
|---|
| 129 | def userLeft(group, user, reason=None): |
|---|
| 130 | """ |
|---|
| 131 | Callback notifying this user that the given user has left the |
|---|
| 132 | given group for the given reason. |
|---|
| 133 | |
|---|
| 134 | @type group: L{IGroup} |
|---|
| 135 | @type user: L{IUser} |
|---|
| 136 | @type reason: C{unicode} |
|---|
| 137 | |
|---|
| 138 | @rtype: L{twisted.internet.defer.Deferred} |
|---|
| 139 | """ |
|---|
| 140 | |
|---|
| 141 | |
|---|
| 142 | class IUser(Interface): |
|---|
| 143 | """Interface through which clients interact with IChatService. |
|---|
| 144 | """ |
|---|
| 145 | |
|---|
| 146 | realm = Attribute("A reference to the Realm to which this user belongs. Set if and only if the user is logged in.") |
|---|
| 147 | mind = Attribute("A reference to the mind which logged in to this user. Set if and only if the user is logged in.") |
|---|
| 148 | name = Attribute("A short string, unique among users.") |
|---|
| 149 | |
|---|
| 150 | lastMessage = Attribute("A POSIX timestamp indicating the time of the last message received from this user.") |
|---|
| 151 | signOn = Attribute("A POSIX timestamp indicating this user's most recent sign on time.") |
|---|
| 152 | |
|---|
| 153 | def loggedIn(realm, mind): |
|---|
| 154 | """Invoked by the associated L{IChatService} when login occurs. |
|---|
| 155 | |
|---|
| 156 | @param realm: The L{IChatService} through which login is occurring. |
|---|
| 157 | @param mind: The mind object used for cred login. |
|---|
| 158 | """ |
|---|
| 159 | |
|---|
| 160 | def send(recipient, message): |
|---|
| 161 | """Send the given message to the given user or group. |
|---|
| 162 | |
|---|
| 163 | @type recipient: Either L{IUser} or L{IGroup} |
|---|
| 164 | @type message: C{dict} |
|---|
| 165 | """ |
|---|
| 166 | |
|---|
| 167 | def join(group): |
|---|
| 168 | """Attempt to join the given group. |
|---|
| 169 | |
|---|
| 170 | @type group: L{IGroup} |
|---|
| 171 | @rtype: L{twisted.internet.defer.Deferred} |
|---|
| 172 | """ |
|---|
| 173 | |
|---|
| 174 | def leave(group): |
|---|
| 175 | """Discontinue participation in the given group. |
|---|
| 176 | |
|---|
| 177 | @type group: L{IGroup} |
|---|
| 178 | @rtype: L{twisted.internet.defer.Deferred} |
|---|
| 179 | """ |
|---|
| 180 | |
|---|
| 181 | def itergroups(): |
|---|
| 182 | """ |
|---|
| 183 | Return an iterator of all groups of which this user is a |
|---|
| 184 | member. |
|---|
| 185 | """ |
|---|
| 186 | |
|---|
| 187 | |
|---|
| 188 | class IChatService(Interface): |
|---|
| 189 | name = Attribute("A short string identifying this chat service (eg, a hostname)") |
|---|
| 190 | |
|---|
| 191 | createGroupOnRequest = Attribute( |
|---|
| 192 | "A boolean indicating whether L{getGroup} should implicitly " |
|---|
| 193 | "create groups which are requested but which do not yet exist.") |
|---|
| 194 | |
|---|
| 195 | createUserOnRequest = Attribute( |
|---|
| 196 | "A boolean indicating whether L{getUser} should implicitly " |
|---|
| 197 | "create users which are requested but which do not yet exist.") |
|---|
| 198 | |
|---|
| 199 | def itergroups(): |
|---|
| 200 | """Return all groups available on this service. |
|---|
| 201 | |
|---|
| 202 | @rtype: C{twisted.internet.defer.Deferred} |
|---|
| 203 | @return: A Deferred which fires with a list of C{IGroup} providers. |
|---|
| 204 | """ |
|---|
| 205 | |
|---|
| 206 | def getGroup(name): |
|---|
| 207 | """Retrieve the group by the given name. |
|---|
| 208 | |
|---|
| 209 | @type name: C{str} |
|---|
| 210 | |
|---|
| 211 | @rtype: L{twisted.internet.defer.Deferred} |
|---|
| 212 | @return: A Deferred which fires with the group with the given |
|---|
| 213 | name if one exists (or if one is created due to the setting of |
|---|
| 214 | L{createGroupOnRequest}, or which fails with |
|---|
| 215 | L{twisted.words.ewords.NoSuchGroup} if no such group exists. |
|---|
| 216 | """ |
|---|
| 217 | |
|---|
| 218 | def createGroup(name): |
|---|
| 219 | """Create a new group with the given name. |
|---|
| 220 | |
|---|
| 221 | @type name: C{str} |
|---|
| 222 | |
|---|
| 223 | @rtype: L{twisted.internet.defer.Deferred} |
|---|
| 224 | @return: A Deferred which fires with the created group, or |
|---|
| 225 | with fails with L{twisted.words.ewords.DuplicateGroup} if a |
|---|
| 226 | group by that name exists already. |
|---|
| 227 | """ |
|---|
| 228 | |
|---|
| 229 | def lookupGroup(name): |
|---|
| 230 | """Retrieve a group by name. |
|---|
| 231 | |
|---|
| 232 | Unlike C{getGroup}, this will never implicitly create a group. |
|---|
| 233 | |
|---|
| 234 | @type name: C{str} |
|---|
| 235 | |
|---|
| 236 | @rtype: L{twisted.internet.defer.Deferred} |
|---|
| 237 | @return: A Deferred which fires with the group by the given |
|---|
| 238 | name, or which fails with L{twisted.words.ewords.NoSuchGroup}. |
|---|
| 239 | """ |
|---|
| 240 | |
|---|
| 241 | def getUser(name): |
|---|
| 242 | """Retrieve the user by the given name. |
|---|
| 243 | |
|---|
| 244 | @type name: C{str} |
|---|
| 245 | |
|---|
| 246 | @rtype: L{twisted.internet.defer.Deferred} |
|---|
| 247 | @return: A Deferred which fires with the user with the given |
|---|
| 248 | name if one exists (or if one is created due to the setting of |
|---|
| 249 | L{createUserOnRequest}, or which fails with |
|---|
| 250 | L{twisted.words.ewords.NoSuchUser} if no such user exists. |
|---|
| 251 | """ |
|---|
| 252 | |
|---|
| 253 | def createUser(name): |
|---|
| 254 | """Create a new user with the given name. |
|---|
| 255 | |
|---|
| 256 | @type name: C{str} |
|---|
| 257 | |
|---|
| 258 | @rtype: L{twisted.internet.defer.Deferred} |
|---|
| 259 | @return: A Deferred which fires with the created user, or |
|---|
| 260 | with fails with L{twisted.words.ewords.DuplicateUser} if a |
|---|
| 261 | user by that name exists already. |
|---|
| 262 | """ |
|---|
| 263 | |
|---|
| 264 | __all__ = [ |
|---|
| 265 | 'IChatInterface', 'IGroup', 'IChatClient', 'IUser', 'IChatService', |
|---|
| 266 | ] |
|---|