Ejemplo n.º 1
0
class EquipmentsPlugin(common.IntervalPlugin):
    __slots__ = ('__generator',)

    def __init__(self, parent):
        super(EquipmentsPlugin, self).__init__(parent)
        self.__generator = SequenceIDGenerator()

    def start(self):
        super(EquipmentsPlugin, self).start()
        ctrl = self.sessionProvider.shared.equipments
        if ctrl is not None:
            ctrl.onEquipmentMarkerShown += self.__onEquipmentMarkerShown
        return

    def stop(self):
        ctrl = self.sessionProvider.shared.equipments
        if ctrl is not None:
            ctrl.onEquipmentMarkerShown -= self.__onEquipmentMarkerShown
        super(EquipmentsPlugin, self).stop()
        return

    def __onEquipmentMarkerShown(self, equipment, position, _, interval):
        uniqueID = self.__generator.next()
        marker = equipment.getMarker()
        if marker in settings.EQ_MARKER_TO_SYMBOL:
            symbol = settings.EQ_MARKER_TO_SYMBOL[marker]
        else:
            LOG_ERROR('Symbol is not found for equipment', equipment)
            return
        matrix = minimap_utils.makePositionMatrix(position)
        model = self._addEntryEx(uniqueID, symbol, _C_NAME.EQUIPMENTS, matrix=matrix, active=True)
        if model is not None:
            self._setCallback(uniqueID, int(interval))
        return
Ejemplo n.º 2
0
class EquipmentsPlugin(common.IntervalPlugin):
    __slots__ = ('__generator',)

    def __init__(self, parent):
        super(EquipmentsPlugin, self).__init__(parent)
        self.__generator = SequenceIDGenerator()

    def start(self):
        super(EquipmentsPlugin, self).start()
        ctrl = g_sessionProvider.shared.equipments
        if ctrl is not None:
            ctrl.onEquipmentMarkerShown += self.__onEquipmentMarkerShown
        return

    def stop(self):
        ctrl = g_sessionProvider.shared.equipments
        if ctrl is not None:
            ctrl.onEquipmentMarkerShown -= self.__onEquipmentMarkerShown
        super(EquipmentsPlugin, self).stop()
        return

    def __onEquipmentMarkerShown(self, equipment, position, _, interval):
        uniqueID = self.__generator.next()
        marker = equipment.getMarker()
        if marker in settings.EQ_MARKER_TO_SYMBOL:
            symbol = settings.EQ_MARKER_TO_SYMBOL[marker]
        else:
            LOG_ERROR('Symbol is not found for equipment', equipment)
            return
        matrix = minimap_utils.makePositionMatrix(position)
        model = self._addEntryEx(uniqueID, symbol, _C_NAME.EQUIPMENTS, matrix=matrix, active=True)
        if model is not None:
            self._setCallback(uniqueID, int(interval))
        return
Ejemplo n.º 3
0
class _SquadInvitationsRecorder(_SquadInvitationsHandler):
    """ This class wraps _SquadInvitationsHandler in order to record player's
    actions with dyn squads during replay recording."""

    __slots__ = ("__idGen",)

    def __init__(self, setup):
        super(_SquadInvitationsRecorder, self).__init__(setup)
        self.__idGen = SequenceIDGenerator()

    def send(self, playerID):
        BattleReplay.g_replayCtrl.serializeCallbackData(_SEND_ACTION_NAME, (self.__idGen.next(), playerID))
        super(_SquadInvitationsRecorder, self).send(playerID)

    def accept(self, playerID):
        BattleReplay.g_replayCtrl.serializeCallbackData(_ACCEPT_ACTION_NAME, (self.__idGen.next(), playerID))
        super(_SquadInvitationsRecorder, self).accept(playerID)

    def reject(self, playerID):
        BattleReplay.g_replayCtrl.serializeCallbackData(_REJECT_ACTION_NAME, (self.__idGen.next(), playerID))
        super(_SquadInvitationsRecorder, self).reject(playerID)
Ejemplo n.º 4
0
class _SquadInvitationsRecorder(_SquadInvitationsHandler):
    __slots__ = ('__idGen', )

    def __init__(self, setup):
        super(_SquadInvitationsRecorder, self).__init__(setup)
        self.__idGen = SequenceIDGenerator()

    def send(self, playerID):
        BattleReplay.g_replayCtrl.serializeCallbackData(
            _SEND_ACTION_NAME, (self.__idGen.next(), playerID))
        super(_SquadInvitationsRecorder, self).send(playerID)

    def accept(self, playerID):
        BattleReplay.g_replayCtrl.serializeCallbackData(
            _ACCEPT_ACTION_NAME, (self.__idGen.next(), playerID))
        super(_SquadInvitationsRecorder, self).accept(playerID)

    def reject(self, playerID):
        BattleReplay.g_replayCtrl.serializeCallbackData(
            _REJECT_ACTION_NAME, (self.__idGen.next(), playerID))
        super(_SquadInvitationsRecorder, self).reject(playerID)
Ejemplo n.º 5
0
class _InvitesIDsManager(object):
    def __init__(self):
        self.clear()

    def clear(self):
        self.__idsGen = SequenceIDGenerator()
        self.__idsMap = {'inviteIDs': {}, 'clubIDs': {}}

    def getInviteID(self, clubDbID, userDbID, creationTime):
        uniqueID = (clubDbID, userDbID, creationTime)
        if uniqueID not in self.__idsMap['clubIDs']:
            inviteID, showAt = self.__idsGen.next(), None
            self.__idsMap['inviteIDs'][inviteID] = uniqueID
            self.__idsMap['clubIDs'][uniqueID] = (inviteID, showAt)
        else:
            inviteID, showAt = self.__idsMap['clubIDs'][uniqueID]
        return (inviteID, showAt)

    def setShowTime(self, inviteID, showAt):
        uniqueID = self.__idsMap['inviteIDs'][inviteID]
        self.__idsMap['clubIDs'][uniqueID] = (inviteID, showAt)
Ejemplo n.º 6
0
class _InvitesIDsManager(object):

    def __init__(self):
        self.clear()

    def clear(self):
        self.__idsGen = SequenceIDGenerator()
        self.__idsMap = {'inviteIDs': {},
         'clubIDs': {}}

    def getInviteID(self, clubDbID, userDbID, creationTime):
        uniqueID = (clubDbID, userDbID, creationTime)
        if uniqueID not in self.__idsMap['clubIDs']:
            inviteID, showAt = self.__idsGen.next(), None
            self.__idsMap['inviteIDs'][inviteID] = uniqueID
            self.__idsMap['clubIDs'][uniqueID] = (inviteID, showAt)
        else:
            inviteID, showAt = self.__idsMap['clubIDs'][uniqueID]
        return (inviteID, showAt)

    def setShowTime(self, inviteID, showAt):
        uniqueID = self.__idsMap['inviteIDs'][inviteID]
        self.__idsMap['clubIDs'][uniqueID] = (inviteID, showAt)
Ejemplo n.º 7
0
class XmppPlugin(IProtoPlugin):
    DISCONNECT_BY_REQUEST = 0
    DISCONNECT_AUTHENTICATION = 1
    DISCONNECT_OTHER_ERROR = 2
    USE_MOCK_DATA = False
    ALLOWED_ROSTER_ACTIONS = [
        USER_ROSTER_ACTION.AddToFriend, USER_ROSTER_ACTION.AddToIgnored,
        USER_ROSTER_ACTION.RemoveFromFriend,
        USER_ROSTER_ACTION.RemoveFromIgnored
    ]

    def __init__(self):
        self.__client = BigWorld.XmppClient()
        self.__currentUser = None
        self.__xmppRoster = None
        self.__usersMgr = None
        self.__model = None
        self.__bwRoster = None
        self.__reconnectCount = 0
        self.__reconnectCallbackId = None
        self.__bwConnected = False
        self.__isEnabled = False
        self.__idsGen = SequenceIDGenerator()
        self.__pendingBattleMode = None
        self.__databaseID = None
        return

    @storage_getter('users')
    def usersStorage(self):
        return None

    @property
    def isConnected(self):
        """
        Shows current XMPP connection status
        """
        if self.__model is not None:
            return self.__model.isConnected
        else:
            return False

    def logState(self):
        if self.__isEnabled:
            if self.__model is not None and self.__model.isConnected:
                itemsStrList = [
                    'XMPP:logState - XMPP is connected. Logging XMPP roster state:'
                ]
                itemsStrList.append('Curr.User JID: {0}  Status: {1}'.format(
                    self.__currentUser.bareJid,
                    self.__currentUser.getPresenceStr(
                        self.__currentUser.presence)))
                for jid, item in self.__xmppRoster.items():
                    itemsStrList.append(
                        'Contact   JID: {0}  Status: {1}  Name: {2}'.format(
                            jid, item.getPresenceStr(item.presence),
                            item.name))

                LOG_DEBUG('\n'.join(itemsStrList))
            else:
                LOG_DEBUG(
                    'XMPP:logState - XMPP is not connected yet. Try to run your command later'
                )
        else:
            LOG_DEBUG(
                'XMPP:logState - You are not logged in or connection to XMPP is disabled by server settings'
            )
        return

    def connect(self, scope=None):
        if scope is not None:
            self._setBattleMode(scope)
        if self.isConnected:
            return
        else:
            self.__bwConnected = True
            self._cancelReconnectCallback()
            settings = self._getServerSettings()
            if settings.get('xmpp_enabled', False):
                self.__isEnabled = bool(int(settings.get('jdCutouts', 0)))
                if self.__isEnabled:
                    self._subscribeToActions()
                    LOG_DEBUG(
                        'XMPP:connect - XMPP functionality is enabled. Starting connection to XMPP server'
                    )
                    if self.__model is None:
                        self.__model = XmppConnectionModel(
                            settings.get('xmpp_host'),
                            settings.get('xmpp_port'),
                            settings.get('xmpp_resource'), False, None, None)
                    else:
                        self.__model = self.__model._replace(
                            host=settings.get('xmpp_host'),
                            port=settings.get('xmpp_port'),
                            resourceName=settings.get('xmpp_resource'),
                            isConnected=False)
                    if self.__model.host is None:
                        raise Exception, 'XMPP: server xmpp_host is not defined'
                    connections = settings.get('xmpp_connections', [])
                    if len(connections) > 0:
                        self.__model = self.__model._replace(
                            connection=random.choice(connections))
                    else:
                        self.__model = self.__model._replace(
                            connection=(self.__model.host, self.__model.port))
                        LOG_DEBUG(
                            'XMPP:connect - no xmpp_connections are passed - using default connection',
                            self.__model.connection)
                    if self.__model.token is None:
                        Account.g_accountRepository and Account.g_accountRepository.onChatTokenReceived.clear(
                        )
                        Account.g_accountRepository.onChatTokenReceived += self._tokenCallback
                    BigWorld.player().requestChatToken(self.__idsGen.next())
                else:
                    LOG_DEBUG(
                        'XMPP:connect - trying to connect using token from previous connection'
                    )
                    self._tokenCallback(
                        cPickle.dumps({
                            'error': None,
                            'token': self.__model.token,
                            'databaseID': self.__databaseID
                        }))
            else:
                LOG_DEBUG(
                    'XMPP:connect - XMPP functionality is disabled. Stopping execution'
                )
            return

    def disconnect(self):
        LOG_DEBUG('XMPP:disconnect')
        if Account.g_accountRepository:
            Account.g_accountRepository.onChatTokenReceived.clear()
        self.__bwConnected = False
        if self.isConnected:
            self.__client.disconnect()
        else:
            self.onDisconnect()

    def onConnect(self):
        """
        Called after successful connection, encryption setup and authentication.
        """
        LOG_DEBUG('XMPP:onConnect - Successfully connected to XMPP server')
        self.__model = self.__model._replace(isConnected=True)
        self.__reconnectCount = 0
        self._cancelReconnectCallback()
        if self.__pendingBattleMode is not None:
            self._setBattleMode(self.__pendingBattleMode)
            self.__pendingBattleMode = None
        self._doRostersSync()
        return

    def onDisconnect(self, reason=DISCONNECT_BY_REQUEST, description=None):
        """
        Called if connection is closed or attempt to connect is failed.
        Additional description (in English) of disconnect reason is given. If
        description is empty then disconnect was caused by user (i.e. by
        explicit call to disconnect()).
        """
        LOG_DEBUG('XMPP:onDisconnect - Disconnected', reason, description)
        self._cancelReconnectCallback()
        if reason == self.DISCONNECT_AUTHENTICATION:
            self.__model = self.__model._replace(token=None)
        if self.__bwConnected:
            if self.__isEnabled:
                self.__model = self.__model._replace(isConnected=False)
                self.__reconnectCount += 1
                reconnectDelay = max(
                    random.random() * 2 * self.__reconnectCount, 10.0)
                self.__reconnectCallbackId = BigWorld.callback(
                    reconnectDelay, self.connect)
                LOG_DEBUG(
                    'XMPP:onDisconnect - will try to reconnect in {0} seconds'.
                    format(reconnectDelay), description)
        else:
            if self.__isEnabled:
                self._unsubscribeFromActions()
            self.__client.xmppHandler = None
            self.__currentUser = None
            self.__xmppRoster = None
            self.__model = None
            self.__bwRoster = None
            self.__isEnabled = False
            self.__reconnectCount = 0
            self.__databaseID = None
        return

    def onNewRosterItem(self, bareJid, name, groups, subscriptionTo,
                        subscriptionFrom):
        """
        Called when the contact is changed or added.
        
        name is custom contact name chosen by user.
        
        groups is set of groups (strings) which contact belongs to.
        
        subscriptionTo is presence subscription state in direction "contact
        TO user". One of SUBSCRIPTION_* values is used.
        
        subscriptionFrom is presence subscription state in direction "FROM user
        to contact". Either SUBSCRIPTION_ON or SUBSCRIPTION_OFF is used here.
        See onSubscribe() event.
        """
        LOG_DEBUG('XMPP:onNewRosterItem - New roster item added', bareJid,
                  name)
        if self.__bwRoster is not None:
            if bareJid in self.__bwRoster:
                self._addToLocalXmppRoster(bareJid, name, groups,
                                           subscriptionTo, subscriptionFrom)
            else:
                self._doXmppRosterAction(bareJid,
                                         USER_ROSTER_ACTION.RemoveFromFriend)
        else:
            self._addToLocalXmppRoster(bareJid, name, groups, subscriptionTo,
                                       subscriptionFrom)
        return

    def onRosterItemRemove(self, bareJid):
        """
        Called when the contact is removed.
        """
        LOG_DEBUG('XMPP:onRosterItemRemove', bareJid)
        if self.__bwRoster is not None:
            if bareJid not in self.__bwRoster:
                self._removeFromLocalXmppRoster(bareJid)
            else:
                user = self.__bwRoster[bareJid]
                action = USER_ROSTER_ACTION.AddToFriend if bool(
                    user.getRoster()
                    & USERS_ROSTER_FRIEND) else USER_ROSTER_ACTION.AddToIgnored
                self._doXmppRosterAction(bareJid, action, user.getName())
        else:
            self._removeFromLocalXmppRoster(bareJid)
        return

    def onNewRosterResource(self, fullJid, priority, status, presence):
        """
        Called when contact resource is changed or added.
        
        You should compare fullJid of resource with fullJid of client to
        determine if this resource change is actually server acknowledgement of
        user presence change.
        
        Exact value of resource priority depends solely on contact's choice.
        
        status can be arbitrary text.
        
        Resource presence is defined by one of PRESENCE_* values.
        """
        LOG_DEBUG('XMPP:onNewRosterResource', fullJid, priority, status,
                  presence)
        fullJidParts = fullJid.split('/')
        if len(fullJidParts) > 1:
            bareJid, resourceName = fullJidParts[0:2]
            if fullJid != self.__client.fullJid:
                if bareJid not in self.__xmppRoster:
                    self.__xmppRoster[bareJid] = RosterItem(bareJid)
                self.__xmppRoster[bareJid].updateResource(
                    resourceName, priority, status, presence)
            else:
                self.__currentUser.updateResource(resourceName, priority,
                                                  status, presence)

    def onRosterResourceRemove(self, fullJid):
        """
        Called when contact resource is removed (i.e. contact has gone offline).
        """
        LOG_DEBUG('XMPP:onRosterResourceRemove', fullJid)
        fullJidParts = fullJid.split('/')
        if len(fullJidParts) > 1:
            bareJid, resourceName = fullJidParts[0:2]
            if fullJid != self.__client.fullJid:
                if bareJid in self.__xmppRoster:
                    self.__xmppRoster[bareJid].removeResource(resourceName)
            else:
                self.__currentUser.removeResource(resourceName)

    def onSubscribe(self, bareJid, message):
        """
        Called when a contact (from roster or not) asks for subscription to user
        status updates.
        
        Call setSubscribed() or setUnsubscribed() to allow or disallow sending
        user status updates to the contact. Roster item will be automatically
        updated by onNewRosterItem event.
        
        Note that transition of subscriptionFrom attribute of contact from
        SUBSCRIPTION_OFF state to SUBSCRIPTION_PENDING state should be done
        manually in this callback. This event shouldn't be generated if
        subscriptionFrom is SUBSCRIPTION_ON, however it's possible.
        """
        LOG_DEBUG('XMPP:onSubscribe - Subscription request received', bareJid,
                  message)
        self.__client.setSubscribed(bareJid)

    def _subscribeToActions(self):
        """
        Adds subscription to UsersManager events
        """
        self.__usersMgr = g_messengerEvents.users
        self.__usersMgr.onUsersRosterReceived += self._onRosterReceived
        self.__usersMgr.onUserRosterChanged += self._onRosterUpdate

    def _unsubscribeFromActions(self):
        """
        Removes subscription to UsersManager events
        """
        if self.__usersMgr:
            self.__usersMgr.onUsersRosterReceived -= self._onRosterReceived
            self.__usersMgr.onUserRosterChanged -= self._onRosterUpdate
            self.__usersMgr = None
        return

    def _getServerSettings(self):
        """
        Gets server setting values
        """
        if self.USE_MOCK_DATA:
            settings = {
                'jdCutouts': 1,
                'xmpp_connections': [('jbr-wowpkis11.pershastudia.org', 5222)],
                'xmpp_host': 'jbr-wowpkis11.pershastudia.org',
                'xmpp_port': 5222,
                'xmpp_resource': 'wot',
                'xmpp_enabled': True
            }
        elif Account.g_accountRepository:
            settings = Account.g_accountRepository.serverSettings
        else:
            settings = {'jdCutouts': 0, 'xmpp_enabled': False}
        return settings

    def _tokenCallback(self, data):
        """
        Callback for PlayerAccount.requestChatToken method call
        """
        data = cPickle.loads(data)
        errorStr = data.get('error', None)
        if errorStr is None:
            self.__model = self.__model._replace(token=data.get('token'))
            self.__databaseID = data.get('databaseID')
            host, port = self.__model.connection
            if self.USE_MOCK_DATA:
                bareJid = '{0}@{1}'.format('admin1', self.__model.host)
            else:
                bareJid = '{0}@{1}'.format(self.__databaseID,
                                           self.__model.host)
            fullJid = '{0}/{1}'.format(bareJid, self.__model.resourceName)
            self.__currentUser = RosterItem(
                bareJid, 'Self', [], BigWorld.XmppClient.SUBSCRIPTION_OFF,
                BigWorld.XmppClient.SUBSCRIPTION_OFF)
            LOG_DEBUG(
                'XMPP:_tokenCallback - Token received - connecting to XMPP server',
                fullJid, self.__model.token, host, port)
            self.__client.xmppHandler = self
            self.__xmppRoster = {}
            self.__client.connect(fullJid, str(self.__model.token), host, port)
        else:
            self.onDisconnect()
            LOG_ERROR(
                'XMPP:_tokenCallback - Error while getting XMPP connection token',
                errorStr)
        return

    def _cancelReconnectCallback(self):
        try:
            if self.__reconnectCallbackId is not None:
                BigWorld.cancelCallback(self.__reconnectCallbackId)
        except:
            pass
        finally:
            self.__reconnectCallbackId = None

        return

    def _onRosterReceived(self):
        """
        Listener for UsersManager.onUsersRosterReceived
        """
        self.__bwRoster = {}
        contacts = self.usersStorage.all()
        LOG_DEBUG('XMPP:_onRosterReceived - BW rooster received', contacts)
        for user in contacts:
            if user.isCurrentPlayer():
                continue
            if self.USE_MOCK_DATA:
                bareJid = '{0}@{1}'.format('admin2', self.__model.host)
            else:
                bareJid = '{0}@{1}'.format(user.getID(), self.__model.host)
            self.__bwRoster[bareJid] = user

        self._doRostersSync()

    def _onRosterUpdate(self, action, user):
        """
        Listener for UsersManager.onUsersRosterUpdate
        """
        if action in self.ALLOWED_ROSTER_ACTIONS:
            if self.USE_MOCK_DATA:
                bareJid = '{0}@{1}'.format('admin2', self.__model.host)
            else:
                bareJid = '{0}@{1}'.format(user.getID(), self.__model.host)
            LOG_DEBUG('XMPP:_onRosterUpdate - BW rooster update', action, user)
            if action in [
                    USER_ROSTER_ACTION.AddToFriend,
                    USER_ROSTER_ACTION.AddToIgnored
            ]:
                self.__bwRoster[bareJid] = user
            elif bareJid in self.__bwRoster:
                del self.__bwRoster[bareJid]
            self._doXmppRosterAction(bareJid, action, user.getName())

    def _doRostersSync(self):
        """
        Performs XMPP roster synchronization with BW roster (BW is Master)
        """
        if self.__bwRoster is not None and self.isConnected:
            bwJidSet = set(self.__bwRoster)
            xmppJidSet = set(self.__xmppRoster)
            LOG_DEBUG('XMPP:_doRostersSync - Syncing BW and XMPP rosters')
            LOG_DEBUG('XMPP:_doRostersSync - BW roster', bwJidSet)
            LOG_DEBUG('XMPP:_doRostersSync - XMPP roster', xmppJidSet)
            toRemove = xmppJidSet - bwJidSet
            toAdd = bwJidSet - xmppJidSet
            for jid in toRemove:
                self._doXmppRosterAction(jid,
                                         USER_ROSTER_ACTION.RemoveFromFriend)

            for jid in toAdd:
                user = self.__bwRoster[jid]
                action = USER_ROSTER_ACTION.AddToFriend if bool(
                    user.getRoster()
                    & USERS_ROSTER_FRIEND) else USER_ROSTER_ACTION.AddToIgnored
                self._doXmppRosterAction(jid, action, user.getName())

        return

    def _addToLocalXmppRoster(self, bareJid, name, groups, subscriptionTo,
                              subscriptionFrom):
        """
        Adds new item to local XMPP roster
        """
        if bareJid in self.__xmppRoster:
            LOG_DEBUG(
                'XMPP:_addToLocalXmppRoster - Updating item in local XMPP roster',
                bareJid, name, groups, subscriptionTo, subscriptionFrom)
            item = self.__xmppRoster.get(bareJid)
            item.name, item.groups, item.subscriptionTo, item.subscriptionFrom = (
                name, groups, subscriptionTo, subscriptionFrom)
        else:
            LOG_DEBUG(
                'XMPP:_addToLocalXmppRoster - Adding item to local XMPP roster',
                bareJid, name, groups, subscriptionTo, subscriptionFrom)
            self.__xmppRoster[bareJid] = RosterItem(bareJid, name, groups,
                                                    subscriptionTo,
                                                    subscriptionFrom)

    def _removeFromLocalXmppRoster(self, bareJid):
        """
        Removes item from local XMPP roster
        """
        LOG_DEBUG(
            'XMPP:_removeFromLocalXmppRoster - Roster item is removed from local XMPP roster',
            bareJid, self.__xmppRoster[bareJid].name)
        del self.__xmppRoster[bareJid]

    def _doXmppRosterAction(self, bareJid, action, userName='******'):
        """
        Triggers needed roster action with XMPP chat server basing on passes action type
        """
        if action in [
                USER_ROSTER_ACTION.AddToFriend, USER_ROSTER_ACTION.AddToIgnored
        ]:
            LOG_DEBUG(
                'XMPP:_doXmppRosterAction - adding user from BW rooster to XMPP roster',
                bareJid, userName)
            self.__client.add(bareJid, userName)
            self.__client.subscribe(bareJid)
        elif action in [
                USER_ROSTER_ACTION.RemoveFromFriend,
                USER_ROSTER_ACTION.RemoveFromIgnored
        ]:
            LOG_DEBUG(
                'XMPP:_doXmppRosterAction - user is removed from BW rooster. Removing from XMPP roster',
                bareJid)
            self.__client.remove(bareJid)
            self.__client.unsubscribe(bareJid)

    def _setBattleMode(self, mode):
        LOG_DEBUG('XMPP:_setBattleMode', mode)
        if self.isConnected:
            self.__client.presence = BigWorld.XmppClient.PRESENCE_DND if mode == MESSENGER_SCOPE.BATTLE else BigWorld.XmppClient.PRESENCE_AVAILABLE
        else:
            self.__pendingBattleMode = mode
            self.onDisconnect()
Ejemplo n.º 8
0
class InvitesManager(object):
    __clanInfo = None

    def __init__(self, loader):
        self.__loader = loader
        self._IDGen = SequenceIDGenerator()
        self._IDMap = {'inviteIDs': {},
         'prbIDs': {}}
        self.__receivedInvites = {}
        self.__unreadInvitesCount = 0
        self.__eventManager = Event.EventManager()
        self.__acceptChain = None
        self.onReceivedInviteListInited = Event.Event(self.__eventManager)
        self.onReceivedInviteListModified = Event.Event(self.__eventManager)
        return

    def __del__(self):
        LOG_DEBUG('InvitesManager deleted')

    def init(self):
        self.__inited = PRB_INVITES_INIT_STEP.UNDEFINED
        g_messengerEvents.users.onUsersListReceived += self.__me_onUsersListReceived
        g_playerEvents.onPrebattleInvitesChanged += self.__pe_onPrebattleInvitesChanged
        g_playerEvents.onPrebattleInvitesStatus += self.__pe_onPrebattleInvitesStatus

    def fini(self):
        self.__clearAcceptChain()
        self.__inited = PRB_INVITES_INIT_STEP.UNDEFINED
        self.__loader = None
        g_messengerEvents.users.onUsersListReceived -= self.__me_onUsersListReceived
        g_playerEvents.onPrebattleInvitesChanged -= self.__pe_onPrebattleInvitesChanged
        g_playerEvents.onPrebattleInvitesStatus -= self.__pe_onPrebattleInvitesStatus
        self.clear()
        return

    def start(self):
        if self.__inited & PRB_INVITES_INIT_STEP.STARTED == 0:
            self.__inited |= PRB_INVITES_INIT_STEP.STARTED
            if self.__inited == PRB_INVITES_INIT_STEP.INITED:
                self.onReceivedInviteListInited()

    def clear(self):
        self.__inited = PRB_INVITES_INIT_STEP.UNDEFINED
        self.__receivedInvites.clear()
        self.__unreadInvitesCount = 0
        self._IDMap = {'inviteIDs': {},
         'prbIDs': {}}
        self.__eventManager.clear()

    def onAvatarBecomePlayer(self):
        if self.__inited & PRB_INVITES_INIT_STEP.STARTED > 0:
            self.__inited ^= PRB_INVITES_INIT_STEP.STARTED
        self.__clearAcceptChain()

    @storage_getter('users')
    def users(self):
        return None

    def isInited(self):
        return self.__inited == PRB_INVITES_INIT_STEP.INITED

    def acceptInvite(self, inviteID, postActions = None):
        try:
            prebattleID, peripheryID = self._IDMap['inviteIDs'][inviteID]
        except KeyError:
            LOG_ERROR('Invite ID is invalid', inviteID, self._IDMap)
            return

        self.__clearAcceptChain()
        if not postActions:
            self._doAccept(prebattleID, peripheryID)
        else:
            self.__acceptChain = _AcceptInvitesPostActions(peripheryID, prebattleID, postActions)
            self.__acceptChain.onStopped += self.__accept_onPostActionsStopped
            self.__acceptChain.start()
        if self.__unreadInvitesCount > 0:
            self.__unreadInvitesCount -= 1

    def declineInvite(self, inviteID):
        try:
            prebattleID, peripheryID = self._IDMap['inviteIDs'][inviteID]
        except KeyError:
            LOG_ERROR('Invite ID is invalid', inviteID, self._IDMap)
            return

        BigWorld.player().prb_declineInvite(prebattleID, peripheryID)
        if self.__unreadInvitesCount > 0:
            self.__unreadInvitesCount -= 1

    def canAcceptInvite(self, invite):
        result = False
        if invite.alwaysAvailable is True:
            result = True
        elif invite.id in self.__receivedInvites:
            dispatcher = self.__loader.getDispatcher()
            if dispatcher:
                prbFunctional = dispatcher.getPrbFunctional()
                unitFunctional = dispatcher.getUnitFunctional()
                preQueueFunctional = dispatcher.getPreQueueFunctional()
                if invite.alreadyJoined:
                    return False
                if prbFunctional and prbFunctional.hasLockedState() or unitFunctional and unitFunctional.hasLockedState() or preQueueFunctional and preQueueFunctional.hasLockedState():
                    return False
            another = invite.anotherPeriphery
            if another:
                if g_preDefinedHosts.periphery(invite.peripheryID) is None:
                    LOG_ERROR('Periphery not found')
                    result = False
                elif g_lobbyContext.getCredentials() is None:
                    LOG_ERROR('Login info not found')
                    result = False
                elif g_preDefinedHosts.isRoamingPeriphery(invite.peripheryID) and not isRoamingEnabled(g_itemsCache.items.stats.attributes):
                    LOG_ERROR('Roaming is not supported')
                    result = False
                else:
                    result = invite.id > 0 and invite.isActive()
            else:
                result = invite.id > 0 and invite.isActive()
        return result

    def canDeclineInvite(self, invite):
        result = False
        if invite.id in self.__receivedInvites:
            result = invite.id > 0 and invite.isActive()
        return result

    def getInviteInfo(self, inviteID):
        try:
            prebattleID, peripheryID = self._IDMap['inviteIDs'][inviteID]
            return (prebattleID, peripheryID)
        except KeyError:
            return (0, 0)

    def getReceivedInviteCount(self):
        return len(self.__receivedInvites)

    def getReceivedInvite(self, inviteID):
        invite = None
        if inviteID in self.__receivedInvites:
            invite = self.__receivedInvites[inviteID]
        return invite

    def getReceivedInvites(self, IDs = None):
        result = self.__receivedInvites.values()
        if IDs is not None:
            result = filter(lambda item: item.id in IDs, result)
        return result

    def getUnreadCount(self):
        return self.__unreadInvitesCount

    def resetUnreadCount(self):
        self.__unreadInvitesCount = 0

    def _doAccept(self, prebattleID, peripheryID):
        if connectionManager.peripheryID == peripheryID:
            BigWorld.player().prb_acceptInvite(prebattleID, peripheryID)
        else:
            LOG_ERROR('Invalid periphery', (prebattleID, peripheryID), connectionManager.peripheryID)

    def _makeInviteID(self, prebattleID, peripheryID):
        inviteID = self._IDMap['prbIDs'].get((prebattleID, peripheryID))
        if inviteID is None:
            inviteID = self._IDGen.next()
            self._IDMap['inviteIDs'][inviteID] = (prebattleID, peripheryID)
            self._IDMap['prbIDs'][prebattleID, peripheryID] = inviteID
        return inviteID

    def _addInvite(self, invite, userGetter):
        if self._isSenderIgnored(invite, userGetter):
            return False
        self.__receivedInvites[invite.id] = invite
        if invite.isActive():
            self.__unreadInvitesCount += 1
        return True

    def _updateInvite(self, other, userGetter):
        inviteID = other.id
        invite = self.__receivedInvites[inviteID]
        if self._isSenderIgnored(invite, userGetter):
            return False
        prevCount = invite.count
        invite = invite._merge(other)
        self.__receivedInvites[inviteID] = invite
        if invite.isActive() and prevCount < invite.count:
            self.__unreadInvitesCount += 1
        return True

    def _delInvite(self, inviteID):
        result = inviteID in self.__receivedInvites
        if result:
            self.__receivedInvites.pop(inviteID)
        return result

    def _isSenderIgnored(self, invite, userGetter):
        user = userGetter(invite.creatorDBID)
        areFriendsOnly = g_settings.userPrefs.invitesFromFriendsOnly
        if user:
            if areFriendsOnly:
                if user.isFriend():
                    return False
                else:
                    LOG_DEBUG('Invite is ignored, shows invites from friends only', invite)
                    return True
            if user.isIgnored():
                LOG_DEBUG('Invite is ignored, there is the contact in ignore list', invite, user)
                return True
        elif areFriendsOnly:
            LOG_DEBUG('Invite is ignored, shows invites from friends only', invite)
        return areFriendsOnly

    def _buildReceivedInvitesList(self, invitesData):
        if self.__inited & PRB_INVITES_INIT_STEP.DATA_BUILD == 0:
            self.__inited |= PRB_INVITES_INIT_STEP.DATA_BUILD
        self.__receivedInvites.clear()
        self.__unreadInvitesCount = 0
        receiver = getattr(BigWorld.player(), 'name', '')
        receiverDBID = getPlayerDatabaseID()
        receiverClanAbbrev = g_lobbyContext.getClanAbbrev(self.__clanInfo)
        userGetter = self.users.getUser
        for (prebattleID, peripheryID), data in invitesData.iteritems():
            inviteID = self._makeInviteID(prebattleID, peripheryID)
            invite = PrbInviteWrapper(id=inviteID, receiver=receiver, receiverDBID=receiverDBID, receiverClanAbbrev=receiverClanAbbrev, peripheryID=peripheryID, prebattleID=prebattleID, **data)
            self._addInvite(invite, userGetter)

    def __initReceivedInvites(self):
        step = PRB_INVITES_INIT_STEP.CONTACTS_RECEIVED
        if self.__inited & step != step:
            return
        invitesData = getattr(BigWorld.player(), 'prebattleInvites', {})
        LOG_DEBUG('Users roster received, list of invites are available', invitesData)
        self._buildReceivedInvitesList(invitesData)
        if self.__inited == PRB_INVITES_INIT_STEP.INITED:
            self.onReceivedInviteListInited()

    def __clearAcceptChain(self):
        if self.__acceptChain is not None:
            self.__acceptChain.onStopped -= self.__accept_onPostActionsStopped
            self.__acceptChain.stop()
            self.__acceptChain = None
        return

    def __me_onUsersListReceived(self, tags):
        doInit = False
        if USER_TAG.FRIEND in tags:
            doInit = True
            step = PRB_INVITES_INIT_STEP.FRIEND_RECEIVED
            if self.__inited & step == 0:
                self.__inited |= step
        if USER_TAG.IGNORED in tags:
            doInit = True
            step = PRB_INVITES_INIT_STEP.IGNORED_RECEIVED
            if self.__inited & step == 0:
                self.__inited |= step
        if doInit:
            self.__initReceivedInvites()

    def __pe_onPrebattleInvitesChanged(self, diff):
        step = PRB_INVITES_INIT_STEP.CONTACTS_RECEIVED
        if self.__inited & step != step:
            LOG_DEBUG('Received invites are ignored. Manager waits for client will receive contacts')
            return
        else:
            prbInvites = diff.get(('prebattleInvites', '_r'))
            if prbInvites is not None:
                self._buildReceivedInvitesList(prbInvites)
            prbInvites = diff.get('prebattleInvites')
            if prbInvites is not None:
                self.__updatePrebattleInvites(prbInvites)
            return

    def __pe_onPrebattleInvitesStatus(self, dbID, name, status):
        if status != PREBATTLE_INVITE_STATUS.OK:
            statusName = PREBATTLE_INVITE_STATUS_NAMES[status]
            SystemMessages.pushI18nMessage('#system_messages:invite/status/%s' % statusName, name=name, type=SystemMessages.SM_TYPE.Warning)

    def __updatePrebattleInvites(self, prbInvites):
        receiver = BigWorld.player().name
        receiverDBID = getPlayerDatabaseID()
        receiverClanAbbrev = g_lobbyContext.getClanAbbrev(self.__clanInfo)
        added = []
        changed = []
        deleted = []
        modified = False
        rosterGetter = self.users.getUser
        for (prebattleID, peripheryID), data in prbInvites.iteritems():
            inviteID = self._makeInviteID(prebattleID, peripheryID)
            if data is None:
                if self._delInvite(inviteID):
                    modified = True
                    deleted.append(inviteID)
                continue
            invite = PrbInviteWrapper(id=inviteID, receiver=receiver, receiverDBID=receiverDBID, receiverClanAbbrev=receiverClanAbbrev, peripheryID=peripheryID, prebattleID=prebattleID, **data)
            inList = inviteID in self.__receivedInvites
            if not inList:
                if self._addInvite(invite, rosterGetter):
                    modified = True
                    added.append(inviteID)
            elif self._updateInvite(invite, rosterGetter):
                modified = True
                changed.append(inviteID)

        if modified:
            self.onReceivedInviteListModified(added, changed, deleted)
        return

    def __accept_onPostActionsStopped(self, isCompleted):
        if not isCompleted:
            return
        prebattleID = self.__acceptChain.prebattleID
        peripheryID = self.__acceptChain.peripheryID
        if (prebattleID, peripheryID) in self._IDMap['prbIDs']:
            self._doAccept(prebattleID, peripheryID)
            if self.__unreadInvitesCount > 0:
                self.__unreadInvitesCount -= 1
        else:
            LOG_ERROR('Prebattle invite not found', prebattleID, peripheryID)
