python-engineio 4.7.1__py3-none-any.whl → 4.8.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
engineio/__init__.py CHANGED
@@ -1,23 +1,13 @@
1
- import sys
2
-
3
1
  from .client import Client
4
2
  from .middleware import WSGIApp, Middleware
5
3
  from .server import Server
6
- if sys.version_info >= (3, 5): # pragma: no cover
7
- from .asyncio_server import AsyncServer
8
- from .asyncio_client import AsyncClient
9
- from .async_drivers.asgi import ASGIApp
10
- try:
11
- from .async_drivers.tornado import get_tornado_handler
12
- except ImportError:
13
- get_tornado_handler = None
14
- else: # pragma: no cover
15
- AsyncServer = None
16
- AsyncClient = None
4
+ from .async_server import AsyncServer
5
+ from .async_client import AsyncClient
6
+ from .async_drivers.asgi import ASGIApp
7
+ try:
8
+ from .async_drivers.tornado import get_tornado_handler
9
+ except ImportError: # pragma: no cover
17
10
  get_tornado_handler = None
18
- ASGIApp = None
19
11
 
20
- __all__ = ['Server', 'WSGIApp', 'Middleware', 'Client']
21
- if AsyncServer is not None: # pragma: no cover
22
- __all__ += ['AsyncServer', 'ASGIApp', 'get_tornado_handler',
23
- 'AsyncClient']
12
+ __all__ = ['Server', 'WSGIApp', 'Middleware', 'Client',
13
+ 'AsyncServer', 'ASGIApp', 'get_tornado_handler', 'AsyncClient']
@@ -8,7 +8,7 @@ try:
8
8
  except ImportError: # pragma: no cover
9
9
  aiohttp = None
10
10
 
11
- from . import client
11
+ from . import base_client
12
12
  from . import exceptions
13
13
  from . import packet
14
14
  from . import payload
@@ -22,7 +22,7 @@ def async_signal_handler():
22
22
  Disconnect all active async clients.
23
23
  """
24
24
  async def _handler(): # pragma: no cover
25
- for c in client.connected_clients[:]:
25
+ for c in base_client.connected_clients[:]:
26
26
  if c.is_asyncio_based():
27
27
  await c.disconnect()
28
28
 
@@ -37,7 +37,7 @@ def async_signal_handler():
37
37
  asyncio.ensure_future(_handler())
38
38
 
39
39
 
40
- class AsyncClient(client.Client):
40
+ class AsyncClient(base_client.BaseClient):
41
41
  """An Engine.IO client for asyncio.
42
42
 
43
43
  This class implements a fully compliant Engine.IO web client with support
@@ -71,7 +71,6 @@ class AsyncClient(client.Client):
71
71
  arguments passed to
72
72
  ``aiohttp.ws_connect()``.
73
73
  """
74
-
75
74
  def is_asyncio_based(self):
76
75
  return True
77
76
 
@@ -164,7 +163,7 @@ class AsyncClient(client.Client):
164
163
  await self.read_loop_task
165
164
  self.state = 'disconnected'
166
165
  try:
167
- client.connected_clients.remove(self)
166
+ base_client.connected_clients.remove(self)
168
167
  except ValueError: # pragma: no cover
169
168
  pass
170
169
  await self._reset()
@@ -262,7 +261,7 @@ class AsyncClient(client.Client):
262
261
  self.base_url += '&sid=' + self.sid
263
262
 
264
263
  self.state = 'connected'
265
- client.connected_clients.append(self)
264
+ base_client.connected_clients.append(self)
266
265
  await self._trigger_event('connect', run_async=False)
267
266
 
268
267
  for pkt in p.packets[1:]:
@@ -384,7 +383,7 @@ class AsyncClient(client.Client):
384
383
  self.current_transport = 'websocket'
385
384
 
386
385
  self.state = 'connected'
387
- client.connected_clients.append(self)
386
+ base_client.connected_clients.append(self)
388
387
  await self._trigger_event('connect', run_async=False)
389
388
 
390
389
  self.ws = ws
@@ -515,7 +514,7 @@ class AsyncClient(client.Client):
515
514
  if self.state == 'connected':
516
515
  await self._trigger_event('disconnect', run_async=False)
517
516
  try:
518
- client.connected_clients.remove(self)
517
+ base_client.connected_clients.remove(self)
519
518
  except ValueError: # pragma: no cover
520
519
  pass
521
520
  await self._reset()
@@ -566,7 +565,7 @@ class AsyncClient(client.Client):
566
565
  if self.state == 'connected':
567
566
  await self._trigger_event('disconnect', run_async=False)
568
567
  try:
569
- client.connected_clients.remove(self)
568
+ base_client.connected_clients.remove(self)
570
569
  except ValueError: # pragma: no cover
571
570
  pass
572
571
  await self._reset()
@@ -233,9 +233,14 @@ class WebSocket(object): # pragma: no cover
233
233
  self.asgi_send = environ['asgi.send']
234
234
  await self.asgi_send({'type': 'websocket.accept'})
235
235
  await self.handler(self)
236
+ return '' # send nothing as response
236
237
 
237
238
  async def close(self):
238
- pass
239
+ try:
240
+ await self.asgi_send({'type': 'websocket.close'})
241
+ except Exception:
242
+ # if the socket is already close we don't care
243
+ pass
239
244
 
240
245
  async def send(self, message):
241
246
  msg_bytes = None
@@ -61,6 +61,7 @@ class uWSGIWebSocket(object): # pragma: no cover
61
61
 
62
62
  self.app(self)
63
63
  uwsgi.disconnect()
64
+ return '' # send nothing as response
64
65
 
65
66
  def close(self):
66
67
  """Disconnects uWSGI from the client."""
@@ -114,6 +114,7 @@ class WebSocket(object): # pragma: no cover
114
114
  """
