def character_knife(): """Start a new knife run for a character.""" if "access_token" in request.args and "state" in request.args: # verify token/start knife process for character # do this all out of band, we might be error limited right now if CACHE.get("authstate.{}".format(request.args["state"])): CACHE.delete("authstate.{}".format(request.args["state"])) token = uuid.uuid4() CACHE.set("new.{}".format(token), request.args["access_token"]) return redirect("/view/{}/".format(token)) # start sso flow state = uuid.uuid4() CACHE.set("authstate.{}".format(state), "1", timeout=300) return redirect( ("https://login.eveonline.com/oauth/authorize?response_type=token" "&redirect_uri={callback}&client_id={client}" "&scope={scopes}&state={state}").format( callback=CALLBACK_URL, client=CLIENT_ID, scopes=SCOPES, state=state, ))
def rate_limit(): """Apply a rate limit.""" key = "".join((Keys.rate_limit.value, get_ip())) reqs = CACHE.get(key) or 0 if reqs >= 20: return True CACHE.set(key, reqs + 1, timeout=60) return False
def process_new(): """Process all new tokens, verify or we're done early.""" for new_key in utils.list_keys(Keys.new.value): uuid = new_key.split(".")[-1] LOG.warning("processing new uuid: %r", uuid) token = CACHE.get(new_key) CACHE.delete(new_key) if not token: LOG.warning("no token stored for uuid: %r", uuid) continue pending_key = "{}{}".format(Keys.pending.value, uuid) CACHE.set( pending_key, "1", timeout=70, ) headers = {"Authorization": "Bearer {}".format(token)} _, res = utils.request_or_wait( "{}/verify/".format(ESI), headers=headers, ) failed = False if isinstance(res, str) or "CharacterID" not in res: utils.write_data(uuid, {"auth failure": res}) failed = True else: _, roles = utils.request_or_wait( "{}/latest/characters/{}/roles/".format( ESI, res["CharacterID"], ), headers=headers, ) if isinstance(roles, str): utils.write_data(uuid, {"roles failure": roles}) failed = True CACHE.delete(pending_key) if not failed: CACHE.set( "{}{}".format(Keys.processing.value, uuid), res["CharacterID"], timeout=7200, ) WORKERS.append( gevent.spawn(knife, uuid, token, res, roles) )
def metrics_index(): """Display some metrics.""" return render_template( "metrics.html", new=len(utils.list_keys(Keys.new.value)), pending=len(utils.list_keys(Keys.pending.value)), processing=len(utils.list_keys(Keys.processing.value)), completed=len(utils.list_keys(Keys.complete.value)), alltime=CACHE.get(Keys.alltime.value) or 0, worker=not APP.knife_worker.dead, error_limited=APP.error_limited, now=datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ"), )
def refresh_spec(): """Refresh the ESI spec. Returns: dictionary: JSON loaded swagger spec """ try: spec_details = CACHE.get(Keys.spec.value) except redis.exceptions.ConnectionError: spec_details = None save_results = False else: save_results = True if spec_details is None: spec_details = {"timestamp": 0} if time.time() - spec_details["timestamp"] > 300: headers = {} if spec_details.get("etag"): headers["If-None-Match"] = spec_details["etag"] _, _, res = request_or_wait( "{}/latest/swagger.json".format(ESI), _as_res=True, headers=headers, ) if isinstance(res, str): LOG.warning("failed to refresh spec: %s", res) return spec_details.get("spec", {}) spec_details["timestamp"] = time.time() if res.status_code != 304: spec_details["etag"] = res.headers.get("ETag") spec_details["spec"] = JsonDeref().deref(res.json()) if save_results: CACHE.set(Keys.spec.value, spec_details, timeout=3600) return spec_details["spec"]
def get_data(uuid): """Open and return the character's data.""" cache_key = "{}{}".format(Keys.complete.value, uuid) try: content = CACHE.get(cache_key) except Exception as error: LOG.warning("failed to get %s: %r", cache_key, error) else: if content is None: return None try: return ujson.loads(gzip.decompress(base64.b64decode(content))) except Exception as error: LOG.warning("failed to decode %s: %r", content, error) else: CACHE.cache._client.expire( # pylint: disable=protected-access cache_key, EXPIRY, ) return None