python-engineio 4.13.1__tar.gz → 4.13.2__tar.gz
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.
- {python_engineio-4.13.1/src/python_engineio.egg-info → python_engineio-4.13.2}/PKG-INFO +1 -1
- {python_engineio-4.13.1 → python_engineio-4.13.2}/pyproject.toml +1 -1
- {python_engineio-4.13.1 → python_engineio-4.13.2}/src/engineio/async_drivers/aiohttp.py +3 -1
- {python_engineio-4.13.1 → python_engineio-4.13.2}/src/engineio/async_drivers/asgi.py +12 -13
- {python_engineio-4.13.1 → python_engineio-4.13.2}/src/engineio/async_server.py +2 -1
- {python_engineio-4.13.1 → python_engineio-4.13.2}/src/engineio/async_socket.py +4 -2
- {python_engineio-4.13.1 → python_engineio-4.13.2}/src/engineio/base_socket.py +4 -1
- {python_engineio-4.13.1 → python_engineio-4.13.2}/src/engineio/server.py +2 -1
- {python_engineio-4.13.1 → python_engineio-4.13.2}/src/engineio/socket.py +4 -2
- {python_engineio-4.13.1 → python_engineio-4.13.2/src/python_engineio.egg-info}/PKG-INFO +1 -1
- {python_engineio-4.13.1 → python_engineio-4.13.2}/src/python_engineio.egg-info/SOURCES.txt +0 -9
- {python_engineio-4.13.1 → python_engineio-4.13.2}/src/python_engineio.egg-info/dependency_links.txt +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/src/python_engineio.egg-info/not-zip-safe +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/src/python_engineio.egg-info/requires.txt +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/src/python_engineio.egg-info/top_level.txt +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/tests/async/test_socket.py +18 -2
- {python_engineio-4.13.1 → python_engineio-4.13.2}/tests/common/test_socket.py +14 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/tox.ini +0 -15
- python_engineio-4.13.1/docs/Makefile +0 -19
- python_engineio-4.13.1/docs/api.rst +0 -14
- python_engineio-4.13.1/docs/client.rst +0 -211
- python_engineio-4.13.1/docs/conf.py +0 -177
- python_engineio-4.13.1/docs/index.rst +0 -23
- python_engineio-4.13.1/docs/intro.rst +0 -152
- python_engineio-4.13.1/docs/make.bat +0 -35
- python_engineio-4.13.1/docs/server.rst +0 -674
- python_engineio-4.13.1/tests/common/__init__.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/LICENSE +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/MANIFEST.in +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/README.md +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/docs/_static/README.md +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/setup.cfg +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/src/engineio/__init__.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/src/engineio/async_client.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/src/engineio/async_drivers/__init__.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/src/engineio/async_drivers/_websocket_wsgi.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/src/engineio/async_drivers/eventlet.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/src/engineio/async_drivers/gevent.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/src/engineio/async_drivers/gevent_uwsgi.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/src/engineio/async_drivers/sanic.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/src/engineio/async_drivers/threading.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/src/engineio/async_drivers/tornado.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/src/engineio/base_client.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/src/engineio/base_server.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/src/engineio/client.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/src/engineio/exceptions.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/src/engineio/json.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/src/engineio/middleware.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/src/engineio/packet.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/src/engineio/payload.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/src/engineio/static_files.py +0 -0
- {python_engineio-4.13.1/tests → python_engineio-4.13.2/tests/async}/__init__.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/tests/async/index.html +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/tests/async/test_aiohttp.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/tests/async/test_asgi.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/tests/async/test_client.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/tests/async/test_sanic.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/tests/async/test_server.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/tests/async/test_tornado.py +0 -0
- {python_engineio-4.13.1/tests/async → python_engineio-4.13.2/tests/common}/__init__.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/tests/common/index.html +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/tests/common/test_client.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/tests/common/test_middleware.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/tests/common/test_packet.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/tests/common/test_payload.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/tests/common/test_server.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/tests/performance/README.md +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/tests/performance/binary_b64_packet.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/tests/performance/binary_packet.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/tests/performance/json_packet.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/tests/performance/payload.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/tests/performance/run.sh +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/tests/performance/server_receive.py +0 -0
- {python_engineio-4.13.1 → python_engineio-4.13.2}/tests/performance/text_packet.py +0 -0
|
@@ -79,11 +79,13 @@ class WebSocket: # pragma: no cover
|
|
|
79
79
|
"""
|
|
80
80
|
def __init__(self, handler, server):
|
|
81
81
|
self.handler = handler
|
|
82
|
+
self.server = server
|
|
82
83
|
self._sock = None
|
|
83
84
|
|
|
84
85
|
async def __call__(self, environ):
|
|
85
86
|
request = environ['aiohttp.request']
|
|
86
|
-
self._sock = WebSocketResponse(
|
|
87
|
+
self._sock = WebSocketResponse(
|
|
88
|
+
max_msg_size=self.server.max_http_buffer_size)
|
|
87
89
|
await self._sock.prepare(request)
|
|
88
90
|
|
|
89
91
|
self.environ = environ
|
|
@@ -136,10 +136,18 @@ class ASGIApp:
|
|
|
136
136
|
|
|
137
137
|
async def translate_request(scope, receive, send):
|
|
138
138
|
class AwaitablePayload: # pragma: no cover
|
|
139
|
-
def __init__(self,
|
|
140
|
-
self.
|
|
139
|
+
def __init__(self, event):
|
|
140
|
+
self.event = event
|
|
141
|
+
self.payload = None
|
|
141
142
|
|
|
142
143
|
async def read(self, length=None):
|
|
144
|
+
if self.payload is None and event['type'] == 'http.request':
|
|
145
|
+
# read payload from http request
|
|
146
|
+
self.payload = self.event.get('body') or b''
|
|
147
|
+
while self.event.get('more_body'):
|
|
148
|
+
self.event = await receive()
|
|
149
|
+
if self.event['type'] == 'http.request':
|
|
150
|
+
self.payload += self.event.get('body') or b''
|
|
143
151
|
if length is None:
|
|
144
152
|
r = self.payload
|
|
145
153
|
self.payload = b''
|
|
@@ -149,16 +157,7 @@ async def translate_request(scope, receive, send):
|
|
|
149
157
|
return r
|
|
150
158
|
|
|
151
159
|
event = await receive()
|
|
152
|
-
|
|
153
|
-
if event['type'] == 'http.request':
|
|
154
|
-
payload += event.get('body') or b''
|
|
155
|
-
while event.get('more_body'):
|
|
156
|
-
event = await receive()
|
|
157
|
-
if event['type'] == 'http.request':
|
|
158
|
-
payload += event.get('body') or b''
|
|
159
|
-
elif event['type'] == 'websocket.connect':
|
|
160
|
-
pass
|
|
161
|
-
else:
|
|
160
|
+
if event['type'] not in ['http.request', 'websocket.connect']:
|
|
162
161
|
return {}
|
|
163
162
|
|
|
164
163
|
raw_uri = scope['path']
|
|
@@ -171,7 +170,7 @@ async def translate_request(scope, receive, send):
|
|
|
171
170
|
else:
|
|
172
171
|
raw_uri += '?' + query_string
|
|
173
172
|
environ = {
|
|
174
|
-
'wsgi.input': AwaitablePayload(
|
|
173
|
+
'wsgi.input': AwaitablePayload(event),
|
|
175
174
|
'wsgi.errors': sys.stderr,
|
|
176
175
|
'wsgi.version': (1, 0),
|
|
177
176
|
'wsgi.async': True,
|
|
@@ -462,7 +462,6 @@ class AsyncServer(base_server.BaseServer):
|
|
|
462
462
|
'maxPayload': self.max_http_buffer_size,
|
|
463
463
|
})
|
|
464
464
|
await s.send(pkt)
|
|
465
|
-
s.schedule_ping()
|
|
466
465
|
|
|
467
466
|
ret = await self._trigger_event('connect', sid, environ,
|
|
468
467
|
run_async=False)
|
|
@@ -471,6 +470,8 @@ class AsyncServer(base_server.BaseServer):
|
|
|
471
470
|
self.logger.warning('Application rejected connection')
|
|
472
471
|
return self._unauthorized(ret or None)
|
|
473
472
|
|
|
473
|
+
s.schedule_ping()
|
|
474
|
+
|
|
474
475
|
if transport == 'websocket':
|
|
475
476
|
ret = await s.handle_get_request(environ)
|
|
476
477
|
if s.closed and sid in self.sockets:
|
|
@@ -128,10 +128,12 @@ class AsyncSocket(base_socket.BaseSocket):
|
|
|
128
128
|
await self.queue.join()
|
|
129
129
|
|
|
130
130
|
def schedule_ping(self):
|
|
131
|
-
|
|
131
|
+
# only schedule a new ping if the previous ping wait cycle completed
|
|
132
|
+
if self.last_ping:
|
|
133
|
+
self.last_ping = None
|
|
134
|
+
self.server.start_background_task(self._send_ping)
|
|
132
135
|
|
|
133
136
|
async def _send_ping(self):
|
|
134
|
-
self.last_ping = None
|
|
135
137
|
await asyncio.sleep(self.server.ping_interval)
|
|
136
138
|
if not self.closing and not self.closed:
|
|
137
139
|
self.last_ping = time.time()
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import time
|
|
2
|
+
|
|
3
|
+
|
|
1
4
|
class BaseSocket:
|
|
2
5
|
upgrade_protocols = ['websocket']
|
|
3
6
|
|
|
@@ -5,7 +8,7 @@ class BaseSocket:
|
|
|
5
8
|
self.server = server
|
|
6
9
|
self.sid = sid
|
|
7
10
|
self.queue = self.server.create_queue()
|
|
8
|
-
self.last_ping =
|
|
11
|
+
self.last_ping = time.time()
|
|
9
12
|
self.connected = False
|
|
10
13
|
self.upgrading = False
|
|
11
14
|
self.upgraded = False
|
|
@@ -401,7 +401,6 @@ class Server(base_server.BaseServer):
|
|
|
401
401
|
'maxPayload': self.max_http_buffer_size,
|
|
402
402
|
})
|
|
403
403
|
s.send(pkt)
|
|
404
|
-
s.schedule_ping()
|
|
405
404
|
|
|
406
405
|
# NOTE: some sections below are marked as "no cover" to workaround
|
|
407
406
|
# what seems to be a bug in the coverage package. All the lines below
|
|
@@ -413,6 +412,8 @@ class Server(base_server.BaseServer):
|
|
|
413
412
|
self.logger.warning('Application rejected connection')
|
|
414
413
|
return self._unauthorized(ret or None)
|
|
415
414
|
|
|
415
|
+
s.schedule_ping()
|
|
416
|
+
|
|
416
417
|
if transport == 'websocket': # pragma: no cover
|
|
417
418
|
ret = s.handle_get_request(environ, start_response)
|
|
418
419
|
if s.closed and sid in self.sockets:
|
|
@@ -130,10 +130,12 @@ class Socket(base_socket.BaseSocket):
|
|
|
130
130
|
self.queue.join()
|
|
131
131
|
|
|
132
132
|
def schedule_ping(self):
|
|
133
|
-
|
|
133
|
+
# only schedule a new ping if the previous ping wait cycle completed
|
|
134
|
+
if self.last_ping:
|
|
135
|
+
self.last_ping = None
|
|
136
|
+
self.server.start_background_task(self._send_ping)
|
|
134
137
|
|
|
135
138
|
def _send_ping(self):
|
|
136
|
-
self.last_ping = None
|
|
137
139
|
self.server.sleep(self.server.ping_interval)
|
|
138
140
|
if not self.closing and not self.closed:
|
|
139
141
|
self.last_ping = time.time()
|
|
@@ -3,14 +3,6 @@ MANIFEST.in
|
|
|
3
3
|
README.md
|
|
4
4
|
pyproject.toml
|
|
5
5
|
tox.ini
|
|
6
|
-
docs/Makefile
|
|
7
|
-
docs/api.rst
|
|
8
|
-
docs/client.rst
|
|
9
|
-
docs/conf.py
|
|
10
|
-
docs/index.rst
|
|
11
|
-
docs/intro.rst
|
|
12
|
-
docs/make.bat
|
|
13
|
-
docs/server.rst
|
|
14
6
|
docs/_static/README.md
|
|
15
7
|
src/engineio/__init__.py
|
|
16
8
|
src/engineio/async_client.py
|
|
@@ -44,7 +36,6 @@ src/python_engineio.egg-info/dependency_links.txt
|
|
|
44
36
|
src/python_engineio.egg-info/not-zip-safe
|
|
45
37
|
src/python_engineio.egg-info/requires.txt
|
|
46
38
|
src/python_engineio.egg-info/top_level.txt
|
|
47
|
-
tests/__init__.py
|
|
48
39
|
tests/async/__init__.py
|
|
49
40
|
tests/async/index.html
|
|
50
41
|
tests/async/test_aiohttp.py
|
{python_engineio-4.13.1 → python_engineio-4.13.2}/src/python_engineio.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_engineio-4.13.1 → python_engineio-4.13.2}/src/python_engineio.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
@@ -95,14 +95,30 @@ class TestSocket:
|
|
|
95
95
|
s = async_socket.AsyncSocket(mock_server, 'sid')
|
|
96
96
|
s.send = mock.AsyncMock()
|
|
97
97
|
|
|
98
|
-
async def
|
|
98
|
+
async def schedule_ping_and_sleep():
|
|
99
99
|
s.schedule_ping()
|
|
100
100
|
await asyncio.sleep(0.05)
|
|
101
101
|
|
|
102
|
-
await
|
|
102
|
+
await schedule_ping_and_sleep()
|
|
103
103
|
assert s.last_ping is not None
|
|
104
104
|
assert s.send.await_args_list[0][0][0].encode() == '2'
|
|
105
105
|
|
|
106
|
+
async def test_schedule_ping_twice(self):
|
|
107
|
+
mock_server = self._get_mock_server()
|
|
108
|
+
mock_server.ping_interval = 0.01
|
|
109
|
+
s = async_socket.AsyncSocket(mock_server, 'sid')
|
|
110
|
+
s.send = mock.AsyncMock()
|
|
111
|
+
|
|
112
|
+
async def schedule_ping_and_sleep():
|
|
113
|
+
s.schedule_ping()
|
|
114
|
+
await asyncio.sleep(0.05)
|
|
115
|
+
|
|
116
|
+
s.schedule_ping()
|
|
117
|
+
assert s.last_ping is None
|
|
118
|
+
await schedule_ping_and_sleep()
|
|
119
|
+
assert s.last_ping is not None
|
|
120
|
+
assert s.send.await_count == 1
|
|
121
|
+
|
|
106
122
|
async def test_schedule_ping_closed_socket(self):
|
|
107
123
|
mock_server = self._get_mock_server()
|
|
108
124
|
mock_server.ping_interval = 0.01
|
|
@@ -21,6 +21,7 @@ class TestSocket:
|
|
|
21
21
|
mock_server.ping_interval_grace_period = 0.001
|
|
22
22
|
mock_server.async_handlers = True
|
|
23
23
|
mock_server.max_http_buffer_size = 128
|
|
24
|
+
mock_server.sleep = time.sleep
|
|
24
25
|
|
|
25
26
|
try:
|
|
26
27
|
import queue
|
|
@@ -104,6 +105,19 @@ class TestSocket:
|
|
|
104
105
|
assert s.last_ping is not None
|
|
105
106
|
assert s.send.call_args_list[0][0][0].encode() == '2'
|
|
106
107
|
|
|
108
|
+
def test_schedule_ping_twice(self):
|
|
109
|
+
mock_server = self._get_mock_server()
|
|
110
|
+
mock_server.ping_interval = 0.1
|
|
111
|
+
s = socket.Socket(mock_server, 'sid')
|
|
112
|
+
s.send = mock.MagicMock()
|
|
113
|
+
s.schedule_ping()
|
|
114
|
+
assert s.last_ping is None
|
|
115
|
+
time.sleep(0.01)
|
|
116
|
+
s.schedule_ping()
|
|
117
|
+
time.sleep(0.1)
|
|
118
|
+
assert s.last_ping is not None
|
|
119
|
+
assert s.send.call_count == 1
|
|
120
|
+
|
|
107
121
|
def test_schedule_ping_closed_socket(self):
|
|
108
122
|
mock_server = self._get_mock_server()
|
|
109
123
|
mock_server.ping_interval = 0.01
|
|
@@ -1,16 +1,3 @@
|
|
|
1
|
-
[tox]
|
|
2
|
-
envlist=flake8,py310,py311,py312,py313,py314,pypy3,docs
|
|
3
|
-
skip_missing_interpreters=True
|
|
4
|
-
|
|
5
|
-
[gh-actions]
|
|
6
|
-
python =
|
|
7
|
-
3.10: py310
|
|
8
|
-
3.11: py311
|
|
9
|
-
3.12: py312
|
|
10
|
-
3.13: py313
|
|
11
|
-
3.14: py314
|
|
12
|
-
pypy-3: pypy3
|
|
13
|
-
|
|
14
1
|
[testenv]
|
|
15
2
|
commands=
|
|
16
3
|
pip install -e .
|
|
@@ -24,8 +11,6 @@ deps=
|
|
|
24
11
|
requests
|
|
25
12
|
websocket-client
|
|
26
13
|
|
|
27
|
-
[testenv:pypy3]
|
|
28
|
-
|
|
29
14
|
[testenv:flake8]
|
|
30
15
|
deps=
|
|
31
16
|
flake8
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# Minimal makefile for Sphinx documentation
|
|
2
|
-
#
|
|
3
|
-
|
|
4
|
-
# You can set these variables from the command line.
|
|
5
|
-
SPHINXOPTS =
|
|
6
|
-
SPHINXBUILD = sphinx-build
|
|
7
|
-
SOURCEDIR = .
|
|
8
|
-
BUILDDIR = _build
|
|
9
|
-
|
|
10
|
-
# Put it first so that "make" without argument is like "make help".
|
|
11
|
-
help:
|
|
12
|
-
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
|
13
|
-
|
|
14
|
-
.PHONY: help Makefile
|
|
15
|
-
|
|
16
|
-
# Catch-all target: route all unknown targets to Sphinx using the new
|
|
17
|
-
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
|
18
|
-
%: Makefile
|
|
19
|
-
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
The Engine.IO Client
|
|
2
|
-
====================
|
|
3
|
-
|
|
4
|
-
This package contains two Engine.IO clients:
|
|
5
|
-
|
|
6
|
-
- The :func:`engineio.Client` class creates a client compatible with the
|
|
7
|
-
standard Python library.
|
|
8
|
-
- The :func:`engineio.AsyncClient` class creates a client compatible with
|
|
9
|
-
the ``asyncio`` package.
|
|
10
|
-
|
|
11
|
-
The methods in the two clients are the same, with the only difference that in
|
|
12
|
-
the ``asyncio`` client most methods are implemented as coroutines.
|
|
13
|
-
|
|
14
|
-
Installation
|
|
15
|
-
------------
|
|
16
|
-
|
|
17
|
-
To install the standard Python client along with its dependencies, use the
|
|
18
|
-
following command::
|
|
19
|
-
|
|
20
|
-
pip install "python-engineio[client]"
|
|
21
|
-
|
|
22
|
-
If instead you plan on using the ``asyncio`` client, then use this::
|
|
23
|
-
|
|
24
|
-
pip install "python-engineio[asyncio_client]"
|
|
25
|
-
|
|
26
|
-
Creating a Client Instance
|
|
27
|
-
--------------------------
|
|
28
|
-
|
|
29
|
-
To instantiate an Engine.IO client, simply create an instance of the
|
|
30
|
-
appropriate client class::
|
|
31
|
-
|
|
32
|
-
import engineio
|
|
33
|
-
|
|
34
|
-
# standard Python
|
|
35
|
-
eio = engineio.Client()
|
|
36
|
-
|
|
37
|
-
# asyncio
|
|
38
|
-
eio = engineio.AsyncClient()
|
|
39
|
-
|
|
40
|
-
Defining Event Handlers
|
|
41
|
-
-----------------------
|
|
42
|
-
|
|
43
|
-
To responds to events triggered by the connection or the server, event Handler
|
|
44
|
-
functions must be defined using the ``on`` decorator::
|
|
45
|
-
|
|
46
|
-
@eio.on('connect')
|
|
47
|
-
def on_connect():
|
|
48
|
-
print('I'm connected!')
|
|
49
|
-
|
|
50
|
-
@eio.on('message')
|
|
51
|
-
def on_message(data):
|
|
52
|
-
print('I received a message!')
|
|
53
|
-
|
|
54
|
-
@eio.on('disconnect')
|
|
55
|
-
def on_disconnect(reason):
|
|
56
|
-
print('I'm disconnected! reason:', reason)
|
|
57
|
-
|
|
58
|
-
For the ``asyncio`` server, event handlers can be regular functions as above,
|
|
59
|
-
or can also be coroutines::
|
|
60
|
-
|
|
61
|
-
@eio.on('message')
|
|
62
|
-
async def on_message(data):
|
|
63
|
-
print('I received a message!')
|
|
64
|
-
|
|
65
|
-
The argument given to the ``on`` decorator is the event name. The events that
|
|
66
|
-
are supported are ``connect``, ``message`` and ``disconnect``.
|
|
67
|
-
|
|
68
|
-
The ``data`` argument passed to the ``'message'`` event handler contains
|
|
69
|
-
application-specific data provided by the server with the event.
|
|
70
|
-
|
|
71
|
-
The ``disconnect`` handler is invoked for client initiated disconnects, server
|
|
72
|
-
initiated disconnects, or accidental disconnects, for example due to
|
|
73
|
-
networking failures. The argument passed to this handler provides the
|
|
74
|
-
disconnect reason. Example::
|
|
75
|
-
|
|
76
|
-
@eio.on('disconnect')
|
|
77
|
-
def on_disconnect(reason):
|
|
78
|
-
if reason == eio.reason.CLIENT_DISCONNECT:
|
|
79
|
-
print('client disconnection')
|
|
80
|
-
elif reason == eio.reason.SERVER_DISCONNECT:
|
|
81
|
-
print('the server kicked me out')
|
|
82
|
-
else:
|
|
83
|
-
print(f'disconnect reason: {reason}')
|
|
84
|
-
|
|
85
|
-
Connecting to a Server
|
|
86
|
-
----------------------
|
|
87
|
-
|
|
88
|
-
The connection to a server is established by calling the ``connect()``
|
|
89
|
-
method::
|
|
90
|
-
|
|
91
|
-
eio.connect('http://localhost:5000')
|
|
92
|
-
|
|
93
|
-
In the case of the ``asyncio`` client, the method is a coroutine::
|
|
94
|
-
|
|
95
|
-
await eio.connect('http://localhost:5000')
|
|
96
|
-
|
|
97
|
-
Upon connection, the server assigns the client a unique session identifier.
|
|
98
|
-
The applicaction can find this identifier in the ``sid`` attribute::
|
|
99
|
-
|
|
100
|
-
print('my sid is', eio.sid)
|
|
101
|
-
|
|
102
|
-
Sending Messages
|
|
103
|
-
----------------
|
|
104
|
-
|
|
105
|
-
The client can send a message to the server using the ``send()`` method::
|
|
106
|
-
|
|
107
|
-
eio.send({'foo': 'bar'})
|
|
108
|
-
|
|
109
|
-
Or in the case of ``asyncio``, as a coroutine::
|
|
110
|
-
|
|
111
|
-
await eio.send({'foo': 'bar'})
|
|
112
|
-
|
|
113
|
-
The single argument provided to the method is the data that is passed on
|
|
114
|
-
to the server. The data can be of type ``str``, ``bytes``, ``dict`` or
|
|
115
|
-
``list``. The data included inside dictionaries and lists is also
|
|
116
|
-
constrained to these types.
|
|
117
|
-
|
|
118
|
-
The ``send()`` method can be invoked inside an event handler as a response
|
|
119
|
-
to a server event, or in any other part of the application, including in
|
|
120
|
-
background tasks.
|
|
121
|
-
|
|
122
|
-
Disconnecting from the Server
|
|
123
|
-
-----------------------------
|
|
124
|
-
|
|
125
|
-
At any time the client can request to be disconnected from the server by
|
|
126
|
-
invoking the ``disconnect()`` method::
|
|
127
|
-
|
|
128
|
-
eio.disconnect()
|
|
129
|
-
|
|
130
|
-
For the ``asyncio`` client this is a coroutine::
|
|
131
|
-
|
|
132
|
-
await eio.disconnect()
|
|
133
|
-
|
|
134
|
-
Managing Background Tasks
|
|
135
|
-
-------------------------
|
|
136
|
-
|
|
137
|
-
When a client connection to the server is established, a few background
|
|
138
|
-
tasks will be spawned to keep the connection alive and handle incoming
|
|
139
|
-
events. The application running on the main thread is free to do any
|
|
140
|
-
work, as this is not going to prevent the functioning of the Engine.IO
|
|
141
|
-
client.
|
|
142
|
-
|
|
143
|
-
If the application does not have anything to do in the main thread and
|
|
144
|
-
just wants to wait until the connection ends, it can call the ``wait()``
|
|
145
|
-
method::
|
|
146
|
-
|
|
147
|
-
eio.wait()
|
|
148
|
-
|
|
149
|
-
Or in the ``asyncio`` version::
|
|
150
|
-
|
|
151
|
-
await eio.wait()
|
|
152
|
-
|
|
153
|
-
For the convenience of the application, a helper function is
|
|
154
|
-
provided to start a custom background task::
|
|
155
|
-
|
|
156
|
-
def my_background_task(my_argument)
|
|
157
|
-
# do some background work here!
|
|
158
|
-
pass
|
|
159
|
-
|
|
160
|
-
eio.start_background_task(my_background_task, 123)
|
|
161
|
-
|
|
162
|
-
The arguments passed to this method are the background function and any
|
|
163
|
-
positional or keyword arguments to invoke the function with.
|
|
164
|
-
|
|
165
|
-
Here is the ``asyncio`` version::
|
|
166
|
-
|
|
167
|
-
async def my_background_task(my_argument)
|
|
168
|
-
# do some background work here!
|
|
169
|
-
pass
|
|
170
|
-
|
|
171
|
-
eio.start_background_task(my_background_task, 123)
|
|
172
|
-
|
|
173
|
-
Note that this function is not a coroutine, since it does not wait for the
|
|
174
|
-
background function to end, but the background function is.
|
|
175
|
-
|
|
176
|
-
The ``sleep()`` method is a second convenience function that is provided for
|
|
177
|
-
the benefit of applications working with background tasks of their own::
|
|
178
|
-
|
|
179
|
-
eio.sleep(2)
|
|
180
|
-
|
|
181
|
-
Or for ``asyncio``::
|
|
182
|
-
|
|
183
|
-
await eio.sleep(2)
|
|
184
|
-
|
|
185
|
-
The single argument passed to the method is the number of seconds to sleep
|
|
186
|
-
for.
|
|
187
|
-
|
|
188
|
-
Debugging and Troubleshooting
|
|
189
|
-
-----------------------------
|
|
190
|
-
|
|
191
|
-
To help you debug issues, the client can be configured to output logs to the
|
|
192
|
-
terminal::
|
|
193
|
-
|
|
194
|
-
import engineio
|
|
195
|
-
|
|
196
|
-
# standard Python
|
|
197
|
-
eio = engineio.Client(logger=True)
|
|
198
|
-
|
|
199
|
-
# asyncio
|
|
200
|
-
eio = engineio.AsyncClient(logger=True)
|
|
201
|
-
|
|
202
|
-
The ``logger`` argument controls logging behavior:
|
|
203
|
-
|
|
204
|
-
* ``True``: Enables log output to ``stderr`` at the ``INFO`` level.
|
|
205
|
-
* ``False``: Enables log output to ``stderr`` at the ``ERROR`` level. This is
|
|
206
|
-
the default.
|
|
207
|
-
* A ``logging.Logger`` instance: Uses the provided logger without additional
|
|
208
|
-
configuration.
|
|
209
|
-
|
|
210
|
-
Logging can help identify the cause of connection problems, unexpected
|
|
211
|
-
disconnections and other issues.
|