Ejemplo n.º 9
0
class ClientChat(object):
    __dataProcessors = [
        '_ClientChat__dataTimeProcessor',
        '_ClientChat__inviteDataTimeProcessor',
        '_ClientChat__systemMessageTimeProcessor'
    ]
    __actionHandlers = {
        CHAT_ACTIONS.receiveInvite.index(): '_ClientChat__onReceiveInvite'
    }

    def __init__(self):
        raise isinstance(self, BigWorld.Entity) or AssertionError
        self.__chatActionCallbacks = {}
        self._idGen = SequenceIDGenerator()

    def acquireRequestID(self):
        return self._idGen.next()

    def requestSystemChatChannels(self):
        self.__baseChatCommand(CHAT_COMMANDS.requestSystemChatChannels)

    def findChatChannels(self, sample, requestID=None):
        if requestID is None:
            requestID = self.acquireRequestID()
        try:
            self.__baseChatCommand(CHAT_COMMANDS.findChatChannels,
                                   stringArg1=sample,
                                   ignoreCooldown=False,
                                   requestID=requestID)
        except ChatError as ex:
            self._processChatError(CHAT_ACTIONS.requestChannels,
                                   0,
                                   ex,
                                   requestID=requestID)

        return

    def getChannelInfoById(self, channelId):
        self.__baseChatCommand(CHAT_COMMANDS.getChannelInfoById,
                               int64Arg=channelId)

    def requestChatChannelMembers(self, channelId):
        self.__baseChannelChatCommand(channelId,
                                      CHAT_COMMANDS.requestChatChannelMembers)

    def requestChatChannelMembersCount(self, channelId):
        self.__baseChannelChatCommand(channelId, CHAT_COMMANDS.getMembersCount)

    def createChatChannel(self, channelName, password=None):
        try:
            self.__baseChatCommand(
                CHAT_COMMANDS.createChatChannel,
                stringArg1=channelName,
                stringArg2=password if password is not None else '',
                ignoreCooldown=False)
        except ChatError as ex:
            self._processChatError(CHAT_COMMANDS.createChatChannel, 0, ex)

        return

    def destroyChatChannel(self, channelId):
        self.__baseChannelChatCommand(channelId,
                                      CHAT_COMMANDS.destroyChatChannel)

    def enterChat(self, channelId, password=None):
        self.__baseChannelChatCommand(
            channelId,
            CHAT_COMMANDS.enterChatChannel,
            stringArg1=password if password is not None else '')
        return

    def broadcast(self, channelId, message):
        if not len(message) or message.isspace():
            return
        message = message.rstrip()
        if not isCommandMessage(message):
            try:
                self.__baseChannelChatCommand(channelId,
                                              CHAT_COMMANDS.broadcast,
                                              stringArg1=message,
                                              ignoreCooldown=False)
            except ChatError as ex:
                self._processChatError(CHAT_ACTIONS.broadcast, channelId, ex)

        else:
            try:
                command, int64Arg, int16Arg, stringArg1, stringArg2 = parseCommandMessage(
                    message)
                self.__baseChannelChatCommand(channelId,
                                              command,
                                              int64Arg,
                                              int16Arg,
                                              stringArg1,
                                              stringArg2,
                                              ignoreCooldown=False)
            except ChatCommandError as ex:
                self._processChatError(CHAT_ACTIONS.userChatCommand, channelId,
                                       ex)

    def leaveChat(self, channelId):
        self.__baseChannelChatCommand(channelId,
                                      CHAT_COMMANDS.leaveChatChannel)

    def onChatActionFailure(self, actionData):
        MessengerEntry.g_instance.protos.BW.onChatActionFailure(actionData)

    def onChatAction(self, chatActionData):
        global g_replayCtrl
        if g_replayCtrl is None:
            import BattleReplay
            g_replayCtrl = BattleReplay.g_replayCtrl
        if g_replayCtrl.isRecording:
            g_replayCtrl.cancelSaveCurrMessage()
        elif g_replayCtrl.isPlaying:
            g_replayCtrl.onChatAction(chatActionData)
            return
        for processor in self.__dataProcessors:
            getattr(self, processor)(chatActionData)

        if CHAT_RESPONSES[
                chatActionData['actionResponse']] != CHAT_RESPONSES.success:
            self.onChatActionFailure(chatActionData)
        else:
            hanlerName = self.__actionHandlers.get(chatActionData['action'],
                                                   None)
            if hanlerName:
                getattr(self, hanlerName)(chatActionData)
            chId = chatActionData['channel']
            commonCallbacks = self.__getChatActionCallbacks(
                CHAT_ACTIONS[chatActionData['action']], 0)
            commonCallbacks(chatActionData)
            if chId != 0:
                channelCallbacks = self.__getChatActionCallbacks(
                    CHAT_ACTIONS[chatActionData['action']], chId)
                channelCallbacks(chatActionData)
        return

    def requestLastSysMessages(self):
        self.__baseChatCommand(CHAT_COMMANDS.requestLastSysMessages)

    def findUsers(self, userNamePattern, onlineMode=None, requestID=None):
        if onlineMode is None:
            searchMode = USER_SEARCH_MODE.ALL
        elif onlineMode:
            searchMode = USER_SEARCH_MODE.ONLINE
        else:
            searchMode = USER_SEARCH_MODE.OFFLINE
        self.__baseChatCommand(CHAT_COMMANDS.findUser,
                               int16Arg=searchMode,
                               stringArg1=userNamePattern,
                               requestID=requestID)
        return

    def requestUsersRoster(self, flags=0):
        self.__baseChatCommand(CHAT_COMMANDS.requestUsersRoster,
                               int16Arg=flags)

    def logVivoxLogin(self):
        self.__baseChatCommand(CHAT_COMMANDS.logVivoxLogin)

    def requestFriendStatus(self, friendID=-1):
        self.__baseChatCommand(CHAT_COMMANDS.requestFriendStatus,
                               int64Arg=friendID)

    def addFriend(self, friendID, friendName):
        self.__baseChatCommand(CHAT_COMMANDS.addFriend,
                               int64Arg=friendID,
                               stringArg1=friendName)

    def createPrivate(self, friendID, friendName):
        self.__baseChatCommand(CHAT_COMMANDS.createPrivate,
                               int64Arg=friendID,
                               stringArg1=friendName)

    def removeFriend(self, friendID):
        self.__baseChatCommand(CHAT_COMMANDS.removeFriend, int64Arg=friendID)

    def addIgnored(self, ignoredID, ignoredName):
        self.__baseChatCommand(CHAT_COMMANDS.addIgnored,
                               int64Arg=ignoredID,
                               stringArg1=ignoredName)

    def removeIgnored(self, ignoredID):
        self.__baseChatCommand(CHAT_COMMANDS.removeIgnored, int64Arg=ignoredID)

    def setMuted(self, mutedID, mutedName):
        self.__baseChatCommand(CHAT_COMMANDS.setMuted,
                               int64Arg=mutedID,
                               stringArg1=mutedName)

    def unsetMuted(self, mutedID):
        self.__baseChatCommand(CHAT_COMMANDS.unsetMuted, int64Arg=mutedID)

    def createPrebattleInvite(self,
                              receiverName,
                              auxText,
                              prebattleID,
                              prebattleType,
                              requestID=None):
        self.__baseInviteCommand(CHAT_COMMANDS.createInvite,
                                 INVITE_TYPES.PREBATTLE,
                                 receiverName,
                                 prebattleID,
                                 prebattleType,
                                 stringArg2=auxText,
                                 requestID=requestID)

    def createBarterInvite(self,
                           receiverName,
                           auxText,
                           itemID,
                           requestID=None):
        self.__baseInviteCommand(CHAT_COMMANDS.createInvite,
                                 INVITE_TYPES.BARTER,
                                 receiverName,
                                 itemID,
                                 stringArg2=auxText,
                                 requestID=requestID)

    def acceptPrebattleInvite(self, inviteID, requestID=None):
        if requestID is None:
            requestID = self.acquireRequestID()
        self.base.ackCommand(requestID, CHAT_COMMANDS.acceptInvite.index(),
                             time.time(), inviteID, -1)
        return

    def rejectInvite(self, inviteID, requestID=None):
        if requestID is None:
            requestID = self.acquireRequestID()
        self.base.ackCommand(requestID, CHAT_COMMANDS.rejectInvite.index(),
                             time.time(), inviteID, -1)
        return

    def getActiveInvites(self):
        self.__baseInviteCommand(CHAT_COMMANDS.getActiveInvites)

    def getArchiveInvites(self):
        self.__baseInviteCommand(CHAT_COMMANDS.getArchiveInvites)

    def requestVOIPCredentials(self, changePwd=0):
        self.__baseChatCommand(CHAT_COMMANDS.requestVOIPCredentials,
                               int16Arg=changePwd)

    def subscribeChatAction(self, callback, action, channelId=None):
        cbs = self.__getChatActionCallbacks(action, channelId)
        cbs += callback

    def unsubscribeChatAction(self, callback, action, channelId=None):
        cbs = self.__getChatActionCallbacks(action, channelId)
        cbs -= callback

    def setChatActionsCallbacks(self, callbacks):
        self.__chatActionCallbacks = callbacks

    def sendChannelChatCommand(self,
                               channelID,
                               command,
                               int64Arg=0,
                               int16Arg=0,
                               stringArg1='',
                               stringArg2=''):
        self.__baseChannelChatCommand(channelID, command, int64Arg, int16Arg,
                                      stringArg1, stringArg2)

    def _processChatError(self, action, channelId, chatError, requestID=-1):
        if isinstance(chatError, ChatError):
            actionData = chatError.messageArgs if chatError.messageArgs is not None else chatError.message
        else:
            actionData = ''
        chatAction = buildChatActionData(
            action=action,
            requestID=requestID,
            channelId=channelId,
            originatorNickName=self.name,
            data=actionData,
            actionResponse=chatError.response if isinstance(
                chatError, ChatError) else CHAT_RESPONSES.internalError)
        self.onChatAction(chatAction)
        return

    def __getChatActionCallbacks(self, action, channelId):
        channelId = channelId if channelId is not None else 0
        key = (action, channelId)
        if key not in self.__chatActionCallbacks:
            handlers = self.__chatActionCallbacks[key] = Event.Event()
        else:
            handlers = self.__chatActionCallbacks[key]
        return handlers

    def __receiveStreamedData(self, streamID, data):
        failed = False
        try:
            data = zlib.decompress(data)
            chatMessages = cPickle.loads(data)
        except:
            LOG_CURRENT_EXCEPTION()
            failed = True

        if not failed:
            chIds = sorted(chatMessages.keys(),
                           cmp=lambda x, y: cmp(abs(x), abs(y)))
            for chId in chIds:
                channelQueue = chatMessages.get(chId, deque())
                while True:
                    try:
                        actionData = channelQueue.popleft()
                        self.onChatAction(actionData)
                    except IndexError:
                        break

        self.__baseChatCommand(CHAT_COMMANDS.initAck,
                               int64Arg=streamID,
                               int16Arg=failed)

    def __baseChannelChatCommand(self,
                                 channelID,
                                 command,
                                 int64Arg=0,
                                 int16Arg=0,
                                 stringArg1='',
                                 stringArg2='',
                                 ignoreCooldown=True):
        if 0 == channelID:
            LOG_ERROR('Can`t execute chat channel command for channelId: %s' %
                      (channelID, ))
        else:
            if chat_shared.isOperationInCooldown(
                    chat_shared.g_chatCooldownData, command):
                if ignoreCooldown:
                    return
                raise ChatCommandInCooldown(command)
            self.__baseChatCommand(command, channelID, int64Arg, int16Arg,
                                   stringArg1, stringArg2)

    def __baseChatCommand(self,
                          command,
                          channelID=0,
                          int64Arg=0,
                          int16Arg=0,
                          stringArg1='',
                          stringArg2='',
                          ignoreCooldown=True,
                          requestID=None):
        if requestID is None:
            requestID = self.acquireRequestID()
        if chat_shared.isOperationInCooldown(chat_shared.g_chatCooldownData,
                                             command):
            if not ignoreCooldown:
                raise ChatCommandInCooldown(command)
        self.base.chatCommandFromClient(requestID, command.index(), channelID,
                                        int64Arg, int16Arg, stringArg1,
                                        stringArg2)
        return

    def __baseInviteCommand(self,
                            command,
                            inviteType=None,
                            receiverName='',
                            int64Arg=0,
                            int16Arg=0,
                            stringArg1='',
                            stringArg2='',
                            requestID=None):
        if requestID is None:
            requestID = self.acquireRequestID()
        self.base.inviteCommand(
            requestID, command.index(),
            inviteType.index() if inviteType is not None else -1, receiverName,
            int64Arg, int16Arg, stringArg1, stringArg2)
        return

    def __onReceiveInvite(self, chatActionData):
        inviteID = chatActionData['data'].get('id', None)
        receivedAt = chatActionData['data'].get('received_at', None)
        if inviteID is not None and receivedAt is None:
            requestID = self.acquireRequestID()
            self.base.ackCommand(requestID,
                                 CHAT_COMMANDS.inviteReceived.index(),
                                 time.time(), inviteID, -1)
        return

    def __dataTimeProcessor(self, actionData):
        actionData['time'] = tm.makeLocalServerTime(actionData['time'])
        actionData['sentTime'] = tm.makeLocalServerTime(actionData['sentTime'])

    def __inviteDataTimeProcessor(self, actionData):
        isInviteAction = CHAT_ACTIONS[actionData['action']] in (
            CHAT_ACTIONS.createInvite, CHAT_ACTIONS.receiveInvite,
            CHAT_ACTIONS.receiveArchiveInvite)
        if isInviteAction:
            if actionData.has_key('data'):
                inviteData = actionData['data']
                if 'sent_at' in inviteData:
                    inviteData['sent_at'] = tm.utcToLocalDatetime(
                        tm.makeLocalServerDatetime(inviteData['sent_at']))
                if 'received_at' in inviteData:
                    inviteData['received_at'] = tm.utcToLocalDatetime(
                        tm.makeLocalServerDatetime(inviteData['received_at']))
                if 'processed_at' in inviteData:
                    inviteData['processed_at'] = tm.utcToLocalDatetime(
                        tm.makeLocalServerDatetime(inviteData['processed_at']))

    def __systemMessageTimeProcessor(self, actionData):
        isSystemMessage = CHAT_ACTIONS[actionData['action']] in (
            CHAT_ACTIONS.personalSysMessage, CHAT_ACTIONS.sysMessage)
        if isSystemMessage:
            if actionData.has_key('data'):
                messageData = actionData['data']
                messageType = messageData['type']
                if 'created_at' in messageData:
                    messageData['created_at'] = tm.makeLocalServerDatetime(
                        messageData['created_at'])
                if 'finished_at' in messageData:
                    messageData['finished_at'] = tm.makeLocalServerDatetime(
                        messageData['finished_at'])
                if 'started_at' in messageData:
                    messageData['started_at'] = tm.makeLocalServerDatetime(
                        messageData['started_at'])
                if messageType == SYS_MESSAGE_TYPE.serverReboot.index():
                    messageData['data'] = tm.makeLocalServerDatetime(
                        messageData['data'])
                elif messageType == SYS_MESSAGE_TYPE.battleResults.index():
                    if 'arenaCreateTime' in messageData['data']:
                        messageData['data'][
                            'arenaCreateTime'] = tm.makeLocalServerTime(
                                messageData['data']['arenaCreateTime'])
                elif messageType == SYS_MESSAGE_TYPE.goldReceived.index():
                    messageData['data']['date'] = tm.makeLocalServerTime(
                        messageData['data']['date'])
                elif messageType in (
                        SYS_MESSAGE_TYPE.accountTypeChanged.index(),
                        SYS_MESSAGE_TYPE.premiumBought.index(),
                        SYS_MESSAGE_TYPE.premiumExtended.index(),
                        SYS_MESSAGE_TYPE.premiumExpired.index()):
                    if 'expiryTime' in messageData['data']:
                        messageData['data'][
                            'expiryTime'] = tm.makeLocalServerTime(
                                messageData['data']['expiryTime'])
Ejemplo n.º 10
0
class ServiceChannelManager(ChatActionsListener):
    def __init__(self):
        ChatActionsListener.__init__(self)
        self.__idGenerator = SequenceIDGenerator()
        self.__messages = deque([], SCH_MSGS_MAX_LENGTH)
        self.__unreadMessagesCount = 0

    def addListeners(self):
        self.addListener(self.onReceiveSysMessage, CHAT_ACTIONS.sysMessage)
        self.addListener(self.onReceivePersonalSysMessage, CHAT_ACTIONS.personalSysMessage)

    def clear(self):
        self.__messages.clear()
        self.__unreadMessagesCount = 0

    def switch(self, scope):
        if scope is MESSENGER_SCOPE.LOBBY:
            self.requestLastServiceMessages()

    def requestLastServiceMessages(self):
        BigWorld.player().requestLastSysMessages()

    def onReceiveSysMessage(self, chatAction):
        message = ServiceChannelMessage.fromChatAction(chatAction)
        self.__addServerMessage(message)

    def onReceivePersonalSysMessage(self, chatAction):
        message = ServiceChannelMessage.fromChatAction(chatAction, personal=True)
        self.__addServerMessage(message)

    def pushClientSysMessage(self, message, msgType, isAlert=False, priority=None):
        return self.__addClientMessage(
            message, SCH_CLIENT_MSG_TYPE.SYS_MSG_TYPE, isAlert=isAlert, auxData=[msgType.name(), priority]
        )

    def pushClientMessage(self, message, msgType, isAlert=False, auxData=None):
        return self.__addClientMessage(message, msgType, isAlert=isAlert, auxData=auxData)

    def getReadMessages(self):
        if self.__unreadMessagesCount > 0:
            messages = list(self.__messages)[: -self.__unreadMessagesCount]
        else:
            messages = self.__messages
        for clientID, message in messages:
            yield (clientID, message)

    def getMessage(self, clientID):
        mapping = dict(self.__messages)
        message = (False, None, None)
        if clientID in mapping:
            message = mapping[clientID]
        return message

    def getUnreadCount(self):
        return self.__unreadMessagesCount

    def resetUnreadCount(self):
        self.__unreadMessagesCount = 0

    def handleUnreadMessages(self):
        if not self.__unreadMessagesCount:
            return
        unread = list(self.__messages)[-self.__unreadMessagesCount :]
        serviceChannel = g_messengerEvents.serviceChannel
        for clientID, (isServerMsg, formatted, settings) in unread:
            if isServerMsg:
                serviceChannel.onServerMessageReceived(clientID, formatted, settings)
            else:
                serviceChannel.onClientMessageReceived(clientID, formatted, settings)

    @process
    def __addServerMessage(self, message):
        yield lambda callback: callback(True)
        formatter = collections_by_type.SERVER_FORMATTERS.get(message.type)
        serviceChannel = g_messengerEvents.serviceChannel
        serviceChannel.onChatMessageReceived(self.__idGenerator.next(), message)
        LOG_DEBUG("Server message received", message, formatter)
        if formatter:
            try:
                if formatter.isAsync():
                    formatted, settings = yield formatter.format(message)
                else:
                    formatted, settings = formatter.format(message)
            except:
                LOG_CURRENT_EXCEPTION()
                return

            if formatted:
                clientID = self.__idGenerator.next()
                self.__messages.append((clientID, (True, formatted, settings)))
                self.__unreadMessagesCount += 1
                serviceChannel.onServerMessageReceived(clientID, formatted, settings)
                customEvent = settings.getCustomEvent()
                if customEvent is not None:
                    serviceChannel.onCustomMessageDataReceived(clientID, customEvent)
            elif IS_DEVELOPMENT:
                LOG_WARNING("Not enough data to format. Action data : ", message)
        elif IS_DEVELOPMENT:
            LOG_WARNING("Formatter not found. Action data : ", message)
        return

    def __addClientMessage(self, message, msgType, isAlert=False, auxData=None):
        if auxData is None:
            auxData = []
        clientID = 0
        formatter = collections_by_type.CLIENT_FORMATTERS.get(msgType)
        if formatter:
            try:
                formatted, settings = formatter.format(message, auxData)
            except:
                LOG_CURRENT_EXCEPTION()
                return

            if formatted:
                clientID = self.__idGenerator.next()
                if not settings.isAlert:
                    settings.isAlert = isAlert
                self.__messages.append((clientID, (False, formatted, settings)))
                self.__unreadMessagesCount += 1
                g_messengerEvents.serviceChannel.onClientMessageReceived(clientID, formatted, settings)
            elif IS_DEVELOPMENT:
                LOG_WARNING("Not enough data to format. Action data : ", message)
        elif IS_DEVELOPMENT:
            LOG_WARNING("Formatter not found:", msgType, message)
        return clientID
Ejemplo n.º 11
0
class FortBattlesCache(object):
    __selectedID = 0

    def __init__(self, controller):
        self.__controller = weakref.proxy(controller)
        self.__idGen = SequenceIDGenerator()
        self.__cache = {}
        self.__idToIndex = {}
        self.__indexToID = {}
        self.__selectedUnit = None
        self.__isRequestInProcess = False
        return

    def __del__(self):
        LOG_DEBUG('Fort battles cache deleted:', self)

    def clear(self):
        self.__controller = None
        self.__cache.clear()
        self.__idToIndex.clear()
        self.__indexToID.clear()
        self.__selectedUnit = None
        return

    def start(self):
        fort = self.__controller.getFort()
        if fort:
            fort.onFortBattleChanged += self.__fort_onFortBattleChanged
            fort.onFortBattleRemoved += self.__fort_onFortBattleRemoved
            fort.onFortBattleUnitReceived += self.__fort_onFortBattleUnitReceived
            fort.onEnemyStateChanged += self.__fort_onEnemyStateChanged
            self.__cache = self.__buildCache()
        else:
            LOG_ERROR('Client fort is not found')

    def stop(self):
        fort = self.__controller.getFort()
        if fort:
            fort.onFortBattleChanged -= self.__fort_onFortBattleChanged
            fort.onFortBattleRemoved -= self.__fort_onFortBattleRemoved
            fort.onFortBattleUnitReceived -= self.__fort_onFortBattleUnitReceived
            fort.onEnemyStateChanged -= self.__fort_onEnemyStateChanged
        self.clear()

    @property
    def isRequestInProcess(self):
        return self.__isRequestInProcess

    @classmethod
    def getSelectedID(cls):
        return cls.__selectedID

    def getSelectedIdx(self):
        return self.__getClientIdx(self.getSelectedID())

    def clearSelectedID(self):
        self.__selectedUnit = None
        self._setSelectedID(0)
        return

    def setSelectedID(self, selectedID):
        if selectedID not in self.__cache:
            LOG_WARNING('Item is not found in cache', selectedID)
            return False
        else:
            self.__selectedUnit = None
            return self._setSelectedID(selectedID)

    def getItem(self, battleID):
        try:
            item, fortBattle = self.__cache[battleID]
        except KeyError:
            LOG_ERROR('Item not found in cache', battleID)
            item = None
            fortBattle = None

        return (item, fortBattle)

    def getUnitByIndex(self, index):
        unit = None
        if index in self.__indexToID:
            battleID = self.__indexToID[index]
            unit = self.__getUnit(battleID)
        return unit

    def getSelectedUnit(self):
        return self.__getUnit(self.getSelectedID())

    def getIterator(self):
        for item, battleItem in self.__cache.itervalues():
            if item.filter():
                yield (item, battleItem)

    @classmethod
    def _setSelectedID(cls, selectedID):
        result = False
        if selectedID != cls.__selectedID:
            cls.__selectedID = selectedID
            result = True
        return result

    @classmethod
    def _removeStoredData(cls):
        cls.__selectedID = (0, 0)

    def __buildCache(self):
        cache = {}
        fort = self.__controller.getFort()
        if not fort:
            LOG_WARNING('Client fort is not found')
            return cache
        fortBattles = fort.getAttacksAndDefencesIn(timePeriod=2 * time_utils.ONE_WEEK)
        selectedID = self.getSelectedID()
        found = False
        for item in fortBattles:
            battleID = item.getBattleID()
            if not found and battleID == selectedID:
                found = True
            battleItem = fort.getBattle(battleID)
            cache[battleID] = (item, battleItem)

        if not found:
            self.clearSelectedID()
        return cache

    def __updateItem(self, battleID, fort):
        item = fort.getBattleItemByBattleID(battleID)
        if item is None:
            LOG_ERROR('Fort battle is not found', battleID, fort.attacks, fort.defences)
            return (None, None)
        else:
            fortBattle = fort.getBattle(battleID)
            self.__cache[battleID] = (item, fortBattle)
            if self.getSelectedID() == battleID:
                self.__selectedUnit = None
            return (item, fortBattle)

    def __requestCallback(self, _):
        self.__isRequestInProcess = False

    def __removeItem(self, battleID):
        result = False
        if battleID in self.__cache:
            self.__cache.pop(battleID)
            result = True
        if self.getSelectedID() == battleID:
            self.clearSelectedID()
        clientIdx = self.__idToIndex.pop(battleID, None)
        if clientIdx is not None:
            self.__indexToID.pop(clientIdx, None)
        return result

    def __getClientIdx(self, battleID):
        if battleID == 0:
            return 0
        if battleID not in self.__idToIndex:
            clientIdx = self.__idGen.next()
            self.__idToIndex[battleID] = clientIdx
            self.__indexToID[clientIdx] = battleID
        else:
            clientIdx = self.__idToIndex[battleID]
        return clientIdx

    def __getUnit(self, battleID):
        fort = self.__controller.getFort()
        if not fort:
            LOG_WARNING('Client fort is not found')
            return
        else:
            isSelected = battleID == self.getSelectedID()
            if isSelected and self.__selectedUnit is not None:
                return self.__selectedUnit
            unit = fort.getFortBattleUnit(battleID)
            if isSelected:
                self.__selectedUnit = unit
            return unit

    def __fort_onEnemyStateChanged(self, battleID, isReady):
        fort = self.__controller.getFort()
        if fort:
            item, battleItem = self.__updateItem(battleID, fort)
            if item:
                self.__controller._listeners.notify('onFortBattleChanged', self, item, battleItem)

    def __fort_onFortBattleChanged(self, battleID):
        fort = self.__controller.getFort()
        if fort:
            item, battleItem = self.__updateItem(battleID, fort)
            if item:
                self.__controller._listeners.notify('onFortBattleChanged', self, item, battleItem)

    def __fort_onFortBattleRemoved(self, battleID):
        if self.__removeItem(battleID):
            self.__controller._listeners.notify('onFortBattleRemoved', self, battleID)

    def __fort_onFortBattleUnitReceived(self, battleID):
        fort = self.__controller.getFort()
        if fort:
            if self.__selectedID == battleID:
                self.__selectedUnit = None
            self.__controller._listeners.notify('onFortBattleUnitReceived', self.__getClientIdx(battleID))
        return
Ejemplo n.º 12
0
class ServiceChannelManager(ChatActionsListener):
    def __init__(self):
        ChatActionsListener.__init__(self)
        self.__idGenerator = SequenceIDGenerator()
        self.__messages = deque([], SCH_MSGS_MAX_LENGTH)
        self.__unreadMessagesCount = 0

    def addListeners(self):
        self.addListener(self.onReceiveSysMessage, CHAT_ACTIONS.sysMessage)
        self.addListener(self.onReceivePersonalSysMessage,
                         CHAT_ACTIONS.personalSysMessage)

    def clear(self):
        self.__messages.clear()
        self.__unreadMessagesCount = 0

    def switch(self, scope):
        if scope is MESSENGER_SCOPE.LOBBY:
            self.requestLastServiceMessages()

    def requestLastServiceMessages(self):
        BigWorld.player().requestLastSysMessages()

    def onReceiveSysMessage(self, chatAction):
        message = ServiceChannelMessage.fromChatAction(chatAction)
        self.__addServerMessage(message)

    def onReceivePersonalSysMessage(self, chatAction):
        message = ServiceChannelMessage.fromChatAction(chatAction,
                                                       personal=True)
        self.__addServerMessage(message)

    def pushClientSysMessage(self,
                             message,
                             msgType,
                             isAlert=False,
                             priority=None,
                             messageData=None):
        return self.__addClientMessage(
            message,
            SCH_CLIENT_MSG_TYPE.SYS_MSG_TYPE,
            isAlert=isAlert,
            auxData=[msgType.name(), priority, messageData])

    def pushClientMessage(self, message, msgType, isAlert=False, auxData=None):
        return self.__addClientMessage(message,
                                       msgType,
                                       isAlert=isAlert,
                                       auxData=auxData)

    def getReadMessages(self):
        if self.__unreadMessagesCount > 0:
            messages = list(self.__messages)[:-self.__unreadMessagesCount]
        else:
            messages = self.__messages
        for clientID, message in messages:
            yield (clientID, message)

    def getMessage(self, clientID):
        mapping = dict(self.__messages)
        message = (False, None, None)
        if clientID in mapping:
            message = mapping[clientID]
        return message

    def getUnreadCount(self):
        return self.__unreadMessagesCount

    def resetUnreadCount(self):
        self.__unreadMessagesCount = 0

    def handleUnreadMessages(self):
        if not self.__unreadMessagesCount:
            return
        unread = list(self.__messages)[-self.__unreadMessagesCount:]
        for clientID, (isServerMsg, formatted, settings) in unread:
            self._handleUnreadMessage(isServerMsg, clientID, formatted,
                                      settings)

    def _handleUnreadMessage(self, isServerMsg, clientID, formatted, settings):
        serviceChannel = g_messengerEvents.serviceChannel
        if isServerMsg:
            serviceChannel.onServerMessageReceived(clientID, formatted,
                                                   settings)
        else:
            serviceChannel.onClientMessageReceived(clientID, formatted,
                                                   settings)

    @process
    def __addServerMessage(self, message):
        yield lambda callback: callback(True)
        formatter = collections_by_type.SERVER_FORMATTERS.get(message.type)
        serviceChannel = g_messengerEvents.serviceChannel
        serviceChannel.onChatMessageReceived(self.__idGenerator.next(),
                                             message)
        LOG_DEBUG('Server message received', message, formatter)
        if formatter:
            try:
                if formatter.isAsync():
                    messagesListData = yield formatter.format(message)
                else:
                    messagesListData = formatter.format(message)
            except:
                LOG_CURRENT_EXCEPTION()
                return

            for mData in messagesListData:
                if mData.data:
                    formatted, settings = mData
                    clientID = self.__idGenerator.next()
                    self.__messages.append(
                        (clientID, (True, formatted, settings)))
                    self.__unreadMessagesCount += 1
                    serviceChannel.onServerMessageReceived(
                        clientID, formatted, settings)
                    customEvent = settings.getCustomEvent()
                    if customEvent is not None:
                        serviceChannel.onCustomMessageDataReceived(
                            clientID, customEvent)
                elif not formatter.canBeEmpty() and IS_DEVELOPMENT:
                    LOG_WARNING('Not enough data to format. Action data : ',
                                message)

        elif IS_DEVELOPMENT:
            LOG_WARNING('Formatter not found. Action data : ', message)
        return

    def __addClientMessage(self,
                           message,
                           msgType,
                           isAlert=False,
                           auxData=None):
        if auxData is None:
            auxData = []
        clientID = 0
        formatter = collections_by_type.CLIENT_FORMATTERS.get(msgType)
        if formatter:
            try:
                messagesListData = formatter.format(message, auxData)
            except:
                LOG_CURRENT_EXCEPTION()
                return

            for mData in messagesListData:
                if mData.data:
                    formatted, settings = mData
                    clientID = self.__idGenerator.next()
                    if not settings.isAlert:
                        settings.isAlert = isAlert
                    self.__messages.append(
                        (clientID, (False, formatted, settings)))
                    self.__unreadMessagesCount += 1
                    g_messengerEvents.serviceChannel.onClientMessageReceived(
                        clientID, formatted, settings)
                elif IS_DEVELOPMENT:
                    LOG_WARNING('Not enough data to format. Action data : ',
                                message)

        elif IS_DEVELOPMENT:
            LOG_WARNING('Formatter not found:', msgType, message)
        return clientID
