Browse Source

feat: routers and examples for routers

pull/1486/head
Konstantin Ponomarev 1 week ago
parent
commit
4dfdddde0d
  1. 2
      README.md
  2. 11
      examples/server/routers/app.py
  3. 16
      examples/server/routers/routers.py
  4. 18
      pyproject.toml
  5. 4
      src/fastsio/__init__.py
  6. 0
      src/fastsio/admin.py
  7. 0
      src/fastsio/asgi.py
  8. 0
      src/fastsio/async_admin.py
  9. 0
      src/fastsio/async_aiopika_manager.py
  10. 0
      src/fastsio/async_client.py
  11. 0
      src/fastsio/async_manager.py
  12. 0
      src/fastsio/async_namespace.py
  13. 0
      src/fastsio/async_pubsub_manager.py
  14. 0
      src/fastsio/async_redis_manager.py
  15. 0
      src/fastsio/async_server.py
  16. 0
      src/fastsio/async_simple_client.py
  17. 0
      src/fastsio/base_client.py
  18. 0
      src/fastsio/base_manager.py
  19. 0
      src/fastsio/base_namespace.py
  20. 18
      src/fastsio/base_server.py
  21. 0
      src/fastsio/client.py
  22. 0
      src/fastsio/exceptions.py
  23. 0
      src/fastsio/kafka_manager.py
  24. 0
      src/fastsio/kombu_manager.py
  25. 0
      src/fastsio/manager.py
  26. 0
      src/fastsio/middleware.py
  27. 0
      src/fastsio/msgpack_packet.py
  28. 0
      src/fastsio/namespace.py
  29. 0
      src/fastsio/packet.py
  30. 0
      src/fastsio/pubsub_manager.py
  31. 0
      src/fastsio/redis_manager.py
  32. 85
      src/fastsio/router.py
  33. 0
      src/fastsio/server.py
  34. 0
      src/fastsio/simple_client.py
  35. 0
      src/fastsio/tornado.py
  36. 0
      src/fastsio/zmq_manager.py

2
README.md

