Advertisement
Guest User

Untitled

a guest
Aug 19th, 2018
175
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 43.64 KB | None | 0 0
  1. # uncompyle6 version 3.2.3
  2. # Python bytecode 2.7 (62211)
  3. # Decompiled from: Python 3.6.2 (v3.6.2:5fd33b5, Jul  8 2017, 04:57:36) [MSC v.1900 64 bit (AMD64)]
  4. # Embedded file name: im\meet.pyo
  5. # Compiled at: 2014-10-22 13:53:01
  6. import logging, types, urllib, urllib2, xmlrpclib, json
  7. from im import session
  8. from imvu.event import EventBus
  9. from imvu.task import task, attachedtask, Sleep, Schedule, Event, WaitForEvent, WaitWithTimeout, TaskTimeout, Return, Queue as TaskQueue, Semaphore, TaskOwner, RunUntilComplete
  10. from imvu.imq.MQManager import MQListener
  11. import imvu.task
  12. from imvu.task.util import CallPeriodically
  13. from imvu.version import __version__
  14. from imvu.network import networkExceptions
  15. from imvu import weakmethod
  16. from imvu.util import assertInRelease
  17. import im.common
  18. from imvu.session import SessionDispatcher
  19. import imvu.fs, imvu.gateway, imvu.gateway.AvatarInfoManager
  20. from imvu.session import LocalChat
  21. from imvu.translation import LString
  22.  
  23. def NullFunc(*args, **kwargs):
  24.     pass
  25.  
  26.  
  27. logger = logging.getLogger('imvu.' + __name__)
  28. ConnectionLostMessage = 'You have been disconnected from the chat.'
  29. NetworkErrorRetryInterval = 10
  30. ERROR_CHAT_FULL = 14
  31. ERROR_CHAT_EMPTY = 15
  32. ERROR_CHAT_NOT_PUBLIC = 16
  33. ERROR_PUBLIC_ROOM_CLIENT_VERSION_OLD = 1
  34. ERROR_PUBLIC_ROOM_AGE_LIMIT = 2
  35. ERROR_PUBLIC_ROOM_CLOSED = 3
  36. ERROR_PUBLIC_ROOM_BOOTED = 4
  37. ERROR_PUBLIC_ROOM_FULL = 5
  38.  
  39. class DuplicateMessageDetector(object):
  40.  
  41.     def __init__(self, serviceProvider, timeout):
  42.         self.__byUser = {}
  43.         self.__timeout = timeout
  44.         self.__timeProvider = serviceProvider.timeProvider
  45.  
  46.     def checkDuplicate(self, msg):
  47.         from_id = str(msg['from_id'])
  48.         candidates = self.__byUser.get(from_id, [])
  49.         newList = []
  50.         isDuplicate = False
  51.         now = self.__timeProvider()
  52.         msgCopy = dict(msg)
  53.         msgCopy['_timeoutTime'] = now + self.__timeout
  54.         msgCopy['from_id'] = from_id
  55.         if 'message' in msgCopy:
  56.             msgCopy['message'] = msgCopy['message'].strip()
  57.         for c in candidates:
  58.             if c['_timeoutTime'] < now:
  59.                 pass
  60.             elif self._isDuplicate(c, msgCopy):
  61.                 logger.debug('Suppressing duplicate message %r', msgCopy)
  62.                 isDuplicate = True
  63.             else:
  64.                 newList.append(c)
  65.  
  66.         if not isDuplicate:
  67.             newList.append(msgCopy)
  68.         self.__byUser[from_id] = newList
  69.         return False
  70.  
  71.     def userDropped(self, userId):
  72.         if self.__byUser.has_key(str(userId)):
  73.             del self.__byUser[str(userId)]
  74.  
  75.     def _isDuplicate(self, a, b):
  76.         return a.get('message', None) == b.get('message', None)
  77.  
  78.  
  79. class NullDuplicateMessageDetector(object):
  80.  
  81.     def __init__(self, services=None, timeout=0):
  82.         pass
  83.  
  84.     def checkDuplicate(self, msg):
  85.         return False
  86.  
  87.     def userDropped(self, userId):
  88.         pass
  89.  
  90.  
  91. class InvitationDeclinedDialog(object):
  92.     uri = 'chrome://imvu/content/dialogs/input/index.html'
  93.     size = (496, 247)
  94.     title = 'Invitation Declined'
  95.     geckoListeners = []
  96.  
  97.  
  98. class DirectConnectSession(im.session.ImSession, TaskOwner, MQListener):
  99.     MaxSecondsToWaitForAccept = 60
  100.  
  101.     def __init__(self, userId, serviceProvider, showMessageFunc=NullFunc, parentHwnd=None, dispatcherFactory=SessionDispatcher, location=None):
  102.         im.session.ImSession.__init__(self)
  103.         TaskOwner.__init__(self, serviceProvider.taskScheduler)
  104.         self.activity = 'DirectConnect'
  105.         self.__dispatcher = serviceProvider.create(dispatcherFactory, sender=self)
  106.         self.__outgoingMessages = TaskQueue()
  107.         self.__duplicateDetector = NullDuplicateMessageDetector()
  108.         self.__location = location
  109.         self.__isConnected = False
  110.         self.__inviteToChatLock = Semaphore(1)
  111.         self.__chatConnectedEvent = Event()
  112.         self.chatId_ = None
  113.         self.userId_ = userId
  114.         self.participants_ = []
  115.         self.__pendingMessages = []
  116.         self.__active = True
  117.         self.showMessageFuncWr_ = weakmethod.ref(showMessageFunc)
  118.         self._updateParticipantEvent = Event()
  119.         self.__serviceProvider = serviceProvider
  120.         self.__parentHwnd = parentHwnd
  121.         self.__ignoredUsers = []
  122.         self.__is_running_ = False
  123.         self.__avatarInfoManager = imvu.gateway.AvatarInfoManager(self.__serviceProvider)
  124.         self.waitingScale_ = 5
  125.         self._log('creating new session')
  126.         self.lastMessageId_ = 0
  127.         self.__inviteAttempts = 0
  128.         self.__queueName = None
  129.         self.__imqSend = False
  130.         self.__imqReceive = False
  131.         self.__lastServerContact = 0
  132.         self.__participantUrl = None
  133.         self.__participantInfo = {}
  134.         self.__infoUpdateQueue = []
  135.         self.__processingParticipantInfoQueue = False
  136.         self.__sawPureUser = False
  137.         self.__account = None
  138.         self.__unsentParticipantChanges = {}
  139.         self.attachTask(CallPeriodically(self.__checkDisconnection, 5, immediatelyCall=True))
  140.         return
  141.  
  142.     def setLocation(self, roomPid):
  143.         self.__location = roomPid
  144.  
  145.     @property
  146.     def location(self):
  147.         return self.__location
  148.  
  149.     def updateParticipantInfo(self, account, updates):
  150.         if account:
  151.             self.__account = account
  152.         if not self.__account or not (self.__account.shouldAlwaysPostToChatParticipantEndPoint() or self.__account.shouldPostToChatParticipantEndPointIfPureUserPresent()):
  153.             return
  154.         self.__infoUpdateQueue.insert(len(self.__infoUpdateQueue), updates)
  155.         if self.__participantUrl != None and not self.__processingParticipantInfoQueue:
  156.             self.__processingParticipantInfoQueue = True
  157.             self.attachTask(self.__processParticipantInfoQueue())
  158.         return
  159.  
  160.     def __triggerParticipantUpdate(self, account=None):
  161.         if self.__unsentParticipantChanges:
  162.             self.updateParticipantInfo(account, self.__unsentParticipantChanges)
  163.  
  164.     def sawPureUser(self, account):
  165.         if not self.__sawPureUser and account.shouldPostToChatParticipantEndPointIfPureUserPresent():
  166.             self.__sawPureUser = True
  167.             self.__triggerParticipantUpdate(account)
  168.  
  169.     @task
  170.     def __processParticipantInfoQueue(self):
  171.         while len(self.__infoUpdateQueue) > 0:
  172.             changes = {}
  173.             queue = self.__infoUpdateQueue[:]
  174.             self.__infoUpdateQueue = []
  175.             for updates in queue:
  176.                 for key in updates.keys():
  177.                     if self.__participantInfo.get(key, None) != updates[key]:
  178.                         changes[key] = updates[key]
  179.  
  180.             if not (changes and self.participants_ and (self.__account.shouldAlwaysPostToChatParticipantEndPoint() or self.__account.shouldPostToChatParticipantEndPointIfPureUserPresent() and self.__sawPureUser)):
  181.                 self.__unsentParticipantChanges.update(changes)
  182.                 break
  183.             self.__participantInfo.update(changes)
  184.             logger.info('NRD POSTing to chat_participant endpoint: %r', changes)
  185.             try:
  186.                 yield imvu.http.securePost(url=self.__participantUrl, params=changes, auth=self.__account.getAuth(), responseSchema=[], network=self.__serviceProvider.network, method='POST')
  187.             except networkExceptions:
  188.                 pass
  189.  
  190.         self.__processingParticipantInfoQueue = False
  191.         return
  192.  
  193.     def _log(self, message, *args):
  194.         logger.info((message + ' session=%r'), *(args + (self,)))
  195.  
  196.     def getChatId(self):
  197.         return self.chatId_
  198.  
  199.     def isOwner(self, userId):
  200.         return self.userId_ == userId
  201.  
  202.     @property
  203.     def active(self):
  204.         return self.__active
  205.  
  206.     def __repr__(self):
  207.         return '<%s %s: instance %s, userId %s, chat %s>' % (
  208.          type(self).__name__,
  209.          self.activity,
  210.          self._instanceId,
  211.          self.userId_,
  212.          self.chatId_)
  213.  
  214.     @task
  215.     @staticmethod
  216.     def __reportChatTermination(chatGateway, userId, chatId):
  217.         if not chatId:
  218.             return
  219.         try:
  220.             yield chatGateway.terminateChat(userId, chatId)
  221.         except networkExceptions:
  222.             logger.exception('chatGateway.terminateChat(%r, %r) failed', userId, chatId)
  223.  
  224.     def closeSession(self):
  225.         self._log('closeSession')
  226.         self.__serviceProvider.taskScheduler.scheduleTask(self.__reportChatTermination(self.__serviceProvider.chatGateway, self.userId_, self.chatId_), executionPolicy=RunUntilComplete)
  227.         self.__markClosed()
  228.  
  229.     def __markClosed(self):
  230.         self._log('__markClosed')
  231.         self.stopAttachedTasks()
  232.         self.__dispatcher.dispose()
  233.         self.__active = False
  234.  
  235.     def isConnected(self):
  236.         return self.__isConnected
  237.  
  238.     def __checkDisconnection(self):
  239.         if self.__isConnected and self.__serviceProvider.timeProvider() - self.__lastServerContact > 120:
  240.             logger.info('Detected disconnection, last server contact at %d, it is now %d', self.__lastServerContact, self.__serviceProvider.timeProvider())
  241.             self.__serviceProvider.eventBus.fire(self, 'DisconnectionDetected', {})
  242.  
  243.     def maybeConnect(self, private=None):
  244.         if self.__isConnected or self.__is_running_:
  245.             return
  246.         self._log('maybeConnect decided to connect')
  247.         self.__is_running_ = True
  248.  
  249.         @task
  250.         def initialize():
  251.             yield self.__connectToChat(private=private)
  252.             self.__setupPostConnectTasks()
  253.  
  254.         self.attachTask(initialize())
  255.  
  256.     def __setupPostConnectTasks(self):
  257.         self.__isConnected = self.chatId_ is not None
  258.         if self.isConnected():
  259.             if not self.__serviceProvider.mqManager.enabled('imq.disable_xmlrpc_chat_polling'):
  260.                 self.attachTask(self._fetchNewMessages())
  261.             self.attachTask(self._sendOutgoingMessages())
  262.             self.attachTask(self._updateParticipantList())
  263.         return
  264.  
  265.     @task
  266.     def __getNewMessages(self):
  267.         try:
  268.             result = yield self.__serviceProvider.chatGateway.getNewMessages(userId=self.userId_, chatId=self.chatId_, lastMessageId=self.lastMessageId_)
  269.             yield Return(result)
  270.         except xmlrpclib.Fault as f:
  271.             if f.faultCode == imvu.gateway.ERROR_NO_LONGER_IN_CHAT:
  272.                 logger.exception('marking %s closed because of fault 9', self)
  273.                 self.__markClosed()
  274.                 self._showUiMessage(self.__serviceProvider.translationTable.LS('Sorry, you are no longer in the chat'))
  275.                 yield Return([])
  276.             else:
  277.                 raise
  278.  
  279.     def _showUiMessage(self, messageText, timeout=3):
  280.         msgFunc = self.showMessageFuncWr_()
  281.         if msgFunc:
  282.             return msgFunc(sess=self, messageText=messageText, timeout=timeout)
  283.  
  284.     def _showConnectedMessage(self):
  285.         pass
  286.  
  287.     def getParticipantUserIds(self):
  288.         return sorted(set([self.userId_] + self.participants_))
  289.  
  290.     @task
  291.     def __handleWaitingResult(self, result):
  292.         self._showStillWaitingMsg()
  293.         logger.debug('%s(userId=%s)::getOrMakeChat returned waiting result: %s', self, self.userId_, result)
  294.         try:
  295.             self.chatId_ = result['chatId']
  296.             self.__chatConnectedEvent.set()
  297.         except KeyError:
  298.             pass
  299.         else:
  300.             self.__serviceProvider.eventBus.fire(self, 'NewChatId', {'chatId': self.chatId_})
  301.  
  302.         yield Sleep(0.5 + self.waitingScale_ * 0.5)
  303.  
  304.     def __joinChat(self, chatId, seat=None, lastMessageId=0):
  305.         self.chatId_ = chatId
  306.         self.__chatConnectedEvent.set()
  307.         self.__serviceProvider.eventBus.fire(self, 'JoinedChat', {'chatId': self.chatId_, 'seat': seat})
  308.         self.__serviceProvider.eventBus.fire(self, 'NewChatId', {'chatId': self.chatId_})
  309.         if self.__serviceProvider.mqManager.enabled('imq.text_chat3'):
  310.             self.__queueName = '/chat/%i' % int(self.chatId_)
  311.             self.__imqSend = self.__serviceProvider.mqManager.enabled('imq.text_chat3.send')
  312.             if self.__serviceProvider.mqManager.enabled('imq.text_chat3.receive'):
  313.                 self.__imqReceive = True
  314.                 if self.__serviceProvider.mqManager.enabled('imq.text_chat3.filter_duplicates'):
  315.                     self.__duplicateDetector = DuplicateMessageDetector(self.__serviceProvider, 120)
  316.             self.__serviceProvider.mqManager.subscribe(self.__queueName, self, {'listen_to_self': True})
  317.         self.lastMessageId_ = int(lastMessageId)
  318.         self._log('Setting lastMessageId_ to %s', self.lastMessageId_)
  319.         if seat is not None:
  320.             self.sendImMessage(messageText='*seat %s' % seat)
  321.             if seat == 1:
  322.                 self.sendImMessage(messageText='*resume %s' % self.userId_)
  323.             else:
  324.                 self.sendImMessage(messageText='*accept %s' % self.userId_)
  325.         self._log('_fetchNewMessages connected to chat %s', self.chatId_)
  326.         self._showConnectedMessage()
  327.         self.__lastServerContact = self.__serviceProvider.timeProvider()
  328.         return
  329.  
  330.     @task
  331.     def __connectToChat(self, private=None):
  332.         attempts = 0
  333.         inviteId = None
  334.         while True:
  335.             if attempts == 5:
  336.                 self.__serviceProvider.eventBus.fire(self, 'ChatConnectFailed')
  337.             try:
  338.                 result = yield self.getOrMakeChat(inviteId=inviteId, private=private)
  339.             except networkExceptions:
  340.                 logger.exception('failed getOrMakeChat for userId %s, retrying', self.userId_)
  341.                 attempts += 1
  342.                 yield Sleep((0.5 + self.waitingScale_ * 0.5) * attempts)
  343.                 continue
  344.  
  345.             if result is None:
  346.                 attempts += 1
  347.                 yield Sleep((0.5 + self.waitingScale_ * 0.5) * attempts)
  348.                 continue
  349.             self._log('getOrMakeChat result: %s', result)
  350.             if result.get('response', 'accepted') == 'declined' or result.get('response', 'accepted') == 'timeout':
  351.                 break
  352.             self.__participantUrl = result.get('participantUrl')
  353.             if result.get('waiting', False):
  354.                 yield self.__handleWaitingResult(result)
  355.                 inviteId = result.get('inviteId', None)
  356.                 continue
  357.             self.__joinChat(result['chatId'], result.get('seat'), result.get('lastMessageId', 0))
  358.             break
  359.  
  360.         return
  361.  
  362.     @task
  363.     def _fetchNewMessages(self):
  364.         while True:
  365.             try:
  366.                 result = yield self.__getNewMessages()
  367.             except networkExceptions:
  368.                 logger.exception('failed getNewMessages for userId %s, retrying', self.userId_)
  369.                 self._showUiMessage(self.__serviceProvider.translationTable.LS('You have been disconnected from the chat.'))
  370.                 yield Sleep(NetworkErrorRetryInterval)
  371.             else:
  372.                 self.__lastServerContact = self.__serviceProvider.timeProvider()
  373.                 if result:
  374.                     self._log('received %s new messages: %s', len(result), result)
  375.                 else:
  376.                     self._log('new message has False result without NetworkException. Why?')
  377.                 i = 1
  378.                 for messageDict in result:
  379.                     self.__addIncomingMessage(messageDict)
  380.                     self.lastMessageId_ = messageDict['message_id']
  381.                     if i % 5 == 0:
  382.                         yield Sleep(0)
  383.                     i += 1
  384.  
  385.                 self._log('Setting lastMessageId_ to %s', self.lastMessageId_)
  386.                 yield Sleep(0.6)
  387.  
  388.     @task
  389.     def flushMessages(self, messages=[]):
  390.  
  391.         def formatMessage((msg, to)):
  392.             return {'userId': self.userId_, 'chatId': self.chatId_, 'message': msg, 'to': to}
  393.  
  394.         while not self.__outgoingMessages.empty():
  395.             messages.append((yield self.__outgoingMessages.get()))
  396.  
  397.         if not messages:
  398.             return
  399.         self._log('flushMessages dequeued messages %r', messages)
  400.         formattedMessages = map(formatMessage, messages)
  401.         if self.__imqSend:
  402.             for m in formattedMessages:
  403.                 jsonMsg = json.dumps(m)
  404.                 logger.debug('send IMQ chat message: %s', jsonMsg)
  405.                 self.__serviceProvider.mqManager.sendMessage(jsonMsg, self.__queueName, 'messages')
  406.  
  407.         if not self.__serviceProvider.mqManager.enabled('imq.disable_xmlrpc_send'):
  408.             for i in range(5):
  409.                 try:
  410.                     result = yield self.__serviceProvider.chatGateway.sendChatMessages(formattedMessages)
  411.                 except networkExceptions:
  412.                     logger.exception('Error sending chat messages')
  413.                     yield Sleep(1.5)
  414.                     continue
  415.                 else:
  416.                     self.__lastServerContact = self.__serviceProvider.timeProvider()
  417.                     self._log('successfully sent messages %r, result %s', messages, result)
  418.                     break
  419.  
  420.             else:
  421.                 for msg, to in messages:
  422.                     if not msg.startswith('*'):
  423.                         self._showUiMessage(self.__serviceProvider.translationTable.FLS('Message was not sent: {0!r}', msg))
  424.                         break
  425.  
  426.     @task
  427.     def _sendOutgoingMessages(self):
  428.         self._log('Starting outgoing message loop')
  429.         while True:
  430.             yield self.flushMessages(messages=[(yield self.__outgoingMessages.get())])
  431.  
  432.     @task
  433.     def _updateParticipantList(self):
  434.         self._log('Starting participant update loop')
  435.         try:
  436.             while True:
  437.                 try:
  438.                     participantInfos = yield self.__serviceProvider.chatGateway.getParticipants(self.userId_, self.chatId_)
  439.                 except networkExceptions:
  440.                     logger.exception('error trying to find participants for chat %s', self.chatId_)
  441.                 else:
  442.                     participantsChanged = False
  443.                     self.__lastServerContact = self.__serviceProvider.timeProvider()
  444.                     seats = {}
  445.                     newParticipants = set()
  446.                     for p in participantInfos:
  447.                         userId = int(p['userId'])
  448.                         seats[userId] = p['seat']
  449.                         newParticipants.add(userId)
  450.  
  451.                     for userId in set(self.participants_) - newParticipants:
  452.                         self._log('notifyParticipantRemoved(): userId: %r', userId)
  453.                         self.participants_.remove(userId)
  454.                         participantsChanged = True
  455.                         yield self.__dispatcher.participantLeft(userId)
  456.  
  457.                     for userId in newParticipants - set(self.participants_):
  458.                         self.participants_.append(userId)
  459.                         participantsChanged = True
  460.                         gotInfo = yield self.__dispatcher.participantAdded(userId, seats[userId])
  461.                         if not gotInfo:
  462.                             self.participants_.remove(userId)
  463.  
  464.                     for message_dict in self.__pendingMessages:
  465.                         if message_dict['from_id'] in self.participants_:
  466.                             self.__processIncomingMessage(message_dict)
  467.                         else:
  468.                             logger.warning('Ignoring message %r because user is not in chat', message_dict)
  469.  
  470.                     del self.__pendingMessages[:]
  471.                     if self.numParticipants() == 1 and self.isRoomSession():
  472.                         self.__outgoingMessages.put(('*uid %d' % self.userId_, 0))
  473.                     if participantsChanged:
  474.                         self.__serviceProvider.eventBus.fire(self, 'ParticipantsUpdated')
  475.                         self.__triggerParticipantUpdate()
  476.                     self._updateParticipantEvent.clear()
  477.                     try:
  478.                         yield WaitForEvent(self._updateParticipantEvent, 14.5)
  479.                     except TaskTimeout:
  480.                         pass
  481.  
  482.         finally:
  483.             self._log('Exiting update participant loop')
  484.  
  485.     def _partnerLeftDialogCallback(self, ignore):
  486.         self._log('_partnerLeftDialogCallback numParticipants_ is %s', self.numParticipants())
  487.         if self.numParticipants() <= 1 and not self.isRoomSession():
  488.             self.endSession()
  489.  
  490.     def ignoreUser(self, userId):
  491.         self.__ignoredUsers.append(userId)
  492.  
  493.     def unIgnoreUser(self, userId):
  494.         self.__ignoredUsers.remove(userId)
  495.  
  496.     def isIgnoredUser(self, userId):
  497.         return userId in self.__ignoredUsers
  498.  
  499.     def __addIncomingMessage(self, messageDict):
  500.         assertInRelease(messageDict)
  501.         from_id = int(messageDict['from_id'])
  502.         if from_id != 0:
  503.             if self.isIgnoredUser(from_id):
  504.                 return
  505.             if from_id not in self.getParticipantUserIds():
  506.                 self._log('Deferring message %r, updating participant list', messageDict)
  507.                 self.__pendingMessages.append(messageDict)
  508.                 self._updateParticipantEvent.set()
  509.                 return
  510.         self.__processIncomingMessage(messageDict)
  511.  
  512.     def __processIncomingMessage(self, messageDict):
  513.         if not self.__duplicateDetector.checkDuplicate(messageDict):
  514.             self.__dispatcher.notifyNewMessage(im.common.ImMessage(message=messageDict.get('message', ''), timestamp=self.__serviceProvider.timeProvider(), fromId=int(messageDict.get('from_id', 0)), toId=int(messageDict.get('to_id', 0))))
  515.  
  516.     def endSession(self):
  517.         self.__serviceProvider.eventBus.fire(self, 'Session.End')
  518.  
  519.     def sendImMessage(self, messageText, to=0):
  520.         self._log('sendImMessage(): messageText: %r', messageText)
  521.         self.maybeConnect()
  522.  
  523.         for i in range(3):
  524.             self.__addIncomingMessage({'from_id': self.userId_, 'message': messageText, 'to_id': to})
  525.             self.__outgoingMessages.put((messageText, to))
  526.  
  527.     def setCommandManager(self, c):
  528.         self.__dispatcher.setCommandManager(c)
  529.  
  530.     def numParticipants(self):
  531.         return len(self.getParticipantUserIds())
  532.  
  533.     def sessionIsFull(self):
  534.         return False
  535.  
  536.     def isPrivate(self):
  537.         return False
  538.  
  539.     @task
  540.     def _sendInvitation(self, partnerId, inviteId=None):
  541.         if partnerId == self.userId_:
  542.             yield Return({'response': 'decline', 'reason': 'You cannot invite yourself to a chat'})
  543.         yield self.__chatConnectedEvent.wait()
  544.         args = {'userId': self.userId_,
  545.            'partnerId': partnerId,
  546.            'chatId': self.chatId_ or 0,
  547.            'location': self.location}
  548.         if inviteId is not None:
  549.             args['inviteId'] = inviteId
  550.         rv = yield self.__serviceProvider.chatGateway.attemptInvite(**args)
  551.         yield Return(rv)
  552.         return
  553.  
  554.     def inviteToChat(self, inviteeId):
  555.         self.attachTask(self.__inviteToChat(inviteeId))
  556.  
  557.     @task
  558.     def sendAwayNote(self, inviteId, inviteeId, reason):
  559.         self._log('sendAwayNote(): inviteId: %r inviteeId: %r reason: %r', inviteId, inviteeId, reason)
  560.         reason = reason[10:]
  561.         partnerName = yield self.__serviceProvider.avatarInfoManager.getAvatarName(inviteeId)
  562.         dialog = InvitationDeclinedDialog()
  563.         dialog.dialogInfo = {'title': LString('Invitation declined'),
  564.            'message': self.__serviceProvider.translationTable.FLS('{avatarname} is currently: ', avatarname=partnerName) + self.__serviceProvider.translationTable.FLS('{awayMessage!r}.  Would you like to leave a note?', awayMessage=reason if reason else ''),
  565.            'defaultValue': ''}
  566.         user_message = self.__serviceProvider.dialogManager.showModal(self.__parentHwnd, dialog)
  567.         if not user_message:
  568.             return
  569.         user_name = yield self.__serviceProvider.avatarInfoManager.getAvatarName(self.userId_)
  570.         if not user_name:
  571.             user_name = '<Avatar>'
  572.         away_note = user_name + ':  ' + user_message
  573.         yield self.__serviceProvider.chatGateway.leaveInviteAwayNote(self.userId_, inviteId, away_note)
  574.  
  575.     @task
  576.     def __inviteToChat(self, inviteeId):
  577.         with (yield self.__inviteToChatLock.acquire()):
  578.             firstInviteAttemptTime = self.__serviceProvider.timeProvider()
  579.             self._log('inviteToChat(%s, %s) firstInviteAttemptTime=%d', self, inviteeId, firstInviteAttemptTime)
  580.             self.__inviteAttempts = 0
  581.             self._showStillWaitingMsg()
  582.             inviteId = None
  583.             while True:
  584.                 self.__inviteAttempts += 1
  585.                 logger.info('inviteToChat attempting to make invite #%d (time is %d)', self.__inviteAttempts, self.__serviceProvider.timeProvider())
  586.                 try:
  587.                     ret = yield self._sendInvitation(partnerId=inviteeId, inviteId=inviteId)
  588.                 except networkExceptions:
  589.                     logger.exception('sendInvitation raised, assuming we should keep waiting.')
  590.                     ret = {'waiting': True}
  591.  
  592.                 newInviteId = ret.get('inviteId')
  593.                 try:
  594.                     newInviteId = int(newInviteId)
  595.                 except (TypeError, ValueError):
  596.                     logger.warning('Got funky inviteId: %r', newInviteId)
  597.  
  598.                 if inviteId is not None and newInviteId is not None and inviteId != newInviteId:
  599.                     logger.critical('We asked for the status of an invite - but got back a new invite!')
  600.                 if inviteId is None:
  601.                     inviteId = newInviteId
  602.                 if not self.chatId_ and ret.get('chatId', 0) != 0:
  603.                     logger.info("Didn't have a chat, but got one! %r", ret['chatId'])
  604.                     self.__joinChat(ret['chatId'], 1)
  605.                     self.__setupPostConnectTasks()
  606.                 if 'waiting' in ret:
  607.                     if self.__serviceProvider.timeProvider() - firstInviteAttemptTime > self.MaxSecondsToWaitForAccept:
  608.                         self._log('partner %s timed out our invitation after %d seconds', inviteeId, self.__serviceProvider.timeProvider() - firstInviteAttemptTime)
  609.                         partnerName = yield self.__serviceProvider.avatarInfoManager.getAvatarName(inviteeId)
  610.                         self._hideStillWaitingMsg()
  611.                         self._showUiMessage(self.__serviceProvider.translationTable.FLS('{partnerName} did not answer your invitation.', partnerName=partnerName), timeout=30)
  612.                         return
  613.                 else:
  614.                     if 'response' in ret:
  615.                         response = ret['response']
  616.                         if response == 'decline':
  617.                             reason = ret.get('reason', None)
  618.                             inviteId = ret.get('inviteId', None)
  619.                             accessViolation = ret.get('accessViolation', None)
  620.                             if not reason:
  621.                                 reason = 'no reason given'
  622.                             self._log('partner %s declined our invitation, closing session', inviteeId)
  623.                             self._hideStillWaitingMsg()
  624.                             if reason.find("I'm away") >= 0 and inviteId:
  625.                                 self.attachTask(self.sendAwayNote(inviteId, inviteeId, reason))
  626.                             else:
  627.                                 partnerName = yield self.__serviceProvider.avatarInfoManager.getAvatarName(inviteeId)
  628.                                 if accessViolation:
  629.                                     self._showUiMessage(self.__serviceProvider.translationTable.FLS('{partnerName} can not join as the room only allows', partnerName=partnerName) + ' ' + accessViolation, timeout=300)
  630.                                 else:
  631.                                     self._showUiMessage(self.__serviceProvider.translationTable.FLS('{partnerName} declined to chat, saying', partnerName=partnerName) + " '" + reason + "'", timeout=300)
  632.                             return
  633.                         raise Exception('unknown response: %r' % ret)
  634.                     else:
  635.                         self._log('inviteToChat: invite was accepted from %s', inviteeId)
  636.                         self._updateParticipantEvent.set()
  637.                         self._hideStillWaitingMsg()
  638.                         return
  639.                 yield Sleep(1)
  640.  
  641.             raise Exception('should never be reached')
  642.         return
  643.  
  644.     def onImqMessage(self, message):
  645.         logger.info('%s.onImqMessage(%r)', type(self).__name__, [
  646.          message.user_id, message.queue, message.mount, message.message])
  647.         if message.mount == 'control':
  648.             m = json.loads(message.message)
  649.             if not isinstance(m, dict):
  650.                 logger.warning('Got invalid control message %r', m)
  651.                 return
  652.             self.__serviceProvider.eventBus.fire(self, 'ControlMessage', m)
  653.         else:
  654.             if message.mount == 'messages' and self.__imqReceive:
  655.                 m = json.loads(message.message)
  656.                 if not isinstance(m, dict):
  657.                     logger.warning('Got invalid chat message %r', m)
  658.                     return
  659.                 if isinstance(message.user_id, int):
  660.                     m['from_id'] = message.user_id if 1 else int(message.user_id.split('/')[-1])
  661.                     if m['from_id'] != m.get('userId', 0):
  662.                         logger.warning('forged message detected: from %r: %r', message.user_id, m)
  663.                     m['to_id'] = m.get('to', 0)
  664.                     self.__addIncomingMessage(m)
  665.  
  666.     def _showStillWaitingMsg(self):
  667.         pass
  668.  
  669.     def _hideStillWaitingMsg(self):
  670.         pass
  671.  
  672.     def canBoot(self, booter, bootee):
  673.         return False
  674.  
  675.     def isLieutenant(self, userId):
  676.         return False
  677.  
  678.  
  679. class InviteDecision():
  680.     ACCEPT = 'ACCEPT'
  681.     DECLINE = 'DECLINE'
  682.     IGNORE = 'IGNORE'
  683.     REJECTED = 'REJECTED'
  684.  
  685.  
  686. class ChatSession(DirectConnectSession):
  687.  
  688.     def __init__(self, serviceProvider, userId, result, showMessageFunc=NullFunc, parentHwnd=None, location=0):
  689.         DirectConnectSession.__init__(self, serviceProvider=serviceProvider, userId=userId, showMessageFunc=showMessageFunc, parentHwnd=parentHwnd, location=location)
  690.         self.__result = result
  691.         self.maybeConnect()
  692.  
  693.     @task
  694.     def getOrMakeChat(self, inviteId=None, private=None):
  695.         return self.__result
  696.  
  697.     def shouldResetRoomDefinitionAtStartup(self):
  698.         return False
  699.  
  700.  
  701. DEFAULT_PUBLIC_ROOM_TITLE = 'IMVU Chat Room'
  702.  
  703. class JoinRoomSession(DirectConnectSession):
  704.  
  705.     def __init__(self, userId, roomInstanceId, serviceProvider, modeConstructedEvent, showMessageFunc=NullFunc, parentHwnd=None, lieutenants=[], roomOwners=[], allowRoomShellOverwrite=False, allowLoadNewRoom=False, private=None, autoBootWhenOwnerLeaves=True):
  706.         DirectConnectSession.__init__(self, serviceProvider=serviceProvider, userId=userId, showMessageFunc=showMessageFunc, parentHwnd=parentHwnd)
  707.         if not isinstance(roomInstanceId, basestring):
  708.             raise TypeError('roomInstanceId must be a string, was %r' % (roomInstanceId,))
  709.         if not isinstance(roomOwners, list):
  710.             raise TypeError('roomOwners must be a list, was %r' % (roomOwners,))
  711.         self.roomInstanceId_ = roomInstanceId
  712.         self.__serviceProvider = serviceProvider
  713.         self.__modeConstructedEvent = modeConstructedEvent
  714.         self.__lieutenants = lieutenants
  715.         self.__roomOwners = roomOwners
  716.         self.__allowRoomShellOverwrite = allowRoomShellOverwrite
  717.         self.__allowLoadNewRoom = allowLoadNewRoom
  718.         self.__parentHwnd = parentHwnd
  719.         self.__private = private
  720.         self.__autoBootWhenOwnerLeaves = autoBootWhenOwnerLeaves
  721.         self.reasons_ = {ERROR_PUBLIC_ROOM_CLIENT_VERSION_OLD: self.__serviceProvider.translationTable.LS('Your client version is too old, please upgrade to the latest version.'),
  722.            ERROR_PUBLIC_ROOM_AGE_LIMIT: self.__serviceProvider.translationTable.LS('You are too young to join a chat room chat.'),
  723.            ERROR_PUBLIC_ROOM_CLOSED: self.__serviceProvider.translationTable.LS('The room is currently closed.'),
  724.            ERROR_PUBLIC_ROOM_BOOTED: self.__serviceProvider.translationTable.LS('You have been kicked out of the room.  Cannot rejoin within 20 minutes.'),
  725.            ERROR_PUBLIC_ROOM_FULL: self.__serviceProvider.translationTable.LS('The room is full.')}
  726.         self.maybeConnect(private=private)
  727.  
  728.     @property
  729.     def location(self):
  730.         return self.roomInstanceId_
  731.  
  732.     def isOwner(self, userId):
  733.         return self.roomInstanceId_.startswith(str(userId) + '-') or userId in self.getRoomOwners()
  734.  
  735.     def isPrivate(self):
  736.         return self.__private
  737.  
  738.     def getOwner(self):
  739.         return int(self.roomInstanceId_.split('-')[0])
  740.  
  741.     def isLieutenant(self, userId):
  742.         return str(userId) in self.__lieutenants
  743.  
  744.     def hasBootPrivileges(self, userId):
  745.         return self.isOwner(userId) or self.isLieutenant(userId)
  746.  
  747.     def canBoot(self, booter, bootee):
  748.         return self.hasBootPrivileges(booter) and not self.hasBootPrivileges(bootee)
  749.  
  750.     def isRoomSession(self):
  751.         return True
  752.  
  753.     def allowRoomShellOverwrite(self):
  754.         return self.__allowRoomShellOverwrite
  755.  
  756.     def autoBootWhenOwnerLeaves(self):
  757.         return self.__autoBootWhenOwnerLeaves
  758.  
  759.     def setAutoBootWhenOwnerLeaves(self, autoBootWhenOwnerLeaves):
  760.         self.__autoBootWhenOwnerLeaves = autoBootWhenOwnerLeaves
  761.  
  762.     def allowLoadNewRoom(self):
  763.         return self.__allowLoadNewRoom
  764.  
  765.     def getRoomOwners(self):
  766.         return self.__roomOwners
  767.  
  768.     def setRoomOwners(self, roomOwners):
  769.         self.__roomOwners = roomOwners
  770.  
  771.     def isAlwaysDriver(self):
  772.         return False
  773.  
  774.     def resetRoomDefinitionAtStartup(self):
  775.         return False
  776.  
  777.     def getRoomInstanceId(self):
  778.         return self.roomInstanceId_
  779.  
  780.     def setRoomInstanceId(self, roomInstanceId):
  781.         self.roomInstanceId_ = roomInstanceId
  782.  
  783.     @task
  784.     def getOrMakeChat(self, inviteId=None, private=None):
  785.         self._log('JoinRoomSession::getOrMakeChat(): self.userId_: %r self.roomInstanceId_: %r', self.userId_, self.roomInstanceId_)
  786.         activity = 'publicroom-%s' % self.roomInstanceId_
  787.         ret = yield self.__serviceProvider.chatGateway.getOrMakeChat(self.userId_, activity, self.chatId_ or 0, capacity=9999, publicRoom=True, private=private)
  788.         if 'response' in ret and ret['response'] == 'declined':
  789.             errorCode = ret.get('reason', None)
  790.             errorExplanation = ret.get('explanation', None)
  791.             self._log('User %s declined to join the chat room, closing session', self.userId_)
  792.             yield self.__modeConstructedEvent.wait()
  793.             self.closeSession()
  794.             self.__showErrorMessage(errorCode, errorExplanation)
  795.         else:
  796.             yield Return(ret)
  797.         return
  798.  
  799.     def bootUser(self, userId):
  800.         self._log('boot user %r', userId)
  801.  
  802.         @task
  803.         def boot():
  804.             yield self.__serviceProvider.chatGateway.bootOutOfChat({'userId': userId,
  805.                'roomInstanceId': self.roomInstanceId_})
  806.             self._updateParticipantEvent.set()
  807.  
  808.         self.attachTask(boot())
  809.  
  810.     def __showErrorMessage(self, errorCode, errorExplanation):
  811.         if errorCode is None:
  812.             return
  813.         if errorCode == ERROR_PUBLIC_ROOM_FULL:
  814.             title = self.__serviceProvider.translationTable.LS('Sorry!')
  815.             text = self.__serviceProvider.translationTable.LS('Looks like this chat room is quite popular and appears to be full! Be sure to visit other rooms and come back here later...')
  816.         else:
  817.             if errorExplanation is None:
  818.                 reason = self.reasons_.get(errorCode, 'no reason given')
  819.                 title = self.__serviceProvider.translationTable.LS('Chat Room Access Declined')
  820.                 text = self.__serviceProvider.translationTable.FLS('Your access to the chat room is declined. Reason: {0!r}', reason)
  821.             else:
  822.                 title = self.__serviceProvider.translationTable.LS('Chat Room Access Declined')
  823.                 text = self.__serviceProvider.translationTable.FLS('{0}', errorExplanation)
  824.         self.__serviceProvider.dialogManager.showModal(self.__parentHwnd, imvu.dialog.ConfirmationDialog(title, text))
  825.         self.endSession()
  826.         return
  827.  
  828.     def _showStillWaitingMsg(self):
  829.         self._showUiMessage(self.__serviceProvider.translationTable.LS('Inviting: waiting for reply...'))
  830.  
  831.  
  832. @task
  833. def handleInvite(serviceProvider, userId, decisionCallback, startChatCallback, parentHwnd=None):
  834.     if serviceProvider.mqManager.isConnected() and serviceProvider.mqManager.enabled('imq.chat_invites'):
  835.         yield _waitForInvite(serviceProvider, userId, decisionCallback, startChatCallback, parentHwnd)
  836.     else:
  837.         yield _pollForInvite(serviceProvider, userId, decisionCallback, startChatCallback, parentHwnd)
  838.  
  839.  
  840. @task
  841. def _pollForInvite(serviceProvider, userId, decisionCallback, startChatCallback, parentHwnd=None):
  842.     try:
  843.         invite = yield serviceProvider.chatGateway.checkForInvite2({'userId': userId})
  844.     except networkExceptions:
  845.         logger.exception('checkForInvite2 failed')
  846.         invite = None
  847.  
  848.     yield _handleInvite(serviceProvider, invite, userId, decisionCallback, startChatCallback, parentHwnd)
  849.     return
  850.  
  851.  
  852. @task
  853. def _waitForInvite(serviceProvider, userId, decisionCallback, startChatCallback, parentHwnd=None):
  854.  
  855.     class IMQInviteReceiver(object):
  856.  
  857.         def __init__(self):
  858.             self.__future = None
  859.             serviceProvider.eventBus.register(serviceProvider.serverEventTransport, 'ServerEvent.chatInvite', self.__inviteReceived)
  860.             return
  861.  
  862.         def __inviteReceived(self, event):
  863.             if self.__future:
  864.                 future = self.__future
  865.                 self.__future = None
  866.                 future.complete(event.info)
  867.             return
  868.  
  869.         @property
  870.         def future(self):
  871.             self.__future = imvu.task.Future()
  872.             return self.__future
  873.  
  874.     logger.info('listening for IMQ chat invites')
  875.     receiver = IMQInviteReceiver()
  876.     while True:
  877.         invite = yield receiver.future
  878.         yield _handleInvite(serviceProvider, invite, userId, decisionCallback, startChatCallback, parentHwnd)
  879.  
  880.  
  881. @task
  882. def _handleInvite(serviceProvider, invite, userId, decisionCallback, startChatCallback, parentHwnd):
  883.     if not (type(invite) is dict and all((key in invite for key in ('chatId', 'inviteId',
  884.                                                                     'partnerId',
  885.                                                                     'location', 'inviter')))):
  886.         logger.error('ignoring invite (%r)', invite)
  887.         return
  888.     chatId = invite['chatId']
  889.     inviteId = invite['inviteId']
  890.     partnerId = invite['partnerId']
  891.     location = invite['location']
  892.     partnerData = invite['inviter']
  893.     decision, reason = yield decisionCallback(partnerId, location, partnerData)
  894.     if decision is InviteDecision.ACCEPT:
  895.         logger.info('Accepting chat invitation')
  896.         try:
  897.             result = yield serviceProvider.chatGateway.acceptInvite({'userId': userId,
  898.                'inviteId': inviteId,
  899.                'chatId': chatId})
  900.             if result.get('expired'):
  901.                 message = serviceProvider.translationTable.LS('Sorry, the invite has expired and the room is unavailable')
  902.                 title = serviceProvider.translationTable.LS('Invite Has Expired')
  903.                 serviceProvider.dialogManager.showModal(parentHwnd, imvu.dialog.ConfirmationDialog(title, message))
  904.                 yield Return(False)
  905.             participantInfos = yield serviceProvider.chatGateway.getParticipants(userId, chatId)
  906.             result['location'] = location
  907.         except networkExceptions:
  908.             logger.exception('acceptInvite failed')
  909.         else:
  910.             logger.info('acceptInvite returned %s', result)
  911.             participants = [ int(x['userId']) for x in participantInfos ]
  912.             if partnerId in participants:
  913.                 startChatCallback(partnerId, result)
  914.             else:
  915.                 name = yield serviceProvider.avatarInfoManager.getAvatarName(partnerId)
  916.                 message = serviceProvider.translationTable.FLS('Oops, {0} has left the chat', name)
  917.                 title = serviceProvider.translationTable.LS('Chat Ended')
  918.                 serviceProvider.dialogManager.showModal(parentHwnd, imvu.dialog.ConfirmationDialog(title, message))
  919.     else:
  920.         if decision is InviteDecision.DECLINE or decision is InviteDecision.REJECTED:
  921.             logger.info('Declining chat invitation')
  922.             try:
  923.                 yield serviceProvider.chatGateway.declineInvite({'userId': userId, 'inviteId': inviteId,
  924.                    'reason': reason,
  925.                    'chatId': chatId,
  926.                    'status': 'rejected' if decision is InviteDecision.REJECTED else 'declined'})
  927.             except networkExceptions:
  928.                 logger.exception('declineInvite failed')
  929.  
  930.  
  931. @task
  932. def checkInviteSafety(serviceProvider, userId, roomPid):
  933.     try:
  934.         avatarInfo = yield serviceProvider.avatarInfoManager.getAvatarInfo(userId)
  935.     except Exception as e:
  936.         yield Return()
  937.  
  938.     if not avatarInfo.hasAP:
  939.         productInfo, = yield serviceProvider.productInfoManager.getProductsByIds([roomPid])
  940.         if productInfo.requiresAP:
  941.             yield Return('You can not invite a non-AP user to an AP room.')
  942.  
  943.  
  944. class MeetSomeoneSession(DirectConnectSession):
  945.  
  946.     def __init__(self, userId, serviceProvider, roomInstanceId, showMessageFunc=NullFunc, parentHwnd=None):
  947.         DirectConnectSession.__init__(self, serviceProvider=serviceProvider, userId=userId, showMessageFunc=showMessageFunc, parentHwnd=parentHwnd)
  948.         self.__serviceProvider = serviceProvider
  949.         self.__roomInstanceId = roomInstanceId
  950.         self.__chatNowParams_ = {}
  951.         self.__avatarInfoManager = imvu.gateway.AvatarInfoManager(self.__serviceProvider)
  952.         self.__parentHwnd = parentHwnd
  953.         self.maybeConnect(private=True)
  954.  
  955.     @property
  956.     def __participantId(self):
  957.         if self.participants_:
  958.             return self.participants_[0]
  959.         return
  960.         return
  961.  
  962.     def getActivity(self):
  963.         return 'Chat now-' + self.__roomInstanceId
  964.  
  965.     def getRoomInstanceId(self):
  966.         return self.__roomInstanceId
  967.  
  968.     def getOwner(self):
  969.         return self.userId_
  970.  
  971.     def setChatNowParams(self, chatParams):
  972.  
  973.         def filter(collection, filters):
  974.             return dict(((key, value) for key, value in chatParams.iteritems() if key in filters))
  975.  
  976.         self.__chatNowParams_ = filter(chatParams, ['age', 'ap', 'location', 'gender', 'language'])
  977.  
  978.     def _getChatNowParams(self):
  979.         return self.__chatNowParams_
  980.  
  981.     def isRoomSession(self):
  982.         return True
  983.  
  984.     @task
  985.     def getOrMakeChat(self, inviteId=None, private=None):
  986.         filter = self.__chatNowParams_.get('filter', 'surprise')
  987.         activity = 'Chat now-' + filter
  988.         args = {'userId': self.userId_, 'version': __version__,
  989.            'activity': activity,
  990.            'chatId': self.chatId_ or 0,
  991.            'private': private or True,
  992.            'chatNowParams': self.__chatNowParams_}
  993.         result = yield self.__serviceProvider.chatGateway.getOrMakeChat(self.userId_, activity, self.chatId_ or 0, capacity=None, publicRoom=None, private=None, chatNowParams=self.__chatNowParams_ or None)
  994.         yield Return(result)
  995.         return
  996.  
  997.     def _showStillWaitingMsg(self):
  998.         self._log('MeetSomeoneSession: _showStillWaitingMsg')
  999.         self._showUiMessage(self.__serviceProvider.translationTable.LS('Connecting you with another person...'), 2)
  1000.  
  1001.     def _showConnectedMessage(self):
  1002.         self._showUiMessage(self.__serviceProvider.translationTable.LS('Chat now! found someone...'))
  1003. # okay decompiling meet.pyo
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement