slim-bindings 0.5.0__cp313-cp313-win_amd64.whl → 0.6.0__cp313-cp313-win_amd64.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.
Potentially problematic release.
This version of slim-bindings might be problematic. Click here for more details.
- slim_bindings/__init__.py +53 -688
- slim_bindings/_slim_bindings.cp313-win_amd64.pyd +0 -0
- slim_bindings/_slim_bindings.pyi +353 -38
- slim_bindings/errors.py +53 -0
- slim_bindings/session.py +219 -0
- slim_bindings/slim.py +383 -0
- slim_bindings/version.py +38 -0
- slim_bindings-0.6.0.dist-info/METADATA +233 -0
- slim_bindings-0.6.0.dist-info/RECORD +10 -0
- slim_bindings-0.5.0.dist-info/METADATA +0 -61
- slim_bindings-0.5.0.dist-info/RECORD +0 -6
- {slim_bindings-0.5.0.dist-info → slim_bindings-0.6.0.dist-info}/WHEEL +0 -0
slim_bindings/__init__.py
CHANGED
|
@@ -1,712 +1,77 @@
|
|
|
1
1
|
# Copyright AGNTCY Contributors (https://github.com/agntcy)
|
|
2
2
|
# SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
from typing import Optional
|
|
7
|
-
|
|
8
|
-
from ._slim_bindings import ( # type: ignore[attr-defined]
|
|
9
|
-
SESSION_UNSPECIFIED,
|
|
4
|
+
from slim_bindings._slim_bindings import (
|
|
5
|
+
PyAlgorithm,
|
|
10
6
|
PyIdentityProvider,
|
|
11
7
|
PyIdentityVerifier,
|
|
8
|
+
PyKey,
|
|
9
|
+
PyKeyData,
|
|
10
|
+
PyKeyFormat,
|
|
12
11
|
PyName,
|
|
13
12
|
PyService,
|
|
14
13
|
PySessionConfiguration,
|
|
15
|
-
|
|
14
|
+
PySessionContext,
|
|
16
15
|
PySessionType,
|
|
17
|
-
__version__,
|
|
18
|
-
build_info,
|
|
19
|
-
build_profile,
|
|
20
16
|
connect,
|
|
21
17
|
create_pyservice,
|
|
22
18
|
create_session,
|
|
23
19
|
delete_session,
|
|
24
20
|
disconnect,
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
get_message,
|
|
22
|
+
init_tracing,
|
|
27
23
|
invite,
|
|
24
|
+
listen_for_session,
|
|
28
25
|
publish,
|
|
29
|
-
|
|
26
|
+
remove,
|
|
30
27
|
remove_route,
|
|
31
28
|
run_server,
|
|
32
29
|
set_default_session_config,
|
|
33
30
|
set_route,
|
|
34
|
-
set_session_config,
|
|
35
31
|
stop_server,
|
|
36
32
|
subscribe,
|
|
37
33
|
unsubscribe,
|
|
38
34
|
)
|
|
39
|
-
from .
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
from .
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
init_tracing
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
""
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
""
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
""
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
""
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
""
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
Returns:
|
|
84
|
-
str: The build information of the SLIM bindings.
|
|
85
|
-
"""
|
|
86
|
-
return build_info
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
class SLIMTimeoutError(TimeoutError):
|
|
90
|
-
"""
|
|
91
|
-
Exception raised for SLIM timeout errors.
|
|
92
|
-
|
|
93
|
-
This exception is raised when an operation in an SLIM session times out.
|
|
94
|
-
It encapsulates detailed information about the timeout event, including the
|
|
95
|
-
ID of the message that caused the timeout and the session identifier. An
|
|
96
|
-
optional underlying exception can also be provided to offer additional context.
|
|
97
|
-
|
|
98
|
-
Attributes:
|
|
99
|
-
message_id (int): The identifier associated with the message triggering the timeout.
|
|
100
|
-
session_id (int): The identifier of the session where the timeout occurred.
|
|
101
|
-
message (str): A brief description of the timeout error.
|
|
102
|
-
original_exception (Exception, optional): The underlying exception that caused the timeout, if any.
|
|
103
|
-
|
|
104
|
-
The string representation of the exception (via __str__) returns a full message that
|
|
105
|
-
includes the custom message, session ID, and message ID, as well as details of the
|
|
106
|
-
original exception (if present). This provides a richer context when the exception is logged
|
|
107
|
-
or printed.
|
|
108
|
-
"""
|
|
109
|
-
|
|
110
|
-
def __init__(
|
|
111
|
-
self,
|
|
112
|
-
message_id: int,
|
|
113
|
-
session_id: int,
|
|
114
|
-
message: str = "SLIM timeout error",
|
|
115
|
-
original_exception: Optional[Exception] = None,
|
|
116
|
-
):
|
|
117
|
-
self.message_id = message_id
|
|
118
|
-
self.session_id = session_id
|
|
119
|
-
self.message = message
|
|
120
|
-
self.original_exception = original_exception
|
|
121
|
-
full_message = f"{message} for session {session_id} and message {message_id}"
|
|
122
|
-
if original_exception:
|
|
123
|
-
full_message = f"{full_message}. Caused by: {original_exception!r}"
|
|
124
|
-
super().__init__(full_message)
|
|
125
|
-
|
|
126
|
-
def __str__(self):
|
|
127
|
-
return self.args[0]
|
|
128
|
-
|
|
129
|
-
def __repr__(self):
|
|
130
|
-
return (
|
|
131
|
-
f"{self.__class__.__name__}(session_id={self.session_id!r}, "
|
|
132
|
-
f"message_id={self.message_id!r}, "
|
|
133
|
-
f"message={self.message!r}, original_exception={self.original_exception!r})"
|
|
134
|
-
)
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
class Slim:
|
|
138
|
-
def __init__(
|
|
139
|
-
self,
|
|
140
|
-
svc: PyService,
|
|
141
|
-
name: PyName,
|
|
142
|
-
):
|
|
143
|
-
"""
|
|
144
|
-
Initialize a new SLIM instance. A SLIM instance is associated with a single
|
|
145
|
-
local app. The app is identified by its organization, namespace, and name.
|
|
146
|
-
The unique ID is determined by the provided service (svc).
|
|
147
|
-
|
|
148
|
-
Args:
|
|
149
|
-
svc (PyService): The Python service instance for SLIM.
|
|
150
|
-
organization (str): The organization of the app.
|
|
151
|
-
namespace (str): The namespace of the app.
|
|
152
|
-
app (str): The name of the app.
|
|
153
|
-
"""
|
|
154
|
-
|
|
155
|
-
# Initialize service
|
|
156
|
-
self.svc = svc
|
|
157
|
-
|
|
158
|
-
# Create sessions map
|
|
159
|
-
self.sessions: dict[int, tuple[Optional[PySessionInfo], asyncio.Queue]] = {
|
|
160
|
-
SESSION_UNSPECIFIED: (None, asyncio.Queue()),
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
# Save local names
|
|
164
|
-
name.id = svc.id
|
|
165
|
-
self.local_name = name
|
|
166
|
-
|
|
167
|
-
# Create connection ID map
|
|
168
|
-
self.conn_ids: dict[str, int] = {}
|
|
169
|
-
|
|
170
|
-
async def __aenter__(self):
|
|
171
|
-
"""
|
|
172
|
-
Start the receiver loop in the background.
|
|
173
|
-
This function is called when the SLIM instance is used in a
|
|
174
|
-
context manager (with statement).
|
|
175
|
-
It will start the receiver loop in the background and return the
|
|
176
|
-
SLIM instance.
|
|
177
|
-
Args:
|
|
178
|
-
None
|
|
179
|
-
Returns:
|
|
180
|
-
Slim: The SLIM instance.
|
|
181
|
-
|
|
182
|
-
"""
|
|
183
|
-
|
|
184
|
-
# Run receiver loop in the background
|
|
185
|
-
self.task = asyncio.create_task(self._receive_loop())
|
|
186
|
-
return self
|
|
187
|
-
|
|
188
|
-
async def __aexit__(self, exc_type, exc_value, traceback):
|
|
189
|
-
"""
|
|
190
|
-
Stop the receiver loop.
|
|
191
|
-
This function is called when the Slim instance is used in a
|
|
192
|
-
context manager (with statement).
|
|
193
|
-
It will stop the receiver loop and wait for it to finish.
|
|
194
|
-
Args:
|
|
195
|
-
exc_type: The exception type.
|
|
196
|
-
exc_value: The exception value.
|
|
197
|
-
traceback: The traceback object.
|
|
198
|
-
Returns:
|
|
199
|
-
None
|
|
200
|
-
"""
|
|
201
|
-
|
|
202
|
-
# Cancel the receiver loop task
|
|
203
|
-
self.task.cancel()
|
|
204
|
-
|
|
205
|
-
# Wait for the task to finish
|
|
206
|
-
try:
|
|
207
|
-
await self.task
|
|
208
|
-
except asyncio.CancelledError:
|
|
209
|
-
pass
|
|
210
|
-
|
|
211
|
-
@classmethod
|
|
212
|
-
async def new(
|
|
213
|
-
cls,
|
|
214
|
-
name: PyName,
|
|
215
|
-
provider: PyIdentityProvider,
|
|
216
|
-
verifier: PyIdentityVerifier,
|
|
217
|
-
) -> "Slim":
|
|
218
|
-
"""
|
|
219
|
-
Create a new SLIM instance. A SLIM instance is associated to one single
|
|
220
|
-
local app. The app is identified by its organization, namespace and name.
|
|
221
|
-
The app ID is optional. If not provided, the app will be created with a new ID.
|
|
222
|
-
|
|
223
|
-
Args:
|
|
224
|
-
organization (str): The organization of the app.
|
|
225
|
-
namespace (str): The namespace of the app.
|
|
226
|
-
app (str): The name of the app.
|
|
227
|
-
app_id (int): The ID of the app. If not provided, a new ID will be created.
|
|
228
|
-
|
|
229
|
-
Returns:
|
|
230
|
-
Slim: A new SLIM instance
|
|
231
|
-
"""
|
|
232
|
-
|
|
233
|
-
return cls(
|
|
234
|
-
await create_pyservice(name, provider, verifier),
|
|
235
|
-
name,
|
|
236
|
-
)
|
|
237
|
-
|
|
238
|
-
def get_id(self) -> int:
|
|
239
|
-
"""
|
|
240
|
-
Get the ID of the app.
|
|
241
|
-
|
|
242
|
-
Args:
|
|
243
|
-
None
|
|
244
|
-
|
|
245
|
-
Returns:
|
|
246
|
-
int: The ID of the app.
|
|
247
|
-
"""
|
|
248
|
-
|
|
249
|
-
return self.svc.id
|
|
250
|
-
|
|
251
|
-
async def create_session(
|
|
252
|
-
self,
|
|
253
|
-
session_config: PySessionConfiguration,
|
|
254
|
-
queue_size: int = 0,
|
|
255
|
-
) -> PySessionInfo:
|
|
256
|
-
"""
|
|
257
|
-
Create a new streaming session.
|
|
258
|
-
|
|
259
|
-
Args:
|
|
260
|
-
session_config (PySessionConfiguration): The session configuration.
|
|
261
|
-
queue_size (int): The size of the queue for the session.
|
|
262
|
-
If 0, the queue will be unbounded.
|
|
263
|
-
If a positive integer, the queue will be bounded to that size.
|
|
264
|
-
|
|
265
|
-
Returns:
|
|
266
|
-
ID of the session
|
|
267
|
-
"""
|
|
268
|
-
|
|
269
|
-
session = await create_session(self.svc, session_config)
|
|
270
|
-
self.sessions[session.id] = (session, asyncio.Queue(queue_size))
|
|
271
|
-
return session
|
|
272
|
-
|
|
273
|
-
async def delete_session(self, session_id: int):
|
|
274
|
-
"""
|
|
275
|
-
Delete a session.
|
|
276
|
-
|
|
277
|
-
Args:
|
|
278
|
-
session_id (int): The ID of the session to delete.
|
|
279
|
-
|
|
280
|
-
Returns:
|
|
281
|
-
None
|
|
282
|
-
|
|
283
|
-
Raises:
|
|
284
|
-
ValueError: If the session ID is not found.
|
|
285
|
-
"""
|
|
286
|
-
|
|
287
|
-
# Check if the session ID is in the sessions map
|
|
288
|
-
if session_id not in self.sessions:
|
|
289
|
-
raise ValueError(f"session not found: {session_id}")
|
|
290
|
-
|
|
291
|
-
# Remove the session from the map
|
|
292
|
-
del self.sessions[session_id]
|
|
293
|
-
|
|
294
|
-
# Remove the session from SLIM
|
|
295
|
-
await delete_session(self.svc, session_id)
|
|
296
|
-
|
|
297
|
-
async def set_session_config(
|
|
298
|
-
self,
|
|
299
|
-
session_id: int,
|
|
300
|
-
session_config: PySessionConfiguration,
|
|
301
|
-
):
|
|
302
|
-
"""
|
|
303
|
-
Set the session configuration for a specific session.
|
|
304
|
-
|
|
305
|
-
Args:
|
|
306
|
-
session_id (int): The ID of the session.
|
|
307
|
-
session_config (PySessionConfiguration): The new configuration for the session.
|
|
308
|
-
|
|
309
|
-
Returns:
|
|
310
|
-
None
|
|
311
|
-
|
|
312
|
-
Raises:
|
|
313
|
-
ValueError: If the session ID is not found.
|
|
314
|
-
"""
|
|
315
|
-
|
|
316
|
-
# Check if the session ID is in the sessions map
|
|
317
|
-
if session_id not in self.sessions:
|
|
318
|
-
raise ValueError(f"session not found: {session_id}")
|
|
319
|
-
|
|
320
|
-
# Set the session configuration
|
|
321
|
-
await set_session_config(self.svc, session_id, session_config)
|
|
322
|
-
|
|
323
|
-
async def get_session_config(
|
|
324
|
-
self,
|
|
325
|
-
session_id: int,
|
|
326
|
-
) -> PySessionConfiguration:
|
|
327
|
-
"""
|
|
328
|
-
Get the session configuration for a specific session.
|
|
329
|
-
|
|
330
|
-
Args:
|
|
331
|
-
session_id (int): The ID of the session.
|
|
332
|
-
|
|
333
|
-
Returns:
|
|
334
|
-
PySessionConfiguration: The configuration of the session.
|
|
335
|
-
|
|
336
|
-
Raises:
|
|
337
|
-
ValueError: If the session ID is not found.
|
|
338
|
-
"""
|
|
339
|
-
|
|
340
|
-
# Check if the session ID is in the sessions map
|
|
341
|
-
if session_id not in self.sessions:
|
|
342
|
-
raise ValueError(f"session not found: {session_id}")
|
|
343
|
-
|
|
344
|
-
# Get the session configuration
|
|
345
|
-
return await get_session_config(self.svc, session_id)
|
|
346
|
-
|
|
347
|
-
async def set_default_session_config(
|
|
348
|
-
self,
|
|
349
|
-
session_config: PySessionConfiguration,
|
|
350
|
-
):
|
|
351
|
-
"""
|
|
352
|
-
Set the default session configuration.
|
|
353
|
-
|
|
354
|
-
Args:
|
|
355
|
-
session_config (PySessionConfiguration): The new default session configuration.
|
|
356
|
-
|
|
357
|
-
Returns:
|
|
358
|
-
None
|
|
359
|
-
"""
|
|
360
|
-
|
|
361
|
-
await set_default_session_config(self.svc, session_config)
|
|
362
|
-
|
|
363
|
-
async def get_default_session_config(
|
|
364
|
-
self,
|
|
365
|
-
session_type: PySessionType,
|
|
366
|
-
) -> PySessionConfiguration:
|
|
367
|
-
"""
|
|
368
|
-
Get the default session configuration.
|
|
369
|
-
|
|
370
|
-
Args:
|
|
371
|
-
session_id (int): The ID of the session.
|
|
372
|
-
|
|
373
|
-
Returns:
|
|
374
|
-
PySessionConfiguration: The default configuration of the session.
|
|
375
|
-
"""
|
|
376
|
-
|
|
377
|
-
return await get_default_session_config(self.svc, session_type)
|
|
378
|
-
|
|
379
|
-
async def run_server(self, config: dict):
|
|
380
|
-
"""
|
|
381
|
-
Start the server part of the SLIM service. The server will be started only
|
|
382
|
-
if its configuration is set. Otherwise, it will raise an error.
|
|
383
|
-
|
|
384
|
-
Args:
|
|
385
|
-
None
|
|
386
|
-
|
|
387
|
-
Returns:
|
|
388
|
-
None
|
|
389
|
-
"""
|
|
390
|
-
|
|
391
|
-
await run_server(self.svc, config)
|
|
392
|
-
|
|
393
|
-
async def stop_server(self, endpoint: str):
|
|
394
|
-
"""
|
|
395
|
-
Stop the server part of the SLIM service.
|
|
396
|
-
|
|
397
|
-
Args:
|
|
398
|
-
None
|
|
399
|
-
|
|
400
|
-
Returns:
|
|
401
|
-
None
|
|
402
|
-
"""
|
|
403
|
-
|
|
404
|
-
await stop_server(self.svc, endpoint)
|
|
405
|
-
|
|
406
|
-
async def connect(self, client_config: dict) -> int:
|
|
407
|
-
"""
|
|
408
|
-
Connect to a remote SLIM service.
|
|
409
|
-
This function will block until the connection is established.
|
|
410
|
-
|
|
411
|
-
Args:
|
|
412
|
-
None
|
|
413
|
-
|
|
414
|
-
Returns:
|
|
415
|
-
int: The connection ID.
|
|
416
|
-
"""
|
|
417
|
-
|
|
418
|
-
conn_id = await connect(
|
|
419
|
-
self.svc,
|
|
420
|
-
client_config,
|
|
421
|
-
)
|
|
422
|
-
|
|
423
|
-
# Save the connection ID
|
|
424
|
-
self.conn_ids[client_config["endpoint"]] = conn_id
|
|
425
|
-
|
|
426
|
-
# For the moment we manage one connection only
|
|
427
|
-
self.conn_id = conn_id
|
|
428
|
-
|
|
429
|
-
# Subscribe to the local name
|
|
430
|
-
await subscribe(self.svc, conn_id, self.local_name)
|
|
431
|
-
|
|
432
|
-
# return the connection ID
|
|
433
|
-
return conn_id
|
|
434
|
-
|
|
435
|
-
async def disconnect(self, endpoint: str):
|
|
436
|
-
"""
|
|
437
|
-
Disconnect from a remote SLIM service.
|
|
438
|
-
This function will block until the disconnection is complete.
|
|
439
|
-
|
|
440
|
-
Args:
|
|
441
|
-
None
|
|
442
|
-
|
|
443
|
-
Returns:
|
|
444
|
-
None
|
|
445
|
-
|
|
446
|
-
"""
|
|
447
|
-
conn = self.conn_ids[endpoint]
|
|
448
|
-
await disconnect(self.svc, conn)
|
|
449
|
-
|
|
450
|
-
async def set_route(
|
|
451
|
-
self,
|
|
452
|
-
name: PyName,
|
|
453
|
-
):
|
|
454
|
-
"""
|
|
455
|
-
Set route for outgoing messages via the connected SLIM instance.
|
|
456
|
-
|
|
457
|
-
Args:
|
|
458
|
-
name (PyName): The name of the app or channel to route messages to.
|
|
459
|
-
|
|
460
|
-
Returns:
|
|
461
|
-
None
|
|
462
|
-
"""
|
|
463
|
-
|
|
464
|
-
await set_route(self.svc, self.conn_id, name)
|
|
465
|
-
|
|
466
|
-
async def remove_route(
|
|
467
|
-
self,
|
|
468
|
-
name: PyName,
|
|
469
|
-
):
|
|
470
|
-
"""
|
|
471
|
-
Remove route for outgoing messages via the connected SLIM instance.
|
|
472
|
-
|
|
473
|
-
Args:
|
|
474
|
-
name (PyName): The name of the app or channel to remove the route for.
|
|
475
|
-
|
|
476
|
-
Returns:
|
|
477
|
-
None
|
|
478
|
-
"""
|
|
479
|
-
|
|
480
|
-
await remove_route(self.svc, self.conn_id, name)
|
|
481
|
-
|
|
482
|
-
async def subscribe(self, name: PyName):
|
|
483
|
-
"""
|
|
484
|
-
Subscribe to receive messages for the given name.
|
|
485
|
-
|
|
486
|
-
Args:
|
|
487
|
-
name (PyName): The name to subscribe to. This can be an app or a channel.
|
|
488
|
-
|
|
489
|
-
Returns:
|
|
490
|
-
None
|
|
491
|
-
"""
|
|
492
|
-
|
|
493
|
-
await subscribe(self.svc, self.conn_id, name)
|
|
494
|
-
|
|
495
|
-
async def unsubscribe(self, name: PyName):
|
|
496
|
-
"""
|
|
497
|
-
Unsubscribe from receiving messages for the given name.
|
|
498
|
-
|
|
499
|
-
Args:
|
|
500
|
-
name (PyName): The name to unsubscribe from. This can be an app or a channel.
|
|
501
|
-
|
|
502
|
-
Returns:
|
|
503
|
-
None
|
|
504
|
-
"""
|
|
505
|
-
|
|
506
|
-
await unsubscribe(self.svc, self.conn_id, name)
|
|
507
|
-
|
|
508
|
-
async def publish(
|
|
509
|
-
self,
|
|
510
|
-
session: PySessionInfo,
|
|
511
|
-
msg: bytes,
|
|
512
|
-
dest: PyName,
|
|
513
|
-
payload_type: Optional[str] = None,
|
|
514
|
-
metadata: Optional[dict] = None,
|
|
515
|
-
):
|
|
516
|
-
"""
|
|
517
|
-
Publish a message to an app or channel via normal matching in subscription table.
|
|
518
|
-
|
|
519
|
-
Args:
|
|
520
|
-
session (PySessionInfo): The session information.
|
|
521
|
-
msg (str): The message to publish.
|
|
522
|
-
dest (PyName): The destination name to publish the message to.
|
|
523
|
-
payload_type (str): The type of the message payload (optional)
|
|
524
|
-
metadata (dict): The metadata associated to the message (optional)
|
|
525
|
-
|
|
526
|
-
Returns:
|
|
527
|
-
None
|
|
528
|
-
"""
|
|
529
|
-
|
|
530
|
-
# Make sure the sessions exists
|
|
531
|
-
if session.id not in self.sessions:
|
|
532
|
-
raise Exception("session not found", session.id)
|
|
533
|
-
|
|
534
|
-
await publish(self.svc, session, 1, msg, dest, payload_type, metadata)
|
|
535
|
-
|
|
536
|
-
async def invite(
|
|
537
|
-
self,
|
|
538
|
-
session: PySessionInfo,
|
|
539
|
-
name: PyName,
|
|
540
|
-
):
|
|
541
|
-
# Make sure the sessions exists
|
|
542
|
-
if session.id not in self.sessions:
|
|
543
|
-
raise Exception("session not found", session.id)
|
|
544
|
-
|
|
545
|
-
await invite(self.svc, session, name)
|
|
546
|
-
|
|
547
|
-
async def request_reply(
|
|
548
|
-
self,
|
|
549
|
-
session: PySessionInfo,
|
|
550
|
-
msg: bytes,
|
|
551
|
-
dest: PyName,
|
|
552
|
-
timeout: Optional[datetime.timedelta] = None,
|
|
553
|
-
) -> tuple[PySessionInfo, Optional[bytes]]:
|
|
554
|
-
"""
|
|
555
|
-
Publish a message and wait for the first response.
|
|
556
|
-
|
|
557
|
-
Args:
|
|
558
|
-
session (PySessionInfo): The session information.
|
|
559
|
-
msg (str): The message to publish.
|
|
560
|
-
dest (PyName): The destination name to publish the message to.
|
|
561
|
-
|
|
562
|
-
Returns:
|
|
563
|
-
tuple: The PySessionInfo and the message.
|
|
564
|
-
"""
|
|
565
|
-
|
|
566
|
-
# Make sure the sessions exists
|
|
567
|
-
if session.id not in self.sessions:
|
|
568
|
-
raise Exception("Session ID not found")
|
|
569
|
-
|
|
570
|
-
await publish(self.svc, session, 1, msg, dest)
|
|
571
|
-
|
|
572
|
-
# Wait for a reply in the corresponding session queue with timeout
|
|
573
|
-
if timeout is not None:
|
|
574
|
-
session_info, message = await asyncio.wait_for(
|
|
575
|
-
self.receive(session.id), timeout=timeout.total_seconds()
|
|
576
|
-
)
|
|
577
|
-
else:
|
|
578
|
-
session_info, message = await self.receive(session.id)
|
|
579
|
-
|
|
580
|
-
return session_info, message
|
|
581
|
-
|
|
582
|
-
async def publish_to(
|
|
583
|
-
self,
|
|
584
|
-
session: PySessionInfo,
|
|
585
|
-
msg: bytes,
|
|
586
|
-
payload_type: Optional[str] = None,
|
|
587
|
-
metadata: Optional[dict] = None,
|
|
588
|
-
):
|
|
589
|
-
"""
|
|
590
|
-
Publish a message back to the application that sent it.
|
|
591
|
-
The information regarding the source app is stored in the session.
|
|
592
|
-
|
|
593
|
-
Args:
|
|
594
|
-
session (PySessionInfo): The session information.
|
|
595
|
-
msg (str): The message to publish.
|
|
596
|
-
|
|
597
|
-
Returns:
|
|
598
|
-
None
|
|
599
|
-
"""
|
|
600
|
-
|
|
601
|
-
await publish(
|
|
602
|
-
self.svc, session, 1, msg, payload_type=payload_type, metadata=metadata
|
|
603
|
-
)
|
|
604
|
-
|
|
605
|
-
async def receive(
|
|
606
|
-
self, session: Optional[int] = None
|
|
607
|
-
) -> tuple[PySessionInfo, Optional[bytes]]:
|
|
608
|
-
"""
|
|
609
|
-
Receive a message , optionally waiting for a specific session ID.
|
|
610
|
-
If session ID is None, it will wait for new sessions to be created.
|
|
611
|
-
This function will block until a message is received (if the session id is specified)
|
|
612
|
-
or until a new session is created (if the session id is None).
|
|
613
|
-
|
|
614
|
-
Args:
|
|
615
|
-
session (int): The session ID. If None, the function will wait for any message.
|
|
616
|
-
|
|
617
|
-
Returns:
|
|
618
|
-
tuple: The PySessionInfo and the message.
|
|
619
|
-
|
|
620
|
-
Raise:
|
|
621
|
-
Exception: If the session ID is not found.
|
|
622
|
-
"""
|
|
623
|
-
|
|
624
|
-
# If session is None, wait for any message
|
|
625
|
-
if session is None:
|
|
626
|
-
return await self.sessions[SESSION_UNSPECIFIED][1].get()
|
|
627
|
-
else:
|
|
628
|
-
# Check if the session ID is in the sessions map
|
|
629
|
-
if session not in self.sessions:
|
|
630
|
-
raise Exception(f"Session ID not found: {session}")
|
|
631
|
-
|
|
632
|
-
# Get the queue for the session
|
|
633
|
-
queue = self.sessions[session][1]
|
|
634
|
-
|
|
635
|
-
# Wait for a message from the queue
|
|
636
|
-
ret = await queue.get()
|
|
637
|
-
|
|
638
|
-
# If message is am exception, raise it
|
|
639
|
-
if isinstance(ret, Exception):
|
|
640
|
-
raise ret
|
|
641
|
-
|
|
642
|
-
# Otherwise, return the message
|
|
643
|
-
return ret
|
|
644
|
-
|
|
645
|
-
async def _receive_loop(self) -> None:
|
|
646
|
-
"""
|
|
647
|
-
Receive messages in a loop running in the background.
|
|
648
|
-
|
|
649
|
-
Returns:
|
|
650
|
-
None
|
|
651
|
-
"""
|
|
652
|
-
|
|
653
|
-
while True:
|
|
654
|
-
try:
|
|
655
|
-
session_info_msg = await receive(self.svc)
|
|
656
|
-
|
|
657
|
-
id: int = session_info_msg[0].id
|
|
658
|
-
|
|
659
|
-
# Check if the session ID is in the sessions map
|
|
660
|
-
if id not in self.sessions:
|
|
661
|
-
# Create the entry in the sessions map
|
|
662
|
-
self.sessions[id] = (
|
|
663
|
-
session_info_msg,
|
|
664
|
-
asyncio.Queue(),
|
|
665
|
-
)
|
|
666
|
-
|
|
667
|
-
# Also add a queue for the session
|
|
668
|
-
await self.sessions[SESSION_UNSPECIFIED][1].put(session_info_msg)
|
|
669
|
-
|
|
670
|
-
await self.sessions[id][1].put(session_info_msg)
|
|
671
|
-
except asyncio.CancelledError:
|
|
672
|
-
raise
|
|
673
|
-
except Exception as e:
|
|
674
|
-
print("Error receiving message:", e)
|
|
675
|
-
# Try to parse the error message
|
|
676
|
-
try:
|
|
677
|
-
message_id, session_id, reason = parse_error_message(str(e))
|
|
678
|
-
|
|
679
|
-
# figure out what exception to raise based on the reason
|
|
680
|
-
if reason == "timeout":
|
|
681
|
-
err = SLIMTimeoutError(message_id, session_id)
|
|
682
|
-
else:
|
|
683
|
-
# we don't know the reason, just raise the original exception
|
|
684
|
-
raise e
|
|
685
|
-
|
|
686
|
-
if session_id in self.sessions:
|
|
687
|
-
await self.sessions[session_id][1].put(
|
|
688
|
-
err,
|
|
689
|
-
)
|
|
690
|
-
else:
|
|
691
|
-
print(self.sessions.keys())
|
|
692
|
-
except Exception:
|
|
693
|
-
raise e
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
def parse_error_message(error_message):
|
|
697
|
-
import re
|
|
698
|
-
|
|
699
|
-
# Define the regular expression pattern
|
|
700
|
-
pattern = r"message=(\d+) session=(\d+): (.+)"
|
|
701
|
-
|
|
702
|
-
# Use re.search to find the pattern in the string
|
|
703
|
-
match = re.search(pattern, error_message)
|
|
704
|
-
|
|
705
|
-
if match:
|
|
706
|
-
# Extract message_id, session_id, and reason from the match groups
|
|
707
|
-
message_id = match.group(1)
|
|
708
|
-
session_id = match.group(2)
|
|
709
|
-
reason = match.group(3)
|
|
710
|
-
return int(message_id), int(session_id), reason
|
|
711
|
-
else:
|
|
712
|
-
raise ValueError("error message does not match the expected format.")
|
|
35
|
+
from slim_bindings.errors import SLIMTimeoutError
|
|
36
|
+
from slim_bindings.session import PySession
|
|
37
|
+
from slim_bindings.slim import Slim
|
|
38
|
+
from slim_bindings.version import get_build_info, get_build_profile, get_version
|
|
39
|
+
|
|
40
|
+
__all__ = [
|
|
41
|
+
"connect",
|
|
42
|
+
"create_pyservice",
|
|
43
|
+
"create_session",
|
|
44
|
+
"delete_session",
|
|
45
|
+
"disconnect",
|
|
46
|
+
"get_build_info",
|
|
47
|
+
"get_build_profile",
|
|
48
|
+
"get_default_session_config",
|
|
49
|
+
"get_message",
|
|
50
|
+
"get_version",
|
|
51
|
+
"init_tracing",
|
|
52
|
+
"invite",
|
|
53
|
+
"remove",
|
|
54
|
+
"listen_for_session",
|
|
55
|
+
"publish",
|
|
56
|
+
"PyAlgorithm",
|
|
57
|
+
"PyIdentityProvider",
|
|
58
|
+
"PyIdentityVerifier",
|
|
59
|
+
"PyKey",
|
|
60
|
+
"PyKeyData",
|
|
61
|
+
"PyKeyFormat",
|
|
62
|
+
"PyName",
|
|
63
|
+
"PyService",
|
|
64
|
+
"PySession",
|
|
65
|
+
"PySessionConfiguration",
|
|
66
|
+
"PySessionContext",
|
|
67
|
+
"PySessionType",
|
|
68
|
+
"remove_route",
|
|
69
|
+
"run_server",
|
|
70
|
+
"set_default_session_config",
|
|
71
|
+
"set_route",
|
|
72
|
+
"SLIMTimeoutError",
|
|
73
|
+
"Slim",
|
|
74
|
+
"stop_server",
|
|
75
|
+
"subscribe",
|
|
76
|
+
"unsubscribe",
|
|
77
|
+
]
|