A corporation manager and dashboard for EVE Online
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 

116 行
3.8 KiB

  1. # -*- coding: utf-8 -*-
  2. import time
  3. from flask import g
  4. import requests
  5. from ..exceptions import ZKillboardError
  6. __all__ = ["ZKillboard"]
  7. class ZKillboard:
  8. """EVE API module for zKillboard."""
  9. _MAX_RATE = 0.5
  10. def __init__(self, session, logger):
  11. self._session = session
  12. self._logger = logger
  13. self._debug = logger.debug
  14. self._base_url = "https://zkillboard.com/api"
  15. self._last_query = 0
  16. def _extend_killmail(self, kill):
  17. """Extend a killmail object to match the old ZKill format.
  18. Requires ESI API calls to fill in entity names. If we can't do them,
  19. we'll just set the names to be empty.
  20. """
  21. esi = g.eve.esi
  22. victim = kill["victim"]
  23. if "character_id" in victim:
  24. char_info = esi().v4.characters(victim["character_id"]).get()
  25. victim["character_name"] = char_info["name"]
  26. else:
  27. victim["character_id"] = 0
  28. victim["character_name"] = ""
  29. if "corporation_id" in victim:
  30. corp_info = esi().v3.corporations(victim["corporation_id"]).get()
  31. victim["corporation_name"] = corp_info["corporation_name"]
  32. else:
  33. victim["corporation_id"] = 0
  34. victim["corporation_name"] = ""
  35. if "alliance_id" in victim:
  36. alliance_info = esi().v2.alliances(victim["alliance_id"]).get()
  37. victim["alliance_name"] = alliance_info["alliance_name"]
  38. else:
  39. victim["alliance_id"] = 0
  40. victim["alliance_name"] = ""
  41. if "faction_id" in victim:
  42. factions = esi().v1.universe.factions.get()
  43. matches = [fac["faction_name"] for fac in factions
  44. if fac["faction_id"] == victim["faction_id"]]
  45. victim["faction_name"] = matches[0] if matches else ""
  46. else:
  47. victim["faction_id"] = 0
  48. victim["faction_name"] = ""
  49. def query(self, *args):
  50. """Make an API query using the given arguments."""
  51. query = "/" + "".join(str(arg) + "/" for arg in args)
  52. url = self._base_url + query
  53. delta = self._MAX_RATE - (time.time() - self._last_query)
  54. if delta > 0:
  55. self._debug("[GET] [wait %.2fs] %s", delta, query)
  56. time.sleep(delta)
  57. else:
  58. self._debug("[GET] %s", query)
  59. try:
  60. try:
  61. resp = self._session.get(url, timeout=10)
  62. except requests.ConnectionError:
  63. self._logger.warn("zKillboard API query failed, retrying once")
  64. time.sleep(self._MAX_RATE)
  65. resp = self._session.get(url, timeout=10)
  66. resp.raise_for_status()
  67. result = resp.json() if resp.content else None
  68. except (requests.RequestException, ValueError):
  69. self._logger.exception("zKillboard API query failed")
  70. raise ZKillboardError()
  71. self._last_query = time.time()
  72. return result
  73. def iter_killmails(self, *args, extended=False):
  74. """Return an iterator over killmails using the given API arguments.
  75. Automagically follows pagination as far as possible. (Be careful.)
  76. If extended is True, we will provide extra information for each kill
  77. (names of entities instead of just IDs), which requires ESI API calls.
  78. This matches the original API format of ZKill before it was, er,
  79. "simplified".
  80. """
  81. page = 1
  82. while True:
  83. if page > 1:
  84. result = self.query(*args, "page", page)
  85. else:
  86. result = self.query(*args)
  87. if result:
  88. if extended:
  89. for kill in result:
  90. yield self._extend_killmail(kill)
  91. else:
  92. yield from result
  93. page += 1
  94. else:
  95. break