RemoteRF 0.0.7.47__tar.gz → 0.0.7.48__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.
Files changed (35) hide show
  1. {remoterf-0.0.7.47/src/remoteRF.egg-info → remoterf-0.0.7.48}/PKG-INFO +1 -1
  2. {remoterf-0.0.7.47 → remoterf-0.0.7.48}/setup.py +17 -7
  3. remoterf-0.0.7.48/src/remoteRF/cli.py +141 -0
  4. {remoterf-0.0.7.47 → remoterf-0.0.7.48}/src/remoteRF/config/cert_fetcher.py +0 -22
  5. {remoterf-0.0.7.47 → remoterf-0.0.7.48}/src/remoteRF/config/config_cli.py +55 -15
  6. {remoterf-0.0.7.47 → remoterf-0.0.7.48}/src/remoteRF/core/acc_login.py +1 -1
  7. {remoterf-0.0.7.47 → remoterf-0.0.7.48}/src/remoteRF/core/version.py +1 -1
  8. {remoterf-0.0.7.47 → remoterf-0.0.7.48/src/remoteRF.egg-info}/PKG-INFO +1 -1
  9. {remoterf-0.0.7.47 → remoterf-0.0.7.48}/src/remoteRF.egg-info/SOURCES.txt +1 -0
  10. {remoterf-0.0.7.47 → remoterf-0.0.7.48}/src/remoteRF.egg-info/entry_points.txt +1 -0
  11. {remoterf-0.0.7.47 → remoterf-0.0.7.48}/LICENSE +0 -0
  12. {remoterf-0.0.7.47 → remoterf-0.0.7.48}/MANIFEST.in +0 -0
  13. {remoterf-0.0.7.47 → remoterf-0.0.7.48}/README.md +0 -0
  14. {remoterf-0.0.7.47 → remoterf-0.0.7.48}/setup.cfg +0 -0
  15. {remoterf-0.0.7.47 → remoterf-0.0.7.48}/src/remoteRF/__init__.py +0 -0
  16. {remoterf-0.0.7.47 → remoterf-0.0.7.48}/src/remoteRF/common/__init__.py +0 -0
  17. {remoterf-0.0.7.47 → remoterf-0.0.7.48}/src/remoteRF/common/grpc/__init__.py +0 -0
  18. {remoterf-0.0.7.47 → remoterf-0.0.7.48}/src/remoteRF/common/grpc/grpc_pb2.py +0 -0
  19. {remoterf-0.0.7.47 → remoterf-0.0.7.48}/src/remoteRF/common/grpc/grpc_pb2_grpc.py +0 -0
  20. {remoterf-0.0.7.47 → remoterf-0.0.7.48}/src/remoteRF/common/utils/__init__.py +0 -0
  21. {remoterf-0.0.7.47 → remoterf-0.0.7.48}/src/remoteRF/common/utils/ansi_codes.py +0 -0
  22. {remoterf-0.0.7.47 → remoterf-0.0.7.48}/src/remoteRF/common/utils/api_token.py +0 -0
  23. {remoterf-0.0.7.47 → remoterf-0.0.7.48}/src/remoteRF/common/utils/list_string.py +0 -0
  24. {remoterf-0.0.7.47 → remoterf-0.0.7.48}/src/remoteRF/common/utils/process_arg.py +0 -0
  25. {remoterf-0.0.7.47 → remoterf-0.0.7.48}/src/remoteRF/config/__init__.py +0 -0
  26. {remoterf-0.0.7.47 → remoterf-0.0.7.48}/src/remoteRF/core/__init__.py +0 -0
  27. {remoterf-0.0.7.47 → remoterf-0.0.7.48}/src/remoteRF/core/app.py +0 -0
  28. {remoterf-0.0.7.47 → remoterf-0.0.7.48}/src/remoteRF/core/grpc_acc.py +0 -0
  29. {remoterf-0.0.7.47 → remoterf-0.0.7.48}/src/remoteRF/core/grpc_client.py +0 -0
  30. {remoterf-0.0.7.47 → remoterf-0.0.7.48}/src/remoteRF/drivers/__init__.py +0 -0
  31. {remoterf-0.0.7.47 → remoterf-0.0.7.48}/src/remoteRF/drivers/adalm_pluto/__init__.py +0 -0
  32. {remoterf-0.0.7.47 → remoterf-0.0.7.48}/src/remoteRF/drivers/adalm_pluto/pluto_remote.py +0 -0
  33. {remoterf-0.0.7.47 → remoterf-0.0.7.48}/src/remoteRF.egg-info/dependency_links.txt +0 -0
  34. {remoterf-0.0.7.47 → remoterf-0.0.7.48}/src/remoteRF.egg-info/requires.txt +0 -0
  35. {remoterf-0.0.7.47 → remoterf-0.0.7.48}/src/remoteRF.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: remoterf
