remotivelabs-cli 0.0.25__py3-none-any.whl → 0.0.26__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.
Files changed (42) hide show
  1. cli/broker/brokers.py +2 -2
  2. cli/broker/export.py +5 -5
  3. cli/broker/files.py +5 -5
  4. cli/broker/lib/broker.py +59 -49
  5. cli/broker/license_flows.py +11 -9
  6. cli/broker/licenses.py +2 -2
  7. cli/broker/playback.py +14 -34
  8. cli/broker/record.py +3 -3
  9. cli/broker/scripting.py +4 -4
  10. cli/broker/signals.py +11 -11
  11. cli/cloud/__init__.py +0 -1
  12. cli/cloud/auth.py +40 -35
  13. cli/cloud/auth_tokens.py +39 -36
  14. cli/cloud/brokers.py +24 -33
  15. cli/cloud/cloud_cli.py +9 -6
  16. cli/cloud/configs.py +19 -11
  17. cli/cloud/filestorage.py +63 -51
  18. cli/cloud/projects.py +10 -7
  19. cli/cloud/recordings.py +127 -108
  20. cli/cloud/recordings_playback.py +52 -39
  21. cli/cloud/rest_helper.py +247 -196
  22. cli/cloud/resumable_upload.py +9 -8
  23. cli/cloud/sample_recordings.py +5 -5
  24. cli/cloud/service_account_tokens.py +18 -16
  25. cli/cloud/service_accounts.py +9 -9
  26. cli/connect/__init__.py +0 -1
  27. cli/connect/connect.py +7 -6
  28. cli/connect/protopie/protopie.py +32 -16
  29. cli/errors.py +6 -5
  30. cli/remotive.py +13 -9
  31. cli/requirements.txt +4 -1
  32. cli/settings.py +9 -9
  33. cli/tools/__init__.py +0 -1
  34. cli/tools/can/__init__.py +0 -1
  35. cli/tools/can/can.py +8 -8
  36. cli/tools/tools.py +2 -2
  37. {remotivelabs_cli-0.0.25.dist-info → remotivelabs_cli-0.0.26.dist-info}/METADATA +5 -3
  38. remotivelabs_cli-0.0.26.dist-info/RECORD +44 -0
  39. remotivelabs_cli-0.0.25.dist-info/RECORD +0 -44
  40. {remotivelabs_cli-0.0.25.dist-info → remotivelabs_cli-0.0.26.dist-info}/LICENSE +0 -0
  41. {remotivelabs_cli-0.0.25.dist-info → remotivelabs_cli-0.0.26.dist-info}/WHEEL +0 -0
  42. {remotivelabs_cli-0.0.25.dist-info → remotivelabs_cli-0.0.26.dist-info}/entry_points.txt +0 -0
cli/cloud/recordings.py CHANGED
@@ -9,32 +9,34 @@ import tempfile
9
9
  import time
10
10
  import urllib.parse
11
11
  from pathlib import Path
12
- from typing import Dict, List, Union
12
+ from typing import Any, Dict, List, Tuple, Union
13
+ from urllib.parse import quote
13
14
 
14
15
  import grpc
15
16
  import requests
16
17
  import typer
17
- from rich.progress import Progress, SpinnerColumn, TextColumn, track
18
+ from rich.progress import Progress, SpinnerColumn, TaskID, TextColumn, track
18
19
 
19
20
  from cli.errors import ErrorPrinter
20
21
 
21
22
  from ..broker.lib.broker import Broker
22
- from . import rest_helper as rest
23
23
  from .recordings_playback import app as playback_app
24
+ from .rest_helper import RestHelper as Rest
25
+ from .rest_helper import err_console
24
26
 
25
27
  app = typer.Typer()
26
28
  app.add_typer(playback_app, name="playback")
27
29
 
28
30
 
29
- def uid(p):
31
+ def uid(p: Any) -> Any:
30
32
  print(p)
31
33
  return p["uid"]
32
34
 