@ -1,4 +1,4 @@
python-socketio fastsio (Fork from python-socketio)
=============== ===============
[![Build status](https://github.com/miguelgrinberg/python-socketio/workflows/build/badge.svg)](https://github.com/miguelgrinberg/python-socketio/actions) [![codecov](https://codecov.io/gh/miguelgrinberg/python-socketio/branch/main/graph/badge.svg)](https://codecov.io/gh/miguelgrinberg/python-socketio) [![Build status](https://github.com/miguelgrinberg/python-socketio/workflows/build/badge.svg)](https://github.com/miguelgrinberg/python-socketio/actions) [![codecov](https://codecov.io/gh/miguelgrinberg/python-socketio/branch/main/graph/badge.svg)](https://codecov.io/gh/miguelgrinberg/python-socketio)

11
examples/server/routers/app.py

@ -0,0 +1,11 @@
import fastsio
from .routers import router
sio = fastsio.AsyncServer(
async_mode="asgi",
cors_allowed_origins=None,
)
# added all routers
sio.add_router(router=router)

16
examples/server/routers/routers.py

@ -0,0 +1,16 @@
from fastsio import RouterSIO
router = RouterSIO(namespace="/app")
@router.on("connect", namespace="/room") # override router namespace
async def on_connect(sid, environ):
print("connect ", sid)
@router.on("disconnect")
async def on_disconnect(sid):
print("disconnect ", sid)
@router.on("message")
async def on_message(sid, data):
print("message ", data)

18
pyproject.toml

@ -1,13 +1,14 @@
[tool.poetry] [tool.poetry]
name = "fast-socketio" name = "fastsio"
version = "5.13.1.dev0" version = "5.13.1.dev0"
description = "light and typization Socket.IO server and client for Python" description = "light and typization Socket.IO server and client for Python"
license = "MIT" license = "MIT"
license-files = ["LICEN[CS]E*"]
readme = "README.md" readme = "README.md"
homepage = "https://github.com/cicwak/fast-socketio" homepage = "https://github.com/cicwak/fastsio"
repository = "https://github.com/cicwak/fast-socketio" repository = "https://github.com/cicwak/fastsio"
packages = [ packages = [
{ include = "socketio", from = "src" }, { include = "fastsio", from = "src" },
] ]
authors = [ authors = [
"Miguel Grinberg <miguel.grinberg@gmail.com>", "Miguel Grinberg <miguel.grinberg@gmail.com>",
@ -19,8 +20,8 @@ file = "README.md"
content-type = "text/markdown" content-type = "text/markdown"
[project.urls] [project.urls]
Homepage = "https://github.com/cicwak/fast-socketio" Homepage = "https://github.com/cicwak/fastsio"
#"Bug Tracker" = "https://github.com/miguelgrinberg/python-socketio/issues" "Bug Tracker" = "https://github.com/cicwak/fastsio/issues"
[project.optional-dependencies] [project.optional-dependencies]
client = [ client = [
@ -62,7 +63,7 @@ where = [
namespaces = false namespaces = false
[build-system] [build-system]
requires = ["setuptools>=61.2"] requires = ["setuptools >= 77.0.3"]
build-backend = "setuptools.build_meta" build-backend = "setuptools.build_meta"
[tool.pytest.ini_options] [tool.pytest.ini_options]
@ -80,9 +81,6 @@ line-length = 88
exclude = [ exclude = [
"migrations", "migrations",
"venv", "venv",
"start_service.dist",
"start_service.build",
"start_service.onefile-build",
] ]

4
src/socketio/__init__.py → src/fastsio/__init__.py

@ -17,7 +17,7 @@ from .redis_manager import RedisManager
from .server import Server from .server import Server
from .simple_client import SimpleClient from .simple_client import SimpleClient
from .tornado import get_tornado_handler from .tornado import get_tornado_handler
from .router import RouterSocketIO from .router import RouterSIO
from .zmq_manager import ZmqManager from .zmq_manager import ZmqManager
__all__ = [ __all__ = [
@ -44,5 +44,5 @@ __all__ = [
"WSGIApp", "WSGIApp",
"ZmqManager", "ZmqManager",
"get_tornado_handler", "get_tornado_handler",
"RouterSocketIO", "RouterSIO",
] ]

0
src/socketio/admin.py → src/fastsio/admin.py

0
src/socketio/asgi.py → src/fastsio/asgi.py

0
src/socketio/async_admin.py → src/fastsio/async_admin.py

0
src/socketio/async_aiopika_manager.py → src/fastsio/async_aiopika_manager.py

0
src/socketio/async_client.py → src/fastsio/async_client.py

0
src/socketio/async_manager.py → src/fastsio/async_manager.py

0
src/socketio/async_namespace.py → src/fastsio/async_namespace.py

0
src/socketio/async_pubsub_manager.py → src/fastsio/async_pubsub_manager.py

0
src/socketio/async_redis_manager.py → src/fastsio/async_redis_manager.py

0
src/socketio/async_server.py → src/fastsio/async_server.py

0
src/socketio/async_simple_client.py → src/fastsio/async_simple_client.py

0
src/socketio/base_client.py → src/fastsio/base_client.py

0
src/socketio/base_manager.py → src/fastsio/base_manager.py

0
src/socketio/base_namespace.py → src/fastsio/base_namespace.py

18
src/socketio/base_server.py → src/fastsio/base_server.py

@ -5,6 +5,7 @@ from typing import Any, Callable, Dict, List, Optional, Tuple, Union
import engineio import engineio
from . import base_namespace, manager, packet from . import base_namespace, manager, packet
from .router import RouterSIO
default_logger = logging.getLogger("socketio.server") default_logger = logging.getLogger("socketio.server")
@ -194,14 +195,25 @@ class BaseServer:
raise ValueError("Not a namespace instance") raise ValueError("Not a namespace instance")
if self.is_asyncio_based() != namespace_handler.is_asyncio_based(): if self.is_asyncio_based() != namespace_handler.is_asyncio_based():
raise ValueError("Not a valid namespace class for this server") raise ValueError("Not a valid namespace class for this server")
namespace_handler._set_server(self)
self.namespace_handlers[namespace_handler.namespace] = namespace_handler
namespace_handler._set_server(self) # type: ignore[misc] namespace_handler._set_server(self) # type: ignore[misc]
ns: str = str(namespace_handler.namespace or "/") ns: str = str(namespace_handler.namespace or "/")
self.namespace_handlers[ns] = namespace_handler self.namespace_handlers[ns] = namespace_handler
def add_router(self, router: RouterSIO) -> None:
"""Attach a RouterSIO to this server.
This will register all function-based handlers and any queued
class-based namespace handlers contained in the router.
"""
# function-based
for ns, event, handler in router.iter_function_handlers():
if ns not in self.handlers:
self.handlers[ns] = {}
self.handlers[ns][event] = handler
# class-based namespaces
for ns_handler in router.iter_namespace_handlers():
self.register_namespace(ns_handler)
def rooms(self, sid, namespace=None):
def rooms(self, sid: str, namespace: Optional[str] = None) -> List[str]: def rooms(self, sid: str, namespace: Optional[str] = None) -> List[str]:
"""Return the rooms a client is in. """Return the rooms a client is in.

0
src/socketio/client.py → src/fastsio/client.py

0
src/socketio/exceptions.py → src/fastsio/exceptions.py

0
src/socketio/kafka_manager.py → src/fastsio/kafka_manager.py

0
src/socketio/kombu_manager.py → src/fastsio/kombu_manager.py

0
src/socketio/manager.py → src/fastsio/manager.py

0
src/socketio/middleware.py → src/fastsio/middleware.py

0
src/socketio/msgpack_packet.py → src/fastsio/msgpack_packet.py

0
src/socketio/namespace.py → src/fastsio/namespace.py

0
src/socketio/packet.py → src/fastsio/packet.py

0
src/socketio/pubsub_manager.py → src/fastsio/pubsub_manager.py

0
src/socketio/redis_manager.py → src/fastsio/redis_manager.py

85
src/fastsio/router.py

@ -0,0 +1,85 @@
from typing import Any, Callable, Dict, List, Optional, Tuple
from . import base_namespace
class RouterSIO:
"""A lightweight router for organizing Socket.IO event handlers.
This provides a FastAPI-like developer experience for grouping and
including handlers. Handlers registered on the router can later be
attached to a server via ``sio.add_router(router)``.
Example:
router = RouterSIO(namespace="/chat")
@router.on("message")
async def handle_message(sid: str, data: Any):
...
sio.add_router(router)
"""
def __init__(self, namespace: Optional[str] = None) -> None:
# Default namespace applied when not provided explicitly in .on()/@event
self.default_namespace: str = namespace or "/"
# Decorator-based function handlers: {namespace: {event: handler}}
self.handlers: Dict[str, Dict[str, Callable[..., Any]]] = {}
# Class-based namespace handlers to be registered on the server
self._namespace_handlers: List[base_namespace.BaseServerNamespace] = []
# Public API mirrors Server.on
def on(
self,
event: str,
handler: Optional[Callable[..., Any]] = None,
namespace: Optional[str] = None,
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
ns = namespace or self.default_namespace
def set_handler(h: Callable[..., Any]) -> Callable[..., Any]:
if ns not in self.handlers:
self.handlers[ns] = {}
self.handlers[ns][event] = h
return h
if handler is None:
return set_handler
set_handler(handler)
return set_handler
# Convenience decorator mirrors Server.event
def event(self, *args: Any, **kwargs: Any) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
if len(args) == 1 and len(kwargs) == 0 and callable(args[0]):
# invoked without arguments: @router.event
return self.on(args[0].__name__)(args[0])
# invoked with arguments: @router.event(namespace="...")
def set_handler(h: Callable[..., Any]) -> Callable[..., Any]:
return self.on(h.__name__, *args, **kwargs)(h)
return set_handler
def register_namespace(self, namespace_handler: base_namespace.BaseServerNamespace) -> None:
"""Queue a class-based namespace handler for registration.
The actual registration occurs when the router is attached to a server
via ``sio.add_router(router)``.
"""
if not isinstance(namespace_handler, base_namespace.BaseServerNamespace): # type: ignore[redundant-expr]
raise ValueError("Not a namespace instance")
self._namespace_handlers.append(namespace_handler)
# Internal helpers used by the server when attaching the router
def iter_function_handlers(self) -> List[Tuple[str, str, Callable[..., Any]]]:
out: List[Tuple[str, str, Callable[..., Any]]] = []
for ns, events in self.handlers.items():
for event, handler in events.items():
out.append((ns, event, handler))
return out
def iter_namespace_handlers(self) -> List[base_namespace.BaseServerNamespace]:
return list(self._namespace_handlers)

0
src/socketio/server.py → src/fastsio/server.py

0
src/socketio/simple_client.py → src/fastsio/simple_client.py

0
src/socketio/tornado.py → src/fastsio/tornado.py

0
src/socketio/zmq_manager.py → src/fastsio/zmq_manager.py

Loading…
Cancel
Save