示例#1
0
def integrate_prometheus_metrics(app: Flask, restful_api: Api):
    # metrics = RESTfulPrometheusMetrics(app, restful_api)
    metrics = PrometheusMetrics(app)
    metrics.info('app_info', 'Application info', version='1.0.3')

    metrics.register_default(
        metrics.summary('by_path_method_time_stamp_summary',
                        'Request summary by request paths, method, timestamp',
                        labels={
                            'path': lambda: request.path,
                            'method': lambda: request.method,
                            'status': lambda r: r.status_code,
                            'time_stamp': lambda: time.time()
                        }))

    return metrics
示例#2
0
class ServerApp:
    sio: flask_socketio.SocketIO
    discord: DiscordOAuth2Session
    metrics: PrometheusMetrics
    fernet_encrypt: Fernet
    guest_encrypt: Optional[Fernet] = None
    patcher_provider: PatcherProvider

    def __init__(self, app: flask.Flask):
        self.app = app
        self.sio = flask_socketio.SocketIO(app)
        self.discord = DiscordOAuth2Session(app)
        self.metrics = PrometheusMetrics(app)
        self.fernet_encrypt = Fernet(app.config["FERNET_KEY"])
        if app.config["GUEST_KEY"] is not None:
            self.guest_encrypt = Fernet(app.config["GUEST_KEY"])
        self.patcher_provider = PatcherProvider()

    def get_server(self) -> socketio.Server:
        return self.sio.server

    def get_session(self, namespace=None):
        return self.get_server().get_session(flask.request.sid,
                                             namespace=namespace)

    def session(self, namespace=None):
        return self.get_server().session(flask.request.sid,
                                         namespace=namespace)

    def get_current_user(self) -> User:
        try:
            return User.get_by_id(self.get_session()["user-id"])
        except KeyError:
            raise NotLoggedIn()
        except peewee.DoesNotExist:
            raise InvalidSession()

    def join_game_session(self, membership: GameSessionMembership):
        flask_socketio.join_room(f"game-session-{membership.session.id}")
        flask_socketio.join_room(
            f"game-session-{membership.session.id}-{membership.user.id}")
        with self.session() as sio_session:
            sio_session["current_game_session"] = membership.session.id

    def leave_game_session(self):
        with self.session() as sio_session:
            if "current_game_session" not in sio_session:
                return
            current_game_session = sio_session.pop("current_game_session")

        user = self.get_current_user()
        flask_socketio.leave_room(f"game-session-{current_game_session}")
        flask_socketio.leave_room(
            f"game-session-{current_game_session}-{user.id}")

    def on(self, message: str, handler, namespace=None):
        @functools.wraps(handler)
        def _handler(*args):
            try:
                return {
                    "result": handler(self, *args),
                }
            except BaseNetworkError as error:
                return error.as_json

            except Exception:
                logger().exception(
                    f"Unhandled exception while processing request for message {message}. Args: {args}"
                )
                return ServerError().as_json

        metric_wrapper = self.metrics.summary(
            f"socket_{message}", f"Socket.io messages of type {message}")

        return self.sio.on(message, namespace)(metric_wrapper(_handler))

    def admin_route(self, route: str):
        def decorator(handler):
            @self.app.route(route)
            @functools.wraps(handler)
            def _handler(**kwargs):
                try:
                    user: User = User.get(
                        discord_id=self.discord.fetch_user().id)
                    if user is None or not user.admin:
                        return "User not authorized", 403

                    return handler(user, **kwargs)

                except flask_discord.exceptions.Unauthorized:
                    return "Unknown user", 404

            return _handler

        return decorator
示例#3
0
class ServerApp:
    sio: flask_socketio.SocketIO
    discord: DiscordOAuth2Session
    metrics: PrometheusMetrics
    fernet_encrypt: Fernet
    guest_encrypt: Optional[Fernet] = None

    def __init__(self, app: flask.Flask):
        self.app = app
        self.sio = flask_socketio.SocketIO(app)
        self.discord = DiscordOAuth2Session(app)
        self.metrics = PrometheusMetrics(app)
        self.fernet_encrypt = Fernet(app.config["FERNET_KEY"])
        if app.config["GUEST_KEY"] is not None:
            self.guest_encrypt = Fernet(app.config["GUEST_KEY"])

    def get_server(self) -> socketio.Server:
        return self.sio.server

    def get_session(self, namespace=None):
        return self.get_server().get_session(flask.request.sid,
                                             namespace=namespace)

    def session(self, namespace=None):
        return self.get_server().session(flask.request.sid,
                                         namespace=namespace)

    def get_current_user(self) -> User:
        try:
            return User.get_by_id(self.get_session()["user-id"])
        except KeyError:
            raise NotLoggedIn()
        except peewee.DoesNotExist:
            raise InvalidSession()

    def join_game_session(self, membership: GameSessionMembership):
        flask_socketio.join_room(f"game-session-{membership.session.id}")
        flask_socketio.join_room(
            f"game-session-{membership.session.id}-{membership.user.id}")
        with self.session() as sio_session:
            sio_session["current_game_session"] = membership.session.id

    def leave_game_session(self):
        with self.session() as sio_session:
            if "current_game_session" not in sio_session:
                return
            current_game_session = sio_session.pop("current_game_session")

        user = self.get_current_user()
        flask_socketio.leave_room(f"game-session-{current_game_session}")
        flask_socketio.leave_room(
            f"game-session-{current_game_session}-{user.id}")

    def on(self, message: str, handler, namespace=None):
        @functools.wraps(handler)
        def _handler(*args):
            try:
                return {
                    "result": handler(self, *args),
                }
            except BaseNetworkError as error:
                return error.as_json

            except Exception:
                logger().exception(
                    "Unexpected exception while processing request")
                return ServerError().as_json

        metric_wrapper = self.metrics.summary(
            f"socket_{message}", f"Socket.io messages of type {message}")

        return self.sio.on(message, namespace)(metric_wrapper(_handler))
