RemoteRF 0.0.7.45__tar.gz → 0.0.7.47__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.
- {remoterf-0.0.7.45/src/remoteRF.egg-info → remoterf-0.0.7.47}/PKG-INFO +2 -1
- {remoterf-0.0.7.45 → remoterf-0.0.7.47}/setup.py +2 -2
- {remoterf-0.0.7.45 → remoterf-0.0.7.47}/src/remoteRF/config/config_cli.py +17 -22
- {remoterf-0.0.7.45 → remoterf-0.0.7.47}/src/remoteRF/core/app.py +34 -2
- {remoterf-0.0.7.45 → remoterf-0.0.7.47}/src/remoteRF/core/grpc_acc.py +8 -1
- remoterf-0.0.7.47/src/remoteRF/core/grpc_client.py +320 -0
- {remoterf-0.0.7.45 → remoterf-0.0.7.47/src/remoteRF.egg-info}/PKG-INFO +2 -1
- {remoterf-0.0.7.45 → remoterf-0.0.7.47}/src/remoteRF.egg-info/requires.txt +1 -0
- remoterf-0.0.7.45/src/remoteRF/core/grpc_client.py +0 -102
- {remoterf-0.0.7.45 → remoterf-0.0.7.47}/LICENSE +0 -0
- {remoterf-0.0.7.45 → remoterf-0.0.7.47}/MANIFEST.in +0 -0
- {remoterf-0.0.7.45 → remoterf-0.0.7.47}/README.md +0 -0
- {remoterf-0.0.7.45 → remoterf-0.0.7.47}/setup.cfg +0 -0
- {remoterf-0.0.7.45 → remoterf-0.0.7.47}/src/remoteRF/__init__.py +0 -0
- {remoterf-0.0.7.45 → remoterf-0.0.7.47}/src/remoteRF/common/__init__.py +0 -0
- {remoterf-0.0.7.45 → remoterf-0.0.7.47}/src/remoteRF/common/grpc/__init__.py +0 -0
- {remoterf-0.0.7.45 → remoterf-0.0.7.47}/src/remoteRF/common/grpc/grpc_pb2.py +0 -0
- {remoterf-0.0.7.45 → remoterf-0.0.7.47}/src/remoteRF/common/grpc/grpc_pb2_grpc.py +0 -0
- {remoterf-0.0.7.45 → remoterf-0.0.7.47}/src/remoteRF/common/utils/__init__.py +0 -0
- {remoterf-0.0.7.45 → remoterf-0.0.7.47}/src/remoteRF/common/utils/ansi_codes.py +0 -0
- {remoterf-0.0.7.45 → remoterf-0.0.7.47}/src/remoteRF/common/utils/api_token.py +0 -0
- {remoterf-0.0.7.45 → remoterf-0.0.7.47}/src/remoteRF/common/utils/list_string.py +0 -0
- {remoterf-0.0.7.45 → remoterf-0.0.7.47}/src/remoteRF/common/utils/process_arg.py +0 -0
- {remoterf-0.0.7.45 → remoterf-0.0.7.47}/src/remoteRF/config/__init__.py +0 -0
- {remoterf-0.0.7.45 → remoterf-0.0.7.47}/src/remoteRF/config/cert_fetcher.py +0 -0
- {remoterf-0.0.7.45 → remoterf-0.0.7.47}/src/remoteRF/core/__init__.py +0 -0
- {remoterf-0.0.7.45 → remoterf-0.0.7.47}/src/remoteRF/core/acc_login.py +0 -0
- {remoterf-0.0.7.45 → remoterf-0.0.7.47}/src/remoteRF/core/version.py +0 -0
- {remoterf-0.0.7.45 → remoterf-0.0.7.47}/src/remoteRF/drivers/__init__.py +0 -0
- {remoterf-0.0.7.45 → remoterf-0.0.7.47}/src/remoteRF/drivers/adalm_pluto/__init__.py +0 -0
- {remoterf-0.0.7.45 → remoterf-0.0.7.47}/src/remoteRF/drivers/adalm_pluto/pluto_remote.py +0 -0
- {remoterf-0.0.7.45 → remoterf-0.0.7.47}/src/remoteRF.egg-info/SOURCES.txt +0 -0
- {remoterf-0.0.7.45 → remoterf-0.0.7.47}/src/remoteRF.egg-info/dependency_links.txt +0 -0
- {remoterf-0.0.7.45 → remoterf-0.0.7.47}/src/remoteRF.egg-info/entry_points.txt +0 -0
- {remoterf-0.0.7.45 → remoterf-0.0.7.47}/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.
|
|
3
|
+
Version: 0.0.7.47
|
|
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
|
|
@@ -14,6 +14,7 @@ Requires-Dist: protobuf<6.0.0,>=5.0.0
|
|
|
14
14
|
Requires-Dist: numpy
|
|
15
15
|
Requires-Dist: prompt_toolkit
|
|
16
16
|
Requires-Dist: python-dotenv
|
|
17
|
+
Requires-Dist: prompt-toolkit
|
|
17
18
|
Dynamic: author
|
|
18
19
|
Dynamic: author-email
|
|
19
20
|
Dynamic: classifier
|
|
@@ -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.
|
|
9
|
+
version="0.0.7.47",
|
|
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.",
|
|
@@ -17,7 +17,7 @@ setup(
|
|
|
17
17
|
license_file='MIT',
|
|
18
18
|
include_package_data=True, # Includes files specified in MANIFEST.in
|
|
19
19
|
install_requires=[
|
|
20
|
-
"grpcio==1.71.0", "protobuf>=5.0.0,<6.0.0", "numpy", "prompt_toolkit", "python-dotenv"
|
|
20
|
+
"grpcio==1.71.0", "protobuf>=5.0.0,<6.0.0", "numpy", "prompt_toolkit", "python-dotenv", "prompt-toolkit"
|
|
21
21
|
],
|
|
22
22
|
classifiers=[
|
|
23
23
|
"Programming Language :: Python :: 3",
|
|
@@ -85,7 +85,7 @@ def main() -> None:
|
|
|
85
85
|
"Usage:\n"
|
|
86
86
|
" remoterf-config <host:port>\n\n"
|
|
87
87
|
"Example:\n"
|
|
88
|
-
" remoterf-config
|
|
88
|
+
" remoterf-config 164.67.195.207:61005\n"
|
|
89
89
|
)
|
|
90
90
|
sys.exit(2)
|
|
91
91
|
|
|
@@ -95,38 +95,33 @@ def main() -> None:
|
|
|
95
95
|
print(f"Error: invalid addr '{args.addr}': {e}", file=sys.stderr)
|
|
96
96
|
sys.exit(2)
|
|
97
97
|
|
|
98
|
-
|
|
98
|
+
# Single-arg policy
|
|
99
|
+
cert_port = grpc_port + 1 # cert-provider convention
|
|
100
|
+
profile = "default"
|
|
101
|
+
timeout_sec = 3.0
|
|
102
|
+
overwrite = True
|
|
99
103
|
|
|
100
|
-
# Destination CA cert file
|
|
101
104
|
certs_dir = _certs_dir()
|
|
102
105
|
certs_dir.mkdir(parents=True, exist_ok=True)
|
|
103
|
-
ca_out = certs_dir / f"{
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
out_path=ca_out,
|
|
113
|
-
timeout_sec=args.timeout,
|
|
114
|
-
overwrite=True,
|
|
115
|
-
)
|
|
106
|
+
ca_out = certs_dir / f"{profile}.crt"
|
|
107
|
+
|
|
108
|
+
fetched_ok = fetch_and_save_ca_cert(
|
|
109
|
+
host,
|
|
110
|
+
cert_port,
|
|
111
|
+
out_path=ca_out,
|
|
112
|
+
timeout_sec=timeout_sec,
|
|
113
|
+
overwrite=overwrite,
|
|
114
|
+
)
|
|
116
115
|
|
|
117
116
|
if not fetched_ok:
|
|
118
|
-
print(
|
|
119
|
-
f"Failed to fetch CA cert from {host}:{cert_port}.\n",
|
|
120
|
-
file=sys.stderr
|
|
121
|
-
)
|
|
117
|
+
print(f"Failed to fetch CA cert from {host}:{cert_port}.", file=sys.stderr)
|
|
122
118
|
sys.exit(1)
|
|
123
119
|
|
|
124
|
-
# Write local .env (or config) with chosen server and CA path
|
|
125
120
|
env_file = _env_path()
|
|
126
121
|
_write_env_kv(env_file, {
|
|
127
122
|
"REMOTERF_ADDR": f"{host}:{grpc_port}",
|
|
128
123
|
"REMOTERF_CA_CERT": str(ca_out),
|
|
129
|
-
"REMOTERF_PROFILE":
|
|
124
|
+
"REMOTERF_PROFILE": profile,
|
|
130
125
|
})
|
|
131
126
|
|
|
132
127
|
print("RemoteRF configured successfully.")
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from remoteRF.core.grpc_client import handle_admin_command
|
|
1
2
|
from . import *
|
|
2
3
|
from ..common.utils import *
|
|
3
4
|
|
|
@@ -30,6 +31,7 @@ def welcome():
|
|
|
30
31
|
|
|
31
32
|
account.password = password
|
|
32
33
|
account.email = input("Email: ") # TODO: Email verification.
|
|
34
|
+
account.enrollment_code = input("Enrollment Code: ")
|
|
33
35
|
# check if login was valid
|
|
34
36
|
os.system('cls' if os.name == 'nt' else 'clear')
|
|
35
37
|
|
|
@@ -59,6 +61,7 @@ def commands():
|
|
|
59
61
|
printf("'getdev' ", Sty.MAGENTA, " : View devices", Sty.DEFAULT)
|
|
60
62
|
printf("'help' or 'h' ", Sty.MAGENTA, " : Show this help message", Sty.DEFAULT)
|
|
61
63
|
printf("'perms' ", Sty.MAGENTA, " : View permissions", Sty.DEFAULT)
|
|
64
|
+
printf("'enroll' ", Sty.MAGENTA, " : Enroll with an enrollment code", Sty.DEFAULT)
|
|
62
65
|
printf("'exit' or 'quit' ", Sty.MAGENTA, ": Exit", Sty.DEFAULT)
|
|
63
66
|
printf("'getres' ", Sty.MAGENTA, " : View all reservations", Sty.DEFAULT)
|
|
64
67
|
printf("'myres' ", Sty.MAGENTA, " : View my reservations", Sty.DEFAULT)
|
|
@@ -66,8 +69,20 @@ def commands():
|
|
|
66
69
|
printf("'resdev' ", Sty.MAGENTA, " : Reserve a device", Sty.DEFAULT)
|
|
67
70
|
# printf("'resdev -n' ", Sty.MAGENTA, "- naive reserve device", Sty.DEFAULT)
|
|
68
71
|
# printf("'resdev s' ", Sty.MAGENTA, "- Reserve a Device (by single date)", Sty.DEFAULT)
|
|
69
|
-
|
|
70
|
-
|
|
72
|
+
|
|
73
|
+
if account.is_admin:
|
|
74
|
+
print()
|
|
75
|
+
printf("Admin Commands:", Sty.BOLD)
|
|
76
|
+
printf("'admin printa' ", Sty.MAGENTA, " : Print all accounts", Sty.DEFAULT)
|
|
77
|
+
printf("'admin printr' ", Sty.MAGENTA, " : Print all reservations", Sty.DEFAULT)
|
|
78
|
+
printf("'admin printp' ", Sty.MAGENTA, " : Print all perms", Sty.DEFAULT)
|
|
79
|
+
printf("'admin printd' ", Sty.MAGENTA, " : Print all devices", Sty.DEFAULT)
|
|
80
|
+
printf("'admin rm a <username>' ", Sty.MAGENTA, " : Remove one account", Sty.DEFAULT)
|
|
81
|
+
printf("'admin rm aa' ", Sty.MAGENTA, " : Remove all accounts", Sty.DEFAULT)
|
|
82
|
+
printf("'admin rm ar' ", Sty.MAGENTA, " : Remove all reservations", Sty.DEFAULT)
|
|
83
|
+
# If you expose set_account remotely:
|
|
84
|
+
printf("'admin setacc <username> <U|P|A> [args...]' ", Sty.MAGENTA, " : Set perms", Sty.DEFAULT)
|
|
85
|
+
|
|
71
86
|
|
|
72
87
|
def clear():
|
|
73
88
|
os.system('cls' if os.name == 'nt' else 'clear')
|
|
@@ -267,6 +282,18 @@ def perms():
|
|
|
267
282
|
printf(f'No restrictions on reservation count or duration.', Sty.DEFAULT)
|
|
268
283
|
else:
|
|
269
284
|
printf(f"Error: Unknown permission level {results[0]}", Sty.BRIGHT_RED)
|
|
285
|
+
|
|
286
|
+
def enroll():
|
|
287
|
+
code = session.prompt(stylize("Enter your enrollment code: ", Sty.DEFAULT))
|
|
288
|
+
account.enrollment_code = code
|
|
289
|
+
data = account.set_enroll()
|
|
290
|
+
|
|
291
|
+
if 'ace' in data.results:
|
|
292
|
+
print(f"Error: {unmap_arg(data.results['ace'])}")
|
|
293
|
+
return
|
|
294
|
+
else:
|
|
295
|
+
# todo: print out specifics, like group name (ie: successfully enrolled in ECE 132A)
|
|
296
|
+
printf("Enrollment successful.", Sty.BOLD_GREEN)
|
|
270
297
|
|
|
271
298
|
# New block scheduling
|
|
272
299
|
|
|
@@ -484,6 +511,8 @@ while True:
|
|
|
484
511
|
commands()
|
|
485
512
|
elif inpu == "perms":
|
|
486
513
|
perms()
|
|
514
|
+
elif inpu == "enroll":
|
|
515
|
+
enroll()
|
|
487
516
|
elif inpu == "quit" or inpu == "exit":
|
|
488
517
|
break
|
|
489
518
|
elif inpu == "getres":
|
|
@@ -496,10 +525,13 @@ while True:
|
|
|
496
525
|
interactive_reserve_next_days(block_minutes=30)
|
|
497
526
|
elif inpu == 'cancelres':
|
|
498
527
|
cancel_my_reservation()
|
|
528
|
+
|
|
499
529
|
elif inpu == 'resdev -n':
|
|
500
530
|
# check if user is admin
|
|
501
531
|
# if account.get_perms().results['UC'] == 'Admin':
|
|
502
532
|
reserve()
|
|
533
|
+
elif account.is_admin and inpu.strip().startswith("admin"):
|
|
534
|
+
handle_admin_command(inpu)
|
|
503
535
|
else:
|
|
504
536
|
print(f"Unknown command: {inpu}")
|
|
505
537
|
except KeyboardInterrupt:
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import ast
|
|
1
2
|
from .grpc_client import rpc_client
|
|
2
3
|
from ..common.utils import *
|
|
3
4
|
|
|
@@ -8,9 +9,10 @@ class RemoteRFAccount:
|
|
|
8
9
|
self.username = username
|
|
9
10
|
self.password = password
|
|
10
11
|
self.email = email
|
|
12
|
+
self.enrollment_code = ""
|
|
11
13
|
|
|
12
14
|
def create_user(self):
|
|
13
|
-
response = rpc_client(function_name="ACC:create_user", args={"un":map_arg(self.username), "pw":map_arg(self.password), "em":map_arg(self.email)})
|
|
15
|
+
response = rpc_client(function_name="ACC:create_user", args={"un":map_arg(self.username), "pw":map_arg(self.password), "em":map_arg(self.email), "ec":map_arg(self.enrollment_code)})
|
|
14
16
|
if 'UC' in response.results:
|
|
15
17
|
print(f'User {unmap_arg(response.results["UC"])} successfully created.')
|
|
16
18
|
return True
|
|
@@ -24,6 +26,8 @@ class RemoteRFAccount:
|
|
|
24
26
|
response = rpc_client(function_name="ACC:login", args={"un":map_arg(username), "pw":map_arg(password)})
|
|
25
27
|
if 'UC' in response.results:
|
|
26
28
|
print(f'User {unmap_arg(response.results["UC"])} successful login.')
|
|
29
|
+
|
|
30
|
+
self.is_admin = (ast.literal_eval(unmap_arg(self.get_perms().results['UC']))[0][0] == 'Admin')
|
|
27
31
|
return True
|
|
28
32
|
elif 'UE' in response.results:
|
|
29
33
|
print(f'Error: {unmap_arg(response.results["UE"])}')
|
|
@@ -49,4 +53,7 @@ class RemoteRFAccount:
|
|
|
49
53
|
def get_perms(self):
|
|
50
54
|
return rpc_client(function_name='ACC:get_perms', args={"un":map_arg(self.username), "pw":map_arg(self.password)})
|
|
51
55
|
|
|
56
|
+
def set_enroll(self):
|
|
57
|
+
return rpc_client(function_name='ACC:set_enroll', args={"un":map_arg(self.username), "pw":map_arg(self.password), "ec":map_arg(self.enrollment_code)})
|
|
58
|
+
|
|
52
59
|
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
import socket
|
|
2
|
+
import getpass
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
import os
|
|
5
|
+
from dotenv import load_dotenv
|
|
6
|
+
|
|
7
|
+
import grpc
|
|
8
|
+
from ..common.grpc import grpc_pb2
|
|
9
|
+
from ..common.grpc import grpc_pb2_grpc
|
|
10
|
+
from ..common.utils import *
|
|
11
|
+
|
|
12
|
+
load_dotenv(Path.home() / ".config" / "remoterf" / ".env")
|
|
13
|
+
addr = os.getenv("REMOTERF_ADDR") # "host:port"
|
|
14
|
+
ca_path = os.getenv("REMOTERF_CA_CERT") # path to saved CA cert
|
|
15
|
+
|
|
16
|
+
options = [
|
|
17
|
+
('grpc.max_send_message_length', 100 * 1024 * 1024),
|
|
18
|
+
('grpc.max_receive_message_length', 100 * 1024 * 1024),
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
# Server.crt
|
|
22
|
+
certs_path = Path(ca_path).expanduser().resolve()
|
|
23
|
+
with certs_path.open('rb') as f:
|
|
24
|
+
trusted_certs = f.read()
|
|
25
|
+
|
|
26
|
+
credentials = grpc.ssl_channel_credentials(root_certificates=trusted_certs)
|
|
27
|
+
channel = grpc.secure_channel(addr, credentials, options=options)
|
|
28
|
+
stub = grpc_pb2_grpc.GenericRPCStub(channel)
|
|
29
|
+
|
|
30
|
+
tcp_calls = 0
|
|
31
|
+
|
|
32
|
+
def get_tcp_calls():
|
|
33
|
+
return tcp_calls
|
|
34
|
+
|
|
35
|
+
def rpc_client(*, function_name, args):
|
|
36
|
+
global tcp_calls
|
|
37
|
+
tcp_calls += 1
|
|
38
|
+
# print(tcp_calls)
|
|
39
|
+
# if not is_connected:
|
|
40
|
+
# response = rpc_client(function_name="UserLogin", args={"username": grpc_pb2.Argument(string_value=input("Username: ")), "password": grpc_pb2.Argument(string_value=getpass.getpass("Password: ")), "client_ip": grpc_pb2.Argument(string_value=local_ip)})
|
|
41
|
+
# if (response.results['status'].string_value == 'Success'):
|
|
42
|
+
# print("Login successful.")
|
|
43
|
+
# is_connected = True
|
|
44
|
+
|
|
45
|
+
# TODO: Handle user login
|
|
46
|
+
|
|
47
|
+
# print(f"Opening connection to {server_ip}:{server_port}")
|
|
48
|
+
|
|
49
|
+
# TODO: Handle Errors
|
|
50
|
+
|
|
51
|
+
# print(f"Calling function: {function_name}")
|
|
52
|
+
response = stub.Call(grpc_pb2.GenericRPCRequest(function_name=function_name, args=args))
|
|
53
|
+
|
|
54
|
+
if 'a' in response.results:
|
|
55
|
+
print(f"Error: {unmap_arg(response.results['a'])}")
|
|
56
|
+
exit()
|
|
57
|
+
|
|
58
|
+
if 'UE' in response.results:
|
|
59
|
+
print(f"UserError: {unmap_arg(response.results['UE'])}")
|
|
60
|
+
input("Hit enter to continue...")
|
|
61
|
+
|
|
62
|
+
if 'Message' in response.results:
|
|
63
|
+
print(f"{unmap_arg(response.results['Message'])}")
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
return response
|
|
67
|
+
|
|
68
|
+
#region Example Usage
|
|
69
|
+
|
|
70
|
+
# if __name__ == '__main__':
|
|
71
|
+
# args={
|
|
72
|
+
# "key1": grpc_pb2.Argument(string_value="Hello"),
|
|
73
|
+
# "key2": grpc_pb2.Argument(int32_value=123),
|
|
74
|
+
# "key3": grpc_pb2.Argument(float_value=4.56),
|
|
75
|
+
# "key4": grpc_pb2.Argument(bool_value=True),
|
|
76
|
+
# "client_ip": grpc_pb2.Argument(string_value=local_ip)
|
|
77
|
+
# }
|
|
78
|
+
|
|
79
|
+
# response = rpc_client(function_name="echo", args=args)
|
|
80
|
+
|
|
81
|
+
# if 'client_ip' in response.results:
|
|
82
|
+
# del response.results['client_ip']
|
|
83
|
+
|
|
84
|
+
# # Print results
|
|
85
|
+
# print("Received response:")
|
|
86
|
+
# for key, arg in response.results.items():
|
|
87
|
+
# # Decode the oneof fields
|
|
88
|
+
# if arg.HasField('string_value'):
|
|
89
|
+
# value = arg.string_value
|
|
90
|
+
# elif arg.HasField('int32_value'):
|
|
91
|
+
# value = arg.int32_value
|
|
92
|
+
# elif arg.HasField('float_value'):
|
|
93
|
+
# value = arg.float_value
|
|
94
|
+
# elif arg.HasField('bool_value'):
|
|
95
|
+
# value = arg.bool_value
|
|
96
|
+
# else:
|
|
97
|
+
# value = "Undefined"
|
|
98
|
+
|
|
99
|
+
# print(f"{key}: {value}")
|
|
100
|
+
|
|
101
|
+
#endregion
|
|
102
|
+
|
|
103
|
+
from typing import Any, Dict, Optional
|
|
104
|
+
|
|
105
|
+
def handle_admin_command(inpu: str):
|
|
106
|
+
"""
|
|
107
|
+
Parses commands like:
|
|
108
|
+
admin help
|
|
109
|
+
admin printa | printr | printp | printd
|
|
110
|
+
admin rm aa | rm ar | rm a <username>
|
|
111
|
+
admin setacc <username> <U|P|A> [devices=1,2,3] [max_res=5] [max_time=1800]
|
|
112
|
+
|
|
113
|
+
Requires account.is_admin == True (client-side gate). Server still enforces.
|
|
114
|
+
"""
|
|
115
|
+
if not getattr(account, "is_admin", False):
|
|
116
|
+
print("Access denied: you are not an Admin.")
|
|
117
|
+
return
|
|
118
|
+
|
|
119
|
+
tokens = (inpu or "").strip().split()
|
|
120
|
+
if len(tokens) < 2 or tokens[0].lower() != "admin":
|
|
121
|
+
print("Usage: admin <command>. Try: admin help")
|
|
122
|
+
return
|
|
123
|
+
|
|
124
|
+
cmd = tokens[1].lower()
|
|
125
|
+
|
|
126
|
+
def call_admin(fn: str, extra: dict | None = None):
|
|
127
|
+
return remote_admin_rpc_client(
|
|
128
|
+
function_name=fn,
|
|
129
|
+
auth_un=account.username,
|
|
130
|
+
auth_pw=account.password,
|
|
131
|
+
args=extra or {},
|
|
132
|
+
print_result=True,
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
if cmd in ("help", "h"):
|
|
136
|
+
print("Admin commands:")
|
|
137
|
+
print(" admin printa - Print all accounts")
|
|
138
|
+
print(" admin printr - Print all reservations")
|
|
139
|
+
print(" admin printp - Print all perms")
|
|
140
|
+
print(" admin printd - Print all devices")
|
|
141
|
+
print(" admin rm aa - Remove all accounts")
|
|
142
|
+
print(" admin rm ar - Remove all reservations")
|
|
143
|
+
print(" admin rm a <username> - Remove one account")
|
|
144
|
+
print(" admin setacc <u> <U|P|A> [devices=1,2] [max_res=3] [max_time=1800]")
|
|
145
|
+
return
|
|
146
|
+
|
|
147
|
+
# ----- print* -----
|
|
148
|
+
if cmd in ("printa", "print_accounts", "print_all_accounts"):
|
|
149
|
+
call_admin("print_all_accounts")
|
|
150
|
+
return
|
|
151
|
+
|
|
152
|
+
if cmd in ("printr", "print_res", "print_all_reservations"):
|
|
153
|
+
call_admin("print_all_reservations")
|
|
154
|
+
return
|
|
155
|
+
|
|
156
|
+
if cmd in ("printp", "print_perms", "print_all_perms"):
|
|
157
|
+
call_admin("print_all_perms")
|
|
158
|
+
return
|
|
159
|
+
|
|
160
|
+
if cmd in ("printd", "print_devices", "print_all_devices"):
|
|
161
|
+
call_admin("print_all_devices")
|
|
162
|
+
return
|
|
163
|
+
|
|
164
|
+
# ----- rm -----
|
|
165
|
+
if cmd == "rm":
|
|
166
|
+
if len(tokens) < 3:
|
|
167
|
+
print("Usage: admin rm <aa|ar|a> [username]")
|
|
168
|
+
return
|
|
169
|
+
|
|
170
|
+
sub = tokens[2].lower()
|
|
171
|
+
|
|
172
|
+
if sub == "aa":
|
|
173
|
+
call_admin("remove_all_users")
|
|
174
|
+
return
|
|
175
|
+
|
|
176
|
+
if sub == "ar":
|
|
177
|
+
call_admin("remove_all_reservations")
|
|
178
|
+
return
|
|
179
|
+
|
|
180
|
+
if sub == "a":
|
|
181
|
+
if len(tokens) < 4:
|
|
182
|
+
print("Usage: admin rm a <username>")
|
|
183
|
+
return
|
|
184
|
+
call_admin("remove_user", {"username": tokens[3]})
|
|
185
|
+
return
|
|
186
|
+
|
|
187
|
+
print("Unknown rm subcommand. Use: aa, ar, a <username>")
|
|
188
|
+
return
|
|
189
|
+
|
|
190
|
+
# ----- setacc -----
|
|
191
|
+
if cmd in ("setacc", "set_account", "setperm", "set"):
|
|
192
|
+
if len(tokens) < 4:
|
|
193
|
+
print("Usage: admin setacc <username> <U|P|A> [devices=1,2] [max_res=3] [max_time=1800]")
|
|
194
|
+
return
|
|
195
|
+
|
|
196
|
+
target_user = tokens[2]
|
|
197
|
+
perm = tokens[3].upper()
|
|
198
|
+
|
|
199
|
+
extra: dict = {"username": target_user, "permission": perm}
|
|
200
|
+
|
|
201
|
+
# Parse optional k=v args (very lightweight parser)
|
|
202
|
+
# Examples:
|
|
203
|
+
# devices=1,2,3
|
|
204
|
+
# max_res=5
|
|
205
|
+
# max_time=1800
|
|
206
|
+
for t in tokens[4:]:
|
|
207
|
+
if "=" not in t:
|
|
208
|
+
continue
|
|
209
|
+
k, v = t.split("=", 1)
|
|
210
|
+
k = k.strip().lower()
|
|
211
|
+
v = v.strip()
|
|
212
|
+
|
|
213
|
+
if k in ("devices", "device_list", "devices_allowed", "device_ids"):
|
|
214
|
+
# server-side remote_admin_call already supports "1,2,3" as string
|
|
215
|
+
extra["device_list"] = v
|
|
216
|
+
elif k in ("max_res", "max_reservations"):
|
|
217
|
+
extra["max_reservations"] = int(v)
|
|
218
|
+
elif k in ("max_time", "max_res_time", "max_reservation_time_sec"):
|
|
219
|
+
extra["max_reservation_time_sec"] = int(v)
|
|
220
|
+
|
|
221
|
+
call_admin("set_account", extra)
|
|
222
|
+
return
|
|
223
|
+
|
|
224
|
+
print(f"Unknown admin command: {cmd}. Try: admin help")
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def remote_admin_rpc_client(
|
|
228
|
+
*,
|
|
229
|
+
function_name: str,
|
|
230
|
+
auth_un: str,
|
|
231
|
+
auth_pw: str,
|
|
232
|
+
args: Optional[Dict[str, Any]] = None,
|
|
233
|
+
raise_on_error: bool = False,
|
|
234
|
+
print_result: bool = False,
|
|
235
|
+
) -> Dict[str, Any]:
|
|
236
|
+
"""
|
|
237
|
+
Client helper for RemoteAdmin:<function> calls.
|
|
238
|
+
|
|
239
|
+
Builds and sends:
|
|
240
|
+
function_name = "RemoteAdmin:<function_name>"
|
|
241
|
+
args include:
|
|
242
|
+
auth_un, auth_pw (mapped via map_arg)
|
|
243
|
+
+ any additional args (mapped via map_arg if not already grpc_pb2.Argument)
|
|
244
|
+
|
|
245
|
+
Returns:
|
|
246
|
+
{
|
|
247
|
+
"ok": bool,
|
|
248
|
+
"result": str | None,
|
|
249
|
+
"error": str | None,
|
|
250
|
+
"traceback": str | None,
|
|
251
|
+
"raw": grpc_pb2.GenericRPCResponse,
|
|
252
|
+
}
|
|
253
|
+
"""
|
|
254
|
+
fn = (function_name or "").strip()
|
|
255
|
+
if fn.startswith("RemoteAdmin:"):
|
|
256
|
+
rpc_fn = fn
|
|
257
|
+
else:
|
|
258
|
+
rpc_fn = f"RemoteAdmin:{fn}"
|
|
259
|
+
|
|
260
|
+
payload: Dict[str, Any] = {
|
|
261
|
+
"auth_un": map_arg(auth_un),
|
|
262
|
+
"auth_pw": map_arg(auth_pw),
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if args:
|
|
266
|
+
for k, v in args.items():
|
|
267
|
+
if v is None:
|
|
268
|
+
continue
|
|
269
|
+
# If caller already passed a grpc Argument, keep it.
|
|
270
|
+
if isinstance(v, grpc_pb2.Argument):
|
|
271
|
+
payload[str(k)] = v
|
|
272
|
+
else:
|
|
273
|
+
payload[str(k)] = map_arg(v)
|
|
274
|
+
|
|
275
|
+
resp = rpc_client(function_name=rpc_fn, args=payload)
|
|
276
|
+
|
|
277
|
+
# Parse the standardized RemoteAdmin response keys:
|
|
278
|
+
# Ok, Result, Error, Traceback (each typically map_arg-encoded)
|
|
279
|
+
results = getattr(resp, "results", {}) or {}
|
|
280
|
+
|
|
281
|
+
def _get_str(key: str) -> Optional[str]:
|
|
282
|
+
if key not in results:
|
|
283
|
+
return None
|
|
284
|
+
try:
|
|
285
|
+
return str(unmap_arg(results[key]))
|
|
286
|
+
except Exception:
|
|
287
|
+
try:
|
|
288
|
+
return str(results[key])
|
|
289
|
+
except Exception:
|
|
290
|
+
return None
|
|
291
|
+
|
|
292
|
+
ok_val = results.get("Ok", None)
|
|
293
|
+
ok = False
|
|
294
|
+
if ok_val is not None:
|
|
295
|
+
try:
|
|
296
|
+
ok = bool(unmap_arg(ok_val))
|
|
297
|
+
except Exception:
|
|
298
|
+
ok = False
|
|
299
|
+
|
|
300
|
+
out = {
|
|
301
|
+
"ok": ok,
|
|
302
|
+
"result": _get_str("Result"),
|
|
303
|
+
"error": _get_str("Error"),
|
|
304
|
+
"traceback": _get_str("Traceback"),
|
|
305
|
+
"raw": resp,
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if print_result:
|
|
309
|
+
if out["ok"]:
|
|
310
|
+
print(out["result"] or "OK")
|
|
311
|
+
else:
|
|
312
|
+
print(out["error"] or "RemoteAdmin call failed.")
|
|
313
|
+
if out["traceback"]:
|
|
314
|
+
print(out["traceback"])
|
|
315
|
+
|
|
316
|
+
if raise_on_error and not out["ok"]:
|
|
317
|
+
msg = out["error"] or "RemoteAdmin call failed."
|
|
318
|
+
raise RuntimeError(msg)
|
|
319
|
+
|
|
320
|
+
return out
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: remoterf
|
|
3
|
-
Version: 0.0.7.
|
|
3
|
+
Version: 0.0.7.47
|
|
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
|
|
@@ -14,6 +14,7 @@ Requires-Dist: protobuf<6.0.0,>=5.0.0
|
|
|
14
14
|
Requires-Dist: numpy
|
|
15
15
|
Requires-Dist: prompt_toolkit
|
|
16
16
|
Requires-Dist: python-dotenv
|
|
17
|
+
Requires-Dist: prompt-toolkit
|
|
17
18
|
Dynamic: author
|
|
18
19
|
Dynamic: author-email
|
|
19
20
|
Dynamic: classifier
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import socket
|
|
2
|
-
import getpass
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
import os
|
|
5
|
-
from dotenv import load_dotenv
|
|
6
|
-
|
|
7
|
-
import grpc
|
|
8
|
-
from ..common.grpc import grpc_pb2
|
|
9
|
-
from ..common.grpc import grpc_pb2_grpc
|
|
10
|
-
from ..common.utils import *
|
|
11
|
-
|
|
12
|
-
load_dotenv(Path.home() / ".config" / "remoterf" / ".env")
|
|
13
|
-
addr = os.getenv("REMOTERF_ADDR") # "host:port"
|
|
14
|
-
ca_path = os.getenv("REMOTERF_CA_CERT") # path to saved CA cert
|
|
15
|
-
|
|
16
|
-
options = [
|
|
17
|
-
('grpc.max_send_message_length', 100 * 1024 * 1024),
|
|
18
|
-
('grpc.max_receive_message_length', 100 * 1024 * 1024),
|
|
19
|
-
]
|
|
20
|
-
|
|
21
|
-
# Server.crt
|
|
22
|
-
certs_path = Path(ca_path).expanduser().resolve()
|
|
23
|
-
with certs_path.open('rb') as f:
|
|
24
|
-
trusted_certs = f.read()
|
|
25
|
-
|
|
26
|
-
credentials = grpc.ssl_channel_credentials(root_certificates=trusted_certs)
|
|
27
|
-
channel = grpc.secure_channel(addr, credentials, options=options)
|
|
28
|
-
stub = grpc_pb2_grpc.GenericRPCStub(channel)
|
|
29
|
-
|
|
30
|
-
tcp_calls = 0
|
|
31
|
-
|
|
32
|
-
def get_tcp_calls():
|
|
33
|
-
return tcp_calls
|
|
34
|
-
|
|
35
|
-
def rpc_client(*, function_name, args):
|
|
36
|
-
global tcp_calls
|
|
37
|
-
tcp_calls += 1
|
|
38
|
-
# print(tcp_calls)
|
|
39
|
-
# if not is_connected:
|
|
40
|
-
# response = rpc_client(function_name="UserLogin", args={"username": grpc_pb2.Argument(string_value=input("Username: ")), "password": grpc_pb2.Argument(string_value=getpass.getpass("Password: ")), "client_ip": grpc_pb2.Argument(string_value=local_ip)})
|
|
41
|
-
# if (response.results['status'].string_value == 'Success'):
|
|
42
|
-
# print("Login successful.")
|
|
43
|
-
# is_connected = True
|
|
44
|
-
|
|
45
|
-
# TODO: Handle user login
|
|
46
|
-
|
|
47
|
-
# print(f"Opening connection to {server_ip}:{server_port}")
|
|
48
|
-
|
|
49
|
-
# TODO: Handle Errors
|
|
50
|
-
|
|
51
|
-
# print(f"Calling function: {function_name}")
|
|
52
|
-
response = stub.Call(grpc_pb2.GenericRPCRequest(function_name=function_name, args=args))
|
|
53
|
-
|
|
54
|
-
if 'a' in response.results:
|
|
55
|
-
print(f"Error: {unmap_arg(response.results['a'])}")
|
|
56
|
-
exit()
|
|
57
|
-
|
|
58
|
-
if 'UE' in response.results:
|
|
59
|
-
print(f"UserError: {unmap_arg(response.results['UE'])}")
|
|
60
|
-
input("Hit enter to continue...")
|
|
61
|
-
|
|
62
|
-
if 'Message' in response.results:
|
|
63
|
-
print(f"{unmap_arg(response.results['Message'])}")
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
return response
|
|
67
|
-
|
|
68
|
-
#region Example Usage
|
|
69
|
-
|
|
70
|
-
# if __name__ == '__main__':
|
|
71
|
-
# args={
|
|
72
|
-
# "key1": grpc_pb2.Argument(string_value="Hello"),
|
|
73
|
-
# "key2": grpc_pb2.Argument(int32_value=123),
|
|
74
|
-
# "key3": grpc_pb2.Argument(float_value=4.56),
|
|
75
|
-
# "key4": grpc_pb2.Argument(bool_value=True),
|
|
76
|
-
# "client_ip": grpc_pb2.Argument(string_value=local_ip)
|
|
77
|
-
# }
|
|
78
|
-
|
|
79
|
-
# response = rpc_client(function_name="echo", args=args)
|
|
80
|
-
|
|
81
|
-
# if 'client_ip' in response.results:
|
|
82
|
-
# del response.results['client_ip']
|
|
83
|
-
|
|
84
|
-
# # Print results
|
|
85
|
-
# print("Received response:")
|
|
86
|
-
# for key, arg in response.results.items():
|
|
87
|
-
# # Decode the oneof fields
|
|
88
|
-
# if arg.HasField('string_value'):
|
|
89
|
-
# value = arg.string_value
|
|
90
|
-
# elif arg.HasField('int32_value'):
|
|
91
|
-
# value = arg.int32_value
|
|
92
|
-
# elif arg.HasField('float_value'):
|
|
93
|
-
# value = arg.float_value
|
|
94
|
-
# elif arg.HasField('bool_value'):
|
|
95
|
-
# value = arg.bool_value
|
|
96
|
-
# else:
|
|
97
|
-
# value = "Undefined"
|
|
98
|
-
|
|
99
|
-
# print(f"{key}: {value}")
|
|
100
|
-
|
|
101
|
-
#endregion
|
|
102
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|