Skip to content

Commit

Permalink
Internal code restructure (no functional changes)
Browse files Browse the repository at this point in the history
  • Loading branch information
miguelgrinberg committed Oct 4, 2023
1 parent 3f36a15 commit 83361a1
Show file tree
Hide file tree
Showing 22 changed files with 739 additions and 736 deletions.
24 changes: 3 additions & 21 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,45 +6,27 @@ API Reference

.. module:: engineio

``Client`` class
----------------

.. autoclass:: Client
:members:

``AsyncClient`` class
---------------------
:inherited-members:

.. autoclass:: AsyncClient
:members:
:inherited-members:

``Server`` class
----------------

.. autoclass:: Server
:members:

``AsyncServer`` class
---------------------
:inherited-members:

.. autoclass:: AsyncServer
:members:
:inherited-members:

``WSGIApp`` class
-----------------

.. autoclass:: WSGIApp
:members:

``ASGIApp`` class
-----------------

.. autoclass:: ASGIApp

``Middleware`` class (deprecated)
---------------------------------
:members:

.. autoclass:: Middleware
:members:
Expand Down
26 changes: 8 additions & 18 deletions src/engineio/__init__.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,13 @@
import sys

from .client import Client
from .middleware import WSGIApp, Middleware
from .server import Server
if sys.version_info >= (3, 5): # pragma: no cover
from .asyncio_server import AsyncServer
from .asyncio_client import AsyncClient
from .async_drivers.asgi import ASGIApp
try:
from .async_drivers.tornado import get_tornado_handler
except ImportError:
get_tornado_handler = None
else: # pragma: no cover
AsyncServer = None
AsyncClient = None
from .async_server import AsyncServer
from .async_client import AsyncClient
from .async_drivers.asgi import ASGIApp
try:
from .async_drivers.tornado import get_tornado_handler
except ImportError: # pragma: no cover
get_tornado_handler = None
ASGIApp = None

__all__ = ['Server', 'WSGIApp', 'Middleware', 'Client']
if AsyncServer is not None: # pragma: no cover
__all__ += ['AsyncServer', 'ASGIApp', 'get_tornado_handler',
'AsyncClient']
__all__ = ['Server', 'WSGIApp', 'Middleware', 'Client',
'AsyncServer', 'ASGIApp', 'get_tornado_handler', 'AsyncClient']
16 changes: 8 additions & 8 deletions src/engineio/asyncio_client.py → src/engineio/async_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
except ImportError: # pragma: no cover
aiohttp = None

from . import client
from . import base_client
from . import exceptions
from . import packet
from . import payload
Expand All @@ -22,7 +22,7 @@ def async_signal_handler():
Disconnect all active async clients.
"""
async def _handler(): # pragma: no cover
for c in client.connected_clients[:]:
for c in base_client.connected_clients[:]:
if c.is_asyncio_based():
await c.disconnect()

Expand All @@ -37,7 +37,7 @@ async def _handler(): # pragma: no cover
asyncio.ensure_future(_handler())


class AsyncClient(client.Client):
class AsyncClient(base_client.BaseClient):
"""An Engine.IO client for asyncio.
This class implements a fully compliant Engine.IO web client with support
Expand Down Expand Up @@ -164,7 +164,7 @@ async def disconnect(self, abort=False):
await self.read_loop_task
self.state = 'disconnected'
try:
client.connected_clients.remove(self)
base_client.connected_clients.remove(self)
except ValueError: # pragma: no cover
pass
await self._reset()
Expand Down Expand Up @@ -262,7 +262,7 @@ async def _connect_polling(self, url, headers, engineio_path):
self.base_url += '&sid=' + self.sid

self.state = 'connected'
client.connected_clients.append(self)
base_client.connected_clients.append(self)
await self._trigger_event('connect', run_async=False)

for pkt in p.packets[1:]:
Expand Down Expand Up @@ -384,7 +384,7 @@ async def _connect_websocket(self, url, headers, engineio_path):
self.current_transport = 'websocket'

self.state = 'connected'
client.connected_clients.append(self)
base_client.connected_clients.append(self)
await self._trigger_event('connect', run_async=False)

self.ws = ws
Expand Down Expand Up @@ -515,7 +515,7 @@ async def _read_loop_polling(self):
if self.state == 'connected':
await self._trigger_event('disconnect', run_async=False)
try:
client.connected_clients.remove(self)
base_client.connected_clients.remove(self)
except ValueError: # pragma: no cover
pass
await self._reset()
Expand Down Expand Up @@ -566,7 +566,7 @@ async def _read_loop_websocket(self):
if self.state == 'connected':
await self._trigger_event('disconnect', run_async=False)
try:
client.connected_clients.remove(self)
base_client.connected_clients.remove(self)
except ValueError: # pragma: no cover
pass
await self._reset()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import asyncio
import urllib

from . import base_server
from . import exceptions
from . import packet
from . import server
from . import asyncio_socket
from . import async_socket


class AsyncServer(server.Server):
class AsyncServer(base_server.BaseServer):
"""An Engine.IO server for asyncio.
This class implements a fully compliant Engine.IO web server with support
Expand Down Expand Up @@ -418,7 +418,7 @@ async def _handle_connect(self, environ, transport, jsonp_index=None):
self._service_task)

sid = self.generate_id()
s = asyncio_socket.AsyncSocket(self, sid)
s = async_socket.AsyncSocket(self, sid)
self.sockets[sid] = s

pkt = packet.Packet(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
import sys
import time

from . import base_socket
from . import exceptions
from . import packet
from . import payload
from . import socket


class AsyncSocket(socket.Socket):
class AsyncSocket(base_socket.BaseSocket):
async def poll(self):
"""Wait for packets to send to the client."""
try:
Expand Down
121 changes: 121 additions & 0 deletions src/engineio/base_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import logging
import time
import urllib
from . import packet

default_logger = logging.getLogger('engineio.client')
connected_clients = []


class BaseClient:
event_names = ['connect', 'disconnect', 'message']

def __init__(self, logger=False, json=None, request_timeout=5,
http_session=None, ssl_verify=True, handle_sigint=True,
websocket_extra_options=None):
self.handlers = {}
self.base_url = None
self.transports = None
self.current_transport = None
self.sid = None
self.upgrades = None
self.ping_interval = None
self.ping_timeout = None
self.http = http_session
self.external_http = http_session is not None
self.handle_sigint = handle_sigint
self.ws = None
self.read_loop_task = None
self.write_loop_task = None
self.queue = None
self.state = 'disconnected'
self.ssl_verify = ssl_verify
self.websocket_extra_options = websocket_extra_options or {}

if json is not None:
packet.Packet.json = json
if not isinstance(logger, bool):
self.logger = logger
else:
self.logger = default_logger
if self.logger.level == logging.NOTSET:
if logger:
self.logger.setLevel(logging.INFO)
else:
self.logger.setLevel(logging.ERROR)
self.logger.addHandler(logging.StreamHandler())

self.request_timeout = request_timeout

def is_asyncio_based(self):
return False

def on(self, event, handler=None):
"""Register an event handler.
:param event: The event name. Can be ``'connect'``, ``'message'`` or
``'disconnect'``.
:param handler: The function that should be invoked to handle the
event. When this parameter is not given, the method
acts as a decorator for the handler function.
Example usage::
# as a decorator:
@eio.on('connect')
def connect_handler():
print('Connection request')
# as a method:
def message_handler(msg):
print('Received message: ', msg)
eio.send('response')
eio.on('message', message_handler)
"""
if event not in self.event_names:
raise ValueError('Invalid event')

def set_handler(handler):
self.handlers[event] = handler
return handler

if handler is None:
return set_handler
set_handler(handler)

def transport(self):
"""Return the name of the transport currently in use.
The possible values returned by this function are ``'polling'`` and
``'websocket'``.
"""
return self.current_transport

def _reset(self):
self.state = 'disconnected'
self.sid = None

def _get_engineio_url(self, url, engineio_path, transport):
"""Generate the Engine.IO connection URL."""
engineio_path = engineio_path.strip('/')
parsed_url = urllib.parse.urlparse(url)

if transport == 'polling':
scheme = 'http'
elif transport == 'websocket':
scheme = 'ws'
else: # pragma: no cover
raise ValueError('invalid transport')
if parsed_url.scheme in ['https', 'wss']:
scheme += 's'

return ('{scheme}://{netloc}/{path}/?{query}'
'{sep}transport={transport}&EIO=4').format(
scheme=scheme, netloc=parsed_url.netloc,
path=engineio_path, query=parsed_url.query,
sep='&' if parsed_url.query else '',
transport=transport)

def _get_url_timestamp(self):
"""Generate the Engine.IO query string timestamp."""
return '&t=' + str(time.time())
Loading

0 comments on commit 83361a1

Please sign in to comment.