示例#4
0
class ServerApp:
    sio: flask_socketio.SocketIO
    discord: CustomDiscordOAuth2Session
    metrics: PrometheusMetrics
    fernet_encrypt: Fernet
    guest_encrypt: Optional[Fernet] = None
    enforce_role: Optional[EnforceDiscordRole] = None
    expected_headers: dict[str, str]

    def __init__(self, app: flask.Flask):
        self.app = app
        self.sio = flask_socketio.SocketIO(app)
        self.discord = CustomDiscordOAuth2Session(app)
        self.metrics = PrometheusMetrics(app)
        self.fernet_encrypt = Fernet(app.config["FERNET_KEY"])
        if app.config["GUEST_KEY"] is not None:
            self.guest_encrypt = Fernet(app.config["GUEST_KEY"])
        if app.config["ENFORCE_ROLE"] is not None:
            self.enforce_role = EnforceDiscordRole(app.config["ENFORCE_ROLE"])

        self.expected_headers = connection_headers()
        self.expected_headers.pop("X-Randovania-Version")

    def get_server(self) -> socketio.Server:
        return self.sio.server

    def get_environ(self) -> Mapping:
        return self.get_server().get_environ(self._request_sid)

    @property
    def _request_sid(self):
        return getattr(flask.request, "sid")

    def save_session(self, session, namespace=None):
        self.get_server().save_session(self._request_sid,
                                       session,
                                       namespace=namespace)

    def get_session(self, namespace=None):
        return self.get_server().get_session(self._request_sid,
                                             namespace=namespace)

    def session(self, namespace=None):
        return self.get_server().session(self._request_sid,
                                         namespace=namespace)

    def get_current_user(self) -> User:
        try:
            return User.get_by_id(self.get_session()["user-id"])
        except KeyError:
            raise NotLoggedIn()
        except peewee.DoesNotExist:
            raise InvalidSession()

    def join_game_session(self, membership: GameSessionMembership):
        flask_socketio.join_room(f"game-session-{membership.session.id}")
        flask_socketio.join_room(
            f"game-session-{membership.session.id}-{membership.user.id}")
        with self.session() as sio_session:
            sio_session["current_game_session"] = membership.session.id

    def leave_game_session(self):
        with self.session() as sio_session:
            if "current_game_session" not in sio_session:
                return
            current_game_session = sio_session.pop("current_game_session")

        user = self.get_current_user()
        flask_socketio.leave_room(f"game-session-{current_game_session}")
        flask_socketio.leave_room(
            f"game-session-{current_game_session}-{user.id}")

    def on(self,
           message: str,
           handler,
           namespace=None,
           *,
           with_header_check: bool = False):
        @functools.wraps(handler)
        def _handler(*args):
            if with_header_check:
                error_msg = self.check_client_headers()
                if error_msg is not None:
                    return UnsupportedClient(error_msg).as_json

            try:
                return {
                    "result": handler(self, *args),
                }
            except BaseNetworkError as error:
                return error.as_json

            except (Exception, TypeError):
                logger().exception(
                    f"Unhandled exception while processing request for message {message}. Args: {args}"
                )
                return ServerError().as_json

        metric_wrapper = self.metrics.summary(
            f"socket_{message}", f"Socket.io messages of type {message}")

        return self.sio.on(message, namespace)(metric_wrapper(_handler))

    def admin_route(self, route: str):
        def decorator(handler):
            @self.app.route(route)
            @functools.wraps(handler)
            def _handler(**kwargs):
                try:
                    user: User
                    if not self.app.debug:
                        user = User.get(
                            discord_id=self.discord.fetch_user().id)
                        if user is None or not user.admin:
                            return "User not authorized", 403
                    else:
                        user = list(User.select().limit(1))[0]

                    return handler(user, **kwargs)

                except flask_discord.exceptions.Unauthorized:
                    return "Unknown user", 404

            return _handler

        return decorator

    def current_client_ip(self, sid=None) -> str:
        try:
            environ = self.get_server().get_environ(sid or self._request_sid)
            forwarded_for = environ.get('HTTP_X_FORWARDED_FOR')
            return f"{environ['REMOTE_ADDR']} ({forwarded_for})"
        except KeyError as e:
            return f"<unknown sid {e}>"

    def check_client_headers(self):
        environ = self.get_server().get_environ(self._request_sid)
        return client_check.check_client_headers(
            self.expected_headers,
            environ,
        )