33
35
 
34
36
  # to be used in options
35
37
  # autocompletion=project_names)
36
- def project_names():
37
- r = requests.get(f"{rest.base_url}/api/bu/{rest.org}/project", headers=rest.headers)
38
+ def project_names() -> Any:
39
+ r = requests.get(f"{Rest.get_base_url()}/api/bu/{Rest.get_org()}/project", headers=Rest.get_headers(), timeout=60)
38
40
  # sys.stderr.write(r.text)
39
41
  if r.status_code == 200:
40
42
  projects = r.json()
@@ -48,7 +50,7 @@ def project_names():
48
50
  def list_recordings(
49
51
  is_processing: bool = typer.Option(default=False, help="Use this option to see only those that are beeing processed or are invalid"),
50
52
  project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT"),
51
- ):
53
+ ) -> None:
52
54
  """
53
55
  List all recording sessions in a project. You can choose to see all valid recordings (default) or use
54
56
  --is-processing and you will get those that are currently beeing processed or that failed to be validated.
@@ -56,35 +58,35 @@ def list_recordings(
56
58
  """
57
59
 
58
60
  if is_processing:
59
- rest.handle_get(f"/api/project/{project}/files/recording/processing")
61
+ Rest.handle_get(f"/api/project/{project}/files/recording/processing")
60
62
  else:
61
- rest.handle_get(f"/api/project/{project}/files/recording")
63
+ Rest.handle_get(f"/api/project/{project}/files/recording")
62
64
 
63
65
 
64
66
  @app.command(help="Shows details about a specific recording in project")
65
67
  def describe(
66
68
  recording_session: str = typer.Argument(..., help="Recording session id", envvar="REMOTIVE_CLOUD_RECORDING_SESSION"),
67
69
  project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT"),
68
- ):
69
- rest.handle_get(f"/api/project/{project}/files/recording/{recording_session}")
70
+ ) -> None:
71
+ Rest.handle_get(f"/api/project/{project}/files/recording/{recording_session}")
70
72
 
71
73
 
72
74
  # @app.command(help="Shows details about a specific recording in project")
73
75
  # def copy(recording_session: str = typer.Argument(..., help="Recording session id"),
74
76
  # target_project: str = typer.Option(..., help="Which project to copy the recording to"),
75
77
  # project: str = typer.Option(..., help="Project ID", envvar='REMOTIVE_CLOUD_PROJECT')):
76
- # rest.handle_post(url=f"/api/project/{project}/files/recording/{recording_session}/copy",
78
+ # Rest.handle_post(url=f"/api/project/{project}/files/recording/{recording_session}/copy",
77
79
  # body=json.dumps({'projectUid': target_project}))
78
80
 
79
81
 
80
- def do_start(name: str, project: str, api_key: str, return_response: bool = False):
82
+ def do_start(name: str, project: str, api_key: str, return_response: bool = False) -> requests.Response | None:
81
83
  if api_key == "":
82
84
  body = {"size": "S"}
83
85
  else:
84
86
  body = {"size": "S", "apiKey": api_key}
85
87
 
86
88
  name = name if name is not None else "personal"
87
- return rest.handle_post(
89
+ return Rest.handle_post(
88
90
  f"/api/project/{project}/brokers/{name}",
89
91
  body=json.dumps(body),
90
92
  return_response=return_response,
@@ -93,19 +95,20 @@ def do_start(name: str, project: str, api_key: str, return_response: bool = Fals
93
95
 
94
96
 
95
97
  @app.command(help="Prepares all recording files and transformations to be available for playback")
96
- def mount(
98
+ def mount( # noqa: C901
97
99
  recording_session: str = typer.Argument(..., help="Recording session id", envvar="REMOTIVE_CLOUD_RECORDING_SESSION"),
98
100
  broker: str = typer.Option(None, help="Broker to use"),
99
101
  ensure_broker_started: bool = typer.Option(default=False, help="Ensure broker exists, start otherwise"),
100
102
  transformation_name: str = typer.Option("default", help="Specify a custom signal transformation to use"),
101
103
  project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT"),
102
- ):
103
- rest.ensure_auth_token()
104
+ ) -> None:
105
+ # pylint: disable=R0912
106
+ Rest.ensure_auth_token()
104
107
 
105
- rest.handle_get(f"/api/project/{project}/files/recording/{recording_session}", return_response=True)
108
+ Rest.handle_get(f"/api/project/{project}/files/recording/{recording_session}", return_response=True)
106
109
 
107
110
  if broker is None:
108
- r = rest.handle_get(url=f"/api/project/{project}/brokers/personal", return_response=True, allow_status_codes=[404])
111
+ r = Rest.handle_get(url=f"/api/project/{project}/brokers/personal", return_response=True, allow_status_codes=[404])
109
112
 
110
113
  if r.status_code == 200:
111
114
  broker = r.json()["shortName"]
@@ -114,32 +117,35 @@ def mount(
114
117
  r = do_start(None, project, "", return_response=True)
115
118
  if r.status_code != 200:
116
119
  print(r.text)
117
- exit(0)
120
+ sys.exit(0)
118
121
  broker = r.json()["shortName"]
119
122
  else:
120
123
  sys.stderr.write(f"Got http status code {r.status_code}")
121
- typer.Exit(0)
124
+ raise typer.Exit(0)
122
125
  else:
123
- r = rest.handle_get(url=f"/api/project/{project}/brokers/{broker}", return_response=True, allow_status_codes=[404])
126
+ r = Rest.handle_get(url=f"/api/project/{project}/brokers/{broker}", return_response=True, allow_status_codes=[404])
124
127
 
128
+ if r is None:
129
+ sys.exit(1)
125
130
  if r.status_code == 404:
126
131
  if ensure_broker_started:
127
132
  r = do_start(broker, project, "", return_response=True)
128
-
133
+ if r is None:
134
+ sys.exit(1)
129
135
  if r.status_code != 200:
130
136
  print(r.text)
131
- exit(1)
137
+ sys.exit(1)
132
138
  else:
133
139
  ErrorPrinter.print_generic_error(f"Broker {broker} not running")
134
- exit(1)
140
+ sys.exit(1)
135
141
  elif r.status_code != 200:
136
142
  sys.stderr.write(f"Got http status code {r.status_code}")
137
- typer.Exit(1)
143
+ raise typer.Exit(1)
138
144
  broker_config_query = ""
139
145
  if transformation_name != "default":
140
146
  broker_config_query = f"?brokerConfigName={transformation_name}"
141
147
 
142
- rest.handle_get(
148
+ Rest.handle_get(
143
149
  f"/api/project/{project}/files/recording/{recording_session}/upload{broker_config_query}",
144
150
  params={"brokerName": broker},
145
151
  return_response=True,
@@ -155,29 +161,33 @@ def download_recording_file(
155
161
  ..., help="Recording session id that this file belongs to", envvar="REMOTIVE_CLOUD_RECORDING_SESSION"
156
162
  ),
157
163
  project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT"),
158
- ):
159
- rest.ensure_auth_token()
164
+ ) -> None:
165
+ Rest.ensure_auth_token()
166
+ recording_file_name_qouted = quote(recording_file_name, safe="")
160
167
  get_signed_url_resp = requests.get(
161
- f"{rest.base_url}/api/project/{project}/files/recording/{recording_session}/recording-file/{recording_file_name}",
162
- headers=rest.headers,
168
+ f"{Rest.get_base_url()}/api/project/{project}/files/recording/{recording_session}/recording-file/{recording_file_name_qouted}",
169
+ headers=Rest.get_headers(),
163
170
  allow_redirects=True,
171
+ timeout=60,
164
172
  )
165
173
  if get_signed_url_resp.status_code == 200:
166
174
  # Next download the actual file
167
- rest.download_file(recording_file_name, get_signed_url_resp.json()["downloadUrl"])
175
+ Rest.download_file(recording_file_name, get_signed_url_resp.json()["downloadUrl"])
168
176
  print(f"Downloaded {recording_file_name}")
177
+ else:
178
+ print(get_signed_url_resp)
169
179
 
170
180
 
171
181
  @app.command(name="delete")
172
182
  def delete(
173
183
  recording_session: str = typer.Argument(..., help="Recording session id", envvar="REMOTIVE_CLOUD_RECORDING_SESSION"),
174
184
  project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT"),
175
- ):
185
+ ) -> None:
176
186
  """
177
187
  Deletes the specified recording session including all media files and configurations.
178
188
 
179
189
  """
180
- rest.handle_delete(f"/api/project/{project}/files/recording/{recording_session}")
190
+ Rest.handle_delete(f"/api/project/{project}/files/recording/{recording_session}")
181
191
 
182
192
 
183
193
  @app.command(name="delete-recording-file")
@@ -187,12 +197,12 @@ def delete_recording_file(
187
197
  ..., help="Recording session id that this file belongs to", envvar="REMOTIVE_CLOUD_RECORDING_SESSION"
188
198
  ),
189
199
  project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT"),
190
- ):
200
+ ) -> None:
191
201
  """
192
202
  Deletes the specified recording file
193
203
 
194
204
  """
195
- rest.handle_delete(f"/api/project/{project}/files/recording/{recording_session}/recording-file/{recording_file_name}")
205
+ Rest.handle_delete(f"/api/project/{project}/files/recording/{recording_session}/recording-file/{recording_file_name}")
196
206
 
197
207
 
198
208
  @app.command()
@@ -209,19 +219,22 @@ def upload( # noqa: C901
209
219
  ),
210
220
  project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT"),
211
221
  recording_session: str = typer.Option(default=None, help="Optional existing recording to upload file to"),
212
- ):
222
+ ) -> None:
223
+ # pylint: disable=R0912,R0914,R0915
213
224
  """
214
225
  Uploads a recording to RemotiveCloud.
215
226
  Except for recordings from RemotiveBroker you can also upload Can ASC (.asc), Can BLF(.blf) and Can LOG (.log, .txt)
216
227
  """