Ejemplo n.º 13
0
class XmppPlugin(IProtoPlugin):
    DISCONNECT_BY_REQUEST = 0
    DISCONNECT_AUTHENTICATION = 1
    DISCONNECT_OTHER_ERROR = 2
    USE_MOCK_DATA = False
    ALLOWED_ROSTER_ACTIONS = [USER_ROSTER_ACTION.AddToFriend,
     USER_ROSTER_ACTION.AddToIgnored,
     USER_ROSTER_ACTION.RemoveFromFriend,
     USER_ROSTER_ACTION.RemoveFromIgnored]

    def __init__(self):
        self.__client = BigWorld.XmppClient()
        self.__currentUser = None
        self.__xmppRoster = None
        self.__usersMgr = None
        self.__model = None
        self.__bwRoster = None
        self.__reconnectCount = 0
        self.__reconnectCallbackId = None
        self.__bwConnected = False
        self.__isEnabled = False
        self.__idsGen = SequenceIDGenerator()
        self.__pendingBattleMode = None
        self.__databaseID = None
        return

    @storage_getter('users')
    def usersStorage(self):
        return None

    @property
    def isConnected(self):
        """
        Shows current XMPP connection status
        """
        if self.__model is not None:
            return self.__model.isConnected
        else:
            return False

    def logState(self):
        if self.__isEnabled:
            if self.__model is not None and self.__model.isConnected:
                itemsStrList = ['XMPP:logState - XMPP is connected. Logging XMPP roster state:']
                itemsStrList.append('Curr.User JID: {0}  Status: {1}'.format(self.__currentUser.bareJid, self.__currentUser.getPresenceStr(self.__currentUser.presence)))
                for jid, item in self.__xmppRoster.items():
                    itemsStrList.append('Contact   JID: {0}  Status: {1}  Name: {2}'.format(jid, item.getPresenceStr(item.presence), item.name))

                LOG_DEBUG('\n'.join(itemsStrList))
            else:
                LOG_DEBUG('XMPP:logState - XMPP is not connected yet. Try to run your command later')
        else:
            LOG_DEBUG('XMPP:logState - You are not logged in or connection to XMPP is disabled by server settings')
        return

    def connect(self, scope = None):
        if scope is not None:
            self._setBattleMode(scope)
        if self.isConnected:
            return
        else:
            self.__bwConnected = True
            self._cancelReconnectCallback()
            settings = self._getServerSettings()
            if settings.get('xmpp_enabled', False):
                self.__isEnabled = bool(int(settings.get('jdCutouts', 0)))
                if self.__isEnabled:
                    self._subscribeToActions()
                    LOG_DEBUG('XMPP:connect - XMPP functionality is enabled. Starting connection to XMPP server')
                    if self.__model is None:
                        self.__model = XmppConnectionModel(settings.get('xmpp_host'), settings.get('xmpp_port'), settings.get('xmpp_resource'), False, None, None)
                    else:
                        self.__model = self.__model._replace(host=settings.get('xmpp_host'), port=settings.get('xmpp_port'), resourceName=settings.get('xmpp_resource'), isConnected=False)
                    if self.__model.host is None:
                        raise Exception, 'XMPP: server xmpp_host is not defined'
                    connections = settings.get('xmpp_connections', [])
                    if len(connections) > 0:
                        self.__model = self.__model._replace(connection=random.choice(connections))
                    else:
                        self.__model = self.__model._replace(connection=(self.__model.host, self.__model.port))
                        LOG_DEBUG('XMPP:connect - no xmpp_connections are passed - using default connection', self.__model.connection)
                    if self.__model.token is None:
                        Account.g_accountRepository and Account.g_accountRepository.onChatTokenReceived.clear()
                        Account.g_accountRepository.onChatTokenReceived += self._tokenCallback
                    BigWorld.player().requestChatToken(self.__idsGen.next())
                else:
                    LOG_DEBUG('XMPP:connect - trying to connect using token from previous connection')
                    self._tokenCallback(cPickle.dumps({'error': None,
                     'token': self.__model.token,
                     'databaseID': self.__databaseID}))
            else:
                LOG_DEBUG('XMPP:connect - XMPP functionality is disabled. Stopping execution')
            return

    def disconnect(self):
        LOG_DEBUG('XMPP:disconnect')
        if Account.g_accountRepository:
            Account.g_accountRepository.onChatTokenReceived.clear()
        self.__bwConnected = False
        if self.isConnected:
            self.__client.disconnect()
        else:
            self.onDisconnect()

    def onConnect(self):
        """
        Called after successful connection, encryption setup and authentication.
        """
        LOG_DEBUG('XMPP:onConnect - Successfully connected to XMPP server')
        self.__model = self.__model._replace(isConnected=True)
        self.__reconnectCount = 0
        self._cancelReconnectCallback()
        if self.__pendingBattleMode is not None:
            self._setBattleMode(self.__pendingBattleMode)
            self.__pendingBattleMode = None
        self._doRostersSync()
        return

    def onDisconnect(self, reason = DISCONNECT_BY_REQUEST, description = None):
        """
        Called if connection is closed or attempt to connect is failed.
        Additional description (in English) of disconnect reason is given. If
        description is empty then disconnect was caused by user (i.e. by
        explicit call to disconnect()).
        """
        LOG_DEBUG('XMPP:onDisconnect - Disconnected', reason, description)
        self._cancelReconnectCallback()
        if reason == self.DISCONNECT_AUTHENTICATION:
            self.__model = self.__model._replace(token=None)
        if self.__bwConnected:
            if self.__isEnabled:
                self.__model = self.__model._replace(isConnected=False)
                self.__reconnectCount += 1
                reconnectDelay = max(random.random() * 2 * self.__reconnectCount, 10.0)
                self.__reconnectCallbackId = BigWorld.callback(reconnectDelay, self.connect)
                LOG_DEBUG('XMPP:onDisconnect - will try to reconnect in {0} seconds'.format(reconnectDelay), description)
        else:
            if self.__isEnabled:
                self._unsubscribeFromActions()
            self.__client.xmppHandler = None
            self.__currentUser = None
            self.__xmppRoster = None
            self.__model = None
            self.__bwRoster = None
            self.__isEnabled = False
            self.__reconnectCount = 0
            self.__databaseID = None
        return

    def onNewRosterItem(self, bareJid, name, groups, subscriptionTo, subscriptionFrom):
        """
        Called when the contact is changed or added.
        
        name is custom contact name chosen by user.
        
        groups is set of groups (strings) which contact belongs to.
        
        subscriptionTo is presence subscription state in direction "contact
        TO user". One of SUBSCRIPTION_* values is used.
        
        subscriptionFrom is presence subscription state in direction "FROM user
        to contact". Either SUBSCRIPTION_ON or SUBSCRIPTION_OFF is used here.
        See onSubscribe() event.
        """
        LOG_DEBUG('XMPP:onNewRosterItem - New roster item added', bareJid, name)
        if self.__bwRoster is not None:
            if bareJid in self.__bwRoster:
                self._addToLocalXmppRoster(bareJid, name, groups, subscriptionTo, subscriptionFrom)
            else:
                self._doXmppRosterAction(bareJid, USER_ROSTER_ACTION.RemoveFromFriend)
        else:
            self._addToLocalXmppRoster(bareJid, name, groups, subscriptionTo, subscriptionFrom)
        return

    def onRosterItemRemove(self, bareJid):
        """
        Called when the contact is removed.
        """
        LOG_DEBUG('XMPP:onRosterItemRemove', bareJid)
        if self.__bwRoster is not None:
            if bareJid not in self.__bwRoster:
                self._removeFromLocalXmppRoster(bareJid)
            else:
                user = self.__bwRoster[bareJid]
                action = USER_ROSTER_ACTION.AddToFriend if bool(user.getRoster() & USERS_ROSTER_FRIEND) else USER_ROSTER_ACTION.AddToIgnored
                self._doXmppRosterAction(bareJid, action, user.getName())
        else:
            self._removeFromLocalXmppRoster(bareJid)
        return

    def onNewRosterResource(self, fullJid, priority, status, presence):
        """
        Called when contact resource is changed or added.
        
        You should compare fullJid of resource with fullJid of client to
        determine if this resource change is actually server acknowledgement of
        user presence change.
        
        Exact value of resource priority depends solely on contact's choice.
        
        status can be arbitrary text.
        
        Resource presence is defined by one of PRESENCE_* values.
        """
        LOG_DEBUG('XMPP:onNewRosterResource', fullJid, priority, status, presence)
        fullJidParts = fullJid.split('/')
        if len(fullJidParts) > 1:
            bareJid, resourceName = fullJidParts[0:2]
            if fullJid != self.__client.fullJid:
                if bareJid not in self.__xmppRoster:
                    self.__xmppRoster[bareJid] = RosterItem(bareJid)
                self.__xmppRoster[bareJid].updateResource(resourceName, priority, status, presence)
            else:
                self.__currentUser.updateResource(resourceName, priority, status, presence)

    def onRosterResourceRemove(self, fullJid):
        """
        Called when contact resource is removed (i.e. contact has gone offline).
        """
        LOG_DEBUG('XMPP:onRosterResourceRemove', fullJid)
        fullJidParts = fullJid.split('/')
        if len(fullJidParts) > 1:
            bareJid, resourceName = fullJidParts[0:2]
            if fullJid != self.__client.fullJid:
                if bareJid in self.__xmppRoster:
                    self.__xmppRoster[bareJid].removeResource(resourceName)
            else:
                self.__currentUser.removeResource(resourceName)

    def onSubscribe(self, bareJid, message):
        """
        Called when a contact (from roster or not) asks for subscription to user
        status updates.
        
        Call setSubscribed() or setUnsubscribed() to allow or disallow sending
        user status updates to the contact. Roster item will be automatically
        updated by onNewRosterItem event.
        
        Note that transition of subscriptionFrom attribute of contact from
        SUBSCRIPTION_OFF state to SUBSCRIPTION_PENDING state should be done
        manually in this callback. This event shouldn't be generated if
        subscriptionFrom is SUBSCRIPTION_ON, however it's possible.
        """
        LOG_DEBUG('XMPP:onSubscribe - Subscription request received', bareJid, message)
        self.__client.setSubscribed(bareJid)

    def _subscribeToActions(self):
        """
        Adds subscription to UsersManager events
        """
        self.__usersMgr = g_messengerEvents.users
        self.__usersMgr.onUsersRosterReceived += self._onRosterReceived
        self.__usersMgr.onUserRosterChanged += self._onRosterUpdate

    def _unsubscribeFromActions(self):
        """
        Removes subscription to UsersManager events
        """
        if self.__usersMgr:
            self.__usersMgr.onUsersRosterReceived -= self._onRosterReceived
            self.__usersMgr.onUserRosterChanged -= self._onRosterUpdate
            self.__usersMgr = None
        return

    def _getServerSettings(self):
        """
        Gets server setting values
        """
        if self.USE_MOCK_DATA:
            settings = {'jdCutouts': 1,
             'xmpp_connections': [('jbr-wowpkis11.pershastudia.org', 5222)],
             'xmpp_host': 'jbr-wowpkis11.pershastudia.org',
             'xmpp_port': 5222,
             'xmpp_resource': 'wot',
             'xmpp_enabled': True}
        elif Account.g_accountRepository:
            settings = Account.g_accountRepository.serverSettings
        else:
            settings = {'jdCutouts': 0,
             'xmpp_enabled': False}
        return settings

    def _tokenCallback(self, data):
        """
        Callback for PlayerAccount.requestChatToken method call
        """
        data = cPickle.loads(data)
        errorStr = data.get('error', None)
        if errorStr is None:
            self.__model = self.__model._replace(token=data.get('token'))
            self.__databaseID = data.get('databaseID')
            host, port = self.__model.connection
            if self.USE_MOCK_DATA:
                bareJid = '{0}@{1}'.format('admin1', self.__model.host)
            else:
                bareJid = '{0}@{1}'.format(self.__databaseID, self.__model.host)
            fullJid = '{0}/{1}'.format(bareJid, self.__model.resourceName)
            self.__currentUser = RosterItem(bareJid, 'Self', [], BigWorld.XmppClient.SUBSCRIPTION_OFF, BigWorld.XmppClient.SUBSCRIPTION_OFF)
            LOG_DEBUG('XMPP:_tokenCallback - Token received - connecting to XMPP server', fullJid, self.__model.token, host, port)
            self.__client.xmppHandler = self
            self.__xmppRoster = {}
            self.__client.connect(fullJid, str(self.__model.token), host, port)
        else:
            self.onDisconnect()
            LOG_ERROR('XMPP:_tokenCallback - Error while getting XMPP connection token', errorStr)
        return

    def _cancelReconnectCallback(self):
        try:
            if self.__reconnectCallbackId is not None:
                BigWorld.cancelCallback(self.__reconnectCallbackId)
        except:
            pass
        finally:
            self.__reconnectCallbackId = None

        return

    def _onRosterReceived(self):
        """
        Listener for UsersManager.onUsersRosterReceived
        """
        self.__bwRoster = {}
        contacts = self.usersStorage.all()
        LOG_DEBUG('XMPP:_onRosterReceived - BW rooster received', contacts)
        for user in contacts:
            if user.isCurrentPlayer():
                continue
            if self.USE_MOCK_DATA:
                bareJid = '{0}@{1}'.format('admin2', self.__model.host)
            else:
                bareJid = '{0}@{1}'.format(user.getID(), self.__model.host)
            self.__bwRoster[bareJid] = user

        self._doRostersSync()

    def _onRosterUpdate(self, action, user):
        """
        Listener for UsersManager.onUsersRosterUpdate
        """
        if action in self.ALLOWED_ROSTER_ACTIONS:
            if self.USE_MOCK_DATA:
                bareJid = '{0}@{1}'.format('admin2', self.__model.host)
            else:
                bareJid = '{0}@{1}'.format(user.getID(), self.__model.host)
            LOG_DEBUG('XMPP:_onRosterUpdate - BW rooster update', action, user)
            if action in [USER_ROSTER_ACTION.AddToFriend, USER_ROSTER_ACTION.AddToIgnored]:
                self.__bwRoster[bareJid] = user
            elif bareJid in self.__bwRoster:
                del self.__bwRoster[bareJid]
            self._doXmppRosterAction(bareJid, action, user.getName())

    def _doRostersSync(self):
        """
        Performs XMPP roster synchronization with BW roster (BW is Master)
        """
        if self.__bwRoster is not None and self.isConnected:
            bwJidSet = set(self.__bwRoster)
            xmppJidSet = set(self.__xmppRoster)
            LOG_DEBUG('XMPP:_doRostersSync - Syncing BW and XMPP rosters')
            LOG_DEBUG('XMPP:_doRostersSync - BW roster', bwJidSet)
            LOG_DEBUG('XMPP:_doRostersSync - XMPP roster', xmppJidSet)
            toRemove = xmppJidSet - bwJidSet
            toAdd = bwJidSet - xmppJidSet
            for jid in toRemove:
                self._doXmppRosterAction(jid, USER_ROSTER_ACTION.RemoveFromFriend)

            for jid in toAdd:
                user = self.__bwRoster[jid]
                action = USER_ROSTER_ACTION.AddToFriend if bool(user.getRoster() & USERS_ROSTER_FRIEND) else USER_ROSTER_ACTION.AddToIgnored
                self._doXmppRosterAction(jid, action, user.getName())

        return

    def _addToLocalXmppRoster(self, bareJid, name, groups, subscriptionTo, subscriptionFrom):
        """
        Adds new item to local XMPP roster
        """
        if bareJid in self.__xmppRoster:
            LOG_DEBUG('XMPP:_addToLocalXmppRoster - Updating item in local XMPP roster', bareJid, name, groups, subscriptionTo, subscriptionFrom)
            item = self.__xmppRoster.get(bareJid)
            item.name, item.groups, item.subscriptionTo, item.subscriptionFrom = (name,
             groups,
             subscriptionTo,
             subscriptionFrom)
        else:
            LOG_DEBUG('XMPP:_addToLocalXmppRoster - Adding item to local XMPP roster', bareJid, name, groups, subscriptionTo, subscriptionFrom)
            self.__xmppRoster[bareJid] = RosterItem(bareJid, name, groups, subscriptionTo, subscriptionFrom)

    def _removeFromLocalXmppRoster(self, bareJid):
        """
        Removes item from local XMPP roster
        """
        LOG_DEBUG('XMPP:_removeFromLocalXmppRoster - Roster item is removed from local XMPP roster', bareJid, self.__xmppRoster[bareJid].name)
        del self.__xmppRoster[bareJid]

    def _doXmppRosterAction(self, bareJid, action, userName = '******'):
        """
        Triggers needed roster action with XMPP chat server basing on passes action type
        """
        if action in [USER_ROSTER_ACTION.AddToFriend, USER_ROSTER_ACTION.AddToIgnored]:
            LOG_DEBUG('XMPP:_doXmppRosterAction - adding user from BW rooster to XMPP roster', bareJid, userName)
            self.__client.add(bareJid, userName)
            self.__client.subscribe(bareJid)
        elif action in [USER_ROSTER_ACTION.RemoveFromFriend, USER_ROSTER_ACTION.RemoveFromIgnored]:
            LOG_DEBUG('XMPP:_doXmppRosterAction - user is removed from BW rooster. Removing from XMPP roster', bareJid)
            self.__client.remove(bareJid)
            self.__client.unsubscribe(bareJid)

    def _setBattleMode(self, mode):
        LOG_DEBUG('XMPP:_setBattleMode', mode)
        if self.isConnected:
            self.__client.presence = BigWorld.XmppClient.PRESENCE_DND if mode == MESSENGER_SCOPE.BATTLE else BigWorld.XmppClient.PRESENCE_AVAILABLE
        else:
            self.__pendingBattleMode = mode
            self.onDisconnect()
Ejemplo n.º 14
0
class InvitesManager(object):
    __clanInfo = None

    def __init__(self):
        from gui.prb_control.formatters.invites import PrbInviteLinkFormatter
        self.__linkFormatter = PrbInviteLinkFormatter()
        self._IDGen = SequenceIDGenerator()
        self._IDMap = {'inviteIDs': {},
         'prbIDs': {}}
        self.__receivedInvites = {}
        self.__unreadInvitesCount = 0
        self.__eventManager = Event.EventManager()
        self.__acceptChain = None
        self.onReceivedInviteListInited = Event.Event(self.__eventManager)
        self.onReceivedInviteListModified = Event.Event(self.__eventManager)
        return

    def init(self):
        self.__isUsersRostersInited = False
        self.__isInvitesListBuild = False
        g_messengerEvents.users.onUsersRosterReceived += self.__me_onUsersRosterReceived
        g_playerEvents.onPrebattleInvitesChanged += self.__pe_onPrebattleInvitesChanged

    def fini(self):
        self.__clearAcceptChain()
        self.__isUsersRostersInited = False
        self.__isInvitesListBuild = False
        g_messengerEvents.users.onUsersRosterReceived += self.__me_onUsersRosterReceived
        g_playerEvents.onPrebattleInvitesChanged -= self.__pe_onPrebattleInvitesChanged
        self.clear()

    def clear(self):
        self.__isUsersRostersInited = False
        self.__isInvitesListBuild = False
        self.__receivedInvites.clear()
        self.__unreadInvitesCount = 0
        self._IDMap = {'inviteIDs': {},
         'prbIDs': {}}
        self.__eventManager.clear()

    @process
    def onAccountShowGUI(self):
        clanInfo = yield StatsRequester().getClanInfo()
        self._setClanInfo(clanInfo)
        g_clientUpdateManager.addCallbacks({'stats.clanInfo': self._setClanInfo})

    def onAvatarBecomePlayer(self):
        g_clientUpdateManager.removeObjectCallbacks(self)
        self.__clearAcceptChain()

    @storage_getter('users')
    def users(self):
        return None

    def isInited(self):
        return self.__isUsersRostersInited and self.__isInvitesListBuild

    def acceptInvite(self, inviteID, postActions = None):
        try:
            prebattleID, peripheryID = self._IDMap['inviteIDs'][inviteID]
        except KeyError:
            LOG_ERROR('Invite ID is invalid', inviteID, self._IDMap)
            return

        self.__clearAcceptChain()
        if not postActions:
            self._doAccept(prebattleID, peripheryID)
        else:
            self.__acceptChain = _AcceptInvitesPostActions(peripheryID, prebattleID, postActions)
            self.__acceptChain.onStopped += self.__accept_onPostActionsStopped
            self.__acceptChain.start()
        if self.__unreadInvitesCount > 0:
            self.__unreadInvitesCount -= 1

    def declineInvite(self, inviteID):
        try:
            prebattleID, peripheryID = self._IDMap['inviteIDs'][inviteID]
        except KeyError:
            LOG_ERROR('Invite ID is invalid', inviteID, self._IDMap)
            return

        BigWorld.player().prb_declineInvite(prebattleID, peripheryID)
        if self.__unreadInvitesCount > 0:
            self.__unreadInvitesCount -= 1

    def canAcceptInvite(self, invite):
        result = False
        if invite.id in self.__receivedInvites:
            from gui.prb_control.dispatcher import g_prbLoader
            dispatcher = g_prbLoader.getDispatcher()
            if dispatcher:
                prbFunctional = dispatcher.getPrbFunctional()
                unitFunctional = dispatcher.getUnitFunctional()
                return (prbFunctional and prbFunctional.hasLockedState() or unitFunctional and unitFunctional.hasLockedState()) and False
        another = invite.anotherPeriphery
        if another:
            if g_preDefinedHosts.periphery(invite.peripheryID) is None:
                LOG_ERROR('Periphery not found')
                result = False
            elif g_lobbyContext.getCredentials() is None:
                LOG_ERROR('Login info not found')
                result = False
            elif g_preDefinedHosts.isRoamingPeriphery(invite.peripheryID) and not isRoamingEnabled(g_itemsCache.items.stats.attributes):
                LOG_ERROR('Roaming is not supported')
                result = False
            elif invite.id > 0:
                result = invite.isActive()
            else:
                result = invite.id > 0 and invite.isActive()
        return result

    def canDeclineInvite(self, invite):
        result = False
        if invite.id in self.__receivedInvites:
            result = invite.id > 0 and invite.isActive()
        return result

    def getInviteInfo(self, inviteID):
        try:
            prebattleID, peripheryID = self._IDMap['inviteIDs'][inviteID]
            return (prebattleID, peripheryID)
        except KeyError:
            return (0, 0)

    def getReceivedInviteCount(self):
        return len(self.__receivedInvites)

    def getReceivedInvite(self, inviteID):
        return self.__receivedInvites.get(inviteID)

    def getReceivedInvites(self, IDs = None):
        result = self.__receivedInvites.values()
        if IDs is not None:
            result = filter(lambda item: item[0].id in IDs, result)
        return result

    def getUnreadCount(self):
        return self.__unreadInvitesCount

    def resetUnreadCount(self):
        self.__unreadInvitesCount = 0

    def _doAccept(self, prebattleID, peripheryID):
        if connectionManager.peripheryID == peripheryID:
            BigWorld.player().prb_acceptInvite(prebattleID, peripheryID)
        else:
            LOG_ERROR('Invalid periphery', (prebattleID, peripheryID), connectionManager.peripheryID)

    def _makeInviteID(self, prebattleID, peripheryID):
        inviteID = self._IDMap['prbIDs'].get((prebattleID, peripheryID))
        if inviteID is None:
            inviteID = self._IDGen.next()
            self._IDMap['inviteIDs'][inviteID] = (prebattleID, peripheryID)
            self._IDMap['prbIDs'][prebattleID, peripheryID] = inviteID
        return inviteID

    def _addInvite(self, invite, userGetter):
        if g_settings.userPrefs.invitesFromFriendsOnly:
            user = userGetter(invite.creatorDBID)
            if user is None or not user.isFriend():
                LOG_DEBUG('Invite to be ignored:', invite)
                return False
        link = self.__linkFormatter.format(invite)
        if not len(link):
            if constants.IS_DEVELOPMENT:
                LOG_WARNING('Formatter not found. Invite data : ', invite)
            return False
        else:
            self.__receivedInvites[invite.id] = (invite, link)
            if invite.isActive():
                self.__unreadInvitesCount += 1
            return True

    def _updateInvite(self, other, userGetter):
        inviteID = other.id
        invite, _ = self.__receivedInvites[inviteID]
        if other.isActive() and g_settings.userPrefs.invitesFromFriendsOnly:
            user = userGetter(invite.creatorDBID)
            if user is None or not user.isFriend():
                LOG_DEBUG('Invite to be ignored:', invite)
                return False
        prevCount = invite.count
        invite = invite._merge(other)
        link = self.__linkFormatter.format(invite)
        self.__receivedInvites[inviteID] = (invite, link)
        if invite.isActive() and prevCount < invite.count:
            self.__unreadInvitesCount += 1
        return True

    def _delInvite(self, inviteID):
        result = inviteID in self.__receivedInvites
        if result:
            self.__receivedInvites.pop(inviteID)
        return result

    def _buildReceivedInvitesList(self, invitesData):
        self.__isInvitesListBuild = True
        self.__receivedInvites.clear()
        self.__unreadInvitesCount = 0
        receiver = BigWorld.player().name
        receiverDBID = getPlayerDatabaseID()
        receiverClanAbbrev = g_lobbyContext.getClanAbbrev(self.__clanInfo)
        userGetter = self.users.getUser
        for (prebattleID, peripheryID), data in invitesData.iteritems():
            inviteID = self._makeInviteID(prebattleID, peripheryID)
            invite = PrbInviteWrapper(id=inviteID, receiver=receiver, receiverDBID=receiverDBID, receiverClanAbbrev=receiverClanAbbrev, peripheryID=peripheryID, **data)
            self._addInvite(invite, userGetter)

    def _setClanInfo(self, clanInfo):
        self.__clanInfo = clanInfo
        if not self.__isUsersRostersInited:
            return
        receiverClanAbbrev = g_lobbyContext.getClanAbbrev(self.__clanInfo)
        changed = []
        for inviteID, (invite, _) in self.__receivedInvites.iteritems():
            if invite.receiverClanAbbrev != receiverClanAbbrev:
                invite = invite._replace(receiverClanAbbrev=receiverClanAbbrev)
                link = self.__linkFormatter.format(invite)
                self.__receivedInvites[inviteID] = (invite, link)
                changed.append(inviteID)

        if len(changed) > 0:
            self.onReceivedInviteListModified([], changed, [])

    def __clearAcceptChain(self):
        if self.__acceptChain is not None:
            self.__acceptChain.onStopped -= self.__accept_onPostActionsStopped
            self.__acceptChain.stop()
            self.__acceptChain = None
        return

    def __me_onUsersRosterReceived(self):
        if not self.__isUsersRostersInited:
            invitesData = getattr(BigWorld.player(), 'prebattleInvites', {})
            LOG_DEBUG('Users roster received, list of invites is available', invitesData)
            self.__isUsersRostersInited = True
            self._buildReceivedInvitesList(invitesData)
            self.onReceivedInviteListInited()

    def __pe_onPrebattleInvitesChanged(self, diff):
        if not self.__isUsersRostersInited:
            LOG_DEBUG('Received invites ignored. Manager waits for client will receive a roster list')
            return
        else:
            prbInvites = diff.get(('prebattleInvites', '_r'))
            if prbInvites is not None:
                self._buildReceivedInvitesList(prbInvites)
            prbInvites = diff.get('prebattleInvites')
            if prbInvites is not None:
                self.__updatePrebattleInvites(prbInvites)
            return

    def __updatePrebattleInvites(self, prbInvites):
        receiver = BigWorld.player().name
        receiverDBID = getPlayerDatabaseID()
        receiverClanAbbrev = g_lobbyContext.getClanAbbrev(self.__clanInfo)
        added = []
        changed = []
        deleted = []
        modified = False
        rosterGetter = self.users.getUser
        for (prebattleID, peripheryID), data in prbInvites.iteritems():
            inviteID = self._makeInviteID(prebattleID, peripheryID)
            if data is None:
                if self._delInvite(inviteID):
                    modified = True
                    deleted.append(inviteID)
                continue
            invite = PrbInviteWrapper(id=inviteID, receiver=receiver, receiverDBID=receiverDBID, receiverClanAbbrev=receiverClanAbbrev, peripheryID=peripheryID, **data)
            inList = inviteID in self.__receivedInvites
            if not inList:
                if self._addInvite(invite, rosterGetter):
                    modified = True
                    added.append(inviteID)
            elif self._updateInvite(invite, rosterGetter):
                modified = True
                changed.append(inviteID)

        if modified:
            self.onReceivedInviteListModified(added, changed, deleted)
        return

    def __accept_onPostActionsStopped(self, isCompleted):
        if not isCompleted:
            return
        prebattleID = self.__acceptChain.prebattleID
        peripheryID = self.__acceptChain.peripheryID
        if (prebattleID, peripheryID) in self._IDMap['prbIDs']:
            self._doAccept(prebattleID, peripheryID)
            if self.__unreadInvitesCount > 0:
                self.__unreadInvitesCount -= 1
        else:
            LOG_ERROR('Prebattle invite not found', prebattleID, peripheryID)
Ejemplo n.º 15
0
class BrowserController(Controller, AppRef):
    _BROWSER_TEXTURE = 'BrowserBg'
    _ALT_BROWSER_TEXTURE = 'AltBrowserBg'

    def __init__(self, proxy):
        super(BrowserController, self).__init__(proxy)
        self.__browsers = {}
        self.__browsersCallbacks = {}
        self.__browserIDGenerator = SequenceIDGenerator()
        self.__eventMgr = Event.EventManager()
        self.onBrowserAdded = Event.Event(self.__eventMgr)
        self.onBrowserDeleted = Event.Event(self.__eventMgr)
        self.__urlMacros = URLMarcos()

    def fini(self):
        self.__eventMgr.clear()
        self.__eventMgr = None
        self.__urlMacros.clear()
        self.__urlMacros = None
        self.__browserIDGenerator = None
        super(BrowserController, self).fini()
        return

    def onBattleStarted(self):
        self.__stop()

    def onDisconnected(self):
        self.__stop()

    @async
    @process
    def load(self, url = None, title = None, showActionBtn = True, showWaiting = True, browserID = None, isAsync = False, browserSize = None, background = None, isDefault = True, callback = None):
        url = url or GUI_SETTINGS.browser.url
        suffix = yield self.__urlMacros.parse(GUI_SETTINGS.browser.params)
        concatenator = '&' if '?' in url else '?'
        if suffix not in url:
            url = concatenator.join([url, suffix])
        size = browserSize or BROWSER.SIZE
        background = background or BROWSER.BACKGROUND
        if browserID not in self.__browsers:
            browserID = self.__browserIDGenerator.next()
            texture = self._BROWSER_TEXTURE if isDefault else self._ALT_BROWSER_TEXTURE
            self.__browsers[browserID] = WebBrowser(browserID, self.app, texture, size, url, backgroundUrl=background)
            self.onBrowserAdded(browserID)
        ctx = {'url': url,
         'title': title,
         'showActionBtn': showActionBtn,
         'showWaiting': showWaiting,
         'browserID': browserID,
         'size': size,
         'isDefault': isDefault,
         'isAsync': isAsync}

        def browserCallback(*args):
            self.__clearCallback(browserID)
            self.__showBrowser(browserID, ctx)

        if isAsync:
            self.__browsersCallbacks[browserID] = (None, browserCallback)
            self.__browsers[browserID].onLoadEnd += browserCallback
        else:
            self.__browsersCallbacks[browserID] = (browserCallback, None)
            self.__browsers[browserID].onLoadStart += browserCallback
        callback(browserID)
        return

    def getBrowser(self, browserID):
        return self.__browsers.get(browserID)

    def delBrowser(self, browserID):
        if browserID in self.__browsers:
            browser = self.__browsers.pop(browserID)
            loadStart, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None))
            if loadStart is not None:
                browser.onLoadStart -= loadStart
            if loadEnd is not None:
                browser.onLoadEnd -= loadEnd
            browser.destroy()
        self.onBrowserDeleted(browserID)
        return

    def __stop(self):
        while self.__browsers:
            browserID, browser = self.__browsers.popitem()
            loadStart, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None))
            if loadStart is not None:
                browser.onLoadStart -= loadStart
            if loadEnd is not None:
                browser.onLoadEnd -= loadEnd
            browser.destroy()

        return

    def __clearCallback(self, browserID):
        if browserID in self.__browsersCallbacks:
            loadStart, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None))
            if loadStart is not None:
                self.__browsers[browserID].onLoadStart -= loadStart
            if loadEnd is not None:
                self.__browsers[browserID].onLoadEnd -= loadEnd
        return

    def __showBrowser(self, browserID, ctx):
        self.app.fireEvent(LoadViewEvent(VIEW_ALIAS.BROWSER_WINDOW, getViewName(VIEW_ALIAS.BROWSER_WINDOW, browserID), ctx=ctx), EVENT_BUS_SCOPE.LOBBY)
Ejemplo n.º 16
0
class BrowserController(Controller):
    _BROWSER_TEXTURE = "BrowserBg"
    _ALT_BROWSER_TEXTURE = "AltBrowserBg"

    def __init__(self, proxy):
        super(BrowserController, self).__init__(proxy)
        self.__browsers = {}
        self.__browsersCallbacks = {}
        self.__browserIDGenerator = SequenceIDGenerator()
        self.__eventMgr = Event.EventManager()
        self.onBrowserAdded = Event.Event(self.__eventMgr)
        self.onBrowserDeleted = Event.Event(self.__eventMgr)
        self.__urlMacros = URLMarcos()

    def fini(self):
        self.__eventMgr.clear()
        self.__eventMgr = None
        self.__urlMacros.clear()
        self.__urlMacros = None
        self.__browserIDGenerator = None
        super(BrowserController, self).fini()
        return

    def onAvatarBecomePlayer(self):
        self.__stop()

    def onDisconnected(self):
        self.__stop()

    @async
    @process
    def load(
        self,
        url=None,
        title=None,
        showActionBtn=True,
        showWaiting=True,
        browserID=None,
        isAsync=False,
        browserSize=None,
        background=None,
        isDefault=True,
        callback=None,
        showCloseBtn=False,
    ):
        url = url or GUI_SETTINGS.browser.url
        suffix = yield self.__urlMacros.parse(GUI_SETTINGS.browser.params)
        concatenator = "&" if "?" in url else "?"
        if suffix not in url:
            url = concatenator.join([url, suffix])
        size = browserSize or BROWSER.SIZE
        background = background or BROWSER.BACKGROUND
        if browserID is None:
            browserID = self.__browserIDGenerator.next()
        if browserID not in self.__browsers:
            texture = self._BROWSER_TEXTURE if isDefault else self._ALT_BROWSER_TEXTURE
            app = g_appLoader.getApp()
            if not app:
                raise AssertionError("Application can not be None")
                self.__browsers[browserID] = WebBrowser(browserID, app, texture, size, url, backgroundUrl=background)
                self.onBrowserAdded(browserID)
            ctx = {
                "url": url,
                "title": title,
                "showActionBtn": showActionBtn,
                "showWaiting": showWaiting,
                "browserID": browserID,
                "size": size,
                "isDefault": isDefault,
                "isAsync": isAsync,
                "showCloseBtn": showCloseBtn,
            }

            def browserCallback(*args):
                self.__clearCallback(browserID)
                self.__showBrowser(browserID, ctx)

            self.__browsersCallbacks[browserID] = isAsync and (None, browserCallback)
            self.__browsers[browserID].onLoadEnd += browserCallback
        else:
            self.__browsersCallbacks[browserID] = (browserCallback, None)
            self.__browsers[browserID].onLoadStart += browserCallback
        callback(browserID)
        return

    def getBrowser(self, browserID):
        return self.__browsers.get(browserID)

    def delBrowser(self, browserID):
        if browserID in self.__browsers:
            browser = self.__browsers.pop(browserID)
            loadStart, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None))
            if loadStart is not None:
                browser.onLoadStart -= loadStart
            if loadEnd is not None:
                browser.onLoadEnd -= loadEnd
            browser.destroy()
        self.onBrowserDeleted(browserID)
        return

    def __stop(self):
        while self.__browsers:
            browserID, browser = self.__browsers.popitem()
            loadStart, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None))
            if loadStart is not None:
                browser.onLoadStart -= loadStart
            if loadEnd is not None:
                browser.onLoadEnd -= loadEnd
            browser.destroy()

        return

    def __clearCallback(self, browserID):
        if browserID in self.__browsersCallbacks:
            loadStart, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None))
            if loadStart is not None:
                self.__browsers[browserID].onLoadStart -= loadStart
            if loadEnd is not None:
                self.__browsers[browserID].onLoadEnd -= loadEnd
        return

    def __showBrowser(self, browserID, ctx):
        g_eventBus.handleEvent(
            LoadViewEvent(VIEW_ALIAS.BROWSER_WINDOW, getViewName(VIEW_ALIAS.BROWSER_WINDOW, browserID), ctx=ctx),
            EVENT_BUS_SCOPE.LOBBY,
        )
Ejemplo n.º 17
0
def _generateUserName():
    global _g_namesGenerator
    if _g_namesGenerator is None:
        _g_namesGenerator = SequenceIDGenerator()
    return '%s %d' % (i18n.makeString(USER_DEFAULT_NAME_PREFIX),
                      _g_namesGenerator.next())
Ejemplo n.º 18
0
class InvitesManager(object):
    __clanInfo = None

    def __init__(self):
        from gui.prb_control.formatters.invites import PrbInviteLinkFormatter
        self.__linkFormatter = PrbInviteLinkFormatter()
        self._IDGen = SequenceIDGenerator()
        self._IDMap = {'inviteIDs': {}, 'prbIDs': {}}
        self.__receivedInvites = {}
        self.__unreadInvitesCount = 0
        self.__eventManager = Event.EventManager()
        self.__acceptChain = None
        self.onReceivedInviteListInited = Event.Event(self.__eventManager)
        self.onReceivedInviteListModified = Event.Event(self.__eventManager)
        return

    def init(self):
        self.__isUsersRostersInited = False
        self.__isInvitesListBuild = False
        g_messengerEvents.users.onUsersRosterReceived += self.__me_onUsersRosterReceived
        g_playerEvents.onPrebattleInvitesChanged += self.__pe_onPrebattleInvitesChanged

    def fini(self):
        self.__clearAcceptChain()
        self.__isUsersRostersInited = False
        self.__isInvitesListBuild = False
        g_messengerEvents.users.onUsersRosterReceived += self.__me_onUsersRosterReceived
        g_playerEvents.onPrebattleInvitesChanged -= self.__pe_onPrebattleInvitesChanged
        self.clear()

    def clear(self):
        self.__isUsersRostersInited = False
        self.__isInvitesListBuild = False
        self.__receivedInvites.clear()
        self.__unreadInvitesCount = 0
        self._IDMap = {'inviteIDs': {}, 'prbIDs': {}}
        self.__eventManager.clear()

    @process
    def onAccountShowGUI(self):
        clanInfo = yield StatsRequester().getClanInfo()
        self._setClanInfo(clanInfo)
        g_clientUpdateManager.addCallbacks(
            {'stats.clanInfo': self._setClanInfo})

    def onAvatarBecomePlayer(self):
        g_clientUpdateManager.removeObjectCallbacks(self)
        self.__clearAcceptChain()

    @storage_getter('users')
    def users(self):
        return None

    def isInited(self):
        return self.__isUsersRostersInited and self.__isInvitesListBuild

    def acceptInvite(self, inviteID, postActions=None):
        try:
            prebattleID, peripheryID = self._IDMap['inviteIDs'][inviteID]
        except KeyError:
            LOG_ERROR('Invite ID is invalid', inviteID, self._IDMap)
            return

        self.__clearAcceptChain()
        if not postActions:
            self._doAccept(prebattleID, peripheryID)
        else:
            self.__acceptChain = _AcceptInvitesPostActions(
                peripheryID, prebattleID, postActions)
            self.__acceptChain.onStopped += self.__accept_onPostActionsStopped
            self.__acceptChain.start()
        if self.__unreadInvitesCount > 0:
            self.__unreadInvitesCount -= 1

    def declineInvite(self, inviteID):
        try:
            prebattleID, peripheryID = self._IDMap['inviteIDs'][inviteID]
        except KeyError:
            LOG_ERROR('Invite ID is invalid', inviteID, self._IDMap)
            return

        BigWorld.player().prb_declineInvite(prebattleID, peripheryID)
        if self.__unreadInvitesCount > 0:
            self.__unreadInvitesCount -= 1

    def canAcceptInvite(self, invite):
        result = False
        if invite.id in self.__receivedInvites:
            from gui.prb_control.dispatcher import g_prbLoader
            dispatcher = g_prbLoader.getDispatcher()
            if dispatcher:
                prbFunctional = dispatcher.getPrbFunctional()
                unitFunctional = dispatcher.getUnitFunctional()
                return (prbFunctional and prbFunctional.hasLockedState()
                        or unitFunctional
                        and unitFunctional.hasLockedState()) and False
        another = invite.anotherPeriphery
        if another:
            if g_preDefinedHosts.periphery(invite.peripheryID) is None:
                LOG_ERROR('Periphery not found')
                result = False
            elif g_lobbyContext.getCredentials() is None:
                LOG_ERROR('Login info not found')
                result = False
            elif g_preDefinedHosts.isRoamingPeriphery(
                    invite.peripheryID) and not isRoamingEnabled(
                        g_itemsCache.items.stats.attributes):
                LOG_ERROR('Roaming is not supported')
                result = False
            elif invite.id > 0:
                result = invite.isActive()
            else:
                result = invite.id > 0 and invite.isActive()
        return result

    def canDeclineInvite(self, invite):
        result = False
        if invite.id in self.__receivedInvites:
            result = invite.id > 0 and invite.isActive()
        return result

    def getInviteInfo(self, inviteID):
        try:
            prebattleID, peripheryID = self._IDMap['inviteIDs'][inviteID]
            return (prebattleID, peripheryID)
        except KeyError:
            return (0, 0)

    def getReceivedInviteCount(self):
        return len(self.__receivedInvites)

    def getReceivedInvite(self, inviteID):
        return self.__receivedInvites.get(inviteID)

    def getReceivedInvites(self, IDs=None):
        result = self.__receivedInvites.values()
        if IDs is not None:
            result = filter(lambda item: item[0].id in IDs, result)
        return result

    def getUnreadCount(self):
        return self.__unreadInvitesCount

    def resetUnreadCount(self):
        self.__unreadInvitesCount = 0

    def _doAccept(self, prebattleID, peripheryID):
        if connectionManager.peripheryID == peripheryID:
            BigWorld.player().prb_acceptInvite(prebattleID, peripheryID)
        else:
            LOG_ERROR('Invalid periphery', (prebattleID, peripheryID),
                      connectionManager.peripheryID)

    def _makeInviteID(self, prebattleID, peripheryID):
        inviteID = self._IDMap['prbIDs'].get((prebattleID, peripheryID))
        if inviteID is None:
            inviteID = self._IDGen.next()
            self._IDMap['inviteIDs'][inviteID] = (prebattleID, peripheryID)
            self._IDMap['prbIDs'][prebattleID, peripheryID] = inviteID
        return inviteID

    def _addInvite(self, invite, userGetter):
        if g_settings.userPrefs.invitesFromFriendsOnly:
            user = userGetter(invite.creatorDBID)
            if user is None or not user.isFriend():
                LOG_DEBUG('Invite to be ignored:', invite)
                return False
        link = self.__linkFormatter.format(invite)
        if not len(link):
            if constants.IS_DEVELOPMENT:
                LOG_WARNING('Formatter not found. Invite data : ', invite)
            return False
        else:
            self.__receivedInvites[invite.id] = (invite, link)
            if invite.isActive():
                self.__unreadInvitesCount += 1
            return True

    def _updateInvite(self, other, userGetter):
        inviteID = other.id
        invite, _ = self.__receivedInvites[inviteID]
        if other.isActive() and g_settings.userPrefs.invitesFromFriendsOnly:
            user = userGetter(invite.creatorDBID)
            if user is None or not user.isFriend():
                LOG_DEBUG('Invite to be ignored:', invite)
                return False
        prevCount = invite.count
        invite = invite._merge(other)
        link = self.__linkFormatter.format(invite)
        self.__receivedInvites[inviteID] = (invite, link)
        if invite.isActive() and prevCount < invite.count:
            self.__unreadInvitesCount += 1
        return True

    def _delInvite(self, inviteID):
        result = inviteID in self.__receivedInvites
        if result:
            self.__receivedInvites.pop(inviteID)
        return result

    def _buildReceivedInvitesList(self, invitesData):
        self.__isInvitesListBuild = True
        self.__receivedInvites.clear()
        self.__unreadInvitesCount = 0
        receiver = BigWorld.player().name
        receiverDBID = getPlayerDatabaseID()
        receiverClanAbbrev = g_lobbyContext.getClanAbbrev(self.__clanInfo)
        userGetter = self.users.getUser
        for (prebattleID, peripheryID), data in invitesData.iteritems():
            inviteID = self._makeInviteID(prebattleID, peripheryID)
            invite = PrbInviteWrapper(id=inviteID,
                                      receiver=receiver,
                                      receiverDBID=receiverDBID,
                                      receiverClanAbbrev=receiverClanAbbrev,
                                      peripheryID=peripheryID,
                                      **data)
            self._addInvite(invite, userGetter)

    def _setClanInfo(self, clanInfo):
        self.__clanInfo = clanInfo
        if not self.__isUsersRostersInited:
            return
        receiverClanAbbrev = g_lobbyContext.getClanAbbrev(self.__clanInfo)
        changed = []
        for inviteID, (invite, _) in self.__receivedInvites.iteritems():
            if invite.receiverClanAbbrev != receiverClanAbbrev:
                invite = invite._replace(receiverClanAbbrev=receiverClanAbbrev)
                link = self.__linkFormatter.format(invite)
                self.__receivedInvites[inviteID] = (invite, link)
                changed.append(inviteID)

        if len(changed) > 0:
            self.onReceivedInviteListModified([], changed, [])

    def __clearAcceptChain(self):
        if self.__acceptChain is not None:
            self.__acceptChain.onStopped -= self.__accept_onPostActionsStopped
            self.__acceptChain.stop()
            self.__acceptChain = None
        return

    def __me_onUsersRosterReceived(self):
        if not self.__isUsersRostersInited:
            invitesData = getattr(BigWorld.player(), 'prebattleInvites', {})
            LOG_DEBUG('Users roster received, list of invites is available',
                      invitesData)
            self.__isUsersRostersInited = True
            self._buildReceivedInvitesList(invitesData)
            self.onReceivedInviteListInited()

    def __pe_onPrebattleInvitesChanged(self, diff):
        if not self.__isUsersRostersInited:
            LOG_DEBUG(
                'Received invites ignored. Manager waits for client will receive a roster list'
            )
            return
        else:
            prbInvites = diff.get(('prebattleInvites', '_r'))
            if prbInvites is not None:
                self._buildReceivedInvitesList(prbInvites)
            prbInvites = diff.get('prebattleInvites')
            if prbInvites is not None:
                self.__updatePrebattleInvites(prbInvites)
            return

    def __updatePrebattleInvites(self, prbInvites):
        receiver = BigWorld.player().name
        receiverDBID = getPlayerDatabaseID()
        receiverClanAbbrev = g_lobbyContext.getClanAbbrev(self.__clanInfo)
        added = []
        changed = []
        deleted = []
        modified = False
        rosterGetter = self.users.getUser
        for (prebattleID, peripheryID), data in prbInvites.iteritems():
            inviteID = self._makeInviteID(prebattleID, peripheryID)
            if data is None:
                if self._delInvite(inviteID):
                    modified = True
                    deleted.append(inviteID)
                continue
            invite = PrbInviteWrapper(id=inviteID,
                                      receiver=receiver,
                                      receiverDBID=receiverDBID,
                                      receiverClanAbbrev=receiverClanAbbrev,
                                      peripheryID=peripheryID,
                                      **data)
            inList = inviteID in self.__receivedInvites
            if not inList:
                if self._addInvite(invite, rosterGetter):
                    modified = True
                    added.append(inviteID)
            elif self._updateInvite(invite, rosterGetter):
                modified = True
                changed.append(inviteID)

        if modified:
            self.onReceivedInviteListModified(added, changed, deleted)
        return

    def __accept_onPostActionsStopped(self, isCompleted):
        if not isCompleted:
            return
        prebattleID = self.__acceptChain.prebattleID
        peripheryID = self.__acceptChain.peripheryID
        if (prebattleID, peripheryID) in self._IDMap['prbIDs']:
            self._doAccept(prebattleID, peripheryID)
            if self.__unreadInvitesCount > 0:
                self.__unreadInvitesCount -= 1
        else:
            LOG_ERROR('Prebattle invite not found', prebattleID, peripheryID)
Ejemplo n.º 19
0
class InvitesManager(UsersInfoHelper):
    __clanInfo = None
    itemsCache = dependency.descriptor(IItemsCache)
    sessionProvider = dependency.descriptor(IBattleSessionProvider)
    settingsCore = dependency.descriptor(ISettingsCore)
    lobbyContext = dependency.descriptor(ILobbyContext)
    appLoader = dependency.descriptor(IAppLoader)

    def __init__(self, loader):
        super(InvitesManager, self).__init__()
        self.__loader = loader
        self._IDGen = SequenceIDGenerator()
        self._IDMap = {}
        self.__invites = {}
        self.__invitesIgnored = {}
        self.__unreadInvitesCount = 0
        self.__eventManager = Event.EventManager()
        self.__acceptChain = None
        self.onInvitesListInited = Event.Event(self.__eventManager)
        self.onReceivedInviteListModified = Event.Event(self.__eventManager)
        self.onSentInviteListModified = Event.Event(self.__eventManager)
        self.__isInBattle = False
        return

    def __del__(self):
        _logger.debug('InvitesManager deleted')
        super(InvitesManager, self).__del__()

    def init(self):
        self.__inited = PRB_INVITES_INIT_STEP.UNDEFINED
        self.settingsCore.onSettingsChanged += self.__onSettingsChanged
        g_messengerEvents.users.onUsersListReceived += self.__onUsersListReceived
        g_messengerEvents.users.onUserActionReceived += self.__onUserActionReceived
        g_messengerEvents.users.onBattleUserActionReceived += self.__onUserActionReceived
        g_playerEvents.onPrebattleInvitesChanged += self.__onPrebattleInvitesChanged
        g_playerEvents.onPrebattleInvitationsChanged += self.__onPrebattleInvitationsChanged
        g_playerEvents.onPrebattleInvitesStatus += self.__onPrebattleInvitesStatus
        g_eventBus.addListener(events.PrbInvitesEvent.ACCEPT, self.__acceptInvite, scope=EVENT_BUS_SCOPE.LOBBY)

    def fini(self):
        self.__clearAcceptChain()
        self.__inited = PRB_INVITES_INIT_STEP.UNDEFINED
        self.__loader = None
        self.settingsCore.onSettingsChanged -= self.__onSettingsChanged
        g_messengerEvents.users.onUsersListReceived -= self.__onUsersListReceived
        g_messengerEvents.users.onUserActionReceived -= self.__onUserActionReceived
        g_messengerEvents.users.onBattleUserActionReceived -= self.__onUserActionReceived
        g_playerEvents.onPrebattleInvitationsChanged -= self.__onPrebattleInvitationsChanged
        g_playerEvents.onPrebattleInvitesChanged -= self.__onPrebattleInvitesChanged
        g_playerEvents.onPrebattleInvitesStatus -= self.__onPrebattleInvitesStatus
        g_eventBus.removeListener(events.PrbInvitesEvent.ACCEPT, self.__acceptInvite, scope=EVENT_BUS_SCOPE.LOBBY)
        self.clear()
        return

    def start(self):
        self.__isInBattle = False
        if self.__inited & PRB_INVITES_INIT_STEP.STARTED == 0:
            self.__inited |= PRB_INVITES_INIT_STEP.STARTED
            if self.__inited == PRB_INVITES_INIT_STEP.INITED:
                self.onInvitesListInited()

    def clear(self):
        self.__inited = PRB_INVITES_INIT_STEP.UNDEFINED
        self.__clearInvites()
        self._IDMap = {}
        self.__eventManager.clear()

    def onAvatarBecomePlayer(self):
        if self.__inited & PRB_INVITES_INIT_STEP.STARTED == 0:
            self.__inited |= PRB_INVITES_INIT_STEP.STARTED
            if self.__inited == PRB_INVITES_INIT_STEP.INITED:
                self.onInvitesListInited()
        self.__isInBattle = True
        self.__clearAcceptChain()

    @storage_getter('users')
    def users(self):
        return None

    def isInited(self):
        return self.__inited == PRB_INVITES_INIT_STEP.INITED

    def acceptInvite(self, inviteID, postActions=None):
        try:
            invite = self.__invites[inviteID]
        except KeyError:
            _logger.error('Invite ID is invalid. %s', (inviteID, self._IDMap))
            return

        self.__clearAcceptChain()
        if not postActions:
            invite.accept()
        else:
            self.__acceptChain = _AcceptInvitesPostActions(invite, postActions)
            self.__acceptChain.onStopped += self.__accept_onPostActionsStopped
            self.__acceptChain.start()
        if self.__unreadInvitesCount > 0:
            self.__unreadInvitesCount -= 1

    def declineInvite(self, inviteID):
        try:
            invite = self.__invites[inviteID]
        except KeyError:
            _logger.error('Invite ID is invalid. %s', (inviteID, self._IDMap))
            return

        invite.decline()
        if self.__unreadInvitesCount > 0:
            self.__unreadInvitesCount -= 1

    def revokeInvite(self, inviteID):
        try:
            invite = self.__invites[inviteID]
        except KeyError:
            _logger.error('Invite ID is invalid. %s', (inviteID, self._IDMap))
            return

        invite.revoke()
        if self.__unreadInvitesCount > 0:
            self.__unreadInvitesCount -= 1

    def canAcceptInvite(self, invite):
        result = False
        if invite.alwaysAvailable is True:
            result = True
        elif invite.clientID in self.__invites:
            dispatcher = self.__loader.getDispatcher()
            if dispatcher:
                if invite.alreadyJoined:
                    return False
                if dispatcher.getEntity().hasLockedState():
                    return False
            another = invite.anotherPeriphery
            if another:
                if g_preDefinedHosts.periphery(invite.peripheryID) is None:
                    _logger.error('Periphery not found')
                    result = False
                elif self.lobbyContext.getCredentials() is None:
                    _logger.error('Login info not found')
                    result = False
                elif g_preDefinedHosts.isRoamingPeriphery(invite.peripheryID) and not isRoamingEnabled(self.itemsCache.items.stats.attributes):
                    _logger.error('Roaming is not supported')
                    result = False
                else:
                    result = invite.clientID > 0 and invite.isActive()
            else:
                result = invite.clientID > 0 and invite.isActive()
        return result

    def canDeclineInvite(self, invite):
        result = False
        if invite.clientID in self.__invites:
            result = invite.clientID > 0 and invite.isActive()
        return result

    def canRevokeInvite(self, invite):
        result = False
        if invite.clientID in self.__invites:
            result = invite.clientID > 0 and invite.isActive() and isCurrentPlayer(invite.creatorID)
        return result

    def getInvites(self, incoming=None, version=None, onlyActive=None, withIgnored=False):
        result = self.__invites.values()
        if withIgnored:
            result = chain(result, self.__invitesIgnored.values())
        if incoming is not None:
            result = [ item for item in result if item.isIncoming() is incoming ]
        if version is not None:
            result = [ item for item in result if item.getVersion() == version ]
        if onlyActive is not None:
            result = [ item for item in result if item.isActive() is onlyActive ]
        return result

    def getInvite(self, inviteID):
        invite = None
        if inviteID in self.__invites:
            invite = self.__invites[inviteID]
        return invite

    def getReceivedInviteCount(self):
        return len(self.getReceivedInvites())

    def getReceivedInvites(self, ids=None):
        result = self.getInvites(incoming=True)
        if ids is not None:
            result = [ item for item in result if item.clientID in ids ]
        return result

    def getSentInvites(self, ids=None):
        result = self.getInvites(incoming=False)
        if ids is not None:
            result = [ item for item in result if item.clientID in ids ]
        return result

    def getSentInviteCount(self):
        return len(self.getSentInvites())

    def getUnreadCount(self):
        return self.__unreadInvitesCount

    def resetUnreadCount(self):
        self.__unreadInvitesCount = 0

    def onUserNamesReceived(self, names):
        updated = defaultdict(list)
        rosterGetter = self.users.getUser
        inviteMaker = self._getNewInviteMaker(rosterGetter)
        prebattleInvitations = _getNewInvites()
        for invite in self.getInvites(version=_InviteVersion.NEW, withIgnored=True):
            if invite.creatorID in names or invite.receiverID in names:
                senderID = invite.creatorID
                if self.appLoader.getSpaceID() == GuiGlobalSpaceID.BATTLE:
                    senderID = invite.creatorVehID
                inviteUniqueId = UniqueId(id=invite.id, senderID=senderID)
                inviteData = prebattleInvitations.get(inviteUniqueId)
                inviteID, invite = inviteMaker(inviteData)
                if inviteData and self._updateInvite(invite):
                    updated[invite.isIncoming()].append(inviteID)

        for isIncoming, event in ((True, self.onReceivedInviteListModified), (False, self.onSentInviteListModified)):
            if updated[isIncoming]:
                event([], updated[isIncoming], [])

    def _makeInviteID(self, prebattleID, peripheryID, senderID, receiverID):
        inviteKey = (prebattleID,
         peripheryID,
         senderID,
         receiverID)
        inviteID = self._IDMap.get(inviteKey)
        if inviteID is None:
            inviteID = self._IDGen.next()
            self._IDMap[inviteKey] = inviteID
        return inviteID

    def _addInvite(self, invite, creator):
        if self.__isInviteSenderIgnored(invite, creator):
            self.__invitesIgnored[invite.clientID] = invite
            return False
        self.__invites[invite.clientID] = invite
        if invite.isActive():
            self.__unreadInvitesCount += 1
        return True

    def _updateInvite(self, other):
        inviteID = other.clientID
        isIgnored = False
        if inviteID in self.__invites:
            invite = self.__invites[inviteID]
        else:
            isIgnored = True
            invite = self.__invitesIgnored[inviteID]
        if invite == other:
            return False
        if isIgnored:
            invite = invite.merge(other)
            self.__invitesIgnored[inviteID] = invite
            return False
        prevCount = invite.count
        invite = invite.merge(other)
        self.__invites[inviteID] = invite
        if invite.isActive() and prevCount < invite.count:
            self.__unreadInvitesCount += 1
        return True

    def _delInvite(self, inviteID):
        result = inviteID in self.__invites
        if result:
            self.__invites.pop(inviteID)
        return result

    def _buildReceivedInvitesList(self, invitesLists):
        if self.__inited & PRB_INVITES_INIT_STEP.DATA_BUILD == 0:
            self.__inited |= PRB_INVITES_INIT_STEP.DATA_BUILD
        self.__clearInvites()
        for invitesData, maker in invitesLists:
            for item in invitesData:
                _, invite = maker(item)
                if invite:
                    creator = self.users.getUser(invite.creatorID, scope=UserEntityScope.BATTLE if invite.creatorVehID else UserEntityScope.LOBBY)
                    self._addInvite(invite, creator)

        if self.appLoader.getSpaceID() != GuiGlobalSpaceID.BATTLE:
            self.syncUsersInfo()

    def _rebuildInvitesLists(self):
        rosterGetter = self.users.getUser
        self._buildReceivedInvitesList([(sorted(_getOldInvites().items(), key=_getOldInviteOrderKey, reverse=False), self._getOldInviteMaker()), (sorted(_getNewInvites().values(), key=operator.itemgetter('sentAt'), reverse=False), self._getNewInviteMaker(rosterGetter))])

    def _getOldInviteMaker(self):
        receiver = getPlayerName()
        receiverID = getPlayerDatabaseID()
        receiverClanAbbrev = self.lobbyContext.getClanAbbrev(self.__clanInfo)

        def _inviteMaker(item):
            (prebattleID, peripheryID), data = item
            creatorID = data['creatorDBID']
            inviteID = self._makeInviteID(prebattleID, peripheryID, creatorID, receiverID)
            if data is not None:
                invite = PrbInviteWrapper(clientID=inviteID, creatorID=creatorID, receiver=receiver, receiverID=receiverID, receiverClanAbbrev=receiverClanAbbrev, peripheryID=peripheryID, prebattleID=prebattleID, **data)
            else:
                invite = None
            return (inviteID, invite)

        return _inviteMaker

    def _getNewInviteMaker(self, rosterGetter):

        def _getUserName(userID, scope):
            name, abbrev = ('', None)
            if userID:
                if self.appLoader.getSpaceID() == GuiGlobalSpaceID.BATTLE:
                    ctx = self.sessionProvider.getCtx()
                    isUserInBattle = ctx.getVehIDBySessionID(userID) != 0
                    if isUserInBattle:
                        name, abbrev = ctx.getPlayerFullNameParts(avatarSessionID=userID, showVehShortName=False)[1:3]
                if not name:
                    userName = self.getUserName(userID, scope)
                    userClanAbbrev = self.getUserClanAbbrev(userID)
                    user = rosterGetter(userID, scope=scope)
                    if user and user.hasValidName():
                        name, abbrev = userName, userClanAbbrev
            return (name, abbrev)

        def _inviteMaker(item):
            peripheryID, prebattleID = PrbInvitationWrapper.getPrbInfo(item.get('info', {}))
            creatorIDScope = UserEntityScope.LOBBY
            receiverIDScope = UserEntityScope.LOBBY
            creatorID = item.get('senderDBID', 0)
            receiverID = item.get('receiverDBID', 0)
            if creatorID <= 0:
                if self.appLoader.getSpaceID() == GuiGlobalSpaceID.BATTLE:
                    ctx = self.sessionProvider.getCtx()
                    if 'senderVehID' in item:
                        creatorID = ctx.getSessionIDByVehID(item['senderVehID'])
                        creatorIDScope = UserEntityScope.BATTLE
            else:
                item['senderVehID'] = 0
            if receiverID <= 0:
                if self.appLoader.getSpaceID() == GuiGlobalSpaceID.BATTLE:
                    ctx = self.sessionProvider.getCtx()
                    if 'receiverVehID' in item:
                        receiverID = ctx.getSessionIDByVehID(item['receiverVehID'])
                        receiverIDScope = UserEntityScope.BATTLE
            else:
                item['receiverVehID'] = 0
            inviteID = self._makeInviteID(prebattleID, peripheryID, creatorID, receiverID)
            senderName, senderClanAbbrev = _getUserName(creatorID, creatorIDScope)
            receiverName, receiverClanAbbrev = _getUserName(receiverID, receiverIDScope)
            return (inviteID, PrbInvitationWrapper(inviteID, creatorID=creatorID, sender=senderName, senderClanAbbrev=senderClanAbbrev, receiverID=receiverID, receiver=receiverName, receiverClanAbbrev=receiverClanAbbrev, **item))

        return _inviteMaker

    def __initReceivedInvites(self):
        step = PRB_INVITES_INIT_STEP.CONTACTS_RECEIVED
        if self.__inited & step != step:
            return
        self._rebuildInvitesLists()
        if self.__inited == PRB_INVITES_INIT_STEP.INITED:
            self.onInvitesListInited()

    def __clearAcceptChain(self):
        if self.__acceptChain is not None:
            self.__acceptChain.onStopped -= self.__accept_onPostActionsStopped
            self.__acceptChain.stop()
            self.__acceptChain = None
        return

    def __onUsersListReceived(self, tags):
        doInit = False
        if USER_TAG.FRIEND in tags:
            doInit = True
            step = PRB_INVITES_INIT_STEP.FRIEND_RECEIVED
            if self.__inited & step == 0:
                self.__inited |= step
        if USER_TAG.IGNORED in tags or USER_TAG.IGNORED_TMP in tags:
            doInit = True
            step = PRB_INVITES_INIT_STEP.IGNORED_RECEIVED
            if self.__inited & step == 0:
                self.__inited |= step
        if doInit:
            self.__initReceivedInvites()

    def __onUserActionReceived(self, actionID, user, *args):
        if actionID in (USER_ACTION_ID.IGNORED_REMOVED, USER_ACTION_ID.TMP_IGNORED_REMOVED):
            self.__refreshIgnoredInvitesRemove(user)
        elif actionID in (USER_ACTION_ID.IGNORED_ADDED, USER_ACTION_ID.TMP_IGNORED_ADDED):
            self.__refreshIgnoredInvitesAdd(user)
        elif actionID == USER_ACTION_ID.FRIEND_ADDED:
            self.__refreshFriendInvitesAdd(user)
        elif actionID == USER_ACTION_ID.FRIEND_REMOVED:
            self.__refreshFriendInvitesRemove(user)
        elif actionID == USER_ACTION_ID.SUBSCRIPTION_CHANGED:
            if user.isFriend():
                self.__refreshFriendInvitesAdd(user)
            else:
                self.__refreshFriendInvitesRemove(user)

    def __onPrebattleInvitesChanged(self, diff):
        step = PRB_INVITES_INIT_STEP.CONTACTS_RECEIVED
        if self.__inited & step != step:
            _logger.debug('Received invites are ignored. Manager waits for client will receive contacts')
            return
        if ('prebattleInvites', '_r') in diff:
            self._rebuildInvitesLists()
        if 'prebattleInvites' in diff:
            self.__updateOldPrebattleInvites(_getOldInvites())

    def __onPrebattleInvitationsChanged(self, invitations):
        step = PRB_INVITES_INIT_STEP.CONTACTS_RECEIVED
        if self.__inited & step != step:
            _logger.debug('Received invites are ignored. Manager waits for client will receive contacts')
            return
        self.__updateNewPrebattleInvites(invitations)

    @staticmethod
    def __onPrebattleInvitesStatus(dbID, name, status):
        if status != PREBATTLE_INVITE_STATUS.OK:
            statusName = PREBATTLE_INVITE_STATUS_NAMES[status]
            SystemMessages.pushI18nMessage(backport.text(R.strings.system_messages.invite.status.dyn(statusName)()), name=name, type=SystemMessages.SM_TYPE.Warning)

    def __updateOldPrebattleInvites(self, prbInvites):
        added = []
        changed = []
        deleted = []
        modified = False
        inviteMaker = self._getOldInviteMaker()
        for item in prbInvites.iteritems():
            inviteID, invite = inviteMaker(item)
            if invite is None:
                if self._delInvite(inviteID):
                    modified = True
                    deleted.append(inviteID)
                continue
            inList = inviteID in self.__invites or inviteID in self.__invitesIgnored
            if not inList:
                creator = self.users.getUser(invite.creatorID)
                if self._addInvite(invite, creator):
                    modified = True
                    added.append(inviteID)
            if self._updateInvite(invite):
                modified = True
                changed.append(inviteID)

        if modified:
            self.onReceivedInviteListModified(added, changed, deleted)
        return

    def __updateNewPrebattleInvites(self, prbInvites):
        added = defaultdict(list)
        changed = defaultdict(list)
        deleted = defaultdict(list)
        modified = dict(((v, False) for v in (True, False)))
        rosterGetter = self.users.getUser
        inviteMaker = self._getNewInviteMaker(rosterGetter)
        newInvites = {}
        for data in sorted(prbInvites.itervalues(), key=operator.itemgetter('sentAt')):
            inviteID, invite = inviteMaker(data)
            if self.appLoader.getSpaceID() != GuiGlobalSpaceID.BATTLE and invite.creatorVehID:
                continue
            if inviteID not in newInvites or invite.createTime > newInvites[inviteID].createTime:
                newInvites[inviteID] = invite

        for invite in self.getInvites(version=_InviteVersion.NEW, withIgnored=True):
            inviteID = invite.clientID
            if (self.appLoader.getSpaceID() != GuiGlobalSpaceID.BATTLE and invite.creatorVehID or inviteID not in newInvites) and self._delInvite(inviteID):
                isIncoming = invite.isIncoming()
                modified[isIncoming] = True
                deleted[isIncoming].append(inviteID)

        for inviteID, invite in newInvites.iteritems():
            isIncoming = invite.isIncoming()
            if inviteID not in self.__invites and inviteID not in self.__invitesIgnored:
                creator = rosterGetter(invite.creatorID, scope=UserEntityScope.BATTLE if invite.creatorVehID else UserEntityScope.LOBBY)
                if self._addInvite(invite, creator):
                    modified[isIncoming] = True
                    added[isIncoming].append(inviteID)
            if self._updateInvite(invite):
                modified[isIncoming] = True
                changed[isIncoming].append(inviteID)

        for isIncoming, event in ((True, self.onReceivedInviteListModified), (False, self.onSentInviteListModified)):
            if modified[isIncoming]:
                event(added[isIncoming], changed[isIncoming], deleted[isIncoming])

        if self.appLoader.getSpaceID() != GuiGlobalSpaceID.BATTLE:
            self.syncUsersInfo()

    def __accept_onPostActionsStopped(self, isCompleted):
        if not isCompleted:
            return
        invite = self.__acceptChain.invite
        invite.accept()
        if self.__unreadInvitesCount > 0:
            self.__unreadInvitesCount -= 1

    def __clearInvites(self):
        self.__invites.clear()
        self.__invitesIgnored.clear()
        self.__unreadInvitesCount = 0

    def __isInviteSenderIgnored(self, invite, user, friendsSetting=None):
        if self.__isInBattle and invite.isIncoming():
            arenaDP = self.sessionProvider.getArenaDP()
            if arenaDP and arenaDP.getVehicleInfo().prebattleID > 0:
                return True
        friendsOnly = friendsSetting if friendsSetting is not None else g_settings.userPrefs.invitesFromFriendsOnly
        return isInviteSenderIgnored(user, friendsOnly, invite.isCreatedInBattle())

    def __refreshIgnoredInvitesRemove(self, user):
        invitations = []
        for invite in self.__invitesIgnored.itervalues():
            if invite.creatorID == user.getID():
                invitations.append(invite.clientID)

        for inviteID in invitations:
            self.__invites[inviteID] = self.__invitesIgnored.pop(inviteID)

        self.onReceivedInviteListModified(invitations, [], [])
        if self.appLoader.getSpaceID() != GuiGlobalSpaceID.BATTLE:
            self.syncUsersInfo()

    def __refreshIgnoredInvitesAdd(self, user):
        invitations = []
        for invite in self.__invites.itervalues():
            if invite.creatorID == user.getID():
                invitations.append(invite.clientID)

        for inviteID in invitations:
            self.__invitesIgnored[inviteID] = self.__invites.pop(inviteID)

        self.onReceivedInviteListModified([], [], invitations)
        if self.appLoader.getSpaceID() != GuiGlobalSpaceID.BATTLE:
            self.syncUsersInfo()

    def __refreshFriendInvitesRemove(self, user):
        invitations = []
        for invite in self.__invites.itervalues():
            if invite.creatorID == user.getID() and self.__isInviteSenderIgnored(invite, user):
                invitations.append(invite.clientID)

        for inviteID in invitations:
            self.__invitesIgnored[inviteID] = self.__invites.pop(inviteID)

        self.onReceivedInviteListModified([], [], invitations)
        if self.appLoader.getSpaceID() != GuiGlobalSpaceID.BATTLE:
            self.syncUsersInfo()

    def __refreshFriendInvitesAdd(self, user):
        invitations = []
        for invite in self.__invitesIgnored.itervalues():
            if invite.creatorID == user.getID() and not self.__isInviteSenderIgnored(invite, user):
                invitations.append(invite.clientID)

        for inviteID in invitations:
            self.__invites[inviteID] = self.__invitesIgnored.pop(inviteID)

        self.onReceivedInviteListModified(invitations, [], [])
        if self.appLoader.getSpaceID() != GuiGlobalSpaceID.BATTLE:
            self.syncUsersInfo()

    def __onSettingsChanged(self, diff):
        if 'invitesFromFriendsOnly' in diff:
            invitations = []
            isFriends = diff['invitesFromFriendsOnly']
            if isFriends:
                for invite in self.__invites.itervalues():
                    user = self.users.getUser(invite.creatorID)
                    if self.__isInviteSenderIgnored(invite, user, isFriends):
                        invitations.append(invite.clientID)

                for inviteID in invitations:
                    self.__invitesIgnored[inviteID] = self.__invites.pop(inviteID)

                self.onReceivedInviteListModified([], [], invitations)
            else:
                for invite in self.__invitesIgnored.itervalues():
                    user = self.users.getUser(invite.creatorID)
                    if not self.__isInviteSenderIgnored(invite, user, isFriends):
                        invitations.append(invite.clientID)

                for inviteID in invitations:
                    self.__invites[inviteID] = self.__invitesIgnored.pop(inviteID)

                self.onReceivedInviteListModified(invitations, [], [])
            if self.appLoader.getSpaceID() != GuiGlobalSpaceID.BATTLE:
                self.syncUsersInfo()

    def __acceptInvite(self, event):
        self.acceptInvite(event.inviteID, event.postActions)
Ejemplo n.º 20
0
class BWChatProvider(object):
    __slots__ = ('__weakref__', '__handlers', '__msgFilters', '__coolDown', '__idGen', '__isEnabled', '__queue')

    def __init__(self):
        super(BWChatProvider, self).__init__()
        self.__handlers = defaultdict(set)
        self.__msgFilters = None
        self.__coolDown = _ChatCooldownManager()
        self.__idGen = SequenceIDGenerator()
        self.__isEnabled = False
        self.__queue = []
        return

    def clear(self):
        self.__handlers.clear()

    def setEnable(self, value):
        if self.__isEnabled == value:
            return
        self.__isEnabled = value
        if self.__isEnabled:
            self.__sendActionsFromQueue()
        else:
            self.__queue = []

    def doAction(self, actionID, args = None, response = False, skipCoolDown = False):
        success, reqID = False, 0
        if self.__coolDown.isInProcess(actionID):
            if not skipCoolDown:
                g_messengerEvents.onErrorReceived(createCoolDownError(actionID))
        else:
            if response:
                reqID = self.__idGen.next()
            if self.__isEnabled:
                success = self.__sendAction(actionID, reqID, args)
            else:
                success = self.__addActionToQueue(actionID, reqID, args)
        return (success, reqID)

    def onActionReceived(self, actionID, reqID, args):
        handlers = self.__handlers[actionID]
        for handler in handlers:
            try:
                handler((actionID, reqID), args)
            except TypeError:
                LOG_ERROR('Handler has been invoked with error', handler)
                LOG_CURRENT_EXCEPTION()

    def setFilters(self, msgFilterChain):
        self.__msgFilters = msgFilterChain

    def filterInMessage(self, message):
        text = self.__msgFilters.chainIn(message.accountDBID, message.text)
        if not text:
            result = None
        else:
            message.text = text
            result = message
        return result

    def filterOutMessage(self, text, limits):
        return self.__msgFilters.chainOut(text, limits)

    def setActionCoolDown(self, actionID, coolDown):
        self.__coolDown.process(actionID, coolDown)

    def isActionInCoolDown(self, actionID):
        return self.__coolDown.isInProcess(actionID)

    def getActionCoolDown(self, actionID):
        return self.__coolDown.getTime(actionID)

    def clearActionCoolDown(self, actionID):
        self.__coolDown.reset(actionID)

    def registerHandler(self, actionID, handler):
        handlers = self.__handlers[actionID]
        if handler in handlers:
            LOG_WARNING('Handler already is exist', actionID, handler)
        else:
            if not hasattr(handler, '__self__') or not isinstance(handler.__self__, ActionsHandler):
                LOG_ERROR('Class of handler is not subclass of ActionsHandler', handler)
                return
            if callable(handler):
                handlers.add(handler)
            else:
                LOG_ERROR('Handler is invalid', handler)

    def unregisterHandler(self, actionID, handler):
        handlers = self.__handlers[actionID]
        if handler in handlers:
            handlers.remove(handler)

    def __sendAction(self, actionID, reqID, args = None):
        player = BigWorld.player()
        if player:
            player.base.messenger_onActionByClient_chat2(actionID, reqID, args or messageArgs())
            return True
        else:
            LOG_ERROR('Player is not defined')
            return False

    def __addActionToQueue(self, actionID, reqID, args = None):
        self.__queue.append((actionID, reqID, args))
        return True

    def __sendActionsFromQueue(self):
        invokedIDs = set()
        while self.__queue:
            actionID, reqID, args = self.__queue.pop()
            if actionID in invokedIDs:
                LOG_WARNING('Action is ignored, your must send action after event "showGUI" is invoked', actionID, reqID, args)
                continue
            self.__sendAction(actionID, reqID, args)
            invokedIDs.add(actionID)
Ejemplo n.º 21
0
class BWChatProvider(object):
    __slots__ = ('__weakref__', '__handlers', '__msgFilters', '__coolDown', '__idGen', '__isEnabled', '__queue', '__battleCmdCooldowns', '__replayHelper')

    def __init__(self):
        super(BWChatProvider, self).__init__()
        self.__handlers = defaultdict(set)
        self.__msgFilters = None
        self.__coolDown = _ChatCooldownManager()
        self.__battleCmdCooldowns = []
        self.__idGen = SequenceIDGenerator()
        self.__isEnabled = False
        self.__queue = []
        self.__replayHelper = ChatProviderReplayHelper()
        return

    def clear(self):
        self.__handlers.clear()
        self.__battleCmdCooldowns = []
        self.__replayHelper.onActionReceivedFromReplay -= self.onActionReceived
        self.__replayHelper.clear()

    def goToReplay(self):
        self.__replayHelper.goToReplay()
        self.__replayHelper.onActionReceivedFromReplay += self.onActionReceived

    def setEnable(self, value):
        if self.__isEnabled == value:
            return
        self.__isEnabled = value
        if self.__isEnabled:
            self.__sendActionsFromQueue()
        else:
            self.__queue = []

    def doAction(self, actionID, args=None, response=False, skipCoolDown=False):
        success, reqID = False, 0
        if self.__isCooldownInProcess(actionID, args):
            shouldShowCooldownError = not skipCoolDown and self.__shouldShowErrorMessage(actionID, args)
            if shouldShowCooldownError:
                g_messengerEvents.onErrorReceived(createCoolDownError(actionID, self.__getCooldownTime(actionID, args)))
        else:
            if response:
                reqID = self.__idGen.next()
            if self.__isEnabled:
                success = self.__sendAction(actionID, reqID, args)
            else:
                success = self.__addActionToQueue(actionID, reqID, args)
        return (success, reqID)

    def onActionReceived(self, actionID, reqID, args):
        self.__replayHelper.onActionReceived(actionID, reqID, args)
        replayCtrl = BattleReplay.g_replayCtrl
        if replayCtrl.isPlaying and replayCtrl.isServerSideReplay:
            if self.__skipReplayChat(actionID, reqID, args):
                return
        handlers = self.__handlers[actionID]
        for handler in handlers:
            try:
                handler((actionID, reqID), args)
            except TypeError:
                LOG_ERROR('Handler has been invoked with error', handler)
                LOG_CURRENT_EXCEPTION()

    def setFilters(self, msgFilterChain):
        self.__msgFilters = msgFilterChain

    def filterInMessage(self, message):
        text = message.text
        senderDBID = message.accountDBID
        if senderDBID > 0:
            text = self.__msgFilters.chainIn(senderDBID, text)
        else:
            senderAvatarID = message.avatarSessionID
            if senderAvatarID:
                text = self.__msgFilters.chainIn(senderAvatarID, text)
        if not text:
            result = None
        else:
            message.text = text
            result = message
        return result

    def filterOutMessage(self, text, limits):
        return self.__msgFilters.chainOut(text, limits)

    def setActionCoolDown(self, actionID, coolDown):
        self.__coolDown.process(actionID, coolDown)

    def setBattleActionCoolDown(self, reqID, actionID, targetID=0, cooldownConfig=None):
        command = _ACTIONS.battleChatCommandFromActionID(actionID)
        if command and cooldownConfig is not None and command.name not in CHAT_COMMANDS_THAT_IGNORE_COOLDOWNS:
            currTime = BigWorld.time()
            addCoolDowns(currTime, self.__battleCmdCooldowns, command.id, command.name, command.cooldownPeriod, targetID, reqID, cooldownConfig)
        return

    def isActionInCoolDown(self, actionID):
        command = _ACTIONS.battleChatCommandFromActionID(actionID)
        if command:
            return [ cdData for cdData in self.__battleCmdCooldowns if cdData.cmdID == actionID ]
        return self.__coolDown.isInProcess(actionID)

    def getActionCooldownData(self, actionID):
        command = _ACTIONS.battleChatCommandFromActionID(actionID)
        if command:
            return [ cdData for cdData in self.__battleCmdCooldowns if cdData.cmdID == actionID ]
        return []

    def clearActionCoolDown(self, actionID):
        self.__coolDown.reset(actionID)

    def clearBattleActionCoolDown(self, requestID, actionID):
        command = _ACTIONS.battleChatCommandFromActionID(actionID)
        if command:
            removeList = [ cdData for cdData in self.__battleCmdCooldowns if cdData.reqID == requestID and cdData.cmdID == command.id ]
            if removeList:
                for dataForRemoval in removeList:
                    self.__battleCmdCooldowns.remove(dataForRemoval)

    def registerHandler(self, actionID, handler):
        handlers = self.__handlers[actionID]
        if handler in handlers:
            LOG_WARNING('Handler already is exist', actionID, handler)
        else:
            if not hasattr(handler, '__self__') or not isinstance(handler.__self__, ActionsHandler):
                LOG_ERROR('Class of handler is not subclass of ActionsHandler', handler)
                return
            if callable(handler):
                handlers.add(handler)
            else:
                LOG_ERROR('Handler is invalid', handler)

    def unregisterHandler(self, actionID, handler):
        handlers = self.__handlers[actionID]
        if handler in handlers:
            handlers.remove(handler)

    def __sendAction(self, actionID, reqID, args=None):
        player = BigWorld.player()
        if not player:
            LOG_ERROR('Player is not defined')
            return False
        player.base.messenger_onActionByClient_chat2(actionID, reqID, args or messageArgs())
        return True

    def __addActionToQueue(self, actionID, reqID, args=None):
        self.__queue.append((actionID, reqID, args))
        return True

    def __sendActionsFromQueue(self):
        invokedIDs = set()
        while self.__queue:
            actionID, reqID, args = self.__queue.pop()
            if actionID in invokedIDs:
                LOG_WARNING('Action is ignored, your must send action after event "showGUI" is invoked', actionID, reqID, args)
                continue
            self.__sendAction(actionID, reqID, args)
            invokedIDs.add(actionID)

    def __isCooldownInProcess(self, actionID, args=None):
        command = _ACTIONS.battleChatCommandFromActionID(actionID)
        if command:
            currTime = BigWorld.time()
            targetID = args['int32Arg1']
            sndrBlockReason = areSenderCooldownsActive(currTime, self.__battleCmdCooldowns, actionID, targetID)
            return command.name not in CHAT_COMMANDS_THAT_IGNORE_COOLDOWNS and sndrBlockReason is not None
        else:
            return self.__coolDown.isInProcess(actionID)

    def __getCooldownTime(self, actionID, args=None):
        command = _ACTIONS.battleChatCommandFromActionID(actionID)
        if command:
            currTime = BigWorld.time()
            targetID = args['int32Arg1']
            sndrBlockReason = areSenderCooldownsActive(currTime, self.__battleCmdCooldowns, actionID, targetID)
            cdTime = round(sndrBlockReason.cooldownEnd - currTime, 1) if sndrBlockReason is not None else 0
            return cdTime
        else:
            self.__coolDown.getTime(actionID)
            return

    def __shouldShowErrorMessage(self, actionID, args=None):
        command = _ACTIONS.battleChatCommandFromActionID(actionID)
        if command is None:
            return False
        else:
            currTime = BigWorld.time()
            targetID = args['int32Arg1']
            sndrBlockReason = areSenderCooldownsActive(currTime, self.__battleCmdCooldowns, actionID, targetID)
            return sndrBlockReason.cooldownType != CHAT_COMMAND_COOLDOWN_TYPE_IDS.TIMEFRAME_DATA_COOLDOWN if sndrBlockReason is not None else False

    def __skipReplayChat(self, actionID, reqID, args):
        replayCtrl = BattleReplay.g_replayCtrl
        reqVehID = args['int64Arg1']
        if actionID == _ACTIONS.ON_BATTLE_MESSAGE_BROADCAST and not replayCtrl.isAllyToObservedVehicle(reqVehID):
            return True
        else:
            if _ACTIONS.battleChatCommandFromActionID(actionID) is not None:
                if _ACTIONS.battleChatCommandFromActionID(actionID).name in (BATTLE_CHAT_COMMAND_NAMES.ATTACKING_ENEMY_WITH_SPG, BATTLE_CHAT_COMMAND_NAMES.ATTACK_ENEMY):
                    if replayCtrl.isAllyToObservedVehicle(reqVehID):
                        return True
                elif not replayCtrl.isAllyToObservedVehicle(reqVehID):
                    return True
            return False
