remoteRF-server 1.1.0.dev38__py3-none-any.whl → 1.1.0.dev40__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.
- remoteRF_server/server/commands.py +4 -3
- remoteRF_server/server/federation/cli.py +76 -14
- remoteRF_server/server/federation/cluster.py +42 -22
- remoteRF_server/server/federation/migrations.py +5 -0
- remoteRF_server/server/reservation.py +10 -1
- remoteRF_server/server/user_group_cli.py +1 -1
- {remoterf_server-1.1.0.dev38.dist-info → remoterf_server-1.1.0.dev40.dist-info}/METADATA +1 -1
- {remoterf_server-1.1.0.dev38.dist-info → remoterf_server-1.1.0.dev40.dist-info}/RECORD +12 -12
- {remoterf_server-1.1.0.dev38.dist-info → remoterf_server-1.1.0.dev40.dist-info}/WHEEL +0 -0
- {remoterf_server-1.1.0.dev38.dist-info → remoterf_server-1.1.0.dev40.dist-info}/entry_points.txt +0 -0
- {remoterf_server-1.1.0.dev38.dist-info → remoterf_server-1.1.0.dev40.dist-info}/licenses/LICENSE +0 -0
- {remoterf_server-1.1.0.dev38.dist-info → remoterf_server-1.1.0.dev40.dist-info}/top_level.txt +0 -0
|
@@ -89,7 +89,7 @@ def _global(verb: str):
|
|
|
89
89
|
|
|
90
90
|
|
|
91
91
|
def _federation(verb: str):
|
|
92
|
-
return lambda argv: _shell("cmd_federation")([verb, *argv])
|
|
92
|
+
return lambda argv: _shell("cmd_federation")([*verb.split(), *argv])
|
|
93
93
|
|
|
94
94
|
|
|
95
95
|
def _table() -> list[Command]:
|
|
@@ -155,7 +155,8 @@ def _table() -> list[Command]:
|
|
|
155
155
|
Command(("cluster join",), "Join with a code: cluster join <code>", _federation("join"), "Clusters"),
|
|
156
156
|
Command(("cluster remove",), "Leave or disband: cluster remove <name>", _federation("remove"), "Clusters"),
|
|
157
157
|
Command(("cluster groups",), "Choose which of your groups a cluster shares (interactive)", _federation("groups"), "Clusters"),
|
|
158
|
-
Command(("cluster codes",), "Codes for your users to join a cluster
|
|
158
|
+
Command(("cluster codes create",), "Codes for your users to join a cluster (interactive)", _federation("codes create"), "Clusters"),
|
|
159
|
+
Command(("cluster codes list",), "List cluster codes", _federation("codes list"), "Clusters"),
|
|
159
160
|
Command(("cluster accept",), "", _federation("accept"), "Clusters", hidden=True),
|
|
160
161
|
Command(("global cluster",), "", _federation("cluster"), "Global", hidden=True),
|
|
161
162
|
# ---- gist ----
|
|
@@ -191,7 +192,7 @@ def normalize(argv: Iterable[str]) -> list[str]:
|
|
|
191
192
|
def resolve(argv: list[str]) -> tuple[Optional[Command], list[str]]:
|
|
192
193
|
"""Longest phrase match wins: `devices add pluto` → ("devices add", ["pluto"])."""
|
|
193
194
|
words = normalize(argv)
|
|
194
|
-
for length in (2, 1):
|
|
195
|
+
for length in (3, 2, 1):
|
|
195
196
|
phrase = " ".join(words[:length]).lower()
|
|
196
197
|
for command in commands():
|
|
197
198
|
if phrase in command.names:
|
|
@@ -170,7 +170,7 @@ def _ask_for(verb: str) -> str:
|
|
|
170
170
|
"accept": "Which cluster's pending join to accept",
|
|
171
171
|
"groups": "Which cluster to share groups with",
|
|
172
172
|
"info": "Which cluster to show",
|
|
173
|
-
"codes": "Which cluster to make
|
|
173
|
+
"codes": "Which cluster to make codes for",
|
|
174
174
|
"remove": "Which cluster to leave (revokes the contract)"}[verb]
|
|
175
175
|
if verb != "create" and names:
|
|
176
176
|
print(f" Your clusters: {', '.join(names)}")
|
|
@@ -212,6 +212,72 @@ def _share_groups(name: str) -> int:
|
|
|
212
212
|
return 0
|
|
213
213
|
|
|
214
214
|
|
|
215
|
+
def _codes_create(name: str) -> int:
|
|
216
|
+
"""The `codes create` questions, bound to a cluster instead of a group."""
|
|
217
|
+
from ...common.utils.ansi_codes import Sty
|
|
218
|
+
from ...common.utils.panel import print_table
|
|
219
|
+
from .. import global_onboarding as g
|
|
220
|
+
from . import cluster
|
|
221
|
+
|
|
222
|
+
if not name:
|
|
223
|
+
return 2
|
|
224
|
+
cluster._find(cluster.load(), name)
|
|
225
|
+
|
|
226
|
+
def ask_int(prompt: str, default: int, minimum: int) -> int | None:
|
|
227
|
+
while True:
|
|
228
|
+
answer = _input(f"{prompt} [{default}] (c to cancel): ")
|
|
229
|
+
if answer.lower() in ("c", "q", "cancel"):
|
|
230
|
+
return None
|
|
231
|
+
if not answer:
|
|
232
|
+
return default
|
|
233
|
+
if answer.isdigit() and int(answer) >= minimum:
|
|
234
|
+
return int(answer)
|
|
235
|
+
_print(f" Enter a whole number of at least {minimum}.", Sty.WARNING)
|
|
236
|
+
|
|
237
|
+
count = ask_int("How many codes?", 1, 1)
|
|
238
|
+
uses = None if count is None else ask_int("Uses per code?", 1, 1)
|
|
239
|
+
duration = None if uses is None else ask_int(
|
|
240
|
+
"Duration in seconds? (0=never expires)", cluster.CODE_DAYS * 86400, 0)
|
|
241
|
+
if duration is None:
|
|
242
|
+
return 2
|
|
243
|
+
codes = cluster.mint_codes(name, count=count, uses=uses, duration_sec=duration)
|
|
244
|
+
rows = [{"invite": g.invite(code)} for code in codes]
|
|
245
|
+
if rows[0]["invite"] == codes[0]:
|
|
246
|
+
print(f"Hand these out as is; users connect first with: remoterf -c -a {g.lan_endpoint() or '<lan address>'}")
|
|
247
|
+
else:
|
|
248
|
+
print("Hand these out as is; new users enter one at: remoterf --register, "
|
|
249
|
+
"existing users enroll with it in the Client.")
|
|
250
|
+
print_table(f"Cluster {name} codes", rows, ["invite"])
|
|
251
|
+
return 0
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def _codes_list(name: str | None) -> int:
|
|
255
|
+
from ...common.utils.panel import print_panel
|
|
256
|
+
from .. import global_onboarding as g
|
|
257
|
+
from ..user_group_cli import _fmt_duration
|
|
258
|
+
from . import cluster
|
|
259
|
+
|
|
260
|
+
if name:
|
|
261
|
+
cluster._find(cluster.load(), name)
|
|
262
|
+
rows = []
|
|
263
|
+
codes = cluster.list_codes(name)
|
|
264
|
+
if not codes:
|
|
265
|
+
rows.append("No cluster codes. Make some with `cluster codes create`.")
|
|
266
|
+
current = None
|
|
267
|
+
for code in codes:
|
|
268
|
+
if code["cluster_name"] != current:
|
|
269
|
+
if current is not None:
|
|
270
|
+
rows.append("")
|
|
271
|
+
current = code["cluster_name"]
|
|
272
|
+
rows.append(current)
|
|
273
|
+
rows.append(f" {g.invite(code['code_name'])} · {_n(code['uses'], 'use')} left · "
|
|
274
|
+
f"{_fmt_duration(code['duration_sec'])}")
|
|
275
|
+
print()
|
|
276
|
+
print_panel("Cluster codes", rows, literal=True)
|
|
277
|
+
print()
|
|
278
|
+
return 0
|
|
279
|
+
|
|
280
|
+
|
|
215
281
|
def _input(prompt: str) -> str:
|
|
216
282
|
# The console's own prompt session: a bare input() inside the running
|
|
217
283
|
# server fights prompt_toolkit for the terminal and kills the process.
|
|
@@ -225,7 +291,7 @@ def _input(prompt: str) -> str:
|
|
|
225
291
|
|
|
226
292
|
|
|
227
293
|
_USAGE = ("Usage: cluster list | cluster create|invite|remove <name> | cluster join <code> | "
|
|
228
|
-
"cluster info [<name>] | cluster groups [<name>] | cluster codes [<name>]
|
|
294
|
+
"cluster info [<name>] | cluster groups [<name>] | cluster codes create|list [<name>]")
|
|
229
295
|
|
|
230
296
|
|
|
231
297
|
def cmd_cluster(argv: list[str]) -> int:
|
|
@@ -237,11 +303,10 @@ def cmd_cluster(argv: list[str]) -> int:
|
|
|
237
303
|
words = [a for a in argv[1:] if not a.startswith("--")]
|
|
238
304
|
if verb == "list" and not words:
|
|
239
305
|
return cmd_clusters()
|
|
240
|
-
if verb == "codes" and
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
if not words and verb in ("create", "invite", "accept", "join", "remove", "groups", "codes", "info"):
|
|
306
|
+
if verb == "codes" and (not words or words[0] not in ("create", "list")):
|
|
307
|
+
print("Usage: cluster codes create [<cluster>] | cluster codes list [<cluster>]", file=sys.stderr)
|
|
308
|
+
return 2
|
|
309
|
+
if not words and verb in ("create", "invite", "accept", "join", "remove", "groups", "info"):
|
|
245
310
|
# Leaving the argument out asks for it (docs/deployment-groups.md §8).
|
|
246
311
|
answer = _ask_for(verb)
|
|
247
312
|
if not answer:
|
|
@@ -277,13 +342,10 @@ def cmd_cluster(argv: list[str]) -> int:
|
|
|
277
342
|
_print(f" {cluster.attach_group(arg, words[2])} is now shared with {arg}.", Sty.GRAY)
|
|
278
343
|
else:
|
|
279
344
|
_print(f" {cluster.detach_group(arg, words[2])} is no longer shared with {arg}.", Sty.GRAY)
|
|
280
|
-
elif verb == "codes" and
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
f"code (single use, {cluster.CODE_DAYS} days):", Sty.GRAY)
|
|
285
|
-
for code in codes:
|
|
286
|
-
_print(f" {code}", Sty.BOLD)
|
|
345
|
+
elif verb == "codes" and words[0] == "create":
|
|
346
|
+
return _codes_create(words[1] if len(words) > 1 else _ask_for("codes"))
|
|
347
|
+
elif verb == "codes" and words[0] == "list":
|
|
348
|
+
return _codes_list(words[1] if len(words) > 1 else None)
|
|
287
349
|
else:
|
|
288
350
|
print(_USAGE, file=sys.stderr)
|
|
289
351
|
return 2
|
|
@@ -491,15 +491,33 @@ def attach_group(name: str, ref: str) -> str:
|
|
|
491
491
|
if group_id in cluster.get("groups", []):
|
|
492
492
|
raise ClusterError(f"{group_name} is already attached to {name}")
|
|
493
493
|
cluster.setdefault("groups", []).append(group_id)
|
|
494
|
-
conn.execute(
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
(group_id, name),
|
|
498
|
-
)
|
|
494
|
+
for (account,) in conn.execute(
|
|
495
|
+
"SELECT local_account_id FROM ClusterAccounts WHERE cluster_name=?", (name,)).fetchall():
|
|
496
|
+
_grant(conn, name, account, group_id)
|
|
499
497
|
save(clusters)
|
|
500
498
|
return group_name
|
|
501
499
|
|
|
502
500
|
|
|
501
|
+
def _grant(conn, name: str, account: int, group_id: int) -> None:
|
|
502
|
+
"""Add a membership on the cluster's behalf -- remembered only if it was
|
|
503
|
+
the cluster, not a group code, that granted it."""
|
|
504
|
+
added = conn.execute("INSERT OR IGNORE INTO UsersLookup(user_id,group_id) VALUES (?,?)",
|
|
505
|
+
(int(account), int(group_id))).rowcount
|
|
506
|
+
if added:
|
|
507
|
+
conn.execute("INSERT OR IGNORE INTO ClusterMemberships(cluster_name,local_account_id,group_id) "
|
|
508
|
+
"VALUES (?,?,?)", (name, int(account), int(group_id)))
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
def _take_back(conn, name: str, group_id: int | None = None) -> None:
|
|
512
|
+
"""Remove exactly the memberships this cluster granted (one group, or all)."""
|
|
513
|
+
where = "cluster_name=?" + ("" if group_id is None else " AND group_id=?")
|
|
514
|
+
args = (name,) if group_id is None else (name, int(group_id))
|
|
515
|
+
conn.execute(
|
|
516
|
+
f"DELETE FROM UsersLookup WHERE (user_id,group_id) IN "
|
|
517
|
+
f"(SELECT local_account_id,group_id FROM ClusterMemberships WHERE {where})", args)
|
|
518
|
+
conn.execute(f"DELETE FROM ClusterMemberships WHERE {where}", args)
|
|
519
|
+
|
|
520
|
+
|
|
503
521
|
def detach_group(name: str, ref: str) -> str:
|
|
504
522
|
clusters = load()
|
|
505
523
|
cluster = _find(clusters, name)
|
|
@@ -508,23 +526,14 @@ def detach_group(name: str, ref: str) -> str:
|
|
|
508
526
|
if group_id not in cluster.get("groups", []):
|
|
509
527
|
raise ClusterError(f"{group_name} is not attached to {name}")
|
|
510
528
|
cluster["groups"].remove(group_id)
|
|
511
|
-
conn
|
|
512
|
-
"DELETE FROM UsersLookup WHERE group_id=? AND user_id IN "
|
|
513
|
-
"(SELECT local_account_id FROM ClusterAccounts WHERE cluster_name=?)",
|
|
514
|
-
(group_id, name),
|
|
515
|
-
)
|
|
529
|
+
_take_back(conn, name, group_id)
|
|
516
530
|
save(clusters)
|
|
517
531
|
return group_name
|
|
518
532
|
|
|
519
533
|
|
|
520
534
|
def _forget_accounts(name: str, cluster: dict) -> None:
|
|
521
535
|
with _usergroups() as conn:
|
|
522
|
-
|
|
523
|
-
conn.execute(
|
|
524
|
-
"DELETE FROM UsersLookup WHERE group_id=? AND user_id IN "
|
|
525
|
-
"(SELECT local_account_id FROM ClusterAccounts WHERE cluster_name=?)",
|
|
526
|
-
(group_id, name),
|
|
527
|
-
)
|
|
536
|
+
_take_back(conn, name)
|
|
528
537
|
conn.execute("DELETE FROM ClusterAccounts WHERE cluster_name=?", (name,))
|
|
529
538
|
|
|
530
539
|
|
|
@@ -536,24 +545,35 @@ def join_account(conn, name: str, cluster: dict, local_account_id: int, *, kind:
|
|
|
536
545
|
(name, int(local_account_id), kind, int(time.time())),
|
|
537
546
|
)
|
|
538
547
|
for group_id in cluster.get("groups", []):
|
|
539
|
-
conn
|
|
540
|
-
(int(local_account_id), int(group_id)))
|
|
548
|
+
_grant(conn, name, local_account_id, group_id)
|
|
541
549
|
|
|
542
550
|
|
|
543
|
-
def mint_codes(name: str, *, count: int = 1, uses: int = 1,
|
|
551
|
+
def mint_codes(name: str, *, count: int = 1, uses: int = 1, duration_sec: int = CODE_DAYS * 86400) -> list[str]:
|
|
552
|
+
"""Same shape as a group code (uses, duration; 0 = never expires), bound
|
|
553
|
+
to the cluster instead of a group."""
|
|
544
554
|
_find(load(), name)
|
|
545
|
-
if not 1 <= count <= 200 or uses < 1 or
|
|
546
|
-
raise ClusterError("count must be 1-200, uses
|
|
555
|
+
if not 1 <= count <= 200 or uses < 1 or duration_sec < 0:
|
|
556
|
+
raise ClusterError("count must be 1-200, uses at least 1, duration 0 or more seconds")
|
|
547
557
|
codes = [CODE_PREFIX + secrets.token_urlsafe(18) for _ in range(count)]
|
|
548
558
|
with _usergroups() as conn:
|
|
549
559
|
conn.executemany(
|
|
550
560
|
"INSERT INTO EnrollmentCodes(code_name,group_id,uses,duration_sec,created_at,cluster_name) "
|
|
551
561
|
"VALUES (?,-1,?,?,?,?)",
|
|
552
|
-
[(code, uses,
|
|
562
|
+
[(code, uses, duration_sec, datetime.now().isoformat(sep=" "), name) for code in codes],
|
|
553
563
|
)
|
|
554
564
|
return codes
|
|
555
565
|
|
|
556
566
|
|
|
567
|
+
def list_codes(name: str | None = None) -> list[dict]:
|
|
568
|
+
with _usergroups() as conn:
|
|
569
|
+
rows = conn.execute(
|
|
570
|
+
"SELECT code_name,cluster_name,uses,duration_sec FROM EnrollmentCodes WHERE cluster_name IS NOT NULL"
|
|
571
|
+
+ (" AND cluster_name=?" if name else "") + " ORDER BY cluster_name,code_id",
|
|
572
|
+
(name,) if name else (),
|
|
573
|
+
).fetchall()
|
|
574
|
+
return [{"code_name": r[0], "cluster_name": r[1], "uses": int(r[2]), "duration_sec": int(r[3])} for r in rows]
|
|
575
|
+
|
|
576
|
+
|
|
557
577
|
def redeem_code(local_account_id: int, code_name: str) -> Optional[str]:
|
|
558
578
|
"""A student types a cluster code at home: returns the cluster joined, or None."""
|
|
559
579
|
if not code_name.startswith(CODE_PREFIX):
|
|
@@ -778,6 +778,11 @@ def migrate_gate_f_usergroups_schema(conn: sqlite3.Connection) -> None:
|
|
|
778
778
|
"cluster_name TEXT NOT NULL, local_account_id INTEGER NOT NULL, "
|
|
779
779
|
"kind TEXT NOT NULL CHECK(kind IN ('local','proxy')), joined_at INTEGER NOT NULL, "
|
|
780
780
|
"PRIMARY KEY(cluster_name,local_account_id));"
|
|
781
|
+
# Memberships the cluster itself created, so un-sharing takes back
|
|
782
|
+
# only those and never a membership a group code granted.
|
|
783
|
+
"CREATE TABLE IF NOT EXISTS ClusterMemberships ("
|
|
784
|
+
"cluster_name TEXT NOT NULL, local_account_id INTEGER NOT NULL, group_id INTEGER NOT NULL, "
|
|
785
|
+
"PRIMARY KEY(cluster_name,local_account_id,group_id));"
|
|
781
786
|
)
|
|
782
787
|
conn.executescript(_GATE_F_DDL)
|
|
783
788
|
conn.execute(
|
|
@@ -428,7 +428,16 @@ class ReservationHandler:
|
|
|
428
428
|
"VALUES (?, ?, 'active', ?)",
|
|
429
429
|
(uid, str(uuid4()), int(time.time())),
|
|
430
430
|
)
|
|
431
|
-
|
|
431
|
+
if ec.startswith("cluster."):
|
|
432
|
+
from .federation import cluster as cluster_module
|
|
433
|
+
|
|
434
|
+
if cluster_module.redeem_code(uid, ec) is not None:
|
|
435
|
+
try:
|
|
436
|
+
cluster_module.enroll_students(self, only_account=uid)
|
|
437
|
+
except Exception: # noqa: BLE001 - the tick retries
|
|
438
|
+
pass
|
|
439
|
+
else:
|
|
440
|
+
user_group_handler.enroll_user_with_code(uid=uid, code_name=ec)
|
|
432
441
|
perms.set_user(un) # set perms
|
|
433
442
|
return {"UC": map_arg(f'{un}')}
|
|
434
443
|
except Exception as e:
|
|
@@ -37,7 +37,7 @@ def _invites(rows: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
|
|
37
37
|
code = str(row.get("code_name", ""))
|
|
38
38
|
# A federation-bound code is redeemed through its signed invitation,
|
|
39
39
|
# never typed as a Global invite.
|
|
40
|
-
federated = row.get("federation_contract_id") is not None
|
|
40
|
+
federated = row.get("federation_contract_id") is not None
|
|
41
41
|
row["invite"] = code if federated else invite(
|
|
42
42
|
code, lan_only=lan_only.get(int(row.get("group_id", -1)), False)
|
|
43
43
|
)
|
|
@@ -52,7 +52,7 @@ remoteRF_server/host/host_tunnel_server.py,sha256=sz06xOtFbaDZSy1UQfw6faKhJmuOy5
|
|
|
52
52
|
remoteRF_server/server/__init__.py,sha256=-1h_xQjiE66oiWRO-vnLGJ4smpgUNhFuV-ZreW9_tD4,667
|
|
53
53
|
remoteRF_server/server/acc_perms.py,sha256=2loCvstVu8uvsb2uCv2Sk7iNQ5GyO_sBIkPQFzqOaRI,13334
|
|
54
54
|
remoteRF_server/server/cert_provider.py,sha256=CRDrZL4DSf-eL6wzPJzwucrzPLOr2PvNRq5V--oZtr0,6272
|
|
55
|
-
remoteRF_server/server/commands.py,sha256=
|
|
55
|
+
remoteRF_server/server/commands.py,sha256=ccb_Ab1mbIkosBsFGJnDSccrjWtR_Lymvvn3IqhOnyc,17519
|
|
56
56
|
remoteRF_server/server/console.py,sha256=J91LfwPVmBgielOxfE740NOYduekggyZkqi-47y_A4w,4472
|
|
57
57
|
remoteRF_server/server/control.py,sha256=Uq1Fk0zIoHHX_EXfz3OuNle8urvO_UhAiB5Lk5cs2e4,5177
|
|
58
58
|
remoteRF_server/server/device_manager.py,sha256=PPuCwlPSmjfVpCqy_hCaOr9WvFgE8mqtLMhWOAgXNDA,39281
|
|
@@ -61,17 +61,17 @@ remoteRF_server/server/dynamic_v2.py,sha256=AMhQEFhNAvCNcF-PdfCCQQLmeoaR7s1Os8et
|
|
|
61
61
|
remoteRF_server/server/global_onboarding.py,sha256=boLAKXCKvcsIY3TDiFwduMaHdDMB9Cr104MyWJYZ-BA,39891
|
|
62
62
|
remoteRF_server/server/grpc_server.py,sha256=91FpJubzN_Wfuk6fW_owIEzNCukd333sAGW68FUU8pk,46787
|
|
63
63
|
remoteRF_server/server/host_dynamic_v2.py,sha256=1rJQwP4knSd0EXkByrSn_ryjLx81f6sp6SNYr_aEass,8105
|
|
64
|
-
remoteRF_server/server/reservation.py,sha256=
|
|
64
|
+
remoteRF_server/server/reservation.py,sha256=BQJLGNVAdKMZu2Lg4DGO9UhuJ0b1GSF8K1DgIOFrYUg,67816
|
|
65
65
|
remoteRF_server/server/rpc_manager.py,sha256=BDvsTSVRxwNF2ujuMbIb5TYNAUI6AH4xXBuXrb8lltM,17223
|
|
66
|
-
remoteRF_server/server/user_group_cli.py,sha256=
|
|
66
|
+
remoteRF_server/server/user_group_cli.py,sha256=thg-pPIqfWVi2ZfvRwJuR2uFO3cJZIbsNLtquJrGtH8,25045
|
|
67
67
|
remoteRF_server/server/user_group_handler.py,sha256=1ax73W_P3H6GDxQS13evwA7G7skIElFVLuS0MFqsFyU,41780
|
|
68
68
|
remoteRF_server/server/v2_errors.py,sha256=IS3hIhf5tDe7jaOrDAVQPjGBpqAjN7442BlJYgfJo7g,3331
|
|
69
69
|
remoteRF_server/server/deployment/__init__.py,sha256=YV86uafd8XiGD7sLaqNfO5xxmt5te2R6DUhD-w1lZuY,77
|
|
70
70
|
remoteRF_server/server/deployment/capabilities.py,sha256=20RxmGG03VoQQZnV3jGhc-3i9B5hOl5fCopnsErFjPk,872
|
|
71
71
|
remoteRF_server/server/federation/__init__.py,sha256=auqdGiGnEGIKQiXX2jFVt8iWmfyZ-V3w4dUmtWDKAZE,735
|
|
72
72
|
remoteRF_server/server/federation/admin.py,sha256=t3F17FIytekzclPICmaFJEA4-F5OuWcDx3rgmFga17A,9187
|
|
73
|
-
remoteRF_server/server/federation/cli.py,sha256=
|
|
74
|
-
remoteRF_server/server/federation/cluster.py,sha256=
|
|
73
|
+
remoteRF_server/server/federation/cli.py,sha256=pJh2TyEqOcxO4uBEDpQsDwvM0CLf7IdpSHAaZrAvt2E,16348
|
|
74
|
+
remoteRF_server/server/federation/cluster.py,sha256=SvJVe1EGKWjmIf8uPTLgSWlG6Hax7gh_RUmWLmabicM,37451
|
|
75
75
|
remoteRF_server/server/federation/contracts.py,sha256=NYh7lb_9etJHFfzXwevjC4HfSBUypLxg5xGeBgydLF4,29305
|
|
76
76
|
remoteRF_server/server/federation/destination.py,sha256=XawmGCiVbL_MfNNn8xwV9_bYxUDW1L7efCpL11K2JAc,35909
|
|
77
77
|
remoteRF_server/server/federation/devices.py,sha256=n5MvnD0UZyl4sFpiekG9ProanWXTYizYq6YchCflLgY,18061
|
|
@@ -80,7 +80,7 @@ remoteRF_server/server/federation/home.py,sha256=-_0__wJN50Y1-Dd396_iUZjGESBkoBN
|
|
|
80
80
|
remoteRF_server/server/federation/home_devices.py,sha256=lbsw201HBOYPP5vbN172vdm2O_ouCdZBo1cRYCVScmg,18754
|
|
81
81
|
remoteRF_server/server/federation/identity.py,sha256=UtQJKm2mChWZto0ZCg385k_ObrwOUtxY7XFyU_s5Q10,7436
|
|
82
82
|
remoteRF_server/server/federation/legacy_state.py,sha256=SpeTZHFqymNYGWG7A3B-78dIRIVLYltBbE2zGDWzt-Q,19838
|
|
83
|
-
remoteRF_server/server/federation/migrations.py,sha256=
|
|
83
|
+
remoteRF_server/server/federation/migrations.py,sha256=opPIfoNvR3BwoN9BaZsuEs14cT-zz4ghXWHV0hno7QI,50958
|
|
84
84
|
remoteRF_server/server/federation/permissions.py,sha256=ou4uFsMAGHnDeBW6zbpGeUTwp0thlYXT5nIAgd3B1rg,15861
|
|
85
85
|
remoteRF_server/server/federation/principals.py,sha256=CsRYa8POmtMaxKzAGwY14sxBTNS5uKjM1nUE19mjpoQ,10410
|
|
86
86
|
remoteRF_server/server/federation/runtime.py,sha256=5CoDlu0jSQrFdwRoGL2Z4_CWxnA46B3j6-eNQo8N2FI,7624
|
|
@@ -90,9 +90,9 @@ remoteRF_server/tools/gen_certs.py,sha256=Vbyu8JjRu__UYPVmyCRXt5SOw0Za1HV7g1md3G
|
|
|
90
90
|
remoteRF_server/tools/gist_status.py,sha256=SFv2iQgQrIKT9gxKrU-_Dr7S0p0rE4wQM6J3OC6FcoM,4649
|
|
91
91
|
remoteRF_server/tools/gist_status_testing.py,sha256=IYw7UkPjAUpKDTtIlnYGb5g6SJkwz4TRGUfJJ6f4LhQ,2690
|
|
92
92
|
remoteRF_server/tools/introspect_uhd.py,sha256=vUpPb0rM9tsHPxWadS3EfMDE-gMd-TvNV0TjrZOQqBY,4531
|
|
93
|
-
remoterf_server-1.1.0.
|
|
94
|
-
remoterf_server-1.1.0.
|
|
95
|
-
remoterf_server-1.1.0.
|
|
96
|
-
remoterf_server-1.1.0.
|
|
97
|
-
remoterf_server-1.1.0.
|
|
98
|
-
remoterf_server-1.1.0.
|
|
93
|
+
remoterf_server-1.1.0.dev40.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
94
|
+
remoterf_server-1.1.0.dev40.dist-info/METADATA,sha256=aX2kuvEg8wV0m1NMsKDFMpOzE_nOALZpwgiJYCPZsF0,42069
|
|
95
|
+
remoterf_server-1.1.0.dev40.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
96
|
+
remoterf_server-1.1.0.dev40.dist-info/entry_points.txt,sha256=_bbKk65PfYi-n6zUjqOiOwcalf_Ws1TCGATIe1TukxE,136
|
|
97
|
+
remoterf_server-1.1.0.dev40.dist-info/top_level.txt,sha256=NuYWe8dSx3qdbxshWBwOgx68EHmJ9I8Zvxam4ARsQ_I,30
|
|
98
|
+
remoterf_server-1.1.0.dev40.dist-info/RECORD,,
|
|
File without changes
|
{remoterf_server-1.1.0.dev38.dist-info → remoterf_server-1.1.0.dev40.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{remoterf_server-1.1.0.dev38.dist-info → remoterf_server-1.1.0.dev40.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
{remoterf_server-1.1.0.dev38.dist-info → remoterf_server-1.1.0.dev40.dist-info}/top_level.txt
RENAMED
|
File without changes
|