3
- Version: 0.0.7.47
3
+ Version: 0.0.7.48
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: Ethan Ge
6
6
  Author-email: ethoGalaxy@gmail.com
@@ -6,7 +6,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
6
6
 
7
7
  setup(
8
8
  name="remoterf",
9
- version="0.0.7.47",
9
+ version="0.0.7.48",
10
10
  author="Ethan Ge",
11
11
  author_email="ethoGalaxy@gmail.com",
12
12
  description="A python API to remotely access signal centric hardware. Client-side only! Courtesy of Wireless Lab @ UCLA & Prof. Ian Roberts.",
@@ -25,11 +25,21 @@ setup(
25
25
  "Operating System :: OS Independent",
26
26
  ],
27
27
  python_requires='>=3.10',
28
+ # entry_points={
29
+ # 'console_scripts': [
30
+ # 'remoterf-login=remoteRF.core.acc_login:main',
31
+ # 'remoterf-v=remoteRF.core.version:main',
32
+ # 'remoterf-config=remoteRF.config.config_cli:main',
33
+ # ],
34
+ # },
35
+
28
36
  entry_points={
29
- 'console_scripts': [
30
- 'remoterf-login=remoteRF.core.acc_login:main',
31
- 'remoterf-v=remoteRF.core.version:main',
32
- 'remoterf-config=remoteRF.config.config_cli:main',
33
- ],
34
- },
37
+ "console_scripts": [
38
+ "remoterf=remoteRF.cli:main",
39
+ "remoterf-login=remoteRF.core.acc_login:main",
40
+ "remoterf-v=remoteRF.core.version:main",
41
+ "remoterf-config=remoteRF.config.config_cli:main",
42
+ ],
43
+ },
44
+
35
45
  )
@@ -0,0 +1,141 @@
1
+ # src/remoteRF/cli.py
2
+ from __future__ import annotations
3
+
4
+ import argparse
5
+ import sys
6
+ from typing import Optional, Sequence
7
+
8
+ from remoteRF.core.acc_login import main as login_main
9
+ from remoteRF.core.version import main as version_main
10
+ from remoteRF.config.config_cli import main as config_main
11
+
12
+
13
+ def build_parser() -> argparse.ArgumentParser:
14
+ p = argparse.ArgumentParser(
15
+ prog="remoterf",
16
+ formatter_class=argparse.RawTextHelpFormatter,
17
+ add_help=True,
18
+ description=(
19
+ "RemoteRF unified CLI\n\n"
20
+ "Examples:\n"
21
+ " remoterf --login\n"
22
+ " remoterf -l\n"
23
+ " remoterf --config --addr 164.67.195.207:61005\n"
24
+ " remoterf -c -a 164.67.195.207:61005\n"
25
+ " remoterf --config --wipe\n"
26
+ " remoterf -v\n"
27
+ ),
28
+ )
29
+
30
+ mode = p.add_mutually_exclusive_group()
31
+
32
+ mode.add_argument("-l", "--login", action="store_true", help="Login / register (interactive).")
33
+ mode.add_argument("-c", "--config", action="store_true", help="Configure server target / CA cert.")
34
+ mode.add_argument("-v", "--version", action="store_true", help="Print version and exit.")
35
+
36
+ # These are only meaningful with --config, but we accept them at top-level
37
+ # so your UX works as requested.
38
+ p.add_argument(
39
+ "-a", "--addr", "-addr",
40
+ dest="addr",
41
+ default=None,
42
+ help="Server address (host:port). Used with --config / -c.",
43
+ )
44
+
45
+ p.add_argument(
46
+ "-w", "--wipe",
47
+ action="store_true",
48
+ help="Wipe local config (~/.config/remoterf). Used with --config / -c.",
49
+ )
50
+
51
+ p.add_argument(
52
+ "--yes",
53
+ action="store_true",
54
+ help="Skip confirmation prompts (use with --config --wipe).",
55
+ )
56
+
57
+ return p
58
+
59
+
60
+ def main(argv: Optional[Sequence[str]] = None) -> int:
61
+ argv = list(sys.argv[1:] if argv is None else argv)
62
+
63
+ parser = build_parser()
64
+
65
+ # No args => help panel
66
+ if len(argv) == 0:
67
+ parser.print_help()
68
+ return 0
69
+
70
+ args, extra = parser.parse_known_args(argv)
71
+
72
+ # --- Version ---
73
+ if args.version:
74
+ if extra:
75
+ parser.error(f"Unexpected arguments for --version: {' '.join(extra)}")
76
+ # If your version_main supports argv, pass [].
77
+ try:
78
+ version_main([])
79
+ except TypeError:
80
+ version_main()
81
+ return 0
82
+
83
+ # --- Login ---
84
+ if args.login:
85
+ if extra:
86
+ parser.error(f"Unexpected arguments for --login: {' '.join(extra)}")
87
+ try:
88
+ login_main([])
89
+ except TypeError:
90
+ login_main()
91
+ return 0
92
+
93
+ # --- Config ---
94
+ if args.config:
95
+ cfg_argv: list[str] = []
96
+
97
+ # Normalize to whatever config_cli expects.
98
+ # If your config_cli supports --wipe/--yes, pass them through.
99
+ if args.wipe:
100
+ cfg_argv.append("--wipe")
101
+ if args.yes:
102
+ cfg_argv.append("--yes")
103
+
104
+ # Address handling
105
+ if args.addr:
106
+ # If config_cli expects a positional addr, pass it positionally:
107
+ cfg_argv.append(args.addr)
108
+ # If your config_cli instead expects --addr, switch to:
109
+ # cfg_argv += ["--addr", args.addr]
110
+
111
+ # Preserve any extra args for config_cli (if you want)
112
+ cfg_argv += extra
113
+
114
+ # If neither addr nor wipe was supplied, show config help-like message.
115
+ if not args.addr and not args.wipe and len(extra) == 0:
116
+ # Call config_cli with --help if it supports it; otherwise print ours.
117
+ try:
118
+ config_main(["--help"])
119
+ except Exception:
120
+ parser.error("Config mode requires --addr <host:port> or --wipe.")
121
+ return 0
122
+
123
+ try:
124
+ config_main(cfg_argv)
125
+ except TypeError:
126
+ # Fallback if config_main does not accept argv; last resort:
127
+ old = sys.argv[:]
128
+ try:
129
+ sys.argv = ["remoterf-config", *cfg_argv]
130
+ config_main()
131
+ finally:
132
+ sys.argv = old
133
+ return 0
134
+
135
+ # If user passed only -a/-w without -c/--config, show help
136
+ parser.print_help()
137
+ return 0
138
+
139
+
140
+ if __name__ == "__main__":
141
+ raise SystemExit(main())
@@ -1,26 +1,4 @@
1
1
  # cert_fetcher.py
