remotivelabs-cli 0.2.2__tar.gz → 0.3.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.
Potentially problematic release.
This version of remotivelabs-cli might be problematic. Click here for more details.
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/PKG-INFO +3 -3
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/broker/lib/broker.py +120 -89
- remotivelabs_cli-0.3.0/cli/broker/lib/client.py +224 -0
- remotivelabs_cli-0.3.0/cli/broker/lib/helper.py +278 -0
- remotivelabs_cli-0.3.0/cli/broker/lib/signalcreator.py +196 -0
- remotivelabs_cli-0.2.2/cli/cloud/cloud_cli.py → remotivelabs_cli-0.3.0/cli/cloud/__init__.py +2 -14
- remotivelabs_cli-0.3.0/cli/cloud/auth/cmd.py +126 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/cloud/auth/login.py +26 -28
- remotivelabs_cli-0.3.0/cli/cloud/auth_tokens.py +143 -0
- remotivelabs_cli-0.3.0/cli/cloud/licenses/cmd.py +14 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/cloud/organisations.py +8 -12
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/cloud/service_account_tokens.py +1 -1
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/connect/protopie/protopie.py +1 -1
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/remotive.py +17 -26
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/settings/__init__.py +1 -2
- remotivelabs_cli-0.3.0/cli/settings/config_file.py +113 -0
- remotivelabs_cli-0.3.0/cli/settings/core.py +320 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/settings/migration/migrate_config_file.py +15 -10
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/settings/migration/migration_tools.py +4 -3
- remotivelabs_cli-0.3.0/cli/settings/state_file.py +67 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/settings/token_file.py +13 -21
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/topology/cmd.py +6 -6
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/utils/rest_helper.py +20 -28
- remotivelabs_cli-0.2.2/cli/utils/version_check.py → remotivelabs_cli-0.3.0/cli/utils/versions.py +30 -20
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/pyproject.toml +3 -3
- remotivelabs_cli-0.2.2/cli/cloud/auth/cmd.py +0 -88
- remotivelabs_cli-0.2.2/cli/cloud/auth_tokens.py +0 -355
- remotivelabs_cli-0.2.2/cli/settings/config_file.py +0 -93
- remotivelabs_cli-0.2.2/cli/settings/core.py +0 -315
- remotivelabs_cli-0.2.2/cli/settings/state_file.py +0 -32
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/LICENSE +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/README.md +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/.DS_Store +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/__init__.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/api/cloud/tokens.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/broker/brokers.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/broker/export.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/broker/files.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/broker/lib/__about__.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/broker/license_flows.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/broker/licenses.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/broker/playback.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/broker/record.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/broker/scripting.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/broker/signals.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/cloud/auth/__init__.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/cloud/brokers.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/cloud/configs.py +0 -0
- {remotivelabs_cli-0.2.2/cli/cloud → remotivelabs_cli-0.3.0/cli/cloud/licenses}/__init__.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/cloud/projects.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/cloud/recordings.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/cloud/recordings_playback.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/cloud/resumable_upload.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/cloud/sample_recordings.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/cloud/service_accounts.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/cloud/storage/__init__.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/cloud/storage/cmd.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/cloud/storage/copy.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/cloud/storage/uri_or_path.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/cloud/uri.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/connect/__init__.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/connect/connect.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/errors.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/settings/migration/__init__.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/settings/migration/migrate_all_token_files.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/settings/migration/migrate_legacy_dirs.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/settings/migration/migrate_token_file.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/tools/__init__.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/tools/can/__init__.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/tools/can/can.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/tools/tools.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/typer/__init__.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/typer/typer_utils.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/utils/__init__.py +0 -0
- {remotivelabs_cli-0.2.2 → remotivelabs_cli-0.3.0}/cli/utils/time.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: remotivelabs-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: CLI for operating RemotiveCloud and RemotiveBroker
|
|
5
5
|
Author: Johan Rask
|
|
6
6
|
Author-email: johan.rask@remotivelabs.com
|
|
@@ -12,7 +12,6 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.12
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.13
|
|
14
14
|
Requires-Dist: click (<8.2.0)
|
|
15
|
-
Requires-Dist: dacite (>=1.9.2,<2.0.0)
|
|
16
15
|
Requires-Dist: email-validator (>=2.2.0,<3.0.0)
|
|
17
16
|
Requires-Dist: grpc-stubs (>=1.53.0.5)
|
|
18
17
|
Requires-Dist: mypy-protobuf (>=3.0.0)
|
|
@@ -21,7 +20,8 @@ Requires-Dist: pydantic (>=2.11.7,<3.0.0)
|
|
|
21
20
|
Requires-Dist: pyjwt (>=2.6,<3.0)
|
|
22
21
|
Requires-Dist: python-can (>=4.3.1)
|
|
23
22
|
Requires-Dist: python-socketio (>=4.6.1)
|
|
24
|
-
Requires-Dist: remotivelabs-broker (>=0.1
|
|
23
|
+
Requires-Dist: remotivelabs-broker (>=0.9.1,<0.10.0)
|
|
24
|
+
Requires-Dist: requests (>=2.32.4,<3.0.0)
|
|
25
25
|
Requires-Dist: rich (>=13.7.0,<13.8.0)
|
|
26
26
|
Requires-Dist: trogon (>=0.5.0)
|
|
27
27
|
Requires-Dist: typer (==0.12.5)
|
|
@@ -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,18 +13,24 @@ 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
30
|
from rich.console import Console
|
|
25
31
|
|
|
32
|
+
from cli.broker.lib.helper import act_on_scripted_signal, act_on_signal, create_channel
|
|
33
|
+
from cli.broker.lib.signalcreator import SignalCreator
|
|
26
34
|
from cli.errors import ErrorPrinter
|
|
27
35
|
from cli.settings import settings
|
|
28
36
|
|
|
@@ -43,6 +51,27 @@ class LicenseInfo:
|
|
|
43
51
|
machine_id: str
|
|
44
52
|
|
|
45
53
|
|
|
54
|
+
def get_sha256(path: str) -> str:
|
|
55
|
+
"""
|
|
56
|
+
Calculate SHA256 for a file.
|
|
57
|
+
"""
|
|
58
|
+
with open(path, "rb") as f:
|
|
59
|
+
b = f.read() # read entire file as bytes
|
|
60
|
+
return hashlib.sha256(b).hexdigest()
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def generate_data(file: BinaryIO, dest_path: str, chunk_size: int, sha256: str) -> Generator[system_api.FileUploadRequest, None, None]:
|
|
64
|
+
for x in itertools.count(start=0):
|
|
65
|
+
if x == 0:
|
|
66
|
+
file_description = system_api.FileDescription(sha256=sha256, path=dest_path)
|
|
67
|
+
yield system_api.FileUploadRequest(fileDescription=file_description)
|
|
68
|
+
else:
|
|
69
|
+
buf = file.read(chunk_size)
|
|
70
|
+
if not buf:
|
|
71
|
+
break
|
|
72
|
+
yield system_api.FileUploadRequest(chunk=buf)
|
|
73
|
+
|
|
74
|
+
|
|
46
75
|
class Broker:
|
|
47
76
|
def __init__(self, url: str, api_key: Union[str, None] = None) -> None:
|
|
48
77
|
self.url = url
|
|
@@ -53,24 +82,24 @@ class Broker:
|
|
|
53
82
|
|
|
54
83
|
if api_key is None or api_key == "":
|
|
55
84
|
if url.startswith("https"):
|
|
56
|
-
self.intercept_channel =
|
|
85
|
+
self.intercept_channel = create_channel(url, None, settings.get_active_token())
|
|
57
86
|
# TODO - Temporary solution to print proper error message, remove ENV once api-key is gone
|
|
58
87
|
os.environ["ACCESS_TOKEN"] = "true"
|
|
59
88
|
else:
|
|
60
89
|
os.environ["ACCESS_TOKEN"] = "false"
|
|
61
|
-
self.intercept_channel =
|
|
90
|
+
self.intercept_channel = create_channel(url, None, None)
|
|
62
91
|
else:
|
|
63
92
|
err_console.print("Option --api-key will is deprecated and will be removed. Use access access tokens by logging in with cli.")
|
|
64
93
|
os.environ["ACCESS_TOKEN"] = "false"
|
|
65
|
-
self.intercept_channel =
|
|
94
|
+
self.intercept_channel = create_channel(url, api_key, None)
|
|
66
95
|
|
|
67
|
-
self.network_stub =
|
|
68
|
-
self.system_stub =
|
|
69
|
-
self.traffic_stub =
|
|
70
|
-
self.signal_creator =
|
|
96
|
+
self.network_stub = network_api_grpc.NetworkServiceStub(self.intercept_channel)
|
|
97
|
+
self.system_stub = system_api_grpc.SystemServiceStub(self.intercept_channel)
|
|
98
|
+
self.traffic_stub = traffic_api_grpc.TrafficServiceStub(self.intercept_channel)
|
|
99
|
+
self.signal_creator = SignalCreator(self.system_stub)
|
|
71
100
|
|
|
72
101
|
@staticmethod
|
|
73
|
-
def __check_playbackmode_result(status:
|
|
102
|
+
def __check_playbackmode_result(status: traffic_api.PlaybackInfos) -> None:
|
|
74
103
|
err_cnt = 0
|
|
75
104
|
for mode in status.playbackInfo:
|
|
76
105
|
if mode.playbackMode.errorMessage:
|
|
@@ -79,112 +108,112 @@ class Broker:
|
|
|
79
108
|
if err_cnt > 0:
|
|
80
109
|
raise typer.Exit(1)
|
|
81
110
|
|
|
82
|
-
def seek(self, recording_and_namespace: List[Any], offset: int, silent: bool = True) ->
|
|
111
|
+
def seek(self, recording_and_namespace: List[Any], offset: int, silent: bool = True) -> traffic_api.PlaybackInfos:
|
|
83
112
|
def to_playback(rec: Any) -> Dict[str, Any]:
|
|
84
|
-
return {"namespace": rec["namespace"], "path": rec["recording"], "mode":
|
|
113
|
+
return {"namespace": rec["namespace"], "path": rec["recording"], "mode": traffic_api.Mode.SEEK, "offsettime": offset}
|
|
85
114
|
|
|
86
115
|
playback_list = map(to_playback, recording_and_namespace)
|
|
87
116
|
|
|
88
|
-
infos =
|
|
89
|
-
status = self.traffic_stub.PlayTraffic(infos)
|
|
117
|
+
infos = traffic_api.PlaybackInfos(playbackInfo=list(map(self.__create_playback_config, playback_list)))
|
|
118
|
+
status: traffic_api.PlaybackInfos = self.traffic_stub.PlayTraffic(infos)
|
|
90
119
|
if not silent:
|
|
91
120
|
self.__check_playbackmode_result(status)
|
|
92
121
|
return status
|
|
93
122
|
|
|
94
|
-
def play(self, recording_and_namespace: List[Any], silent: bool = False) ->
|
|
123
|
+
def play(self, recording_and_namespace: List[Any], silent: bool = False) -> traffic_api.PlaybackInfos:
|
|
95
124
|
def to_playback(rec: Any) -> Dict[str, Any]:
|
|
96
125
|
return {
|
|
97
126
|
"namespace": rec["namespace"],
|
|
98
127
|
"path": rec["recording"],
|
|
99
|
-
"mode":
|
|
128
|
+
"mode": traffic_api.Mode.PLAY,
|
|
100
129
|
}
|
|
101
130
|
|
|
102
131
|
playback_list = map(to_playback, recording_and_namespace)
|
|
103
132
|
|
|
104
|
-
status = self.traffic_stub.PlayTraffic(
|
|
105
|
-
|
|
133
|
+
status: traffic_api.PlaybackInfos = self.traffic_stub.PlayTraffic(
|
|
134
|
+
traffic_api.PlaybackInfos(playbackInfo=list(map(self.__create_playback_config, playback_list)))
|
|
106
135
|
)
|
|
107
136
|
|
|
108
137
|
if not silent:
|
|
109
138
|
self.__check_playbackmode_result(status)
|
|
110
139
|
return status
|
|
111
140
|
|
|
112
|
-
def stop_play(self, recording_and_namespace: List[Any], silent: bool = False) ->
|
|
141
|
+
def stop_play(self, recording_and_namespace: List[Any], silent: bool = False) -> traffic_api.PlaybackInfos:
|
|
113
142
|
def to_playback(rec: Any) -> Dict[str, Any]:
|
|
114
143
|
return {
|
|
115
144
|
"namespace": rec["namespace"],
|
|
116
145
|
"path": rec["recording"],
|
|
117
|
-
"mode":
|
|
146
|
+
"mode": traffic_api.Mode.STOP,
|
|
118
147
|
}
|
|
119
148
|
|
|
120
149
|
playback_list = map(to_playback, recording_and_namespace)
|
|
121
150
|
|
|
122
|
-
status = self.traffic_stub.PlayTraffic(
|
|
123
|
-
|
|
151
|
+
status: traffic_api.PlaybackInfos = self.traffic_stub.PlayTraffic(
|
|
152
|
+
traffic_api.PlaybackInfos(playbackInfo=list(map(self.__create_playback_config, playback_list)))
|
|
124
153
|
)
|
|
125
154
|
if not silent:
|
|
126
155
|
self.__check_playbackmode_result(status)
|
|
127
156
|
return status
|
|
128
157
|
|
|
129
|
-
def pause_play(self, recording_and_namespace: List[Any], silent: bool = False) ->
|
|
158
|
+
def pause_play(self, recording_and_namespace: List[Any], silent: bool = False) -> traffic_api.PlaybackInfos:
|
|
130
159
|
def to_playback(rec: Any) -> Dict[str, Any]:
|
|
131
160
|
return {
|
|
132
161
|
"namespace": rec["namespace"],
|
|
133
162
|
"path": rec["recording"],
|
|
134
|
-
"mode":
|
|
163
|
+
"mode": traffic_api.Mode.PAUSE,
|
|
135
164
|
}
|
|
136
165
|
|
|
137
166
|
playback_list = map(to_playback, recording_and_namespace)
|
|
138
167
|
|
|
139
|
-
status = self.traffic_stub.PlayTraffic(
|
|
140
|
-
|
|
168
|
+
status: traffic_api.PlaybackInfos = self.traffic_stub.PlayTraffic(
|
|
169
|
+
traffic_api.PlaybackInfos(playbackInfo=list(map(self.__create_playback_config, playback_list)))
|
|
141
170
|
)
|
|
142
171
|
if not silent:
|
|
143
172
|
self.__check_playbackmode_result(status)
|
|
144
173
|
return status
|
|
145
174
|
|
|
146
|
-
def record_multiple(self, namespaces: List[str], path: str) ->
|
|
175
|
+
def record_multiple(self, namespaces: List[str], path: str) -> traffic_api.PlaybackInfos:
|
|
147
176
|
def to_playback(namespace: str) -> Dict[str, Any]:
|
|
148
177
|
return {
|
|
149
178
|
"namespace": namespace,
|
|
150
179
|
"path": path + "_" + namespace,
|
|
151
|
-
"mode":
|
|
180
|
+
"mode": traffic_api.Mode.RECORD,
|
|
152
181
|
}
|
|
153
182
|
|
|
154
183
|
playback_list = list(map(to_playback, namespaces))
|
|
155
184
|
|
|
156
|
-
status = self.traffic_stub.PlayTraffic(
|
|
157
|
-
|
|
185
|
+
status: traffic_api.PlaybackInfos = self.traffic_stub.PlayTraffic(
|
|
186
|
+
traffic_api.PlaybackInfos(playbackInfo=list(map(self.__create_playback_config, playback_list)))
|
|
158
187
|
)
|
|
159
188
|
self.__check_playbackmode_result(status)
|
|
160
189
|
return status
|
|
161
190
|
|
|
162
|
-
def record(self, namespace: str, path: str) ->
|
|
191
|
+
def record(self, namespace: str, path: str) -> traffic_api.PlaybackInfos:
|
|
163
192
|
playback_list = [
|
|
164
193
|
{
|
|
165
194
|
"namespace": namespace,
|
|
166
195
|
"path": path,
|
|
167
|
-
"mode":
|
|
196
|
+
"mode": traffic_api.Mode.RECORD,
|
|
168
197
|
}
|
|
169
198
|
]
|
|
170
199
|
|
|
171
|
-
status = self.traffic_stub.PlayTraffic(
|
|
172
|
-
|
|
200
|
+
status: traffic_api.PlaybackInfos = self.traffic_stub.PlayTraffic(
|
|
201
|
+
traffic_api.PlaybackInfos(playbackInfo=list(map(self.__create_playback_config, playback_list)))
|
|
173
202
|
)
|
|
174
203
|
self.__check_playbackmode_result(status)
|
|
175
204
|
return status
|
|
176
205
|
|
|
177
|
-
def stop(self, namespace: str, path: str, silent: bool = False) ->
|
|
206
|
+
def stop(self, namespace: str, path: str, silent: bool = False) -> traffic_api.PlaybackInfos:
|
|
178
207
|
playback_list = [
|
|
179
208
|
{
|
|
180
209
|
"namespace": namespace,
|
|
181
210
|
"path": path,
|
|
182
|
-
"mode":
|
|
211
|
+
"mode": traffic_api.Mode.STOP,
|
|
183
212
|
}
|
|
184
213
|
]
|
|
185
214
|
|
|
186
215
|
status: traffic_api.PlaybackInfos = self.traffic_stub.PlayTraffic(
|
|
187
|
-
|
|
216
|
+
traffic_api.PlaybackInfos(playbackInfo=list(map(self.__create_playback_config, playback_list)))
|
|
188
217
|
)
|
|
189
218
|
if not silent:
|
|
190
219
|
self.__check_playbackmode_result(status)
|
|
@@ -202,7 +231,7 @@ class Broker:
|
|
|
202
231
|
return "stopped"
|
|
203
232
|
raise ValueError("Unknown Mode")
|
|
204
233
|
|
|
205
|
-
sub = self.traffic_stub.PlayTrafficStatus(
|
|
234
|
+
sub = self.traffic_stub.PlayTrafficStatus(common.Empty())
|
|
206
235
|
for playback_state in sub:
|
|
207
236
|
# p = typing.cast(br.traffic_api_pb2.PlaybackInfos, playback_state) # REDUNDANT CAST
|
|
208
237
|
p = playback_state
|
|
@@ -221,40 +250,40 @@ class Broker:
|
|
|
221
250
|
callback(offset_length, total_length, get_mode(mode))
|
|
222
251
|
|
|
223
252
|
def listen_on_frame_distribution(self, namespace: str, callback: Callable[[Dict[str, Any]], None]) -> None:
|
|
224
|
-
config = network_api.FramesDistributionConfig(namespace=
|
|
253
|
+
config = network_api.FramesDistributionConfig(namespace=common.NameSpace(name=namespace))
|
|
225
254
|
frame_distribution_stream = self.network_stub.SubscribeToFramesDistribution(config)
|
|
226
255
|
for frame in frame_distribution_stream:
|
|
227
256
|
f = MessageToDict(frame, including_default_value_fields=True, preserving_proto_field_name=True)
|
|
228
257
|
callback(f)
|
|
229
258
|
|
|
230
|
-
def pause(self, namespace: str, path: str, silent: bool = False) ->
|
|
259
|
+
def pause(self, namespace: str, path: str, silent: bool = False) -> traffic_api.PlaybackInfos:
|
|
231
260
|
playback_list = [
|
|
232
261
|
{
|
|
233
262
|
"namespace": namespace,
|
|
234
263
|
"path": path,
|
|
235
|
-
"mode":
|
|
264
|
+
"mode": traffic_api.Mode.PAUSE,
|
|
236
265
|
}
|
|
237
266
|
]
|
|
238
267
|
|
|
239
268
|
status: traffic_api.PlaybackInfos = self.traffic_stub.PlayTraffic(
|
|
240
|
-
|
|
269
|
+
traffic_api.PlaybackInfos(playbackInfo=list(map(self.__create_playback_config, playback_list)))
|
|
241
270
|
)
|
|
242
271
|
if not silent:
|
|
243
272
|
self.__check_playbackmode_result(status)
|
|
244
273
|
return status
|
|
245
274
|
|
|
246
|
-
def stop_multiple(self, namespaces: List[str], path: str) ->
|
|
275
|
+
def stop_multiple(self, namespaces: List[str], path: str) -> traffic_api.PlaybackInfos:
|
|
247
276
|
def to_playback(namespace: str) -> Dict[str, Any]:
|
|
248
277
|
return {
|
|
249
278
|
"namespace": namespace,
|
|
250
279
|
"path": path + "_" + namespace,
|
|
251
|
-
"mode":
|
|
280
|
+
"mode": traffic_api.Mode.STOP,
|
|
252
281
|
}
|
|
253
282
|
|
|
254
283
|
playback_list = list(map(to_playback, namespaces))
|
|
255
284
|
|
|
256
|
-
status = self.traffic_stub.PlayTraffic(
|
|
257
|
-
|
|
285
|
+
status: traffic_api.PlaybackInfos = self.traffic_stub.PlayTraffic(
|
|
286
|
+
traffic_api.PlaybackInfos(playbackInfo=list(map(self.__create_playback_config, playback_list)))
|
|
258
287
|
)
|
|
259
288
|
self.__check_playbackmode_result(status)
|
|
260
289
|
return status
|
|
@@ -308,37 +337,40 @@ class Broker:
|
|
|
308
337
|
print(f"Namespace {r['namespace']} did not receive any traffic")
|
|
309
338
|
|
|
310
339
|
def upload(self, file: str, dest: str) -> None:
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
340
|
+
sha256 = get_sha256(file)
|
|
341
|
+
with open(file, "rb") as f:
|
|
342
|
+
upload_iterator = generate_data(f, dest.replace(ntpath.sep, posixpath.sep), 1000000, sha256)
|
|
343
|
+
try:
|
|
344
|
+
self.system_stub.UploadFile(upload_iterator, compression=grpc.Compression.Gzip)
|
|
345
|
+
except grpc.RpcError as rpc_error:
|
|
346
|
+
print(f"Failed to upload file - {rpc_error.details()} ({rpc_error.code()})")
|
|
347
|
+
raise typer.Exit(1)
|
|
316
348
|
|
|
317
349
|
def delete_files(self, path: List[str], exit_on_faliure: bool) -> None:
|
|
318
350
|
for file in path:
|
|
319
351
|
try:
|
|
320
352
|
self.system_stub.BatchDeleteFiles(
|
|
321
|
-
|
|
322
|
-
fileDescriptions=[br.system_api_pb2.FileDescription(path=file.replace(ntpath.sep, posixpath.sep))]
|
|
323
|
-
)
|
|
353
|
+
system_api.FileDescriptions(fileDescriptions=[system_api.FileDescription(path=file.replace(ntpath.sep, posixpath.sep))])
|
|
324
354
|
)
|
|
325
355
|
except grpc.RpcError as rpc_error:
|
|
326
356
|
print(f"Failed to delete file - {rpc_error.details()} ({rpc_error.code()})")
|
|
327
357
|
if exit_on_faliure:
|
|
328
358
|
raise typer.Exit(1)
|
|
329
359
|
|
|
330
|
-
# rpc BatchDeleteFiles (FileDescriptions) returns (Empty) {}
|
|
331
|
-
|
|
332
360
|
def upload_folder(self, folder: str) -> None:
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
raise typer.Exit(1)
|
|
361
|
+
files = [y for x in os.walk(folder) for y in glob(os.path.join(x[0], "*")) if not os.path.isdir(y)]
|
|
362
|
+
assert len(files) != 0, "Specified upload folder is empty or does not exist"
|
|
363
|
+
for file in files:
|
|
364
|
+
self.upload(file, file.replace(folder, ""))
|
|
338
365
|
|
|
339
366
|
def download(self, file: str, dest: str, delegate_err: bool = False) -> None:
|
|
340
367
|
try:
|
|
341
|
-
|
|
368
|
+
with open(dest, "wb") as f:
|
|
369
|
+
for response in self.system_stub.BatchDownloadFiles(
|
|
370
|
+
system_api.FileDescriptions(fileDescriptions=[system_api.FileDescription(path=file.replace(ntpath.sep, posixpath.sep))])
|
|
371
|
+
):
|
|
372
|
+
assert not response.HasField("errorMessage"), f"Error uploading file, message is: {response.errorMessage}"
|
|
373
|
+
f.write(response.chunk)
|
|
342
374
|
except grpc.RpcError as rpc_error:
|
|
343
375
|
if delegate_err:
|
|
344
376
|
raise rpc_error
|
|
@@ -349,7 +381,7 @@ class Broker:
|
|
|
349
381
|
|
|
350
382
|
def reload_config(self) -> None:
|
|
351
383
|
try:
|
|
352
|
-
request =
|
|
384
|
+
request = common.Empty()
|
|
353
385
|
response = self.system_stub.ReloadConfiguration(request, timeout=60000)
|
|
354
386
|
if response.errorMessage:
|
|
355
387
|
print(f"Failed to reload config: {response.errorMessage}")
|
|
@@ -361,7 +393,7 @@ class Broker:
|
|
|
361
393
|
|
|
362
394
|
def list_namespaces(self) -> List[str]:
|
|
363
395
|
# Lists available signals
|
|
364
|
-
configuration = self.system_stub.GetConfiguration(
|
|
396
|
+
configuration = self.system_stub.GetConfiguration(common.Empty())
|
|
365
397
|
namespaces = []
|
|
366
398
|
for network_info in configuration.networkInfo:
|
|
367
399
|
namespaces.append(network_info.namespace.name)
|
|
@@ -369,7 +401,7 @@ class Broker:
|
|
|
369
401
|
|
|
370
402
|
def list_signal_names(self, prefix: Union[str, None], suffix: Union[str, None]) -> List[Dict[str, Any]]:
|
|
371
403
|
# Lists available signals
|
|
372
|
-
configuration = self.system_stub.GetConfiguration(
|
|
404
|
+
configuration = self.system_stub.GetConfiguration(common.Empty())
|
|
373
405
|
|
|
374
406
|
signal_names = []
|
|
375
407
|
for network_info in configuration.networkInfo:
|
|
@@ -412,13 +444,12 @@ class Broker:
|
|
|
412
444
|
def subscribe_on_script(
|
|
413
445
|
self,
|
|
414
446
|
script: bytes,
|
|
415
|
-
on_frame: Callable[[Sequence[
|
|
447
|
+
on_frame: Callable[[Sequence[network_api.Signal]], None],
|
|
416
448
|
changed_values_only: bool = False,
|
|
417
449
|
) -> Any:
|
|
418
|
-
client_id =
|
|
419
|
-
# sync = queue.Queue()
|
|
450
|
+
client_id = common.ClientId(id="cli")
|
|
420
451
|
thread = Thread(
|
|
421
|
-
target=
|
|
452
|
+
target=act_on_scripted_signal,
|
|
422
453
|
args=(
|
|
423
454
|
client_id,
|
|
424
455
|
self.network_stub,
|
|
@@ -472,20 +503,20 @@ class Broker:
|
|
|
472
503
|
def long_name_subscribe(
|
|
473
504
|
self, signals_to_subscribe_to: List[SubscribableSignal], on_frame: Callable[..., Any], changed_values_only: bool = True
|
|
474
505
|
) -> Any:
|
|
475
|
-
client_id =
|
|
506
|
+
client_id = common.ClientId(id="cli")
|
|
476
507
|
|
|
477
508
|
# TODO - This can be improved moving forward and we also need to move the validation into api
|
|
478
509
|
self.validate_and_get_subscribed_signals(
|
|
479
510
|
list(map(lambda s: s.namespace, signals_to_subscribe_to)), (list(map(lambda s: s.name, signals_to_subscribe_to)))
|
|
480
511
|
)
|
|
481
512
|
|
|
482
|
-
def to_protobuf_signal(s: SubscribableSignal) ->
|
|
513
|
+
def to_protobuf_signal(s: SubscribableSignal) -> common.SignalId:
|
|
483
514
|
return self.signal_creator.signal(s.name, s.namespace)
|
|
484
515
|
|
|
485
516
|
signals_to_subscribe_on = list(map(to_protobuf_signal, signals_to_subscribe_to))
|
|
486
517
|
|
|
487
518
|
Thread(
|
|
488
|
-
target=
|
|
519
|
+
target=act_on_signal,
|
|
489
520
|
args=(
|
|
490
521
|
client_id,
|
|
491
522
|
self.network_stub,
|
|
@@ -506,19 +537,19 @@ class Broker:
|
|
|
506
537
|
on_frame: Callable[..., Any],
|
|
507
538
|
changed_values_only: bool = True,
|
|
508
539
|
) -> Any:
|
|
509
|
-
client_id =
|
|
540
|
+
client_id = common.ClientId(id="cli")
|
|
510
541
|
|
|
511
542
|
signals_to_subscribe_to: List[SubscribableSignal] = self.validate_and_get_subscribed_signals(
|
|
512
543
|
subscribed_namespaces, subscribed_signals
|
|
513
544
|
)
|
|
514
545
|
|
|
515
|
-
def to_protobuf_signal(s: SubscribableSignal) ->
|
|
546
|
+
def to_protobuf_signal(s: SubscribableSignal) -> common.SignalId:
|
|
516
547
|
return self.signal_creator.signal(s.name, s.namespace)
|
|
517
548
|
|
|
518
549
|
signals_to_subscribe_on = list(map(to_protobuf_signal, signals_to_subscribe_to))
|
|
519
550
|
|
|
520
551
|
Thread(
|
|
521
|
-
target=
|
|
552
|
+
target=act_on_signal,
|
|
522
553
|
args=(
|
|
523
554
|
client_id,
|
|
524
555
|
self.network_stub,
|
|
@@ -532,7 +563,7 @@ class Broker:
|
|
|
532
563
|
ecu, subscription = self.q.get()
|
|
533
564
|
return subscription
|
|
534
565
|
|
|
535
|
-
def __each_signal(self, signals: Iterable[
|
|
566
|
+
def __each_signal(self, signals: Iterable[network_api.Signal], callback: Callable[..., Any]) -> None:
|
|
536
567
|
callback(
|
|
537
568
|
map(
|
|
538
569
|
lambda s: {"timestamp_us": s.timestamp, "namespace": s.id.namespace.name, "name": s.id.name, "value": self.__get_value(s)},
|
|
@@ -541,7 +572,7 @@ class Broker:
|
|
|
541
572
|
)
|
|
542
573
|
|
|
543
574
|
@staticmethod
|
|
544
|
-
def __get_value(signal:
|
|
575
|
+
def __get_value(signal: network_api.Signal) -> Any:
|
|
545
576
|
if signal.raw != b"":
|
|
546
577
|
return "0x" + binascii.hexlify(signal.raw).decode("ascii")
|
|
547
578
|
if signal.HasField("integer"):
|
|
@@ -553,7 +584,7 @@ class Broker:
|
|
|
553
584
|
return "empty"
|
|
554
585
|
|
|
555
586
|
@staticmethod
|
|
556
|
-
def __create_playback_config(item: Dict[str, Any]) ->
|
|
587
|
+
def __create_playback_config(item: Dict[str, Any]) -> traffic_api.PlaybackInfo:
|
|
557
588
|
"""Creating configuration for playback
|
|
558
589
|
|
|
559
590
|
Parameters
|
|
@@ -573,26 +604,26 @@ class Broker:
|
|
|
573
604
|
return int(item["offsettime"])
|
|
574
605
|
return 0
|
|
575
606
|
|
|
576
|
-
playback_config =
|
|
577
|
-
fileDescription=
|
|
578
|
-
namespace=
|
|
607
|
+
playback_config = traffic_api.PlaybackConfig(
|
|
608
|
+
fileDescription=system_api.FileDescription(path=item["path"]),
|
|
609
|
+
namespace=common.NameSpace(name=item["namespace"]),
|
|
579
610
|
)
|
|
580
|
-
return
|
|
611
|
+
return traffic_api.PlaybackInfo(
|
|
581
612
|
playbackConfig=playback_config,
|
|
582
|
-
playbackMode=
|
|
613
|
+
playbackMode=traffic_api.PlaybackMode(mode=item["mode"], offsetTime=get_offset_time()),
|
|
583
614
|
)
|
|
584
615
|
|
|
585
616
|
def get_license(self) -> LicenseInfo:
|
|
586
|
-
license_info = self.system_stub.GetLicenseInfo(
|
|
617
|
+
license_info = self.system_stub.GetLicenseInfo(common.Empty())
|
|
587
618
|
return LicenseInfo(
|
|
588
|
-
valid=license_info.status ==
|
|
619
|
+
valid=license_info.status == system_api.LicenseStatus.VALID,
|
|
589
620
|
expires=license_info.expires,
|
|
590
621
|
email=license_info.requestId,
|
|
591
622
|
machine_id=license_info.requestMachineId.decode("utf-8"),
|
|
592
623
|
)
|
|
593
624
|
|
|
594
625
|
def apply_license(self, license_data_b64: bytes) -> LicenseInfo:
|
|
595
|
-
license =
|
|
626
|
+
license = system_api.License()
|
|
596
627
|
license.data = license_data_b64
|
|
597
628
|
license.termsAgreement = True
|
|
598
629
|
self.system_stub.SetLicense(license)
|