Exemple #1
0
    def test_keys(self):
        cache = LRUCache(5, 60)
        samples = {
            "a": {"a": 123, "b": 456},
            "bc": {"z": 156}, 
            "foo": 223,
            "bar": "adada"}

        for key in samples:
            cache.set(key, samples[key])

        self.assertListEqual(cache.keys(), samples.keys())
        
        for key in samples:
            self.assertTrue(cache.has_key(key))
            self.assertEqual(cache.get(key), samples[key])
Exemple #2
0
class EDRLegalRecords(object):
    EDR_LEGAL_RECORDS_CACHE = utils2to3.abspathmaker(__file__, 'cache', 'legal_records.v3.p')
    
    def __init__(self, server):
        self.server = server
        
        self.timespan = None
        self.records_check_interval = None
        config = EDRConfig()
        try:
            with open(self.EDR_LEGAL_RECORDS_CACHE, 'rb') as handle:
                self.records = pickle.load(handle)
        except:
            self.records = LRUCache(config.lru_max_size(), config.legal_records_max_age())
        
        self.timespan = config.legal_records_recent_threshold()
        self.records_check_interval = config.legal_records_check_interval()
    
    def persist(self):
        with open(self.EDR_LEGAL_RECORDS_CACHE, 'wb') as handle:
            pickle.dump(self.records, handle, protocol=pickle.HIGHEST_PROTOCOL)
    
    def summarize(self, cmdr_id):
        if not cmdr_id:
            EDRLOG.log(u"No cmdr_id, no records for {}".format(cmdr_id), "INFO")
            return None
        self.__update_records_if_stale(cmdr_id)
        records = self.records.get(cmdr_id)["records"] if self.records.has_key(cmdr_id) else None
        if not records:
            EDRLOG.log(u"No legal records for {}".format(cmdr_id), "INFO")
            return None
        
        EDRLOG.log(u"Got legal records for {}".format(cmdr_id), "INFO")
        overview = None
        (clean, wanted, bounties, recent_stats) = self.__process(records)
        timespan = EDTime.pretty_print_timespan(self.timespan, short=True, verbose=True)
        maxB = u""
        lastB = u""
        if recent_stats["maxBounty"]:
            max_bounty = EDFineOrBounty(recent_stats["maxBounty"]).pretty_print()
            maxB = _(u", max={} cr").format(max_bounty)

        if "last" in recent_stats and recent_stats["last"].get("value", None) and (recent_stats["last"].get("starSystem", "") not in ["", "unknown", "Unknown"]):
            tminus = EDTime.t_minus(recent_stats["last"]["timestamp"], short=True)
            last_bounty = EDFineOrBounty(recent_stats["last"]["value"]).pretty_print()
            lastB = _(u", last: {} cr in {} {}").format(last_bounty, recent_stats["last"]["starSystem"], tminus)
        
        # Translators: this is an overview of a cmdr's recent legal history for the 'last {}' days, number of clean and wanted scans, and optionally max and last bounties
        overview = _(u"[Past {}] clean:{} / wanted:{}{}{}").format(timespan, recent_stats["clean"], recent_stats["wanted"], maxB, lastB)
        return {"overview": overview, "clean": clean, "wanted": wanted, "bounties": bounties}

    def __are_records_stale_for_cmdr(self, cmdr_id):
        if self.records.get(cmdr_id) is None:
            return True
        last_updated = self.records.get(cmdr_id)["last_updated"]
        now = datetime.datetime.now()
        epoch_now = time.mktime(now.timetuple())
        epoch_updated = time.mktime(last_updated.timetuple())
        return (epoch_now - epoch_updated) > self.records_check_interval

    
    def __update_records_if_stale(self, cmdr_id):
        updated = False
        if self.__are_records_stale_for_cmdr(cmdr_id):
            now = datetime.datetime.now() 
            records = self.server.legal_stats(cmdr_id)
            self.records.set(cmdr_id, {"last_updated": now, "records": records})
            updated = True
        return updated

    def __process(self, legal_stats):
        last = self.__emptyMonthlyBag()
        clean = []
        wanted = []
        bounties = []       
        recent_stats = {"clean": 0, "wanted": 0, "maxBounty": 0, "last": {"value": 0, "timestamp": None, "starSystem": None}}
        now_date = datetime.datetime.now()
        currentYear = now_date.year
        currentMonth = now_date.month
        orderly = self.__orderlyMonthNo()
        monthSpan = int(min(12, round(1 + (self.timespan / (60*60*24) - now_date.day)/30)))
        
        for m in orderly:
            if (m not in legal_stats):
                clean.append(0)
                wanted.append(0)
                bounties.append(0)
                continue

            wayTooOld = int(legal_stats[m]["year"]) < currentYear-1
            tooOld = (int(legal_stats[m]["year"]) == currentYear-1) and int(m) <= currentMonth
            if (wayTooOld or tooOld):
                clean.append(0)
                wanted.append(0)
                bounties.append(0)
                continue
            
            if (m in orderly[12-monthSpan:]):
                recent_stats["clean"] += legal_stats[m]["clean"]
                recent_stats["wanted"] += legal_stats[m]["wanted"]
                if legal_stats[m]["max"]:
                    recent_stats["maxBounty"] = max(recent_stats["maxBounty"], legal_stats[m]["max"].get("value", 0))
                if legal_stats[m]["last"] and legal_stats[m]["last"].get("value", 0) >= recent_stats["last"]["value"]:
                    recent_stats["last"] = legal_stats[m]["last"]

            clean.append(legal_stats[m]["clean"])
            wanted.append(legal_stats[m]["wanted"])
            last[m] = legal_stats[m]["last"]
            bounties.append(legal_stats[m]["max"]["value"])

        return (clean, wanted, bounties, recent_stats)

    @staticmethod
    def __orderlyMonthNo():
        currentMonthIDX0 = datetime.datetime.now().month-1
        return [ str((((currentMonthIDX0 - i) %12) + 12)%12)  for i in range(11,-1,-1)]
    
    @staticmethod
    def __emptyMonthlyBag():
        return {
            '0': None,
            '1': None,
            '2': None,
            '3': None,
            '4': None,
            '5': None,
            '6': None,
            '7': None,
            '8': None,
            '9': None,
            '10': None,
            '11': None
        }
Exemple #3
0
class EDRCmdrs(object):
    #TODO these should be player and/or squadron specific
    EDR_CMDRS_CACHE = utils2to3.abspathmaker(__file__, 'cache', 'cmdrs.v7.p')
    EDR_INARA_CACHE = utils2to3.abspathmaker(__file__, 'cache', 'inara.v7.p')
    EDR_SQDRDEX_CACHE = utils2to3.abspathmaker(__file__, 'cache',
                                               'sqdrdex.v2.p')

    def __init__(self, edrserver):
        self.server = edrserver
        self._player = EDPlayerOne()
        self.heartbeat_timestamp = None

        edr_config = EDRConfig()
        self._edr_heartbeat = edr_config.edr_heartbeat()

        try:
            with open(self.EDR_CMDRS_CACHE, 'rb') as handle:
                self.cmdrs_cache = pickle.load(handle)
        except:
            self.cmdrs_cache = LRUCache(edr_config.lru_max_size(),
                                        edr_config.cmdrs_max_age())

        try:
            with open(self.EDR_INARA_CACHE, 'rb') as handle:
                self.inara_cache = pickle.load(handle)
        except:
            self.inara_cache = LRUCache(edr_config.lru_max_size(),
                                        edr_config.inara_max_age())

        try:
            with open(self.EDR_SQDRDEX_CACHE, 'rb') as handle:
                self.sqdrdex_cache = pickle.load(handle)
        except:
            self.sqdrdex_cache = LRUCache(edr_config.lru_max_size(),
                                          edr_config.sqdrdex_max_age())

    @property
    def player(self):
        return self._player

    def player_name(self):
        return self._player.name

    def set_player_name(self, new_player_name):
        if (new_player_name != self._player.name):
            self._player.force_new_name(new_player_name)
            self.__update_squadron_info(force_update=True)

    def player_pledged_to(self, power, time_pledged=0):
        edr_config = EDRConfig()
        delta = time_pledged - self._player.time_pledged if self._player.time_pledged else time_pledged
        if power == self._player.power and delta <= edr_config.noteworthy_pledge_threshold(
        ):
            EDRLOG.log(
                u"Skipping pledged_to (not noteworthy): current vs. proposed {} vs. {}; {} vs {}"
                .format(self._player.power, power, self._player.time_pledged,
                        time_pledged), "DEBUG")
            return False
        self._player.pledged_to(power, time_pledged)
        since = self._player.pledged_since()
        return self.server.pledged_to(power, since)

    def __squadron_id(self):
        self.__update_squadron_info()
        info = self._player.squadron_info()
        return info["squadronId"] if info else None

    def __update_squadron_info(self, force_update=False):
        if self.server.is_anonymous():
            return
        mark_twain_flag = int(
            (EDTime.js_epoch_now() - self.heartbeat_timestamp) /
            1000) >= self._edr_heartbeat if self.heartbeat_timestamp else True
        if force_update or mark_twain_flag:
            info = self.server.heartbeat()
            if info:
                self.heartbeat_timestamp = info[
                    "heartbeat"] if "heartbeat" in info else EDTime.js_epoch_now(
                    )
                self._player.squadron_member(
                    info) if "squadronId" in info else self._player.lone_wolf(
                    )
            else:
                self.heartbeat_timestamp = EDTime.js_epoch_now()
                self._player.lone_wolf()

    def persist(self):
        with open(self.EDR_CMDRS_CACHE, 'wb') as handle:
            pickle.dump(self.cmdrs_cache,
                        handle,
                        protocol=pickle.HIGHEST_PROTOCOL)

        with open(self.EDR_INARA_CACHE, 'wb') as handle:
            pickle.dump(self.inara_cache,
                        handle,
                        protocol=pickle.HIGHEST_PROTOCOL)

        with open(self.EDR_SQDRDEX_CACHE, 'wb') as handle:
            pickle.dump(self.sqdrdex_cache,
                        handle,
                        protocol=pickle.HIGHEST_PROTOCOL)

    def evict(self, cmdr):
        try:
            del self.cmdrs_cache[cmdr.lower()]
        except KeyError:
            pass

        try:
            del self.inara_cache[cmdr.lower()]
        except KeyError:
            pass

        try:
            sqdr_id = self.__squadron_id()
            if sqdr_id:
                sq_cmdr_key = u"{}:{}".format(sqdr_id, cmdr.lower())
                del self.sqdrdex_cache[sq_cmdr_key]
        except KeyError:
            pass

    def __edr_cmdr(self, cmdr_name, autocreate):
        profile = self.cmdrs_cache.get(cmdr_name.lower())
        cached = self.cmdrs_cache.has_key(cmdr_name.lower())
        if cached or profile:
            EDRLOG.log(
                u"Cmdr {cmdr} is in the EDR cache with id={cid}".format(
                    cmdr=cmdr_name, cid=profile.cid if profile else 'N/A'),
                "DEBUG")
            return profile

        profile = self.server.cmdr(cmdr_name, autocreate)

        if not profile:
            self.cmdrs_cache.set(cmdr_name.lower(), None)
            EDRLOG.log(
                u"No match on EDR. Temporary entry to be nice on EDR's server.",
                "DEBUG")
            return None
        dex_profile = self.server.cmdrdex(profile.cid)
        if dex_profile:
            EDRLOG.log(
                u"EDR CmdrDex entry found for {cmdr}: {id}".format(
                    cmdr=cmdr_name, id=profile.cid), "DEBUG")
            profile.dex(dex_profile)
        self.cmdrs_cache.set(cmdr_name.lower(), profile)
        EDRLOG.log(
            u"Cached EDR profile {cmdr}: {id}".format(cmdr=cmdr_name,
                                                      id=profile.cid), "DEBUG")
        return profile

    def __edr_sqdrdex(self, cmdr_name, autocreate):
        sqdr_id = self.__squadron_id()
        if not sqdr_id:
            return None
        key = u"{}:{}".format(sqdr_id, cmdr_name.lower())
        profile = self.sqdrdex_cache.get(key)
        if profile:
            EDRLOG.log(
                u"Cmdr {cmdr} is in the EDR IFF cache for squadron {sqid} with key {key}"
                .format(cmdr=cmdr_name, sqid=sqdr_id, key=key), "DEBUG")
            return profile

        profile = self.__edr_cmdr(cmdr_name, autocreate)
        if not profile:
            return None

        sqdrdex_dict = self.server.sqdrdex(sqdr_id, profile.cid)
        if sqdrdex_dict:
            EDRLOG.log(
                u"EDR SqdrDex {sqid} entry found for {cmdr}@{cid}".format(
                    sqid=sqdr_id, cmdr=cmdr_name, cid=profile.cid), "DEBUG")
            profile.sqdrdex(sqdrdex_dict)
        self.sqdrdex_cache.set(u"{}:{}".format(sqdr_id, cmdr_name.lower()),
                               profile)
        EDRLOG.log(
            u"Cached EDR SqdrDex {sqid} entry for {cmdr}@{cid}".format(
                sqid=sqdr_id, cmdr=cmdr_name, cid=profile.cid), "DEBUG")
        return profile.sqdrdex_profile

    def __inara_cmdr(self, cmdr_name, check_inara_server):
        inara_profile = None
        stale = self.inara_cache.is_stale(cmdr_name.lower())
        cached = self.inara_cache.has_key(cmdr_name.lower())
        if cached and not stale:
            inara_profile = self.inara_cache.get(cmdr_name.lower())
            EDRLOG.log(
                u"Cmdr {} is in the Inara cache (name={})".format(
                    cmdr_name, inara_profile.name if inara_profile else 'N/A'),
                "DEBUG")
        elif check_inara_server:
            EDRLOG.log(
                u"Stale {} or not cached {} in Inara cache. Inara API call for {}."
                .format(stale, cached, cmdr_name), "INFO")
            inara_profile = self.server.inara_cmdr(cmdr_name)

            if inara_profile and inara_profile.name.lower() == cmdr_name.lower(
            ):
                self.inara_cache.set(cmdr_name.lower(), inara_profile)
                EDRLOG.log(
                    u"Cached Inara profile {}: {},{},{},{}".format(
                        cmdr_name, inara_profile.name, inara_profile.squadron,
                        inara_profile.role, inara_profile.powerplay), "DEBUG")
            elif self.inara_cache.has_key(cmdr_name.lower()):
                inara_profile = self.inara_cache.peek(cmdr_name.lower())
                self.inara_cache.refresh(cmdr_name.lower())
                EDRLOG.log(u"Refresh and re-use stale match in Inara cache.",
                           "INFO")
            else:
                inara_profile = None
                self.inara_cache.set(cmdr_name.lower(), None)
                EDRLOG.log(
                    u"No match on Inara. Temporary entry to be nice on Inara's server.",
                    "INFO")
        return inara_profile

    def cmdr(self, cmdr_name, autocreate=True, check_inara_server=False):
        profile = self.__edr_cmdr(cmdr_name, autocreate)
        inara_profile = self.__inara_cmdr(cmdr_name, check_inara_server)

        if profile is None:
            if inara_profile is None:
                EDRLOG.log(
                    u"Failed to retrieve/create cmdr {}".format(cmdr_name),
                    "ERROR")
                return None
            else:
                return inara_profile

        if inara_profile:
            EDRLOG.log(
                u"Combining info from EDR and Inara for cmdr {}".format(
                    cmdr_name), "INFO")
            profile.complement(inara_profile)

        squadron_profile = self.__edr_sqdrdex(cmdr_name, autocreate)
        if squadron_profile:
            EDRLOG.log(
                u"Combining info from Squadron for cmdr {}".format(cmdr_name),
                "INFO")
            profile.sqdrdex(squadron_profile.sqdrdex_dict())

        return profile

    def is_friend(self, cmdr_name):
        profile = self.__edr_cmdr(cmdr_name, False)
        if profile is None:
            return False
        return profile.is_friend()

    def is_ally(self, cmdr_name):
        sqdr_id = self.__squadron_id()
        if not sqdr_id:
            return False

        profile = self.__edr_sqdrdex(cmdr_name, False)
        if profile:
            return profile.is_ally()
        return False

    def tag_cmdr(self, cmdr_name, tag):
        if tag in ["enemy", "ally"]:
            return self.__squadron_tag_cmdr(cmdr_name, tag)
        else:
            return self.__tag_cmdr(cmdr_name, tag)

    def contracts(self):
        return self.server.contracts()

    def contract_for(self, cmdr_name):
        if not cmdr_name:
            return False

        profile = self.cmdr(cmdr_name)
        if not profile:
            return False

        return self.server.contract_for(profile.cid)

    def place_contract(self, cmdr_name, reward):
        if not cmdr_name:
            return False

        if reward <= 0:
            return self.remove_contract(cmdr_name)

        profile = self.cmdr(cmdr_name)
        if not profile:
            return False

        return self.server.place_contract(profile.cid, {
            "cname": cmdr_name.lower(),
            "reward": reward
        })

    def remove_contract(self, cmdr_name):
        if not cmdr_name:
            return False

        profile = self.cmdr(cmdr_name)
        if not profile:
            return False

        return self.server.remove_contract(profile.cid)

    def __tag_cmdr(self, cmdr_name, tag):
        EDRLOG.log(u"Tagging {} with {}".format(cmdr_name, tag), "DEBUG")
        profile = self.__edr_cmdr(cmdr_name, False)
        if profile is None:
            EDRLOG.log(u"Couldn't find a profile for {}.".format(cmdr_name),
                       "DEBUG")
            return False

        tagged = profile.tag(tag)
        if not tagged:
            EDRLOG.log(
                u"Couldn't tag {} with {} (e.g. already tagged)".format(
                    cmdr_name, tag), "DEBUG")
            self.evict(cmdr_name)
            return False

        dex_dict = profile.dex_dict()
        EDRLOG.log(u"New dex state: {}".format(dex_dict), "DEBUG")
        success = self.server.update_cmdrdex(profile.cid, dex_dict)
        self.evict(cmdr_name)
        return success

    def __squadron_tag_cmdr(self, cmdr_name, tag):
        sqdr_id = self.__squadron_id()
        if not sqdr_id:
            EDRLOG.log(u"Can't tag: not a member of a squadron", "DEBUG")
            return False

        EDRLOG.log(u"Tagging {} with {} for squadron".format(cmdr_name, tag),
                   "DEBUG")
        profile = self.__edr_sqdrdex(cmdr_name, False)
        if profile is None:
            EDRLOG.log(
                u"Couldn't find a squadron profile for {}.".format(cmdr_name),
                "DEBUG")
            return False

        tagged = profile.tag(tag)
        if not tagged:
            EDRLOG.log(
                u"Couldn't tag {} with {} (e.g. already tagged)".format(
                    cmdr_name, tag), "DEBUG")
            self.evict(cmdr_name)
            return False

        sqdrdex_dict = profile.sqdrdex_dict()
        EDRLOG.log(u"New dex state: {}".format(sqdrdex_dict), "DEBUG")
        augmented_sqdrdex_dict = sqdrdex_dict
        augmented_sqdrdex_dict["level"] = self._player.squadron_info(
        )["squadronLevel"]
        augmented_sqdrdex_dict["by"] = self._player.name
        success = self.server.update_sqdrdex(sqdr_id, profile.cid,
                                             augmented_sqdrdex_dict)
        self.evict(cmdr_name)
        return success

    def memo_cmdr(self, cmdr_name, memo):
        if memo is None:
            return self.clear_memo_cmdr(cmdr_name)
        EDRLOG.log(u"Writing a note about {}: {}".format(memo, cmdr_name),
                   "DEBUG")
        profile = self.__edr_cmdr(cmdr_name, False)
        if profile is None:
            EDRLOG.log(u"Couldn't find a profile for {}.".format(cmdr_name),
                       "DEBUG")
            return False

        noted = profile.memo(memo)
        if not noted:
            EDRLOG.log(u"Couldn't write a note about {}".format(cmdr_name),
                       "DEBUG")
            self.evict(cmdr_name)
            return False

        dex_dict = profile.dex_dict()
        success = self.server.update_cmdrdex(profile.cid, dex_dict)
        self.evict(cmdr_name)
        return success

    def clear_memo_cmdr(self, cmdr_name):
        EDRLOG.log(u"Removing a note from {}".format(cmdr_name), "DEBUG")
        profile = self.__edr_cmdr(cmdr_name, False)
        if profile is None:
            EDRLOG.log(u"Couldn't find a profile for {}.".format(cmdr_name),
                       "DEBUG")
            return False

        noted = profile.remove_memo()
        if not noted:
            EDRLOG.log(u"Couldn't remove a note from {}".format(cmdr_name),
                       "DEBUG")
            self.evict(cmdr_name)
            return False

        dex_dict = profile.dex_dict()
        success = self.server.update_cmdrdex(profile.cid, dex_dict)
        self.evict(cmdr_name)
        return success

    def untag_cmdr(self, cmdr_name, tag):
        if tag in ["enemy", "ally"]:
            return self.__squadron_untag_cmdr(cmdr_name, tag)
        else:
            return self.__untag_cmdr(cmdr_name, tag)

    def __untag_cmdr(self, cmdr_name, tag):
        EDRLOG.log(u"Removing {} tag from {}".format(tag, cmdr_name), "DEBUG")
        profile = self.__edr_cmdr(cmdr_name, False)
        if profile is None:
            EDRLOG.log(u"Couldn't find a profile for {}.".format(cmdr_name),
                       "DEBUG")
            return False

        untagged = profile.untag(tag)
        if not untagged:
            EDRLOG.log(
                u"Couldn't untag {} (e.g. tag not present)".format(cmdr_name),
                "DEBUG")
            self.evict(cmdr_name)
            return False

        dex_dict = profile.dex_dict()
        EDRLOG.log(u"New dex state: {}".format(dex_dict), "DEBUG")
        success = self.server.update_cmdrdex(profile.cid, dex_dict)
        self.evict(cmdr_name)
        return success

    def __squadron_untag_cmdr(self, cmdr_name, tag):
        sqdr_id = self.__squadron_id()
        if not sqdr_id:
            EDRLOG.log(u"Can't untag: not a member of a squadron", "DEBUG")
            return False

        EDRLOG.log(u"Removing {} tag from {}".format(tag, cmdr_name), "DEBUG")
        profile = self.__edr_cmdr(cmdr_name, False)
        if profile is None:
            EDRLOG.log(u"Couldn't find a profile for {}.".format(cmdr_name),
                       "DEBUG")
            return False

        untagged = profile.untag(tag)
        if not untagged:
            EDRLOG.log(
                u"Couldn't untag {} (e.g. tag not present)".format(cmdr_name),
                "DEBUG")
            self.evict(cmdr_name)
            return False

        sqdrdex_dict = profile.sqdrdex_dict()
        EDRLOG.log(u"New dex state: {}".format(sqdrdex_dict), "DEBUG")
        augmented_sqdrdex_dict = sqdrdex_dict
        augmented_sqdrdex_dict["level"] = self._player.squadron_info(
        )["squadronLevel"]
        augmented_sqdrdex_dict["by"] = self._player.name
        success = self.server.update_sqdrdex(sqdr_id, profile.cid,
                                             augmented_sqdrdex_dict)
        self.evict(cmdr_name)
        return success