2
- """
3
- RemoteRF Client-Side Cert Fetcher (bootstrap)
4
-
5
- Purpose:
6
- - Fetch the public CA certificate (ca.crt) from a server's bootstrap endpoint
7
- (your cert_provider) and save it locally for later use in:
8
- grpc.ssl_channel_credentials(root_certificates=ca_bytes)
9
-
10
- Security note (TOFU):
11
- - This fetch is typically done over plaintext HTTP (or raw TCP). The CA cert is public,
12
- but authenticity is not guaranteed on first fetch. If you want TOFU done "right",
13
- you should display the SHA256 fingerprint and require user confirmation elsewhere.
14
- This module focuses only on: fetch + save + return success.
15
-
16
- Behavior:
17
- - Attempts HTTP GET first: http://{host}:{port}/ca.crt
18
- - If HTTP fails, falls back to raw TCP (reads until EOF).
19
- - Saves to a per-profile file under ~/.config/remoterf/certs/ by default.
20
-
21
- Exported API:
22
- - fetch_and_save_ca_cert(host, port, *, out_path=None, profile=None, timeout_sec=3.0) -> bool
23
- """
24
2
 
25
3
  from __future__ import annotations
26
4
 
@@ -2,19 +2,18 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- import argparse
6
5
  import os
7
6
  import sys
7
+ import shutil
8
8
  from pathlib import Path
9
9
  from typing import Tuple
10
10
 
11
- from .cert_fetcher import fetch_and_save_ca_cert # your earlier module
11
+ from .cert_fetcher import fetch_and_save_ca_cert
12
12
 
13
13
  # -----------------------------
14
14
  # Local config locations
15
15
  # -----------------------------
16
16
  def _config_root() -> Path:
17
- # Keep it simple and consistent with earlier suggestions.
18
17
  return Path(os.path.expanduser("~")) / ".config" / "remoterf"
19
18
 
20
19
  def _env_path() -> Path:
@@ -40,16 +39,10 @@ def _parse_hostport(s: str) -> Tuple[str, int]:
40
39
  raise ValueError("Port out of range")
41
40
  return host, port
42
41
 
43
-
44
42
  def _write_env_kv(path: Path, kv: dict[str, str]) -> None:
45
- """
46
- Writes/overwrites a simple dotenv-style file.
47
- (We overwrite the whole file for simplicity and correctness.)
48
- """
49
43
  path.parent.mkdir(parents=True, exist_ok=True)
50
- lines = []
44
+ lines: list[str] = []
51
45
  for k, v in kv.items():
52
- # Quote only if needed; keep simple and safe.
53
46
  if any(c.isspace() for c in v) or any(c in v for c in ['"', "'"]):
54
47
  v = v.replace('"', '\\"')
55
48
  lines.append(f'{k}="{v}"')
@@ -57,9 +50,29 @@ def _write_env_kv(path: Path, kv: dict[str, str]) -> None:
57
50
  lines.append(f"{k}={v}")
58
51
  path.write_text("\n".join(lines) + "\n", encoding="utf-8")
59
52
 
60
- def main() -> None:
53
+ def _confirm_wipe(root: Path) -> bool:
54
+ prompt = (
55
+ f"This will permanently delete ALL RemoteRF config at:\n"
56
+ f" {root}\n\n"
57
+ f"Type 'wipe' to confirm: "
58
+ )
59
+ try:
60
+ return input(prompt).strip().lower() == "wipe"
61
+ except KeyboardInterrupt:
62
+ print("\nCancelled.")
63
+ return False
64
+
65
+ def _wipe_config(root: Path) -> None:
66
+ if not root.exists():
67
+ print(f"No config found at: {root}")
68
+ return
69
+ if not root.is_dir():
70
+ raise RuntimeError(f"Config root exists but is not a directory: {root}")
71
+ shutil.rmtree(root)
72
+ print(f"Wiped RemoteRF config: {root}")
73
+
74
+ def main(argv=None) -> None:
61
75
  import argparse
62
- import sys
63
76
 
64
77
  parser = argparse.ArgumentParser(
65
78
  prog="remoterf-config",
@@ -77,13 +90,41 @@ def main() -> None:
77
90
  help="Server address in host:port form. Example: 164.67.195.207:61005",
78
91
  )
79
92
 
93
+ parser.add_argument(
94
+ "--wipe",
95
+ action="store_true",
96
+ help="Delete ALL existing RemoteRF config at ~/.config/remoterf and exit.",
97
+ )
98
+
99
+ parser.add_argument(
100
+ "--yes",
101
+ action="store_true",
102
+ help="Skip confirmation prompts (use with --wipe).",
103
+ )
104
+
80
105
  args = parser.parse_args()
81
106
 
107
+ # ----- Wipe mode -----
108
+ if args.wipe:
109
+ root = _config_root()
110
+ if not args.yes:
111
+ if not _confirm_wipe(root):
112
+ print("Wipe aborted.")
113
+ sys.exit(1)
114
+ try:
115
+ _wipe_config(root)
116
+ sys.exit(0)
117
+ except Exception as e:
118
+ print(f"Error wiping config: {e}", file=sys.stderr)
119
+ sys.exit(1)
120
+
121
+ # ----- Normal configure mode -----
82
122
  if not args.addr:
83
123
  print(
84
124
  "\nError: missing required argument: host:port\n\n"
85
125
  "Usage:\n"
86
- " remoterf-config <host:port>\n\n"
126
+ " remoterf-config <host:port>\n"
127
+ " remoterf-config --wipe [--yes]\n\n"
87
128
  "Example:\n"
88
129
  " remoterf-config 164.67.195.207:61005\n"
89
130
  )
@@ -95,8 +136,7 @@ def main() -> None:
95
136
  print(f"Error: invalid addr '{args.addr}': {e}", file=sys.stderr)
96
137
  sys.exit(2)
97
138
 
98
- # Single-arg policy
99
- cert_port = grpc_port + 1 # cert-provider convention
139
+ cert_port = grpc_port + 1
100
140
  profile = "default"
101
141
  timeout_sec = 3.0
102
142
  overwrite = True
@@ -1,4 +1,4 @@
1
1
  from . import app as client
2
2
 
3
- def main():
3
+ def main(argv=None):
4
4
  pass
@@ -1,6 +1,6 @@
1
1
  from importlib.metadata import version, PackageNotFoundError
2
2
 
3
- def main():
3
+ def main(argv=None):
4
4
  try:
5
5
  v = version("remoterf")
6
6
  except PackageNotFoundError:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: remoterf
3
- Version: 0.0.7.47
3
+ Version: 0.0.7.48
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: Ethan Ge
6
6
  Author-email: ethoGalaxy@gmail.com
@@ -3,6 +3,7 @@ MANIFEST.in
3
3
  README.md
4
4
  setup.py
5
5
  src/remoteRF/__init__.py
6
+ src/remoteRF/cli.py
6
7
  src/remoteRF.egg-info/PKG-INFO
7
8
  src/remoteRF.egg-info/SOURCES.txt
8
9
  src/remoteRF.egg-info/dependency_links.txt
@@ -1,4 +1,5 @@
1
1
  [console_scripts]
2
+ remoterf = remoteRF.cli:main
2
3
  remoterf-config = remoteRF.config.config_cli:main
3
4
  remoterf-login = remoteRF.core.acc_login:main
4
5
  remoterf-v = remoteRF.core.version:main
File without changes
File without changes
File without changes
File without changes