def do_refresh(): """DRY helper to refresh all stale ESI specs. Returns: list of updated ESI spec versions """ status, versions = do_request("{}/versions/".format(ESI)) if status == 200: for version in versions: if version not in ESI_SPECS: ESI_SPECS[version] = {"timestamp": 0, "spec": {}} updates = {} for version, details in ESI_SPECS.items(): if not details["spec"] or details["timestamp"] < time.time() + 300: status, spec = do_request("{}/{}/swagger.json".format( ESI, version, )) if status == 200: updates[version] = {"timestamp": time.time(), "spec": spec} ESI_SPECS.update(updates) return list(updates)
def status(*_): """Generic ESI status.""" now = time.time() if now - STATUS["timestamp"] > 60: code, esi_status = do_request("{}/status.json".format(ESI)) if code == 200: STATUS["status"] = esi_status else: return ":fire: (failed to fetch status.json)" red_routes = [ route for route in STATUS["status"] if route["status"] == "red" ] yellow_routes = [ route for route in STATUS["status"] if route["status"] == "yellow" ] attachments = [] if red_routes: attachments.append({ "color": "danger", "fallback": "{} red".format(len(red_routes)), "text": "{emoji} {count} red {emoji} {details}".format( emoji=":fire:" * int( max( round(len(red_routes) / len(STATUS["status"]) * 10), 1, )), count=len(red_routes), details=_status_str(red_routes), ) }) if yellow_routes: attachments.append({ "color": "warning", "fallback": "{} yellow".format(len(yellow_routes)), "text": "{emoji} {count} yellow {emoji} {details}".format( emoji=":fire_engine:" * int( max( round(len(yellow_routes) / len(STATUS["status"]) * 10), 1, )), count=len(yellow_routes), details=_status_str(yellow_routes), ) }) if not red_routes and not yellow_routes: attachments.append({ "color": "good", "text": "ESI is fully armed and operational!" }) return REPLY(content=None, attachments=attachments)
def do_refresh(base_url): """DRY helper to refresh all stale ESI specs. Returns: list of updated ESI spec versions """ status, versions = do_request("{}/versions/".format(base_url)) if status == 200: for version in versions: if version not in ESI_SPECS[base_url]: ESI_SPECS[base_url][version] = {"timestamp": 0, "spec": {}} spec_urls = {} # url: version for version, details in ESI_SPECS[base_url].items(): if not details["spec"] or details["timestamp"] < time.time() + 300: url = "{}/{}/swagger.json".format(base_url, version) spec_urls[url] = version updates = {} for url, result in multi_request(spec_urls.keys()).items(): status, spec = result if status == 200: updates[spec_urls[url]] = {"timestamp": time.time(), "spec": spec} ESI_SPECS[base_url].update(updates) return list(updates)
def item(msg): """Look up a type by ID, including dogma information.""" start = time.time() if not msg.args: return "usage: !esi {} <id>".format(msg.command) item_id = msg.args[0] try: int(item_id) except ValueError: return "get outta here hackerman" type_url = "{}/v3/universe/types/{}/".format(esi_base_url(msg), item_id) ret, res = do_request(type_url) reqs = _expand_dogma(res, *_get_dogma_urls(msg, res)) return SNIPPET( content=json.dumps(res, sort_keys=True, indent=4), filename="{}.json".format(item_id), filetype="json", comment="Item {}: {} ({:,d} request{} in {:,.0f}ms)".format( item_id, res["name"] if ret == 200 else "Error", reqs + 1, "s" * int(reqs > 0), (time.time() - start) * 1000, ), title=type_url, )
def request(match, *_): """Make an ESI GET request, if the path is known.""" version, *req_sections = match.groupdict()["esi_path"].split("/") if version not in ESI_SPECS: req_sections.insert(0, version) version = "latest" params = "" if "?" in req_sections[-1]: if req_sections[-1].startswith("?"): params = req_sections.pop() params = params[1:] else: # qsparams passed w/out trailing slash final_path, params = req_sections.pop().split("?") req_sections.append(final_path) params = html.unescape(params) path = "/{}/".format("/".join(x for x in req_sections if x)) if _valid_path(path, version): url = "{}/{}{}{}{}".format( ESI, version, path, "?" * int(params != ""), params, ) status, res = do_request(url) return "{}\n{}\n```{}```".format( url, status, json.dumps(res, sort_keys=True, indent=4) ) return "failed to find GET {} in the {} ESI spec".format(path, version)
def server_status(datasource): """Generate """ if datasource not in ("tranquility", "singularity"): return "Cannot request server status for `{}`".format(datasource) status_code, response = do_request("{}/v1/status/?datasource={}".format( ESI, datasource)) server_name = datasource.capitalize() if status_code == 200: vip = response.get("vip") attachment = { "color": "warning" if vip else "good", "title": "{} status".format(server_name), "fields": [ { "title": "Players online", "value": "{:,}".format(response["players"]), "short": True, }, { "title": "Server started", "value": response["start_time"], "short": True, }, ], "fallback": "{} status: {:,} online, started at {}{}".format( server_name, response["players"], response["start_time"], ", in VIP" * int(vip is True), ) } if vip: attachment["fields"].append({"title": "In VIP mode"}) elif status == 503: attachment = { "color": "danger", "title": "{} status".format(server_name), "text": "Offline", "fallback": "{} status: Offline".format(server_name), } else: indeterminate = ( "Cannot determine server status. " "It might be offline, or experiencing connectivity issues.") attachment = { "color": "danger", "title": "{} status".format(server_name), "text": indeterminate, "fallback": "{} status: {}".format(server_name, indeterminate), } return REPLY(content=None, attachments=[attachment])
def status(msg): """Return the current ESI health/status.""" base_url = esi_base_url(msg) now = time.time() if now - STATUS[base_url]["timestamp"] > 60: code, esi_status = do_request("{}/status.json".format(base_url)) if code == 200: STATUS[base_url]["status"] = esi_status else: return ":fire: (failed to fetch status.json)" attachments = [] categories = [ ("red", ":fire:", "danger"), ("yellow", ":fire_engine:", "warning"), ] status_json = STATUS[base_url]["status"] for status_color, emoji, color_value in categories: routes = [ route for route in status_json if route["status"] == status_color ] if routes: attachments.append({ "color": color_value, "fallback": "{}: {} out of {}, {:.2%}".format( status_color.capitalize(), len(routes), len(status_json), len(routes) / len(status_json), ), "text": "{emoji} {count} {emoji} {details}".format( emoji=emoji * max( min(int(round(len(routes) / len(status_json) * 10)), 5), 1), count="{} {} (out of {}, {:.2%})".format( len(routes), status_color, len(status_json), len(routes) / len(status_json), ), details=_status_str(routes), ) }) if not attachments: attachments.append({ "color": "good", "text": ":ok_hand:", }) return REPLY(content=None, attachments=attachments)
def issue(match, msg): """Look up ESI-issue details on GitHub.""" code, details = do_request( "https://api.github.com/repos/esi/esi-issues/issues/{}".format( match.groupdict()["gh_issue"])) if code >= 400: return "failed to lookup details for issue {}".format(msg.command) return "{} ({})".format(details["html_url"], details["state"])
def request(match, *_): """Make an ESI GET request, if the path is known.""" version, *req_sections = match.groupdict()["esi_path"].split("/") if version not in ESI_SPECS: req_sections.insert(0, version) version = "latest" params = "" if "?" in req_sections[-1]: if req_sections[-1].startswith("?"): params = req_sections.pop() params = params[1:] else: # qsparams passed w/out trailing slash final_path, params = req_sections.pop().split("?") req_sections.append(final_path) params = html.unescape(params) path = "/{}/".format("/".join(x for x in req_sections if x)) if _valid_path(path, version): url = "{}/{}{}{}{}".format( ESI, version, path, "?" * int(params != ""), params, ) start = time.time() status, res = do_request(url) try: status = http.HTTPStatus(status) # pylint: disable=E1120 except ValueError: pass else: status = "{} {}".format(status.value, status.name) return SNIPPET( content=json.dumps(res, sort_keys=True, indent=4), filename="response.json", filetype="json", comment="{} ({:,.0f}ms)".format( status, (time.time() - start) * 1000, ), title=url, ) return "failed to find GET {} in the {} ESI spec".format(path, version)
def status(*_): """Generic ESI status.""" now = time.time() if now - STATUS["timestamp"] > 60: code, esi_status = do_request("{}/status.json".format(ESI)) if code == 200: STATUS["status"] = esi_status else: return ":fire: (failed to fetch status.json)" red_routes = [ route for route in STATUS["status"] if route["status"] == "red" ] yellow_routes = [ route for route in STATUS["status"] if route["status"] == "yellow" ] slow_route_count = len(red_routes) + len(yellow_routes) slow_route_ratio = slow_route_count / len(STATUS["status"]) if slow_route_ratio > 0.3: return ":fire:" * round(slow_route_ratio * 10) status_messages = [] if red_routes: status_messages.append(":fire: {} red :fire: {}".format( len(red_routes), _status_str(red_routes), )) if yellow_routes: status_messages.append( ":fire_engine: {} yellow :fire_engine: {}".format( len(yellow_routes), _status_str(yellow_routes), )) return "\n".join(status_messages) if status_messages else ":ok_hand:"
def sisi_status(*_): """Display current status of Singularity, the main test server.""" sisi = do_request("{}/dev/status/?datasource=singularity".format(ESI))[1] return "Singularity status: ```{}```".format( json.dumps(sisi, sort_keys=True, indent=4))
def tq_status(*_): """Display current status of Tranquility, the main game server.""" tq = do_request("{}/dev/status/".format(ESI))[1] return "Tranquility status: ```{}```".format( json.dumps(tq, sort_keys=True, indent=4))
def server_status(datsource): """Generate a reply describing the status of an EVE server/datasource.""" if datsource == "tranquility": base_url = ESI elif datsource == "serenity": base_url = ESI_CHINA else: return "Cannot request server status for `{}`".format(datsource) status_code, response = do_request("{}/v1/status/?datasource={}".format( base_url, datsource, )) server_name = datsource.capitalize() if status_code == 200: start_time = datetime.strptime( response["start_time"], "%Y-%m-%dT%H:%M:%SZ", ) vip = response.get("vip") # pylint: disable=no-member attachment = { "color": "warning" if vip else "good", "title": "{} status".format(server_name), "fields": [ { "title": "Players online", "value": "{:,}".format(response["players"]), }, { "title": "Started at", "value": response["start_time"], "short": True, }, { "title": "Running for", "value": _running_for(start_time), "short": True, }, ], "fallback": "{} status: {:,} online, started at {}{}".format( server_name, response["players"], response["start_time"], ", in VIP" * int(vip is True), ), } if vip: attachment["fields"].insert(0, {"title": "In VIP mode"}) elif status_code == 503: attachment = { "color": "danger", "title": "{} status".format(server_name), "text": "Offline", "fallback": "{} status: Offline".format(server_name), } else: indeterminate = ( "Cannot determine server status. " "It might be offline, or experiencing connectivity issues.") attachment = { "color": "danger", "title": "{} status".format(server_name), "text": indeterminate, "fallback": "{} status: {}".format(server_name, indeterminate), } return REPLY(content=None, attachments=[attachment])
def request(match, msg): """Make an ESI GET request, if the path is known. Options: --headers nest the response and add the headers """ match_group = match.groupdict() if "evepc.163.com" in (match_group["esi"] or ""): base_url = ESI_CHINA else: base_url = esi_base_url(msg) version, *req_sections = match_group["esi_path"].split("/") if version not in ESI_SPECS[base_url]: req_sections.insert(0, version) version = "latest" params = "" if "?" in req_sections[-1]: if req_sections[-1].startswith("?"): params = req_sections.pop() params = params[1:] else: # qsparams passed w/out trailing slash final_path, params = req_sections.pop().split("?") req_sections.append(final_path) params = html.unescape(params) path = "/{}/".format("/".join(x for x in req_sections if x)) if _valid_path(base_url, path, version): url = "{}/{}{}{}{}".format( base_url, version, path, "?" * int(params != ""), params, ) start = time.time() res = do_request(url, return_response=True) try: content = res.json() except ValueError: content = res.text try: status = http.HTTPStatus(res.status_code) # pylint: disable=E1120 except ValueError: status = str(res.status_code) else: status = "{} {}".format(status.value, status.name) # pylint: disable=E1101 if "--headers" in msg.args: res = {"response": content, "headers": dict(res.headers)} else: res = content return SNIPPET( content=json.dumps(res, sort_keys=True, indent=4), filename="response.json", filetype="json", comment="{} ({:,.0f}ms)".format( status, (time.time() - start) * 1000, ), title=url, ) return "failed to find GET {} in the {} ESI{} spec".format( path, version, " China" * int(base_url == ESI_CHINA), )