RemoteRF 2.2.2__py3-none-any.whl → 2.2.3__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.
@@ -14,7 +14,7 @@
14
14
  # along with this program. If not, see <https://www.gnu.org/licenses/>.
15
15
 
16
16
  def main(*, register=False, enrollment_code=None, server_label=None, show_banner=True,
17
- home=None, route=None):
17
+ home=None, route=None, username=None):
18
18
  from .app import run
19
19
  return run(
20
20
  register=register,
@@ -23,4 +23,5 @@ def main(*, register=False, enrollment_code=None, server_label=None, show_banner
23
23
  show_banner=show_banner,
24
24
  home=home,
25
25
  route=route,
26
+ username=username,
26
27
  )
remoterf/core/app.py CHANGED
@@ -116,6 +116,8 @@ def _password_confirmation(*, enforce_policy=False):
116
116
 
117
117
  # The code typed at `remoterf -r`, used once for this registration.
118
118
  pending_enrollment_code = None
119
+ # A username already given (found on Global): the login asks only the password.
120
+ pending_username = None
119
121
  # The saved home this shell is attached to (None on a bare direct profile).
120
122
  home_name = None
121
123
  # The route it was reached over (None on a bare direct profile or an HTTPS home).
@@ -249,7 +251,9 @@ def _account_command(command):
249
251
  return False
250
252
  if command in ('l', 'login'):
251
253
  printf(f"Login to {_home_name()}", (Sty.BOLD, Sty.BLUE))
252
- account.username = _ask('Username or Email' if account.is_https_home else 'Username')
254
+ global pending_username
255
+ account.username = pending_username or _ask('Username or Email' if account.is_https_home else 'Username')
256
+ pending_username = None
253
257
  account.password = _ask('Password (Hidden)', hidden=True)
254
258
  ok = bool(account.login_user(remember=not account.is_https_home))
255
259
  if ok:
@@ -1585,8 +1589,9 @@ def interactive_reserve_next_days_auto():
1585
1589
 
1586
1590
 
1587
1591
  def run(backend=None, *, register=False, enrollment_code=None, server_label=None,
1588
- show_banner=True, home=None, route=None):
1589
- global account, session, server_addr, pending_enrollment_code, home_name, current_route
1592
+ show_banner=True, home=None, route=None, username=None):
1593
+ global account, session, server_addr, pending_enrollment_code, home_name, current_route, pending_username
1594
+ pending_username = username
1590
1595
  home_name = home
1591
1596
  current_route = route
1592
1597
  from ..deployment.backend import selected_backend
@@ -268,6 +268,27 @@ def connect(name: str) -> dict:
268
268
  return route
269
269
 
270
270
 
271
+ # Global's own account home, by its name on Global's broker.
272
+ GLOBAL_HOME = "home"
273
+
274
+
275
+ def lookup_username(global_origin: str, username: str) -> str | None:
276
+ """The deployment that holds this username on Global, or None."""
277
+ from .http import AccountBackendError, JsonTransport
278
+
279
+ transport = JsonTransport(global_origin)
280
+ try:
281
+ return transport.request(
282
+ "POST", "/v2/broker/usernames/lookup", data={"username": username}
283
+ )["deployment"]
284
+ except AccountBackendError as exc:
285
+ if exc.code == "not_found":
286
+ return None
287
+ raise
288
+ finally:
289
+ transport.close()
290
+
291
+
271
292
  def register_home(host: str) -> tuple[str, dict, dict]:
272
293
  """Learn a deployment from its code, save it, and connect to it."""
273
294
  document = discover(host)
remoterf/remoterf_cli.py CHANGED
@@ -180,7 +180,8 @@ def print_help() -> None:
180
180
 
181
181
  def _account_shell(*, register: bool, enrollment_code: str | None = None,
182
182
  server_label: str | None = None, show_banner: bool = True,
183
- home: str | None = None, route: dict | None = None) -> int:
183
+ home: str | None = None, route: dict | None = None,
184
+ username: str | None = None) -> int:
184
185
  ok, _ = _ensure_config_present()
185
186
  if not ok:
186
187
  _print_server_unavailable()
@@ -198,6 +199,7 @@ def _account_shell(*, register: bool, enrollment_code: str | None = None,
198
199
  show_banner=show_banner,
199
200
  home=home,
200
201
  route=route,
202
+ username=username,
201
203
  )
202
204
  or 0
203
205
  )
@@ -212,7 +214,7 @@ def _global_origin() -> str:
212
214
  return os.getenv('REMOTERF_GLOBAL_ORIGIN', 'https://global.remoterf.net')
213
215
 
214
216
 
