motorcortex-python 0.22.9__tar.gz → 0.23.0__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.
- {motorcortex-python-0.22.9/motorcortex_python.egg-info → motorcortex-python-0.23.0}/PKG-INFO +1 -1
- {motorcortex-python-0.22.9 → motorcortex-python-0.23.0}/motorcortex/__init__.py +2 -0
- {motorcortex-python-0.22.9 → motorcortex-python-0.23.0}/motorcortex/message_types.py +4 -4
- {motorcortex-python-0.22.9 → motorcortex-python-0.23.0}/motorcortex/parameter_tree.py +1 -1
- {motorcortex-python-0.22.9 → motorcortex-python-0.23.0}/motorcortex/reply.py +5 -5
- {motorcortex-python-0.22.9 → motorcortex-python-0.23.0}/motorcortex/request.py +28 -24
- {motorcortex-python-0.22.9 → motorcortex-python-0.23.0}/motorcortex/setup_logger.py +1 -1
- motorcortex-python-0.23.0/motorcortex/state_callback_handler.py +62 -0
- {motorcortex-python-0.22.9 → motorcortex-python-0.23.0}/motorcortex/subscribe.py +21 -16
- {motorcortex-python-0.22.9 → motorcortex-python-0.23.0}/motorcortex/subscription.py +10 -12
- motorcortex-python-0.23.0/motorcortex/version.py +1 -0
- {motorcortex-python-0.22.9 → motorcortex-python-0.23.0/motorcortex_python.egg-info}/PKG-INFO +1 -1
- {motorcortex-python-0.22.9 → motorcortex-python-0.23.0}/motorcortex_python.egg-info/SOURCES.txt +1 -0
- {motorcortex-python-0.22.9 → motorcortex-python-0.23.0}/motorcortex_python.egg-info/requires.txt +1 -1
- {motorcortex-python-0.22.9 → motorcortex-python-0.23.0}/setup.py +1 -1
- motorcortex-python-0.22.9/motorcortex/version.py +0 -1
- {motorcortex-python-0.22.9 → motorcortex-python-0.23.0}/LICENSE +0 -0
- {motorcortex-python-0.22.9 → motorcortex-python-0.23.0}/MANIFEST.in +0 -0
- {motorcortex-python-0.22.9 → motorcortex-python-0.23.0}/README.md +0 -0
- {motorcortex-python-0.22.9 → motorcortex-python-0.23.0}/motorcortex/motorcortex_hash.json +0 -0
- {motorcortex-python-0.22.9 → motorcortex-python-0.23.0}/motorcortex/motorcortex_pb2.py +0 -0
- {motorcortex-python-0.22.9 → motorcortex-python-0.23.0}/motorcortex_python.egg-info/dependency_links.txt +0 -0
- {motorcortex-python-0.22.9 → motorcortex-python-0.23.0}/motorcortex_python.egg-info/top_level.txt +0 -0
- {motorcortex-python-0.22.9 → motorcortex-python-0.23.0}/setup.cfg +0 -0
|
@@ -13,6 +13,8 @@ from motorcortex.reply import Reply
|
|
|
13
13
|
from motorcortex.subscribe import Subscribe
|
|
14
14
|
from motorcortex.subscription import Subscription
|
|
15
15
|
from motorcortex.setup_logger import logger
|
|
16
|
+
from motorcortex.state_callback_handler import StateCallbackHandler
|
|
17
|
+
|
|
16
18
|
|
|
17
19
|
def parseUrl(url):
|
|
18
20
|
end = url.rfind(':')
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/python3
|
|
2
2
|
|
|
3
3
|
#
|
|
4
|
-
# Developer
|
|
4
|
+
# Developer: Alexey Zakharov (alexey.zakharov@vectioneer.com)
|
|
5
5
|
# All rights reserved. Copyright (c) 2016 VECTIONEER.
|
|
6
6
|
#
|
|
7
7
|
|
|
@@ -120,11 +120,11 @@ class PrimitiveTypes(object):
|
|
|
120
120
|
if t is bytes:
|
|
121
121
|
return value
|
|
122
122
|
|
|
123
|
-
# if string prepare and encode
|
|
123
|
+
# if the argument is a string, prepare and encode
|
|
124
124
|
if t is str:
|
|
125
125
|
return self.__encoder(-1, value)
|
|
126
126
|
|
|
127
|
-
# if not list convert to list
|
|
127
|
+
# if not list, convert to list
|
|
128
128
|
if t is not list:
|
|
129
129
|
value = [value]
|
|
130
130
|
|
|
@@ -213,7 +213,7 @@ class MessageTypes(object):
|
|
|
213
213
|
self.__hashes_by_name[hash_type_pair['type']] = hash
|
|
214
214
|
|
|
215
215
|
module = module_hash_pair.module
|
|
216
|
-
# searching for messages from hash file
|
|
216
|
+
# searching for messages from a hash file
|
|
217
217
|
|
|
218
218
|
for name in module.__dict__:
|
|
219
219
|
type = module.__dict__[name]
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/python3
|
|
2
2
|
|
|
3
3
|
#
|
|
4
|
-
# Developer
|
|
4
|
+
# Developer: Alexey Zakharov (alexey.zakharov@vectioneer.com)
|
|
5
5
|
# All rights reserved. Copyright (c) 2016-2020 VECTIONEER.
|
|
6
6
|
#
|
|
7
7
|
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
class Reply(object):
|
|
10
10
|
"""Reply handle is a JavaScript-like Promise.
|
|
11
11
|
|
|
12
|
-
It is resolved when reply is received with successful status and fails otherwise.
|
|
12
|
+
It is resolved when a reply is received with successful status and fails otherwise.
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
15
|
def __init__(self, future):
|
|
@@ -34,15 +34,15 @@ class Reply(object):
|
|
|
34
34
|
def done(self):
|
|
35
35
|
"""
|
|
36
36
|
Returns:
|
|
37
|
-
bool: True if the call was successfully
|
|
37
|
+
bool: True if the call was successfully canceled or finished running.
|
|
38
38
|
"""
|
|
39
39
|
return self.__future.done()
|
|
40
40
|
|
|
41
41
|
def then(self, received_clb, *args, **kwargs):
|
|
42
|
-
"""JavaScript-like promise, which is resolved when reply is received.
|
|
42
|
+
"""JavaScript-like promise, which is resolved when a reply is received.
|
|
43
43
|
|
|
44
44
|
Args:
|
|
45
|
-
received_clb: callback which is resolved when reply is received.
|
|
45
|
+
received_clb: callback which is resolved when the reply is received.
|
|
46
46
|
|
|
47
47
|
Returns:
|
|
48
48
|
self pointer to add 'catch' callback
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/python3
|
|
2
2
|
|
|
3
3
|
#
|
|
4
|
-
# Developer
|
|
5
|
-
# All rights reserved. Copyright (c) 2016-
|
|
4
|
+
# Developer: Alexey Zakharov (alexey.zakharov@vectioneer.com)
|
|
5
|
+
# All rights reserved. Copyright (c) 2016-2025 VECTIONEER.
|
|
6
6
|
#
|
|
7
7
|
import base64
|
|
8
8
|
import hashlib
|
|
@@ -11,6 +11,7 @@ import tempfile
|
|
|
11
11
|
|
|
12
12
|
from motorcortex.reply import Reply
|
|
13
13
|
from motorcortex.setup_logger import logger
|
|
14
|
+
from motorcortex.state_callback_handler import StateCallbackHandler
|
|
14
15
|
|
|
15
16
|
import os
|
|
16
17
|
import queue
|
|
@@ -56,9 +57,9 @@ class Request(object):
|
|
|
56
57
|
self.__connected_lock = None
|
|
57
58
|
self.__protobuf_types = protobuf_types
|
|
58
59
|
self.__parameter_tree = parameter_tree
|
|
59
|
-
self.__pool = ThreadPoolExecutor(max_workers=1)
|
|
60
|
-
self.__clb = ThreadPoolExecutor(max_workers=1)
|
|
61
60
|
self.__connection_state = ConnectionState.DISCONNECTED
|
|
61
|
+
self.__pool = ThreadPoolExecutor(max_workers=1)
|
|
62
|
+
self.__callback_handler = StateCallbackHandler()
|
|
62
63
|
|
|
63
64
|
def url(self):
|
|
64
65
|
return self.__url
|
|
@@ -66,6 +67,10 @@ class Request(object):
|
|
|
66
67
|
def connect(self, url, **kwargs):
|
|
67
68
|
self.__connection_state = ConnectionState.CONNECTING
|
|
68
69
|
conn_timeout_ms, recv_timeout_ms, certificate, state_update = self.parse(**kwargs)
|
|
70
|
+
|
|
71
|
+
if state_update:
|
|
72
|
+
self.__callback_handler.start(state_update)
|
|
73
|
+
|
|
69
74
|
self.__url = url
|
|
70
75
|
tls_config = None
|
|
71
76
|
if certificate:
|
|
@@ -77,8 +82,7 @@ class Request(object):
|
|
|
77
82
|
def pre_connect_cb(pipe):
|
|
78
83
|
self.__connected_lock.put(True)
|
|
79
84
|
self.__connection_state = ConnectionState.CONNECTION_OK
|
|
80
|
-
|
|
81
|
-
self.__clb.submit(state_update, self, self.connectionState())
|
|
85
|
+
self.__callback_handler.notify(self, self.connectionState())
|
|
82
86
|
|
|
83
87
|
def post_remove_cb(pipe):
|
|
84
88
|
if self.__connection_state == ConnectionState.DISCONNECTING:
|
|
@@ -88,8 +92,7 @@ class Request(object):
|
|
|
88
92
|
elif self.__connection_state == ConnectionState.CONNECTION_OK:
|
|
89
93
|
self.__connection_state = ConnectionState.CONNECTION_LOST
|
|
90
94
|
self.__connected_lock.put(False)
|
|
91
|
-
|
|
92
|
-
self.__clb.submit(state_update, self, self.connectionState())
|
|
95
|
+
self.__callback_handler.notify(self, self.connectionState())
|
|
93
96
|
|
|
94
97
|
self.__socket.add_post_pipe_connect_cb(pre_connect_cb)
|
|
95
98
|
self.__socket.add_post_pipe_remove_cb(post_remove_cb)
|
|
@@ -103,6 +106,7 @@ class Request(object):
|
|
|
103
106
|
if self.__connected_lock:
|
|
104
107
|
self.__connected_lock.put(False)
|
|
105
108
|
self.__socket.close()
|
|
109
|
+
self.__callback_handler.stop()
|
|
106
110
|
|
|
107
111
|
def send(self, encoded_msg, do_not_decode_reply=False):
|
|
108
112
|
if self.__socket is not None:
|
|
@@ -119,7 +123,7 @@ class Request(object):
|
|
|
119
123
|
|
|
120
124
|
Results:
|
|
121
125
|
Reply(StatusMsg): A Promise, which resolves if login is successful and fails otherwise.
|
|
122
|
-
|
|
126
|
+
The returned message has a status code, which indicates the status of the login.
|
|
123
127
|
|
|
124
128
|
Examples:
|
|
125
129
|
>>> login_reply = req.login('operator', 'iddqd')
|
|
@@ -161,7 +165,7 @@ class Request(object):
|
|
|
161
165
|
"""Request a parameter tree from the server.
|
|
162
166
|
|
|
163
167
|
Returns:
|
|
164
|
-
Reply(ParameterTreeMsg): A Promise, which resolves when parameter tree is received or fails
|
|
168
|
+
Reply(ParameterTreeMsg): A Promise, which resolves when a parameter tree is received or fails
|
|
165
169
|
otherwise. ParameterTreeMsg message has a status field to check the status of the operation.
|
|
166
170
|
|
|
167
171
|
Examples:
|
|
@@ -194,14 +198,14 @@ class Request(object):
|
|
|
194
198
|
return self.send(self.__protobuf_types.encode(param_save_msg))
|
|
195
199
|
|
|
196
200
|
def setParameter(self, path, value, type_name=None, offset=0, length=0):
|
|
197
|
-
"""Set new value to a parameter with given path
|
|
201
|
+
"""Set a new value to a parameter with a given path
|
|
198
202
|
|
|
199
203
|
Args:
|
|
200
204
|
path(str): parameter path in the tree
|
|
201
205
|
value(any): new parameter value
|
|
202
|
-
type_name(str): type of the value (by default resolved automatically)
|
|
203
|
-
offset(int): offset of the elements to update in the destination array, (by default is 0)
|
|
204
|
-
length(int): number of the elements to update in the destination array, (by default takes length of the
|
|
206
|
+
type_name(str): type of the value (by default, resolved automatically)
|
|
207
|
+
offset(int): offset of the elements to update in the destination array, (by default, is 0)
|
|
208
|
+
length(int): number of the elements to update in the destination array, (by default, takes length of the
|
|
205
209
|
value argument)
|
|
206
210
|
|
|
207
211
|
Returns:
|
|
@@ -262,7 +266,7 @@ class Request(object):
|
|
|
262
266
|
path(str): parameter path in the tree.
|
|
263
267
|
|
|
264
268
|
Returns:
|
|
265
|
-
Reply(ParameterMsg): Returns a Promise, which resolves when parameter
|
|
269
|
+
Reply(ParameterMsg): Returns a Promise, which resolves when a parameter
|
|
266
270
|
message is successfully obtained, fails otherwise.
|
|
267
271
|
|
|
268
272
|
Examples:
|
|
@@ -276,10 +280,10 @@ class Request(object):
|
|
|
276
280
|
"""Get description and values of requested parameters.
|
|
277
281
|
|
|
278
282
|
Args:
|
|
279
|
-
path_list(list(str)): list of parameter paths in the tree.
|
|
283
|
+
path_list(list(str)): a list of parameter paths in the tree.
|
|
280
284
|
|
|
281
285
|
Returns:
|
|
282
|
-
Reply(ParameterListMsg): A Promise, which resolves when list of the parameter values is received, fails
|
|
286
|
+
Reply(ParameterListMsg): A Promise, which resolves when a list of the parameter values is received, fails
|
|
283
287
|
otherwise.
|
|
284
288
|
|
|
285
289
|
Examples:
|
|
@@ -299,17 +303,17 @@ class Request(object):
|
|
|
299
303
|
|
|
300
304
|
def overwriteParameter(self, path, value, force_activate=False, type_name=None):
|
|
301
305
|
"""Overwrites actual value of the parameter and depending on the flag forces this value to stay active.
|
|
302
|
-
This method of setting values is useful during debug and installation process, it is not recommended to use
|
|
306
|
+
This method of setting values is useful during the debug and installation process, it is not recommended to use
|
|
303
307
|
this method during normal operation.
|
|
304
308
|
|
|
305
309
|
Args:
|
|
306
310
|
path(str): parameter path in the tree
|
|
307
311
|
value(any): new parameter value
|
|
308
|
-
force_activate(bool): forces new value to stay active. (by default is set to 'False')
|
|
309
|
-
type_name(str): type of the value (by default resolved automatically)
|
|
312
|
+
force_activate(bool): forces the new value to stay active. (by default, is set to 'False')
|
|
313
|
+
type_name(str): type of the value (by default, resolved automatically)
|
|
310
314
|
|
|
311
315
|
Returns:
|
|
312
|
-
Reply(StatusMsg): A Promise, which resolves when parameter value is updated or fails otherwise.
|
|
316
|
+
Reply(StatusMsg): A Promise, which resolves when a parameter value is updated or fails otherwise.
|
|
313
317
|
|
|
314
318
|
Examples:
|
|
315
319
|
>>> reply = req.overwriteParameter("root/Control/dummyBool", False, True)
|
|
@@ -322,13 +326,13 @@ class Request(object):
|
|
|
322
326
|
self.__parameter_tree)))
|
|
323
327
|
|
|
324
328
|
def releaseParameter(self, path):
|
|
325
|
-
"""Deactivate overwrite operation of the parameter.
|
|
329
|
+
"""Deactivate the overwrite operation of the parameter.
|
|
326
330
|
|
|
327
331
|
Args:
|
|
328
332
|
path(str): parameter path in the tree
|
|
329
333
|
|
|
330
334
|
Returns:
|
|
331
|
-
Reply(StatusMsg): A Promise, which resolves when parameter value is released or fails otherwise.
|
|
335
|
+
Reply(StatusMsg): A Promise, which resolves when a parameter value is released or fails otherwise.
|
|
332
336
|
|
|
333
337
|
Examples:
|
|
334
338
|
>>> reply = req.releaseParameter("root/Control/dummyBool")
|
|
@@ -348,7 +352,7 @@ class Request(object):
|
|
|
348
352
|
frq_divider(int): frequency divider is a downscaling factor for the group publish rate
|
|
349
353
|
|
|
350
354
|
Returns:
|
|
351
|
-
Reply(GroupStatusMsg): A Promise, which resolves when subscription is complete,
|
|
355
|
+
Reply(GroupStatusMsg): A Promise, which resolves when the subscription is complete,
|
|
352
356
|
fails otherwise.
|
|
353
357
|
"""
|
|
354
358
|
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/python3
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# Developer: Alexey Zakharov (alexey.zakharov@vectioneer.com)
|
|
5
|
+
# All rights reserved. Copyright (c) 2025 VECTIONEER.
|
|
6
|
+
#
|
|
7
|
+
|
|
8
|
+
from queue import Queue, Empty
|
|
9
|
+
import threading
|
|
10
|
+
from motorcortex.setup_logger import logger
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class StateCallbackHandler:
|
|
14
|
+
"""Handles state change callbacks processing"""
|
|
15
|
+
|
|
16
|
+
def __init__(self):
|
|
17
|
+
self.running = False
|
|
18
|
+
self.callback_queue = Queue()
|
|
19
|
+
self.callback_thread = None
|
|
20
|
+
self.state_update_handler = None
|
|
21
|
+
|
|
22
|
+
def start(self, state_update_handler):
|
|
23
|
+
"""Start the callback handler with the given update function"""
|
|
24
|
+
if state_update_handler:
|
|
25
|
+
self.state_update_handler = state_update_handler
|
|
26
|
+
self.running = True
|
|
27
|
+
self.callback_thread = threading.Thread(
|
|
28
|
+
target=self.__process_callbacks,
|
|
29
|
+
daemon=True
|
|
30
|
+
)
|
|
31
|
+
self.callback_thread.start()
|
|
32
|
+
|
|
33
|
+
def stop(self):
|
|
34
|
+
"""Stop the callback handler and clean up"""
|
|
35
|
+
self.running = False
|
|
36
|
+
if self.callback_thread:
|
|
37
|
+
self.callback_queue.put(None) # Signal thread to exit
|
|
38
|
+
self.callback_thread.join(timeout=1.0)
|
|
39
|
+
self.callback_thread = None
|
|
40
|
+
self.state_update_handler = None
|
|
41
|
+
|
|
42
|
+
def notify(self, *args):
|
|
43
|
+
"""Queue a state update notification"""
|
|
44
|
+
if self.state_update_handler:
|
|
45
|
+
self.callback_queue.put(args)
|
|
46
|
+
|
|
47
|
+
def __process_callbacks(self):
|
|
48
|
+
"""Process callbacks in a dedicated thread"""
|
|
49
|
+
while self.running:
|
|
50
|
+
try:
|
|
51
|
+
args = self.callback_queue.get(timeout=0.1)
|
|
52
|
+
if args is None: # Stop signal
|
|
53
|
+
break
|
|
54
|
+
try:
|
|
55
|
+
self.state_update_handler(*args)
|
|
56
|
+
except Exception as e:
|
|
57
|
+
logger.exception("Error in state callback: %s", e)
|
|
58
|
+
except Empty:
|
|
59
|
+
continue
|
|
60
|
+
except Exception as e:
|
|
61
|
+
if self.running:
|
|
62
|
+
logger.exception("Error processing callbacks: %s", e)
|
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/python3
|
|
2
2
|
|
|
3
3
|
#
|
|
4
|
-
# Developer
|
|
5
|
-
# All rights reserved. Copyright (c) 2016 VECTIONEER.
|
|
4
|
+
# Developer: Alexey Zakharov (alexey.zakharov@vectioneer.com)
|
|
5
|
+
# All rights reserved. Copyright (c) 2016-2025 VECTIONEER.
|
|
6
6
|
#
|
|
7
7
|
|
|
8
8
|
from motorcortex.request import Request, Reply, ConnectionState
|
|
9
9
|
from motorcortex.subscription import Subscription
|
|
10
|
+
from motorcortex.state_callback_handler import StateCallbackHandler
|
|
11
|
+
from motorcortex.setup_logger import logger
|
|
10
12
|
from pynng import Sub0, TLSConfig
|
|
11
13
|
from concurrent.futures import ThreadPoolExecutor
|
|
12
14
|
from queue import Queue
|
|
13
15
|
|
|
14
16
|
|
|
15
17
|
class Subscribe:
|
|
16
|
-
"""Subscribe class is used to receive continuous parameter updates from motorcortex server.
|
|
18
|
+
"""Subscribe class is used to receive continuous parameter updates from the motorcortex server.
|
|
17
19
|
|
|
18
20
|
Subscribe class simplifies creating and removing subscription groups.
|
|
19
21
|
|
|
@@ -31,22 +33,26 @@ class Subscribe:
|
|
|
31
33
|
self.__protobuf_types = protobuf_types
|
|
32
34
|
self.__subscriptions = dict()
|
|
33
35
|
self.__pool = ThreadPoolExecutor()
|
|
34
|
-
self.
|
|
36
|
+
self.__callback_handler = StateCallbackHandler()
|
|
35
37
|
self.__connection_state = ConnectionState.DISCONNECTED
|
|
36
38
|
|
|
37
39
|
def connect(self, url, **kwargs):
|
|
38
|
-
"""Open a
|
|
40
|
+
"""Open a subscription connection.
|
|
39
41
|
|
|
40
42
|
Args:
|
|
41
43
|
url(str): motorcortex server URL
|
|
42
44
|
|
|
43
45
|
Returns:
|
|
44
|
-
bool: True - if connected, False
|
|
46
|
+
bool: True - if connected, False otherwise
|
|
45
47
|
"""
|
|
46
48
|
|
|
47
49
|
self.__connection_state = ConnectionState.CONNECTING
|
|
48
50
|
conn_timeout_ms, recv_timeout_ms, certificate, state_update = Request.parse(**kwargs)
|
|
49
|
-
|
|
51
|
+
|
|
52
|
+
if state_update:
|
|
53
|
+
self.__callback_handler.start(state_update)
|
|
54
|
+
|
|
55
|
+
if not recv_timeout_ms:
|
|
50
56
|
recv_timeout_ms = 500
|
|
51
57
|
|
|
52
58
|
self.__url = url
|
|
@@ -61,8 +67,7 @@ class Subscribe:
|
|
|
61
67
|
def pre_connect_cb(pipe):
|
|
62
68
|
self.__connected_lock.put(True)
|
|
63
69
|
self.__connection_state = ConnectionState.CONNECTION_OK
|
|
64
|
-
|
|
65
|
-
self.__clb.submit(state_update, self.__req, self, self.connectionState())
|
|
70
|
+
self.__callback_handler.notify(self.__req, self, self.connectionState())
|
|
66
71
|
|
|
67
72
|
def post_remove_cb(pipe):
|
|
68
73
|
if self.__connection_state == ConnectionState.DISCONNECTING:
|
|
@@ -72,8 +77,7 @@ class Subscribe:
|
|
|
72
77
|
elif self.__connection_state == ConnectionState.CONNECTION_OK:
|
|
73
78
|
self.__connection_state = ConnectionState.CONNECTION_LOST
|
|
74
79
|
self.__connected_lock.put(False)
|
|
75
|
-
|
|
76
|
-
self.__clb.submit(state_update, self.__req, self, self.connectionState())
|
|
80
|
+
self.__callback_handler.notify(self.__req, self, self.connectionState())
|
|
77
81
|
|
|
78
82
|
self.__socket.add_pre_pipe_connect_cb(pre_connect_cb)
|
|
79
83
|
self.__socket.add_post_pipe_remove_cb(post_remove_cb)
|
|
@@ -90,6 +94,7 @@ class Subscribe:
|
|
|
90
94
|
if self.__connected_lock:
|
|
91
95
|
self.__connected_lock.put(False)
|
|
92
96
|
self.__socket.close()
|
|
97
|
+
self.__callback_handler.stop()
|
|
93
98
|
self.__pool.shutdown(wait=True)
|
|
94
99
|
|
|
95
100
|
def run(self, socket):
|
|
@@ -107,9 +112,9 @@ class Subscribe:
|
|
|
107
112
|
elif protocol_version == 0:
|
|
108
113
|
sub._updateProtocol0(buffer[4:], length - 4)
|
|
109
114
|
else:
|
|
110
|
-
|
|
115
|
+
logger.error(f'Unknown protocol version: {protocol_version}')
|
|
111
116
|
|
|
112
|
-
|
|
117
|
+
logger.debug('Subscribe connection closed')
|
|
113
118
|
|
|
114
119
|
def subscribe(self, param_list, group_alias, frq_divider=1):
|
|
115
120
|
"""Create a subscription group for a list of the parameters.
|
|
@@ -121,11 +126,11 @@ class Subscribe:
|
|
|
121
126
|
|
|
122
127
|
Returns:
|
|
123
128
|
Subscription: A subscription handle, which acts as a JavaScript Promise,
|
|
124
|
-
it is resolved when subscription is ready or failed. After the subscription
|
|
125
|
-
is ready the handle is used to retrieve latest data.
|
|
129
|
+
it is resolved when the subscription is ready or failed. After the subscription
|
|
130
|
+
is ready, the handle is used to retrieve the latest data.
|
|
126
131
|
"""
|
|
127
132
|
|
|
128
|
-
subscription = Subscription(group_alias, self.__protobuf_types, frq_divider)
|
|
133
|
+
subscription = Subscription(group_alias, self.__protobuf_types, frq_divider, self.__pool)
|
|
129
134
|
reply = self.__req.createGroup(param_list, group_alias, frq_divider)
|
|
130
135
|
reply.then(self.__complete, subscription, self.__socket).catch(
|
|
131
136
|
subscription._failed)
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/python3
|
|
2
2
|
|
|
3
3
|
#
|
|
4
|
-
# Developer
|
|
5
|
-
# All rights reserved. Copyright (c) 2016 VECTIONEER.
|
|
4
|
+
# Developer: Alexey Zakharov (alexey.zakharov@vectioneer.com)
|
|
5
|
+
# All rights reserved. Copyright (c) 2016-2025 VECTIONEER.
|
|
6
6
|
#
|
|
7
7
|
|
|
8
8
|
from collections import namedtuple
|
|
9
9
|
from struct import unpack_from
|
|
10
|
-
from concurrent.futures import Future
|
|
10
|
+
from concurrent.futures import Future
|
|
11
11
|
import time
|
|
12
12
|
|
|
13
13
|
timespec = namedtuple('timespec', 'sec, nsec')
|
|
@@ -110,18 +110,17 @@ class Subscription(object):
|
|
|
110
110
|
notifies on every update or could be used as polling.
|
|
111
111
|
"""
|
|
112
112
|
|
|
113
|
-
def __init__(self, group_alias, protobuf_types, frq_divider):
|
|
113
|
+
def __init__(self, group_alias, protobuf_types, frq_divider, pool):
|
|
114
114
|
self.__info = None
|
|
115
115
|
self.__group_alias = group_alias
|
|
116
116
|
self.__protobuf_types = protobuf_types
|
|
117
117
|
self.__decoder = []
|
|
118
|
-
self.__clb_list = []
|
|
119
118
|
self.__future = Future()
|
|
120
119
|
self.__values = None
|
|
121
120
|
self.__layout = None
|
|
122
121
|
self.__is_complete = False
|
|
123
122
|
self.__observer_list = []
|
|
124
|
-
self.__pool =
|
|
123
|
+
self.__pool = pool
|
|
125
124
|
self.__frq_divider = frq_divider
|
|
126
125
|
|
|
127
126
|
def id(self):
|
|
@@ -164,7 +163,7 @@ class Subscription(object):
|
|
|
164
163
|
def done(self):
|
|
165
164
|
"""
|
|
166
165
|
Returns:
|
|
167
|
-
bool: True if the call was successfully
|
|
166
|
+
bool: True if the call was successfully canceled or finished running.
|
|
168
167
|
|
|
169
168
|
Examples:
|
|
170
169
|
>>> subscription = sub.subscribe("root/logger/logOut", "log")
|
|
@@ -176,7 +175,7 @@ class Subscription(object):
|
|
|
176
175
|
def get(self, timeout_sec=1.0):
|
|
177
176
|
"""
|
|
178
177
|
Returns:
|
|
179
|
-
bool: StatusMsg if the call was
|
|
178
|
+
bool: StatusMsg if the call was successful, None if timeout happened.
|
|
180
179
|
|
|
181
180
|
Examples:
|
|
182
181
|
>>> subscription = sub.subscribe("root/logger/logOut", "log")
|
|
@@ -186,10 +185,10 @@ class Subscription(object):
|
|
|
186
185
|
return self.__future.result(timeout_sec)
|
|
187
186
|
|
|
188
187
|
def then(self, subscribed_clb):
|
|
189
|
-
"""JavaScript-like promise, which is resolved when subscription is completed.
|
|
188
|
+
"""JavaScript-like promise, which is resolved when the subscription is completed.
|
|
190
189
|
|
|
191
190
|
Args:
|
|
192
|
-
subscribed_clb: callback which is resolved when subscription is completed.
|
|
191
|
+
subscribed_clb: callback which is resolved when the subscription is completed.
|
|
193
192
|
|
|
194
193
|
Returns:
|
|
195
194
|
self pointer to add 'catch' callback
|
|
@@ -208,7 +207,7 @@ class Subscription(object):
|
|
|
208
207
|
"""JavaScript-like promise, which is resolved when subscription has failed.
|
|
209
208
|
|
|
210
209
|
Args:
|
|
211
|
-
failed: callback which is resolved when subscription has failed
|
|
210
|
+
failed: callback which is resolved when the subscription has failed
|
|
212
211
|
|
|
213
212
|
Returns:
|
|
214
213
|
self pointer to add 'then' callback
|
|
@@ -238,7 +237,6 @@ class Subscription(object):
|
|
|
238
237
|
|
|
239
238
|
"""
|
|
240
239
|
self.__observer_list = observer_list if type(observer_list) is list else [observer_list]
|
|
241
|
-
self.__pool = ThreadPoolExecutor(len(self.__observer_list))
|
|
242
240
|
|
|
243
241
|
def _complete(self, msg):
|
|
244
242
|
self.__decoder = []
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '0.23.0'
|
{motorcortex-python-0.22.9 → motorcortex-python-0.23.0}/motorcortex_python.egg-info/requires.txt
RENAMED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
protobuf==3.20.*
|
|
2
|
-
pynng==0.
|
|
2
|
+
pynng==0.8.*
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = '0.22.9'
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{motorcortex-python-0.22.9 → motorcortex-python-0.23.0}/motorcortex_python.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|