Ejemplo n.º 22
0
class RibbonsAggregator(object):
    sessionProvider = dependency.descriptor(IBattleSessionProvider)

    def __init__(self):
        super(RibbonsAggregator, self).__init__()
        self.__feedbackProvider = None
        self.__vehicleStateCtrl = None
        self.__cache = _RibbonsCache()
        self.__accumulatedRibbons = _RibbonsCache()
        self.__rules = {}
        self.__idGenerator = SequenceIDGenerator()
        self.onRibbonAdded = Event.Event()
        self.onRibbonUpdated = Event.Event()
        self.__isStarted = False
        self.__isSuspended = False
        self.__isInPostmortemMode = False
        return

    def start(self):
        self.__isStarted = True
        if self.__feedbackProvider is None:
            self.__feedbackProvider = self.sessionProvider.shared.feedback
            self.__feedbackProvider.onPlayerFeedbackReceived += self._onPlayerFeedbackReceived
        if self.__vehicleStateCtrl is None:
            self.__vehicleStateCtrl = self.sessionProvider.shared.vehicleState
            self.__vehicleStateCtrl.onPostMortemSwitched += self._onPostMortemSwitched
            self.__vehicleStateCtrl.onRespawnBaseMoving += self.__onRespawnBaseMoving
        return

    def suspend(self):
        if self.__isStarted:
            self.__isSuspended = True

    def resume(self):
        if self.__isSuspended:
            self.__isSuspended = False

    def stop(self):
        self.__isStarted = False
        self.__isSuspended = False
        self.clearRibbonsData()
        if self.__feedbackProvider is not None:
            self.__feedbackProvider.onPlayerFeedbackReceived -= self._onPlayerFeedbackReceived
            self.__feedbackProvider = None
        if self.__vehicleStateCtrl is None:
            self.__vehicleStateCtrl.onPostMortemSwitched -= self._onPostMortemSwitched
            self.__vehicleStateCtrl.onRespawnBaseMoving -= self.__onRespawnBaseMoving
            self.__vehicleStateCtrl = None
        return

    def getRibbon(self, ribbonID):
        """
        Gets ribbon by the given ID.
        :param ribbonID: Ribbon ID.
        :return: ribbon or None.
        """
        return self.__cache.get(ribbonID, None)

    def resetRibbonData(self, ribbonID):
        """
        Reset ribbon's data by the given ID.
        :param ribbonID: ribbon ID
        """
        ribbon = self.__cache.pop(ribbonID)
        if ribbon is not None and ribbon.getType() in _ACCUMULATED_RIBBON_TYPES:
            self.__accumulatedRibbons.add(ribbon)
        return

    def clearRibbonsData(self):
        """
        Clears all cached ribbons.
        """
        self.__cache.clear()
        self.__accumulatedRibbons.clear()

    def _onPostMortemSwitched(self, noRespawnPossible, respawnAvailable):
        """
        Callback on switching to the postmortem mode  (see VehicleStateController).
        """
        self.__isInPostmortemMode = True

    def __onRespawnBaseMoving(self):
        """
        Callback on switching to alive state (see VehicleStateController).
        """
        self.__isInPostmortemMode = False

    def _onPlayerFeedbackReceived(self, events):
        """
        Callback on player feedback event (see BattleFeedbackAdaptor).
        
        :param events: list of PlayerFeedbackEvent
        """

        def _ribbonsGenerator(events):
            for e in events:
                r = _createRibbonFromPlayerFeedbackEvent(self.__idGenerator.next(), e)
                if r is not None:
                    yield r

            return

        self._aggregateRibbons(_ribbonsGenerator(events))

    def _aggregateRibbons(self, ribbons):
        """
        Aggregates ribbons according to some rules and converts them to appropriate battle
        efficiency events (see _FEEDBACK_EVENT_TO_RIBBON_CLS). Puts ribbons to the inner cache
        and triggers appropriate RibbonsAggregator events.
        
        Note that knowledge about aggregation is kept in each ribbon type/class (see canAggregate
        method).
        
        :param ribbons: list of Ribbon derived instances
        """
        aggregatedRibbons = {}
        for ribbon in ribbons:
            if self.__isSuspended and ribbon.getType() not in _ACCUMULATED_RIBBON_TYPES:
                continue
            if ribbon.getType() in aggregatedRibbons:
                temporaryRibbons = aggregatedRibbons[ribbon.getType()]
                for temporaryRibbon in temporaryRibbons:
                    if temporaryRibbon.aggregate(ribbon):
                        break
                else:
                    temporaryRibbons.append(ribbon)

            else:
                aggregatedRibbons[ribbon.getType()] = [ribbon]

        filteredRibbons = self.__filterRibbons(aggregatedRibbons)
        sortedRibbons = self.__getSortedList(filteredRibbons)
        for ribbon in sortedRibbons:
            etype = ribbon.getType()
            if etype in _NOT_CACHED_RIBBON_TYPES:
                self.__cache.add(ribbon)
                self.onRibbonAdded(ribbon)
            else:
                for cachedRibbon in self.__cache.iterByType(etype):
                    if cachedRibbon.aggregate(ribbon):
                        if not self.__isSuspended:
                            self.onRibbonUpdated(cachedRibbon)
                        break
                else:
                    if etype in _ACCUMULATED_RIBBON_TYPES:
                        for accumulatedRibbon in self.__accumulatedRibbons.iterByType(etype):
                            if accumulatedRibbon.aggregate(ribbon):
                                if not self.__isSuspended:
                                    self.__accumulatedRibbons.pop(accumulatedRibbon.getID())
                                    self.__cache.add(accumulatedRibbon)
                                    self.onRibbonAdded(accumulatedRibbon)
                                break
                        else:
                            if self.__isSuspended:
                                self.__accumulatedRibbons.add(ribbon)
                            else:
                                self.__cache.add(ribbon)
                                self.onRibbonAdded(ribbon)
                    elif not self.__isSuspended:
                        self.__cache.add(ribbon)
                        self.onRibbonAdded(ribbon)

    def __filterRibbons(self, ribbons):
        if self.__isInPostmortemMode:
            for rType in _RIBBON_TYPES_EXCLUDED_IN_POSTMORTEM:
                if rType in ribbons:
                    del ribbons[rType]

        if BATTLE_EFFICIENCY_TYPES.DESTRUCTION in ribbons:
            killRibbons = dict(((r.getVehicleID(), r) for r in ribbons[BATTLE_EFFICIENCY_TYPES.DESTRUCTION]))
            damageRibbons = dict(((t, ribbons[t]) for t in _RIBBON_TYPES_AGGREGATED_WITH_KILL_RIBBON if t in ribbons))
            for rType, tmpRibbons in damageRibbons.iteritems():
                filteredRibbons = []
                for tmpRibbon in tmpRibbons:
                    if tmpRibbon.getVehicleID() in killRibbons:
                        killRibbon = killRibbons[tmpRibbon.getVehicleID()]
                        killRibbon.setExtraValue(killRibbon.getExtraValue() + tmpRibbon.getExtraValue())
                    else:
                        filteredRibbons.append(tmpRibbon)

                ribbons[rType] = filteredRibbons

            excludedRibbons = dict(((t, ribbons[t]) for t in _RIBBON_TYPES_EXCLUDED_IF_KILL_RIBBON if t in ribbons))
            for rType, tmpRibbons in excludedRibbons.iteritems():
                filteredRibbons = [ r for r in tmpRibbons if r.getVehicleID() not in killRibbons ]
                ribbons[rType] = filteredRibbons

        return ribbons

    def __getSortedList(self, ribbons):
        """
        Sort events according to the following rules:
        1. Enemy kill ribbon should appear at the end of the list.
        2. Enemy detection ribbon should appear at the top of the list.
        
        NOTE: according to aggregation rules, the output ribbons don't contain duplicates of
        ribbons with the same type). If there are a few ribbons with the same type in the
        server response, use the last one.
        
        :param ribbons: dict of ribbons to be resorted according to rules described above
                        and converted to the list without duplicates.
        
        :return: Sorted ribbons list.
        """

        def _sortKey(ribbon):
            """
            Routine to be used for sorting ribbons by time. Ribbon ID is used for comparing because
            it grows with time.
            :param ribbon: _Ribbon derived instance.
            """
            return ribbon.getID()

        sortedRibons = []
        if ribbons:
            killRibbons = ribbons.pop(BATTLE_EFFICIENCY_TYPES.DESTRUCTION, None)
            detectionRibbons = ribbons.pop(BATTLE_EFFICIENCY_TYPES.DETECTION, None)
            if detectionRibbons is not None:
                sortedRibons.extend(sorted(detectionRibbons, key=_sortKey))
            remaningRibbons = []
            for newRibbons in ribbons.itervalues():
                remaningRibbons.extend(newRibbons)

            sortedRibons.extend(sorted(remaningRibbons, key=_sortKey))
            if killRibbons is not None:
                sortedRibons.extend(sorted(killRibbons, key=_sortKey))
        return sortedRibons
Ejemplo n.º 23
0
class BWChatProvider(object):

    def __init__(self):
        super(BWChatProvider, self).__init__()
        self.__handlers = defaultdict(set)
        self.__msgFilters = None
        self.__coolDown = _ChatCooldownManager()
        self.__idGen = SequenceIDGenerator()



    def clear(self):
        self.__handlers.clear()



    def doAction(self, actionID, args = None, response = False, skipCoolDown = False):
        player = BigWorld.player()
        (success, reqID,) = (False, 0)
        if player:
            if self.__coolDown.isInProcess(actionID):
                if not skipCoolDown:
                    g_messengerEvents.onServerErrorReceived(createCoolDownError(actionID))
            elif response:
                reqID = self.__idGen.next()
            player.base.messenger_onActionByClient_chat2(actionID, reqID, args or messageArgs())
            success = True
        else:
            LOG_ERROR('Player is not defined')
        return (success, reqID)



    def onActionReceived(self, actionID, reqID, args):
        handlers = self.__handlers[actionID]
        for handler in handlers:
            try:
                handler((actionID, reqID), args)
            except TypeError:
                LOG_ERROR('Handler has been invoked with error', handler)
                LOG_CURRENT_EXCEPTION()




    def setFilters(self, msgFilterChain):
        self.__msgFilters = msgFilterChain



    def filterInMessage(self, message):
        text = self.__msgFilters.chainIn(message.accountDBID, message.text)
        if not text:
            result = None
        else:
            message.text = text
            result = message
        return result



    def filterOutMessage(self, text, limits):
        return self.__msgFilters.chainOut(text, limits)



    def setActionCoolDown(self, actionID, coolDown):
        self.__coolDown.process(actionID, coolDown)



    def isActionInCoolDown(self, actionID):
        return self.__coolDown.isInProcess(actionID)



    def getActionCoolDown(self, actionID):
        return self.__coolDown.getTime(actionID)



    def clearActionCoolDown(self, actionID):
        self.__coolDown.reset(actionID)



    def registerHandler(self, actionID, handler):
        handlers = self.__handlers[actionID]
        if handler in handlers:
            LOG_WARNING('Handler already is exist', actionID, handler)
        elif not hasattr(handler, '__self__') or not isinstance(handler.__self__, ActionsHandler):
            LOG_ERROR('Class of handler is not subclass of ActionsHandler', handler)
            return 
        if callable(handler):
            handlers.add(handler)
        else:
            LOG_ERROR('Handler is invalid', handler)



    def unregisterHandler(self, actionID, handler):
        handlers = self.__handlers[actionID]
        if handler in handlers:
            handlers.remove(handler)
Ejemplo n.º 24
0
class SortiesCache(object):
    __selectedID = (0, 0)
    __rosterTypeID = 0

    def __init__(self, controller):
        self.__controller = weakref.proxy(controller)
        self.__idGen = SequenceIDGenerator()
        self.__cache = {}
        self.__idToIndex = {}
        self.__indexToID = {}
        self.__selectedUnit = None
        self.__isRequestInProcess = False
        self.__cooldownRequest = None
        return

    def __del__(self):
        LOG_DEBUG('Sortie cache deleted:', self)

    def clear(self):
        self.__controller = None
        self.__cache.clear()
        self.__idToIndex.clear()
        self.__indexToID.clear()
        self.__selectedUnit = None
        if self.__cooldownRequest is not None:
            BigWorld.cancelCallback(self.__cooldownRequest)
            self.__cooldownRequest = None
        return

    def start(self):
        fort = self.__controller.getFort()
        if fort:
            fort.onSortieChanged += self.__fort_onSortieChanged
            fort.onSortieRemoved += self.__fort_onSortieRemoved
            fort.onSortieUnitReceived += self.__fort_onSortieUnitReceived
            self.__cache = self.__buildCache()
        else:
            LOG_ERROR('Client fort is not found')

    def stop(self):
        fort = self.__controller.getFort()
        if fort:
            fort.onSortieChanged -= self.__fort_onSortieChanged
            fort.onSortieRemoved -= self.__fort_onSortieRemoved
            fort.onSortieUnitReceived -= self.__fort_onSortieUnitReceived
        self.clear()

    def setController(self, controller):
        self.__controller = weakref.proxy(controller)

    @property
    def isRequestInProcess(self):
        return self.__isRequestInProcess

    @classmethod
    def getSelectedID(cls):
        return cls.__selectedID

    def clearSelectedID(self):
        self.__selectedUnit = None
        self._setSelectedID((0, 0))
        return

    def setSelectedID(self, selectedID):
        if selectedID not in self.__cache:
            LOG_WARNING('Item is not found in cache', selectedID)
            return False
        else:
            self.__selectedUnit = None
            self._setSelectedID(selectedID)
            if BigWorld.player().isLongDisconnectedFromCenter:
                self.__controller._listeners.notify('onSortieUnitReceived', self.__getClientIdx(selectedID))
                return True
            unit = self.getSelectedUnit()
            if unit and not self.__cache[selectedID]._isDirty:
                self.__controller._listeners.notify('onSortieUnitReceived', self.__getClientIdx(selectedID))
            else:
                self._requestSortieUnit(selectedID)
            return True

    @classmethod
    def getRosterTypeID(cls):
        return cls.__rosterTypeID

    def setRosterTypeID(self, rosterTypeID):
        result = self._setRosterTypeID(rosterTypeID)
        if result:
            self.__cache = self.__buildCache()
        return result

    def getItem(self, sortieID):
        try:
            item = self.__cache[sortieID]
        except KeyError:
            LOG_ERROR('Item not found in cache', sortieID)
            item = None

        return item

    def getUnitByIndex(self, index):
        unit = None
        if index in self.__indexToID:
            sortieID = self.__indexToID[index]
            unit = self.__getUnit(sortieID)
        return unit

    def getSelectedUnit(self):
        return self.__getUnit(self.getSelectedID())

    def getIterator(self):
        for item in self.__cache.itervalues():
            if item.filter(self.__rosterTypeID):
                yield item

    def _requestSortieUnit(self, selectedID):
        Waiting.show('fort/sortie/get')
        if self.__cooldownRequest is not None:
            Waiting.hide('fort/sortie/get')
            BigWorld.cancelCallback(self.__cooldownRequest)
            self.__cooldownRequest = None
        ctx = RequestSortieUnitCtx(waitingID='', *selectedID)

        def requester():
            self.__cooldownRequest = None
            self.__isRequestInProcess = True
            self.__controller.request(ctx, self.__requestCallback)
            return

        if self.__controller._cooldown.isInProcess(ctx.getRequestType()):
            self.__cooldownRequest = BigWorld.callback(self.__controller._cooldown.getTime(ctx.getRequestType()), requester)
        else:
            requester()
        return

    @classmethod
    def _setSelectedID(cls, selectedID):
        result = False
        if selectedID != cls.__selectedID and len(selectedID) == 2:
            cls.__selectedID = selectedID
            result = True
        return result

    @classmethod
    def _setRosterTypeID(cls, rosterTypeID):
        result = False
        if rosterTypeID != cls.__rosterTypeID:
            cls.__rosterTypeID = rosterTypeID
            result = True
        return result

    @classmethod
    def _removeStoredData(cls):
        cls.__selectedID = (0, 0)
        cls.__rosterTypeID = 0

    def __buildCache(self):
        cache = {}
        fort = self.__controller.getFort()
        if not fort:
            LOG_WARNING('Client fort is not found')
            return cache
        sorties = fort.getSorties()
        selectedID = self.getSelectedID()
        found = False
        for sortieID, sortie in sorties.iteritems():
            item = SortieItem(sortieID, sortie)
            if not found and item.getID() == selectedID:
                found = True
            cache[sortieID] = item

        if not found:
            self.clearSelectedID()
        return cache

    def __updateItem(self, sortieID, fort):
        sortie = fort.getSortieShortData(*sortieID)
        if sortie is None:
            LOG_ERROR('Sortie is not found', sortieID, fort.sorties)
            return
        else:
            if sortieID in self.__cache:
                item = self.__cache[sortieID]
                item._updateItemData(sortie)
                if item._isDirty and self.__selectedID == item.getID() and item.filter(self.getRosterTypeID()):
                    self.__selectedUnit = None
                    self._requestSortieUnit(sortieID)
            else:
                item = SortieItem(sortieID, sortie)
                self.__cache[sortieID] = item
            return item

    def __requestCallback(self, _):
        Waiting.hide('fort/sortie/get')
        self.__isRequestInProcess = False

    def __removeItem(self, sortieID):
        result = False
        if sortieID in self.__cache:
            self.__cache.pop(sortieID)
            result = True
        if self.getSelectedID() == sortieID:
            self.clearSelectedID()
        clientIdx = self.__idToIndex.pop(sortieID, None)
        if clientIdx is not None:
            self.__indexToID.pop(clientIdx, None)
        return result

    def __getClientIdx(self, sortieID):
        if sortieID == (0, 0):
            return 0
        if sortieID not in self.__idToIndex:
            clientIdx = self.__idGen.next()
            self.__idToIndex[sortieID] = clientIdx
            self.__indexToID[clientIdx] = sortieID
        else:
            clientIdx = self.__idToIndex[sortieID]
        return clientIdx

    def __getUnit(self, sortieID):
        fort = self.__controller.getFort()
        if not fort:
            LOG_WARNING('Client fort is not found')
            return
        else:
            isSelected = self.getSelectedID() == sortieID
            if isSelected and self.__selectedUnit is not None:
                return self.__selectedUnit
            unit = fort.getSortieUnit(*sortieID)
            if isSelected:
                self.__selectedUnit = unit
            return unit

    def __fort_onSortieChanged(self, unitMgrID, peripheryID):
        fort = self.__controller.getFort()
        sortieID = (unitMgrID, peripheryID)
        if fort:
            item = self.__updateItem(sortieID, fort)
            if item:
                self.__controller._listeners.notify('onSortieChanged', self, item)

    def __fort_onSortieRemoved(self, unitMgrID, peripheryID):
        sortieID = (unitMgrID, peripheryID)
        if self.__removeItem(sortieID):
            self.__controller._listeners.notify('onSortieRemoved', self, sortieID)

    def __fort_onSortieUnitReceived(self, unitMgrID, peripheryID):
        fort = self.__controller.getFort()
        sortieID = (unitMgrID, peripheryID)
        if fort:
            if unitMgrID in self.__cache:
                self.__cache[sortieID]._isDirty = False
            if self.getSelectedID() == sortieID:
                self.__selectedUnit = None
            self.__controller._listeners.notify('onSortieUnitReceived', self.__getClientIdx(sortieID))
        return
Ejemplo n.º 25
0
class ClientChat(object):
    __dataProcessors = ['_ClientChat__dataTimeProcessor', '_ClientChat__inviteDataTimeProcessor', '_ClientChat__systemMessageTimeProcessor']
    __actionHandlers = {CHAT_ACTIONS.receiveInvite.index(): '_ClientChat__onReceiveInvite'}

    def __init__(self):
        raise isinstance(self, BigWorld.Entity) or AssertionError
        self.__chatActionCallbacks = {}
        self._idGen = SequenceIDGenerator()

    def acquireRequestID(self):
        return self._idGen.next()

    def requestSystemChatChannels(self):
        self.__baseChatCommand(CHAT_COMMANDS.requestSystemChatChannels)

    def findChatChannels(self, sample, requestID = None):
        if requestID is None:
            requestID = self.acquireRequestID()
        try:
            self.__baseChatCommand(CHAT_COMMANDS.findChatChannels, stringArg1=sample, ignoreCooldown=False, requestID=requestID)
        except ChatError as ex:
            self._processChatError(CHAT_ACTIONS.requestChannels, 0, ex, requestID=requestID)

        return

    def getChannelInfoById(self, channelId):
        self.__baseChatCommand(CHAT_COMMANDS.getChannelInfoById, int64Arg=channelId)

    def requestChatChannelMembers(self, channelId):
        self.__baseChannelChatCommand(channelId, CHAT_COMMANDS.requestChatChannelMembers)

    def requestChatChannelMembersCount(self, channelId):
        self.__baseChannelChatCommand(channelId, CHAT_COMMANDS.getMembersCount)

    def createChatChannel(self, channelName, password = None):
        try:
            self.__baseChatCommand(CHAT_COMMANDS.createChatChannel, stringArg1=channelName, stringArg2=password if password is not None else '', ignoreCooldown=False)
        except ChatError as ex:
            self._processChatError(CHAT_COMMANDS.createChatChannel, 0, ex)

        return

    def destroyChatChannel(self, channelId):
        self.__baseChannelChatCommand(channelId, CHAT_COMMANDS.destroyChatChannel)

    def enterChat(self, channelId, password = None):
        self.__baseChannelChatCommand(channelId, CHAT_COMMANDS.enterChatChannel, stringArg1=password if password is not None else '')
        return

    def broadcast(self, channelId, message):
        if not len(message) or message.isspace():
            return
        message = message.rstrip()
        if not isCommandMessage(message):
            try:
                self.__baseChannelChatCommand(channelId, CHAT_COMMANDS.broadcast, stringArg1=message, ignoreCooldown=False)
            except ChatError as ex:
                self._processChatError(CHAT_ACTIONS.broadcast, channelId, ex)

        else:
            try:
                command, int64Arg, int16Arg, stringArg1, stringArg2 = parseCommandMessage(message)
                self.__baseChannelChatCommand(channelId, command, int64Arg, int16Arg, stringArg1, stringArg2, ignoreCooldown=False)
            except ChatCommandError as ex:
                self._processChatError(CHAT_ACTIONS.userChatCommand, channelId, ex)

    def leaveChat(self, channelId):
        self.__baseChannelChatCommand(channelId, CHAT_COMMANDS.leaveChatChannel)

    def onChatActionFailure(self, actionData):
        MessengerEntry.g_instance.protos.BW.onChatActionFailure(actionData)

    def onChatAction(self, chatActionData):
        global g_replayCtrl
        if g_replayCtrl is None:
            import BattleReplay
            g_replayCtrl = BattleReplay.g_replayCtrl
        if g_replayCtrl.isRecording:
            g_replayCtrl.cancelSaveCurrMessage()
        elif g_replayCtrl.isPlaying:
            g_replayCtrl.onChatAction(chatActionData)
            return
        for processor in self.__dataProcessors:
            getattr(self, processor)(chatActionData)

        if CHAT_RESPONSES[chatActionData['actionResponse']] != CHAT_RESPONSES.success:
            self.onChatActionFailure(chatActionData)
        else:
            hanlerName = self.__actionHandlers.get(chatActionData['action'], None)
            if hanlerName:
                getattr(self, hanlerName)(chatActionData)
            chId = chatActionData['channel']
            commonCallbacks = self.__getChatActionCallbacks(CHAT_ACTIONS[chatActionData['action']], 0)
            commonCallbacks(chatActionData)
            if chId != 0:
                channelCallbacks = self.__getChatActionCallbacks(CHAT_ACTIONS[chatActionData['action']], chId)
                channelCallbacks(chatActionData)
        return

    def requestLastSysMessages(self):
        self.__baseChatCommand(CHAT_COMMANDS.requestLastSysMessages)

    def findUsers(self, userNamePattern, onlineMode = None, requestID = None):
        if onlineMode is None:
            searchMode = USER_SEARCH_MODE.ALL
        elif onlineMode:
            searchMode = USER_SEARCH_MODE.ONLINE
        else:
            searchMode = USER_SEARCH_MODE.OFFLINE
        self.__baseChatCommand(CHAT_COMMANDS.findUser, int16Arg=searchMode, stringArg1=userNamePattern, requestID=requestID)
        return

    def requestUsersRoster(self, flags = 0):
        self.__baseChatCommand(CHAT_COMMANDS.requestUsersRoster, int16Arg=flags)

    def logVivoxLogin(self):
        self.__baseChatCommand(CHAT_COMMANDS.logVivoxLogin)

    def requestFriendStatus(self, friendID = -1):
        self.__baseChatCommand(CHAT_COMMANDS.requestFriendStatus, int64Arg=friendID)

    def addFriend(self, friendID, friendName):
        self.__baseChatCommand(CHAT_COMMANDS.addFriend, int64Arg=friendID, stringArg1=friendName)

    def createPrivate(self, friendID, friendName):
        self.__baseChatCommand(CHAT_COMMANDS.createPrivate, int64Arg=friendID, stringArg1=friendName)

    def removeFriend(self, friendID):
        self.__baseChatCommand(CHAT_COMMANDS.removeFriend, int64Arg=friendID)

    def addIgnored(self, ignoredID, ignoredName):
        self.__baseChatCommand(CHAT_COMMANDS.addIgnored, int64Arg=ignoredID, stringArg1=ignoredName)

    def removeIgnored(self, ignoredID):
        self.__baseChatCommand(CHAT_COMMANDS.removeIgnored, int64Arg=ignoredID)

    def setMuted(self, mutedID, mutedName):
        self.__baseChatCommand(CHAT_COMMANDS.setMuted, int64Arg=mutedID, stringArg1=mutedName)

    def unsetMuted(self, mutedID):
        self.__baseChatCommand(CHAT_COMMANDS.unsetMuted, int64Arg=mutedID)

    def createPrebattleInvite(self, receiverName, auxText, prebattleID, prebattleType, requestID = None):
        self.__baseInviteCommand(CHAT_COMMANDS.createInvite, INVITE_TYPES.PREBATTLE, receiverName, prebattleID, prebattleType, stringArg2=auxText, requestID=requestID)

    def createBarterInvite(self, receiverName, auxText, itemID, requestID = None):
        self.__baseInviteCommand(CHAT_COMMANDS.createInvite, INVITE_TYPES.BARTER, receiverName, itemID, stringArg2=auxText, requestID=requestID)

    def acceptPrebattleInvite(self, inviteID, requestID = None):
        if requestID is None:
            requestID = self.acquireRequestID()
        self.base.ackCommand(requestID, CHAT_COMMANDS.acceptInvite.index(), time.time(), inviteID, -1)
        return

    def rejectInvite(self, inviteID, requestID = None):
        if requestID is None:
            requestID = self.acquireRequestID()
        self.base.ackCommand(requestID, CHAT_COMMANDS.rejectInvite.index(), time.time(), inviteID, -1)
        return

    def getActiveInvites(self):
        self.__baseInviteCommand(CHAT_COMMANDS.getActiveInvites)

    def getArchiveInvites(self):
        self.__baseInviteCommand(CHAT_COMMANDS.getArchiveInvites)

    def requestVOIPCredentials(self, changePwd = 0):
        self.__baseChatCommand(CHAT_COMMANDS.requestVOIPCredentials, int16Arg=changePwd)

    def subscribeChatAction(self, callback, action, channelId = None):
        cbs = self.__getChatActionCallbacks(action, channelId)
        cbs += callback

    def unsubscribeChatAction(self, callback, action, channelId = None):
        cbs = self.__getChatActionCallbacks(action, channelId)
        cbs -= callback

    def setChatActionsCallbacks(self, callbacks):
        self.__chatActionCallbacks = callbacks

    def sendChannelChatCommand(self, channelID, command, int64Arg = 0, int16Arg = 0, stringArg1 = '', stringArg2 = ''):
        self.__baseChannelChatCommand(channelID, command, int64Arg, int16Arg, stringArg1, stringArg2)

    def _processChatError(self, action, channelId, chatError, requestID = -1):
        if isinstance(chatError, ChatError):
            actionData = chatError.messageArgs if chatError.messageArgs is not None else chatError.message
        else:
            actionData = ''
        chatAction = buildChatActionData(action=action, requestID=requestID, channelId=channelId, originatorNickName=self.name, data=actionData, actionResponse=chatError.response if isinstance(chatError, ChatError) else CHAT_RESPONSES.internalError)
        self.onChatAction(chatAction)
        return

    def __getChatActionCallbacks(self, action, channelId):
        channelId = channelId if channelId is not None else 0
        key = (action, channelId)
        if key not in self.__chatActionCallbacks:
            handlers = self.__chatActionCallbacks[key] = Event.Event()
        else:
            handlers = self.__chatActionCallbacks[key]
        return handlers

    def __receiveStreamedData(self, streamID, data):
        failed = False
        try:
            data = zlib.decompress(data)
            chatMessages = cPickle.loads(data)
        except:
            LOG_CURRENT_EXCEPTION()
            failed = True

        if not failed:
            chIds = sorted(chatMessages.keys(), cmp=lambda x, y: cmp(abs(x), abs(y)))
            for chId in chIds:
                channelQueue = chatMessages.get(chId, deque())
                while True:
                    try:
                        actionData = channelQueue.popleft()
                        self.onChatAction(actionData)
                    except IndexError:
                        break

        self.__baseChatCommand(CHAT_COMMANDS.initAck, int64Arg=streamID, int16Arg=failed)

    def __baseChannelChatCommand(self, channelID, command, int64Arg = 0, int16Arg = 0, stringArg1 = '', stringArg2 = '', ignoreCooldown = True):
        if 0 == channelID:
            LOG_ERROR('Can`t execute chat channel command for channelId: %s' % (channelID,))
        else:
            if chat_shared.isOperationInCooldown(chat_shared.g_chatCooldownData, command):
                if ignoreCooldown:
                    return
                raise ChatCommandInCooldown(command)
            self.__baseChatCommand(command, channelID, int64Arg, int16Arg, stringArg1, stringArg2)

    def __baseChatCommand(self, command, channelID = 0, int64Arg = 0, int16Arg = 0, stringArg1 = '', stringArg2 = '', ignoreCooldown = True, requestID = None):
        if requestID is None:
            requestID = self.acquireRequestID()
        if chat_shared.isOperationInCooldown(chat_shared.g_chatCooldownData, command):
            if not ignoreCooldown:
                raise ChatCommandInCooldown(command)
        self.base.chatCommandFromClient(requestID, command.index(), channelID, int64Arg, int16Arg, stringArg1, stringArg2)
        return

    def __baseInviteCommand(self, command, inviteType = None, receiverName = '', int64Arg = 0, int16Arg = 0, stringArg1 = '', stringArg2 = '', requestID = None):
        if requestID is None:
            requestID = self.acquireRequestID()
        self.base.inviteCommand(requestID, command.index(), inviteType.index() if inviteType is not None else -1, receiverName, int64Arg, int16Arg, stringArg1, stringArg2)
        return

    def __onReceiveInvite(self, chatActionData):
        inviteID = chatActionData['data'].get('id', None)
        receivedAt = chatActionData['data'].get('received_at', None)
        if inviteID is not None and receivedAt is None:
            requestID = self.acquireRequestID()
            self.base.ackCommand(requestID, CHAT_COMMANDS.inviteReceived.index(), time.time(), inviteID, -1)
        return

    def __dataTimeProcessor(self, actionData):
        actionData['time'] = tm.makeLocalServerTime(actionData['time'])
        actionData['sentTime'] = tm.makeLocalServerTime(actionData['sentTime'])

    def __inviteDataTimeProcessor(self, actionData):
        isInviteAction = CHAT_ACTIONS[actionData['action']] in (CHAT_ACTIONS.createInvite, CHAT_ACTIONS.receiveInvite, CHAT_ACTIONS.receiveArchiveInvite)
        if isInviteAction:
            if actionData.has_key('data'):
                inviteData = actionData['data']
                if 'sent_at' in inviteData:
                    inviteData['sent_at'] = tm.utcToLocalDatetime(tm.makeLocalServerDatetime(inviteData['sent_at']))
                if 'received_at' in inviteData:
                    inviteData['received_at'] = tm.utcToLocalDatetime(tm.makeLocalServerDatetime(inviteData['received_at']))
                if 'processed_at' in inviteData:
                    inviteData['processed_at'] = tm.utcToLocalDatetime(tm.makeLocalServerDatetime(inviteData['processed_at']))

    def __systemMessageTimeProcessor(self, actionData):
        isSystemMessage = CHAT_ACTIONS[actionData['action']] in (CHAT_ACTIONS.personalSysMessage, CHAT_ACTIONS.sysMessage)
        if isSystemMessage:
            if actionData.has_key('data'):
                messageData = actionData['data']
                messageType = messageData['type']
                if 'created_at' in messageData:
                    messageData['created_at'] = tm.makeLocalServerDatetime(messageData['created_at'])
                if 'finished_at' in messageData:
                    messageData['finished_at'] = tm.makeLocalServerDatetime(messageData['finished_at'])
                if 'started_at' in messageData:
                    messageData['started_at'] = tm.makeLocalServerDatetime(messageData['started_at'])
                if messageType == SYS_MESSAGE_TYPE.serverReboot.index():
                    messageData['data'] = tm.makeLocalServerDatetime(messageData['data'])
                elif messageType == SYS_MESSAGE_TYPE.battleResults.index():
                    messageData['data']['arenaCreateTime'] = tm.makeLocalServerTime(messageData['data']['arenaCreateTime'])
                elif messageType == SYS_MESSAGE_TYPE.goldReceived.index():
                    messageData['data']['date'] = tm.makeLocalServerTime(messageData['data']['date'])
                elif messageType in (SYS_MESSAGE_TYPE.accountTypeChanged.index(),
                 SYS_MESSAGE_TYPE.premiumBought.index(),
                 SYS_MESSAGE_TYPE.premiumExtended.index(),
                 SYS_MESSAGE_TYPE.premiumExpired.index()):
                    if 'expiryTime' in messageData['data']:
                        messageData['data']['expiryTime'] = tm.makeLocalServerTime(messageData['data']['expiryTime'])
Ejemplo n.º 26
0
class BrowserController(IBrowserController):
    _BROWSER_TEXTURE = 'BrowserBg'
    _ALT_BROWSER_TEXTURE = 'AltBrowserBg'

    def __init__(self):
        super(BrowserController, self).__init__()
        self.__browsers = {}
        self.__browsersCallbacks = {}
        self.__browserCreationCallbacks = {}
        self.__browserIDGenerator = SequenceIDGenerator()
        self.__eventMgr = Event.EventManager()
        self.onBrowserAdded = Event.Event(self.__eventMgr)
        self.onBrowserDeleted = Event.Event(self.__eventMgr)
        self.__urlMacros = URLMarcos()
        self.__pendingBrowsers = {}
        self.__creatingBrowserID = None
        self.__filters = _getGlobalFilters()
        return

    def fini(self):
        self.__filters = None
        self.__eventMgr.clear()
        self.__eventMgr = None
        self.__urlMacros.clear()
        self.__urlMacros = None
        self.__browsersCallbacks.clear()
        self.__browsersCallbacks = None
        self.__browsers.clear()
        self.__browsers = None
        self.__pendingBrowsers.clear()
        self.__pendingBrowsers = None
        self.__browserIDGenerator = None
        super(BrowserController, self).fini()
        return

    def onAvatarBecomePlayer(self):
        self.__stop()

    def onDisconnected(self):
        self.__stop()

    def addFilterHandler(self, handler):
        """ Adds given @handler to the browser urls filter chain. Calls
        it if there is a @tag in url onto opened browser page.
        Handler should receive url and list of client-specific tags,
        return bool as flag that routine have to stop
        """
        self.__filters.add(handler)

    def removeFilterHandler(self, handler):
        """ Remove given @handler from filtering chain. Handler description
        can be seen in addFilterhandler method doc-string
        """
        self.__filters.discard(handler)

    @async
    @process
    def load(self,
             url=None,
             title=None,
             showActionBtn=True,
             showWaiting=True,
             browserID=None,
             isAsync=False,
             browserSize=None,
             isDefault=True,
             callback=None,
             showCloseBtn=False,
             useBrowserWindow=True,
             isModal=False,
             showCreateWaiting=False,
             handlers=None,
             showBrowserCallback=None,
             isSolidBorder=False):
        if constants.IS_BOOTCAMP_ENABLED:
            from bootcamp.Bootcamp import g_bootcamp
            if g_bootcamp.isRunning():
                return
        if showCreateWaiting:
            Waiting.show('browser/init')
        url = yield self.__urlMacros.parse(url or GUI_SETTINGS.browser.url)
        suffix = yield self.__urlMacros.parse(GUI_SETTINGS.browser.params)
        concatenator = '&' if '?' in url else '?'
        if suffix not in url:
            url = concatenator.join([url, suffix])
        size = browserSize or BROWSER.SIZE
        webBrowserID = browserID
        if browserID is None:
            browserID = self.__browserIDGenerator.next()
            webBrowserID = browserID
        elif type(browserID) is not int:
            webBrowserID = self.__browserIDGenerator.next()
        ctx = {
            'url': url,
            'title': title,
            'showActionBtn': showActionBtn,
            'showWaiting': showWaiting,
            'browserID': browserID,
            'size': size,
            'isAsync': isAsync,
            'showCloseBtn': showCloseBtn,
            'showWindow': useBrowserWindow,
            'alias': VIEW_ALIAS.BROWSER_WINDOW_MODAL
            if isModal else VIEW_ALIAS.BROWSER_WINDOW,
            'showCreateWaiting': showCreateWaiting,
            'handlers': handlers,
            'showBrowserCallback': showBrowserCallback,
            'isSolidBorder': isSolidBorder
        }
        texture = browserID not in self.__browsers and browserID not in self.__pendingBrowsers and self._BROWSER_TEXTURE
        app = g_appLoader.getApp()
        if not app:
            raise AssertionError('Application can not be None')
            browser = WebBrowser(webBrowserID,
                                 app,
                                 texture,
                                 size,
                                 url,
                                 handlers=self.__filters)
            self.__browsers[browserID] = browser
            if self.__isCreatingBrowser():
                LOG_BROWSER('CTRL: Queueing a browser creation: ', browserID,
                            url)
                self.__pendingBrowsers[browserID] = ctx
            else:
                self.__createBrowser(ctx)
        elif browserID in self.__pendingBrowsers:
            LOG_BROWSER('CTRL: Re-queuing a browser creation, overriding: ',
                        browserID, url)
            self.__pendingBrowsers[browserID] = ctx
        elif browserID in self.__browsers:
            LOG_BROWSER('CTRL: Re-navigating an existing browser: ', browserID,
                        url)
            browser = self.__browsers[browserID]
            browser.navigate(url)
            browser.changeTitle(title)
        callback(browserID)
        return

    def getBrowser(self, browserID):
        return self.__browsers.get(browserID)

    def delBrowser(self, browserID):
        if browserID in self.__browsers:
            LOG_BROWSER('CTRL: Deleting a browser: ', browserID)
            browser = self.__browsers.pop(browserID)
            self.__clearCallbacks(browserID, browser, True)
            browser.destroy()
            if self.__creatingBrowserID == browserID:
                self.__creatingBrowserID = None
                self.__tryCreateNextPendingBrowser()
            if browserID in self.__pendingBrowsers:
                del self.__pendingBrowsers[browserID]
        self.onBrowserDeleted(browserID)
        return

    def __isCreatingBrowser(self):
        return self.__creatingBrowserID is not None

    def __createDone(self, ctx):
        LOG_BROWSER('CTRL: Finished creating a browser: ',
                    self.__creatingBrowserID)
        if ctx['showCreateWaiting']:
            Waiting.hide('browser/init')

    def __tryCreateNextPendingBrowser(self):
        self.__creatingBrowserID = None
        if len(self.__pendingBrowsers) > 0:
            nextCtx = self.__pendingBrowsers.popitem()[1]
            self.__createBrowser(nextCtx)
        return

    def __createBrowser(self, ctx):
        browserID = ctx['browserID']
        LOG_BROWSER('CTRL: Creating a browser: ', browserID, ctx['url'])
        self.__creatingBrowserID = browserID
        if not self.__browsers[browserID].create():
            LOG_BROWSER('CTRL: Failed the create step: ', browserID)
            self.delBrowser(browserID)
            self.__tryCreateNextPendingBrowser()
            return
        else:
            self.onBrowserAdded(browserID)

            def createBrowserTimeout():
                LOG_BROWSER('CTRL: Browser create timed out')
                createNextBrowser()

            timeoutid = BigWorld.callback(30.0, createBrowserTimeout)

            def createNextBrowser():
                LOG_BROWSER('CTRL: Triggering create of next browser from: ',
                            browserID)
                BigWorld.cancelCallback(timeoutid)
                creation = self.__browserCreationCallbacks.pop(browserID, None)
                if creation is not None:
                    self.__browsers[
                        browserID].onCanCreateNewBrowser -= creation
                BigWorld.callback(1.0, self.__tryCreateNextPendingBrowser)
                return

            def failedCreationCallback(url):
                LOG_BROWSER('CTRL: Failed a creation: ', browserID, url)
                self.__clearCallbacks(browserID, self.__browsers[browserID],
                                      False)
                self.delBrowser(browserID)

            def successfulCreationCallback(url, isLoaded, httpStatusCode=None):
                LOG_BROWSER('CTRL: Ready to show: ', browserID, isLoaded, url)
                self.__clearCallbacks(browserID, self.__browsers[browserID],
                                      False)
                if isLoaded:
                    self.__showBrowser(browserID, ctx)
                else:
                    LOG_WARNING('Browser request url was not loaded!', url)
                g_eventBus.handleEvent(
                    BrowserEvent(BrowserEvent.BROWSER_CREATED, ctx=ctx))
                self.__createDone(ctx)

            self.__browsers[
                browserID].onCanCreateNewBrowser += createNextBrowser
            self.__browserCreationCallbacks[browserID] = createNextBrowser
            self.__browsers[
                browserID].onFailedCreation += failedCreationCallback
            if ctx['isAsync']:
                self.__browsersCallbacks[browserID] = (
                    None, successfulCreationCallback, failedCreationCallback)
                self.__browsers[
                    browserID].onLoadEnd += successfulCreationCallback
            else:
                self.__browsersCallbacks[browserID] = (
                    successfulCreationCallback, None, failedCreationCallback)
                self.__browsers[
                    browserID].onReady += successfulCreationCallback
            return

    def __stop(self):
        while self.__browsers:
            browserID, browser = self.__browsers.popitem()
            self.__clearCallbacks(browserID, browser, True)
            browser.destroy()

    def __clearCallbacks(self, browserID, browser, incDelayedCreation):
        ready, loadEnd, failed = self.__browsersCallbacks.pop(
            browserID, (None, None, None))
        if browser is not None:
            if failed is not None:
                browser.onFailedCreation -= failed
            if ready is not None:
                browser.onReady -= ready
            if loadEnd is not None:
                browser.onLoadEnd -= loadEnd
        if incDelayedCreation:
            creation = self.__browserCreationCallbacks.pop(browserID, None)
            if browser is not None and creation is not None:
                browser.onCanCreateNewBrowser -= creation
        return

    def __showBrowser(self, browserID, ctx):
        LOG_BROWSER('CTRL: Showing a browser: ', browserID, ctx['url'])
        if ctx.get('showWindow'):
            alias = ctx['alias']
            g_eventBus.handleEvent(
                LoadViewEvent(alias, getViewName(alias, browserID), ctx=ctx),
                EVENT_BUS_SCOPE.LOBBY)
        showBrowserCallback = ctx.get('showBrowserCallback')
        if showBrowserCallback:
            showBrowserCallback()
Ejemplo n.º 27
0
class InvitesManager(UsersInfoHelper):
    __clanInfo = None

    def __init__(self, loader):
        super(InvitesManager, self).__init__()
        self.__loader = loader
        self._IDGen = SequenceIDGenerator()
        self._IDMap = {}
        self.__invites = {}
        self.__unreadInvitesCount = 0
        self.__eventManager = Event.EventManager()
        self.__acceptChain = None
        self.onInvitesListInited = Event.Event(self.__eventManager)
        self.onReceivedInviteListModified = Event.Event(self.__eventManager)
        self.onSentInviteListModified = Event.Event(self.__eventManager)
        self.__isInBattle = False
        return

    def __del__(self):
        LOG_DEBUG('InvitesManager deleted')
        super(InvitesManager, self).__del__()

    def init(self):
        self.__inited = PRB_INVITES_INIT_STEP.UNDEFINED
        g_messengerEvents.users.onUsersListReceived += self.__me_onUsersListReceived
        g_playerEvents.onPrebattleInvitesChanged += self.__pe_onPrebattleInvitesChanged
        g_playerEvents.onPrebattleInvitationsChanged += self.__pe_onPrebattleInvitationsChanged
        g_playerEvents.onPrebattleInvitesStatus += self.__pe_onPrebattleInvitesStatus

    def fini(self):
        self.__clearAcceptChain()
        self.__inited = PRB_INVITES_INIT_STEP.UNDEFINED
        self.__loader = None
        g_messengerEvents.users.onUsersListReceived -= self.__me_onUsersListReceived
        g_playerEvents.onPrebattleInvitationsChanged -= self.__pe_onPrebattleInvitationsChanged
        g_playerEvents.onPrebattleInvitesChanged -= self.__pe_onPrebattleInvitesChanged
        g_playerEvents.onPrebattleInvitesStatus -= self.__pe_onPrebattleInvitesStatus
        self.clear()
        return

    def start(self):
        self.__isInBattle = False
        if self.__inited & PRB_INVITES_INIT_STEP.STARTED == 0:
            self.__inited |= PRB_INVITES_INIT_STEP.STARTED
            if self.__inited == PRB_INVITES_INIT_STEP.INITED:
                self.onInvitesListInited()

    def clear(self):
        self.__inited = PRB_INVITES_INIT_STEP.UNDEFINED
        self.__clearInvites()
        self._IDMap = {}
        self.__eventManager.clear()

    def onAvatarBecomePlayer(self):
        self.__isInBattle = True
        self.__clearAcceptChain()

    @storage_getter('users')
    def users(self):
        return None

    def isInited(self):
        return self.__inited == PRB_INVITES_INIT_STEP.INITED

    def acceptInvite(self, inviteID, postActions = None):
        try:
            invite = self.__invites[inviteID]
        except KeyError:
            LOG_ERROR('Invite ID is invalid', inviteID, self._IDMap)
            return

        self.__clearAcceptChain()
        if not postActions:
            invite.accept()
        else:
            self.__acceptChain = _AcceptInvitesPostActions(invite, postActions)
            self.__acceptChain.onStopped += self.__accept_onPostActionsStopped
            self.__acceptChain.start()
        if self.__unreadInvitesCount > 0:
            self.__unreadInvitesCount -= 1

    def declineInvite(self, inviteID):
        try:
            invite = self.__invites[inviteID]
        except KeyError:
            LOG_ERROR('Invite ID is invalid', inviteID, self._IDMap)
            return

        invite.decline()
        if self.__unreadInvitesCount > 0:
            self.__unreadInvitesCount -= 1

    def revokeInvite(self, inviteID):
        try:
            invite = self.__invites[inviteID]
        except KeyError:
            LOG_ERROR('Invite ID is invalid', inviteID, self._IDMap)
            return

        invite.revoke()
        if self.__unreadInvitesCount > 0:
            self.__unreadInvitesCount -= 1

    def canAcceptInvite(self, invite):
        result = False
        if invite.alwaysAvailable is True:
            result = True
        elif invite.clientID in self.__invites:
            dispatcher = self.__loader.getDispatcher()
            if dispatcher:
                prbFunctional = dispatcher.getPrbFunctional()
                unitFunctional = dispatcher.getUnitFunctional()
                preQueueFunctional = dispatcher.getPreQueueFunctional()
                if invite.alreadyJoined:
                    return False
                if prbFunctional and prbFunctional.hasLockedState() or unitFunctional and unitFunctional.hasLockedState() or preQueueFunctional and preQueueFunctional.hasLockedState():
                    return False
            another = invite.anotherPeriphery
            if another:
                if g_preDefinedHosts.periphery(invite.peripheryID) is None:
                    LOG_ERROR('Periphery not found')
                    result = False
                elif g_lobbyContext.getCredentials() is None:
                    LOG_ERROR('Login info not found')
                    result = False
                elif g_preDefinedHosts.isRoamingPeriphery(invite.peripheryID) and not isRoamingEnabled(g_itemsCache.items.stats.attributes):
                    LOG_ERROR('Roaming is not supported')
                    result = False
                else:
                    result = invite.clientID > 0 and invite.isActive()
            else:
                result = invite.clientID > 0 and invite.isActive()
        return result

    def canDeclineInvite(self, invite):
        result = False
        if invite.clientID in self.__invites:
            result = invite.clientID > 0 and invite.isActive()
        return result

    def canRevokeInvite(self, invite):
        result = False
        if invite.clientID in self.__invites:
            result = invite.clientID > 0 and invite.isActive() and invite.creatorDBID == getPlayerDatabaseID()
        return result

    def getInvites(self, incoming = None, version = None, onlyActive = None):
        result = self.__invites.values()
        if incoming is not None:
            result = filter(lambda item: item.isIncoming() is incoming, result)
        if version is not None:
            result = filter(lambda item: item.getVersion() == version, result)
        if onlyActive is not None:
            result = filter(lambda item: item.isActive() is onlyActive, result)
        return result

    def getInvite(self, inviteID):
        invite = None
        if inviteID in self.__invites:
            invite = self.__invites[inviteID]
        return invite

    def getReceivedInviteCount(self):
        return len(self.getReceivedInvites())

    def getReceivedInvites(self, IDs = None):
        result = self.getInvites(incoming=True)
        if IDs is not None:
            result = filter(lambda item: item.clientID in IDs, result)
        return result

    def getSentInvites(self, IDs = None):
        result = self.getInvites(incoming=False)
        if IDs is not None:
            result = filter(lambda item: item.clientID in IDs, result)
        return result

    def getSentInviteCount(self):
        return len(self.getSentInvites())

    def getUnreadCount(self):
        return self.__unreadInvitesCount

    def resetUnreadCount(self):
        self.__unreadInvitesCount = 0

    def onUserNamesReceived(self, names):
        updated = defaultdict(list)
        rosterGetter = self.users.getUser
        inviteMaker = self._getNewInviteMaker(rosterGetter)
        prebattleInvitations = _getNewInvites()
        for invite in self.getInvites(version=_INVITE_VERSION.NEW):
            if invite.creatorDBID in names or invite.receiverDBID in names:
                inviteData = prebattleInvitations.get(invite.id)
                inviteID, invite = inviteMaker(inviteData)
                if inviteData and self._updateInvite(invite, rosterGetter):
                    updated[invite.isIncoming()].append(inviteID)

        for isIncoming, event in ((True, self.onReceivedInviteListModified), (False, self.onSentInviteListModified)):
            if updated[isIncoming]:
                event([], updated[isIncoming], [])

    def _makeInviteID(self, prebattleID, peripheryID, senderDBID, receiverDBID):
        inviteKey = (prebattleID,
         peripheryID,
         senderDBID,
         receiverDBID)
        inviteID = self._IDMap.get(inviteKey)
        if inviteID is None:
            inviteID = self._IDGen.next()
            self._IDMap[inviteKey] = inviteID
        return inviteID

    def _addInvite(self, invite, userGetter):
        if self.__isInviteSenderIgnoredInBattle(invite, userGetter):
            return False
        self.__invites[invite.clientID] = invite
        if invite.isActive():
            self.__unreadInvitesCount += 1
        return True

    def _updateInvite(self, other, userGetter):
        inviteID = other.clientID
        invite = self.__invites[inviteID]
        if invite == other or self.__isInviteSenderIgnoredInBattle(invite, userGetter):
            return False
        prevCount = invite.count
        invite = invite._merge(other)
        self.__invites[inviteID] = invite
        if invite.isActive() and prevCount < invite.count:
            self.__unreadInvitesCount += 1
        return True

    def _delInvite(self, inviteID):
        result = inviteID in self.__invites
        if result:
            self.__invites.pop(inviteID)
        return result

    def _buildReceivedInvitesList(self, invitesLists):
        if self.__inited & PRB_INVITES_INIT_STEP.DATA_BUILD == 0:
            self.__inited |= PRB_INVITES_INIT_STEP.DATA_BUILD
        self.__clearInvites()
        userGetter = self.users.getUser
        for invitesData, maker in invitesLists:
            for item in invitesData:
                _, invite = maker(item)
                if invite:
                    self._addInvite(invite, userGetter)

        if g_appLoader.getSpaceID() != GUI_GLOBAL_SPACE_ID.BATTLE:
            self.syncUsersInfo()

    def _rebuildInvitesLists(self):
        rosterGetter = self.users.getUser
        self._buildReceivedInvitesList([(_getOldInvites().items(), self._getOldInviteMaker(rosterGetter)), (_getNewInvites().values(), self._getNewInviteMaker(rosterGetter))])

    def _getOldInviteMaker(self, rosterGetter):
        receiver = getPlayerName()
        receiverDBID = getPlayerDatabaseID()
        receiverClanAbbrev = g_lobbyContext.getClanAbbrev(self.__clanInfo)

        def _inviteMaker(item):
            (prebattleID, peripheryID), data = item
            inviteID = self._makeInviteID(prebattleID, peripheryID, data['creatorDBID'], receiverDBID)
            if data is not None:
                invite = PrbInviteWrapper(clientID=inviteID, receiver=receiver, receiverDBID=receiverDBID, receiverClanAbbrev=receiverClanAbbrev, peripheryID=peripheryID, prebattleID=prebattleID, **data)
            else:
                invite = None
            return (inviteID, invite)

        return _inviteMaker

    def _getNewInviteMaker(self, rosterGetter):

        def _getUserName(userDBID):
            name, abbrev = ('', None)
            if userDBID:
                if g_appLoader.getSpaceID() == GUI_GLOBAL_SPACE_ID.BATTLE:
                    name, abbrev = g_battleCtrl.getCtx().getPlayerFullNameParts(accID=userDBID, showVehShortName=False)[1:3]
                if not name:
                    userName = self.getUserName(userDBID)
                    userClanAbbrev = self.getUserClanAbbrev(userDBID)
                    user = rosterGetter(userDBID)
                    if user and user.hasValidName():
                        name, abbrev = userName, userClanAbbrev
            return (name, abbrev)

        def _inviteMaker(item):
            peripheryID, prebattleID = PrbInvitationWrapper.getPrbInfo(item.get('info', {}))
            senderDBID = item.get('senderDBID', 0)
            receiverDBID = item.get('receiverDBID', 0)
            inviteID = self._makeInviteID(prebattleID, peripheryID, senderDBID, receiverDBID)
            senderName, senderClanAbbrev = _getUserName(senderDBID)
            receiverName, receiverClanAbbrev = _getUserName(receiverDBID)
            return (inviteID, PrbInvitationWrapper(inviteID, sender=senderName, senderClanAbbrev=senderClanAbbrev, receiver=receiverName, receiverClanAbbrev=receiverClanAbbrev, **item))

        return _inviteMaker

    def __initReceivedInvites(self):
        step = PRB_INVITES_INIT_STEP.CONTACTS_RECEIVED
        if self.__inited & step != step:
            return
        self._rebuildInvitesLists()
        if self.__inited == PRB_INVITES_INIT_STEP.INITED:
            self.onInvitesListInited()

    def __clearAcceptChain(self):
        if self.__acceptChain is not None:
            self.__acceptChain.onStopped -= self.__accept_onPostActionsStopped
            self.__acceptChain.stop()
            self.__acceptChain = None
        return

    def __me_onUsersListReceived(self, tags):
        doInit = False
        if USER_TAG.FRIEND in tags:
            doInit = True
            step = PRB_INVITES_INIT_STEP.FRIEND_RECEIVED
            if self.__inited & step == 0:
                self.__inited |= step
        if USER_TAG.IGNORED in tags:
            doInit = True
            step = PRB_INVITES_INIT_STEP.IGNORED_RECEIVED
            if self.__inited & step == 0:
                self.__inited |= step
        if doInit:
            self.__initReceivedInvites()

    def __pe_onPrebattleInvitesChanged(self, diff):
        step = PRB_INVITES_INIT_STEP.CONTACTS_RECEIVED
        if self.__inited & step != step:
            LOG_DEBUG('Received invites are ignored. Manager waits for client will receive contacts')
            return
        if ('prebattleInvites', '_r') in diff:
            self._rebuildInvitesLists()
        if 'prebattleInvites' in diff:
            self.__updateOldPrebattleInvites(_getOldInvites())

    def __pe_onPrebattleInvitationsChanged(self, invitations):
        step = PRB_INVITES_INIT_STEP.CONTACTS_RECEIVED
        if self.__inited & step != step:
            LOG_DEBUG('Received invites are ignored. Manager waits for client will receive contacts')
            return
        self.__updateNewPrebattleInvites(invitations)

    def __pe_onPrebattleInvitesStatus(self, dbID, name, status):
        if status != PREBATTLE_INVITE_STATUS.OK:
            statusName = PREBATTLE_INVITE_STATUS_NAMES[status]
            SystemMessages.pushI18nMessage('#system_messages:invite/status/%s' % statusName, name=name, type=SystemMessages.SM_TYPE.Warning)

    def __updateOldPrebattleInvites(self, prbInvites):
        added = []
        changed = []
        deleted = []
        modified = False
        rosterGetter = self.users.getUser
        inviteMaker = self._getOldInviteMaker(rosterGetter)
        for item in prbInvites.iteritems():
            inviteID, invite = inviteMaker(item)
            if invite is None:
                if self._delInvite(inviteID):
                    modified = True
                    deleted.append(inviteID)
                continue
            inList = inviteID in self.__invites
            if not inList:
                if self._addInvite(invite, rosterGetter):
                    modified = True
                    added.append(inviteID)
            elif self._updateInvite(invite, rosterGetter):
                modified = True
                changed.append(inviteID)

        if modified:
            self.onReceivedInviteListModified(added, changed, deleted)
        return

    def __updateNewPrebattleInvites(self, prbInvites):
        added = defaultdict(list)
        changed = defaultdict(list)
        deleted = defaultdict(list)
        modified = dict(((v, False) for v in (True, False)))
        rosterGetter = self.users.getUser
        inviteMaker = self._getNewInviteMaker(rosterGetter)
        newInvites = {}
        for data in prbInvites.itervalues():
            inviteID, invite = inviteMaker(data)
            if inviteID not in newInvites or invite.createTime > newInvites[inviteID].createTime:
                newInvites[inviteID] = invite

        for invite in self.getInvites(version=_INVITE_VERSION.NEW):
            inviteID = invite.clientID
            if inviteID not in newInvites and self._delInvite(inviteID):
                isIncoming = invite.isIncoming()
                modified[isIncoming] = True
                deleted[isIncoming].append(inviteID)
            else:
                continue

        for inviteID, invite in newInvites.iteritems():
            isIncoming = invite.isIncoming()
            if inviteID not in self.__invites:
                if self._addInvite(invite, rosterGetter):
                    modified[isIncoming] = True
                    added[isIncoming].append(inviteID)
            elif self._updateInvite(invite, rosterGetter):
                modified[isIncoming] = True
                changed[isIncoming].append(inviteID)

        for isIncoming, event in ((True, self.onReceivedInviteListModified), (False, self.onSentInviteListModified)):
            if modified[isIncoming]:
                event(added[isIncoming], changed[isIncoming], deleted[isIncoming])

        self.syncUsersInfo()

    def __accept_onPostActionsStopped(self, isCompleted):
        if not isCompleted:
            return
        invite = self.__acceptChain.invite
        invite.accept()
        if self.__unreadInvitesCount > 0:
            self.__unreadInvitesCount -= 1

    def __clearInvites(self):
        self.__invites.clear()
        self.__unreadInvitesCount = 0

    def __isInviteSenderIgnoredInBattle(self, invite, userGetter):
        return isInviteSenderIgnoredInBattle(userGetter(invite.creatorDBID), g_settings.userPrefs.invitesFromFriendsOnly, invite.isCreatedInBattle())
Ejemplo n.º 28
0
class BrowserController(Controller):
    _BROWSER_TEXTURE = 'BrowserBg'
    _ALT_BROWSER_TEXTURE = 'AltBrowserBg'

    def __init__(self, proxy):
        super(BrowserController, self).__init__(proxy)
        self.__browsers = {}
        self.__browsersCallbacks = {}
        self.__browserIDGenerator = SequenceIDGenerator()
        self.__eventMgr = Event.EventManager()
        self.onBrowserAdded = Event.Event(self.__eventMgr)
        self.onBrowserDeleted = Event.Event(self.__eventMgr)
        self.__urlMacros = URLMarcos()

    def fini(self):
        self.__eventMgr.clear()
        self.__eventMgr = None
        self.__urlMacros.clear()
        self.__urlMacros = None
        self.__browserIDGenerator = None
        super(BrowserController, self).fini()

    def onAvatarBecomePlayer(self):
        self.__stop()

    def onDisconnected(self):
        self.__stop()

    @async
    @process
    def load(self, url = None, title = None, showActionBtn = True, showWaiting = True, browserID = None, isAsync = False, browserSize = None, background = None, isDefault = True, callback = None, showCloseBtn = False):
        url = url or GUI_SETTINGS.browser.url
        suffix = yield self.__urlMacros.parse(GUI_SETTINGS.browser.params)
        concatenator = '&' if '?' in url else '?'
        if suffix not in url:
            url = concatenator.join([url, suffix])
        size = browserSize or BROWSER.SIZE
        background = background or BROWSER.BACKGROUND
        if browserID is None:
            browserID = self.__browserIDGenerator.next()
        if browserID not in self.__browsers:
            texture = self._BROWSER_TEXTURE if isDefault else self._ALT_BROWSER_TEXTURE
            app = g_appLoader.getApp()
            assert app, 'Application can not be None'
            self.__browsers[browserID] = WebBrowser(browserID, app, texture, size, url, backgroundUrl=background)
            self.onBrowserAdded(browserID)
        ctx = {'url': url,
         'title': title,
         'showActionBtn': showActionBtn,
         'showWaiting': showWaiting,
         'browserID': browserID,
         'size': size,
         'isDefault': isDefault,
         'isAsync': isAsync,
         'showCloseBtn': showCloseBtn}

        def browserCallback(*args):
            self.__clearCallback(browserID)
            self.__showBrowser(browserID, ctx)

        if isAsync:
            self.__browsersCallbacks[browserID] = (None, browserCallback)
            self.__browsers[browserID].onLoadEnd += browserCallback
        else:
            self.__browsersCallbacks[browserID] = (browserCallback, None)
            self.__browsers[browserID].onLoadStart += browserCallback
        callback(browserID)

    def getBrowser(self, browserID):
        return self.__browsers.get(browserID)

    def delBrowser(self, browserID):
        if browserID in self.__browsers:
            browser = self.__browsers.pop(browserID)
            loadStart, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None))
            if loadStart is not None:
                browser.onLoadStart -= loadStart
            if loadEnd is not None:
                browser.onLoadEnd -= loadEnd
            browser.destroy()
        self.onBrowserDeleted(browserID)

    def __stop(self):
        while self.__browsers:
            browserID, browser = self.__browsers.popitem()
            loadStart, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None))
            if loadStart is not None:
                browser.onLoadStart -= loadStart
            if loadEnd is not None:
                browser.onLoadEnd -= loadEnd
            browser.destroy()

    def __clearCallback(self, browserID):
        if browserID in self.__browsersCallbacks:
            loadStart, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None))
            if loadStart is not None:
                self.__browsers[browserID].onLoadStart -= loadStart
            if loadEnd is not None:
                self.__browsers[browserID].onLoadEnd -= loadEnd

    def __showBrowser(self, browserID, ctx):
        g_eventBus.handleEvent(LoadViewEvent(VIEW_ALIAS.BROWSER_WINDOW, getViewName(VIEW_ALIAS.BROWSER_WINDOW, browserID), ctx=ctx), EVENT_BUS_SCOPE.LOBBY)
class BWChatProvider(object):
    __slots__ = ('__weakref__', '__handlers', '__msgFilters', '__coolDown',
                 '__idGen', '__isEnabled', '__queue', '__battleCmdCooldowns')

    def __init__(self):
        super(BWChatProvider, self).__init__()
        self.__handlers = defaultdict(set)
        self.__msgFilters = None
        self.__coolDown = _ChatCooldownManager()
        self.__battleCmdCooldowns = []
        self.__idGen = SequenceIDGenerator()
        self.__isEnabled = False
        self.__queue = []
        return

    def clear(self):
        self.__handlers.clear()
        self.__battleCmdCooldowns = []
        BattleReplay.g_replayCtrl.delDataCallback(
            CallbackDataNames.BW_CHAT2_REPLAY_ACTION_RECEIVED_CALLBACK,
            self.__onActionReceivedFromReplay)

    def goToReplay(self):
        BattleReplay.g_replayCtrl.setDataCallback(
            CallbackDataNames.BW_CHAT2_REPLAY_ACTION_RECEIVED_CALLBACK,
            self.__onActionReceivedFromReplay)

    def setEnable(self, value):
        if self.__isEnabled == value:
            return
        self.__isEnabled = value
        if self.__isEnabled:
            self.__sendActionsFromQueue()
        else:
            self.__queue = []

    def doAction(self,
                 actionID,
                 args=None,
                 response=False,
                 skipCoolDown=False):
        success, reqID = False, 0
        if self.__isCooldownInProcess(actionID, args):
            if not skipCoolDown:
                g_messengerEvents.onErrorReceived(
                    createCoolDownError(actionID,
                                        self.__getCooldownTime(actionID,
                                                               args)))
        else:
            if response:
                reqID = self.__idGen.next()
            if self.__isEnabled:
                success = self.__sendAction(actionID, reqID, args)
            else:
                success = self.__addActionToQueue(actionID, reqID, args)
        return (success, reqID)

    def onActionReceived(self, actionID, reqID, args):
        if BattleReplay.g_replayCtrl.isRecording and self.__isActionWrittenToReplay(
                actionID):
            BattleReplay.g_replayCtrl.serializeCallbackData(
                CallbackDataNames.BW_CHAT2_REPLAY_ACTION_RECEIVED_CALLBACK,
                (actionID, reqID, args))
        handlers = self.__handlers[actionID]
        for handler in handlers:
            try:
                handler((actionID, reqID), args)
            except TypeError:
                LOG_ERROR('Handler has been invoked with error', handler)
                LOG_CURRENT_EXCEPTION()

    def setFilters(self, msgFilterChain):
        self.__msgFilters = msgFilterChain

    def filterInMessage(self, message):
        text = message.text
        senderDBID = message.accountDBID
        if senderDBID > 0:
            text = self.__msgFilters.chainIn(senderDBID, text)
        else:
            senderAvatarID = message.avatarSessionID
            if senderAvatarID:
                text = self.__msgFilters.chainIn(senderAvatarID, text)
        if not text:
            result = None
        else:
            message.text = text
            result = message
        return result

    def filterOutMessage(self, text, limits):
        return self.__msgFilters.chainOut(text, limits)

    def setActionCoolDown(self, actionID, coolDown, targetID=0):
        command = _ACTIONS.battleChatCommandFromActionID(actionID)
        if command and command.name not in CHAT_COMMANDS_THAT_IGNORE_COOLDOWNS:
            currTime = BigWorld.time()
            addCoolDowns(currTime, self.__battleCmdCooldowns, command.id,
                         command.name, command.cooldownPeriod, targetID)
        else:
            self.__coolDown.process(actionID, coolDown)

    def isActionInCoolDown(self, actionID):
        command = _ACTIONS.battleChatCommandFromActionID(actionID)
        if command:
            return [
                cdData for cdData in self.__battleCmdCooldowns
                if cdData.cmdID == actionID
            ]
        return self.__coolDown.isInProcess(actionID)

    def getActionCooldownData(self, actionID):
        command = _ACTIONS.battleChatCommandFromActionID(actionID)
        if command:
            return [
                cdData for cdData in self.__battleCmdCooldowns
                if cdData.cmdID == actionID
            ]
        return []

    def clearActionCoolDown(self, actionID):
        command = _ACTIONS.battleChatCommandFromActionID(actionID)
        if command:
            removeList = [
                cdData for cdData in self.__battleCmdCooldowns
                if cdData.cmdID == command.id
            ]
            if removeList:
                for dataForRemoval in removeList:
                    self.__battleCmdCooldowns.remove(dataForRemoval)

        else:
            self.__coolDown.reset(actionID)

    def registerHandler(self, actionID, handler):
        handlers = self.__handlers[actionID]
        if handler in handlers:
            LOG_WARNING('Handler already is exist', actionID, handler)
        else:
            if not hasattr(handler, '__self__') or not isinstance(
                    handler.__self__, ActionsHandler):
                LOG_ERROR('Class of handler is not subclass of ActionsHandler',
                          handler)
                return
            if callable(handler):
                handlers.add(handler)
            else:
                LOG_ERROR('Handler is invalid', handler)

    def unregisterHandler(self, actionID, handler):
        handlers = self.__handlers[actionID]
        if handler in handlers:
            handlers.remove(handler)

    def __sendAction(self, actionID, reqID, args=None):
        player = BigWorld.player()
        if not player:
            LOG_ERROR('Player is not defined')
            return False
        player.base.messenger_onActionByClient_chat2(actionID, reqID, args
                                                     or messageArgs())
        return True

    def __addActionToQueue(self, actionID, reqID, args=None):
        self.__queue.append((actionID, reqID, args))
        return True

    def __sendActionsFromQueue(self):
        invokedIDs = set()
        while self.__queue:
            actionID, reqID, args = self.__queue.pop()
            if actionID in invokedIDs:
                LOG_WARNING(
                    'Action is ignored, your must send action after event "showGUI" is invoked',
                    actionID, reqID, args)
                continue
            self.__sendAction(actionID, reqID, args)
            invokedIDs.add(actionID)

    @staticmethod
    def __isActionWrittenToReplay(actionID):
        return actionID == _ACTIONS.INIT_BATTLE_CHAT or _ACTIONS.battleChatCommandFromActionID(
            actionID) is not None

    def __onActionReceivedFromReplay(self, actionID, reqID, args):
        self.onActionReceived(actionID, reqID, args)

    def __isCooldownInProcess(self, actionID, args=None):
        command = _ACTIONS.battleChatCommandFromActionID(actionID)
        if command:
            currTime = BigWorld.time()
            targetID = args['int32Arg1']
            sndrBlockReason = areSenderCooldownsActive(
                currTime, self.__battleCmdCooldowns, actionID, targetID)
            cdTime = sndrBlockReason.cooldownEnd - currTime if sndrBlockReason is not None else 0
            return command.name not in CHAT_COMMANDS_THAT_IGNORE_COOLDOWNS and sndrBlockReason is not None and cdTime > 0
        else:
            return self.__coolDown.isInProcess(actionID)

    def __getCooldownTime(self, actionID, args=None):
        command = _ACTIONS.battleChatCommandFromActionID(actionID)
        if command:
            currTime = BigWorld.time()
            targetID = args['int32Arg1']
            sndrBlockReason = areSenderCooldownsActive(
                currTime, self.__battleCmdCooldowns, actionID, targetID)
            cdTime = round(sndrBlockReason.cooldownEnd -
                           currTime, 1) if sndrBlockReason is not None else 0
            return cdTime
        else:
            self.__coolDown.getTime(actionID)
            return
Ejemplo n.º 30
0
def _generateUserName():
    global _g_namesGenerator
    if _g_namesGenerator is None:
        _g_namesGenerator = SequenceIDGenerator()
    return '%s %d' % (USER_DEFAULT_NAME_PREFIX, _g_namesGenerator.next())
Ejemplo n.º 31
0
class BrowserController(Controller):
    _BROWSER_TEXTURE = 'BrowserBg'
    _ALT_BROWSER_TEXTURE = 'AltBrowserBg'

    def __init__(self, proxy):
        super(BrowserController, self).__init__(proxy)
        self.__browsers = {}
        self.__browsersCallbacks = {}
        self.__browserIDGenerator = SequenceIDGenerator()
        self.__eventMgr = Event.EventManager()
        self.onBrowserAdded = Event.Event(self.__eventMgr)
        self.onBrowserDeleted = Event.Event(self.__eventMgr)
        self.__urlMacros = URLMarcos()

    def fini(self):
        self.__eventMgr.clear()
        self.__eventMgr = None
        self.__urlMacros.clear()
        self.__urlMacros = None
        self.__browserIDGenerator = None
        super(BrowserController, self).fini()
        return

    def onAvatarBecomePlayer(self):
        self.__stop()

    def onDisconnected(self):
        self.__stop()

    @async
    @process
    def load(self, url = None, title = None, showActionBtn = True, showWaiting = True, browserID = None, isAsync = False, browserSize = None, isDefault = True, callback = None, showCloseBtn = False):
        url = yield self.__urlMacros.parse(url or GUI_SETTINGS.browser.url)
        suffix = yield self.__urlMacros.parse(GUI_SETTINGS.browser.params)
        concatenator = '&' if '?' in url else '?'
        if suffix not in url:
            url = concatenator.join([url, suffix])
        size = browserSize or BROWSER.SIZE
        if browserID is None:
            browserID = self.__browserIDGenerator.next()
        if browserID not in self.__browsers:
            texture = self._BROWSER_TEXTURE if isDefault else self._ALT_BROWSER_TEXTURE
            app = g_appLoader.getApp()
            if not app:
                raise AssertionError('Application can not be None')
                self.__browsers[browserID] = WebBrowser(browserID, app, texture, size, url)
                self.onBrowserAdded(browserID)
            ctx = {'url': url,
             'title': title,
             'showActionBtn': showActionBtn,
             'showWaiting': showWaiting,
             'browserID': browserID,
             'size': size,
             'isDefault': isDefault,
             'isAsync': isAsync,
             'showCloseBtn': showCloseBtn}

            def browserCallback(*args):
                self.__clearCallback(browserID)
                self.__showBrowser(browserID, ctx)

            def browserAsyncCallback(url, isLoaded):
                self.__clearCallback(browserID)
                if isLoaded:
                    self.__showBrowser(browserID, ctx)
                else:
                    LOG_WARNING('Browser async request url was not loaded!', url)

            self.__browsersCallbacks[browserID] = isAsync and (None, browserCallback)
            self.__browsers[browserID].onLoadEnd += browserAsyncCallback
        else:
            self.__browsersCallbacks[browserID] = (browserCallback, None)
            self.__browsers[browserID].onLoadStart += browserCallback
        callback(browserID)
        return

    def getBrowser(self, browserID):
        return self.__browsers.get(browserID)

    def delBrowser(self, browserID):
        if browserID in self.__browsers:
            browser = self.__browsers.pop(browserID)
            loadStart, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None))
            if loadStart is not None:
                browser.onLoadStart -= loadStart
            if loadEnd is not None:
                browser.onLoadEnd -= loadEnd
            browser.destroy()
        self.onBrowserDeleted(browserID)
        return

    def __stop(self):
        while self.__browsers:
            browserID, browser = self.__browsers.popitem()
            loadStart, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None))
            if loadStart is not None:
                browser.onLoadStart -= loadStart
            if loadEnd is not None:
                browser.onLoadEnd -= loadEnd
            browser.destroy()

        return

    def __clearCallback(self, browserID):
        if browserID in self.__browsersCallbacks:
            loadStart, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None))
            if loadStart is not None:
                self.__browsers[browserID].onLoadStart -= loadStart
            if loadEnd is not None:
                self.__browsers[browserID].onLoadEnd -= loadEnd
        return

    def __showBrowser(self, browserID, ctx):
        g_eventBus.handleEvent(LoadViewEvent(VIEW_ALIAS.BROWSER_WINDOW, getViewName(VIEW_ALIAS.BROWSER_WINDOW, browserID), ctx=ctx), EVENT_BUS_SCOPE.LOBBY)
class RibbonsAggregator(object):
    sessionProvider = dependency.descriptor(IBattleSessionProvider)

    def __init__(self):
        super(RibbonsAggregator, self).__init__()
        self.__feedbackProvider = None
        self.__vehicleStateCtrl = None
        self.__cache = _RibbonsCache()
        self.__accumulatedRibbons = _RibbonsCache()
        self.__rules = {}
        self.__idGenerator = SequenceIDGenerator()
        self.onRibbonAdded = Event.Event()
        self.onRibbonUpdated = Event.Event()
        self.__isStarted = False
        self.__isSuspended = False
        self.__isInPostmortemMode = False
        return

    def start(self):
        self.__isStarted = True
        if self.__feedbackProvider is None:
            self.__feedbackProvider = self.sessionProvider.shared.feedback
            if self.__feedbackProvider is not None:
                self.__feedbackProvider.onPlayerFeedbackReceived += self._onPlayerFeedbackReceived
        if self.__vehicleStateCtrl is None:
            self.__vehicleStateCtrl = self.sessionProvider.shared.vehicleState
            if self.__vehicleStateCtrl is not None:
                self.__vehicleStateCtrl.onPostMortemSwitched += self._onPostMortemSwitched
                self.__vehicleStateCtrl.onRespawnBaseMoving += self.__onRespawnBaseMoving
        return

    def suspend(self):
        if self.__isStarted:
            self.__isSuspended = True

    def resume(self):
        if self.__isSuspended:
            self.__isSuspended = False

    def stop(self):
        self.__isStarted = False
        self.__isSuspended = False
        self.clearRibbonsData()
        if self.__feedbackProvider is not None:
            self.__feedbackProvider.onPlayerFeedbackReceived -= self._onPlayerFeedbackReceived
            self.__feedbackProvider = None
        if self.__vehicleStateCtrl is not None:
            self.__vehicleStateCtrl.onPostMortemSwitched -= self._onPostMortemSwitched
            self.__vehicleStateCtrl.onRespawnBaseMoving -= self.__onRespawnBaseMoving
            self.__vehicleStateCtrl = None
        return

    def getRibbon(self, ribbonID):
        return self.__cache.get(ribbonID, None)

    def resetRibbonData(self, ribbonID):
        ribbon = self.__cache.pop(ribbonID)
        if ribbon is not None and ribbon.getType(
        ) in _ACCUMULATED_RIBBON_TYPES:
            self.__accumulatedRibbons.add(ribbon)
        return

    def clearRibbonsData(self):
        self.__cache.clear()
        self.__accumulatedRibbons.clear()

    def _onPostMortemSwitched(self, noRespawnPossible, respawnAvailable):
        self.__isInPostmortemMode = True

    def __onRespawnBaseMoving(self):
        self.__isInPostmortemMode = False

    def _onPlayerFeedbackReceived(self, events):
        def _ribbonsGenerator(events):
            for e in events:
                r = _createRibbonFromPlayerFeedbackEvent(
                    self.__idGenerator.next(), e)
                if r is not None:
                    yield r

            return

        self._aggregateRibbons(_ribbonsGenerator(events))

    def _aggregateRibbons(self, ribbons):
        aggregatedRibbons = {}
        for ribbon in ribbons:
            if self.__isSuspended and ribbon.getType(
            ) not in _ACCUMULATED_RIBBON_TYPES:
                continue
            if ribbon.getType() in aggregatedRibbons:
                temporaryRibbons = aggregatedRibbons[ribbon.getType()]
                for temporaryRibbon in temporaryRibbons:
                    if temporaryRibbon.aggregate(ribbon):
                        break
                else:
                    temporaryRibbons.append(ribbon)

            aggregatedRibbons[ribbon.getType()] = [ribbon]

        filteredRibbons = self.__filterRibbons(aggregatedRibbons)
        sortedRibbons = self.__getSortedList(filteredRibbons)
        for ribbon in sortedRibbons:
            etype = ribbon.getType()
            if etype in _NOT_CACHED_RIBBON_TYPES:
                self.__cache.add(ribbon)
                self.onRibbonAdded(ribbon)
            for cachedRibbon in self.__cache.iterByType(etype):
                if cachedRibbon.aggregate(ribbon):
                    if not self.__isSuspended:
                        updateData = cachedRibbon if cachedRibbon.isAggregating else ribbon
                        self.onRibbonUpdated(updateData)
                    break
            else:
                if etype in _ACCUMULATED_RIBBON_TYPES:
                    for accumulatedRibbon in self.__accumulatedRibbons.iterByType(
                            etype):
                        if accumulatedRibbon.aggregate(ribbon):
                            if not self.__isSuspended:
                                self.__accumulatedRibbons.pop(
                                    accumulatedRibbon.getID())
                                self.__cache.add(accumulatedRibbon)
                                self.onRibbonAdded(accumulatedRibbon)
                            break
                    else:
                        if self.__isSuspended:
                            self.__accumulatedRibbons.add(ribbon)
                        else:
                            self.__cache.add(ribbon)
                            self.onRibbonAdded(ribbon)
                if not self.__isSuspended:
                    self.__cache.add(ribbon)
                    self.onRibbonAdded(ribbon)

    def __filterRibbons(self, ribbons):
        if self.__isInPostmortemMode and not avatar_getter.isObserver():
            for rType in _RIBBON_TYPES_EXCLUDED_IN_POSTMORTEM:
                if rType in ribbons:
                    del ribbons[rType]

        if BATTLE_EFFICIENCY_TYPES.DESTRUCTION in ribbons:
            killRibbons = dict(
                ((r.getVehicleID(), r)
                 for r in ribbons[BATTLE_EFFICIENCY_TYPES.DESTRUCTION]))
            damageRibbons = dict(
                ((t, ribbons[t])
                 for t in _RIBBON_TYPES_AGGREGATED_WITH_KILL_RIBBON
                 if t in ribbons))
            for rType, tmpRibbons in damageRibbons.iteritems():
                filteredRibbons = []
                for tmpRibbon in tmpRibbons:
                    if tmpRibbon.getVehicleID() in killRibbons:
                        killRibbon = killRibbons[tmpRibbon.getVehicleID()]
                        if not killRibbon.aggregate(tmpRibbon):
                            filteredRibbons.append(tmpRibbon)
                    filteredRibbons.append(tmpRibbon)

                ribbons[rType] = filteredRibbons

            excludedRibbons = dict(
                ((t, ribbons[t]) for t in _RIBBON_TYPES_EXCLUDED_IF_KILL_RIBBON
                 if t in ribbons))
            for rType, tmpRibbons in excludedRibbons.iteritems():
                filteredRibbons = [
                    r for r in tmpRibbons
                    if r.getVehicleID() not in killRibbons
                ]
                ribbons[rType] = filteredRibbons

        return ribbons

    def __getSortedList(self, ribbons):
        def _sortKey(ribbon):
            return ribbon.getID()

        sortedRibons = []
        if ribbons:
            killRibbons = ribbons.pop(BATTLE_EFFICIENCY_TYPES.DESTRUCTION,
                                      None)
            detectionRibbons = ribbons.pop(BATTLE_EFFICIENCY_TYPES.DETECTION,
                                           None)
            if detectionRibbons is not None:
                sortedRibons.extend(sorted(detectionRibbons, key=_sortKey))
            remaningRibbons = []
            for newRibbons in ribbons.itervalues():
                remaningRibbons.extend(newRibbons)

            sortedRibons.extend(sorted(remaningRibbons, key=_sortKey))
            if killRibbons is not None:
                sortedRibons.extend(sorted(killRibbons, key=_sortKey))
        return sortedRibons
Ejemplo n.º 33
0
class BrowserController(IBrowserController):
    _BROWSER_TEXTURE = 'BrowserBg'
    _ALT_BROWSER_TEXTURE = 'AltBrowserBg'

    def __init__(self):
        super(BrowserController, self).__init__()
        self.__browsers = {}
        self.__browsersCallbacks = {}
        self.__browserIDGenerator = SequenceIDGenerator()
        self.__eventMgr = Event.EventManager()
        self.onBrowserAdded = Event.Event(self.__eventMgr)
        self.onBrowserDeleted = Event.Event(self.__eventMgr)
        self.__urlMacros = URLMarcos()
        self.__pendingBrowsers = {}
        self.__creatingBrowserID = None
        self.__filters = _getGlobalFilters()
        return

    def fini(self):
        self.__filters = None
        self.__eventMgr.clear()
        self.__eventMgr = None
        self.__urlMacros.clear()
        self.__urlMacros = None
        self.__browserIDGenerator = None
        super(BrowserController, self).fini()
        return

    def onAvatarBecomePlayer(self):
        self.__stop()

    def onDisconnected(self):
        self.__stop()

    def addFilterHandler(self, handler):
        """ Adds given @handler to the browser urls filter chain. Calls
        it if there is a @tag in url onto opened browser page.
        Handler should receive url and list of client-specific tags,
        return bool as flag that routine have to stop
        """
        self.__filters.add(handler)

    def removeFilterHandler(self, handler):
        """ Remove given @handler from filtering chain. Handler description
        can be seen in addFilterhandler method doc-string
        """
        self.__filters.discard(handler)

    @async
    @process
    def load(self,
             url=None,
             title=None,
             showActionBtn=True,
             showWaiting=True,
             browserID=None,
             isAsync=False,
             browserSize=None,
             isDefault=True,
             callback=None,
             showCloseBtn=False,
             useBrowserWindow=True):
        url = yield self.__urlMacros.parse(url or GUI_SETTINGS.browser.url)
        suffix = yield self.__urlMacros.parse(GUI_SETTINGS.browser.params)
        concatenator = '&' if '?' in url else '?'
        if suffix not in url:
            url = concatenator.join([url, suffix])
        size = browserSize or BROWSER.SIZE
        webBrowserID = browserID
        if browserID is None:
            browserID = self.__browserIDGenerator.next()
            webBrowserID = browserID
        elif type(browserID) is not int:
            webBrowserID = self.__browserIDGenerator.next()
        ctx = {
            'url': url,
            'title': title,
            'showActionBtn': showActionBtn,
            'showWaiting': showWaiting,
            'browserID': browserID,
            'size': size,
            'isAsync': isAsync,
            'showCloseBtn': showCloseBtn,
            'showWindow': useBrowserWindow
        }
        texture = browserID not in self.__browsers and browserID not in self.__pendingBrowsers and self._BROWSER_TEXTURE
        app = g_appLoader.getApp()
        if not app:
            raise AssertionError('Application can not be None')
            browser = WebBrowser(webBrowserID,
                                 app,
                                 texture,
                                 size,
                                 url,
                                 handlers=self.__filters)
            self.__browsers[browserID] = browser
            if self.__isCreatingBrowser():
                self.__pendingBrowsers[browserID] = ctx
            else:
                self.__createBrowser(ctx)
        elif browserID in self.__pendingBrowsers:
            self.__pendingBrowsers[browserID] = ctx
        elif browserID in self.__browsers:
            self.__browsers[browserID].navigate(url)
        callback(browserID)
        return

    def getBrowser(self, browserID):
        return self.__browsers.get(browserID)

    def delBrowser(self, browserID):
        if browserID in self.__browsers:
            browser = self.__browsers.pop(browserID)
            loadStart, loadEnd = self.__browsersCallbacks.pop(
                browserID, (None, None))
            if loadStart is not None:
                browser.onLoadStart -= loadStart
            if loadEnd is not None:
                browser.onLoadEnd -= loadEnd
            browser.destroy()
            if self.__creatingBrowserID == browserID:
                self.__creatingBrowserID = None
                self.__tryCreateNextPendingBrowser()
        self.onBrowserDeleted(browserID)
        return

    def __isCreatingBrowser(self):
        return self.__creatingBrowserID is not None

    def __createDone(self, ctx):
        self.__creatingBrowserID = None
        g_eventBus.handleEvent(
            BrowserEvent(BrowserEvent.BROWSER_CREATED, ctx=ctx))
        self.__tryCreateNextPendingBrowser()
        return

    def __tryCreateNextPendingBrowser(self):
        if len(self.__pendingBrowsers) > 0:
            nextCtx = self.__pendingBrowsers.popitem()[1]
            self.__createBrowser(nextCtx)

    def __createBrowser(self, ctx):
        browserID = ctx['browserID']
        self.__creatingBrowserID = browserID
        self.__browsers[browserID].create()
        self.onBrowserAdded(browserID)

        def browserCallback(url, isLoaded):
            self.__clearCallback(browserID)
            if isLoaded:
                self.__showBrowser(browserID, ctx)
            else:
                LOG_WARNING('Browser request url was not loaded!', url)
            self.__createDone(browserID)

        if ctx['isAsync']:
            self.__browsersCallbacks[browserID] = (None, browserCallback)
            self.__browsers[browserID].onLoadEnd += browserCallback
        else:
            self.__browsersCallbacks[browserID] = (browserCallback, None)
            self.__browsers[browserID].onReady += browserCallback
        return

    def __stop(self):
        while self.__browsers:
            browserID, browser = self.__browsers.popitem()
            ready, loadEnd = self.__browsersCallbacks.pop(
                browserID, (None, None))
            if ready is not None:
                browser.onReady -= ready
            if loadEnd is not None:
                browser.onLoadEnd -= loadEnd
            browser.destroy()

        return

    def __clearCallback(self, browserID):
        ready, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None))
        if ready is not None:
            self.__browsers[browserID].onReady -= ready
        if loadEnd is not None:
            self.__browsers[browserID].onLoadEnd -= loadEnd
        return

    def __showBrowser(self, browserID, ctx):
        if ctx.get('showWindow'):
            g_eventBus.handleEvent(
                LoadViewEvent(VIEW_ALIAS.BROWSER_WINDOW,
                              getViewName(VIEW_ALIAS.BROWSER_WINDOW,
                                          browserID),
                              ctx=ctx), EVENT_BUS_SCOPE.LOBBY)
Ejemplo n.º 34
0
class BrowserController(IBrowserController):
    _BROWSER_TEXTURE = 'BrowserBg'
    _ALT_BROWSER_TEXTURE = 'AltBrowserBg'

    def __init__(self):
        super(BrowserController, self).__init__()
        self.__browsers = {}
        self.__browsersCallbacks = {}
        self.__browserCreationCallbacks = {}
        self.__browserIDGenerator = SequenceIDGenerator()
        self.__eventMgr = Event.EventManager()
        self.onBrowserAdded = Event.Event(self.__eventMgr)
        self.onBrowserDeleted = Event.Event(self.__eventMgr)
        self.__urlMacros = URLMarcos()
        self.__pendingBrowsers = {}
        self.__creatingBrowserID = None
        self.__filters = _getGlobalFilters()
        return

    def fini(self):
        self.__filters = None
        self.__eventMgr.clear()
        self.__eventMgr = None
        self.__urlMacros.clear()
        self.__urlMacros = None
        self.__browsersCallbacks.clear()
        self.__browsersCallbacks = None
        self.__browsers.clear()
        self.__browsers = None
        self.__pendingBrowsers.clear()
        self.__pendingBrowsers = None
        self.__browserIDGenerator = None
        super(BrowserController, self).fini()
        return

    def onAvatarBecomePlayer(self):
        self.__stop()

    def onDisconnected(self):
        self.__stop()

    def addFilterHandler(self, handler):
        self.__filters.add(handler)

    def removeFilterHandler(self, handler):
        self.__filters.discard(handler)

    @async
    @process
    def load(self, url=None, title=None, showActionBtn=True, showWaiting=True, browserID=None, isAsync=False, browserSize=None, isDefault=True, callback=None, showCloseBtn=False, useBrowserWindow=True, isModal=False, showCreateWaiting=False, handlers=None, showBrowserCallback=None, isSolidBorder=False):
        if showCreateWaiting:
            Waiting.show('browser/init')
        url = yield self.__urlMacros.parse(url or GUI_SETTINGS.browser.url)
        suffix = yield self.__urlMacros.parse(GUI_SETTINGS.browser.params)
        concatenator = '&' if '?' in url else '?'
        if suffix not in url:
            url = concatenator.join([url, suffix])
        size = browserSize or BROWSER.SIZE
        webBrowserID = browserID
        if browserID is None:
            browserID = self.__browserIDGenerator.next()
            webBrowserID = browserID
        elif type(browserID) is not int:
            webBrowserID = self.__browserIDGenerator.next()
        ctx = {'url': url,
         'title': title,
         'showActionBtn': showActionBtn,
         'showWaiting': showWaiting,
         'browserID': browserID,
         'size': size,
         'isAsync': isAsync,
         'showCloseBtn': showCloseBtn,
         'showWindow': useBrowserWindow,
         'alias': VIEW_ALIAS.BROWSER_WINDOW_MODAL if isModal else VIEW_ALIAS.BROWSER_WINDOW,
         'showCreateWaiting': showCreateWaiting,
         'handlers': handlers,
         'showBrowserCallback': showBrowserCallback,
         'isSolidBorder': isSolidBorder}
        if browserID not in self.__browsers and browserID not in self.__pendingBrowsers:
            texture = self._BROWSER_TEXTURE
            app = g_appLoader.getApp()
            if app is None:
                raise SoftException('Application can not be None')
            browser = WebBrowser(webBrowserID, app, texture, size, url, handlers=self.__filters)
            self.__browsers[browserID] = browser
            if self.__isCreatingBrowser():
                _logger.debug('CTRL: Queueing a browser creation: %r - %s', browserID, url)
                self.__pendingBrowsers[browserID] = ctx
            else:
                self.__createBrowser(ctx)
        elif browserID in self.__pendingBrowsers:
            _logger.debug('CTRL: Re-queuing a browser creation, overriding: %r - %s', browserID, url)
            self.__pendingBrowsers[browserID] = ctx
        elif browserID in self.__browsers:
            _logger.debug('CTRL: Re-navigating an existing browser: %r - %s', browserID, url)
            browser = self.__browsers[browserID]
            browser.navigate(url)
            browser.changeTitle(title)
        callback(browserID)
        return

    def getAllBrowsers(self):
        return self.__browsers

    def getBrowser(self, browserID):
        return self.__browsers.get(browserID)

    def delBrowser(self, browserID):
        if browserID in self.__browsers:
            _logger.debug('CTRL: Deleting a browser: %s', browserID)
            browser = self.__browsers.pop(browserID)
            self.__clearCallbacks(browserID, browser, True)
            browser.destroy()
            if self.__creatingBrowserID == browserID:
                self.__creatingBrowserID = None
                self.__tryCreateNextPendingBrowser()
            if browserID in self.__pendingBrowsers:
                del self.__pendingBrowsers[browserID]
        self.onBrowserDeleted(browserID)
        return

    def __isCreatingBrowser(self):
        return self.__creatingBrowserID is not None

    def __createDone(self, ctx):
        _logger.debug('CTRL: Finished creating a browser: %s', self.__creatingBrowserID)
        if ctx['showCreateWaiting']:
            Waiting.hide('browser/init')

    def __tryCreateNextPendingBrowser(self):
        self.__creatingBrowserID = None
        if self.__pendingBrowsers:
            nextCtx = self.__pendingBrowsers.popitem()[1]
            self.__createBrowser(nextCtx)
        return

    def __createBrowser(self, ctx):
        browserID = ctx['browserID']
        _logger.debug('CTRL: Creating a browser: %r - %s', browserID, ctx['url'])
        self.__creatingBrowserID = browserID
        browser = self.__browsers[browserID]
        if not browser.create():
            _logger.debug('CTRL: Failed the create step: %r', browserID)
            self.delBrowser(browserID)
            self.__tryCreateNextPendingBrowser()
            return
        else:
            self.onBrowserAdded(browserID)

            def createBrowserTimeout():
                _logger.debug('CTRL: Browser create timed out')
                createNextBrowser()

            timeoutid = BigWorld.callback(30.0, createBrowserTimeout)

            def createNextBrowser():
                _logger.debug('CTRL: Triggering create of next browser from: %s', browserID)
                BigWorld.cancelCallback(timeoutid)
                creation = self.__browserCreationCallbacks.pop(browserID, None)
                if creation is not None:
                    self.__browsers[browserID].onCanCreateNewBrowser -= creation
                BigWorld.callback(1.0, self.__tryCreateNextPendingBrowser)
                return

            def failedCreationCallback(url):
                _logger.debug('CTRL: Failed a creation: %r - %s', browserID, url)
                self.__clearCallbacks(browserID, self.__browsers[browserID], False)
                self.delBrowser(browserID)

            def successfulCreationCallback(url, isLoaded, httpStatusCode=None):
                _logger.debug('CTRL: Ready to show: %r - %r - %s', browserID, isLoaded, url)
                self.__clearCallbacks(browserID, self.__browsers[browserID], False)
                if isLoaded:
                    self.__showBrowser(browserID, ctx)
                else:
                    _logger.warning('Browser request url %s was not loaded!', url)
                g_eventBus.handleEvent(BrowserEvent(BrowserEvent.BROWSER_CREATED, ctx=ctx))
                self.__createDone(ctx)

            def titleUpdateCallback(title):
                ctx['title'] = title

            browser.onCanCreateNewBrowser += createNextBrowser
            self.__browserCreationCallbacks[browserID] = createNextBrowser
            browser.onFailedCreation += failedCreationCallback
            browser.onTitleChange += titleUpdateCallback
            if ctx['isAsync']:
                self.__browsersCallbacks[browserID] = (None,
                 successfulCreationCallback,
                 failedCreationCallback,
                 titleUpdateCallback)
                browser.onLoadEnd += successfulCreationCallback
            else:
                self.__browsersCallbacks[browserID] = (successfulCreationCallback,
                 None,
                 failedCreationCallback,
                 titleUpdateCallback)
                browser.onReady += successfulCreationCallback
            return

    def __stop(self):
        while self.__browsers:
            browserID, browser = self.__browsers.popitem()
            self.__clearCallbacks(browserID, browser, True)
            browser.destroy()

    def __clearCallbacks(self, browserID, browser, incDelayedCreation):
        ready, loadEnd, failed, title = self.__browsersCallbacks.pop(browserID, (None, None, None, None))
        if browser is not None:
            if failed is not None:
                browser.onFailedCreation -= failed
            if ready is not None:
                browser.onReady -= ready
            if loadEnd is not None:
                browser.onLoadEnd -= loadEnd
            if title is not None:
                browser.onTitleChange -= title
        if incDelayedCreation:
            creation = self.__browserCreationCallbacks.pop(browserID, None)
            if browser is not None and creation is not None:
                browser.onCanCreateNewBrowser -= creation
        return

    def __showBrowser(self, browserID, ctx):
        _logger.debug('CTRL: Showing a browser: %r - %s', browserID, ctx['url'])
        if ctx.get('showWindow'):
            alias = ctx['alias']
            g_eventBus.handleEvent(LoadViewEvent(alias, getViewName(alias, browserID), ctx=ctx), EVENT_BUS_SCOPE.LOBBY)
        showBrowserCallback = ctx.get('showBrowserCallback')
        if showBrowserCallback:
            showBrowserCallback()
Ejemplo n.º 35
0
class InvitesManager(UsersInfoHelper):
    __clanInfo = None
    itemsCache = dependency.descriptor(IItemsCache)
    sessionProvider = dependency.descriptor(IBattleSessionProvider)
    lobbyContext = dependency.descriptor(ILobbyContext)

    def __init__(self, loader):
        super(InvitesManager, self).__init__()
        self.__loader = loader
        self._IDGen = SequenceIDGenerator()
        self._IDMap = {}
        self.__invites = {}
        self.__unreadInvitesCount = 0
        self.__eventManager = Event.EventManager()
        self.__acceptChain = None
        self.onInvitesListInited = Event.Event(self.__eventManager)
        self.onReceivedInviteListModified = Event.Event(self.__eventManager)
        self.onSentInviteListModified = Event.Event(self.__eventManager)
        self.__isInBattle = False
        return

    def __del__(self):
        LOG_DEBUG('InvitesManager deleted')
        super(InvitesManager, self).__del__()

    def init(self):
        self.__inited = PRB_INVITES_INIT_STEP.UNDEFINED
        g_messengerEvents.users.onUsersListReceived += self.__me_onUsersListReceived
        g_playerEvents.onPrebattleInvitesChanged += self.__pe_onPrebattleInvitesChanged
        g_playerEvents.onPrebattleInvitationsChanged += self.__pe_onPrebattleInvitationsChanged
        g_playerEvents.onPrebattleInvitesStatus += self.__pe_onPrebattleInvitesStatus

    def fini(self):
        self.__clearAcceptChain()
        self.__inited = PRB_INVITES_INIT_STEP.UNDEFINED
        self.__loader = None
        g_messengerEvents.users.onUsersListReceived -= self.__me_onUsersListReceived
        g_playerEvents.onPrebattleInvitationsChanged -= self.__pe_onPrebattleInvitationsChanged
        g_playerEvents.onPrebattleInvitesChanged -= self.__pe_onPrebattleInvitesChanged
        g_playerEvents.onPrebattleInvitesStatus -= self.__pe_onPrebattleInvitesStatus
        self.clear()
        return

    def start(self):
        self.__isInBattle = False
        if self.__inited & PRB_INVITES_INIT_STEP.STARTED == 0:
            self.__inited |= PRB_INVITES_INIT_STEP.STARTED
            if self.__inited == PRB_INVITES_INIT_STEP.INITED:
                self.onInvitesListInited()

    def clear(self):
        self.__inited = PRB_INVITES_INIT_STEP.UNDEFINED
        self.__clearInvites()
        self._IDMap = {}
        self.__eventManager.clear()

    def onAvatarBecomePlayer(self):
        if self.__inited & PRB_INVITES_INIT_STEP.STARTED == 0:
            self.__inited |= PRB_INVITES_INIT_STEP.STARTED
            if self.__inited == PRB_INVITES_INIT_STEP.INITED:
                self.onInvitesListInited()
        self.__isInBattle = True
        self.__clearAcceptChain()

    @storage_getter('users')
    def users(self):
        return None

    def isInited(self):
        return self.__inited == PRB_INVITES_INIT_STEP.INITED

    def acceptInvite(self, inviteID, postActions = None):
        try:
            invite = self.__invites[inviteID]
        except KeyError:
            LOG_ERROR('Invite ID is invalid', inviteID, self._IDMap)
            return

        self.__clearAcceptChain()
        if not postActions:
            invite.accept()
        else:
            self.__acceptChain = _AcceptInvitesPostActions(invite, postActions)
            self.__acceptChain.onStopped += self.__accept_onPostActionsStopped
            self.__acceptChain.start()
        if self.__unreadInvitesCount > 0:
            self.__unreadInvitesCount -= 1

    def declineInvite(self, inviteID):
        try:
            invite = self.__invites[inviteID]
        except KeyError:
            LOG_ERROR('Invite ID is invalid', inviteID, self._IDMap)
            return

        invite.decline()
        if self.__unreadInvitesCount > 0:
            self.__unreadInvitesCount -= 1

    def revokeInvite(self, inviteID):
        try:
            invite = self.__invites[inviteID]
        except KeyError:
            LOG_ERROR('Invite ID is invalid', inviteID, self._IDMap)
            return

        invite.revoke()
        if self.__unreadInvitesCount > 0:
            self.__unreadInvitesCount -= 1

    def canAcceptInvite(self, invite):
        result = False
        if invite.alwaysAvailable is True:
            result = True
        elif invite.clientID in self.__invites:
            dispatcher = self.__loader.getDispatcher()
            if dispatcher:
                if invite.alreadyJoined:
                    return False
                if dispatcher.getEntity().hasLockedState():
                    return False
            another = invite.anotherPeriphery
            if another:
                if g_preDefinedHosts.periphery(invite.peripheryID) is None:
                    LOG_ERROR('Periphery not found')
                    result = False
                elif self.lobbyContext.getCredentials() is None:
                    LOG_ERROR('Login info not found')
                    result = False
                elif g_preDefinedHosts.isRoamingPeriphery(invite.peripheryID) and not isRoamingEnabled(self.itemsCache.items.stats.attributes):
                    LOG_ERROR('Roaming is not supported')
                    result = False
                else:
                    result = invite.clientID > 0 and invite.isActive()
            else:
                result = invite.clientID > 0 and invite.isActive()
        return result

    def canDeclineInvite(self, invite):
        result = False
        if invite.clientID in self.__invites:
            result = invite.clientID > 0 and invite.isActive()
        return result

    def canRevokeInvite(self, invite):
        result = False
        if invite.clientID in self.__invites:
            result = invite.clientID > 0 and invite.isActive() and invite.creatorDBID == getPlayerDatabaseID()
        return result

    def getInvites(self, incoming = None, version = None, onlyActive = None):
        result = self.__invites.values()
        if incoming is not None:
            result = filter(lambda item: item.isIncoming() is incoming, result)
        if version is not None:
            result = filter(lambda item: item.getVersion() == version, result)
        if onlyActive is not None:
            result = filter(lambda item: item.isActive() is onlyActive, result)
        return result

    def getInvite(self, inviteID):
        invite = None
        if inviteID in self.__invites:
            invite = self.__invites[inviteID]
        return invite

    def getReceivedInviteCount(self):
        return len(self.getReceivedInvites())

    def getReceivedInvites(self, IDs = None):
        result = self.getInvites(incoming=True)
        if IDs is not None:
            result = filter(lambda item: item.clientID in IDs, result)
        return result

    def getSentInvites(self, IDs = None):
        result = self.getInvites(incoming=False)
        if IDs is not None:
            result = filter(lambda item: item.clientID in IDs, result)
        return result

    def getSentInviteCount(self):
        return len(self.getSentInvites())

    def getUnreadCount(self):
        return self.__unreadInvitesCount

    def resetUnreadCount(self):
        self.__unreadInvitesCount = 0

    def onUserNamesReceived(self, names):
        updated = defaultdict(list)
        rosterGetter = self.users.getUser
        inviteMaker = self._getNewInviteMaker(rosterGetter)
        prebattleInvitations = _getNewInvites()
        for invite in self.getInvites(version=_INVITE_VERSION.NEW):
            if invite.creatorDBID in names or invite.receiverDBID in names:
                inviteUniqueId = UniqueId(id=invite.id, senderDBID=invite.creatorDBID)
                inviteData = prebattleInvitations.get(inviteUniqueId)
                inviteID, invite = inviteMaker(inviteData)
                if inviteData and self._updateInvite(invite, rosterGetter):
                    updated[invite.isIncoming()].append(inviteID)

        for isIncoming, event in ((True, self.onReceivedInviteListModified), (False, self.onSentInviteListModified)):
            if updated[isIncoming]:
                event([], updated[isIncoming], [])

    def _makeInviteID(self, prebattleID, peripheryID, senderDBID, receiverDBID):
        inviteKey = (prebattleID,
         peripheryID,
         senderDBID,
         receiverDBID)
        inviteID = self._IDMap.get(inviteKey)
        if inviteID is None:
            inviteID = self._IDGen.next()
            self._IDMap[inviteKey] = inviteID
        return inviteID

    def _addInvite(self, invite, userGetter):
        if self.__isInviteSenderIgnoredInBattle(invite, userGetter):
            return False
        self.__invites[invite.clientID] = invite
        if invite.isActive():
            self.__unreadInvitesCount += 1
        return True

    def _updateInvite(self, other, userGetter):
        inviteID = other.clientID
        invite = self.__invites[inviteID]
        if invite == other or not invite.isActive() and self.__isInviteSenderIgnoredInBattle(invite, userGetter):
            return False
        prevCount = invite.count
        invite = invite._merge(other)
        self.__invites[inviteID] = invite
        if invite.isActive() and prevCount < invite.count:
            self.__unreadInvitesCount += 1
        return True

    def _delInvite(self, inviteID):
        result = inviteID in self.__invites
        if result:
            self.__invites.pop(inviteID)
        return result

    def _buildReceivedInvitesList(self, invitesLists):
        if self.__inited & PRB_INVITES_INIT_STEP.DATA_BUILD == 0:
            self.__inited |= PRB_INVITES_INIT_STEP.DATA_BUILD
        self.__clearInvites()
        userGetter = self.users.getUser
        for invitesData, maker in invitesLists:
            for item in invitesData:
                _, invite = maker(item)
                if invite:
                    self._addInvite(invite, userGetter)

        if g_appLoader.getSpaceID() != GUI_GLOBAL_SPACE_ID.BATTLE:
            self.syncUsersInfo()

    def _rebuildInvitesLists(self):
        rosterGetter = self.users.getUser
        self._buildReceivedInvitesList([(_getOldInvites().items(), self._getOldInviteMaker(rosterGetter)), (_getNewInvites().values(), self._getNewInviteMaker(rosterGetter))])

    def _getOldInviteMaker(self, rosterGetter):
        receiver = getPlayerName()
        receiverDBID = getPlayerDatabaseID()
        receiverClanAbbrev = self.lobbyContext.getClanAbbrev(self.__clanInfo)

        def _inviteMaker(item):
            (prebattleID, peripheryID), data = item
            inviteID = self._makeInviteID(prebattleID, peripheryID, data['creatorDBID'], receiverDBID)
            if data is not None:
                invite = PrbInviteWrapper(clientID=inviteID, receiver=receiver, receiverDBID=receiverDBID, receiverClanAbbrev=receiverClanAbbrev, peripheryID=peripheryID, prebattleID=prebattleID, **data)
            else:
                invite = None
            return (inviteID, invite)

        return _inviteMaker

    def _getNewInviteMaker(self, rosterGetter):

        def _getUserName(userDBID):
            name, abbrev = ('', None)
            if userDBID:
                if g_appLoader.getSpaceID() == GUI_GLOBAL_SPACE_ID.BATTLE:
                    ctx = self.sessionProvider.getCtx()
                    isUserInBattle = ctx.getVehIDByAccDBID(userDBID) != 0
                    if isUserInBattle:
                        name, abbrev = ctx.getPlayerFullNameParts(accID=userDBID, showVehShortName=False)[1:3]
                if not name:
                    userName = self.getUserName(userDBID)
                    userClanAbbrev = self.getUserClanAbbrev(userDBID)
                    user = rosterGetter(userDBID)
                    if user and user.hasValidName():
                        name, abbrev = userName, userClanAbbrev
            return (name, abbrev)

        def _inviteMaker(item):
            peripheryID, prebattleID = PrbInvitationWrapper.getPrbInfo(item.get('info', {}))
            senderDBID = item.get('senderDBID', 0)
            receiverDBID = item.get('receiverDBID', 0)
            inviteID = self._makeInviteID(prebattleID, peripheryID, senderDBID, receiverDBID)
            senderName, senderClanAbbrev = _getUserName(senderDBID)
            receiverName, receiverClanAbbrev = _getUserName(receiverDBID)
            return (inviteID, PrbInvitationWrapper(inviteID, sender=senderName, senderClanAbbrev=senderClanAbbrev, receiver=receiverName, receiverClanAbbrev=receiverClanAbbrev, **item))

        return _inviteMaker

    def __initReceivedInvites(self):
        step = PRB_INVITES_INIT_STEP.CONTACTS_RECEIVED
        if self.__inited & step != step:
            return
        self._rebuildInvitesLists()
        if self.__inited == PRB_INVITES_INIT_STEP.INITED:
            self.onInvitesListInited()

    def __clearAcceptChain(self):
        if self.__acceptChain is not None:
            self.__acceptChain.onStopped -= self.__accept_onPostActionsStopped
            self.__acceptChain.stop()
            self.__acceptChain = None
        return

    def __me_onUsersListReceived(self, tags):
        doInit = False
        if USER_TAG.FRIEND in tags:
            doInit = True
            step = PRB_INVITES_INIT_STEP.FRIEND_RECEIVED
            if self.__inited & step == 0:
                self.__inited |= step
        if USER_TAG.IGNORED in tags or USER_TAG.IGNORED_TMP in tags:
            doInit = True
            step = PRB_INVITES_INIT_STEP.IGNORED_RECEIVED
            if self.__inited & step == 0:
                self.__inited |= step
        if doInit:
            self.__initReceivedInvites()

    def __pe_onPrebattleInvitesChanged(self, diff):
        step = PRB_INVITES_INIT_STEP.CONTACTS_RECEIVED
        if self.__inited & step != step:
            LOG_DEBUG('Received invites are ignored. Manager waits for client will receive contacts')
            return
        if ('prebattleInvites', '_r') in diff:
            self._rebuildInvitesLists()
        if 'prebattleInvites' in diff:
            self.__updateOldPrebattleInvites(_getOldInvites())

    def __pe_onPrebattleInvitationsChanged(self, invitations):
        step = PRB_INVITES_INIT_STEP.CONTACTS_RECEIVED
        if self.__inited & step != step:
            LOG_DEBUG('Received invites are ignored. Manager waits for client will receive contacts')
            return
        self.__updateNewPrebattleInvites(invitations)

    def __pe_onPrebattleInvitesStatus(self, dbID, name, status):
        if status != PREBATTLE_INVITE_STATUS.OK:
            statusName = PREBATTLE_INVITE_STATUS_NAMES[status]
            SystemMessages.pushI18nMessage('#system_messages:invite/status/%s' % statusName, name=name, type=SystemMessages.SM_TYPE.Warning)

    def __updateOldPrebattleInvites(self, prbInvites):
        added = []
        changed = []
        deleted = []
        modified = False
        rosterGetter = self.users.getUser
        inviteMaker = self._getOldInviteMaker(rosterGetter)
        for item in prbInvites.iteritems():
            inviteID, invite = inviteMaker(item)
            if invite is None:
                if self._delInvite(inviteID):
                    modified = True
                    deleted.append(inviteID)
                continue
            inList = inviteID in self.__invites
            if not inList:
                if self._addInvite(invite, rosterGetter):
                    modified = True
                    added.append(inviteID)
            elif self._updateInvite(invite, rosterGetter):
                modified = True
                changed.append(inviteID)

        if modified:
            self.onReceivedInviteListModified(added, changed, deleted)
        return

    def __updateNewPrebattleInvites(self, prbInvites):
        added = defaultdict(list)
        changed = defaultdict(list)
        deleted = defaultdict(list)
        modified = dict(((v, False) for v in (True, False)))
        rosterGetter = self.users.getUser
        inviteMaker = self._getNewInviteMaker(rosterGetter)
        newInvites = {}
        for data in prbInvites.itervalues():
            inviteID, invite = inviteMaker(data)
            if inviteID not in newInvites or invite.createTime > newInvites[inviteID].createTime:
                newInvites[inviteID] = invite

        for invite in self.getInvites(version=_INVITE_VERSION.NEW):
            inviteID = invite.clientID
            if inviteID not in newInvites and self._delInvite(inviteID):
                isIncoming = invite.isIncoming()
                modified[isIncoming] = True
                deleted[isIncoming].append(inviteID)
            else:
                continue

        for inviteID, invite in newInvites.iteritems():
            isIncoming = invite.isIncoming()
            if inviteID not in self.__invites:
                if self._addInvite(invite, rosterGetter):
                    modified[isIncoming] = True
                    added[isIncoming].append(inviteID)
            elif self._updateInvite(invite, rosterGetter):
                modified[isIncoming] = True
                changed[isIncoming].append(inviteID)

        for isIncoming, event in ((True, self.onReceivedInviteListModified), (False, self.onSentInviteListModified)):
            if modified[isIncoming]:
                event(added[isIncoming], changed[isIncoming], deleted[isIncoming])

        self.syncUsersInfo()

    def __accept_onPostActionsStopped(self, isCompleted):
        if not isCompleted:
            return
        invite = self.__acceptChain.invite
        invite.accept()
        if self.__unreadInvitesCount > 0:
            self.__unreadInvitesCount -= 1

    def __clearInvites(self):
        self.__invites.clear()
        self.__unreadInvitesCount = 0

    def __isInviteSenderIgnoredInBattle(self, invite, userGetter):
        return isInviteSenderIgnoredInBattle(userGetter(invite.creatorDBID), g_settings.userPrefs.invitesFromFriendsOnly, invite.isCreatedInBattle())
class BWChatProvider(object):
    __slots__ = ('__weakref__', '__handlers', '__msgFilters', '__coolDown',
                 '__idGen', '__isEnabled', '__queue')

    def __init__(self):
        super(BWChatProvider, self).__init__()
        self.__handlers = defaultdict(set)
        self.__msgFilters = None
        self.__coolDown = _ChatCooldownManager()
        self.__idGen = SequenceIDGenerator()
        self.__isEnabled = False
        self.__queue = []
        return

    def clear(self):
        self.__handlers.clear()
        BattleReplay.g_replayCtrl.delDataCallback(
            _REPLAY_ACTION_RECEIVED_CALLBACK,
            self.__onActionReceivedFromReplay)

    def goToReplay(self):
        BattleReplay.g_replayCtrl.setDataCallback(
            _REPLAY_ACTION_RECEIVED_CALLBACK,
            self.__onActionReceivedFromReplay)

    def setEnable(self, value):
        if self.__isEnabled == value:
            return
        self.__isEnabled = value
        if self.__isEnabled:
            self.__sendActionsFromQueue()
        else:
            self.__queue = []

    def doAction(self,
                 actionID,
                 args=None,
                 response=False,
                 skipCoolDown=False):
        success, reqID = False, 0
        if self.__coolDown.isInProcess(actionID):
            if not skipCoolDown:
                g_messengerEvents.onErrorReceived(
                    createCoolDownError(actionID))
        else:
            if response:
                reqID = self.__idGen.next()
            if self.__isEnabled:
                success = self.__sendAction(actionID, reqID, args)
            else:
                success = self.__addActionToQueue(actionID, reqID, args)
        return (success, reqID)

    def onActionReceived(self, actionID, reqID, args):
        if BattleReplay.g_replayCtrl.isRecording and self.__isActionWrittenToReplay(
                actionID):
            BattleReplay.g_replayCtrl.serializeCallbackData(
                _REPLAY_ACTION_RECEIVED_CALLBACK, (actionID, reqID, args))
        handlers = self.__handlers[actionID]
        for handler in handlers:
            try:
                handler((actionID, reqID), args)
            except TypeError:
                LOG_ERROR('Handler has been invoked with error', handler)
                LOG_CURRENT_EXCEPTION()

    def setFilters(self, msgFilterChain):
        self.__msgFilters = msgFilterChain

    def filterInMessage(self, message):
        text = self.__msgFilters.chainIn(message.accountDBID, message.text)
        if not text:
            result = None
        else:
            message.text = text
            result = message
        return result

    def filterOutMessage(self, text, limits):
        return self.__msgFilters.chainOut(text, limits)

    def setActionCoolDown(self, actionID, coolDown):
        self.__coolDown.process(actionID, coolDown)

    def isActionInCoolDown(self, actionID):
        return self.__coolDown.isInProcess(actionID)

    def getActionCoolDown(self, actionID):
        return self.__coolDown.getTime(actionID)

    def clearActionCoolDown(self, actionID):
        self.__coolDown.reset(actionID)

    def registerHandler(self, actionID, handler):
        handlers = self.__handlers[actionID]
        if handler in handlers:
            LOG_WARNING('Handler already is exist', actionID, handler)
        else:
            if not hasattr(handler, '__self__') or not isinstance(
                    handler.__self__, ActionsHandler):
                LOG_ERROR('Class of handler is not subclass of ActionsHandler',
                          handler)
                return
            if callable(handler):
                handlers.add(handler)
            else:
                LOG_ERROR('Handler is invalid', handler)

    def unregisterHandler(self, actionID, handler):
        handlers = self.__handlers[actionID]
        if handler in handlers:
            handlers.remove(handler)

    def __sendAction(self, actionID, reqID, args=None):
        player = BigWorld.player()
        if not player:
            LOG_ERROR('Player is not defined')
            return False
        player.base.messenger_onActionByClient_chat2(actionID, reqID, args
                                                     or messageArgs())
        return True

    def __addActionToQueue(self, actionID, reqID, args=None):
        self.__queue.append((actionID, reqID, args))
        return True

    def __sendActionsFromQueue(self):
        invokedIDs = set()
        while self.__queue:
            actionID, reqID, args = self.__queue.pop()
            if actionID in invokedIDs:
                LOG_WARNING(
                    'Action is ignored, your must send action after event "showGUI" is invoked',
                    actionID, reqID, args)
                continue
            self.__sendAction(actionID, reqID, args)
            invokedIDs.add(actionID)

    @staticmethod
    def __isActionWrittenToReplay(actionID):
        return actionID == _ACTIONS.INIT_BATTLE_CHAT or _ACTIONS.battleChatCommandFromActionID(
            actionID) is not None

    def __onActionReceivedFromReplay(self, actionID, reqID, args):
        self.onActionReceived(actionID, reqID, args)
Ejemplo n.º 37
0
class SortiesCache(object):
    __selectedID = (0, 0)
    __rosterTypeID = 0

    def __init__(self, controller):
        self.__controller = weakref.proxy(controller)
        self.__idGen = SequenceIDGenerator()
        self.__cache = {}
        self.__idToIndex = {}
        self.__indexToID = {}
        self.__selectedUnit = None
        self.__isRequestInProcess = False
        self.__cooldownRequest = None
        return

    def __del__(self):
        LOG_DEBUG('Sortie cache deleted:', self)

    def clear(self):
        self.__controller = None
        self.__cache.clear()
        self.__idToIndex.clear()
        self.__indexToID.clear()
        self.__selectedUnit = None
        if self.__cooldownRequest is not None:
            BigWorld.cancelCallback(self.__cooldownRequest)
            self.__cooldownRequest = None
        return

    def start(self):
        fort = self.__controller.getFort()
        if fort:
            fort.onSortieChanged += self.__fort_onSortieChanged
            fort.onSortieRemoved += self.__fort_onSortieRemoved
            fort.onSortieUnitReceived += self.__fort_onSortieUnitReceived
            self.__cache = self.__buildCache()
        else:
            LOG_ERROR('Client fort is not found')

    def stop(self):
        fort = self.__controller.getFort()
        if fort:
            fort.onSortieChanged -= self.__fort_onSortieChanged
            fort.onSortieRemoved -= self.__fort_onSortieRemoved
            fort.onSortieUnitReceived -= self.__fort_onSortieUnitReceived
        self.clear()

    def setController(self, controller):
        self.__controller = weakref.proxy(controller)

    @property
    def isRequestInProcess(self):
        return self.__isRequestInProcess

    @classmethod
    def getSelectedID(cls):
        return cls.__selectedID

    def clearSelectedID(self):
        self.__selectedUnit = None
        self._setSelectedID((0, 0))
        return

    def setSelectedID(self, selectedID):
        if selectedID not in self.__cache:
            LOG_WARNING('Item is not found in cache', selectedID)
            return False
        else:
            self.__selectedUnit = None
            self._setSelectedID(selectedID)
            if BigWorld.player().isLongDisconnectedFromCenter:
                self.__controller._listeners.notify('onSortieUnitReceived', self.__getClientIdx(selectedID))
                return True
            unit = self.getSelectedUnit()
            if unit and not self.__cache[selectedID]._isDirty:
                self.__controller._listeners.notify('onSortieUnitReceived', self.__getClientIdx(selectedID))
            else:
                self._requestSortieUnit(selectedID)
            return True

    @classmethod
    def getRosterTypeID(cls):
        return cls.__rosterTypeID

    def setRosterTypeID(self, rosterTypeID):
        result = self._setRosterTypeID(rosterTypeID)
        if result:
            self.__cache = self.__buildCache()
        return result

    def getItem(self, sortieID):
        try:
            item = self.__cache[sortieID]
        except KeyError:
            LOG_ERROR('Item not found in cache', sortieID)
            item = None

        return item

    def getUnitByIndex(self, index):
        unit = None
        if index in self.__indexToID:
            sortieID = self.__indexToID[index]
            unit = self.__getUnit(sortieID)
        return unit

    def getSelectedUnit(self):
        return self.__getUnit(self.getSelectedID())

    def getIterator(self):
        for item in self.__cache.itervalues():
            if item.filter(self.__rosterTypeID):
                yield item

    def _requestSortieUnit(self, selectedID):
        Waiting.show('fort/sortie/get')
        if self.__cooldownRequest is not None:
            Waiting.hide('fort/sortie/get')
            BigWorld.cancelCallback(self.__cooldownRequest)
            self.__cooldownRequest = None
        ctx = RequestSortieUnitCtx(waitingID='', *selectedID)

        def requester():
            self.__cooldownRequest = None
            self.__isRequestInProcess = True
            self.__controller.request(ctx, self.__requestCallback)
            return

        if self.__controller._cooldown.isInProcess(ctx.getRequestType()):
            self.__cooldownRequest = BigWorld.callback(self.__controller._cooldown.getTime(ctx.getRequestType()), requester)
        else:
            requester()
        return

    @classmethod
    def _setSelectedID(cls, selectedID):
        result = False
        if selectedID != cls.__selectedID and len(selectedID) == 2:
            cls.__selectedID = selectedID
            result = True
        return result

    @classmethod
    def _setRosterTypeID(cls, rosterTypeID):
        result = False
        if rosterTypeID != cls.__rosterTypeID:
            cls.__rosterTypeID = rosterTypeID
            result = True
        return result

    @classmethod
    def _removeStoredData(cls):
        cls.__selectedID = (0, 0)
        cls.__rosterTypeID = 0

    def __buildCache(self):
        cache = {}
        fort = self.__controller.getFort()
        if not fort:
            LOG_WARNING('Client fort is not found')
            return cache
        sorties = fort.getSorties()
        selectedID = self.getSelectedID()
        found = False
        for sortieID, sortie in sorties.iteritems():
            item = SortieItem(sortieID, sortie)
            if not found and item.getID() == selectedID:
                found = True
            cache[sortieID] = item

        if not found:
            self.clearSelectedID()
        return cache

    def __updateItem(self, sortieID, fort):
        sortie = fort.getSortieShortData(*sortieID)
        if sortie is None:
            LOG_ERROR('Sortie is not found', sortieID, fort.sorties)
            return
        else:
            if sortieID in self.__cache:
                item = self.__cache[sortieID]
                item._updateItemData(sortie)
                if item._isDirty and self.__selectedID == item.getID() and item.filter(self.getRosterTypeID()):
                    self.__selectedUnit = None
                    self._requestSortieUnit(sortieID)
            else:
                item = SortieItem(sortieID, sortie)
                self.__cache[sortieID] = item
            return item

    def __requestCallback(self, _):
        Waiting.hide('fort/sortie/get')
        self.__isRequestInProcess = False

    def __removeItem(self, sortieID):
        result = False
        if sortieID in self.__cache:
            self.__cache.pop(sortieID)
            result = True
        if self.getSelectedID() == sortieID:
            self.clearSelectedID()
        clientIdx = self.__idToIndex.pop(sortieID, None)
        if clientIdx is not None:
            self.__indexToID.pop(clientIdx, None)
        return result

    def __getClientIdx(self, sortieID):
        if sortieID == (0, 0):
            return 0
        if sortieID not in self.__idToIndex:
            clientIdx = self.__idGen.next()
            self.__idToIndex[sortieID] = clientIdx
            self.__indexToID[clientIdx] = sortieID
        else:
            clientIdx = self.__idToIndex[sortieID]
        return clientIdx

    def __getUnit(self, sortieID):
        fort = self.__controller.getFort()
        if not fort:
            LOG_WARNING('Client fort is not found')
            return
        else:
            isSelected = self.getSelectedID() == sortieID
            if isSelected and self.__selectedUnit is not None:
                return self.__selectedUnit
            unit = fort.getSortieUnit(*sortieID)
            if isSelected:
                self.__selectedUnit = unit
            return unit

    def __fort_onSortieChanged(self, unitMgrID, peripheryID):
        fort = self.__controller.getFort()
        sortieID = (unitMgrID, peripheryID)
        if fort:
            item = self.__updateItem(sortieID, fort)
            if item:
                self.__controller._listeners.notify('onSortieChanged', self, item)

    def __fort_onSortieRemoved(self, unitMgrID, peripheryID):
        sortieID = (unitMgrID, peripheryID)
        if self.__removeItem(sortieID):
            self.__controller._listeners.notify('onSortieRemoved', self, sortieID)

    def __fort_onSortieUnitReceived(self, unitMgrID, peripheryID):
        fort = self.__controller.getFort()
        sortieID = (unitMgrID, peripheryID)
        if fort:
            if unitMgrID in self.__cache:
                self.__cache[sortieID]._isDirty = False
            if self.getSelectedID() == sortieID:
                self.__selectedUnit = None
            self.__controller._listeners.notify('onSortieUnitReceived', self.__getClientIdx(sortieID))
        return
Ejemplo n.º 38
0
class BrowserController(Controller):
    _BROWSER_TEXTURE = 'BrowserBg'
    _ALT_BROWSER_TEXTURE = 'AltBrowserBg'

    def __init__(self, proxy):
        super(BrowserController, self).__init__(proxy)
        self.__browsers = {}
        self.__browsersCallbacks = {}
        self.__browserIDGenerator = SequenceIDGenerator()
        self.__eventMgr = Event.EventManager()
        self.onBrowserAdded = Event.Event(self.__eventMgr)
        self.onBrowserDeleted = Event.Event(self.__eventMgr)
        self.__urlMacros = URLMarcos()
        self.__pendingBrowsers = {}
        self.__creatingBrowserID = None
        self.__filters = _getGlobalFilters()
        return

    def fini(self):
        self.__filters = None
        self.__eventMgr.clear()
        self.__eventMgr = None
        self.__urlMacros.clear()
        self.__urlMacros = None
        self.__browserIDGenerator = None
        super(BrowserController, self).fini()
        return

    def onAvatarBecomePlayer(self):
        self.__stop()

    def onDisconnected(self):
        self.__stop()

    def addFilterHandler(self, handler):
        """ Adds given @handler to the browser urls filter chain. Calls
        it if there is a @tag in url onto opened browser page.
        Handler should receive url and list of client-specific tags,
        return bool as flag that routine have to stop
        """
        self.__filters.add(handler)

    def removeFilterHandler(self, handler):
        """ Remove given @handler from filtering chain. Handler description
        can be seen in addFilterhandler method doc-string
        """
        self.__filters.discard(handler)

    @async
    @process
    def load(self, url = None, title = None, showActionBtn = True, showWaiting = True, browserID = None, isAsync = False, browserSize = None, isDefault = True, callback = None, showCloseBtn = False, useBrowserWindow = True):
        url = yield self.__urlMacros.parse(url or GUI_SETTINGS.browser.url)
        suffix = yield self.__urlMacros.parse(GUI_SETTINGS.browser.params)
        concatenator = '&' if '?' in url else '?'
        if suffix not in url:
            url = concatenator.join([url, suffix])
        size = browserSize or BROWSER.SIZE
        webBrowserID = browserID
        if browserID is None:
            browserID = self.__browserIDGenerator.next()
            webBrowserID = browserID
        elif type(browserID) is not int:
            webBrowserID = self.__browserIDGenerator.next()
        ctx = {'url': url,
         'title': title,
         'showActionBtn': showActionBtn,
         'showWaiting': showWaiting,
         'browserID': browserID,
         'size': size,
         'isAsync': isAsync,
         'showCloseBtn': showCloseBtn,
         'showWindow': useBrowserWindow}
        texture = browserID not in self.__browsers and browserID not in self.__pendingBrowsers and self._BROWSER_TEXTURE
        app = g_appLoader.getApp()
        if not app:
            raise AssertionError('Application can not be None')
            browser = WebBrowser(webBrowserID, app, texture, size, url, handlers=self.__filters)
            self.__browsers[browserID] = browser
            if self.__isCreatingBrowser():
                self.__pendingBrowsers[browserID] = ctx
            else:
                self.__createBrowser(ctx)
        elif browserID in self.__pendingBrowsers:
            self.__pendingBrowsers[browserID] = ctx
        elif browserID in self.__browsers:
            self.__browsers[browserID].navigate(url)
        callback(browserID)
        return

    def getBrowser(self, browserID):
        return self.__browsers.get(browserID)

    def delBrowser(self, browserID):
        if browserID in self.__browsers:
            browser = self.__browsers.pop(browserID)
            loadStart, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None))
            if loadStart is not None:
                browser.onLoadStart -= loadStart
            if loadEnd is not None:
                browser.onLoadEnd -= loadEnd
            browser.destroy()
            if self.__creatingBrowserID == browserID:
                self.__creatingBrowserID = None
                self.__tryCreateNextPendingBrowser()
        self.onBrowserDeleted(browserID)
        return

    def __isCreatingBrowser(self):
        return self.__creatingBrowserID is not None

    def __createDone(self, ctx):
        self.__creatingBrowserID = None
        g_eventBus.handleEvent(BrowserEvent(BrowserEvent.BROWSER_CREATED, ctx=ctx))
        self.__tryCreateNextPendingBrowser()
        return

    def __tryCreateNextPendingBrowser(self):
        if len(self.__pendingBrowsers) > 0:
            nextCtx = self.__pendingBrowsers.popitem()[1]
            self.__createBrowser(nextCtx)

    def __createBrowser(self, ctx):
        browserID = ctx['browserID']
        self.__creatingBrowserID = browserID
        self.__browsers[browserID].create()
        self.onBrowserAdded(browserID)

        def browserCallback(url, isLoaded):
            self.__clearCallback(browserID)
            if isLoaded:
                self.__showBrowser(browserID, ctx)
            else:
                LOG_WARNING('Browser request url was not loaded!', url)
            self.__createDone(browserID)

        if ctx['isAsync']:
            self.__browsersCallbacks[browserID] = (None, browserCallback)
            self.__browsers[browserID].onLoadEnd += browserCallback
        else:
            self.__browsersCallbacks[browserID] = (browserCallback, None)
            self.__browsers[browserID].onReady += browserCallback
        return

    def __stop(self):
        while self.__browsers:
            browserID, browser = self.__browsers.popitem()
            ready, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None))
            if ready is not None:
                browser.onReady -= ready
            if loadEnd is not None:
                browser.onLoadEnd -= loadEnd
            browser.destroy()

        return

    def __clearCallback(self, browserID):
        ready, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None))
        if ready is not None:
            self.__browsers[browserID].onReady -= ready
        if loadEnd is not None:
            self.__browsers[browserID].onLoadEnd -= loadEnd
        return

    def __showBrowser(self, browserID, ctx):
        if ctx.get('showWindow'):
            g_eventBus.handleEvent(LoadViewEvent(VIEW_ALIAS.BROWSER_WINDOW, getViewName(VIEW_ALIAS.BROWSER_WINDOW, browserID), ctx=ctx), EVENT_BUS_SCOPE.LOBBY)
Ejemplo n.º 39
0
class FortBattlesCache(object):
    __selectedID = 0

    def __init__(self, controller):
        self.__controller = weakref.proxy(controller)
        self.__idGen = SequenceIDGenerator()
        self.__cache = {}
        self.__idToIndex = {}
        self.__indexToID = {}
        self.__selectedUnit = None
        self.__isRequestInProcess = False
        return

    def __del__(self):
        LOG_DEBUG('Fort battles cache deleted:', self)

    def clear(self):
        self.__controller = None
        self.__cache.clear()
        self.__idToIndex.clear()
        self.__indexToID.clear()
        self.__selectedUnit = None
        return

    def start(self):
        fort = self.__controller.getFort()
        if fort:
            fort.onFortBattleChanged += self.__fort_onFortBattleChanged
            fort.onFortBattleRemoved += self.__fort_onFortBattleRemoved
            fort.onFortBattleUnitReceived += self.__fort_onFortBattleUnitReceived
            fort.onEnemyStateChanged += self.__fort_onEnemyStateChanged
            self.__cache = self.__buildCache()
        else:
            LOG_ERROR('Client fort is not found')

    def stop(self):
        fort = self.__controller.getFort()
        if fort:
            fort.onFortBattleChanged -= self.__fort_onFortBattleChanged
            fort.onFortBattleRemoved -= self.__fort_onFortBattleRemoved
            fort.onFortBattleUnitReceived -= self.__fort_onFortBattleUnitReceived
            fort.onEnemyStateChanged -= self.__fort_onEnemyStateChanged
        self.clear()

    @property
    def isRequestInProcess(self):
        return self.__isRequestInProcess

    @classmethod
    def getSelectedID(cls):
        return cls.__selectedID

    def getSelectedIdx(self):
        return self.__getClientIdx(self.getSelectedID())

    def clearSelectedID(self):
        self.__selectedUnit = None
        self._setSelectedID(0)
        return

    def setSelectedID(self, selectedID):
        if selectedID not in self.__cache:
            LOG_WARNING('Item is not found in cache', selectedID)
            return False
        else:
            self.__selectedUnit = None
            return self._setSelectedID(selectedID)

    def getItem(self, battleID):
        try:
            item, fortBattle = self.__cache[battleID]
        except KeyError:
            LOG_ERROR('Item not found in cache', battleID)
            item = None
            fortBattle = None

        return (item, fortBattle)

    def getUnitByIndex(self, index):
        unit = None
        if index in self.__indexToID:
            battleID = self.__indexToID[index]
            unit = self.__getUnit(battleID)
        return unit

    def getSelectedUnit(self):
        return self.__getUnit(self.getSelectedID())

    def getIterator(self):
        for item, battleItem in self.__cache.itervalues():
            if item.filter():
                yield (item, battleItem)

    @classmethod
    def _setSelectedID(cls, selectedID):
        result = False
        if selectedID != cls.__selectedID:
            cls.__selectedID = selectedID
            result = True
        return result

    @classmethod
    def _removeStoredData(cls):
        cls.__selectedID = (0, 0)

    def __buildCache(self):
        cache = {}
        fort = self.__controller.getFort()
        if not fort:
            LOG_WARNING('Client fort is not found')
            return cache
        fortBattles = fort.getAttacksAndDefencesIn(timePeriod=2 * time_utils.ONE_WEEK)
        selectedID = self.getSelectedID()
        found = False
        for item in fortBattles:
            battleID = item.getBattleID()
            if not found and battleID == selectedID:
                found = True
            battleItem = fort.getBattle(battleID)
            cache[battleID] = (item, battleItem)

        if not found:
            self.clearSelectedID()
        return cache

    def __updateItem(self, battleID, fort):
        item = fort.getBattleItemByBattleID(battleID)
        if item is None:
            LOG_ERROR('Fort battle is not found', battleID, fort.attacks, fort.defences)
            return (None, None)
        else:
            fortBattle = fort.getBattle(battleID)
            self.__cache[battleID] = (item, fortBattle)
            if self.getSelectedID() == battleID:
                self.__selectedUnit = None
            return (item, fortBattle)

    def __requestCallback(self, _):
        self.__isRequestInProcess = False

    def __removeItem(self, battleID):
        result = False
        if battleID in self.__cache:
            self.__cache.pop(battleID)
            result = True
        if self.getSelectedID() == battleID:
            self.clearSelectedID()
        clientIdx = self.__idToIndex.pop(battleID, None)
        if clientIdx is not None:
            self.__indexToID.pop(clientIdx, None)
        return result

    def __getClientIdx(self, battleID):
        if battleID == 0:
            return 0
        if battleID not in self.__idToIndex:
            clientIdx = self.__idGen.next()
            self.__idToIndex[battleID] = clientIdx
            self.__indexToID[clientIdx] = battleID
        else:
            clientIdx = self.__idToIndex[battleID]
        return clientIdx

    def __getUnit(self, battleID):
        fort = self.__controller.getFort()
        if not fort:
            LOG_WARNING('Client fort is not found')
            return
        else:
            isSelected = battleID == self.getSelectedID()
            if isSelected and self.__selectedUnit is not None:
                return self.__selectedUnit
            unit = fort.getFortBattleUnit(battleID)
            if isSelected:
                self.__selectedUnit = unit
            return unit

    def __fort_onEnemyStateChanged(self, battleID, isReady):
        fort = self.__controller.getFort()
        if fort:
            item, battleItem = self.__updateItem(battleID, fort)
            if item:
                self.__controller._listeners.notify('onFortBattleChanged', self, item, battleItem)

    def __fort_onFortBattleChanged(self, battleID):
        fort = self.__controller.getFort()
        if fort:
            item, battleItem = self.__updateItem(battleID, fort)
            if item:
                self.__controller._listeners.notify('onFortBattleChanged', self, item, battleItem)

    def __fort_onFortBattleRemoved(self, battleID):
        if self.__removeItem(battleID):
            self.__controller._listeners.notify('onFortBattleRemoved', self, battleID)

    def __fort_onFortBattleUnitReceived(self, battleID):
        fort = self.__controller.getFort()
        if fort:
            if self.__selectedID == battleID:
                self.__selectedUnit = None
            self.__controller._listeners.notify('onFortBattleUnitReceived', self.__getClientIdx(battleID))
        return
Ejemplo n.º 40
0
class BrowserController(Controller):
    _BROWSER_TEXTURE = 'BrowserBg'
    _ALT_BROWSER_TEXTURE = 'AltBrowserBg'

    def __init__(self, proxy):
        super(BrowserController, self).__init__(proxy)
        self.__browsers = {}
        self.__browsersCallbacks = {}
        self.__browserIDGenerator = SequenceIDGenerator()
        self.__eventMgr = Event.EventManager()
        self.onBrowserAdded = Event.Event(self.__eventMgr)
        self.onBrowserDeleted = Event.Event(self.__eventMgr)
        self.__urlMacros = URLMarcos()
        self.__pendingBrowsers = {}
        self.__creatingBrowser = False

    def fini(self):
        self.__eventMgr.clear()
        self.__eventMgr = None
        self.__urlMacros.clear()
        self.__urlMacros = None
        self.__browserIDGenerator = None
        super(BrowserController, self).fini()
        return

    def onAvatarBecomePlayer(self):
        self.__stop()

    def onDisconnected(self):
        self.__stop()

    @async
    @process
    def load(self, url = None, title = None, showActionBtn = True, showWaiting = True, browserID = None, isAsync = False, browserSize = None, isDefault = True, callback = None, showCloseBtn = False, useWhitelisting = False):
        url = yield self.__urlMacros.parse(url or GUI_SETTINGS.browser.url)
        suffix = yield self.__urlMacros.parse(GUI_SETTINGS.browser.params)
        concatenator = '&' if '?' in url else '?'
        if suffix not in url:
            url = concatenator.join([url, suffix])
        size = browserSize or BROWSER.SIZE
        webBrowserID = browserID
        if browserID is None:
            browserID = self.__browserIDGenerator.next()
            webBrowserID = browserID
        elif type(browserID) is not int:
            webBrowserID = self.__browserIDGenerator.next()
        ctx = {'url': url,
         'title': title,
         'showActionBtn': showActionBtn,
         'showWaiting': showWaiting,
         'browserID': browserID,
         'size': size,
         'isDefault': isDefault,
         'isAsync': isAsync,
         'showCloseBtn': showCloseBtn}
        texture = browserID not in self.__browsers and browserID not in self.__pendingBrowsers and (self._BROWSER_TEXTURE if isDefault else self._ALT_BROWSER_TEXTURE)
        app = g_appLoader.getApp()
        if not app:
            raise AssertionError('Application can not be None')
            browser = WebBrowser(webBrowserID, app, texture, size, url, useWhitelisting)
            self.__browsers[browserID] = browser
            if self.__creatingBrowser:
                self.__pendingBrowsers[browserID] = ctx
            else:
                self.__createBrowser(ctx)
        elif browserID in self.__pendingBrowsers:
            self.__pendingBrowsers[browserID] = ctx
        elif browserID in self.__browsers:
            self.__browsers[browserID].navigate(url)
        callback(browserID)
        return

    def __createDone(self, browserID):
        self.__creatingBrowser = False
        if len(self.__pendingBrowsers) > 0:
            ctx = self.__pendingBrowsers.popitem()[1]
            self.__createBrowser(ctx)

    def __createBrowser(self, ctx):
        self.__creatingBrowser = True
        browserID = ctx['browserID']
        self.__browsers[browserID].create()
        self.onBrowserAdded(browserID)

        def browserCallback(*args):
            self.__clearCallback(browserID)
            self.__showBrowser(browserID, ctx)
            self.__createDone(browserID)

        def browserAsyncCallback(url, isLoaded):
            self.__clearCallback(browserID)
            if isLoaded:
                self.__showBrowser(browserID, ctx)
            else:
                LOG_WARNING('Browser async request url was not loaded!', url)
            self.__createDone(browserID)

        if ctx['isAsync']:
            self.__browsersCallbacks[browserID] = (None, browserAsyncCallback)
            self.__browsers[browserID].onLoadEnd += browserAsyncCallback
        else:
            self.__browsersCallbacks[browserID] = (browserCallback, None)
            self.__browsers[browserID].onReady += browserCallback
        return

    def getBrowser(self, browserID):
        return self.__browsers.get(browserID)

    def delBrowser(self, browserID):
        if browserID in self.__browsers:
            browser = self.__browsers.pop(browserID)
            loadStart, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None))
            if loadStart is not None:
                browser.onLoadStart -= loadStart
            if loadEnd is not None:
                browser.onLoadEnd -= loadEnd
            browser.destroy()
        self.onBrowserDeleted(browserID)
        return

    def __stop(self):
        while self.__browsers:
            browserID, browser = self.__browsers.popitem()
            ready, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None))
            if ready is not None:
                browser.onReady -= ready
            if loadEnd is not None:
                browser.onLoadEnd -= loadEnd
            browser.destroy()

        return

    def __clearCallback(self, browserID):
        ready, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None))
        if ready is not None:
            self.__browsers[browserID].onReady -= ready
        if loadEnd is not None:
            self.__browsers[browserID].onLoadEnd -= loadEnd
        return

    def __showBrowser(self, browserID, ctx):
        g_eventBus.handleEvent(LoadViewEvent(VIEW_ALIAS.BROWSER_WINDOW, getViewName(VIEW_ALIAS.BROWSER_WINDOW, browserID), ctx=ctx), EVENT_BUS_SCOPE.LOBBY)
Ejemplo n.º 41
0
class MarathonRewardWindowView(ViewImpl):
    eventsCache = dependency.descriptor(IEventsCache)
    marathonController = dependency.descriptor(IMarathonEventsController)
    c11n = dependency.descriptor(ICustomizationService)
    itemsCache = dependency.descriptor(IItemsCache)

    def __init__(self, ctx, *args, **kwargs):
        settings = ViewSettings(R.views.lobby.marathon.RewardWindow())
        settings.flags = ViewFlags.VIEW
        settings.model = MarathonPrizeRewardModel()
        super(MarathonRewardWindowView, self).__init__(settings, *args, **kwargs)
        self.__rewards = []
        self.__convertRewards(ctx)
        self.__marathon = self.marathonController.getMarathon(ctx.get('marathonPrefix'))
        self.__idGen = SequenceIDGenerator()
        self.__bonusCache = {}

    @property
    def viewModel(self):
        return super(MarathonRewardWindowView, self).getViewModel()

    def createToolTipContent(self, event, contentID):
        if event.contentID == R.views.lobby.marathon.tooltips.RestRewardTooltip() and len(self.__rewards) > MAX_REWARDS_COUNT:
            restRewards = self.__rewards[MAX_REWARDS_COUNT:]
            formatterRewards = self.__formatterRewards(restRewards, False)
            return MarathonRewardTooltipContent(formatterRewards)
        return super(MarathonRewardWindowView, self).createToolTipContent(event, contentID)

    def createToolTip(self, event):
        tooltipId = event.getArgument('tooltipId')
        if not tooltipId:
            return super(MarathonRewardWindowView, self).createToolTip(event)
        bonus = self.__bonusCache.get(tooltipId)
        if bonus:
            window = BackportTooltipWindow(createTooltipData(tooltip=bonus.tooltip, isSpecial=bonus.isSpecial, specialAlias=bonus.specialAlias, specialArgs=bonus.specialArgs), self.getParentWindow())
            window.load()
            return window
        return super(MarathonRewardWindowView, self).createToolTip(event)

    def _onLoading(self, *args, **kwargs):
        super(MarathonRewardWindowView, self)._onLoading(*args, **kwargs)
        with self.viewModel.transaction() as model:
            self._fillModel(model)

    def _initialize(self, *args, **kwargs):
        super(MarathonRewardWindowView, self)._initialize(*args, **kwargs)
        self._addListeners()

    def _finalize(self):
        self._removeListeners()
        self.__bonusCache.clear()
        super(MarathonRewardWindowView, self)._finalize()

    def _addListeners(self):
        self.viewModel.onAcceptClicked += self._onAccepted
        self.viewModel.onCancelClicked += self._onCancel
        self.viewModel.onSecondaryClicked += self._onSecondary

    def _removeListeners(self):
        self.viewModel.onAcceptClicked -= self._onAccepted
        self.viewModel.onCancelClicked -= self._onCancel
        self.viewModel.onSecondaryClicked -= self._onSecondary

    def _getVehicleObtainedTitle(self):
        current, last = self.__marathon.getMarathonProgress()
        if current == 0:
            return R.strings.marathon.reward.stageAllComplete()
        return R.strings.marathon.reward.stageNotAllComplete() if current < last else R.strings.marathon.reward.stageCompleteLast()

    def _fillModel(self, model):
        isMainProgressionReward = not self.__marathon.isPostRewardObtained()
        vehicle = self.__marathon.vehicle
        self._fillRewards(model)
        if isMainProgressionReward:
            stage = 1
            suptitle = self._getVehicleObtainedTitle()
            model.setSupTitle(suptitle)
            model.setTitle(R.strings.marathon.reward.vehicleTitle())
            model.setSubTitle(R.strings.marathon.reward.nameVehicle())
            model.setImage(_ICON_PATH.vehicle_image_cn() if IS_CHINA else _ICON_PATH.vehicle_image())
            model.vehicle.setName(vehicle.userName)
            model.vehicle.setType(vehicle.type)
            model.vehicle.setLevel(vehicle.level)
        else:
            stage = 2
            model.setSupTitle(R.strings.marathon.reward.stageStyle())
            model.setTitle(R.strings.marathon.reward.styleTitle())
            model.setSubTitle(R.strings.marathon.reward.nameStyle())
            model.setImage(_ICON_PATH.style_image_cn() if IS_CHINA else _ICON_PATH.style_image())
            model.setIconReward(_ICON_PATH.style_reward())
        model.setHasVehicle(isMainProgressionReward)
        model.setStage(stage)

    def _onAccepted(self, *args):
        self.destroyWindow()
        if not self.__marathon.isPostRewardObtained():
            selectVehicleInHangar(self.__marathon.vehicle.compactDescr)

    def _onCancel(self):
        self.destroyWindow()

    def _onSecondary(self):
        if self.__marathon.vehicle.isInInventory:
            self.c11n.showCustomization(self.__marathon.vehicle.invID)
        else:
            style = self.c11n.getItemByID(GUI_ITEM_TYPE.STYLE, self.__marathon.styleID)
            showStylePreview(self.__marathon.vehicle.compactDescr, style, style.getDescription(), showHangar)

    def _fillRewards(self, model):
        rewardsCount = len(self.__rewards)
        if rewardsCount > MAX_REWARDS_COUNT:
            rewards = self.__rewards[:MAX_REWARDS_COUNT]
            restRewardsCount = rewardsCount - MAX_REWARDS_COUNT
            model.setRewards(self.__formatterRewards(rewards, True))
            model.setRestRewardsCount(restRewardsCount)
        else:
            model.setRewards(self.__formatterRewards(self.__rewards, True))
            model.setRestRewardsCount(0)

    def __formatterRewards(self, rewards, addTooltip=False):
        results = Array()
        for reward in rewards:
            model = BonusModel()
            model.setName(reward.bonusName)
            model.setIcon(getRewardImage(reward.images['big']))
            model.setLabel(getRewardLabel(reward.label))
            model.setOverlayType(getRewardOverlayType(reward.overlayType))
            if addTooltip:
                self.__setTooltip(model, reward)
            else:
                model.setDescription(reward.userName)
            results.addViewModel(model)

        return results

    def __setTooltip(self, model, reward):
        tooltipId = '{}'.format(self.__idGen.next())
        self.__bonusCache[tooltipId] = reward
        model.setTooltipId(tooltipId)

    def __sortRewardsByPriority(self, rewards, priority=REWARDS_PRIORITY, defaultPriority=len(REWARDS_PRIORITY)):
        rewards.sort(key=lambda x: self.__sortRewardsFunc(x, priority, defaultPriority))
        return rewards

    def __sortRewardsFunc(self, bonus, priority, defaultPriority):
        name = bonus.getName()
        if name == 'items':
            epicBonusList = bonus.getWrappedEpicBonusList()
            if epicBonusList:
                id_ = epicBonusList[0]['id']
                name = self.itemsCache.items.getItemByCD(id_).itemTypeName
        return priority.index(name) if name in priority else defaultPriority

    def __convertRewards(self, ctx):
        self.__rewards = ctx.get('rewards', [])
        self.__rewards = splitBonuses(self.__rewards)
        crewRewards = ctx.get('crewRewards', None)
        if crewRewards:
            self.__rewards.append(crewRewards)
        self.__rewards = self.__sortRewardsByPriority(self.__rewards)
        formatter = getMarathonRewardScreenPacker()
        self.__rewards = formatter.format(self.__rewards)
        return