215
- def _use_global(*, register: bool, show_banner: bool = True) -> int:
217
+ def _use_global(*, register: bool, show_banner: bool = True, username: str | None = None) -> int:
216
218
  """Register or log in with the RemoteRF Global identity itself.
217
219
 
218
220
  A Global-native account is complete on its own: it needs no deployment
@@ -238,7 +240,7 @@ def _use_global(*, register: bool, show_banner: bool = True) -> int:
238
240
  except (RuntimeError, ValueError) as exc:
239
241
  print(f'Could not reach RemoteRF Global: {exc}')
240
242
  return 2
241
- return _account_shell(register=register, show_banner=show_banner)
243
+ return _account_shell(register=register, show_banner=show_banner, username=username)
242
244
 
243
245
 
244
246
  @contextmanager
@@ -397,7 +399,7 @@ def _login(target: str | None) -> int:
397
399
  # Nothing saved. A legacy address in .env still logs in there;
398
400
  # a fresh install has nothing to log in to, so `-l` is `-r`.
399
401
  if not _ensure_config_present()[0]:
400
- return _register()
402
+ return _login_by_username()
401
403
  return _account_shell(register=False)
402
404
  if target == 'global':
403
405
  # Global's address is built in, so a fresh install can log in to an
@@ -409,6 +411,43 @@ def _login(target: str | None) -> int:
409
411
  return _use_home(target, register=False)
410
412
 
411
413
 
414
+ def _login_by_username() -> int:
415
+ """A fresh install: Global knows which lab holds a username, so the
416
+ account is found by name. Enter registers, as `-l` here always did."""
417
+ from remoterf.deployment import homes
418
+
419
+ try:
420
+ name = input('Username (Enter to register): ').strip()
421
+ except (EOFError, KeyboardInterrupt):
422
+ print()
423
+ return 1
424
+ if not name:
425
+ return _register()
426
+ try:
427
+ with _working("Looking up your account…"):
428
+ deployment = homes.lookup_username(_global_origin(), name)
429
+ except (RuntimeError, ValueError) as exc:
430
+ printf(f'Could not reach RemoteRF Global: {_reason(exc)}', Sty.WARNING)
431
+ return 2
432
+ if deployment is None:
433
+ printf(f'No RemoteRF account named {name!r} was found.', Sty.WARNING)
434
+ printf('Run: ', Sty.GRAY, 'remoterf --register', Sty.CYAN)
435
+ return 2
436
+ if deployment == homes.GLOBAL_HOME:
437
+ return _use_global(register=False, username=name)
438
+ host = f'{deployment}.{homes.GLOBAL_DOMAIN}'
439
+ try:
440
+ with _working(f"Looking up {host}…"):
441
+ lab, home, route = homes.register_home(host)
442
+ except (RuntimeError, ValueError) as exc:
443
+ printf(f'Could not reach {host}: {_reason(exc)}', Sty.WARNING)
444
+ return 2
445
+ return _account_shell(
446
+ register=False, server_label=f'{lab} ({_route_label(route)})',
447
+ home=lab, route={**route, 'home': home}, username=name,
448
+ )
449
+
450
+
412
451
  def _print_pick_a_target() -> int:
413
452
  _print_homes()
414
453
  printf('Choose one: ', Sty.GRAY, 'remoterf --login <name>', Sty.CYAN)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: remoterf
3
- Version: 2.2.2
3
+ Version: 2.2.3
4
4
  Summary: A python API to remotely access signal centric hardware. Client-side only! Courtesy of Wireless Lab @ UCLA & Prof. Ian Roberts.
5
5
  Author-email: Ethan Ge <ethoGalaxy@gmail.com>
6
6
  License-Expression: GPL-3.0-or-later
@@ -1,6 +1,6 @@
1
1
  remoterf.py,sha256=3fQ4zYeDo4Q8n5stT0H5ol8t2njckfY-FDuTZ2yEx5w,1843
2
2
  remoterf/__init__.py,sha256=-1h_xQjiE66oiWRO-vnLGJ4smpgUNhFuV-ZreW9_tD4,667
3
- remoterf/remoterf_cli.py,sha256=yqCypQAefP4C120G9848gZMsZXCM4W1HRyJWb6zX7eY,22034
3
+ remoterf/remoterf_cli.py,sha256=X7s6mKc-lWo5WYiGkhHgX9uxGXg_54WgvXodnQLpdw4,23618
4
4
  remoterf/version.py,sha256=NWzcPOAdd567IvC8ei1yyPdeS7w0kt99oKwL6oWAQSc,850
5
5
  remoterf/common/__init__.py,sha256=ey1IjkAaXFL1sZBnBwuWVlHhA_n0bu_uxgkDV_KOxYg,708
6
6
  remoterf/common/tos_notice.txt,sha256=fUHXV6U9uhZDvVs8BcRi4kWbU1PeU9mkxML0n5DDQp8,334
@@ -22,8 +22,8 @@ remoterf/config/__init__.py,sha256=-1h_xQjiE66oiWRO-vnLGJ4smpgUNhFuV-ZreW9_tD4,6
22
22
  remoterf/config/cert_fetcher.py,sha256=_m4CiYxJPTckDrdynwUjwnehD_gd6yZoly5etfT83JY,6986
23
23
  remoterf/config/config.py,sha256=xuwYXS7zLgG77nSEn6br4X0vXK7Z2rlmBKedyDVI7Fc,9353
24
24
  remoterf/core/__init__.py,sha256=1E9ARnxVICp4uCpGNQT3Fb-jD9TvUYbJmctuUqPy8hU,1206
25
- remoterf/core/acc_login.py,sha256=Qct7vEsc0OIdVwmikOv2mVv9-ehH4CMVw7QWHe2yOsg,1010
26
- remoterf/core/app.py,sha256=bOdy0nuJC4r3ubB5_cAz48XV24YHDwn_0MjVBXpbOws,73373
25
+ remoterf/core/acc_login.py,sha256=i-uKtN2LPaGbPy0ngUzR1fIXWTxSMUwyDHF3ProEKz4,1052
26
+ remoterf/core/app.py,sha256=dnY4vsnQ3EUN6y_Voqrt5uSHcZVa0nx2IIGJKLK7Nxs,73626
27
27
  remoterf/core/banner_note.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
28
  remoterf/core/direct_path.py,sha256=PeqagybrFESHO9-LKwR8F8t14T0dJTZHIlRxepTQtoo,32291
29
29
  remoterf/core/dynamic_v2_transport.py,sha256=rR0Mfjh3Kcz4QJKJen2gsUNjYtHy22PfsZg2KLDIptI,22052
@@ -34,7 +34,7 @@ remoterf/core/v2_errors.py,sha256=Xmuta24cfQEy4FGG7HZk7B9hD5g4pGT5Hz8Eguy42lU,29
34
34
  remoterf/deployment/__init__.py,sha256=aEl9z32KMUBfRRm6Ho0-fM-VUtiKIRq4bQBU2_u29-c,69
35
35
  remoterf/deployment/backend.py,sha256=FNj3wYk0NSpt4LZnBNwU4OHSCFGLNGYmmuSuFZ6rIcQ,16155
36
36
  remoterf/deployment/direct.py,sha256=uD72drR0Z21cNG7xSZUeDiQ80OSspFLj9BS_vj9Dapk,1048
37
- remoterf/deployment/homes.py,sha256=BSdBMpS4DveL35lS-YLlKKdSvNxJrjaGeRyQZAfQb6g,12358
37
+ remoterf/deployment/homes.py,sha256=vl22wenXDEZDrXJGDr2qcsxxrvkQFUXFAOjwrLQ9I38,12985
38
38
  remoterf/deployment/http.py,sha256=ePwOyRrkwNiciIOImqMiS1VoJCw51j6MeLEcaMavgh0,4564
39
39
  remoterf/deployment/state.py,sha256=rXHEMf-kJP1sYCJn-VD84ZNalkYUaNAiYaoaVu4uo3U,6541
40
40
  remoterf/drivers/__init__.py,sha256=DXjon8E0R1X27fDQDy6IrwzqTFwrT6-suC5VSDXUP8Y,1250
@@ -59,9 +59,9 @@ remoterf/drivers/ti_mmwave/ti_mmwave_remote.py,sha256=hYUJUtPz3yRgGsmXzwo95ZYnvJ
59
59
  remoterf/drivers/usrp/__init__.py,sha256=y79nl50_4dV9-AI3cfDptOAWeR58fAaihHObqJI9HJM,780
60
60
  remoterf/drivers/usrp/usrp_remote.py,sha256=hBh_CmGOAoEkkdQQ8uPFAsBA6LVeZsPSlpPGgo1c7sM,115018
61
61
  remoterf/drivers/usrp/usrp_remote.pyi,sha256=MG7rMJdjyT0hLLoJmnS1emDQjgepWz695GbFED3v-T4,11810
62
- remoterf-2.2.2.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
63
- remoterf-2.2.2.dist-info/METADATA,sha256=ao6P--YcXdeAseHEKKbiuZ9j_0LQxE5Cilb4zZ5LlOQ,12778
64
- remoterf-2.2.2.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
65
- remoterf-2.2.2.dist-info/entry_points.txt,sha256=83-XNRsKpeQK8A0rzkPfjwb4zF4m3l3cCRhxWm_Er0w,56
66
- remoterf-2.2.2.dist-info/top_level.txt,sha256=BUtCT3KOhL-A4r6WL4RslW53rsZflOhHwq77RODYhlk,9
67
- remoterf-2.2.2.dist-info/RECORD,,
62
+ remoterf-2.2.3.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
63
+ remoterf-2.2.3.dist-info/METADATA,sha256=LP22rygDfwp8cZnDi2euOiC6OZ32rJIkIW_f3qny3pY,12778
64
+ remoterf-2.2.3.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
65
+ remoterf-2.2.3.dist-info/entry_points.txt,sha256=83-XNRsKpeQK8A0rzkPfjwb4zF4m3l3cCRhxWm_Er0w,56
66
+ remoterf-2.2.3.dist-info/top_level.txt,sha256=BUtCT3KOhL-A4r6WL4RslW53rsZflOhHwq77RODYhlk,9
67
+ remoterf-2.2.3.dist-info/RECORD,,