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