Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # uncompyle6 version 3.2.3
- # Python bytecode 2.7 (62211)
- # Decompiled from: Python 3.6.2 (v3.6.2:5fd33b5, Jul 8 2017, 04:57:36) [MSC v.1900 64 bit (AMD64)]
- # Embedded file name: im\meet.pyo
- # Compiled at: 2014-10-22 13:53:01
- import logging, types, urllib, urllib2, xmlrpclib, json
- from im import session
- from imvu.event import EventBus
- from imvu.task import task, attachedtask, Sleep, Schedule, Event, WaitForEvent, WaitWithTimeout, TaskTimeout, Return, Queue as TaskQueue, Semaphore, TaskOwner, RunUntilComplete
- from imvu.imq.MQManager import MQListener
- import imvu.task
- from imvu.task.util import CallPeriodically
- from imvu.version import __version__
- from imvu.network import networkExceptions
- from imvu import weakmethod
- from imvu.util import assertInRelease
- import im.common
- from imvu.session import SessionDispatcher
- import imvu.fs, imvu.gateway, imvu.gateway.AvatarInfoManager
- from imvu.session import LocalChat
- from imvu.translation import LString
- def NullFunc(*args, **kwargs):
- pass
- logger = logging.getLogger('imvu.' + __name__)
- ConnectionLostMessage = 'You have been disconnected from the chat.'
- NetworkErrorRetryInterval = 10
- ERROR_CHAT_FULL = 14
- ERROR_CHAT_EMPTY = 15
- ERROR_CHAT_NOT_PUBLIC = 16
- ERROR_PUBLIC_ROOM_CLIENT_VERSION_OLD = 1
- ERROR_PUBLIC_ROOM_AGE_LIMIT = 2
- ERROR_PUBLIC_ROOM_CLOSED = 3
- ERROR_PUBLIC_ROOM_BOOTED = 4
- ERROR_PUBLIC_ROOM_FULL = 5
- class DuplicateMessageDetector(object):
- def __init__(self, serviceProvider, timeout):
- self.__byUser = {}
- self.__timeout = timeout
- self.__timeProvider = serviceProvider.timeProvider
- def checkDuplicate(self, msg):
- from_id = str(msg['from_id'])
- candidates = self.__byUser.get(from_id, [])
- newList = []
- isDuplicate = False
- now = self.__timeProvider()
- msgCopy = dict(msg)
- msgCopy['_timeoutTime'] = now + self.__timeout
- msgCopy['from_id'] = from_id
- if 'message' in msgCopy:
- msgCopy['message'] = msgCopy['message'].strip()
- for c in candidates:
- if c['_timeoutTime'] < now:
- pass
- elif self._isDuplicate(c, msgCopy):
- logger.debug('Suppressing duplicate message %r', msgCopy)
- isDuplicate = True
- else:
- newList.append(c)
- if not isDuplicate:
- newList.append(msgCopy)
- self.__byUser[from_id] = newList
- return False
- def userDropped(self, userId):
- if self.__byUser.has_key(str(userId)):
- del self.__byUser[str(userId)]
- def _isDuplicate(self, a, b):
- return a.get('message', None) == b.get('message', None)
- class NullDuplicateMessageDetector(object):
- def __init__(self, services=None, timeout=0):
- pass
- def checkDuplicate(self, msg):
- return False
- def userDropped(self, userId):
- pass
- class InvitationDeclinedDialog(object):
- uri = 'chrome://imvu/content/dialogs/input/index.html'
- size = (496, 247)
- title = 'Invitation Declined'
- geckoListeners = []
- class DirectConnectSession(im.session.ImSession, TaskOwner, MQListener):
- MaxSecondsToWaitForAccept = 60
- def __init__(self, userId, serviceProvider, showMessageFunc=NullFunc, parentHwnd=None, dispatcherFactory=SessionDispatcher, location=None):
- im.session.ImSession.__init__(self)
- TaskOwner.__init__(self, serviceProvider.taskScheduler)
- self.activity = 'DirectConnect'
- self.__dispatcher = serviceProvider.create(dispatcherFactory, sender=self)
- self.__outgoingMessages = TaskQueue()
- self.__duplicateDetector = NullDuplicateMessageDetector()
- self.__location = location
- self.__isConnected = False
- self.__inviteToChatLock = Semaphore(1)
- self.__chatConnectedEvent = Event()
- self.chatId_ = None
- self.userId_ = userId
- self.participants_ = []
- self.__pendingMessages = []
- self.__active = True
- self.showMessageFuncWr_ = weakmethod.ref(showMessageFunc)
- self._updateParticipantEvent = Event()
- self.__serviceProvider = serviceProvider
- self.__parentHwnd = parentHwnd
- self.__ignoredUsers = []
- self.__is_running_ = False
- self.__avatarInfoManager = imvu.gateway.AvatarInfoManager(self.__serviceProvider)
- self.waitingScale_ = 5
- self._log('creating new session')
- self.lastMessageId_ = 0
- self.__inviteAttempts = 0
- self.__queueName = None
- self.__imqSend = False
- self.__imqReceive = False
- self.__lastServerContact = 0
- self.__participantUrl = None
- self.__participantInfo = {}
- self.__infoUpdateQueue = []
- self.__processingParticipantInfoQueue = False
- self.__sawPureUser = False
- self.__account = None
- self.__unsentParticipantChanges = {}
- self.attachTask(CallPeriodically(self.__checkDisconnection, 5, immediatelyCall=True))
- return
- def setLocation(self, roomPid):
- self.__location = roomPid
- @property
- def location(self):
- return self.__location
- def updateParticipantInfo(self, account, updates):
- if account:
- self.__account = account
- if not self.__account or not (self.__account.shouldAlwaysPostToChatParticipantEndPoint() or self.__account.shouldPostToChatParticipantEndPointIfPureUserPresent()):
- return
- self.__infoUpdateQueue.insert(len(self.__infoUpdateQueue), updates)
- if self.__participantUrl != None and not self.__processingParticipantInfoQueue:
- self.__processingParticipantInfoQueue = True
- self.attachTask(self.__processParticipantInfoQueue())
- return
- def __triggerParticipantUpdate(self, account=None):
- if self.__unsentParticipantChanges:
- self.updateParticipantInfo(account, self.__unsentParticipantChanges)
- def sawPureUser(self, account):
- if not self.__sawPureUser and account.shouldPostToChatParticipantEndPointIfPureUserPresent():
- self.__sawPureUser = True
- self.__triggerParticipantUpdate(account)
- @task
- def __processParticipantInfoQueue(self):
- while len(self.__infoUpdateQueue) > 0:
- changes = {}
- queue = self.__infoUpdateQueue[:]
- self.__infoUpdateQueue = []
- for updates in queue:
- for key in updates.keys():
- if self.__participantInfo.get(key, None) != updates[key]:
- changes[key] = updates[key]
- if not (changes and self.participants_ and (self.__account.shouldAlwaysPostToChatParticipantEndPoint() or self.__account.shouldPostToChatParticipantEndPointIfPureUserPresent() and self.__sawPureUser)):
- self.__unsentParticipantChanges.update(changes)
- break
- self.__participantInfo.update(changes)
- logger.info('NRD POSTing to chat_participant endpoint: %r', changes)
- try:
- yield imvu.http.securePost(url=self.__participantUrl, params=changes, auth=self.__account.getAuth(), responseSchema=[], network=self.__serviceProvider.network, method='POST')
- except networkExceptions:
- pass
- self.__processingParticipantInfoQueue = False
- return
- def _log(self, message, *args):
- logger.info((message + ' session=%r'), *(args + (self,)))
- def getChatId(self):
- return self.chatId_
- def isOwner(self, userId):
- return self.userId_ == userId
- @property
- def active(self):
- return self.__active
- def __repr__(self):
- return '<%s %s: instance %s, userId %s, chat %s>' % (
- type(self).__name__,
- self.activity,
- self._instanceId,
- self.userId_,
- self.chatId_)
- @task
- @staticmethod
- def __reportChatTermination(chatGateway, userId, chatId):
- if not chatId:
- return
- try:
- yield chatGateway.terminateChat(userId, chatId)
- except networkExceptions:
- logger.exception('chatGateway.terminateChat(%r, %r) failed', userId, chatId)
- def closeSession(self):
- self._log('closeSession')
- self.__serviceProvider.taskScheduler.scheduleTask(self.__reportChatTermination(self.__serviceProvider.chatGateway, self.userId_, self.chatId_), executionPolicy=RunUntilComplete)
- self.__markClosed()
- def __markClosed(self):
- self._log('__markClosed')
- self.stopAttachedTasks()
- self.__dispatcher.dispose()
- self.__active = False
- def isConnected(self):
- return self.__isConnected
- def __checkDisconnection(self):
- if self.__isConnected and self.__serviceProvider.timeProvider() - self.__lastServerContact > 120:
- logger.info('Detected disconnection, last server contact at %d, it is now %d', self.__lastServerContact, self.__serviceProvider.timeProvider())
- self.__serviceProvider.eventBus.fire(self, 'DisconnectionDetected', {})
- def maybeConnect(self, private=None):
- if self.__isConnected or self.__is_running_:
- return
- self._log('maybeConnect decided to connect')
- self.__is_running_ = True
- @task
- def initialize():
- yield self.__connectToChat(private=private)
- self.__setupPostConnectTasks()
- self.attachTask(initialize())
- def __setupPostConnectTasks(self):
- self.__isConnected = self.chatId_ is not None
- if self.isConnected():
- if not self.__serviceProvider.mqManager.enabled('imq.disable_xmlrpc_chat_polling'):
- self.attachTask(self._fetchNewMessages())
- self.attachTask(self._sendOutgoingMessages())
- self.attachTask(self._updateParticipantList())
- return
- @task
- def __getNewMessages(self):
- try:
- result = yield self.__serviceProvider.chatGateway.getNewMessages(userId=self.userId_, chatId=self.chatId_, lastMessageId=self.lastMessageId_)
- yield Return(result)
- except xmlrpclib.Fault as f:
- if f.faultCode == imvu.gateway.ERROR_NO_LONGER_IN_CHAT:
- logger.exception('marking %s closed because of fault 9', self)
- self.__markClosed()
- self._showUiMessage(self.__serviceProvider.translationTable.LS('Sorry, you are no longer in the chat'))
- yield Return([])
- else:
- raise
- def _showUiMessage(self, messageText, timeout=3):
- msgFunc = self.showMessageFuncWr_()
- if msgFunc:
- return msgFunc(sess=self, messageText=messageText, timeout=timeout)
- def _showConnectedMessage(self):
- pass
- def getParticipantUserIds(self):
- return sorted(set([self.userId_] + self.participants_))
- @task
- def __handleWaitingResult(self, result):
- self._showStillWaitingMsg()
- logger.debug('%s(userId=%s)::getOrMakeChat returned waiting result: %s', self, self.userId_, result)
- try:
- self.chatId_ = result['chatId']
- self.__chatConnectedEvent.set()
- except KeyError:
- pass
- else:
- self.__serviceProvider.eventBus.fire(self, 'NewChatId', {'chatId': self.chatId_})
- yield Sleep(0.5 + self.waitingScale_ * 0.5)
- def __joinChat(self, chatId, seat=None, lastMessageId=0):
- self.chatId_ = chatId
- self.__chatConnectedEvent.set()
- self.__serviceProvider.eventBus.fire(self, 'JoinedChat', {'chatId': self.chatId_, 'seat': seat})
- self.__serviceProvider.eventBus.fire(self, 'NewChatId', {'chatId': self.chatId_})
- if self.__serviceProvider.mqManager.enabled('imq.text_chat3'):
- self.__queueName = '/chat/%i' % int(self.chatId_)
- self.__imqSend = self.__serviceProvider.mqManager.enabled('imq.text_chat3.send')
- if self.__serviceProvider.mqManager.enabled('imq.text_chat3.receive'):
- self.__imqReceive = True
- if self.__serviceProvider.mqManager.enabled('imq.text_chat3.filter_duplicates'):
- self.__duplicateDetector = DuplicateMessageDetector(self.__serviceProvider, 120)
- self.__serviceProvider.mqManager.subscribe(self.__queueName, self, {'listen_to_self': True})
- self.lastMessageId_ = int(lastMessageId)
- self._log('Setting lastMessageId_ to %s', self.lastMessageId_)
- if seat is not None:
- self.sendImMessage(messageText='*seat %s' % seat)
- if seat == 1:
- self.sendImMessage(messageText='*resume %s' % self.userId_)
- else:
- self.sendImMessage(messageText='*accept %s' % self.userId_)
- self._log('_fetchNewMessages connected to chat %s', self.chatId_)
- self._showConnectedMessage()
- self.__lastServerContact = self.__serviceProvider.timeProvider()
- return
- @task
- def __connectToChat(self, private=None):
- attempts = 0
- inviteId = None
- while True:
- if attempts == 5:
- self.__serviceProvider.eventBus.fire(self, 'ChatConnectFailed')
- try:
- result = yield self.getOrMakeChat(inviteId=inviteId, private=private)
- except networkExceptions:
- logger.exception('failed getOrMakeChat for userId %s, retrying', self.userId_)
- attempts += 1
- yield Sleep((0.5 + self.waitingScale_ * 0.5) * attempts)
- continue
- if result is None:
- attempts += 1
- yield Sleep((0.5 + self.waitingScale_ * 0.5) * attempts)
- continue
- self._log('getOrMakeChat result: %s', result)
- if result.get('response', 'accepted') == 'declined' or result.get('response', 'accepted') == 'timeout':
- break
- self.__participantUrl = result.get('participantUrl')
- if result.get('waiting', False):
- yield self.__handleWaitingResult(result)
- inviteId = result.get('inviteId', None)
- continue
- self.__joinChat(result['chatId'], result.get('seat'), result.get('lastMessageId', 0))
- break
- return
- @task
- def _fetchNewMessages(self):
- while True:
- try:
- result = yield self.__getNewMessages()
- except networkExceptions:
- logger.exception('failed getNewMessages for userId %s, retrying', self.userId_)
- self._showUiMessage(self.__serviceProvider.translationTable.LS('You have been disconnected from the chat.'))
- yield Sleep(NetworkErrorRetryInterval)
- else:
- self.__lastServerContact = self.__serviceProvider.timeProvider()
- if result:
- self._log('received %s new messages: %s', len(result), result)
- else:
- self._log('new message has False result without NetworkException. Why?')
- i = 1
- for messageDict in result:
- self.__addIncomingMessage(messageDict)
- self.lastMessageId_ = messageDict['message_id']
- if i % 5 == 0:
- yield Sleep(0)
- i += 1
- self._log('Setting lastMessageId_ to %s', self.lastMessageId_)
- yield Sleep(0.6)
- @task
- def flushMessages(self, messages=[]):
- def formatMessage((msg, to)):
- return {'userId': self.userId_, 'chatId': self.chatId_, 'message': msg, 'to': to}
- while not self.__outgoingMessages.empty():
- messages.append((yield self.__outgoingMessages.get()))
- if not messages:
- return
- self._log('flushMessages dequeued messages %r', messages)
- formattedMessages = map(formatMessage, messages)
- if self.__imqSend:
- for m in formattedMessages:
- jsonMsg = json.dumps(m)
- logger.debug('send IMQ chat message: %s', jsonMsg)
- self.__serviceProvider.mqManager.sendMessage(jsonMsg, self.__queueName, 'messages')
- if not self.__serviceProvider.mqManager.enabled('imq.disable_xmlrpc_send'):
- for i in range(5):
- try:
- result = yield self.__serviceProvider.chatGateway.sendChatMessages(formattedMessages)
- except networkExceptions:
- logger.exception('Error sending chat messages')
- yield Sleep(1.5)
- continue
- else:
- self.__lastServerContact = self.__serviceProvider.timeProvider()
- self._log('successfully sent messages %r, result %s', messages, result)
- break
- else:
- for msg, to in messages:
- if not msg.startswith('*'):
- self._showUiMessage(self.__serviceProvider.translationTable.FLS('Message was not sent: {0!r}', msg))
- break
- @task
- def _sendOutgoingMessages(self):
- self._log('Starting outgoing message loop')
- while True:
- yield self.flushMessages(messages=[(yield self.__outgoingMessages.get())])
- @task
- def _updateParticipantList(self):
- self._log('Starting participant update loop')
- try:
- while True:
- try:
- participantInfos = yield self.__serviceProvider.chatGateway.getParticipants(self.userId_, self.chatId_)
- except networkExceptions:
- logger.exception('error trying to find participants for chat %s', self.chatId_)
- else:
- participantsChanged = False
- self.__lastServerContact = self.__serviceProvider.timeProvider()
- seats = {}
- newParticipants = set()
- for p in participantInfos:
- userId = int(p['userId'])
- seats[userId] = p['seat']
- newParticipants.add(userId)
- for userId in set(self.participants_) - newParticipants:
- self._log('notifyParticipantRemoved(): userId: %r', userId)
- self.participants_.remove(userId)
- participantsChanged = True
- yield self.__dispatcher.participantLeft(userId)
- for userId in newParticipants - set(self.participants_):
- self.participants_.append(userId)
- participantsChanged = True
- gotInfo = yield self.__dispatcher.participantAdded(userId, seats[userId])
- if not gotInfo:
- self.participants_.remove(userId)
- for message_dict in self.__pendingMessages:
- if message_dict['from_id'] in self.participants_:
- self.__processIncomingMessage(message_dict)
- else:
- logger.warning('Ignoring message %r because user is not in chat', message_dict)
- del self.__pendingMessages[:]
- if self.numParticipants() == 1 and self.isRoomSession():
- self.__outgoingMessages.put(('*uid %d' % self.userId_, 0))
- if participantsChanged:
- self.__serviceProvider.eventBus.fire(self, 'ParticipantsUpdated')
- self.__triggerParticipantUpdate()
- self._updateParticipantEvent.clear()
- try:
- yield WaitForEvent(self._updateParticipantEvent, 14.5)
- except TaskTimeout:
- pass
- finally:
- self._log('Exiting update participant loop')
- def _partnerLeftDialogCallback(self, ignore):
- self._log('_partnerLeftDialogCallback numParticipants_ is %s', self.numParticipants())
- if self.numParticipants() <= 1 and not self.isRoomSession():
- self.endSession()
- def ignoreUser(self, userId):
- self.__ignoredUsers.append(userId)
- def unIgnoreUser(self, userId):
- self.__ignoredUsers.remove(userId)
- def isIgnoredUser(self, userId):
- return userId in self.__ignoredUsers
- def __addIncomingMessage(self, messageDict):
- assertInRelease(messageDict)
- from_id = int(messageDict['from_id'])
- if from_id != 0:
- if self.isIgnoredUser(from_id):
- return
- if from_id not in self.getParticipantUserIds():
- self._log('Deferring message %r, updating participant list', messageDict)
- self.__pendingMessages.append(messageDict)
- self._updateParticipantEvent.set()
- return
- self.__processIncomingMessage(messageDict)
- def __processIncomingMessage(self, messageDict):
- if not self.__duplicateDetector.checkDuplicate(messageDict):
- 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))))
- def endSession(self):
- self.__serviceProvider.eventBus.fire(self, 'Session.End')
- def sendImMessage(self, messageText, to=0):
- self._log('sendImMessage(): messageText: %r', messageText)
- self.maybeConnect()
- for i in range(3):
- self.__addIncomingMessage({'from_id': self.userId_, 'message': messageText, 'to_id': to})
- self.__outgoingMessages.put((messageText, to))
- def setCommandManager(self, c):
- self.__dispatcher.setCommandManager(c)
- def numParticipants(self):
- return len(self.getParticipantUserIds())
- def sessionIsFull(self):
- return False
- def isPrivate(self):
- return False
- @task
- def _sendInvitation(self, partnerId, inviteId=None):
- if partnerId == self.userId_:
- yield Return({'response': 'decline', 'reason': 'You cannot invite yourself to a chat'})
- yield self.__chatConnectedEvent.wait()
- args = {'userId': self.userId_,
- 'partnerId': partnerId,
- 'chatId': self.chatId_ or 0,
- 'location': self.location}
- if inviteId is not None:
- args['inviteId'] = inviteId
- rv = yield self.__serviceProvider.chatGateway.attemptInvite(**args)
- yield Return(rv)
- return
- def inviteToChat(self, inviteeId):
- self.attachTask(self.__inviteToChat(inviteeId))
- @task
- def sendAwayNote(self, inviteId, inviteeId, reason):
- self._log('sendAwayNote(): inviteId: %r inviteeId: %r reason: %r', inviteId, inviteeId, reason)
- reason = reason[10:]
- partnerName = yield self.__serviceProvider.avatarInfoManager.getAvatarName(inviteeId)
- dialog = InvitationDeclinedDialog()
- dialog.dialogInfo = {'title': LString('Invitation declined'),
- '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 ''),
- 'defaultValue': ''}
- user_message = self.__serviceProvider.dialogManager.showModal(self.__parentHwnd, dialog)
- if not user_message:
- return
- user_name = yield self.__serviceProvider.avatarInfoManager.getAvatarName(self.userId_)
- if not user_name:
- user_name = '<Avatar>'
- away_note = user_name + ': ' + user_message
- yield self.__serviceProvider.chatGateway.leaveInviteAwayNote(self.userId_, inviteId, away_note)
- @task
- def __inviteToChat(self, inviteeId):
- with (yield self.__inviteToChatLock.acquire()):
- firstInviteAttemptTime = self.__serviceProvider.timeProvider()
- self._log('inviteToChat(%s, %s) firstInviteAttemptTime=%d', self, inviteeId, firstInviteAttemptTime)
- self.__inviteAttempts = 0
- self._showStillWaitingMsg()
- inviteId = None
- while True:
- self.__inviteAttempts += 1
- logger.info('inviteToChat attempting to make invite #%d (time is %d)', self.__inviteAttempts, self.__serviceProvider.timeProvider())
- try:
- ret = yield self._sendInvitation(partnerId=inviteeId, inviteId=inviteId)
- except networkExceptions:
- logger.exception('sendInvitation raised, assuming we should keep waiting.')
- ret = {'waiting': True}
- newInviteId = ret.get('inviteId')
- try:
- newInviteId = int(newInviteId)
- except (TypeError, ValueError):
- logger.warning('Got funky inviteId: %r', newInviteId)
- if inviteId is not None and newInviteId is not None and inviteId != newInviteId:
- logger.critical('We asked for the status of an invite - but got back a new invite!')
- if inviteId is None:
- inviteId = newInviteId
- if not self.chatId_ and ret.get('chatId', 0) != 0:
- logger.info("Didn't have a chat, but got one! %r", ret['chatId'])
- self.__joinChat(ret['chatId'], 1)
- self.__setupPostConnectTasks()
- if 'waiting' in ret:
- if self.__serviceProvider.timeProvider() - firstInviteAttemptTime > self.MaxSecondsToWaitForAccept:
- self._log('partner %s timed out our invitation after %d seconds', inviteeId, self.__serviceProvider.timeProvider() - firstInviteAttemptTime)
- partnerName = yield self.__serviceProvider.avatarInfoManager.getAvatarName(inviteeId)
- self._hideStillWaitingMsg()
- self._showUiMessage(self.__serviceProvider.translationTable.FLS('{partnerName} did not answer your invitation.', partnerName=partnerName), timeout=30)
- return
- else:
- if 'response' in ret:
- response = ret['response']
- if response == 'decline':
- reason = ret.get('reason', None)
- inviteId = ret.get('inviteId', None)
- accessViolation = ret.get('accessViolation', None)
- if not reason:
- reason = 'no reason given'
- self._log('partner %s declined our invitation, closing session', inviteeId)
- self._hideStillWaitingMsg()
- if reason.find("I'm away") >= 0 and inviteId:
- self.attachTask(self.sendAwayNote(inviteId, inviteeId, reason))
- else:
- partnerName = yield self.__serviceProvider.avatarInfoManager.getAvatarName(inviteeId)
- if accessViolation:
- self._showUiMessage(self.__serviceProvider.translationTable.FLS('{partnerName} can not join as the room only allows', partnerName=partnerName) + ' ' + accessViolation, timeout=300)
- else:
- self._showUiMessage(self.__serviceProvider.translationTable.FLS('{partnerName} declined to chat, saying', partnerName=partnerName) + " '" + reason + "'", timeout=300)
- return
- raise Exception('unknown response: %r' % ret)
- else:
- self._log('inviteToChat: invite was accepted from %s', inviteeId)
- self._updateParticipantEvent.set()
- self._hideStillWaitingMsg()
- return
- yield Sleep(1)
- raise Exception('should never be reached')
- return
- def onImqMessage(self, message):
- logger.info('%s.onImqMessage(%r)', type(self).__name__, [
- message.user_id, message.queue, message.mount, message.message])
- if message.mount == 'control':
- m = json.loads(message.message)
- if not isinstance(m, dict):
- logger.warning('Got invalid control message %r', m)
- return
- self.__serviceProvider.eventBus.fire(self, 'ControlMessage', m)
- else:
- if message.mount == 'messages' and self.__imqReceive:
- m = json.loads(message.message)
- if not isinstance(m, dict):
- logger.warning('Got invalid chat message %r', m)
- return
- if isinstance(message.user_id, int):
- m['from_id'] = message.user_id if 1 else int(message.user_id.split('/')[-1])
- if m['from_id'] != m.get('userId', 0):
- logger.warning('forged message detected: from %r: %r', message.user_id, m)
- m['to_id'] = m.get('to', 0)
- self.__addIncomingMessage(m)
- def _showStillWaitingMsg(self):
- pass
- def _hideStillWaitingMsg(self):
- pass
- def canBoot(self, booter, bootee):
- return False
- def isLieutenant(self, userId):
- return False
- class InviteDecision():
- ACCEPT = 'ACCEPT'
- DECLINE = 'DECLINE'
- IGNORE = 'IGNORE'
- REJECTED = 'REJECTED'
- class ChatSession(DirectConnectSession):
- def __init__(self, serviceProvider, userId, result, showMessageFunc=NullFunc, parentHwnd=None, location=0):
- DirectConnectSession.__init__(self, serviceProvider=serviceProvider, userId=userId, showMessageFunc=showMessageFunc, parentHwnd=parentHwnd, location=location)
- self.__result = result
- self.maybeConnect()
- @task
- def getOrMakeChat(self, inviteId=None, private=None):
- return self.__result
- def shouldResetRoomDefinitionAtStartup(self):
- return False
- DEFAULT_PUBLIC_ROOM_TITLE = 'IMVU Chat Room'
- class JoinRoomSession(DirectConnectSession):
- def __init__(self, userId, roomInstanceId, serviceProvider, modeConstructedEvent, showMessageFunc=NullFunc, parentHwnd=None, lieutenants=[], roomOwners=[], allowRoomShellOverwrite=False, allowLoadNewRoom=False, private=None, autoBootWhenOwnerLeaves=True):
- DirectConnectSession.__init__(self, serviceProvider=serviceProvider, userId=userId, showMessageFunc=showMessageFunc, parentHwnd=parentHwnd)
- if not isinstance(roomInstanceId, basestring):
- raise TypeError('roomInstanceId must be a string, was %r' % (roomInstanceId,))
- if not isinstance(roomOwners, list):
- raise TypeError('roomOwners must be a list, was %r' % (roomOwners,))
- self.roomInstanceId_ = roomInstanceId
- self.__serviceProvider = serviceProvider
- self.__modeConstructedEvent = modeConstructedEvent
- self.__lieutenants = lieutenants
- self.__roomOwners = roomOwners
- self.__allowRoomShellOverwrite = allowRoomShellOverwrite
- self.__allowLoadNewRoom = allowLoadNewRoom
- self.__parentHwnd = parentHwnd
- self.__private = private
- self.__autoBootWhenOwnerLeaves = autoBootWhenOwnerLeaves
- self.reasons_ = {ERROR_PUBLIC_ROOM_CLIENT_VERSION_OLD: self.__serviceProvider.translationTable.LS('Your client version is too old, please upgrade to the latest version.'),
- ERROR_PUBLIC_ROOM_AGE_LIMIT: self.__serviceProvider.translationTable.LS('You are too young to join a chat room chat.'),
- ERROR_PUBLIC_ROOM_CLOSED: self.__serviceProvider.translationTable.LS('The room is currently closed.'),
- ERROR_PUBLIC_ROOM_BOOTED: self.__serviceProvider.translationTable.LS('You have been kicked out of the room. Cannot rejoin within 20 minutes.'),
- ERROR_PUBLIC_ROOM_FULL: self.__serviceProvider.translationTable.LS('The room is full.')}
- self.maybeConnect(private=private)
- @property
- def location(self):
- return self.roomInstanceId_
- def isOwner(self, userId):
- return self.roomInstanceId_.startswith(str(userId) + '-') or userId in self.getRoomOwners()
- def isPrivate(self):
- return self.__private
- def getOwner(self):
- return int(self.roomInstanceId_.split('-')[0])
- def isLieutenant(self, userId):
- return str(userId) in self.__lieutenants
- def hasBootPrivileges(self, userId):
- return self.isOwner(userId) or self.isLieutenant(userId)
- def canBoot(self, booter, bootee):
- return self.hasBootPrivileges(booter) and not self.hasBootPrivileges(bootee)
- def isRoomSession(self):
- return True
- def allowRoomShellOverwrite(self):
- return self.__allowRoomShellOverwrite
- def autoBootWhenOwnerLeaves(self):
- return self.__autoBootWhenOwnerLeaves
- def setAutoBootWhenOwnerLeaves(self, autoBootWhenOwnerLeaves):
- self.__autoBootWhenOwnerLeaves = autoBootWhenOwnerLeaves
- def allowLoadNewRoom(self):
- return self.__allowLoadNewRoom
- def getRoomOwners(self):
- return self.__roomOwners
- def setRoomOwners(self, roomOwners):
- self.__roomOwners = roomOwners
- def isAlwaysDriver(self):
- return False
- def resetRoomDefinitionAtStartup(self):
- return False
- def getRoomInstanceId(self):
- return self.roomInstanceId_
- def setRoomInstanceId(self, roomInstanceId):
- self.roomInstanceId_ = roomInstanceId
- @task
- def getOrMakeChat(self, inviteId=None, private=None):
- self._log('JoinRoomSession::getOrMakeChat(): self.userId_: %r self.roomInstanceId_: %r', self.userId_, self.roomInstanceId_)
- activity = 'publicroom-%s' % self.roomInstanceId_
- ret = yield self.__serviceProvider.chatGateway.getOrMakeChat(self.userId_, activity, self.chatId_ or 0, capacity=9999, publicRoom=True, private=private)
- if 'response' in ret and ret['response'] == 'declined':
- errorCode = ret.get('reason', None)
- errorExplanation = ret.get('explanation', None)
- self._log('User %s declined to join the chat room, closing session', self.userId_)
- yield self.__modeConstructedEvent.wait()
- self.closeSession()
- self.__showErrorMessage(errorCode, errorExplanation)
- else:
- yield Return(ret)
- return
- def bootUser(self, userId):
- self._log('boot user %r', userId)
- @task
- def boot():
- yield self.__serviceProvider.chatGateway.bootOutOfChat({'userId': userId,
- 'roomInstanceId': self.roomInstanceId_})
- self._updateParticipantEvent.set()
- self.attachTask(boot())
- def __showErrorMessage(self, errorCode, errorExplanation):
- if errorCode is None:
- return
- if errorCode == ERROR_PUBLIC_ROOM_FULL:
- title = self.__serviceProvider.translationTable.LS('Sorry!')
- 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...')
- else:
- if errorExplanation is None:
- reason = self.reasons_.get(errorCode, 'no reason given')
- title = self.__serviceProvider.translationTable.LS('Chat Room Access Declined')
- text = self.__serviceProvider.translationTable.FLS('Your access to the chat room is declined. Reason: {0!r}', reason)
- else:
- title = self.__serviceProvider.translationTable.LS('Chat Room Access Declined')
- text = self.__serviceProvider.translationTable.FLS('{0}', errorExplanation)
- self.__serviceProvider.dialogManager.showModal(self.__parentHwnd, imvu.dialog.ConfirmationDialog(title, text))
- self.endSession()
- return
- def _showStillWaitingMsg(self):
- self._showUiMessage(self.__serviceProvider.translationTable.LS('Inviting: waiting for reply...'))
- @task
- def handleInvite(serviceProvider, userId, decisionCallback, startChatCallback, parentHwnd=None):
- if serviceProvider.mqManager.isConnected() and serviceProvider.mqManager.enabled('imq.chat_invites'):
- yield _waitForInvite(serviceProvider, userId, decisionCallback, startChatCallback, parentHwnd)
- else:
- yield _pollForInvite(serviceProvider, userId, decisionCallback, startChatCallback, parentHwnd)
- @task
- def _pollForInvite(serviceProvider, userId, decisionCallback, startChatCallback, parentHwnd=None):
- try:
- invite = yield serviceProvider.chatGateway.checkForInvite2({'userId': userId})
- except networkExceptions:
- logger.exception('checkForInvite2 failed')
- invite = None
- yield _handleInvite(serviceProvider, invite, userId, decisionCallback, startChatCallback, parentHwnd)
- return
- @task
- def _waitForInvite(serviceProvider, userId, decisionCallback, startChatCallback, parentHwnd=None):
- class IMQInviteReceiver(object):
- def __init__(self):
- self.__future = None
- serviceProvider.eventBus.register(serviceProvider.serverEventTransport, 'ServerEvent.chatInvite', self.__inviteReceived)
- return
- def __inviteReceived(self, event):
- if self.__future:
- future = self.__future
- self.__future = None
- future.complete(event.info)
- return
- @property
- def future(self):
- self.__future = imvu.task.Future()
- return self.__future
- logger.info('listening for IMQ chat invites')
- receiver = IMQInviteReceiver()
- while True:
- invite = yield receiver.future
- yield _handleInvite(serviceProvider, invite, userId, decisionCallback, startChatCallback, parentHwnd)
- @task
- def _handleInvite(serviceProvider, invite, userId, decisionCallback, startChatCallback, parentHwnd):
- if not (type(invite) is dict and all((key in invite for key in ('chatId', 'inviteId',
- 'partnerId',
- 'location', 'inviter')))):
- logger.error('ignoring invite (%r)', invite)
- return
- chatId = invite['chatId']
- inviteId = invite['inviteId']
- partnerId = invite['partnerId']
- location = invite['location']
- partnerData = invite['inviter']
- decision, reason = yield decisionCallback(partnerId, location, partnerData)
- if decision is InviteDecision.ACCEPT:
- logger.info('Accepting chat invitation')
- try:
- result = yield serviceProvider.chatGateway.acceptInvite({'userId': userId,
- 'inviteId': inviteId,
- 'chatId': chatId})
- if result.get('expired'):
- message = serviceProvider.translationTable.LS('Sorry, the invite has expired and the room is unavailable')
- title = serviceProvider.translationTable.LS('Invite Has Expired')
- serviceProvider.dialogManager.showModal(parentHwnd, imvu.dialog.ConfirmationDialog(title, message))
- yield Return(False)
- participantInfos = yield serviceProvider.chatGateway.getParticipants(userId, chatId)
- result['location'] = location
- except networkExceptions:
- logger.exception('acceptInvite failed')
- else:
- logger.info('acceptInvite returned %s', result)
- participants = [ int(x['userId']) for x in participantInfos ]
- if partnerId in participants:
- startChatCallback(partnerId, result)
- else:
- name = yield serviceProvider.avatarInfoManager.getAvatarName(partnerId)
- message = serviceProvider.translationTable.FLS('Oops, {0} has left the chat', name)
- title = serviceProvider.translationTable.LS('Chat Ended')
- serviceProvider.dialogManager.showModal(parentHwnd, imvu.dialog.ConfirmationDialog(title, message))
- else:
- if decision is InviteDecision.DECLINE or decision is InviteDecision.REJECTED:
- logger.info('Declining chat invitation')
- try:
- yield serviceProvider.chatGateway.declineInvite({'userId': userId, 'inviteId': inviteId,
- 'reason': reason,
- 'chatId': chatId,
- 'status': 'rejected' if decision is InviteDecision.REJECTED else 'declined'})
- except networkExceptions:
- logger.exception('declineInvite failed')
- @task
- def checkInviteSafety(serviceProvider, userId, roomPid):
- try:
- avatarInfo = yield serviceProvider.avatarInfoManager.getAvatarInfo(userId)
- except Exception as e:
- yield Return()
- if not avatarInfo.hasAP:
- productInfo, = yield serviceProvider.productInfoManager.getProductsByIds([roomPid])
- if productInfo.requiresAP:
- yield Return('You can not invite a non-AP user to an AP room.')
- class MeetSomeoneSession(DirectConnectSession):
- def __init__(self, userId, serviceProvider, roomInstanceId, showMessageFunc=NullFunc, parentHwnd=None):
- DirectConnectSession.__init__(self, serviceProvider=serviceProvider, userId=userId, showMessageFunc=showMessageFunc, parentHwnd=parentHwnd)
- self.__serviceProvider = serviceProvider
- self.__roomInstanceId = roomInstanceId
- self.__chatNowParams_ = {}
- self.__avatarInfoManager = imvu.gateway.AvatarInfoManager(self.__serviceProvider)
- self.__parentHwnd = parentHwnd
- self.maybeConnect(private=True)
- @property
- def __participantId(self):
- if self.participants_:
- return self.participants_[0]
- return
- return
- def getActivity(self):
- return 'Chat now-' + self.__roomInstanceId
- def getRoomInstanceId(self):
- return self.__roomInstanceId
- def getOwner(self):
- return self.userId_
- def setChatNowParams(self, chatParams):
- def filter(collection, filters):
- return dict(((key, value) for key, value in chatParams.iteritems() if key in filters))
- self.__chatNowParams_ = filter(chatParams, ['age', 'ap', 'location', 'gender', 'language'])
- def _getChatNowParams(self):
- return self.__chatNowParams_
- def isRoomSession(self):
- return True
- @task
- def getOrMakeChat(self, inviteId=None, private=None):
- filter = self.__chatNowParams_.get('filter', 'surprise')
- activity = 'Chat now-' + filter
- args = {'userId': self.userId_, 'version': __version__,
- 'activity': activity,
- 'chatId': self.chatId_ or 0,
- 'private': private or True,
- 'chatNowParams': self.__chatNowParams_}
- result = yield self.__serviceProvider.chatGateway.getOrMakeChat(self.userId_, activity, self.chatId_ or 0, capacity=None, publicRoom=None, private=None, chatNowParams=self.__chatNowParams_ or None)
- yield Return(result)
- return
- def _showStillWaitingMsg(self):
- self._log('MeetSomeoneSession: _showStillWaitingMsg')
- self._showUiMessage(self.__serviceProvider.translationTable.LS('Connecting you with another person...'), 2)
- def _showConnectedMessage(self):
- self._showUiMessage(self.__serviceProvider.translationTable.LS('Chat now! found someone...'))
- # okay decompiling meet.pyo
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement