1
2
3
4
5
6
7
8
9
10
11 from twisted.internet import task
12 from twisted.spread import pb
13 from twisted.python import log
14 import zope.interface
15 import mx.DateTime
16 import M2Crypto as m2
17
18 from util import Util
19 from constants import Constants
23
24 zope.interface.implements(pb.IPerspective)
25
26 - def __init__(self, userAttributes, clientServices=None, virtual=False):
27 '''
28 Generates a user object.
29 '''
30
31 self._userName = userAttributes['username']
32
33 self._domainName = userAttributes['domain']
34
35 self._client = userAttributes.get('clientReference')
36
37 self._clientServices = clientServices
38
39 self._fullname = None
40
41 self._lang = None
42
43 self._server = None
44
45 self._virtual = virtual
46
47 self._id = Util.uniq()
48
49 self._ip = None
50
51 self._start = None
52
53 self._numConns = 0
54
55 self._avatarList = None
56
57 self._pingTask = task.LoopingCall(self.pingClient)
58
59
60 self._loseConnection = None
61
62 self._missingPingCount = 0
63
64 self._authList = [1,2,3]
65
67 '''
68 Convert to a dict holding only standard python types.
69 '''
70 __slots__ = ['_userName', '_domainName', '_fullname', '_lang', '_virtual', '_id', '_authList']
71 return dict([(k, getattr(self, k, None)) for k in __slots__])
72
73 @staticmethod
75 '''
76 Returns an MCUser instance by using the dictionary passed.
77
78 @param aDict: A dictionary, previously obtained by toDict()
79 @type aDict: dict
80 @returns: A new MCUser instance
81 '''
82 __slots__ = ['_fullname', '_lang', '_virtual', '_id', '_authList']
83 user = MCUser({'username':aDict['_userName'], 'domain':aDict['_domainName']})
84
85 for attr in __slots__:
86 setattr(user, attr, aDict[attr])
87
88 return user
89
91 '''
92 Returns the client service object assigned.
93 '''
94 return self._clientServices
95
96 - def setIP(self, address):
97 '''
98 Sets the currently connected client's IP address.
99
100 @param address: IP address
101 '''
102 self._ip = address
103
105 '''
106 Sets the remote client reference.
107
108 @param client: Avatar's mind object (reference to remote client
109 presence)
110 '''
111 self._client = client
112
114 '''
115 Returns the remote client reference.
116 '''
117 return self._client
118
120 '''
121 Sets the method to be used for disconnecting client represented
122 by this object.
123
124 @param method: Reference to client's loseConnection method.
125 '''
126 self._loseConnection = method
127
129 '''
130 Sets the connected user's full name.
131
132 @param fullName: Full name of user
133 @type fullName: str
134 '''
135 self._fullname = fullName
136
138 '''
139 Sets the starting time for this user connection.
140
141 @param time: If given, this time is used as the start time
142 of connection. If None, current time is used.
143 @type time: mx.DateTime
144 '''
145 if time is None:
146 time = mx.DateTime.now()
147 self._start = time
148
150 '''
151 Sets a reference to the application server.
152
153 @param server: Reference to application server.
154 @type server: Server
155 '''
156 self._server = server
157
159 '''
160 Assigns the currently connected avatar list to this avatar.
161
162 @param avatarList: A list of currently connected avatars.
163 @type avatarList: list
164 '''
165 self._avatarList = avatarList
166
168 '''
169 Returns unique ID of this user instance.
170 '''
171 return self._id
172
174 '''
175 Return the username of the user object.
176 '''
177 return self._userName
178
180 '''
181 Sets the username of the user object to a new name.
182
183 @param userName: User name
184 @type userName: str
185 '''
186 self._userName = userName
187
188 - def domainName(self):
189 '''
190 Return the domain name of the user object.
191 '''
192 return self._domainName
193
194 - def setDomainName(self, domain):
195 '''
196 Sets the domain name of the user object.
197 '''
198 self._domainName = domain
199
201 '''
202 Returns the client IP address of this user.
203 '''
204 return self._ip
205
207 '''
208 Returns if user is virtual or not.
209 '''
210 return self._virtual
211
213 '''
214 Sets the virtual property of the user object.
215 '''
216 self._virtual = virtual
217
219 '''
220 Returns the list of this user's authentication code list.
221 '''
222 return self._authList
223
225 '''
226 Sets the authentication code list of this user.
227 '''
228 self._authList = authList
229
231 '''
232 Periodically calls a remote ping method on the client. If the request
233 sent in the previous call is unanswered, then increments the missing ping
234 count. If missing ping count is exceeded, force the disconnect of the
235 remote user.
236 '''
237 def cb_gotReply(result):
238
239 self._missingPingCount = 0
240
241 if self._missingPingCount < Constants.MAX_PINGS:
242
243 self._missingPingCount += 1
244 try:
245 self._client.callRemote('ping').addCallback(cb_gotReply)
246 return
247 except:
248 log.err()
249
250
251 log.msg('Client is being disconnected due to unanswered ping requests.')
252 self.forceDisconnect()
253
255 '''
256 This method was copied from spread/pb.py.
257 '''
258 args = broker.unserialize(args, self)
259 kw = broker.unserialize(kw, self)
260 method = getattr(self, "perspective_%s" % message)
261
262 try:
263 state = method(*args, **kw)
264 except TypeError:
265 log.err("%s didn't accept %s and %s" % (method, args, kw))
266 raise
267
268 return broker.serialize(state, self, method, args, kw)
269
271 '''
272 Method called upon connection of the client represented by this
273 class.
274
275 @param startPinger: If True, ping tester task is run, which is
276 the default.
277 '''
278 self._numConns += 1
279
280 self._server.userLoggedIn(self)
281
282 if startPinger:
283
284 self._pingTask.start(Constants.PING_TIMEOUT)
285
287 '''
288 Method called upon disconnection of the client represented by this
289 class.
290 '''
291 if self._pingTask.running:
292 self._pingTask.stop()
293
294 log.msg(tr('sys00006') % (self.domainName(), self.userName()))
295
296 self._numConns -= 1
297
298
299 if self._numConns == 0:
300 del self._avatarList[self.uniqID()]
301
302
303 self._server.userLoggedOut(self)
304
306 '''
307 Forcibly disconnects the client represented by this object. May be
308 called directly by the developer.
309 '''
310 self.disconnect()
311
312 if self._loseConnection:
313 self._loseConnection()
314
316 '''
317 Returns the remotely callable services to the client.
318 '''
319 return self.clientServices()
320
322 '''
323 Remote method that is to be called by the clients to obtain the server's
324 certificate that includes the public key. Certificate is returned in PEM
325 format.
326
327 @return: Server's certificate in PEM format
328 '''
329 return m2.X509.load_cert_string(open(Constants.CERTIFICATE, 'rb').read()).as_pem()
330
332 '''
333 Answers client's periodic ping requests.
334 '''
335 return True
336