217
228
 
218
229
  filename = os.path.basename(path.name)
219
- rest.ensure_auth_token()
230
+ Rest.ensure_auth_token()
220
231
 
221
232
  if recording_session is None:
222
- r = rest.handle_post(f"/api/project/{project}/files/recording/{filename}", return_response=True)
233
+ r = Rest.handle_post(f"/api/project/{project}/files/recording/{filename}", return_response=True)
223
234
  else:
224
- r = rest.handle_post(f"/api/project/{project}/files/recording/{recording_session}/recording-file/{filename}", return_response=True)
235
+ r = Rest.handle_post(f"/api/project/{project}/files/recording/{recording_session}/recording-file/{filename}", return_response=True)
236
+ if r is None:
237
+ return
225
238
 
226
239
  upload_url = r.text
227
240
  url_path = urllib.parse.urlparse(upload_url).path
@@ -234,14 +247,18 @@ def upload( # noqa: C901
234
247
  "Something went wrong, please try again. Please contact RemotiveLabs support if this problem remains"
235
248
  )
236
249
  ErrorPrinter.print_hint("Please make sure to use the latest version of RemotiveCLI")
237
- exit(1)
250
+ sys.exit(1)
238
251
 
239
- upload_response = rest.upload_file_with_signed_url(
252
+ upload_response = Rest.upload_file_with_signed_url(
240
253
  path=path, url=upload_url, upload_headers={"Content-Type": "application/x-www-form-urlencoded"}, return_response=True
241
254
  )
242
255
 
256
+ if upload_response is None:
257
+ return
258
+
243
259
  # Exact same as in cloud console
244
260
  def get_processing_message(step: str) -> str:
261
+ # pylint: disable=R0911
245
262
  if step == "REQUESTED":
246
263
  return "Preparing file..."
247
264
  if step == "VALIDATING":
@@ -264,10 +281,12 @@ def upload( # noqa: C901
264
281
  t = p.add_task("Processing...", total=1)
265
282
  while True:
266
283
  time.sleep(1)
267
- r = rest.handle_get(
284
+ r = Rest.handle_get(
268
285
  f"/api/project/{project}/files/recording/processing", return_response=True, use_progress_indicator=False
269
286
  )
270
- status_list: List[Dict[str, any]] = r.json()
287
+ if r is None:
288
+ return
289
+ status_list: List[Dict[str, Any]] = r.json()
271
290
  res = list(filter(lambda s: s["uploadId"] == upload_id, status_list))
272
291
  if len(res) == 1:
273
292
  tracking_state = res[0]
@@ -284,19 +303,20 @@ def upload( # noqa: C901
284
303
  break
285
304
  if error_message is not None:
286
305
  ErrorPrinter.print_generic_error(error_message)
287
- exit(1)
306
+ sys.exit(1)
288
307
 
289
308
  else:
290
- rest.err_console.print(f":boom: [bold red]Got status code[/bold red]: {upload_response.status_code} {upload_response.text}")
309
+ err_console.print(f":boom: [bold red]Got status code[/bold red]: {upload_response.status_code} {upload_response.text}")
291
310
 
292
311
 
293
312
  @app.command()
294
- def upload_broker_configuration(
313
+ def upload_broker_configuration( # noqa: C901
295
314
  directory: str = typer.Argument(..., help="Configuration directory"),
296
315
  recording_session: str = typer.Option(..., help="Recording session id", envvar="REMOTIVE_CLOUD_RECORDING_SESSION"),
297
316
  project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT"),
298
317
  overwrite: bool = typer.Option(False, help="Overwrite existing configuration if it exists"),
299
- ):
318
+ ) -> None:
319
+ # pylint: disable=R0914,R0915
300
320
  # Must end with /
301
321
  if not directory.endswith("/"):
302
322
  directory = f"{directory}/"
@@ -319,14 +339,16 @@ def upload_broker_configuration(
319
339
  # name already exists
320
340
  #
321
341
  # task = progress.add_task(description=f"Preparing upload of {broker_config_dir_name}", total=1)
322
- details_resp = rest.handle_get(f"/api/project/{project}/files/recording/{recording_session}", return_response=True)
342
+ details_resp = Rest.handle_get(f"/api/project/{project}/files/recording/{recording_session}", return_response=True)
343
+ if details_resp is None:
344
+ return
323
345
  details = details_resp.json()
324
346
  existing_configs = details["brokerConfigurations"]
325
347
  if len(existing_configs) > 0:
326
348
  data = list(filter(lambda x: x["name"] == broker_config_dir_name, existing_configs))
327
349
  if len(data) > 0:
328
350
  if overwrite:
329
- rest.handle_delete(
351
+ Rest.handle_delete(
330
352
  f"/api/project/{project}/files/recording/{recording_session}/configuration/{broker_config_dir_name}", quiet=True
331
353
  )
332
354
  else:
@@ -349,11 +371,13 @@ def upload_broker_configuration(
349
371
  #
350
372
  json_request_upload_urls_req = {"name": "not_used", "paths": list(map(lambda x: x["remote_path"], file_infos))}
351
373
 
352
- response = rest.handle_put(
374
+ response = Rest.handle_put(
353
375
  url=f"/api/project/{project}/files/recording/{recording_session}/configuration",
354
376
  return_response=True,
355
377
  body=json.dumps(json_request_upload_urls_req),
356
378
  )
379
+ if response is None:
380
+ return
357
381
  if response.status_code != 200:
358
382
  print("Failed to prepare configuration upload")
359
383
  print(f"{response.text} - {response.status_code}")
@@ -371,12 +395,12 @@ def upload_broker_configuration(
371
395
  path = file["local_path"]
372
396
  url = upload_urls[key]
373
397
  headers = {"Content-Type": "application/x-www-form-urlencoded"}
374
- r = requests.put(url, open(path, "rb"), headers=headers)
398
+ r = requests.put(url, open(path, "rb"), headers=headers, timeout=60) # pylint: disable=R1732
375
399
  if r.status_code != 200:
376
400
  print("Failed to upload broker configuration")
377
401
  print(r.status_code)
378
402
  print(r.text)
379
- typer.Exit(1)
403
+ raise typer.Exit(1)
380
404
 
381
405
  print(f"Successfully uploaded broker configuration {broker_config_dir_name}")
382
406
 
@@ -386,32 +410,36 @@ def download_configuration(
386
410
  broker_config_name: str = typer.Argument(..., help="Broker config name"),
387
411
  recording_session: str = typer.Option(..., help="Recording session id", envvar="REMOTIVE_CLOUD_RECORDING_SESSION"),
388
412
  project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT"),
389
- ):
390
- rest.ensure_auth_token()
391
- r = rest.handle_get(
413
+ ) -> None:
414
+ Rest.ensure_auth_token()
415
+ r = Rest.handle_get(
392
416
  url=f"/api/project/{project}/files/recording/{recording_session}/configuration/{broker_config_name}", return_response=True
393
417
  )
418
+ if r is None:
419
+ return
394
420
  filename = get_filename_from_cd(r.headers.get("content-disposition"))
395
- open(filename, "wb").write(r.content)
396
- print(f"Downloaded file {filename}")
421
+ if filename is not None:
422
+ with open(filename, "wb") as f:
423
+ f.write(r.content)
424
+ print(f"Downloaded file {filename}")
397
425
 
398
426
 
399
- @app.command(help="Downloads the specified broker configuration directory as zip file")
427
+ @app.command(help="Delete the specified broker configuration")
400
428
  def delete_configuration(
401
429
  broker_config_name: str = typer.Argument(..., help="Broker config name"),
402
430
  recording_session: str = typer.Option(..., help="Recording session id", envvar="REMOTIVE_CLOUD_RECORDING_SESSION"),
403
431
  project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT"),
404
- ):
405
- rest.handle_delete(url=f"/api/project/{project}/files/recording/{recording_session}/configuration/{broker_config_name}")
432
+ ) -> None:
433
+ Rest.handle_delete(url=f"/api/project/{project}/files/recording/{recording_session}/configuration/{broker_config_name}")
406
434
 
407
435
 
408
436
  @app.command(help="Copy recording to another project")
409
437
  def copy(
410
438
  recording_session: str = typer.Argument(..., help="Recording session id"),
411
- project: str = typer.Option(..., help="Project to import sample recording into", envvar="REMOTIVE_CLOUD_PROJECT"),
439
+ project: str = typer.Option(..., help="Source project", envvar="REMOTIVE_CLOUD_PROJECT"),
412
440
  destination_project: str = typer.Option(..., help="Destination project"),
413
- ):
414
- rest.handle_post(
441
+ ) -> None:
442
+ Rest.handle_post(
415
443
  url=f"/api/project/{project}/files/recording/{recording_session}/copy", body=json.dumps({"projectUid": destination_project})
416
444
  )
417
445
 
@@ -421,7 +449,7 @@ def play(
421
449
  recording_session: str = typer.Argument(..., help="Recording session id", envvar="REMOTIVE_CLOUD_RECORDING_SESSION"),
422
450
  broker: str = typer.Option(None, help="Broker to use"),
423
451
  project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT"),
424
- ):
452
+ ) -> None:
425
453
  """
426
454
  Plays a recording (Deprecated - Use recordings playback play)"
427
455
  """
@@ -433,32 +461,20 @@ def pause(
433
461
  recording_session: str = typer.Argument(..., help="Recording session id", envvar="REMOTIVE_CLOUD_RECORDING_SESSION"),
434
462
  broker: str = typer.Option(None, help="Broker to use"),
435
463
  project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT"),
436
- ):
464
+ ) -> None:
437
465
  """
438
466
  Pause recording (Deprecated - Use recordings playback pause")
439
467
  """
440
468
  _do_change_playback_mode("pause", recording_session, broker, project)
441
469
 
442
470
 
443
- @app.command(name="playback-status", deprecated=True)
444
- def playback_status(
445
- recording_session: str = typer.Argument(..., help="Recording session id", envvar="REMOTIVE_CLOUD_RECORDING_SESSION"),
446
- broker: str = typer.Option(None, help="Broker to use"),
447
- project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT"),
448
- ):
449
- """
450
- Playback progress (Deprecated - Use recordings playback progress)
451
- """
452
- _do_change_playback_mode("status", recording_session, broker, project)
453
-
454
-
455
471
  @app.command(deprecated=True)
456
472
  def seek(
457
473
  recording_session: str = typer.Argument(..., help="Recording session id", envvar="REMOTIVE_CLOUD_RECORDING_SESSION"),
458
474
  seconds: int = typer.Option(..., min=0, help="Target offset in seconds"),
459
475
  broker: str = typer.Option(None, help="Broker to use"),
460
476
  project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT"),
461
- ):
477
+ ) -> None:
462
478
  """
463
479
  Seek into recording (Deprecated - Use recordings playback seek)
464
480
  """
@@ -470,30 +486,36 @@ def stop(
470
486
  recording_session: str = typer.Argument(..., help="Recording session id", envvar="REMOTIVE_CLOUD_RECORDING_SESSION"),
471
487
  broker: str = typer.Option(None, help="Broker to use"),
472
488
  project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT"),
473
- ):
489
+ ) -> None:
474
490
  """
475
491
  Stop recording (Deprecated - Use recordings playback stop)
476
492
  """
477
493
  _do_change_playback_mode("stop", recording_session, broker, project)
478
494
 
479
495
 
480
- def _do_change_playback_mode(mode: str, recording_session: str, broker: str, project: str, seconds: int | None = None): # noqa: C901
481
- response = rest.handle_get(f"/api/project/{project}/files/recording/{recording_session}", return_response=True)
496
+ # pylint: disable-next=C0301
497
+ def _do_change_playback_mode(mode: str, recording_session: str, broker_name: str, project: str, seconds: int | None = None) -> None: # noqa: C901
498
+ # pylint: disable=R0912,R0914,R0915
499
+ response = Rest.handle_get(f"/api/project/{project}/files/recording/{recording_session}", return_response=True)
500
+ if response is None:
501
+ return
482
502
  r = json.loads(response.text)
483
- recordings: list = r["recordings"]
503
+ recordings: List[Any] = r["recordings"]
484
504
  files = list(map(lambda rec: {"recording": rec["fileName"], "namespace": rec["metadata"]["namespace"]}, recordings))
485
505
 
486
- if broker is not None:
487
- response = rest.handle_get(f"/api/project/{project}/brokers/{broker}", return_response=True, allow_status_codes=[404])
506
+ if broker_name is not None:
507
+ response = Rest.handle_get(f"/api/project/{project}/brokers/{broker_name}", return_response=True, allow_status_codes=[404])
488
508
  else:
489
- response = rest.handle_get(f"/api/project/{project}/brokers/personal", return_response=True, allow_status_codes=[404])
509
+ response = Rest.handle_get(f"/api/project/{project}/brokers/personal", return_response=True, allow_status_codes=[404])
510
+ if response is None:
511
+ return
490
512
  if response.status_code == 404:
491
513
  broker_arg = ""
492
- if broker is not None:
493
- broker_arg = f" --broker {broker} --ensure-broker-started"
514
+ if broker_name is not None:
515
+ broker_arg = f" --broker {broker_name} --ensure-broker-started"
494
516
  ErrorPrinter.print_generic_error("You need to mount the recording before you play")
495
517
  ErrorPrinter.print_hint(f"remotive cloud recordings mount {recording_session}{broker_arg} --project {project}")
496
- exit(1)
518
+ sys.exit(1)
497
519
 
498
520
  broker_info = json.loads(response.text)
499
521
  broker = Broker(broker_info["url"], None)
@@ -503,7 +525,7 @@ def _do_change_playback_mode(mode: str, recording_session: str, broker: str, pro
503
525
  # error messages
504
526
  tmp = os.path.join(tempfile.gettempdir(), os.urandom(24).hex())
505
527
  broker.download(".cloud.context", tmp, True)
506
- with open(tmp, "r") as f:
528
+ with open(tmp, "r", encoding="utf8") as f:
507
529
  json_context = json.loads(f.read())
508
530
  if json_context["recordingSessionId"] != recording_session:
509
531
  ErrorPrinter.print_generic_error(
@@ -511,33 +533,30 @@ def _do_change_playback_mode(mode: str, recording_session: str, broker: str, pro
511
533
  f"which not the same as you are trying to {mode}, use cmd below to mount this recording"
512
534
  )
513
535
  ErrorPrinter.print_hint(f"remotive cloud recordings mount {recording_session} --project {project}")
514
- exit(1)
536
+ sys.exit(1)
515
537
  except grpc.RpcError as rpc_error:
516
- if rpc_error.code() == grpc.StatusCode.NOT_FOUND:
517
- ErrorPrinter.print_generic_error(f"You must use mount to prepare a recording before you can use {mode}")
518
- ErrorPrinter.print_hint(f"remotive cloud recordings mount {recording_session} --project {project}")
519
- else:
520
- ErrorPrinter.print_grpc_error(rpc_error)
521
- exit(1)
538
+ # if rpc_error.code() == grpc.StatusCode.NOT_FOUND:
539
+ # ErrorPrinter.print_generic_error(f"You must use mount to prepare a recording before you can use {mode}")
540
+ # ErrorPrinter.print_hint(f"remotive cloud recordings mount {recording_session} --project {project}")
541
+ # else:
542
+ ErrorPrinter.print_grpc_error(rpc_error)
543
+ sys.exit(1)
522
544
  if mode == "pause":
523
545
  broker.pause_play(files, True)
524
546
  elif mode == "play":
525
547
  r = broker.play(files, True)
526
548
  elif mode == "seek":
527
- broker.seek(files, int(seconds * 1000000), True)
549
+ if seconds is not None:
550
+ broker.seek(files, int(seconds * 1000000), True)
551
+ else:
552
+ broker.seek(files, 0, True)
528
553
  elif mode == "stop":
529
554
  broker.seek(files, 0, True)
530
- elif mode == "status":
531
- p = Progress(SpinnerColumn(), TextColumn("[progress.description]{task.description}"), transient=True)
532
- t = p.add_task("label", total=1)
533
-
534
- with p:
535
- broker.listen_on_playback(lambda c: p.update(t, description=str(c)))
536
555
  else:
537
- raise Exception(f"Illegal command {mode}")
556
+ raise ValueError(f"Illegal command {mode}")
538
557
 
539
558
 
540
- def get_filename_from_cd(cd):
559
+ def get_filename_from_cd(cd: Union[str, None]) -> Union[str, None]:
541
560
  """
542
561
  Get filename from content-disposition
543
562
  """
@@ -546,10 +565,10 @@ def get_filename_from_cd(cd):
546
565
  fname = re.findall("filename=(.+)", cd)
547
566
  if len(fname) == 0:
548
567
  return None
549
- return fname[0]
568
+ return str(fname[0])
550
569
 
551
570
 
552
- def use_progress(label: str):
571
+ def use_progress(label: str) -> Tuple[Progress, TaskID]:
553
572
  p = Progress(SpinnerColumn(), TextColumn("[progress.description]{task.description}"), transient=True)
554
573
  t = p.add_task(label, total=1)
555
574
  return (p, t)