@@ -2,6 +2,7 @@ | |||
import time | |||
from flask import g | |||
import requests | |||
from ..exceptions import ZKillboardError | |||
@@ -20,6 +21,45 @@ class ZKillboard: | |||
self._base_url = "https://zkillboard.com/api" | |||
self._last_query = 0 | |||
def _extend_killmail(self, kill): | |||
"""Extend a killmail object to match the old ZKill format. | |||
Requires ESI API calls to fill in entity names. If we can't do them, | |||
we'll just set the names to be empty. | |||
""" | |||
esi = g.eve.esi() | |||
victim = kill["victim"] | |||
if "character_id" in victim: | |||
char_info = esi.v4.characters(victim["character_id"]).get() | |||
victim["character_name"] = char_info["name"] | |||
else: | |||
victim["character_id"] = 0 | |||
victim["character_name"] = "" | |||
if "corporation_id" in victim: | |||
corp_info = esi.v3.corporations(victim["corporation_id"]).get() | |||
victim["corporation_name"] = corp_info["corporation_name"] | |||
else: | |||
victim["corporation_id"] = 0 | |||
victim["corporation_name"] = "" | |||
if "alliance_id" in victim: | |||
alliance_info = esi.v2.alliances(victim["alliance_id"]).get() | |||
victim["alliance_name"] = alliance_info["alliance_name"] | |||
else: | |||
victim["alliance_id"] = 0 | |||
victim["alliance_name"] = "" | |||
if "faction_id" in victim: | |||
factions = esi.v1.universe.factions.get() | |||
matches = [fac["faction_name"] for fac in factions | |||
if fac["faction_id"] == victim["faction_id"]] | |||
victim["faction_name"] = matches[0] if matches else "" | |||
else: | |||
victim["faction_id"] = 0 | |||
victim["faction_name"] = "" | |||
def query(self, *args): | |||
"""Make an API query using the given arguments.""" | |||
query = "/" + "".join(str(arg) + "/" for arg in args) | |||
@@ -47,10 +87,15 @@ class ZKillboard: | |||
self._last_query = time.time() | |||
return result | |||
def iter_killmails(self, *args): | |||
def iter_killmails(self, *args, extended=False): | |||
"""Return an iterator over killmails using the given API arguments. | |||
Automagically follows pagination as far as possible. (Be careful.) | |||
If extended is True, we will provide extra information for each kill | |||
(names of entities instead of just IDs), which requires ESI API calls. | |||
This matches the original API format of ZKill before it was, er, | |||
"simplified". | |||
""" | |||
page = 1 | |||
while True: | |||
@@ -60,7 +105,11 @@ class ZKillboard: | |||
result = self.query(*args) | |||
if result: | |||
yield from result | |||
if extended: | |||
for kill in result: | |||
yield self._extend_killmail(kill) | |||
else: | |||
yield from result | |||
page += 1 | |||
else: | |||
break |
@@ -94,10 +94,10 @@ class CampaignDB: | |||
def add_kill(self, kill): | |||
"""Insert a killmail into the database.""" | |||
try: | |||
datetime.strptime(kill["killTime"], "%Y-%m-%d %H:%M:%S") | |||
datetime.strptime(kill["killmail_time"], "%Y-%m-%d %H:%M:%S") | |||
except ValueError: | |||
raise RuntimeError("Invalid kill_date=%s for kill_id=%d" % ( | |||
kill["killTime"], kill["killID"])) | |||
kill["killmail_time"], kill["killmail_id"])) | |||
query = """INSERT OR REPLACE INTO kill ( | |||
kill_id, kill_date, kill_system, kill_victim_shipid, | |||
@@ -108,12 +108,13 @@ class CampaignDB: | |||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""" | |||
victim = kill["victim"] | |||
args = ( | |||
int(kill["killID"]), kill["killTime"], int(kill["solarSystemID"]), | |||
int(victim["shipTypeID"]), int(victim["characterID"]), | |||
victim["characterName"], int(victim["corporationID"]), | |||
victim["corporationName"], int(victim["allianceID"]), | |||
victim["allianceName"], int(victim["factionID"]), | |||
victim["factionName"], float(kill["zkb"]["totalValue"])) | |||
int(kill["killmail_id"]), kill["killmail_time"], | |||
int(kill["solar_system_id"]), int(victim["ship_type_id"]), | |||
int(victim["character_id"]), victim["character_name"], | |||
int(victim["corporation_id"]), victim["corporation_name"], | |||
int(victim["alliance_id"]), victim["alliance_name"], | |||
int(victim["faction_id"]), victim["faction_name"], | |||
float(kill["zkb"]["totalValue"])) | |||
with self._conn as conn: | |||
conn.execute(query, args) | |||
@@ -33,7 +33,7 @@ def _build_filter(qualifiers, arg): | |||
def _store_kill(cname, opnames, kill): | |||
"""Store the given kill and its associations into the database.""" | |||
kid = kill["killID"] | |||
kid = kill["killmail_id"] | |||
if g.campaign_db.has_kill(kid): | |||
current = g.campaign_db.get_kill_associations(cname, kid) | |||
opnames -= set(current) | |||
@@ -59,12 +59,16 @@ def _update_killboard_operations(cname, opnames, min_kill_id): | |||
"no-attackers", "orderDirection", "desc"] | |||
max_kill_id = min_kill_id | |||
for kill in g.eve.zkill.iter_killmails(*args): | |||
kid = kill["killID"] | |||
for kill in g.eve.zkill.iter_killmails(*args, extended=True): | |||
kid = kill["killmail_id"] | |||
if min_kill_id > 0 and kid == min_kill_id: | |||
# TODO: This fails if ZKill receives kills out of order. | |||
# Should look ahead for kills within, say, 12 hours of the | |||
# min_kill_id, and extend code below to ignore kills aleady | |||
# included instead of re-adding. | |||
break | |||
ktime = kill["killTime"] | |||
ktime = kill["killmail_time"] | |||
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) | |||