basesession.py (77585B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\script\sys\basesession.py 2 import copy 3 import random 4 import sys 5 import types 6 import weakref 7 from collections import deque, defaultdict 8 import blue 9 import bluepy 10 import carbon.common.script.net.machobase as machobase 11 import carbon.common.script.util.format as formatUtil 12 import localstorage 13 import log 14 import uthread 15 from carbon.common.script.sys.service import CallWrapper, FastCallWrapper, ServiceCallWrapper, UnlockedServiceCallWrapper 16 from carbon.common.script.sys.serviceConst import ROLE_LOGIN, ROLE_PLAYER, ROLE_REMOTESERVICE, ROLE_SERVICE, SERVICE_FAILED, SERVICE_RUNNING, SERVICE_STOPPED 17 from carbon.common.script.sys.serviceProxy import ServiceProxy 18 from carbon.common.lib import const 19 from eveexceptions import UserError 20 from eveprefs import prefs 21 from eveservices.roles import has_any_role, remove_role, add_role 22 from markers import PopMark, PushMark 23 from stringutil import strx 24 SESSIONCHANGEDELAY = 10 * const.SEC 25 allObjectConnections = weakref.WeakSet() 26 allConnectedObjects = weakref.WeakSet() 27 service_sessions = {} 28 local_sid = 0 29 sessionsByAttribute = {'userid': defaultdict(set), 30 'userType': defaultdict(set), 31 'charid': defaultdict(set), 32 'objectID': defaultdict(dict)} 33 sessionsBySID = {} 34 allSessionsBySID = weakref.WeakValueDictionary({}) 35 __contextOnlyTypes__ = [] 36 dyingObjects = deque() 37 38 def ObjectKillah(): 39 n = 0 40 while 1: 41 maxNumObjects = prefs.GetValue('objectKillahMaxObjects', -1) 42 sleepTime = prefs.GetValue('objectKilla.SleepWallclockTime', 30) 43 if dyingObjects and (maxNumObjects <= 0 or n < maxNumObjects): 44 delay = (dyingObjects[0][0] - blue.os.GetWallclockTime()) / const.SEC 45 delay = min(delay, 30) 46 if delay > 0: 47 blue.pyos.synchro.SleepWallclock(1000 * delay) 48 else: 49 dietime, diediedie = dyingObjects.popleft() 50 try: 51 with bluepy.Timer('sessions::' + diediedie.GetObjectConnectionLogClass()): 52 diediedie.DisconnectObject() 53 except Exception: 54 log.LogException() 55 sys.exc_clear() 56 57 del diediedie 58 n += 1 59 else: 60 if maxNumObjects > 0 and n >= maxNumObjects: 61 log.general.Log("ObjectKillah killed the maximum number of allowed objects for this round, %d, which means that we're lagging behind! Sleeping for %d seconds" % (maxNumObjects, sleepTime), log.LGWARN) 62 elif n > 0: 63 if maxNumObjects > 0: 64 log.general.Log('ObjectKillah killed %d objects for this round out of a maximum of %d. Sleeping for %d seconds' % (n, maxNumObjects, sleepTime), log.LGINFO) 65 else: 66 log.general.Log('ObjectKillah killed %d objects for this round. Sleeping for %d seconds' % (n, sleepTime), log.LGINFO) 67 n = 0 68 blue.pyos.synchro.SleepWallclock(1000 * sleepTime) 69 70 71 objectKillaThread = uthread.new(ObjectKillah) 72 objectKillaThread.context = 'sessions::ObjectKillah' 73 74 class ObjectConnection(): 75 __passbyvalue__ = 0 76 __restrictedcalls__ = {'PseudoMethodCall': 1, 77 'LogPseudoMethodCall': 1, 78 'GetObjectConnectionLogClass': 1, 79 'RedirectObject': 1, 80 'Objectcast': 1} 81 82 def __init__(self, sess, object, c2ooid, serviceName = None, bindParams = None): 83 if object is None: 84 sess.LogSessionError('Establishing an object connection to None') 85 log.LogTraceback() 86 self.__dict__['__last_used__'] = blue.os.GetWallclockTime() 87 self.__dict__['__constructing__'] = 1 88 self.__dict__['__deleting__'] = 0 89 self.__dict__['__machoObjectUUID__'] = GetObjectUUID(object) 90 self.__dict__['__redirectObject__'] = None 91 self.__dict__['__disconnected__'] = 1 92 self.__dict__['__session__'] = weakref.proxy(sess) 93 self.__dict__['__c2ooid__'] = c2ooid 94 self.__dict__['__object__'] = object 95 self.__dict__['__serviceName__'] = serviceName 96 self.__dict__['__bindParams__'] = bindParams 97 self.__dict__['__publicattributes__'] = getattr(object, '__publicattributes__') 98 try: 99 lock = None 100 if not object.sessionConnections: 101 if has_any_role(sess, ROLE_PLAYER): 102 sm.GetService(serviceName).LogInfo('Player session re-aquiring big lock. Session:', sess) 103 lock = (sm.GetService(serviceName).LockService(bindParams), bindParams) 104 object.service = weakref.proxy(sm.GetService(serviceName)) 105 object.session = weakref.proxy(object.service.session) 106 for depServiceName in getattr(object, '__dependencies__', []): 107 if not hasattr(object.service, depServiceName): 108 dep = object.service.session.ConnectToService(depServiceName) 109 setattr(object.service, depServiceName, dep) 110 setattr(object, depServiceName, getattr(object.service, depServiceName)) 111 112 self.PseudoMethodCall(object, 'OnRun') 113 if has_any_role(sess, ROLE_PLAYER) and lock is None: 114 charid = sess.charid 115 lock = (object.service.LockService((bindParams, charid)), (bindParams, charid)) 116 if sess.sid not in object.sessionConnections: 117 object.sessionConnections[sess.sid] = sess 118 object.objectConnections[sess.sid] = {} 119 try: 120 self.PseudoMethodCall(object, 'OnSessionAttach') 121 except Exception: 122 object.sessionConnections.pop(sess.sid, None) 123 object.objectConnections.pop(sess.sid, None) 124 log.LogTraceback('OnSessionAttach failed in ObjectConnection') 125 log.LogException() 126 raise 127 128 else: 129 self.PseudoMethodCall(object, 'OnSessionReattach') 130 object.objectConnections[sess.sid][c2ooid] = self 131 sess.connectedObjects[self.__c2ooid__] = (self,) 132 self.__disconnected__ = 0 133 self.__pendingDisconnect__ = 0 134 allObjectConnections.add(self) 135 allConnectedObjects.add(object) 136 finally: 137 if lock is not None: 138 sm.GetService(serviceName).UnLockService(lock[1], lock[0]) 139 140 self.__dict__['__constructing__'] = 0 141 142 def GetSession(self): 143 return self.__session__ 144 145 def __del__(self): 146 if not self.__deleting__: 147 self.__deleting__ = 1 148 if not self.__disconnected__: 149 if log.methodcalls.IsOpen(2): 150 log.methodcalls.Log("Curious.... Disconnecting during __del__ wasn't entirely expected...", 2, 1) 151 self.DisconnectObject(30) 152 153 def __str__(self): 154 return 'ObjectConnection to ' + strx(self.__object__) 155 156 def __repr__(self): 157 return self.__str__() 158 159 def GetInstanceID(self): 160 return self.__object__.machoInstanceID 161 162 def PseudoMethodCall(self, object, method, *args, **keywords): 163 global CallTimer 164 self.__dict__['__last_used__'] = blue.os.GetWallclockTime() 165 if hasattr(object, method): 166 with self.__session__.Masquerade({'base.caller': weakref.ref(self)}): 167 with CallTimer(machobase.GetLogName(object) + '::' + method): 168 try: 169 result = getattr(object, method)(*args, **keywords) 170 except Exception as e: 171 self.LogPseudoMethodCall(e, method) 172 raise 173 174 self.LogPseudoMethodCall(result, method) 175 return result 176 177 def LogPseudoMethodCall(self, result, method, *args, **keywords): 178 logChannel = log.methodcalls 179 if logChannel.IsOpen(log.LGINFO): 180 logname = machobase.GetLogName(self.__object__) 181 if isinstance(result, Exception): 182 eorr = ', EXCEPTION=' 183 else: 184 eorr = ', retval=' 185 if keywords: 186 logwhat = [logname, 187 '::', 188 method, 189 ' args=', 190 args, 191 ', keywords={', 192 keywords, 193 '}', 194 eorr, 195 result] 196 else: 197 logwhat = [logname, 198 '::', 199 method, 200 ' args=', 201 args, 202 eorr, 203 result] 204 timer = PushMark(logname + '::LogPseudoMethodCall') 205 try: 206 s = ''.join(map(strx, logwhat)) 207 if len(s) > 2500: 208 s = s[:2500] 209 while len(s) > 255: 210 logChannel.Log(s[:253], log.LGINFO, 1) 211 s = '- ' + s[253:] 212 213 logChannel.Log(s, log.LGINFO, 1) 214 except TypeError: 215 logChannel.Log('[X]'.join(map(strx, logwhat)).replace('\x00', '\\0'), log.LGINFO, 1) 216 sys.exc_clear() 217 except UnicodeEncodeError: 218 logChannel.Log('[U]'.join(map(lambda x: x.encode('ascii', 'replace'), map(unicode, logwhat))), log.LGINFO, 1) 219 sys.exc_clear() 220 finally: 221 PopMark(timer) 222 223 def GetObjectConnectionLogClass(self): 224 return machobase.AssignLogName(self.__object__) 225 226 def __GetObjectType(self): 227 return 'ObjectConnection to ' + self.GetObjectConnectionLogClass() 228 229 def RedirectObject(self, serviceName = None, bindParams = None): 230 if serviceName is None: 231 serviceName = self.__serviceName__ 232 if bindParams is None: 233 bindParams = self.__bindParams__ 234 self.__redirectObject__ = (serviceName, bindParams) 235 236 def DisconnectObject(self, delaySecs = 0): 237 if delaySecs: 238 if not self.__pendingDisconnect__: 239 dyingObjects.append((blue.os.GetWallclockTime() + delaySecs * const.SEC, self)) 240 self.__pendingDisconnect__ = 1 241 else: 242 self.__pendingDisconnect__ += 1 243 if self.__pendingDisconnect__ in (10, 100, 1000, 10000, 100000, 1000000, 10000000): 244 if not prefs.GetValue('suppressObjectKillahDupSpam', 0): 245 log.LogTraceback('Many duplicate requests (%d) to add object to objectKillah dyingObjects list - %r %r' % (self.__pendingDisconnect__, self, self.GetObjectConnectionLogClass()), severity=log.LGWARN) 246 return 247 if not self.__disconnected__: 248 self.__disconnected__ = 1 249 try: 250 if not sm.IsServiceRunning(self.__serviceName__): 251 return 252 service = sm.GetService(self.__serviceName__) 253 lock = None 254 if self.__session__.role & ROLE_PLAYER: 255 charid = getattr(self.__session__, 'charid') 256 lock = sm.GetService(self.__serviceName__).LockService((self.__bindParams__, charid)) 257 try: 258 objectID = GetObjectUUID(self) 259 if objectID in self.__session__.machoObjectsByID: 260 objectType = self.__GetObjectType() 261 self.__session__.LogSessionHistory('%s object %s disconnected from this session by the server' % (objectType, objectID), strx(self.__object__)) 262 self.__session__.UnregisterMachoObject(objectID, None, 0) 263 service.RemoveSessionConnectionFromObject(self) 264 finally: 265 if lock: 266 sm.GetService(self.__serviceName__).UnLockService((self.__bindParams__, charid), lock) 267 268 except ReferenceError: 269 pass 270 except Exception: 271 log.LogException() 272 273 self.__object__ = None 274 275 def __getattr__(self, method): 276 if method in self.__dict__: 277 return self.__dict__[method] 278 if not method.isupper(): 279 if method in self.__dict__['__publicattributes__']: 280 return getattr(self.__object__, method) 281 if method.startswith('__'): 282 raise AttributeError(method) 283 if self.__c2ooid__ not in self.__session__.connectedObjects: 284 self.__session__.LogSessionHistory('Object no longer live: c2ooid=' + strx(self.__c2ooid__) + ', serviceName=' + strx(self.__serviceName__) + ', bindParams=' + strx(self.__bindParams__) + ', uuid=' + strx(self.__machoObjectUUID__), None, 1) 285 self.__session__.LogSessionError('This object connection is no longer live') 286 raise RuntimeError('This object connection is no longer live') 287 self.__dict__['__last_used__'] = blue.os.GetWallclockTime() 288 if self.__session__.role & (ROLE_SERVICE | ROLE_REMOTESERVICE) == ROLE_SERVICE: 289 if method.endswith('_Ex'): 290 return FastCallWrapper(self.__session__, self.__object__, method[:-3], self) 291 else: 292 return FastCallWrapper(self.__session__, self.__object__, method, self) 293 return CallWrapper(self.__session__, self.__object__, method, self, self.GetObjectConnectionLogClass()) 294 295 296 def FindClientsAndHoles(attr, val, maxCount): 297 ret = [] 298 nf = [] 299 attributes = attr.split('&') 300 if attributes[0] not in sessionsByAttribute: 301 log.LogWarn('FindClientsAndHoles by non-existent attribute ', attributes[0]) 302 return (0, ret, nf) 303 if len(attributes) > 1: 304 if len(attributes) != len(val): 305 raise RuntimeError('For a complex session query, the value must be a tuple of equal length to the complex query params') 306 for i in range(len(val[0])): 307 f = 0 308 r = [] 309 for sid in sessionsByAttribute[attributes[0]].get(val[0][i], set()): 310 if sid in sessionsBySID: 311 sess = sessionsBySID[sid] 312 k = 1 313 for j in range(1, len(val)): 314 if attributes[j] in ('corprole', 'rolesAtAll', 'rolesAtHQ', 'rolesAtBase', 'rolesAtOther'): 315 corprole = getattr(sess, attributes[j]) 316 k = 0 317 for r2 in val[j]: 318 if r2 and r2 & corprole == r2: 319 k = 1 320 break 321 322 elif getattr(sess, attributes[j]) not in val[j]: 323 k = 0 324 if not k: 325 break 326 327 if k: 328 f = 1 329 clientID = getattr(sessionsBySID[sid], 'clientID', None) 330 if clientID is not None: 331 if maxCount is not None and len(ret) >= maxCount: 332 return (1, [], []) 333 ret.append(clientID) 334 else: 335 r.append(sid) 336 337 for each in r: 338 try: 339 sessionsByAttribute[attributes[0]][val[0][i]].discard(each) 340 except AttributeError: 341 sessionsByAttribute[attributes[0]][val[0][i]].pop(each, None) 342 343 if not f: 344 nf.append(val[0][i]) 345 346 if len(nf): 347 nf2 = list(copy.copy(val)) 348 nf2[0] = nf 349 nf = nf2 350 return (0, ret, nf) 351 for v in val: 352 f = 0 353 r = [] 354 for sid in sessionsByAttribute[attr].get(v, set()): 355 if sid in sessionsBySID: 356 clientID = getattr(sessionsBySID[sid], 'clientID', None) 357 if clientID is not None: 358 if maxCount is not None and len(ret) >= maxCount: 359 return (1, [], []) 360 ret.append(clientID) 361 f = 1 362 else: 363 r.append(sid) 364 365 if r: 366 sessionsWithAttribute = sessionsByAttribute[attr][v] 367 for each in r: 368 if isinstance(sessionsWithAttribute, dict): 369 sessionsWithAttribute.pop(each, None) 370 else: 371 sessionsWithAttribute.discard(each) 372 373 if not f: 374 nf.append(v) 375 376 return (0, ret, nf) 377 378 379 def FindSessions(attr, val): 380 ret = [] 381 for v in val: 382 try: 383 r = [] 384 for sid in sessionsByAttribute[attr].get(v, set()): 385 if sid in sessionsBySID: 386 ret.append(sessionsBySID[sid]) 387 else: 388 r.append(sid) 389 390 if r: 391 sessionsWithAttribute = sessionsByAttribute[attr][v] 392 for each in r: 393 if isinstance(sessionsWithAttribute, dict): 394 sessionsWithAttribute.pop(each, None) 395 else: 396 sessionsWithAttribute.discard(each) 397 398 except: 399 srv = sm.services['sessionMgr'] 400 srv.LogError('Session map borked') 401 srv.LogError('sessionsByAttribute=', sessionsByAttribute) 402 srv.LogError('sessionsBySID=', sessionsBySID) 403 log.LogTraceback() 404 raise 405 406 if len(ret) > 1 and attr in ('charid', 'userid'): 407 return sorted(ret, key=lambda s: s.localSID, reverse=True) 408 return ret 409 410 411 def FindSessionClient(attr, val): 412 session = FindSessions(attr, val) 413 if session: 414 return getattr(session[0], 'clientID', None) 415 416 417 callTimerKeys = {} 418 serviceCallTimes = {} 419 webCallTimes = {} 420 userCallTimes = {} 421 outstandingCallTimers = [] 422 methodCallHistory = deque(maxlen=1000) 423 424 class RealCallTimer(): 425 TimerType = 2 426 427 def __init__(self, k): 428 k = callTimerKeys.setdefault(k, k) 429 self.key = k 430 localstorage.UpdateLocalStorage({'calltimer.key': k}) 431 if not session: 432 self.mask = GetServiceSession('DefaultCallTimer').Masquerade() 433 else: 434 self.mask = None 435 self.start = blue.os.GetWallclockTimeNow() 436 outstandingCallTimers.append((k, self.start)) 437 438 def Done(self): 439 stop = blue.os.GetWallclockTimeNow() 440 t = stop - self.start 441 if t < 0: 442 log.general.Log('blue.os.GetWallclockTimeNow() is running backwards... now=%s, start=%s' % (stop, self.start), 2, 1) 443 t = 0 444 if session and not session.role & ROLE_SERVICE: 445 if getattr(session, 'clientID', 0): 446 other = userCallTimes 447 else: 448 other = webCallTimes 449 else: 450 other = serviceCallTimes 451 for calltimes in (session.calltimes, other): 452 if self.key not in calltimes: 453 theCallTime = [0, 454 0, 455 -1, 456 -1, 457 0, 458 0] 459 calltimes[self.key] = theCallTime 460 else: 461 theCallTime = calltimes[self.key] 462 theCallTime[0] += 1 463 theCallTime[1] += t 464 if theCallTime[2] == -1 or t < theCallTime[2]: 465 theCallTime[2] = t 466 if theCallTime[3] == -1 or t > theCallTime[3]: 467 theCallTime[3] = t 468 469 if self.mask: 470 self.mask.UnMask() 471 if machobase.mode == 'client': 472 k = (self.key, self.start, t) 473 methodCallHistory.append(k) 474 try: 475 outstandingCallTimers.remove((self.key, self.start)) 476 except: 477 sys.exc_clear() 478 479 def __enter__(self): 480 pass 481 482 def __exit__(self, e, v, tb): 483 self.Done() 484 485 486 class BasicCallTimer(object): 487 TimerType = 1 488 489 def __init__(self, k): 490 k = callTimerKeys.setdefault(k, k) 491 self.key = k 492 self.start = blue.os.GetWallclockTimeNow() 493 494 def Done(self): 495 stop = blue.os.GetWallclockTimeNow() 496 elapsed = stop - self.start 497 if session and not session.role & ROLE_SERVICE: 498 if getattr(session, 'clientID', 0): 499 callTimes = userCallTimes 500 else: 501 callTimes = webCallTimes 502 else: 503 callTimes = serviceCallTimes 504 if elapsed < 0: 505 log.general.Log('blue.os.GetWallclockTimeNow() is running backwards... now=%s, start=%s' % (stop, self.start), 2, 1) 506 elapsed = 0 507 if self.key not in callTimes: 508 callEntry = [0, 509 0, 510 -1, 511 -1, 512 0, 513 0] 514 callTimes[self.key] = callEntry 515 else: 516 callEntry = callTimes[self.key] 517 callEntry[0] += 1 518 callEntry[1] += elapsed 519 if callEntry[2] == -1 or elapsed < callEntry[2]: 520 callEntry[2] = elapsed 521 if callEntry[3] == -1 or elapsed > callEntry[3]: 522 callEntry[3] = elapsed 523 524 def __enter__(self): 525 pass 526 527 def __exit__(self, e, v, tb): 528 self.Done() 529 530 531 class DummyCallTimer(object): 532 TimerType = 0 533 534 def __init__(self, k): 535 pass 536 537 def Done(self): 538 pass 539 540 def __enter__(self): 541 pass 542 543 def __exit__(self, e, v, tb): 544 pass 545 546 547 CallTimer = DummyCallTimer 548 549 def EnableCallTimers(timerType): 550 global CallTimer 551 was = CallTimer.TimerType 552 if timerType == 0: 553 CallTimer = DummyCallTimer 554 elif timerType == 1: 555 CallTimer = BasicCallTimer 556 else: 557 CallTimer = RealCallTimer 558 return was 559 560 561 def IsInClientContext(): 562 return 'base.ClientContext' in localstorage.GetLocalStorage() 563 564 565 def CallTimersEnabled(): 566 return CallTimer.TimerType 567 568 569 def GetCallTimes(): 570 return (userCallTimes, serviceCallTimes, webCallTimes) 571 572 573 def GetNewSid(): 574 return random.getrandbits(63) 575 576 577 def CloseSession(sess, isRemote = False): 578 if sess is not None: 579 if hasattr(sess, 'remoteServiceSessionRefCount'): 580 sess.__dict__['remoteServiceSessionRefCount'] -= 1 581 if sess.__dict__['remoteServiceSessionRefCount'] > 0: 582 return 583 if sess.sid in sessionsBySID: 584 sess.ClearAttributes(isRemote) 585 586 587 class CoreSession(): 588 __persistvars__ = ['userid', 589 'languageID', 590 'role', 591 'charid', 592 'address', 593 'userType', 594 'maxSessionTime', 595 'sessionType', 596 'countryCode'] 597 __nonpersistvars__ = ['sid', 598 'c2ooid', 599 'connectedObjects', 600 'connectedServices', 601 'clientID', 602 'localSID', 603 'contextOnly', 604 'receivedVersion', 605 'irrelevanceTime'] 606 __attributesWithDefaultValueOfZero__ = [] 607 __characterDependantAttributes__ = {'objectID', 608 'wingid', 609 'constellationid', 610 'regionid', 611 'locationid', 612 'shipid', 613 'squadid', 614 'solarsystemid', 615 'charid', 616 'corpid', 617 'structureid', 618 'stationid', 619 'fleetid', 620 'warfactionid', 621 'allianceid', 622 'solarsystemid2', 623 'inDetention'} 624 __userDependantAttributes__ = {'userid', 625 'languageID', 626 'address', 627 'userType', 628 'maxSessionTime', 629 'countryCode', 630 'role'} 631 632 def __init__(self, sid, localSID, role, sessionType, defaultVarList = []): 633 global __contextOnlyTypes__ 634 if sessionType not in const.session.VALID_SESSION_TYPES: 635 raise ValueError('Trying to create a session with an invalid session type') 636 d = self.__dict__ 637 d['additionalNoSetAttributes'] = [] 638 defaultVarList = self.__persistvars__ + defaultVarList 639 for attName in defaultVarList: 640 d[attName] = self.GetDefaultValueOfAttribute(attName) 641 642 d['version'] = 1 643 d['receivedVersion'] = 1 644 d['irrelevanceTime'] = None 645 d['sid'] = sid 646 d['localSID'] = localSID 647 d['role'] = None 648 d['sessionType'] = sessionType 649 d['c2ooid'] = 1 650 d['connectedObjects'] = {} 651 d['connectedServices'] = {} 652 d['calltimes'] = {} 653 d['notificationID'] = 0 654 d['machoObjectsByID'] = {} 655 d['machoObjectConnectionsByObjectID'] = {} 656 d['sessionVariables'] = {} 657 d['lastRemoteCall'] = blue.os.GetWallclockTime() 658 d['nextSessionChange'] = None 659 d['sessionChangeReason'] = 'Initial State' 660 d['rwlock'] = None 661 d['sessionhist'] = [] 662 d['hasproblems'] = 0 663 d['mutating'] = 0 664 d['changing'] = None 665 d['additionalDistributedProps'] = [] 666 d['additionalNonIntegralAttributes'] = [] 667 d['longAttributes'] = [] 668 d['additionalAttributesToPrint'] = [] 669 d['additionalHexAttributes'] = [] 670 d['callThrottling'] = {} 671 d['contextOnly'] = machobase.mode == 'server' and sessionType in __contextOnlyTypes__ 672 d['countryCode'] = None 673 self.__ChangeAttribute('role', role) 674 self.LogSessionHistory('Session created') 675 676 def Throttle(self, key, throttleTimes, throttleInterval, userErrorMessage, userErrorParams = None): 677 lastKeyTimes = self.callThrottling.get(key, []) 678 now = blue.os.GetWallclockTime() 679 if len(lastKeyTimes) >= throttleTimes: 680 temp = [] 681 earliestTime = None 682 for time in lastKeyTimes: 683 if now - time < throttleInterval: 684 temp.append(time) 685 if earliestTime is None or time < earliestTime: 686 earliestTime = time 687 688 if len(temp) >= throttleTimes: 689 self.callThrottling[key] = temp 690 remainingTime = earliestTime + throttleInterval - now if earliestTime is not None else throttleInterval 691 mergedErrorParams = {'remainingTime': max(0, remainingTime)} 692 if userErrorParams is not None: 693 mergedErrorParams.update(userErrorParams) 694 raise UserError(userErrorMessage, mergedErrorParams) 695 else: 696 lastKeyTimes = temp 697 lastKeyTimes.append(now) 698 self.callThrottling[key] = lastKeyTimes 699 700 def IsMutating(self): 701 return self.mutating 702 703 def IsChanging(self): 704 return self.changing is not None 705 706 def IsItSafe(self): 707 return not (self.IsMutating() or self.IsChanging()) 708 709 def IsItSemiSafe(self): 710 return self.IsItSafe() or self.IsMutating() and self.IsChanging() 711 712 def WaitUntilSafe(self): 713 if session.IsItSafe(): 714 return 715 timeWaited = 0 716 while timeWaited <= 30000 and not session.IsItSafe(): 717 blue.pyos.synchro.SleepWallclock(100) 718 timeWaited += 100 719 720 if not session.IsItSafe(): 721 raise RuntimeError('Session did not become safe within 30secs') 722 723 def RegisterMachoObjectConnection(self, objectID, connection, refID): 724 connectionID = GetObjectUUID(connection) 725 if objectID not in self.machoObjectConnectionsByObjectID: 726 self.machoObjectConnectionsByObjectID[objectID] = [0, weakref.WeakValueDictionary({})] 727 self.machoObjectConnectionsByObjectID[objectID][1][connectionID] = connection 728 self.machoObjectConnectionsByObjectID[objectID][0] = max(self.machoObjectConnectionsByObjectID[objectID][0], refID) 729 730 def UnregisterMachoObjectConnection(self, objectID, connection): 731 connectionID = GetObjectUUID(connection) 732 if objectID not in self.machoObjectConnectionsByObjectID: 733 return None 734 else: 735 if connectionID in self.machoObjectConnectionsByObjectID[objectID][1]: 736 log.LogTraceback('Unexpected Crapola: connectionID still found in machoObjectConnectionsByObjectID[objectID]') 737 del self.machoObjectConnectionsByObjectID[objectID][1][connectionID] 738 if not self.machoObjectConnectionsByObjectID[objectID][1]: 739 refID = self.machoObjectConnectionsByObjectID[objectID][0] 740 del self.machoObjectConnectionsByObjectID[objectID] 741 return refID 742 return None 743 744 def RegisterMachoObject(self, objectID, object, refID): 745 sessionsByAttribute['objectID'][objectID][self.sid] = max(refID, sessionsByAttribute['objectID'][objectID].get(self.sid, 0)) 746 if objectID in self.machoObjectsByID: 747 self.machoObjectsByID[objectID][0] = max(refID, self.machoObjectsByID[objectID][0]) 748 else: 749 self.machoObjectsByID[objectID] = [refID, object] 750 751 def UnregisterMachoObject(self, objectID, refID, suppressnotification = 1): 752 try: 753 if objectID in self.machoObjectConnectionsByObjectID: 754 del self.machoObjectConnectionsByObjectID[objectID] 755 if objectID in sessionsByAttribute['objectID']: 756 if self.sid in sessionsByAttribute['objectID'][objectID]: 757 if refID is None or refID >= sessionsByAttribute['objectID'][objectID][self.sid]: 758 del sessionsByAttribute['objectID'][objectID][self.sid] 759 if not sessionsByAttribute['objectID'][objectID]: 760 del sessionsByAttribute['objectID'][objectID] 761 if objectID in self.machoObjectsByID: 762 if refID is None or refID >= self.machoObjectsByID[objectID][0]: 763 object = self.machoObjectsByID[objectID][1] 764 del self.machoObjectsByID[objectID] 765 if machobase.mode != 'client' and not suppressnotification and getattr(self, 'clientID', 0) and not getattr(self, 'clearing_session', 0): 766 sm.services['machoNet'].Scattercast('+clientID', [self.clientID], 'OnMachoObjectDisconnect', objectID, self.clientID, refID) 767 if isinstance(object, ObjectConnection): 768 object.DisconnectObject() 769 except Exception: 770 log.LogException() 771 sys.exc_clear() 772 773 def DumpSession(self, prefix, reason): 774 loglines = [prefix + ': ' + reason + ". It's history is as follows:"] 775 lastEntry = '' 776 for eachHistoryRecord in self.sessionhist: 777 header = prefix + ': ' + formatUtil.FmtDateEng(eachHistoryRecord[0], 'll') + ': ' 778 lines = eachHistoryRecord[1].split('\n') 779 tmp = eachHistoryRecord[2] 780 if tmp == lastEntry: 781 txt = '< same >' 782 else: 783 txt = tmp 784 lastEntry = tmp 785 footer = ', ' + txt 786 for eachLine in lines[:len(lines) - 1]: 787 loglines.append(header + eachLine) 788 789 loglines.append(header + lines[len(lines) - 1] + footer) 790 791 loglines.append(prefix + ': Current Session Data: %s' % strx(self)) 792 currentcall = localstorage.GetLocalStorage().get('base.currentcall', None) 793 if currentcall: 794 try: 795 currentcall = currentcall() 796 loglines.append('currentcall was: ' + strx(currentcall)) 797 except ReferenceError: 798 sys.exc_clear() 799 800 log.general.Log('\n'.join(loglines), 1, 2) 801 802 def Masquerade(self, props = None): 803 w = weakref.ref(self) 804 if self.charid: 805 tmp = {'base.session': w, 806 'base.charsession': w} 807 else: 808 tmp = {'base.session': w} 809 if props is not None: 810 tmp.update(props) 811 return MasqueradeMask(tmp) 812 813 def GetActualSession(self): 814 return self 815 816 def LogSessionHistory(self, reason, details = None, noBlather = 0): 817 if self.role & ROLE_SERVICE and not self.hasproblems: 818 return 819 timer = PushMark('LogSessionHistory') 820 try: 821 if details is None: 822 details = '' 823 for each in ['sid', 'clientID'] + self.__persistvars__: 824 if getattr(self, each, None) is not None: 825 details = details + each + ':' + strx(getattr(self, each)) + ', ' 826 827 details = 'session=' + details[:-2] 828 else: 829 details = 'info=' + strx(details) 830 self.__dict__['sessionhist'].append((blue.os.GetWallclockTime(), strx(reason)[:255], strx(details)[:255])) 831 if len(self.__dict__['sessionhist']) > 120: 832 self.__dict__['sessionhist'] = self.__dict__['sessionhist'][70:] 833 if not noBlather and log.general.IsOpen(1) and 'sm' in globals() and not sm.services['machoNet'].IsClusterShuttingDown(): 834 log.general.Log('SessionHistory: reason=%s, %s' % (reason, strx(details)), 1, 1) 835 finally: 836 PopMark(timer) 837 838 def LogSessionError(self, what, novalidate = 0): 839 self.__LogSessionProblem(what, 4, novalidate) 840 841 def __LogSessionProblem(self, what, how, novalidate = 0): 842 self.hasproblems = 1 843 self.LogSessionHistory(what) 844 if log.general.IsOpen(how): 845 lines = ['A session related error has occurred. Session history:'] 846 for eachHistoryRecord in self.sessionhist: 847 s = ''.join(map(strx, formatUtil.FmtDateEng(eachHistoryRecord[0], 'll') + ': ' + eachHistoryRecord[1] + ', ' + eachHistoryRecord[2])) 848 if len(s) > 5000: 849 s = s[:5000] 850 while len(s) > 255: 851 lines.append(s[:253]) 852 s = '- ' + s[253:] 853 854 lines.append(s) 855 856 lines.append('Session Data (should be identical to last history record): %s' % strx(self)) 857 try: 858 currentcall = localstorage.GetLocalStorage().get('base.currentcall', None) 859 if currentcall: 860 currentcall = currentcall() 861 lines.append('currentcall was: ' + strx(currentcall)) 862 except ReferenceError: 863 sys.exc_clear() 864 865 log.general.Log('\n'.join(lines), how, 2) 866 if not novalidate: 867 self.ValidateSession('session-error-dump') 868 869 def SetSessionVariable(self, k, v): 870 if v is None: 871 try: 872 del self.__dict__['sessionVariables'][k] 873 except: 874 sys.exc_clear() 875 876 else: 877 self.__dict__['sessionVariables'][k] = v 878 879 def GetSessionVariable(self, k, defaultValue = None): 880 try: 881 return self.__dict__['sessionVariables'][k] 882 except: 883 sys.exc_clear() 884 if defaultValue is not None: 885 self.__dict__['sessionVariables'][k] = defaultValue 886 return defaultValue 887 return 888 889 def GetDistributedProps(self, getAll): 890 retval = [] 891 if self.role & ROLE_SERVICE == 0: 892 for attribute in self.__persistvars__ + self.additionalDistributedProps: 893 if getAll or self.__dict__[attribute] != self.GetDefaultValueOfAttribute(attribute): 894 retval.append(attribute) 895 896 return retval 897 898 __dependant_attributes__ = {'userid': ['role', 899 'charid', 900 'callback', 901 'languageID', 902 'userType', 903 'maxSessionTime', 904 'countryCode'], 905 'sid': ['userid']} 906 907 def DependantAttributes(self, attribute): 908 retval = self.__dependant_attributes__.get(attribute, []) 909 retval2 = set() 910 for each in retval: 911 retval2.add(each) 912 for other in self.DependantAttributes(each): 913 retval2.add(other) 914 915 return list(retval2) 916 917 def GetDefaultValueOfAttribute(self, attribute): 918 if attribute == 'role': 919 return ROLE_LOGIN 920 if attribute == 'sessionType': 921 return self.__dict__.get('sessionType', None) 922 if attribute in self.__attributesWithDefaultValueOfZero__: 923 return 0 924 if attribute == 'languageID' and machobase.mode == 'client': 925 return strx(prefs.GetValue('languageID', 'EN')) 926 927 def _DisconnectSessionObjects(self): 928 for each in self.__dict__['connectedObjects'].values(): 929 each[0].DisconnectObject() 930 931 for objectID in copy.copy(self.__dict__['machoObjectsByID']): 932 self.UnregisterMachoObject(objectID, None) 933 934 def ClearCharacterDependantAttributes(self): 935 machoNet = sm.GetServiceIfRunning('machoNet') 936 if machoNet and machoNet.IsClusterShuttingDown() and self.userid: 937 log.general.Log('Cluster shutting down, rejecting session clearing %s' % self.userid, log.LGINFO) 938 return 939 self.StartSessionChange(reason='ClearCharacterDependantAttributes') 940 try: 941 if getattr(self, 'clearing_session', 0): 942 self.LogSessionHistory("Tried to clear a cleared/clearing session's attributes") 943 else: 944 self.LogSessionHistory('Clearing character dependant session attributes') 945 self._DisconnectSessionObjects() 946 if self.sid in sessionsBySID: 947 self.ValidateSession('pre-clear') 948 for attr in self.__characterDependantAttributes__: 949 v = getattr(self, attr, None) 950 try: 951 del sessionsByAttribute[attr][v][self.sid] 952 if not sessionsByAttribute[attr][v]: 953 del sessionsByAttribute[attr][v] 954 except KeyError: 955 sys.exc_clear() 956 957 self.__dict__['clearing_session'] = 1 958 try: 959 d = {} 960 for each in self.__persistvars__: 961 if each in self.__userDependantAttributes__: 962 d[each] = getattr(self, each, None) 963 elif each not in ('connectedObjects', 'c2ooid'): 964 d[each] = self.GetDefaultValueOfAttribute(each) 965 966 self.SetAttributes(d, False, True) 967 self.__dict__['connectedObjects'] = {} 968 self.__dict__['machoObjectsByID'] = {} 969 d['sessionVariables'] = {} 970 self.LogSessionHistory('Character dependant session attributes cleared') 971 finally: 972 self.__dict__['clearing_session'] = 0 973 974 finally: 975 self.changing = None 976 977 def ClearAttributes(self, isRemote = 0, dontSendMessage = False): 978 machoNet = sm.GetServiceIfRunning('machoNet') 979 if machoNet and machoNet.IsClusterShuttingDown() and self.userid: 980 log.general.Log('Cluster shutting down, rejecting session clearing %s' % self.userid, log.LGINFO) 981 return 982 self.StartSessionChange(reason='ClearAttributes') 983 try: 984 if getattr(self, 'clearing_session', 0): 985 self.LogSessionHistory("Tried to clear a cleared/clearing session's attributes") 986 else: 987 self.LogSessionHistory('Clearing session attributes') 988 self._DisconnectSessionObjects() 989 if self.sid in sessionsBySID: 990 self.ValidateSession('pre-clear') 991 sid = self.sid 992 del sessionsBySID[sid] 993 for attr in sessionsByAttribute: 994 val = getattr(self, attr, None) 995 try: 996 try: 997 sessionsByAttribute[attr][val].discard(sid) 998 except AttributeError: 999 del sessionsByAttribute[attr][val][sid] 1000 1001 if not sessionsByAttribute[attr][val]: 1002 del sessionsByAttribute[attr][val] 1003 except Exception: 1004 sys.exc_clear() 1005 1006 self.__dict__['clearing_session'] = 1 1007 d = {} 1008 for each in self.__persistvars__: 1009 if each not in ('connectedObjects', 'c2ooid'): 1010 d[each] = self.GetDefaultValueOfAttribute(each) 1011 1012 self.SetAttributes(d, isRemote, dontSendMessage=dontSendMessage) 1013 self.__dict__['connectedObjects'] = {} 1014 self.__dict__['machoObjectsByID'] = {} 1015 d['sessionVariables'] = {} 1016 sm.ScatterEvent('OnSessionEnd', self.sid) 1017 self.LogSessionHistory('Session attributes cleared') 1018 finally: 1019 self.changing = None 1020 1021 def ValidateSession(self, prefix): 1022 bad = False 1023 if not self.contextOnly: 1024 if not getattr(self, 'clearing_session', 0): 1025 for attribute in sessionsByAttribute: 1026 value = getattr(self, attribute, None) 1027 if value: 1028 valueSIDs = sessionsByAttribute[attribute] 1029 if value not in valueSIDs: 1030 self.LogSessionHistory('sessionsByAttribute[%s] broken, %s is not found' % (attribute, value)) 1031 bad = True 1032 elif self.sid not in valueSIDs[value]: 1033 self.LogSessionHistory('sessionsByAttribute[%s][%s] broken, %s is not found' % (attribute, value, self.sid)) 1034 bad = True 1035 elif attribute in ('userid', 'charid') and len(valueSIDs[value]) != 1: 1036 self.LogSessionHistory('sessionsByAttribute[%s][%s] broken, this user/char has multiple sessions (%d)' % (attribute, value, len(valueSIDs[value]))) 1037 bad = True 1038 1039 if bad: 1040 self.LogSessionError("The session failed it's %s validation check. Session dump and stack trace follows." % (prefix,), 1) 1041 log.LogTraceback() 1042 return bad 1043 1044 def DisconnectFilteredObjects(self, disappeared): 1045 if disappeared: 1046 objects = [] 1047 for oid in self.connectedObjects.iterkeys(): 1048 objConn = self.connectedObjects[oid][0] 1049 object = objConn.__object__ 1050 if object is not None and hasattr(object, '__sessionfilter__'): 1051 for attribute in disappeared: 1052 if attribute in object.__sessionfilter__: 1053 objects.append((objConn, oid)) 1054 break 1055 1056 for objConn, oid in objects: 1057 with self.Masquerade({'base.caller': weakref.ref(objConn)}): 1058 try: 1059 if oid in self.connectedObjects: 1060 objConn.DisconnectObject() 1061 except Exception: 1062 log.LogException() 1063 sys.exc_clear() 1064 1065 def CallProcessChangeOnObjects(self, notify, isRemote): 1066 objects = [] 1067 notifyNodes = [] 1068 for oid in self.connectedObjects.iterkeys(): 1069 objConn = self.connectedObjects[oid][0] 1070 object = objConn.__object__ 1071 if object is not None and hasattr(object, '__sessionfilter__') and hasattr(object, 'ProcessSessionChange'): 1072 for attribute in notify.iterkeys(): 1073 if attribute in object.__sessionfilter__: 1074 objects.append((objConn, object, oid)) 1075 break 1076 1077 for objConn, object, oid in objects: 1078 with self.Masquerade({'base.caller': weakref.ref(objConn)}): 1079 try: 1080 if oid in self.connectedObjects: 1081 notifyNodes.append(object.ProcessSessionChange(isRemote, self, notify)) 1082 except Exception: 1083 log.LogException() 1084 sys.exc_clear() 1085 1086 return notifyNodes 1087 1088 def ComputeNotifySets(self, changes, pairs): 1089 notify = {} 1090 disappeared = set() 1091 for attribute in changes.iterkeys(): 1092 currentEffectiveValue = self.__dict__.get(attribute, self.GetDefaultValueOfAttribute(attribute)) 1093 newValue = changes[attribute][1] if pairs else changes[attribute] 1094 if currentEffectiveValue != newValue: 1095 notify[attribute] = (currentEffectiveValue, newValue) 1096 if currentEffectiveValue and not newValue: 1097 disappeared.add(attribute) 1098 1099 return (notify, disappeared) 1100 1101 def __ChangeAttribute(self, attribute, newValue): 1102 self.__dict__['nextSessionChange'] = blue.os.GetSimTime() + SESSIONCHANGEDELAY 1103 if getattr(self, 'clearing_session', 0): 1104 self.__dict__[attribute] = newValue 1105 else: 1106 valueSIDs = sessionsByAttribute.get(attribute, None) 1107 if valueSIDs is None: 1108 self.__dict__[attribute] = newValue 1109 else: 1110 try: 1111 if newValue and newValue not in valueSIDs: 1112 valueSIDs[newValue] = {} 1113 oldValue = self.__dict__[attribute] 1114 if not self.contextOnly: 1115 if oldValue and oldValue in valueSIDs and self.sid in valueSIDs[oldValue]: 1116 del valueSIDs[oldValue][self.sid] 1117 self.__dict__[attribute] = newValue 1118 if not self.contextOnly: 1119 if newValue: 1120 valueSIDs[newValue][self.sid] = 1 1121 if oldValue and oldValue in valueSIDs and not len(valueSIDs[oldValue]): 1122 del valueSIDs[oldValue] 1123 if newValue and attribute == 'charid' and not charsession: 1124 localstorage.UpdateLocalStorage({'base.charsession': weakref.ref(self)}) 1125 except: 1126 self.DumpSession('ARGH!!!', 'This session is blowing up during change attribute') 1127 raise 1128 1129 def RecalculateDependantAttributes(self, d): 1130 pass 1131 1132 def StartSessionChange(self, reason): 1133 if not self.changing: 1134 self.changing = reason 1135 1136 def SetAttributes(self, requestedChanges, isRemote = 0, dontSendMessage = False): 1137 machoNet = sm.GetServiceIfRunning('machoNet') 1138 if machoNet and machoNet.IsClusterShuttingDown() and getattr(self, 'userid', None): 1139 log.LogNotice('Cluster shutting down, rejecting session change %s' % self.userid) 1140 return 1141 self.StartSessionChange(reason='SetAttributes') 1142 try: 1143 self.LogSessionHistory('Setting session attributes') 1144 try: 1145 requestedChanges = copy.copy(requestedChanges) 1146 nonPersisted = [] 1147 for attribute in requestedChanges: 1148 if attribute not in self.__persistvars__: 1149 nonPersisted.append(attribute) 1150 1151 if nonPersisted: 1152 log.LogTraceback(extraText=strx(nonPersisted), severity=log.LGWARN) 1153 for attribute in nonPersisted: 1154 del requestedChanges[attribute] 1155 1156 dependantAttributes = [] 1157 changes = {} 1158 for attribute in requestedChanges.iterkeys(): 1159 dependantAttributes += self.DependantAttributes(attribute) 1160 if requestedChanges[attribute] is not None and attribute not in ['address', 'languageID', 'countryCode'] + self.additionalNonIntegralAttributes: 1161 try: 1162 if attribute in self.longAttributes: 1163 changes[attribute] = long(requestedChanges[attribute]) 1164 else: 1165 changes[attribute] = int(requestedChanges[attribute]) 1166 except TypeError: 1167 log.general.Log('%s is not an integer %s' % (attribute, strx(requestedChanges[attribute])), 4, 1) 1168 log.LogTraceback() 1169 raise 1170 1171 else: 1172 changes[attribute] = requestedChanges[attribute] 1173 1174 charID = requestedChanges.get('charid', None) 1175 if charID is not None and charID != self.charid: 1176 changes.update(sm.GetService('sessionMgr').GetInitialValuesFromCharID(charID)) 1177 for attribute in dependantAttributes: 1178 if attribute not in changes: 1179 changes[attribute] = self.GetDefaultValueOfAttribute(attribute) 1180 1181 self.RecalculateDependantAttributes(changes) 1182 self.ValidateSession('pre-change') 1183 notify, disappeared = self.ComputeNotifySets(changes, pairs=False) 1184 if notify: 1185 if 'userid' in notify and notify['userid'][0] and notify['userid'][1]: 1186 self.LogSessionError("A session's userID may not change, %s=>%s" % notify['userid']) 1187 raise RuntimeError("A session's userID may not change") 1188 mask = None 1189 try: 1190 if self.role & ROLE_SERVICE == 0: 1191 mask = self.Masquerade() 1192 if not self.contextOnly: 1193 sm.NotifySessionChange('DoSessionChanging', isRemote, self, notify) 1194 self.DisconnectFilteredObjects(disappeared) 1195 for attribute in notify: 1196 self.__ChangeAttribute(attribute, changes[attribute]) 1197 1198 self.ValidateSession('post-change') 1199 if self.role & ROLE_SERVICE == 0 and not dontSendMessage: 1200 if not self.contextOnly: 1201 notifyAdditionalNodes = list(sm.NotifySessionChange('ProcessSessionChange', isRemote, self, notify)) 1202 notifyAdditionalNodes.append(self.CallProcessChangeOnObjects(notify, isRemote)) 1203 else: 1204 notifyAdditionalNodes = sm.GetService('sessionMgr').ProcessSessionChange(isRemote, self, notify) 1205 clientID = getattr(self, 'clientID', None) 1206 if clientID and not isRemote: 1207 if not (self.role & (ROLE_LOGIN | ROLE_PLAYER) or self.role & (ROLE_SERVICE | ROLE_REMOTESERVICE)): 1208 self.LogSessionError("A distributed session's role should probably always have login and player rights, even before a change broadcast") 1209 sessionChangeLayer = sm.services['machoNet'].GetGPCS('sessionchange') 1210 if sessionChangeLayer is not None: 1211 sessionChangeLayer.SessionChanged(clientID, self.sid, notify, notifyAdditionalNodes) 1212 if not self.contextOnly: 1213 sm.NotifySessionChange('OnSessionChanged', isRemote, self, notify) 1214 finally: 1215 if mask is not None: 1216 mask.UnMask() 1217 1218 finally: 1219 self.LogSessionHistory('Session attributes set') 1220 1221 finally: 1222 self.changing = None 1223 1224 def RecalculateDependantAttributesWithChanges(self, changes): 1225 pass 1226 1227 def ApplyRemoteAttributeChanges(self, changes, initialState): 1228 self.StartSessionChange(reason='ApplyInitialState' if initialState else 'ApplyRemoteAttributeChanges') 1229 try: 1230 self.LogSessionHistory('Receiving and performing %s' % self.changing) 1231 if self.role & ROLE_SERVICE: 1232 errorString = 'A service session may not change via %s, changes=%s' % (self.changing, strx(changes)) 1233 self.LogSessionError(errorString) 1234 raise RuntimeError(errorString) 1235 if not self.role & (ROLE_LOGIN | ROLE_PLAYER): 1236 self.LogSessionError("A distributed session's role should probably always have login and player rights, even during a change broadcast") 1237 self.ValidateSession('pre-change') 1238 if initialState: 1239 self.RecalculateDependantAttributes(changes) 1240 else: 1241 self.RecalculateDependantAttributesWithChanges(changes) 1242 notify, disappeared = self.ComputeNotifySets(changes, pairs=not initialState) 1243 if notify: 1244 if 'userid' in notify and notify['userid'][0] and notify['userid'][1]: 1245 self.LogSessionError("A session's userID may not change, %s=>%s" % notify['userid']) 1246 raise RuntimeError("A session's userID may not change") 1247 if not initialState and 'role' in notify and self.charid and notify['role'][1] != self.role: 1248 initial_roles, new_roles = changes['role'] 1249 if initial_roles and new_roles: 1250 if new_roles not in (add_role(initial_roles, ROLE_PLAYER), remove_role(initial_roles, ROLE_PLAYER)): 1251 self.LogSessionError("A session's role should probably not change for active characters, even in remote attribute stuff") 1252 mask = None 1253 try: 1254 mask = self.Masquerade() 1255 if not self.contextOnly: 1256 sm.NotifySessionChange('DoSessionChanging', True, self, notify) 1257 self.DisconnectFilteredObjects(disappeared) 1258 for attribute in notify: 1259 self.__ChangeAttribute(attribute, changes[attribute] if initialState else changes[attribute][1]) 1260 1261 self.ValidateSession('post-change') 1262 if not self.contextOnly: 1263 sm.NotifySessionChange('ProcessSessionChange', True, self, notify) 1264 self.CallProcessChangeOnObjects(notify, isRemote=True) 1265 sm.NotifySessionChange('OnSessionChanged', True, self, notify) 1266 finally: 1267 if mask is not None: 1268 mask.UnMask() 1269 self.LogSessionHistory(self.changing) 1270 1271 finally: 1272 self.changing = None 1273 1274 def DelayedInitialStateChange(self): 1275 if self.role & ROLE_SERVICE != 0: 1276 errorString = 'A service session may not change via DelayedInitialStateChange' 1277 self.LogSessionError(errorString) 1278 raise RuntimeError(errorString) 1279 if machobase.mode != 'server': 1280 raise RuntimeError('DelayedInitialStateChange called on %s, can only be called on server', machobase.mode) 1281 mask = None 1282 try: 1283 self.LogSessionHistory('CTXSESS: Performing a delayed initial state change on session', self.sid) 1284 self.StartSessionChange(reason='ApplyInitialState') 1285 changes = {attr:self.__dict__[attr] for attr in self.GetDistributedProps(False)} 1286 notify = {} 1287 for attribute, myValue in changes.iteritems(): 1288 defaultValue = self.GetDefaultValueOfAttribute(attribute) 1289 if myValue != defaultValue: 1290 notify[attribute] = (defaultValue, myValue) 1291 1292 if notify: 1293 mask = self.Masquerade() 1294 sm.NotifySessionChange('DoSessionChanging', True, self, notify) 1295 for attribute, value in changes.iteritems(): 1296 valueSIDs = sessionsByAttribute.get(attribute, None) 1297 if valueSIDs is not None: 1298 if value not in valueSIDs: 1299 valueSIDs[value] = {} 1300 valueSIDs[value][self.sid] = 1 1301 1302 sessionsBySID[self.sid] = self 1303 self.ValidateSession('post-delayedinitialstatechange') 1304 sm.NotifySessionChange('ProcessSessionChange', True, self, notify) 1305 self.CallProcessChangeOnObjects(notify, isRemote=True) 1306 sm.NotifySessionChange('OnSessionChanged', True, self, notify) 1307 finally: 1308 if mask is not None: 1309 mask.UnMask() 1310 self.LogSessionHistory('Delayed ApplyInitialState') 1311 self.changing = None 1312 1313 def __repr__(self): 1314 ret = '<Session: (' 1315 for each in ['sid', 1316 'clientID', 1317 'changing', 1318 'mutating', 1319 'contextOnly'] + self.additionalAttributesToPrint + self.__persistvars__: 1320 if getattr(self, each, None) is not None: 1321 if each in ['role'] + self.additionalHexAttributes: 1322 ret = ret + each + ':' + strx(hex(getattr(self, each))) + ', ' 1323 else: 1324 ret = ret + each + ':' + strx(getattr(self, each)) + ', ' 1325 1326 ret = ret[:-2] + ')>' 1327 return ret 1328 1329 def __setattr__(self, attr, value): 1330 if attr in ['sid', 'clientID'] + self.additionalNoSetAttributes + self.__persistvars__: 1331 raise RuntimeError('ReadOnly', attr) 1332 else: 1333 self.__dict__[attr] = value 1334 1335 def DisconnectObject(self, object, key = None, delaySecs = 1): 1336 if key is None: 1337 caller = localstorage.GetLocalStorage().get('base.caller', None) 1338 if caller: 1339 caller = caller() 1340 if isinstance(caller, ObjectConnection) and caller.__object__ is object: 1341 caller.DisconnectObject(delaySecs) 1342 return 1343 for k, v in self.connectedObjects.items(): 1344 obConn, = v 1345 if obConn.__object__ is object and (key is None or key == (obConn.__dict__['__session__'].sid, obConn.__dict__['__c2ooid__'])): 1346 obConn.DisconnectObject(delaySecs) 1347 1348 def RedirectObject(self, object, serviceName = None, bindParams = None, key = None): 1349 for k, v in self.connectedObjects.items(): 1350 obConn, = v 1351 if obConn.__object__ is object and (key is None or key == (obConn.__dict__['__session__'].sid, obConn.__dict__['__c2ooid__'])): 1352 obConn.RedirectObject(serviceName, bindParams) 1353 1354 def ConnectToObject(self, object, serviceName = None, bindParams = None): 1355 c2ooid = self.__dict__['c2ooid'] 1356 self.__dict__['c2ooid'] += 1 1357 return ObjectConnection(self, object, c2ooid, serviceName, bindParams) 1358 1359 def ConnectToClientService(self, svc, idtype = None, theID = None): 1360 if theID is None or idtype is None: 1361 if self.role & ROLE_SERVICE: 1362 log.LogTraceback() 1363 raise RuntimeError('You must specify an ID type and ID to identify the client') 1364 else: 1365 theID = self.clientID 1366 idtype = 'clientID' 1367 elif not self.role & ROLE_SERVICE and machobase.mode != 'client' and not IsInClientContext(): 1368 log.LogTraceback() 1369 raise RuntimeError('You cannot cross the wire except in the context of a service') 1370 if currentcall: 1371 currentcall.UnLockSession() 1372 return sm.services['sessionMgr'].ConnectToClientService(svc, idtype, theID) 1373 1374 def ConnectToService(self, svc, **keywords): 1375 return ServiceConnection(self, svc, **keywords) 1376 1377 def ConnectToAllServices(self, svc, batchInterval = 0): 1378 if not self.role & ROLE_SERVICE and machobase.mode != 'client' and not IsInClientContext(): 1379 raise RuntimeError('You cannot cross the wire except in the context of a service') 1380 return sm.services['machoNet'].ConnectToAllServices(svc, self, batchInterval=batchInterval) 1381 1382 def ConnectToRemoteService(self, svc, nodeID = None): 1383 if not self.role & ROLE_SERVICE and machobase.mode != 'client' and not IsInClientContext(): 1384 raise RuntimeError('You cannot cross the wire except in the context of a service') 1385 if machobase.mode == 'server' and nodeID is None: 1386 nodeID = sm.GetService(svc).MachoResolve(self) 1387 if type(nodeID) == types.StringType: 1388 raise RuntimeError(nodeID) 1389 elif nodeID is None: 1390 return self.ConnectToService(svc) 1391 if nodeID is not None and nodeID == sm.services['machoNet'].GetNodeID(): 1392 return self.ConnectToService(svc) 1393 return sm.services['machoNet'].ConnectToRemoteService(svc, nodeID, self) 1394 1395 def ConnectToSolServerService(self, svc, nodeID = None): 1396 if not self.role & ROLE_SERVICE and machobase.mode != 'client' and not IsInClientContext(): 1397 raise RuntimeError('You cannot cross the wire except in the context of a service') 1398 if machobase.mode == 'server' and nodeID is None: 1399 nodeID = sm.GetService(svc).MachoResolve(self) 1400 if type(nodeID) == types.StringType: 1401 raise RuntimeError(nodeID) 1402 elif nodeID is None: 1403 return self.ConnectToService(svc) 1404 if machobase.mode == 'server' and (nodeID is None or nodeID == sm.services['machoNet'].GetNodeID()): 1405 return self.ConnectToService(svc) 1406 else: 1407 return sm.services['machoNet'].ConnectToRemoteService(svc, nodeID, self) 1408 1409 def ConnectToProxyServerService(self, svc, nodeID = None): 1410 if not self.role & ROLE_SERVICE and machobase.mode != 'client' and not IsInClientContext(): 1411 raise RuntimeError('You cannot cross the wire except in the context of a service') 1412 if machobase.mode == 'proxy' and (nodeID is None or nodeID == sm.services['machoNet'].GetNodeID()): 1413 return self.ConnectToService(svc) 1414 else: 1415 return sm.services['machoNet'].ConnectToRemoteService(svc, nodeID, self) 1416 1417 def ConnectToAnyService(self, svc): 1418 if not self.role & ROLE_SERVICE and machobase.mode != 'client' and not IsInClientContext(): 1419 raise RuntimeError('You cannot cross the wire except in the context of a service') 1420 if svc in sm.services: 1421 return self.ConnectToService(svc) 1422 else: 1423 return self.ConnectToRemoteService(svc) 1424 1425 def ConnectToAllNeighboringServices(self, svc, batchInterval = 0): 1426 if not self.role & ROLE_SERVICE and machobase.mode != 'client' and not IsInClientContext(): 1427 raise RuntimeError('You cannot cross the wire except in the context of a service') 1428 return sm.services['machoNet'].ConnectToAllNeighboringServices(svc, self, batchInterval=batchInterval) 1429 1430 def ConnectToAllProxyServerServices(self, svc, batchInterval = 0): 1431 if not self.role & ROLE_SERVICE and machobase.mode != 'client' and not IsInClientContext(): 1432 raise RuntimeError('You cannot cross the wire except in the context of a service') 1433 if machobase.mode == 'proxy': 1434 return sm.services['machoNet'].ConnectToAllSiblingServices(svc, self, batchInterval=batchInterval) 1435 else: 1436 return sm.services['machoNet'].ConnectToAllNeighboringServices(svc, self, batchInterval=batchInterval) 1437 1438 def ConnectToAllSolServerServices(self, svc, batchInterval = 0): 1439 if not self.role & ROLE_SERVICE and machobase.mode != 'client' and not IsInClientContext(): 1440 raise RuntimeError('You cannot cross the wire except in the context of a service') 1441 if machobase.mode == 'server': 1442 return sm.services['machoNet'].ConnectToAllSiblingServices(svc, self, batchInterval=batchInterval) 1443 else: 1444 return sm.services['machoNet'].ConnectToAllNeighboringServices(svc, self, batchInterval=batchInterval) 1445 1446 def RemoteServiceCall(self, dest, service, method, *args, **keywords): 1447 return self.RemoteServiceCallWithoutTheStars(dest, service, method, args, keywords) 1448 1449 def RemoteServiceCallWithoutTheStars(self, dest, service, method, *args, **keywords): 1450 if not self.role & ROLE_SERVICE and machobase.mode != 'client' and not IsInClientContext(): 1451 raise RuntimeError('You cannot cross the wire except in the context of a service') 1452 return sm.services['machoNet'].RemoteServiceCallWithoutTheStars(self, dest, service, method, args, keywords) 1453 1454 def RemoteServiceNotify(self, dest, service, method, *args, **keywords): 1455 return self.RemoteServiceNotifyWithoutTheStars(dest, service, method, args, keywords) 1456 1457 def RemoteServiceNotifyWithoutTheStars(self, dest, service, method, args, keywords): 1458 if not self.role & ROLE_SERVICE and machobase.mode != 'client' and not IsInClientContext(): 1459 raise RuntimeError('You cannot cross the wire except in the context of a service') 1460 sm.services['machoNet'].RemoteServiceNotifyWithoutTheStars(self, args, keywords) 1461 1462 def ResetSessionChangeTimer(self, reason): 1463 sm.GetService('sessionMgr').LogInfo("Resetting next legal session change timer, reason='", reason, "', was ", formatUtil.FmtDateEng(self.nextSessionChange or blue.os.GetSimTime())) 1464 self.nextSessionChange = None 1465 1466 def ServiceProxy(self, serviceName): 1467 return ServiceProxy(serviceName, self) 1468 1469 1470 class ServiceConnection(): 1471 __restrictedcalls__ = {'Lock': 1, 1472 'UnLock': 1, 1473 'GetMachoObjectBoundToSession': 1} 1474 1475 def __init__(self, sess, service, **keywords): 1476 self.__session__ = weakref.proxy(sess) 1477 self.__service__ = service 1478 self.__remote__ = keywords.get('remote', 0) 1479 sm.StartService(self.__service__) 1480 1481 def Lock(self, lockID): 1482 return sm.GetService(self.__service__).LockService(lockID) 1483 1484 def UnLock(self, lockID, lock): 1485 sm.GetService(self.__service__).UnLockService(lockID, lock) 1486 1487 def GetInstanceID(self): 1488 return sm.GetService(self.__service__).startedWhen 1489 1490 def __getitem__(self, key): 1491 mn = sm.services['machoNet'] 1492 if type(key) == types.TupleType: 1493 nodeID = mn.GetNodeFromAddress(key[0], key[1]) 1494 elif type(key) == types.IntType: 1495 nodeID = key 1496 else: 1497 srv = sm.StartServiceAndWaitForRunningState(self.__service__) 1498 nodeID = self.MachoResolve(key) 1499 if nodeID == mn.GetNodeID(): 1500 return self 1501 else: 1502 return self.__session__.ConnectToRemoteService(self.__service__, nodeID) 1503 1504 def __nonzero__(self): 1505 return 1 1506 1507 def __str__(self): 1508 sess = 'unknown' 1509 try: 1510 sess = strx(self.__session__) 1511 except: 1512 pass 1513 1514 return 'ServiceConnection, Service:' + strx(self.__service__) + '. Session:' + sess 1515 1516 def __repr__(self): 1517 return self.__str__() 1518 1519 def __getattr__(self, method): 1520 if method in self.__dict__: 1521 return self.__dict__[method] 1522 if method.startswith('__'): 1523 raise AttributeError(method) 1524 svc = sm.StartService(self.__service__) 1525 if not self.__remote__ and (self.__session__.role & ROLE_SERVICE or machobase.mode == 'client' or method == 'MachoResolve'): 1526 self.__WaitForRunningState(svc) 1527 if method.endswith('_Ex'): 1528 return FastCallWrapper(self.__session__, svc, method[:-3], self) 1529 else: 1530 return FastCallWrapper(self.__session__, svc, method, self) 1531 if self.__session__.role & ROLE_SERVICE: 1532 return UnlockedServiceCallWrapper(self.__session__, svc, method, self, self.__service__) 1533 else: 1534 return ServiceCallWrapper(self.__session__, svc, method, self, self.__service__) 1535 1536 def __WaitForRunningState(self, svc): 1537 desiredStates = (SERVICE_RUNNING,) 1538 errorStates = (SERVICE_FAILED, SERVICE_STOPPED) 1539 sm.WaitForServiceObjectState(svc, desiredStates, errorStates) 1540 1541 1542 class MasqueradeMask(object): 1543 1544 def __init__(self, props): 1545 self.__prevStorage = localstorage.UpdateLocalStorage(props) 1546 1547 def __enter__(self): 1548 pass 1549 1550 def __exit__(self, e, v, tb): 1551 self.UnMask() 1552 1553 def UnMask(self): 1554 localstorage.SetLocalStorage(self.__prevStorage) 1555 self.__prevStorage = None 1556 1557 1558 class Session(CoreSession): 1559 __persistvars__ = CoreSession.__persistvars__ + ['regionid', 1560 'constellationid', 1561 'allianceid', 1562 'warfactionid', 1563 'corpid', 1564 'fleetid', 1565 'fleetrole', 1566 'wingid', 1567 'squadid', 1568 'shipid', 1569 'stationid', 1570 'structureid', 1571 'solarsystemid', 1572 'solarsystemid2', 1573 'hqID', 1574 'baseID', 1575 'rolesAtAll', 1576 'rolesAtHQ', 1577 'rolesAtBase', 1578 'rolesAtOther', 1579 'genderID', 1580 'bloodlineID', 1581 'raceID', 1582 'corpAccountKey', 1583 'inDetention'] 1584 __nonpersistvars__ = CoreSession.__nonpersistvars__ + ['locationid', 'corprole'] 1585 __attributesWithDefaultValueOfZero__ = CoreSession.__attributesWithDefaultValueOfZero__ + ['corprole', 1586 'rolesAtAll', 1587 'rolesAtHQ', 1588 'rolesAtBase', 1589 'rolesAtOther'] 1590 __dependant_attributes_eve__ = {'userid': ['inDetention'], 1591 'charid': ['corpid', 1592 'fleetid', 1593 'shipid', 1594 'stationid', 1595 'structureid', 1596 'solarsystemid', 1597 'bloodlineID', 1598 'raceID', 1599 'genderID'], 1600 'corpid': ['baseID', 1601 'rolesAtAll', 1602 'rolesAtHQ', 1603 'rolesAtBase', 1604 'rolesAtOther', 1605 'hqID', 1606 'allianceid', 1607 'corpAccountKey', 1608 'warfactionid'], 1609 'baseID': ['corprole'], 1610 'rolesAtAll': ['corprole'], 1611 'rolesAtHQ': ['corprole'], 1612 'rolesAtBase': ['corprole'], 1613 'rolesAtOther': ['corprole'], 1614 'hqID': ['corprole'], 1615 'corpAccountKey': [], 1616 'stationid': ['locationid'], 1617 'solarsystemid': ['locationid'], 1618 'locationid': ['solarsystemid2'], 1619 'solarsystemid2': ['constellationid'], 1620 'constellationid': ['regionid'], 1621 'fleetid': ['fleetrole', 'wingid', 'squadid'], 1622 'wingid': ['squadid'], 1623 'squadid': []} 1624 __dependant_attributes__ = {} 1625 for key, val in CoreSession.__dependant_attributes__.iteritems(): 1626 __dependant_attributes__[key] = val + __dependant_attributes_eve__.get(key, []) 1627 1628 for key, val in __dependant_attributes_eve__.iteritems(): 1629 if key not in __dependant_attributes__: 1630 __dependant_attributes__[key] = val 1631 1632 def __init__(self, sid, localSID, role, sessionType): 1633 CoreSession.__init__(self, sid, localSID, role, sessionType, ['locationid', 'corprole']) 1634 self.additionalNoSetAttributes = ['locationid', 'corprole'] 1635 self.additionalDistributedProps = ['locationid', 'corprole'] 1636 self.additionalNonIntegralAttributes = ['fleetid', 1637 'fleetrole', 1638 'wingid', 1639 'squadid'] 1640 self.longAttributes = ['corprole'] 1641 self.additionalAttributesToPrint = ['locationid', 'corprole'] 1642 self.additionalHexAttributes = ['corprole', 1643 'rolesAtAll', 1644 'rolesAtHQ', 1645 'rolesAtBase', 1646 'rolesAtOther'] 1647 1648 def RecalculateDependantAttributes(self, d): 1649 if 'stationid' in d or 'solarsystemid' in d: 1650 d['locationid'] = d.get('stationid') or d.get('solarsystemid') 1651 for each in ('hqID', 'baseID', 'rolesAtAll', 'rolesAtHQ', 'rolesAtBase', 'rolesAtOther', 'stationid', 'solarsystemid'): 1652 if each in d: 1653 rolesAtAll = d.get('rolesAtAll', self.rolesAtAll) 1654 rolesAtHQ = d.get('rolesAtHQ', self.rolesAtHQ) 1655 rolesAtBase = d.get('rolesAtBase', self.rolesAtBase) 1656 rolesAtOther = d.get('rolesAtOther', self.rolesAtOther) 1657 hqID = d.get('hqID', self.hqID) 1658 baseID = d.get('baseID', self.baseID) 1659 stationid = d.get('stationid', self.stationid) 1660 solarsystemid = d.get('solarsystemid', self.solarsystemid) 1661 corprole = rolesAtAll | rolesAtOther 1662 if stationid: 1663 if stationid == hqID: 1664 corprole = rolesAtAll | rolesAtHQ 1665 elif stationid == baseID: 1666 corprole = rolesAtAll | rolesAtBase 1667 d['corprole'] = corprole 1668 break 1669 1670 def RecalculateDependantAttributesWithChanges(self, changes): 1671 if 'stationid' in changes or 'solarsystemid' in changes: 1672 old = self.locationid 1673 new = changes.get('stationid', [None, None])[1] 1674 if not new: 1675 new = changes.get('solarsystemid', [None, None])[1] 1676 changes['locationid'] = (old, new) 1677 for each in ('hqID', 'baseID', 'rolesAtAll', 'rolesAtHQ', 'rolesAtBase', 'rolesAtOther', 'stationid', 'solarsystemid'): 1678 if each in changes: 1679 rolesAtAll = changes.get('rolesAtAll', [None, self.rolesAtAll])[1] 1680 rolesAtHQ = changes.get('rolesAtHQ', [None, self.rolesAtHQ])[1] 1681 rolesAtBase = changes.get('rolesAtBase', [None, self.rolesAtBase])[1] 1682 rolesAtOther = changes.get('rolesAtOther', [None, self.rolesAtOther])[1] 1683 hqID = changes.get('hqID', [None, self.hqID])[1] 1684 baseID = changes.get('baseID', [None, self.baseID])[1] 1685 stationid = changes.get('stationid', [None, self.stationid])[1] 1686 solarsystemid = changes.get('solarsystemid', [None, self.solarsystemid])[1] 1687 old = self.corprole 1688 corprole = rolesAtAll | rolesAtOther 1689 if stationid: 1690 if stationid == hqID: 1691 corprole = rolesAtAll | rolesAtHQ 1692 elif stationid == baseID: 1693 corprole = rolesAtAll | rolesAtBase 1694 if old != corprole: 1695 changes['corprole'] = (old, corprole) 1696 break 1697 1698 1699 def CreateSession(sid = None, sessionType = const.session.SESSION_TYPE_GAME, role = ROLE_LOGIN): 1700 global local_sid 1701 if sessionType not in const.session.VALID_SESSION_TYPES: 1702 raise ValueError('Trying to create a session with an invalid session type') 1703 local_sid += 1 1704 while sid is None: 1705 sid = GetNewSid() 1706 if sid in sessionsBySID: 1707 log.general.Log('Session SID random collision!', log.LGWARN) 1708 sid = None 1709 1710 if sid in sessionsBySID: 1711 log.general.Log('Session SID collision!', log.LGERR) 1712 log.general.Log('Local session being broken %s' % (sessionsBySID[sid],), log.LGERR) 1713 s = Session(sid, local_sid, role, sessionType) 1714 if not s.contextOnly: 1715 sessionsBySID[sid] = s 1716 allSessionsBySID[sid] = s 1717 return s 1718 1719 1720 def GetServiceSession(serviceKey, refcounted = False): 1721 if serviceKey not in service_sessions: 1722 ret = CreateSession(GetNewSid(), const.session.SESSION_TYPE_SERVICE, ROLE_SERVICE) 1723 ret.serviceName = serviceKey 1724 service_sessions[serviceKey] = ret 1725 else: 1726 ret = service_sessions[serviceKey] 1727 if refcounted: 1728 if not hasattr(ret, 'remoteServiceSessionRefCount'): 1729 ret.__dict__['remoteServiceSessionRefCount'] = 1 1730 else: 1731 ret.__dict__['remoteServiceSessionRefCount'] += 1 1732 return ret 1733 1734 1735 class ObjectcastCallWrapper(): 1736 1737 def __init__(self, object): 1738 self.object = weakref.proxy(object) 1739 1740 def __call__(self, method, *args): 1741 sm.services['machoNet'].ObjectcastWithoutTheStars(self.object, method, args) 1742 1743 1744 class UpdatePublicAttributesCallWrapper(): 1745 1746 def __init__(self, object): 1747 self.object = weakref.proxy(object) 1748 1749 def __call__(self, *args, **keywords): 1750 pa = {} 1751 k = keywords.get('partial', []) 1752 for each in getattr(self.object, '__publicattributes__', []): 1753 if k and each not in k: 1754 continue 1755 if hasattr(self.object, each): 1756 pa[each] = getattr(self.object, each) 1757 1758 sm.services['machoNet'].Objectcast(self.object, 'OnObjectPublicAttributesUpdated', GetObjectUUID(self.object), pa, args, keywords) 1759 1760 1761 objectsByUUID = weakref.WeakValueDictionary({}) 1762 objectUUID = 0 1763 1764 def GetObjectUUID(object): 1765 global objectUUID 1766 global objectsByUUID 1767 if hasattr(object, '__machoObjectUUID__'): 1768 return object.__machoObjectUUID__ 1769 else: 1770 objectUUID += 1 1771 if machobase.mode == 'client': 1772 t = 'C=0:%s' % objectUUID 1773 else: 1774 t = 'N=%s:%s' % (sm.services['machoNet'].GetNodeID(), objectUUID) 1775 setattr(object, '__machoObjectUUID__', t) 1776 if not hasattr(object, '__publicattributes__'): 1777 setattr(object, '__publicattributes__', []) 1778 setattr(object, 'Objectcast', ObjectcastCallWrapper(object)) 1779 setattr(object, 'UpdatePublicAttributes', UpdatePublicAttributesCallWrapper(object)) 1780 objectsByUUID[t] = object 1781 return t 1782 1783 1784 def GetObjectByUUID(uuid): 1785 try: 1786 return objectsByUUID.get(uuid, None) 1787 except ReferenceError: 1788 sys.exc_clear() 1789 return None 1790 1791 1792 def ReadContextSessionTypesPrefs(): 1793 global __contextOnlyTypes__ 1794 PREFS_PARAMETER = 'ContextSessionTypes' 1795 try: 1796 __contextOnlyTypes__ = [] 1797 prefValue = prefs.GetValue(PREFS_PARAMETER, None) 1798 if prefValue is not None: 1799 log.LogInfo('CTXSESS: %s = %s', PREFS_PARAMETER, prefValue) 1800 contextTypes = prefValue.split(',') 1801 for typeName in contextTypes: 1802 if typeName in const.session.SESSION_NAME_TO_TYPE: 1803 __contextOnlyTypes__.append(const.session.SESSION_NAME_TO_TYPE[typeName]) 1804 else: 1805 log.LogError("Ignoring invalid session type '%s' in prefs parameter '%s'" % (typeName, PREFS_PARAMETER)) 1806 1807 else: 1808 log.LogInfo('CTXSESS: %s not provided, no context sessions will be created' % PREFS_PARAMETER) 1809 except Exception: 1810 log.LogException("Exception while parsing prefs parameter '%s'" % PREFS_PARAMETER) 1811 1812 1813 ReadContextSessionTypesPrefs()