1 """
2 The client classes.
3 """
4
5 from time import time
6
7 from twisted.internet import reactor, defer
8 from twisted.internet import protocol
9 from twisted.internet.task import LoopingCall
10
11 from lacewing.protocol import BaseProtocol
12 from lacewing.packet import ServerPacket, ClientPacket
13 from lacewing.packetloaders import server, client
14 from lacewing.multidict import MultikeyDict
15 from lacewing.packetloaders.common import (detectType, CONNECT, SET_NAME,
16 JOIN_CHANNEL, LEAVE_CHANNEL, CHANNEL_LIST)
17
19 """
20 Represents a remote client.
21 @ivar name: The name of the client.
22 @ivar id: The ID of the client
23 @ivar master: True if this peer is the master of the channel
24 """
25 user = None
26 name = None
27 id = None
28 master = False
29
30 - def __init__(self, name, id, master, channel):
36
37 - def sendMessage(self, message, subchannel, typeName = None,
38 asObject = False, asDatagram = False):
39 """
40 Send a message to another peer
41
42 @type message: str/number/ByteReader
43 @param subchannel: The subchannel of the message in the range 0-256
44 @param typeName: If not specified, the type will be
45 automatically detected (see L{lacewing.packetloaders.common.DATA_TYPES}
46 for possible values)
47 """
48 if asObject:
49 newMessage = client.ObjectPeerMessage()
50 else:
51 newMessage = client.BinaryPeerMessage()
52 newMessage.value = message
53 newMessage.subchannel = subchannel
54 newMessage.channel = self.channel.id
55 newMessage.peer = self.id
56 newMessage.setDataType(typeName or detectType(message))
57 self.user.sendLoader(newMessage, asDatagram)
58
59 - def kick(self, peer):
61
63 """
64 Represents a server channel.
65 @ivar id: The ID of the channel.
66 @ivar name: The name of the channel.
67 @ivar connections: A dict of signed on connections.
68 """
69 user = None
70
71 id = None
72 name = None
73
77
78 - def sendMessage(self, message, subchannel, typeName = None, asObject = False,
79 asDatagram = False):
80 """
81 Send a message to the channel
82
83 @type message: str/number/ByteReader
84 @param subchannel: The subchannel of the message in the range 0-256
85 @param typeName: If not specified, the type will be
86 automatically detected (see L{lacewing.packetloaders.common.DATA_TYPES}
87 for possible values)
88 """
89 if typeName is None:
90 typeName = detectType(message)
91 if asObject:
92 newMessage = client.ObjectChannelMessage()
93 else:
94 newMessage = client.BinaryChannelMessage()
95 newMessage.value = message
96 newMessage.subchannel = subchannel
97 newMessage.channel = self.id
98 newMessage.setDataType(typeName)
99 self.user.sendLoader(newMessage, asDatagram)
100
102 """
103 The client protocol.
104
105 @ivar datagram: The ClientDatagram protocol this connection is using for
106 UDP handling
107 """
108 datagram = None
109 _udpCheck = None
110 udpTimeout = 3000
111 _loginName = None
112
113 _channelList = None
114 _channelListDefer = None
115 _receivePacket = ServerPacket
116
130
132 packetId = loader.id
133 if packetId == server.Response.id:
134 if not loader.success:
135 self.serverDenied(loader)
136 return
137 response = loader.response
138 if response == CONNECT:
139 datagram = ClientDatagram(self)
140 reactor.listenUDP(0, datagram)
141 self.datagram = datagram
142 self.serverGreeted(loader.welcome)
143 self.id = loader.playerId
144 self._enableUDP()
145
146 elif response == SET_NAME:
147 name = self.name = loader.name
148 if self.loggedIn:
149 self.nameChanged(name)
150 else:
151 self.loggedIn = True
152 self.loginAccepted(self.name)
153
154 elif response == JOIN_CHANNEL:
155 channelId = loader.channel
156 channelName = loader.name
157 channel = ClientChannel(self)
158 channel.id = channelId
159 channel.name = channelName
160 self.channels[channelId, channelName] = channel
161 connections = channel.connections
162 for peer in loader.peers:
163 clientId = peer.id
164 name = peer.name
165 peer = Peer(name, clientId, peer.isMaster, channel)
166 self.channelUserExists(channel, peer)
167 connections[clientId, name] = peer
168 self.channelJoined(channel)
169
170 elif response == LEAVE_CHANNEL:
171 channel, = self.channels[loader.channel]
172 del self.channels[channel]
173 self.channelLeft(channel)
174
175 elif response == CHANNEL_LIST:
176 self._channelListDefer.pop(0).callback(loader.channels)
177 return
178
179 elif packetId == server.UDPWelcome.id and not self.udpEnabled:
180 self._udpCheck.stop()
181 self.isAccepted = True
182 self.connectionAccepted()
183
184 elif packetId in (server.BinaryServerMessage.id,
185 server.ObjectServerMessage.id):
186 self.messageReceived(loader)
187
188 elif packetId in (server.BinaryChannelMessage.id,
189 server.ObjectChannelMessage.id):
190 channel, = self.channels[loader.channel]
191 sender, = channel.connections[loader.peer]
192 self.channelMessageReceived(channel, sender, loader)
193
194 elif packetId == server.Ping.id:
195 self.sendLoader(client.Pong())
196 self.pingReceived()
197
198 elif packetId == server.Peer.id:
199 channel, = self.channels[loader.channel]
200 connections = channel.connections
201 clientId = loader.peer
202 name = loader.name
203 if name is not None:
204 if not clientId in connections:
205
206 peer = Peer(name, clientId, loader.isMaster, channel)
207 self.channelUserJoined(channel, peer)
208 else:
209 peer, = channel.connections[clientId]
210 del channel.connections[peer]
211 peer.name = name
212 peer.master = loader.isMaster
213 self.channelUserChanged(channel, peer)
214 connections[clientId, name] = peer
215 else:
216 peer, = channel.connections[clientId]
217 self.channelUserLeft(channel, peer)
218 del connections[peer]
219
220 elif packetId in (server.BinaryPeerMessage.id,
221 server.ObjectPeerMessage.id):
222 channel, = self.channels[loader.channel]
223 peer, = channel.connections[loader.peer]
224 self.privateMessageReceived(channel, peer, loader)
225
226 else:
227
228 raise NotImplementedError('unknown packet type (%s)' % packetId)
229
230 - def sendLoader(self, loader, asDatagram = False):
231 """
232 Sends a packetloader to the server
233 @param loader: The packetloader to send.
234 """
235 if asDatagram:
236 self.datagram.sendLoader(loader)
237 else:
238 newPacket = ClientPacket()
239 newPacket.loader = loader
240 self.transport.write(newPacket.generate())
241
244
247
261
262 - def sendMessage(self, message, subchannel, typeName = None,
263 asObject = False, asDatagram = False):
264 """
265 Send a message directly to the server.
266 @param message: The message to send.
267 @type message: str/number/ByteReader
268 @param subchannel: A subchannel in the range 0-256
269 @param typeName: If not specified, the type will be
270 automatically detected (see L{lacewing.packetloaders.common.DATA_TYPES}
271 for possible values)
272 """
273 if typeName is None:
274 typeName = detectType(message)
275 if asObject:
276 newMessage = client.ObjectServerMessage()
277 else:
278 newMessage = client.BinaryServerMessage()
279 newMessage.value = message
280 newMessage.subchannel = subchannel
281 newMessage.setDataType(typeName)
282 self.sendLoader(newMessage, asDatagram)
283
284 - def joinChannel(self, channelName, hidden = False, autoClose = False):
300
312
323
324
325
327 """
328 Called when the server has responded to our welcome.
329 """
330
332 """
333 Called when the server has accepted the requested connection.
334 """
335
337 """
338 Called when the server has accepted the requested name
339 (or has specified one itself).
340 @arg name: The name of the client.
341 @type name: str object
342 """
343
345 """
346 Called when the server has accepted name change
347 (or has given the client a new one).
348 @type name: str
349 @arg name: The new name for the client.
350 """
351
353 """
354 Called when the server disconnects or when the
355 server denies an client request.
356 @arg response: The response of the action.
357 """
358
360 """
361 Called when a server message arrives.
362 @type message: L{server.BinaryServerMessage} or
363 L{server.ObjectServerMessage}
364 """
365
367 """
368 Called when a message from a channel arrives.
369 @arg channel: the channel the message came from.
370 @arg user: the sender of the message.
371 @type message: L{server.BinaryChannelMessage} or
372 L{server.ObjectChannelMessage}
373 """
374
376 """
377 Called when a private message has been received
378 @arg channel: the channel the user is sending from.
379 @type message: L{server.BinaryChannelMessage} or
380 L{server.ObjectChannelMessage}
381 @type sender: L{Peer} object
382 """
383
385 """
386 Called when the server has accepted a channel join request.
387 @arg channel: The channel the client has joined.
388 """
389
391 """
392 Called when the server has accepted a channel leave request.
393 @arg channel: The channel the client has left.
394 """
395
397 """
398 Called when a client has joined the channel.
399 @arg channel: The channel the client has joined.
400 """
401
403 """
404 Called when a client exists in the channel.
405 @arg channel: The channel the client exists in.
406 """
407
409 """
410 Called when a client has left the channel.
411 @arg channel: The channel the client has left.
412 """
413
415 """
416 Called when a client in the channel has changed name.
417 @arg channel: The channel the client resides in.
418 """
419
421 """
422 Called when a server ping has been received.
423 """
424
449