Advertisement
Guest User

Untitled

a guest
Aug 19th, 2018
189
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 43.61 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 isDuplicate
  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.         self.__addIncomingMessage({'from_id': self.userId_, 'message': messageText, 'to_id': to})
  523.         self.__outgoingMessages.put((messageText, to))
  524.  
  525.     def setCommandManager(self, c):
  526.         self.__dispatcher.setCommandManager(c)
  527.  
  528.     def numParticipants(self):
  529.         return len(self.getParticipantUserIds())
  530.  
  531.     def sessionIsFull(self):
  532.         return False
  533.  
  534.     def isPrivate(self):
  535.         return False
  536.  
  537.     @task
  538.     def _sendInvitation(self, partnerId, inviteId=None):
  539.         if partnerId == self.userId_:
  540.             yield Return({'response': 'decline', 'reason': 'You cannot invite yourself to a chat'})
  541.         yield self.__chatConnectedEvent.wait()
  542.         args = {'userId': self.userId_,
  543.            'partnerId': partnerId,
  544.            'chatId': self.chatId_ or 0,
  545.            'location': self.location}
  546.         if inviteId is not None:
  547.             args['inviteId'] = inviteId
  548.         rv = yield self.__serviceProvider.chatGateway.attemptInvite(**args)
  549.         yield Return(rv)
  550.         return
  551.  
  552.     def inviteToChat(self, inviteeId):
  553.         self.attachTask(self.__inviteToChat(inviteeId))
  554.  
  555.     @task
  556.     def sendAwayNote(self, inviteId, inviteeId, reason):
  557.         self._log('sendAwayNote(): inviteId: %r inviteeId: %r reason: %r', inviteId, inviteeId, reason)
  558.         reason = reason[10:]
  559.         partnerName = yield self.__serviceProvider.avatarInfoManager.getAvatarName(inviteeId)
  560.         dialog = InvitationDeclinedDialog()
  561.         dialog.dialogInfo = {'title': LString('Invitation declined'),
  562.            '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 ''),
  563.            'defaultValue': ''}
  564.         user_message = self.__serviceProvider.dialogManager.showModal(self.__parentHwnd, dialog)
  565.         if not user_message:
  566.             return
  567.         user_name = yield self.__serviceProvider.avatarInfoManager.getAvatarName(self.userId_)
  568.         if not user_name:
  569.             user_name = '<Avatar>'
  570.         away_note = user_name + ':  ' + user_message
  571.         yield self.__serviceProvider.chatGateway.leaveInviteAwayNote(self.userId_, inviteId, away_note)
  572.  
  573.     @task
  574.     def __inviteToChat(self, inviteeId):
  575.         with (yield self.__inviteToChatLock.acquire()):
  576.             firstInviteAttemptTime = self.__serviceProvider.timeProvider()
  577.             self._log('inviteToChat(%s, %s) firstInviteAttemptTime=%d', self, inviteeId, firstInviteAttemptTime)
  578.             self.__inviteAttempts = 0
  579.             self._showStillWaitingMsg()
  580.             inviteId = None
  581.             while True:
  582.                 self.__inviteAttempts += 1
  583.                 logger.info('inviteToChat attempting to make invite #%d (time is %d)', self.__inviteAttempts, self.__serviceProvider.timeProvider())
  584.                 try:
  585.                     ret = yield self._sendInvitation(partnerId=inviteeId, inviteId=inviteId)
  586.                 except networkExceptions:
  587.                     logger.exception('sendInvitation raised, assuming we should keep waiting.')
  588.                     ret = {'waiting': True}
  589.  
  590.                 newInviteId = ret.get('inviteId')
  591.                 try:
  592.                     newInviteId = int(newInviteId)
  593.                 except (TypeError, ValueError):
  594.                     logger.warning('Got funky inviteId: %r', newInviteId)
  595.  
  596.                 if inviteId is not None and newInviteId is not None and inviteId != newInviteId:
  597.                     logger.critical('We asked for the status of an invite - but got back a new invite!')
  598.                 if inviteId is None:
  599.                     inviteId = newInviteId
  600.                 if not self.chatId_ and ret.get('chatId', 0) != 0:
  601.                     logger.info("Didn't have a chat, but got one! %r", ret['chatId'])
  602.                     self.__joinChat(ret['chatId'], 1)
  603.                     self.__setupPostConnectTasks()
  604.                 if 'waiting' in ret:
  605.                     if self.__serviceProvider.timeProvider() - firstInviteAttemptTime > self.MaxSecondsToWaitForAccept:
  606.                         self._log('partner %s timed out our invitation after %d seconds', inviteeId, self.__serviceProvider.timeProvider() - firstInviteAttemptTime)
  607.                         partnerName = yield self.__serviceProvider.avatarInfoManager.getAvatarName(inviteeId)
  608.                         self._hideStillWaitingMsg()
  609.                         self._showUiMessage(self.__serviceProvider.translationTable.FLS('{partnerName} did not answer your invitation.', partnerName=partnerName), timeout=30)
  610.                         return
  611.                 else:
  612.                     if 'response' in ret:
  613.                         response = ret['response']
  614.                         if response == 'decline':
  615.                             reason = ret.get('reason', None)
  616.                             inviteId = ret.get('inviteId', None)
  617.                             accessViolation = ret.get('accessViolation', None)
  618.                             if not reason:
  619.                                 reason = 'no reason given'
  620.                             self._log('partner %s declined our invitation, closing session', inviteeId)
  621.                             self._hideStillWaitingMsg()
  622.                             if reason.find("I'm away") >= 0 and inviteId:
  623.                                 self.attachTask(self.sendAwayNote(inviteId, inviteeId, reason))
  624.                             else:
  625.                                 partnerName = yield self.__serviceProvider.avatarInfoManager.getAvatarName(inviteeId)
  626.                                 if accessViolation:
  627.                                     self._showUiMessage(self.__serviceProvider.translationTable.FLS('{partnerName} can not join as the room only allows', partnerName=partnerName) + ' ' + accessViolation, timeout=300)
  628.                                 else:
  629.                                     self._showUiMessage(self.__serviceProvider.translationTable.FLS('{partnerName} declined to chat, saying', partnerName=partnerName) + " '" + reason + "'", timeout=300)
  630.                             return
  631.                         raise Exception('unknown response: %r' % ret)
  632.                     else:
  633.                         self._log('inviteToChat: invite was accepted from %s', inviteeId)
  634.                         self._updateParticipantEvent.set()
  635.                         self._hideStillWaitingMsg()
  636.                         return
  637.                 yield Sleep(1)
  638.  
  639.             raise Exception('should never be reached')
  640.         return
  641.  
  642.     def onImqMessage(self, message):
  643.         logger.info('%s.onImqMessage(%r)', type(self).__name__, [
  644.          message.user_id, message.queue, message.mount, message.message])
  645.         if message.mount == 'control':
  646.             m = json.loads(message.message)
  647.             if not isinstance(m, dict):
  648.                 logger.warning('Got invalid control message %r', m)
  649.                 return
  650.             self.__serviceProvider.eventBus.fire(self, 'ControlMessage', m)
  651.         else:
  652.             if message.mount == 'messages' and self.__imqReceive:
  653.                 m = json.loads(message.message)
  654.                 if not isinstance(m, dict):
  655.                     logger.warning('Got invalid chat message %r', m)
  656.                     return
  657.                 if isinstance(message.user_id, int):
  658.                     m['from_id'] = message.user_id if 1 else int(message.user_id.split('/')[-1])
  659.                     if m['from_id'] != m.get('userId', 0):
  660.                         logger.warning('forged message detected: from %r: %r', message.user_id, m)
  661.                     m['to_id'] = m.get('to', 0)
  662.                     self.__addIncomingMessage(m)
  663.  
  664.     def _showStillWaitingMsg(self):
  665.         pass
  666.  
  667.     def _hideStillWaitingMsg(self):
  668.         pass
  669.  
  670.     def canBoot(self, booter, bootee):
  671.         return False
  672.  
  673.     def isLieutenant(self, userId):
  674.         return False
  675.  
  676.  
  677. class InviteDecision():
  678.     ACCEPT = 'ACCEPT'
  679.     DECLINE = 'DECLINE'
  680.     IGNORE = 'IGNORE'
  681.     REJECTED = 'REJECTED'
  682.  
  683.  
  684. class ChatSession(DirectConnectSession):
  685.  
  686.     def __init__(self, serviceProvider, userId, result, showMessageFunc=NullFunc, parentHwnd=None, location=0):
  687.         DirectConnectSession.__init__(self, serviceProvider=serviceProvider, userId=userId, showMessageFunc=showMessageFunc, parentHwnd=parentHwnd, location=location)
  688.         self.__result = result
  689.         self.maybeConnect()
  690.  
  691.     @task
  692.     def getOrMakeChat(self, inviteId=None, private=None):
  693.         return self.__result
  694.  
  695.     def shouldResetRoomDefinitionAtStartup(self):
  696.         return False
  697.  
  698.  
  699. DEFAULT_PUBLIC_ROOM_TITLE = 'IMVU Chat Room'
  700.  
  701. class JoinRoomSession(DirectConnectSession):
  702.  
  703.     def __init__(self, userId, roomInstanceId, serviceProvider, modeConstructedEvent, showMessageFunc=NullFunc, parentHwnd=None, lieutenants=[], roomOwners=[], allowRoomShellOverwrite=False, allowLoadNewRoom=False, private=None, autoBootWhenOwnerLeaves=True):
  704.         DirectConnectSession.__init__(self, serviceProvider=serviceProvider, userId=userId, showMessageFunc=showMessageFunc, parentHwnd=parentHwnd)
  705.         if not isinstance(roomInstanceId, basestring):
  706.             raise TypeError('roomInstanceId must be a string, was %r' % (roomInstanceId,))
  707.         if not isinstance(roomOwners, list):
  708.             raise TypeError('roomOwners must be a list, was %r' % (roomOwners,))
  709.         self.roomInstanceId_ = roomInstanceId
  710.         self.__serviceProvider = serviceProvider
  711.         self.__modeConstructedEvent = modeConstructedEvent
  712.         self.__lieutenants = lieutenants
  713.         self.__roomOwners = roomOwners
  714.         self.__allowRoomShellOverwrite = allowRoomShellOverwrite
  715.         self.__allowLoadNewRoom = allowLoadNewRoom
  716.         self.__parentHwnd = parentHwnd
  717.         self.__private = private
  718.         self.__autoBootWhenOwnerLeaves = autoBootWhenOwnerLeaves
  719.         self.reasons_ = {ERROR_PUBLIC_ROOM_CLIENT_VERSION_OLD: self.__serviceProvider.translationTable.LS('Your client version is too old, please upgrade to the latest version.'),
  720.            ERROR_PUBLIC_ROOM_AGE_LIMIT: self.__serviceProvider.translationTable.LS('You are too young to join a chat room chat.'),
  721.            ERROR_PUBLIC_ROOM_CLOSED: self.__serviceProvider.translationTable.LS('The room is currently closed.'),
  722.            ERROR_PUBLIC_ROOM_BOOTED: self.__serviceProvider.translationTable.LS('You have been kicked out of the room.  Cannot rejoin within 20 minutes.'),
  723.            ERROR_PUBLIC_ROOM_FULL: self.__serviceProvider.translationTable.LS('The room is full.')}
  724.         self.maybeConnect(private=private)
  725.  
  726.     @property
  727.     def location(self):
  728.         return self.roomInstanceId_
  729.  
  730.     def isOwner(self, userId):
  731.         return self.roomInstanceId_.startswith(str(userId) + '-') or userId in self.getRoomOwners()
  732.  
  733.     def isPrivate(self):
  734.         return self.__private
  735.  
  736.     def getOwner(self):
  737.         return int(self.roomInstanceId_.split('-')[0])
  738.  
  739.     def isLieutenant(self, userId):
  740.         return str(userId) in self.__lieutenants
  741.  
  742.     def hasBootPrivileges(self, userId):
  743.         return self.isOwner(userId) or self.isLieutenant(userId)
  744.  
  745.     def canBoot(self, booter, bootee):
  746.         return self.hasBootPrivileges(booter) and not self.hasBootPrivileges(bootee)
  747.  
  748.     def isRoomSession(self):
  749.         return True
  750.  
  751.     def allowRoomShellOverwrite(self):
  752.         return self.__allowRoomShellOverwrite
  753.  
  754.     def autoBootWhenOwnerLeaves(self):
  755.         return self.__autoBootWhenOwnerLeaves
  756.  
  757.     def setAutoBootWhenOwnerLeaves(self, autoBootWhenOwnerLeaves):
  758.         self.__autoBootWhenOwnerLeaves = autoBootWhenOwnerLeaves
  759.  
  760.     def allowLoadNewRoom(self):
  761.         return self.__allowLoadNewRoom
  762.  
  763.     def getRoomOwners(self):
  764.         return self.__roomOwners
  765.  
  766.     def setRoomOwners(self, roomOwners):
  767.         self.__roomOwners = roomOwners
  768.  
  769.     def isAlwaysDriver(self):
  770.         return False
  771.  
  772.     def resetRoomDefinitionAtStartup(self):
  773.         return False
  774.  
  775.     def getRoomInstanceId(self):
  776.         return self.roomInstanceId_
  777.  
  778.     def setRoomInstanceId(self, roomInstanceId):
  779.         self.roomInstanceId_ = roomInstanceId
  780.  
  781.     @task
  782.     def getOrMakeChat(self, inviteId=None, private=None):
  783.         self._log('JoinRoomSession::getOrMakeChat(): self.userId_: %r self.roomInstanceId_: %r', self.userId_, self.roomInstanceId_)
  784.         activity = 'publicroom-%s' % self.roomInstanceId_
  785.         ret = yield self.__serviceProvider.chatGateway.getOrMakeChat(self.userId_, activity, self.chatId_ or 0, capacity=9999, publicRoom=True, private=private)
  786.         if 'response' in ret and ret['response'] == 'declined':
  787.             errorCode = ret.get('reason', None)
  788.             errorExplanation = ret.get('explanation', None)
  789.             self._log('User %s declined to join the chat room, closing session', self.userId_)
  790.             yield self.__modeConstructedEvent.wait()
  791.             self.closeSession()
  792.             self.__showErrorMessage(errorCode, errorExplanation)
  793.         else:
  794.             yield Return(ret)
  795.         return
  796.  
  797.     def bootUser(self, userId):
  798.         self._log('boot user %r', userId)
  799.  
  800.         @task
  801.         def boot():
  802.             yield self.__serviceProvider.chatGateway.bootOutOfChat({'userId': userId,
  803.                'roomInstanceId': self.roomInstanceId_})
  804.             self._updateParticipantEvent.set()
  805.  
  806.         self.attachTask(boot())
  807.  
  808.     def __showErrorMessage(self, errorCode, errorExplanation):
  809.         if errorCode is None:
  810.             return
  811.         if errorCode == ERROR_PUBLIC_ROOM_FULL:
  812.             title = self.__serviceProvider.translationTable.LS('Sorry!')
  813.             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...')
  814.         else:
  815.             if errorExplanation is None:
  816.                 reason = self.reasons_.get(errorCode, 'no reason given')
  817.                 title = self.__serviceProvider.translationTable.LS('Chat Room Access Declined')
  818.                 text = self.__serviceProvider.translationTable.FLS('Your access to the chat room is declined. Reason: {0!r}', reason)
  819.             else:
  820.                 title = self.__serviceProvider.translationTable.LS('Chat Room Access Declined')
  821.                 text = self.__serviceProvider.translationTable.FLS('{0}', errorExplanation)
  822.         self.__serviceProvider.dialogManager.showModal(self.__parentHwnd, imvu.dialog.ConfirmationDialog(title, text))
  823.         self.endSession()
  824.         return
  825.  
  826.     def _showStillWaitingMsg(self):
  827.         self._showUiMessage(self.__serviceProvider.translationTable.LS('Inviting: waiting for reply...'))
  828.  
  829.  
  830. @task
  831. def handleInvite(serviceProvider, userId, decisionCallback, startChatCallback, parentHwnd=None):
  832.     if serviceProvider.mqManager.isConnected() and serviceProvider.mqManager.enabled('imq.chat_invites'):
  833.         yield _waitForInvite(serviceProvider, userId, decisionCallback, startChatCallback, parentHwnd)
  834.     else:
  835.         yield _pollForInvite(serviceProvider, userId, decisionCallback, startChatCallback, parentHwnd)
  836.  
  837.  
  838. @task
  839. def _pollForInvite(serviceProvider, userId, decisionCallback, startChatCallback, parentHwnd=None):
  840.     try:
  841.         invite = yield serviceProvider.chatGateway.checkForInvite2({'userId': userId})
  842.     except networkExceptions:
  843.         logger.exception('checkForInvite2 failed')
  844.         invite = None
  845.  
  846.     yield _handleInvite(serviceProvider, invite, userId, decisionCallback, startChatCallback, parentHwnd)
  847.     return
  848.  
  849.  
  850. @task
  851. def _waitForInvite(serviceProvider, userId, decisionCallback, startChatCallback, parentHwnd=None):
  852.  
  853.     class IMQInviteReceiver(object):
  854.  
  855.         def __init__(self):
  856.             self.__future = None
  857.             serviceProvider.eventBus.register(serviceProvider.serverEventTransport, 'ServerEvent.chatInvite', self.__inviteReceived)
  858.             return
  859.  
  860.         def __inviteReceived(self, event):
  861.             if self.__future:
  862.                 future = self.__future
  863.                 self.__future = None
  864.                 future.complete(event.info)
  865.             return
  866.  
  867.         @property
  868.         def future(self):
  869.             self.__future = imvu.task.Future()
  870.             return self.__future
  871.  
  872.     logger.info('listening for IMQ chat invites')
  873.     receiver = IMQInviteReceiver()
  874.     while True:
  875.         invite = yield receiver.future
  876.         yield _handleInvite(serviceProvider, invite, userId, decisionCallback, startChatCallback, parentHwnd)
  877.  
  878.  
  879. @task
  880. def _handleInvite(serviceProvider, invite, userId, decisionCallback, startChatCallback, parentHwnd):
  881.     if not (type(invite) is dict and all((key in invite for key in ('chatId', 'inviteId',
  882.                                                                     'partnerId',
  883.                                                                     'location', 'inviter')))):
  884.         logger.error('ignoring invite (%r)', invite)
  885.         return
  886.     chatId = invite['chatId']
  887.     inviteId = invite['inviteId']
  888.     partnerId = invite['partnerId']
  889.     location = invite['location']
  890.     partnerData = invite['inviter']
  891.     decision, reason = yield decisionCallback(partnerId, location, partnerData)
  892.     if decision is InviteDecision.ACCEPT:
  893.         logger.info('Accepting chat invitation')
  894.         try:
  895.             result = yield serviceProvider.chatGateway.acceptInvite({'userId': userId,
  896.                'inviteId': inviteId,
  897.                'chatId': chatId})
  898.             if result.get('expired'):
  899.                 message = serviceProvider.translationTable.LS('Sorry, the invite has expired and the room is unavailable')
  900.                 title = serviceProvider.translationTable.LS('Invite Has Expired')
  901.                 serviceProvider.dialogManager.showModal(parentHwnd, imvu.dialog.ConfirmationDialog(title, message))
  902.                 yield Return(False)
  903.             participantInfos = yield serviceProvider.chatGateway.getParticipants(userId, chatId)
  904.             result['location'] = location
  905.         except networkExceptions:
  906.             logger.exception('acceptInvite failed')
  907.         else:
  908.             logger.info('acceptInvite returned %s', result)
  909.             participants = [ int(x['userId']) for x in participantInfos ]
  910.             if partnerId in participants:
  911.                 startChatCallback(partnerId, result)
  912.             else:
  913.                 name = yield serviceProvider.avatarInfoManager.getAvatarName(partnerId)
  914.                 message = serviceProvider.translationTable.FLS('Oops, {0} has left the chat', name)
  915.                 title = serviceProvider.translationTable.LS('Chat Ended')
  916.                 serviceProvider.dialogManager.showModal(parentHwnd, imvu.dialog.ConfirmationDialog(title, message))
  917.     else:
  918.         if decision is InviteDecision.DECLINE or decision is InviteDecision.REJECTED:
  919.             logger.info('Declining chat invitation')
  920.             try:
  921.                 yield serviceProvider.chatGateway.declineInvite({'userId': userId, 'inviteId': inviteId,
  922.                    'reason': reason,
  923.                    'chatId': chatId,
  924.                    'status': 'rejected' if decision is InviteDecision.REJECTED else 'declined'})
  925.             except networkExceptions:
  926.                 logger.exception('declineInvite failed')
  927.  
  928.  
  929. @task
  930. def checkInviteSafety(serviceProvider, userId, roomPid):
  931.     try:
  932.         avatarInfo = yield serviceProvider.avatarInfoManager.getAvatarInfo(userId)
  933.     except Exception as e:
  934.         yield Return()
  935.  
  936.     if not avatarInfo.hasAP:
  937.         productInfo, = yield serviceProvider.productInfoManager.getProductsByIds([roomPid])
  938.         if productInfo.requiresAP:
  939.             yield Return('You can not invite a non-AP user to an AP room.')
  940.  
  941.  
  942. class MeetSomeoneSession(DirectConnectSession):
  943.  
  944.     def __init__(self, userId, serviceProvider, roomInstanceId, showMessageFunc=NullFunc, parentHwnd=None):
  945.         DirectConnectSession.__init__(self, serviceProvider=serviceProvider, userId=userId, showMessageFunc=showMessageFunc, parentHwnd=parentHwnd)
  946.         self.__serviceProvider = serviceProvider
  947.         self.__roomInstanceId = roomInstanceId
  948.         self.__chatNowParams_ = {}
  949.         self.__avatarInfoManager = imvu.gateway.AvatarInfoManager(self.__serviceProvider)
  950.         self.__parentHwnd = parentHwnd
  951.         self.maybeConnect(private=True)
  952.  
  953.     @property
  954.     def __participantId(self):
  955.         if self.participants_:
  956.             return self.participants_[0]
  957.         return
  958.         return
  959.  
  960.     def getActivity(self):
  961.         return 'Chat now-' + self.__roomInstanceId
  962.  
  963.     def getRoomInstanceId(self):
  964.         return self.__roomInstanceId
  965.  
  966.     def getOwner(self):
  967.         return self.userId_
  968.  
  969.     def setChatNowParams(self, chatParams):
  970.  
  971.         def filter(collection, filters):
  972.             return dict(((key, value) for key, value in chatParams.iteritems() if key in filters))
  973.  
  974.         self.__chatNowParams_ = filter(chatParams, ['age', 'ap', 'location', 'gender', 'language'])
  975.  
  976.     def _getChatNowParams(self):
  977.         return self.__chatNowParams_
  978.  
  979.     def isRoomSession(self):
  980.         return True
  981.  
  982.     @task
  983.     def getOrMakeChat(self, inviteId=None, private=None):
  984.         filter = self.__chatNowParams_.get('filter', 'surprise')
  985.         activity = 'Chat now-' + filter
  986.         args = {'userId': self.userId_, 'version': __version__,
  987.            'activity': activity,
  988.            'chatId': self.chatId_ or 0,
  989.            'private': private or True,
  990.            'chatNowParams': self.__chatNowParams_}
  991.         result = yield self.__serviceProvider.chatGateway.getOrMakeChat(self.userId_, activity, self.chatId_ or 0, capacity=None, publicRoom=None, private=None, chatNowParams=self.__chatNowParams_ or None)
  992.         yield Return(result)
  993.         return
  994.  
  995.     def _showStillWaitingMsg(self):
  996.         self._log('MeetSomeoneSession: _showStillWaitingMsg')
  997.         self._showUiMessage(self.__serviceProvider.translationTable.LS('Connecting you with another person...'), 2)
  998.  
  999.     def _showConnectedMessage(self):
  1000.         self._showUiMessage(self.__serviceProvider.translationTable.LS('Chat now! found someone...'))
  1001. # okay decompiling meet.pyo
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement