|
- # -*- coding: utf-8 -*-
-
- import sys
- import textwrap
-
- from flask import g
-
- from .._provided import config, logger
-
- __all__ = ["update_operation"]
-
- def _save_operation(cname, opname, primary, secondary, key=None):
- """Save the given campaign/operation overview info in the database."""
- secstr = "" if secondary is None else (" secondary=%d" % secondary)
- logger.debug("Setting overview primary=%d%s campaign=%s operation=%s",
- primary, secstr, cname, opname)
- g.campaign_db.set_overview(cname, opname, primary, secondary)
- g.campaign_db.touch_operation(cname, opname, key=key)
-
- def _build_filter(qualifiers):
- """Given a qualifiers string from the config, return a filter function.
-
- This function is extremely sensitive since it executes arbitrary Python
- code. It should never be run with a user-provided argument! We trust the
- contents of a config file because it originates from a known place on the
- filesystem.
- """
- namespace = {"g": g}
- body = "def _func(kill):\n" + textwrap.indent(qualifiers, " " * 4)
- exec(body, namespace)
- return namespace["_func"]
-
- def _store_kill(cname, opnames, kill):
- """Store the given kill and its associations into the database."""
- kid = kill["killID"]
- if g.campaign_db.has_kill(kid):
- current = g.campaign_db.get_kill_associations(cname, kid)
- opnames -= set(current)
- if opnames:
- logger.debug("Adding operations=%s to kill id=%d campaign=%s",
- ",".join(opnames), kid, cname)
- else:
- logger.debug("Adding kill id=%d campaign=%s operations=%s", kid, cname,
- ",".join(opnames))
- g.campaign_db.add_kill(kill)
-
- g.campaign_db.associate_kill(cname, kid, opnames)
-
- def _update_killboard_operations(cname, opnames, min_kill_id):
- """Update all killboard-type operations in the given campaign subset."""
- operations = config["campaigns"][cname]["operations"]
- filters = []
- for opname in opnames:
- qualif = operations[opname]["qualifiers"]
- filters.append((_build_filter(qualif), opname))
-
- args = ["kills", "corporationID", g.config.get("corp.id"), "no-items",
- "no-attackers", "orderDirection", "asc"]
- if min_kill_id > 0:
- args += ["afterKillID", min_kill_id]
-
- max_kill_id = min_kill_id
- for kill in g.eve.zkill.iter_killmails(*args):
- kid = kill["killID"]
- ktime = kill["killTime"]
- logger.debug("Evaluating kill date=%s id=%d for campaign=%s "
- "operations=%s", ktime, kid, cname, ",".join(opnames))
- max_kill_id = max(max_kill_id, kid)
- ops = set()
- for filt, opname in filters:
- if filt(kill):
- ops.add(opname)
- if ops:
- _store_kill(cname, ops, kill)
-
- for opname in opnames:
- primary, secondary = g.campaign_db.count_kills(cname, opname)
- show_isk = operations[opname].get("isk", True)
- if not show_isk:
- secondary = None
- _save_operation(cname, opname, primary, secondary, key=max_kill_id)
-
- def _update_collection_operations(cname, opnames):
- """Update all collection-type operations in the given campaign subset."""
- campaign = config["campaigns"][cname]
- for opname in opnames:
- operation = campaign["operations"][opname]
- show_isk = operation.get("isk", True)
-
- # store per-user counts; update for all users in corp who have fresh
- # API keys and leave other data stale
- ...
- primary = __import__("random").randint(10, 99)
- secondary = __import__("random").randint(10000000, 5000000000) / 100 \
- if show_isk else None
-
- _save_operation(cname, opname, primary, secondary)
-
- def update_operation(cname, opname, new=False):
- """Update a campaign/operation. Assumes a thread-exclusive lock is held."""
- campaign = config["campaigns"][cname]
- operations = campaign["operations"]
- optype = operations[opname]["type"]
- opnames = [opn for opn in campaign["enabled"]
- if operations[opn]["type"] == optype]
-
- if optype == "killboard":
- opsubset = []
- min_key = 0 if new else sys.maxsize
- for opname in opnames:
- last_updated, key = g.campaign_db.check_operation(cname, opname)
- if new and last_updated is None:
- opsubset.append(opname)
- elif not new and last_updated is not None:
- min_key = min(min_key, key)
- opsubset.append(opname)
- _update_killboard_operations(cname, opsubset, min_key)
- elif optype == "collection":
- _update_collection_operations(cname, opnames)
- else:
- raise RuntimeError("Unknown operation type: %s" % optype)
|