115
115
  def __init__(self, handler, server):
116
116
  self.handler = handler
117
+ self.server = server
117
118
  self._sock = None
118
119
 
119
120
  async def __call__(self, environ):
@@ -123,6 +124,7 @@ class WebSocket(object): # pragma: no cover
123
124
 
124
125
  self.environ = environ
125
126
  await self.handler(self)
127
+ return self.server._ok()
126
128
 
127
129
  async def close(self):
128
130
  await self._sock.close()
@@ -1,13 +1,13 @@
1
1
  import asyncio
2
2
  import urllib
3
3
 
4
+ from . import base_server
4
5
  from . import exceptions
5
6
  from . import packet
6
- from . import server
7
- from . import asyncio_socket
7
+ from . import async_socket
8
8
 
9
9
 
10
- class AsyncServer(server.Server):
10
+ class AsyncServer(base_server.BaseServer):
11
11
  """An Engine.IO server for asyncio.
12
12
 
13
13
  This class implements a fully compliant Engine.IO web server with support
@@ -418,7 +418,7 @@ class AsyncServer(server.Server):
418
418
  self._service_task)
419
419
 
420
420
  sid = self.generate_id()
421
- s = asyncio_socket.AsyncSocket(self, sid)
421
+ s = async_socket.AsyncSocket(self, sid)
422
422
  self.sockets[sid] = s
423
423
 
424
424
  pkt = packet.Packet(
@@ -2,13 +2,13 @@ import asyncio
2
2
  import sys
3
3
  import time
4
4
 
5
+ from . import base_socket
5
6
  from . import exceptions
6
7
  from . import packet
7
8
  from . import payload
8
- from . import socket
9
9
 
10
10
 
11
- class AsyncSocket(socket.Socket):
11
+ class AsyncSocket(base_socket.BaseSocket):
12
12
  async def poll(self):
13
13
  """Wait for packets to send to the client."""
14
14
  try:
@@ -122,14 +122,14 @@ class AsyncSocket(socket.Socket):
122
122
  await self.queue.join()
123
123
 
124
124
  def schedule_ping(self):
125
- async def send_ping():
126
- self.last_ping = None
127
- await asyncio.sleep(self.server.ping_interval)
128
- if not self.closing and not self.closed:
129
- self.last_ping = time.time()
130
- await self.send(packet.Packet(packet.PING))
131
-
132
- self.server.start_background_task(send_ping)
125
+ self.server.start_background_task(self._send_ping)
126
+
127
+ async def _send_ping(self):
128
+ self.last_ping = None
129
+ await asyncio.sleep(self.server.ping_interval)
130
+ if not self.closing and not self.closed:
131
+ self.last_ping = time.time()
132
+ await self.send(packet.Packet(packet.PING))
133
133
 
134
134
  async def _upgrade_websocket(self, environ):
135
135
  """Upgrade the connection from polling to websocket."""
@@ -0,0 +1,146 @@
1
+ import logging
2
+ import signal
3
+ import threading
4
+ import time
5
+ import urllib
6
+ from . import packet
7
+
8
+ default_logger = logging.getLogger('engineio.client')
9
+ connected_clients = []
10
+
11
+
12
+ def signal_handler(sig, frame):
13
+ """SIGINT handler.
14
+
15
+ Disconnect all active clients and then invoke the original signal handler.
16
+ """
17
+ for client in connected_clients[:]:
18
+ if not client.is_asyncio_based():
19
+ client.disconnect()
20
+ if callable(original_signal_handler):
21
+ return original_signal_handler(sig, frame)
22
+ else: # pragma: no cover
23
+ # Handle case where no original SIGINT handler was present.
24
+ return signal.default_int_handler(sig, frame)
25
+
26
+
27
+ original_signal_handler = None
28
+
29
+
30
+ class BaseClient:
31
+ event_names = ['connect', 'disconnect', 'message']
32
+
33
+ def __init__(self, logger=False, json=None, request_timeout=5,
34
+ http_session=None, ssl_verify=True, handle_sigint=True,
35
+ websocket_extra_options=None):
36
+ global original_signal_handler
37
+ if handle_sigint and original_signal_handler is None and \
38
+ threading.current_thread() == threading.main_thread():
39
+ original_signal_handler = signal.signal(signal.SIGINT,
40
+ signal_handler)
41
+ self.handlers = {}
42
+ self.base_url = None
43
+ self.transports = None
44
+ self.current_transport = None
45
+ self.sid = None
46
+ self.upgrades = None
47
+ self.ping_interval = None
48
+ self.ping_timeout = None
49
+ self.http = http_session
50
+ self.external_http = http_session is not None
51
+ self.handle_sigint = handle_sigint
52
+ self.ws = None
53
+ self.read_loop_task = None
54
+ self.write_loop_task = None
55
+ self.queue = None
56
+ self.state = 'disconnected'
57
+ self.ssl_verify = ssl_verify
58
+ self.websocket_extra_options = websocket_extra_options or {}
59
+
60
+ if json is not None:
61
+ packet.Packet.json = json
62
+ if not isinstance(logger, bool):
63
+ self.logger = logger
64
+ else:
65
+ self.logger = default_logger
66
+ if self.logger.level == logging.NOTSET:
67
+ if logger:
68
+ self.logger.setLevel(logging.INFO)
69
+ else:
70
+ self.logger.setLevel(logging.ERROR)
71
+ self.logger.addHandler(logging.StreamHandler())
72
+
73
+ self.request_timeout = request_timeout
74
+
75
+ def is_asyncio_based(self):
76
+ return False
77
+
78
+ def on(self, event, handler=None):
79
+ """Register an event handler.
80
+
81
+ :param event: The event name. Can be ``'connect'``, ``'message'`` or
82
+ ``'disconnect'``.
83
+ :param handler: The function that should be invoked to handle the
84
+ event. When this parameter is not given, the method
85
+ acts as a decorator for the handler function.
86
+
87
+ Example usage::
88
+
89
+ # as a decorator:
90
+ @eio.on('connect')
91
+ def connect_handler():
92
+ print('Connection request')
93
+
94
+ # as a method:
95
+ def message_handler(msg):
96
+ print('Received message: ', msg)
97
+ eio.send('response')
98
+ eio.on('message', message_handler)
99
+ """
100
+ if event not in self.event_names:
101
+ raise ValueError('Invalid event')
102
+
103
+ def set_handler(handler):
104
+ self.handlers[event] = handler
105
+ return handler
106
+
107
+ if handler is None:
108
+ return set_handler
109
+ set_handler(handler)
110
+
111
+ def transport(self):
112
+ """Return the name of the transport currently in use.
113
+
114
+ The possible values returned by this function are ``'polling'`` and
115
+ ``'websocket'``.
116
+ """
117
+ return self.current_transport
118
+
119
+ def _reset(self):
120
+ self.state = 'disconnected'
121
+ self.sid = None
122
+
123
+ def _get_engineio_url(self, url, engineio_path, transport):
124
+ """Generate the Engine.IO connection URL."""
125
+ engineio_path = engineio_path.strip('/')
126
+ parsed_url = urllib.parse.urlparse(url)
127
+
128
+ if transport == 'polling':
129
+ scheme = 'http'
130
+ elif transport == 'websocket':
131
+ scheme = 'ws'
132
+ else: # pragma: no cover
133
+ raise ValueError('invalid transport')
134
+ if parsed_url.scheme in ['https', 'wss']:
135
+ scheme += 's'
136
+
137
+ return ('{scheme}://{netloc}/{path}/?{query}'
138
+ '{sep}transport={transport}&EIO=4').format(
139
+ scheme=scheme, netloc=parsed_url.netloc,
140
+ path=engineio_path, query=parsed_url.query,
141
+ sep='&' if parsed_url.query else '',
142
+ transport=transport)
143
+
144
+ def _get_url_timestamp(self):
145
+ """Generate the Engine.IO query string timestamp."""
146
+ return '&t=' + str(time.time())