Skip to content

catch exception on socketio connection #1365

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 13, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,23 @@
from typing import Dict, List, Optional

from aiohttp import web
from socketio.exceptions import ConnectionRefusedError as socket_io_connection_error

from servicelib.observer import observe
from servicelib.utils import fire_and_forget_task, logged_gather
from socketio.exceptions import ConnectionRefusedError as SocketIOConnectionError

from ..login.decorators import RQT_USERID_KEY, login_required
from ..resource_manager.websocket_manager import managed_resource
from .config import get_socket_server
from .handlers_utils import register_socketio_handler

ANONYMOUS_USER_ID = -1
_SOCKET_IO_AIOHTTP_REQUEST_KEY = "aiohttp.request"

log = logging.getLogger(__file__)


@register_socketio_handler
async def connect(sid: str, environ: Dict, app: web.Application) -> bool:
"""socketio reserved handler for when the fontend connects through socket.io

Expand All @@ -42,7 +44,10 @@ async def connect(sid: str, environ: Dict, app: web.Application) -> bool:
try:
await authenticate_user(sid, app, request)
except web.HTTPUnauthorized:
raise socket_io_connection_error("authentification failed")
raise SocketIOConnectionError("authentification failed")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor Minor: capitalize :-)

except Exception as exc: # pylint: disable=broad-except
raise SocketIOConnectionError(f"Unexpected error: {exc}")


return True

Expand Down Expand Up @@ -107,6 +112,7 @@ async def user_logged_out(
fire_and_forget_task(disconnect_other_sockets(sio, sockets))


@register_socketio_handler
async def disconnect(sid: str, app: web.Application) -> None:
"""socketio reserved handler for when the socket.io connection is disconnected.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
from .config import APP_CLIENT_SOCKET_DECORATED_HANDLERS_KEY, get_socket_server


socketio_handlers_registry = []


def socket_io_handler(app: web.Application):
"""this decorator allows passing additional paramters to python-socketio compatible handlers.
I.e. python-socketio handler expect functions of type `async def function(sid, *args, **kwargs)`
Expand All @@ -18,6 +21,7 @@ def decorator(func):
async def wrapped(*args, **kwargs):
return await func(*args, **kwargs, app=app)


return wrapped

return decorator
Expand All @@ -33,13 +37,9 @@ def has_socket_io_handler_signature(fun) -> bool:

def register_handlers(app: web.Application, module: ModuleType):
sio = get_socket_server(app)
predicate = (
lambda obj: inspect.isfunction(obj)
and has_socket_io_handler_signature(obj)
and inspect.iscoroutinefunction(obj)
and inspect.getmodule(obj) == module
)
member_fcts = inspect.getmembers(module, predicate)
member_fcts = [
fct for fct in socketio_handlers_registry if inspect.getmodule(fct) == module
]
# convert handler
partial_fcts = [
socket_io_handler(app)(func_handler) for _, func_handler in member_fcts
Expand All @@ -48,3 +48,23 @@ def register_handlers(app: web.Application, module: ModuleType):
# register the fcts
for func in partial_fcts:
sio.on(func.__name__, handler=func)


def register_socketio_handler(func: callable) -> callable:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MINOR:

from typing import Callable, Dict, Optional

HandlerT = Callable[[str, Dict, web.Application], Optional[bool]]

def register_socketio_handler(func: HandlerT) -> HandlerT:

And can even use HandlerT to assert signature below or moreover, perhaps mypy will catch issues when decorating functions of different signature

"""this decorator appends handlers to a registry if they fit certain rules

:param func: the function to call
:type func: callable
:return: the function to call
:rtype: callable
"""
is_handler = (
inspect.isfunction(func)
and has_socket_io_handler_signature(func)
and inspect.iscoroutinefunction(func)
)
if is_handler:
socketio_handlers_registry.append(func)
else:
raise SyntaxError("the function shall be of type fct(*args, app: web.Application")
return func