remotivelabs-cli 0.2.3__py3-none-any.whl → 0.3.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.
Potentially problematic release.
This version of remotivelabs-cli might be problematic. Click here for more details.
- cli/broker/__init__.py +36 -0
- cli/broker/discovery.py +43 -0
- cli/broker/export.py +6 -36
- cli/broker/files.py +12 -12
- cli/broker/lib/broker.py +132 -106
- cli/broker/lib/client.py +224 -0
- cli/broker/lib/helper.py +277 -0
- cli/broker/lib/signalcreator.py +196 -0
- cli/broker/license_flows.py +11 -13
- cli/broker/playback.py +10 -10
- cli/broker/record.py +4 -4
- cli/broker/scripting.py +6 -9
- cli/broker/signals.py +17 -19
- cli/cloud/__init__.py +17 -0
- cli/cloud/auth/cmd.py +74 -33
- cli/cloud/auth/login.py +42 -54
- cli/cloud/auth_tokens.py +40 -247
- cli/cloud/brokers.py +5 -9
- cli/cloud/configs.py +4 -17
- cli/cloud/licenses/__init__.py +0 -0
- cli/cloud/licenses/cmd.py +14 -0
- cli/cloud/organisations.py +12 -17
- cli/cloud/projects.py +3 -3
- cli/cloud/recordings.py +35 -61
- cli/cloud/recordings_playback.py +22 -22
- cli/cloud/resumable_upload.py +6 -6
- cli/cloud/service_account_tokens.py +4 -3
- cli/cloud/storage/cmd.py +2 -3
- cli/cloud/storage/copy.py +2 -1
- cli/connect/connect.py +4 -4
- cli/connect/protopie/protopie.py +22 -30
- cli/remotive.py +16 -26
- cli/settings/__init__.py +1 -2
- cli/settings/config_file.py +2 -0
- cli/settings/core.py +146 -146
- cli/settings/migration/migrate_config_file.py +13 -6
- cli/settings/migration/migration_tools.py +6 -4
- cli/settings/state_file.py +12 -4
- cli/tools/can/can.py +4 -7
- cli/topology/__init__.py +3 -0
- cli/topology/cmd.py +60 -83
- cli/topology/start_trial.py +105 -0
- cli/typer/typer_utils.py +3 -6
- cli/utils/console.py +61 -0
- cli/utils/rest_helper.py +33 -31
- cli/utils/versions.py +7 -19
- {remotivelabs_cli-0.2.3.dist-info → remotivelabs_cli-0.3.1.dist-info}/METADATA +3 -2
- remotivelabs_cli-0.3.1.dist-info/RECORD +74 -0
- cli/broker/brokers.py +0 -93
- cli/cloud/cloud_cli.py +0 -29
- cli/errors.py +0 -44
- remotivelabs_cli-0.2.3.dist-info/RECORD +0 -67
- {remotivelabs_cli-0.2.3.dist-info → remotivelabs_cli-0.3.1.dist-info}/LICENSE +0 -0
- {remotivelabs_cli-0.2.3.dist-info → remotivelabs_cli-0.3.1.dist-info}/WHEEL +0 -0
- {remotivelabs_cli-0.2.3.dist-info → remotivelabs_cli-0.3.1.dist-info}/entry_points.txt +0 -0
cli/broker/lib/broker.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import binascii
|
|
4
|
+
import hashlib
|
|
5
|
+
import itertools
|
|
4
6
|
import ntpath
|
|
5
7
|
import os
|
|
6
8
|
import posixpath
|
|
@@ -11,22 +13,25 @@ import tempfile
|
|
|
11
13
|
import time
|
|
12
14
|
import zipfile
|
|
13
15
|
from dataclasses import dataclass
|
|
16
|
+
from glob import glob
|
|
14
17
|
from threading import Thread
|
|
15
|
-
from typing import Any, Callable, Dict, Iterable, List, Sequence, Union
|
|
18
|
+
from typing import Any, BinaryIO, Callable, Dict, Generator, Iterable, List, Sequence, Union
|
|
16
19
|
|
|
17
20
|
import grpc
|
|
18
|
-
import remotivelabs.broker.
|
|
19
|
-
import remotivelabs.broker.
|
|
20
|
-
import remotivelabs.broker.
|
|
21
|
-
import remotivelabs.broker.
|
|
21
|
+
import remotivelabs.broker._generated.common_pb2 as common
|
|
22
|
+
import remotivelabs.broker._generated.network_api_pb2 as network_api
|
|
23
|
+
import remotivelabs.broker._generated.network_api_pb2_grpc as network_api_grpc
|
|
24
|
+
import remotivelabs.broker._generated.system_api_pb2 as system_api
|
|
25
|
+
import remotivelabs.broker._generated.system_api_pb2_grpc as system_api_grpc
|
|
26
|
+
import remotivelabs.broker._generated.traffic_api_pb2 as traffic_api
|
|
27
|
+
import remotivelabs.broker._generated.traffic_api_pb2_grpc as traffic_api_grpc
|
|
22
28
|
import typer
|
|
23
29
|
from google.protobuf.json_format import MessageToDict
|
|
24
|
-
from rich.console import Console
|
|
25
30
|
|
|
26
|
-
from cli.
|
|
31
|
+
from cli.broker.lib.helper import act_on_scripted_signal, act_on_signal, create_channel
|
|
32
|
+
from cli.broker.lib.signalcreator import SignalCreator
|
|
27
33
|
from cli.settings import settings
|
|
28
|
-
|
|
29
|
-
err_console = Console(stderr=True)
|
|
34
|
+
from cli.utils.console import print_generic_error, print_hint, print_success
|
|
30
35
|
|
|
31
36
|
|
|
32
37
|
@dataclass
|
|
@@ -43,6 +48,27 @@ class LicenseInfo:
|
|
|
43
48
|
machine_id: str
|
|
44
49
|
|
|
45
50
|
|
|
51
|
+
def get_sha256(path: str) -> str:
|
|
52
|
+
"""
|
|
53
|
+
Calculate SHA256 for a file.
|
|
54
|
+
"""
|
|
55
|
+
with open(path, "rb") as f:
|
|
56
|
+
b = f.read() # read entire file as bytes
|
|
57
|
+
return hashlib.sha256(b).hexdigest()
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def generate_data(file: BinaryIO, dest_path: str, chunk_size: int, sha256: str) -> Generator[system_api.FileUploadRequest, None, None]:
|
|
61
|
+
for x in itertools.count(start=0):
|
|
62
|
+
if x == 0:
|
|
63
|
+
file_description = system_api.FileDescription(sha256=sha256, path=dest_path)
|
|
64
|
+
yield system_api.FileUploadRequest(fileDescription=file_description)
|
|
65
|
+
else:
|
|
66
|
+
buf = file.read(chunk_size)
|
|
67
|
+
if not buf:
|
|
68
|
+
break
|
|
69
|
+
yield system_api.FileUploadRequest(chunk=buf)
|
|
70
|
+
|
|
71
|
+
|
|
46
72
|
class Broker:
|
|
47
73
|
def __init__(self, url: str, api_key: Union[str, None] = None) -> None:
|
|
48
74
|
self.url = url
|
|
@@ -53,138 +79,138 @@ class Broker:
|
|
|
53
79
|
|
|
54
80
|
if api_key is None or api_key == "":
|
|
55
81
|
if url.startswith("https"):
|
|
56
|
-
self.intercept_channel =
|
|
82
|
+
self.intercept_channel = create_channel(url, None, settings.get_active_token())
|
|
57
83
|
# TODO - Temporary solution to print proper error message, remove ENV once api-key is gone
|
|
58
84
|
os.environ["ACCESS_TOKEN"] = "true"
|
|
59
85
|
else:
|
|
60
86
|
os.environ["ACCESS_TOKEN"] = "false"
|
|
61
|
-
self.intercept_channel =
|
|
87
|
+
self.intercept_channel = create_channel(url, None, None)
|
|
62
88
|
else:
|
|
63
|
-
|
|
89
|
+
print_hint("Option --api-key will is deprecated and will be removed. Use access access tokens by logging in with cli.")
|
|
64
90
|
os.environ["ACCESS_TOKEN"] = "false"
|
|
65
|
-
self.intercept_channel =
|
|
91
|
+
self.intercept_channel = create_channel(url, api_key, None)
|
|
66
92
|
|
|
67
|
-
self.network_stub =
|
|
68
|
-
self.system_stub =
|
|
69
|
-
self.traffic_stub =
|
|
70
|
-
self.signal_creator =
|
|
93
|
+
self.network_stub = network_api_grpc.NetworkServiceStub(self.intercept_channel)
|
|
94
|
+
self.system_stub = system_api_grpc.SystemServiceStub(self.intercept_channel)
|
|
95
|
+
self.traffic_stub = traffic_api_grpc.TrafficServiceStub(self.intercept_channel)
|
|
96
|
+
self.signal_creator = SignalCreator(self.system_stub)
|
|
71
97
|
|
|
72
98
|
@staticmethod
|
|
73
|
-
def __check_playbackmode_result(status:
|
|
99
|
+
def __check_playbackmode_result(status: traffic_api.PlaybackInfos) -> None:
|
|
74
100
|
err_cnt = 0
|
|
75
101
|
for mode in status.playbackInfo:
|
|
76
102
|
if mode.playbackMode.errorMessage:
|
|
77
|
-
|
|
103
|
+
print_generic_error(mode.playbackMode.errorMessage)
|
|
78
104
|
err_cnt = err_cnt + 1
|
|
79
105
|
if err_cnt > 0:
|
|
80
106
|
raise typer.Exit(1)
|
|
81
107
|
|
|
82
|
-
def seek(self, recording_and_namespace: List[Any], offset: int, silent: bool = True) ->
|
|
108
|
+
def seek(self, recording_and_namespace: List[Any], offset: int, silent: bool = True) -> traffic_api.PlaybackInfos:
|
|
83
109
|
def to_playback(rec: Any) -> Dict[str, Any]:
|
|
84
|
-
return {"namespace": rec["namespace"], "path": rec["recording"], "mode":
|
|
110
|
+
return {"namespace": rec["namespace"], "path": rec["recording"], "mode": traffic_api.Mode.SEEK, "offsettime": offset}
|
|
85
111
|
|
|
86
112
|
playback_list = map(to_playback, recording_and_namespace)
|
|
87
113
|
|
|
88
|
-
infos =
|
|
89
|
-
status = self.traffic_stub.PlayTraffic(infos)
|
|
114
|
+
infos = traffic_api.PlaybackInfos(playbackInfo=list(map(self.__create_playback_config, playback_list)))
|
|
115
|
+
status: traffic_api.PlaybackInfos = self.traffic_stub.PlayTraffic(infos)
|
|
90
116
|
if not silent:
|
|
91
117
|
self.__check_playbackmode_result(status)
|
|
92
118
|
return status
|
|
93
119
|
|
|
94
|
-
def play(self, recording_and_namespace: List[Any], silent: bool = False) ->
|
|
120
|
+
def play(self, recording_and_namespace: List[Any], silent: bool = False) -> traffic_api.PlaybackInfos:
|
|
95
121
|
def to_playback(rec: Any) -> Dict[str, Any]:
|
|
96
122
|
return {
|
|
97
123
|
"namespace": rec["namespace"],
|
|
98
124
|
"path": rec["recording"],
|
|
99
|
-
"mode":
|
|
125
|
+
"mode": traffic_api.Mode.PLAY,
|
|
100
126
|
}
|
|
101
127
|
|
|
102
128
|
playback_list = map(to_playback, recording_and_namespace)
|
|
103
129
|
|
|
104
|
-
status = self.traffic_stub.PlayTraffic(
|
|
105
|
-
|
|
130
|
+
status: traffic_api.PlaybackInfos = self.traffic_stub.PlayTraffic(
|
|
131
|
+
traffic_api.PlaybackInfos(playbackInfo=list(map(self.__create_playback_config, playback_list)))
|
|
106
132
|
)
|
|
107
133
|
|
|
108
134
|
if not silent:
|
|
109
135
|
self.__check_playbackmode_result(status)
|
|
110
136
|
return status
|
|
111
137
|
|
|
112
|
-
def stop_play(self, recording_and_namespace: List[Any], silent: bool = False) ->
|
|
138
|
+
def stop_play(self, recording_and_namespace: List[Any], silent: bool = False) -> traffic_api.PlaybackInfos:
|
|
113
139
|
def to_playback(rec: Any) -> Dict[str, Any]:
|
|
114
140
|
return {
|
|
115
141
|
"namespace": rec["namespace"],
|
|
116
142
|
"path": rec["recording"],
|
|
117
|
-
"mode":
|
|
143
|
+
"mode": traffic_api.Mode.STOP,
|
|
118
144
|
}
|
|
119
145
|
|
|
120
146
|
playback_list = map(to_playback, recording_and_namespace)
|
|
121
147
|
|
|
122
|
-
status = self.traffic_stub.PlayTraffic(
|
|
123
|
-
|
|
148
|
+
status: traffic_api.PlaybackInfos = self.traffic_stub.PlayTraffic(
|
|
149
|
+
traffic_api.PlaybackInfos(playbackInfo=list(map(self.__create_playback_config, playback_list)))
|
|
124
150
|
)
|
|
125
151
|
if not silent:
|
|
126
152
|
self.__check_playbackmode_result(status)
|
|
127
153
|
return status
|
|
128
154
|
|
|
129
|
-
def pause_play(self, recording_and_namespace: List[Any], silent: bool = False) ->
|
|
155
|
+
def pause_play(self, recording_and_namespace: List[Any], silent: bool = False) -> traffic_api.PlaybackInfos:
|
|
130
156
|
def to_playback(rec: Any) -> Dict[str, Any]:
|
|
131
157
|
return {
|
|
132
158
|
"namespace": rec["namespace"],
|
|
133
159
|
"path": rec["recording"],
|
|
134
|
-
"mode":
|
|
160
|
+
"mode": traffic_api.Mode.PAUSE,
|
|
135
161
|
}
|
|
136
162
|
|
|
137
163
|
playback_list = map(to_playback, recording_and_namespace)
|
|
138
164
|
|
|
139
|
-
status = self.traffic_stub.PlayTraffic(
|
|
140
|
-
|
|
165
|
+
status: traffic_api.PlaybackInfos = self.traffic_stub.PlayTraffic(
|
|
166
|
+
traffic_api.PlaybackInfos(playbackInfo=list(map(self.__create_playback_config, playback_list)))
|
|
141
167
|
)
|
|
142
168
|
if not silent:
|
|
143
169
|
self.__check_playbackmode_result(status)
|
|
144
170
|
return status
|
|
145
171
|
|
|
146
|
-
def record_multiple(self, namespaces: List[str], path: str) ->
|
|
172
|
+
def record_multiple(self, namespaces: List[str], path: str) -> traffic_api.PlaybackInfos:
|
|
147
173
|
def to_playback(namespace: str) -> Dict[str, Any]:
|
|
148
174
|
return {
|
|
149
175
|
"namespace": namespace,
|
|
150
176
|
"path": path + "_" + namespace,
|
|
151
|
-
"mode":
|
|
177
|
+
"mode": traffic_api.Mode.RECORD,
|
|
152
178
|
}
|
|
153
179
|
|
|
154
180
|
playback_list = list(map(to_playback, namespaces))
|
|
155
181
|
|
|
156
|
-
status = self.traffic_stub.PlayTraffic(
|
|
157
|
-
|
|
182
|
+
status: traffic_api.PlaybackInfos = self.traffic_stub.PlayTraffic(
|
|
183
|
+
traffic_api.PlaybackInfos(playbackInfo=list(map(self.__create_playback_config, playback_list)))
|
|
158
184
|
)
|
|
159
185
|
self.__check_playbackmode_result(status)
|
|
160
186
|
return status
|
|
161
187
|
|
|
162
|
-
def record(self, namespace: str, path: str) ->
|
|
188
|
+
def record(self, namespace: str, path: str) -> traffic_api.PlaybackInfos:
|
|
163
189
|
playback_list = [
|
|
164
190
|
{
|
|
165
191
|
"namespace": namespace,
|
|
166
192
|
"path": path,
|
|
167
|
-
"mode":
|
|
193
|
+
"mode": traffic_api.Mode.RECORD,
|
|
168
194
|
}
|
|
169
195
|
]
|
|
170
196
|
|
|
171
|
-
status = self.traffic_stub.PlayTraffic(
|
|
172
|
-
|
|
197
|
+
status: traffic_api.PlaybackInfos = self.traffic_stub.PlayTraffic(
|
|
198
|
+
traffic_api.PlaybackInfos(playbackInfo=list(map(self.__create_playback_config, playback_list)))
|
|
173
199
|
)
|
|
174
200
|
self.__check_playbackmode_result(status)
|
|
175
201
|
return status
|
|
176
202
|
|
|
177
|
-
def stop(self, namespace: str, path: str, silent: bool = False) ->
|
|
203
|
+
def stop(self, namespace: str, path: str, silent: bool = False) -> traffic_api.PlaybackInfos:
|
|
178
204
|
playback_list = [
|
|
179
205
|
{
|
|
180
206
|
"namespace": namespace,
|
|
181
207
|
"path": path,
|
|
182
|
-
"mode":
|
|
208
|
+
"mode": traffic_api.Mode.STOP,
|
|
183
209
|
}
|
|
184
210
|
]
|
|
185
211
|
|
|
186
212
|
status: traffic_api.PlaybackInfos = self.traffic_stub.PlayTraffic(
|
|
187
|
-
|
|
213
|
+
traffic_api.PlaybackInfos(playbackInfo=list(map(self.__create_playback_config, playback_list)))
|
|
188
214
|
)
|
|
189
215
|
if not silent:
|
|
190
216
|
self.__check_playbackmode_result(status)
|
|
@@ -202,7 +228,7 @@ class Broker:
|
|
|
202
228
|
return "stopped"
|
|
203
229
|
raise ValueError("Unknown Mode")
|
|
204
230
|
|
|
205
|
-
sub = self.traffic_stub.PlayTrafficStatus(
|
|
231
|
+
sub = self.traffic_stub.PlayTrafficStatus(common.Empty())
|
|
206
232
|
for playback_state in sub:
|
|
207
233
|
# p = typing.cast(br.traffic_api_pb2.PlaybackInfos, playback_state) # REDUNDANT CAST
|
|
208
234
|
p = playback_state
|
|
@@ -221,40 +247,40 @@ class Broker:
|
|
|
221
247
|
callback(offset_length, total_length, get_mode(mode))
|
|
222
248
|
|
|
223
249
|
def listen_on_frame_distribution(self, namespace: str, callback: Callable[[Dict[str, Any]], None]) -> None:
|
|
224
|
-
config = network_api.FramesDistributionConfig(namespace=
|
|
250
|
+
config = network_api.FramesDistributionConfig(namespace=common.NameSpace(name=namespace))
|
|
225
251
|
frame_distribution_stream = self.network_stub.SubscribeToFramesDistribution(config)
|
|
226
252
|
for frame in frame_distribution_stream:
|
|
227
|
-
f = MessageToDict(frame,
|
|
253
|
+
f = MessageToDict(frame, preserving_proto_field_name=True)
|
|
228
254
|
callback(f)
|
|
229
255
|
|
|
230
|
-
def pause(self, namespace: str, path: str, silent: bool = False) ->
|
|
256
|
+
def pause(self, namespace: str, path: str, silent: bool = False) -> traffic_api.PlaybackInfos:
|
|
231
257
|
playback_list = [
|
|
232
258
|
{
|
|
233
259
|
"namespace": namespace,
|
|
234
260
|
"path": path,
|
|
235
|
-
"mode":
|
|
261
|
+
"mode": traffic_api.Mode.PAUSE,
|
|
236
262
|
}
|
|
237
263
|
]
|
|
238
264
|
|
|
239
265
|
status: traffic_api.PlaybackInfos = self.traffic_stub.PlayTraffic(
|
|
240
|
-
|
|
266
|
+
traffic_api.PlaybackInfos(playbackInfo=list(map(self.__create_playback_config, playback_list)))
|
|
241
267
|
)
|
|
242
268
|
if not silent:
|
|
243
269
|
self.__check_playbackmode_result(status)
|
|
244
270
|
return status
|
|
245
271
|
|
|
246
|
-
def stop_multiple(self, namespaces: List[str], path: str) ->
|
|
272
|
+
def stop_multiple(self, namespaces: List[str], path: str) -> traffic_api.PlaybackInfos:
|
|
247
273
|
def to_playback(namespace: str) -> Dict[str, Any]:
|
|
248
274
|
return {
|
|
249
275
|
"namespace": namespace,
|
|
250
276
|
"path": path + "_" + namespace,
|
|
251
|
-
"mode":
|
|
277
|
+
"mode": traffic_api.Mode.STOP,
|
|
252
278
|
}
|
|
253
279
|
|
|
254
280
|
playback_list = list(map(to_playback, namespaces))
|
|
255
281
|
|
|
256
|
-
status = self.traffic_stub.PlayTraffic(
|
|
257
|
-
|
|
282
|
+
status: traffic_api.PlaybackInfos = self.traffic_stub.PlayTraffic(
|
|
283
|
+
traffic_api.PlaybackInfos(playbackInfo=list(map(self.__create_playback_config, playback_list)))
|
|
258
284
|
)
|
|
259
285
|
self.__check_playbackmode_result(status)
|
|
260
286
|
return status
|
|
@@ -302,66 +328,69 @@ class Broker:
|
|
|
302
328
|
|
|
303
329
|
for r in response:
|
|
304
330
|
if r["data"]:
|
|
305
|
-
|
|
331
|
+
print_success(f"Received traffic on {r['namespace']}")
|
|
306
332
|
keep_running = False
|
|
307
333
|
elif not wait_for_traffic or (not keep_running and not keep_running_during_recording):
|
|
308
|
-
|
|
334
|
+
print_generic_error(f"Namespace {r['namespace']} did not receive any traffic")
|
|
309
335
|
|
|
310
336
|
def upload(self, file: str, dest: str) -> None:
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
337
|
+
sha256 = get_sha256(file)
|
|
338
|
+
with open(file, "rb") as f:
|
|
339
|
+
upload_iterator = generate_data(f, dest.replace(ntpath.sep, posixpath.sep), 1000000, sha256)
|
|
340
|
+
try:
|
|
341
|
+
self.system_stub.UploadFile(upload_iterator, compression=grpc.Compression.Gzip)
|
|
342
|
+
except grpc.RpcError as rpc_error:
|
|
343
|
+
print_generic_error(f"Failed to upload file - {rpc_error.details()} ({rpc_error.code()})")
|
|
344
|
+
raise typer.Exit(1)
|
|
316
345
|
|
|
317
346
|
def delete_files(self, path: List[str], exit_on_faliure: bool) -> None:
|
|
318
347
|
for file in path:
|
|
319
348
|
try:
|
|
320
349
|
self.system_stub.BatchDeleteFiles(
|
|
321
|
-
|
|
322
|
-
fileDescriptions=[br.system_api_pb2.FileDescription(path=file.replace(ntpath.sep, posixpath.sep))]
|
|
323
|
-
)
|
|
350
|
+
system_api.FileDescriptions(fileDescriptions=[system_api.FileDescription(path=file.replace(ntpath.sep, posixpath.sep))])
|
|
324
351
|
)
|
|
325
352
|
except grpc.RpcError as rpc_error:
|
|
326
|
-
|
|
353
|
+
print_generic_error(f"Failed to delete file - {rpc_error.details()} ({rpc_error.code()})")
|
|
327
354
|
if exit_on_faliure:
|
|
328
355
|
raise typer.Exit(1)
|
|
329
356
|
|
|
330
|
-
# rpc BatchDeleteFiles (FileDescriptions) returns (Empty) {}
|
|
331
|
-
|
|
332
357
|
def upload_folder(self, folder: str) -> None:
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
raise typer.Exit(1)
|
|
358
|
+
files = [y for x in os.walk(folder) for y in glob(os.path.join(x[0], "*")) if not os.path.isdir(y)]
|
|
359
|
+
assert len(files) != 0, "Specified upload folder is empty or does not exist"
|
|
360
|
+
for file in files:
|
|
361
|
+
self.upload(file, file.replace(folder, ""))
|
|
338
362
|
|
|
339
363
|
def download(self, file: str, dest: str, delegate_err: bool = False) -> None:
|
|
340
364
|
try:
|
|
341
|
-
|
|
365
|
+
with open(dest, "wb") as f:
|
|
366
|
+
for response in self.system_stub.BatchDownloadFiles(
|
|
367
|
+
system_api.FileDescriptions(fileDescriptions=[system_api.FileDescription(path=file.replace(ntpath.sep, posixpath.sep))])
|
|
368
|
+
):
|
|
369
|
+
assert not response.HasField("errorMessage"), f"Error uploading file, message is: {response.errorMessage}"
|
|
370
|
+
f.write(response.chunk)
|
|
342
371
|
except grpc.RpcError as rpc_error:
|
|
343
372
|
if delegate_err:
|
|
344
373
|
raise rpc_error
|
|
345
|
-
|
|
374
|
+
print_generic_error(f"Failed to download file - {rpc_error.details()} ({rpc_error.code()})")
|
|
346
375
|
# There will be an empty file if the download fails so remove that one here
|
|
347
376
|
os.remove(dest)
|
|
348
377
|
raise typer.Exit(1)
|
|
349
378
|
|
|
350
379
|
def reload_config(self) -> None:
|
|
351
380
|
try:
|
|
352
|
-
request =
|
|
381
|
+
request = common.Empty()
|
|
353
382
|
response = self.system_stub.ReloadConfiguration(request, timeout=60000)
|
|
354
383
|
if response.errorMessage:
|
|
355
|
-
|
|
384
|
+
print_generic_error(f"Failed to reload config: {response.errorMessage}")
|
|
356
385
|
raise typer.Exit(1)
|
|
357
386
|
# br.helper.reload_configuration(system_stub=self.system_stub)
|
|
358
387
|
except grpc.RpcError as rpc_error:
|
|
359
|
-
|
|
388
|
+
print_generic_error(f"Failed to reload configuration - {rpc_error.details()} ({rpc_error.code()})")
|
|
360
389
|
raise typer.Exit(1)
|
|
361
390
|
|
|
362
391
|
def list_namespaces(self) -> List[str]:
|
|
363
392
|
# Lists available signals
|
|
364
|
-
configuration = self.system_stub.GetConfiguration(
|
|
393
|
+
configuration = self.system_stub.GetConfiguration(common.Empty())
|
|
365
394
|
namespaces = []
|
|
366
395
|
for network_info in configuration.networkInfo:
|
|
367
396
|
namespaces.append(network_info.namespace.name)
|
|
@@ -369,7 +398,7 @@ class Broker:
|
|
|
369
398
|
|
|
370
399
|
def list_signal_names(self, prefix: Union[str, None], suffix: Union[str, None]) -> List[Dict[str, Any]]:
|
|
371
400
|
# Lists available signals
|
|
372
|
-
configuration = self.system_stub.GetConfiguration(
|
|
401
|
+
configuration = self.system_stub.GetConfiguration(common.Empty())
|
|
373
402
|
|
|
374
403
|
signal_names = []
|
|
375
404
|
for network_info in configuration.networkInfo:
|
|
@@ -380,7 +409,6 @@ class Broker:
|
|
|
380
409
|
):
|
|
381
410
|
metadata_dict = MessageToDict(
|
|
382
411
|
finfo.signalInfo.metaData,
|
|
383
|
-
including_default_value_fields=True,
|
|
384
412
|
preserving_proto_field_name=True,
|
|
385
413
|
)
|
|
386
414
|
sig_dict = {
|
|
@@ -398,7 +426,6 @@ class Broker:
|
|
|
398
426
|
|
|
399
427
|
metadata_dict = MessageToDict(
|
|
400
428
|
sinfo.metaData,
|
|
401
|
-
including_default_value_fields=True,
|
|
402
429
|
preserving_proto_field_name=True,
|
|
403
430
|
)
|
|
404
431
|
sig_dict = {
|
|
@@ -412,13 +439,12 @@ class Broker:
|
|
|
412
439
|
def subscribe_on_script(
|
|
413
440
|
self,
|
|
414
441
|
script: bytes,
|
|
415
|
-
on_frame: Callable[[Sequence[
|
|
442
|
+
on_frame: Callable[[Sequence[network_api.Signal]], None],
|
|
416
443
|
changed_values_only: bool = False,
|
|
417
444
|
) -> Any:
|
|
418
|
-
client_id =
|
|
419
|
-
# sync = queue.Queue()
|
|
445
|
+
client_id = common.ClientId(id="cli")
|
|
420
446
|
thread = Thread(
|
|
421
|
-
target=
|
|
447
|
+
target=act_on_scripted_signal,
|
|
422
448
|
args=(
|
|
423
449
|
client_id,
|
|
424
450
|
self.network_stub,
|
|
@@ -454,7 +480,7 @@ class Broker:
|
|
|
454
480
|
if ns not in existing_ns:
|
|
455
481
|
ns_not_matching.append(ns)
|
|
456
482
|
if len(ns_not_matching) > 0:
|
|
457
|
-
|
|
483
|
+
print_hint(f"Namespace(s) {ns_not_matching} does not exist on broker. Namespaces found on broker: {existing_ns}")
|
|
458
484
|
sys.exit(1)
|
|
459
485
|
|
|
460
486
|
available_signals = list(filter(verify_namespace, existing_signals)) # type: ignore
|
|
@@ -464,7 +490,7 @@ class Broker:
|
|
|
464
490
|
signals_subscribed_to_but_does_not_exist = set(subscribed_signals) - set(map(lambda s: s["signal"], signals_to_subscribe_to))
|
|
465
491
|
|
|
466
492
|
if len(signals_subscribed_to_but_does_not_exist) > 0:
|
|
467
|
-
|
|
493
|
+
print_hint(f"One or more signals you subscribed to does not exist {signals_subscribed_to_but_does_not_exist}")
|
|
468
494
|
sys.exit(1)
|
|
469
495
|
|
|
470
496
|
return list(map(lambda s: SubscribableSignal(s["signal"], s["namespace"]), signals_to_subscribe_to))
|
|
@@ -472,20 +498,20 @@ class Broker:
|
|
|
472
498
|
def long_name_subscribe(
|
|
473
499
|
self, signals_to_subscribe_to: List[SubscribableSignal], on_frame: Callable[..., Any], changed_values_only: bool = True
|
|
474
500
|
) -> Any:
|
|
475
|
-
client_id =
|
|
501
|
+
client_id = common.ClientId(id="cli")
|
|
476
502
|
|
|
477
503
|
# TODO - This can be improved moving forward and we also need to move the validation into api
|
|
478
504
|
self.validate_and_get_subscribed_signals(
|
|
479
505
|
list(map(lambda s: s.namespace, signals_to_subscribe_to)), (list(map(lambda s: s.name, signals_to_subscribe_to)))
|
|
480
506
|
)
|
|
481
507
|
|
|
482
|
-
def to_protobuf_signal(s: SubscribableSignal) ->
|
|
508
|
+
def to_protobuf_signal(s: SubscribableSignal) -> common.SignalId:
|
|
483
509
|
return self.signal_creator.signal(s.name, s.namespace)
|
|
484
510
|
|
|
485
511
|
signals_to_subscribe_on = list(map(to_protobuf_signal, signals_to_subscribe_to))
|
|
486
512
|
|
|
487
513
|
Thread(
|
|
488
|
-
target=
|
|
514
|
+
target=act_on_signal,
|
|
489
515
|
args=(
|
|
490
516
|
client_id,
|
|
491
517
|
self.network_stub,
|
|
@@ -506,19 +532,19 @@ class Broker:
|
|
|
506
532
|
on_frame: Callable[..., Any],
|
|
507
533
|
changed_values_only: bool = True,
|
|
508
534
|
) -> Any:
|
|
509
|
-
client_id =
|
|
535
|
+
client_id = common.ClientId(id="cli")
|
|
510
536
|
|
|
511
537
|
signals_to_subscribe_to: List[SubscribableSignal] = self.validate_and_get_subscribed_signals(
|
|
512
538
|
subscribed_namespaces, subscribed_signals
|
|
513
539
|
)
|
|
514
540
|
|
|
515
|
-
def to_protobuf_signal(s: SubscribableSignal) ->
|
|
541
|
+
def to_protobuf_signal(s: SubscribableSignal) -> common.SignalId:
|
|
516
542
|
return self.signal_creator.signal(s.name, s.namespace)
|
|
517
543
|
|
|
518
544
|
signals_to_subscribe_on = list(map(to_protobuf_signal, signals_to_subscribe_to))
|
|
519
545
|
|
|
520
546
|
Thread(
|
|
521
|
-
target=
|
|
547
|
+
target=act_on_signal,
|
|
522
548
|
args=(
|
|
523
549
|
client_id,
|
|
524
550
|
self.network_stub,
|
|
@@ -532,7 +558,7 @@ class Broker:
|
|
|
532
558
|
ecu, subscription = self.q.get()
|
|
533
559
|
return subscription
|
|
534
560
|
|
|
535
|
-
def __each_signal(self, signals: Iterable[
|
|
561
|
+
def __each_signal(self, signals: Iterable[network_api.Signal], callback: Callable[..., Any]) -> None:
|
|
536
562
|
callback(
|
|
537
563
|
map(
|
|
538
564
|
lambda s: {"timestamp_us": s.timestamp, "namespace": s.id.namespace.name, "name": s.id.name, "value": self.__get_value(s)},
|
|
@@ -541,7 +567,7 @@ class Broker:
|
|
|
541
567
|
)
|
|
542
568
|
|
|
543
569
|
@staticmethod
|
|
544
|
-
def __get_value(signal:
|
|
570
|
+
def __get_value(signal: network_api.Signal) -> Any:
|
|
545
571
|
if signal.raw != b"":
|
|
546
572
|
return "0x" + binascii.hexlify(signal.raw).decode("ascii")
|
|
547
573
|
if signal.HasField("integer"):
|
|
@@ -553,7 +579,7 @@ class Broker:
|
|
|
553
579
|
return "empty"
|
|
554
580
|
|
|
555
581
|
@staticmethod
|
|
556
|
-
def __create_playback_config(item: Dict[str, Any]) ->
|
|
582
|
+
def __create_playback_config(item: Dict[str, Any]) -> traffic_api.PlaybackInfo:
|
|
557
583
|
"""Creating configuration for playback
|
|
558
584
|
|
|
559
585
|
Parameters
|
|
@@ -573,26 +599,26 @@ class Broker:
|
|
|
573
599
|
return int(item["offsettime"])
|
|
574
600
|
return 0
|
|
575
601
|
|
|
576
|
-
playback_config =
|
|
577
|
-
fileDescription=
|
|
578
|
-
namespace=
|
|
602
|
+
playback_config = traffic_api.PlaybackConfig(
|
|
603
|
+
fileDescription=system_api.FileDescription(path=item["path"]),
|
|
604
|
+
namespace=common.NameSpace(name=item["namespace"]),
|
|
579
605
|
)
|
|
580
|
-
return
|
|
606
|
+
return traffic_api.PlaybackInfo(
|
|
581
607
|
playbackConfig=playback_config,
|
|
582
|
-
playbackMode=
|
|
608
|
+
playbackMode=traffic_api.PlaybackMode(mode=item["mode"], offsetTime=get_offset_time()),
|
|
583
609
|
)
|
|
584
610
|
|
|
585
611
|
def get_license(self) -> LicenseInfo:
|
|
586
|
-
license_info = self.system_stub.GetLicenseInfo(
|
|
612
|
+
license_info = self.system_stub.GetLicenseInfo(common.Empty())
|
|
587
613
|
return LicenseInfo(
|
|
588
|
-
valid=license_info.status ==
|
|
614
|
+
valid=license_info.status == system_api.LicenseStatus.VALID,
|
|
589
615
|
expires=license_info.expires,
|
|
590
616
|
email=license_info.requestId,
|
|
591
617
|
machine_id=license_info.requestMachineId.decode("utf-8"),
|
|
592
618
|
)
|
|
593
619
|
|
|
594
620
|
def apply_license(self, license_data_b64: bytes) -> LicenseInfo:
|
|
595
|
-
license =
|
|
621
|
+
license = system_api.License()
|
|
596
622
|
license.data = license_data_b64
|
|
597
623
|
license.termsAgreement = True
|
|
598
624
|
self.system_stub.SetLicense(license)
|