weed-cli 1.2.3__tar.gz → 1.2.7__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.
- {weed_cli-1.2.3 → weed_cli-1.2.7}/PKG-INFO +1 -1
- {weed_cli-1.2.3 → weed_cli-1.2.7}/discovery_relay.py +43 -6
- {weed_cli-1.2.3 → weed_cli-1.2.7}/node.py +23 -0
- {weed_cli-1.2.3 → weed_cli-1.2.7}/pyproject.toml +1 -1
- {weed_cli-1.2.3 → weed_cli-1.2.7}/shell.py +58 -12
- {weed_cli-1.2.3 → weed_cli-1.2.7}/web_ui.py +4 -9
- {weed_cli-1.2.3 → weed_cli-1.2.7}/weed.py +35 -9
- {weed_cli-1.2.3 → weed_cli-1.2.7}/weed_cli.egg-info/PKG-INFO +1 -1
- {weed_cli-1.2.3 → weed_cli-1.2.7}/LICENSE +0 -0
- {weed_cli-1.2.3 → weed_cli-1.2.7}/README.md +0 -0
- {weed_cli-1.2.3 → weed_cli-1.2.7}/dht.py +0 -0
- {weed_cli-1.2.3 → weed_cli-1.2.7}/lightning_settle.py +0 -0
- {weed_cli-1.2.3 → weed_cli-1.2.7}/poc_reputation.py +0 -0
- {weed_cli-1.2.3 → weed_cli-1.2.7}/setup.cfg +0 -0
- {weed_cli-1.2.3 → weed_cli-1.2.7}/tunnel_relay.py +0 -0
- {weed_cli-1.2.3 → weed_cli-1.2.7}/weed_cli.egg-info/SOURCES.txt +0 -0
- {weed_cli-1.2.3 → weed_cli-1.2.7}/weed_cli.egg-info/dependency_links.txt +0 -0
- {weed_cli-1.2.3 → weed_cli-1.2.7}/weed_cli.egg-info/entry_points.txt +0 -0
- {weed_cli-1.2.3 → weed_cli-1.2.7}/weed_cli.egg-info/requires.txt +0 -0
- {weed_cli-1.2.3 → weed_cli-1.2.7}/weed_cli.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: weed-cli
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.7
|
|
4
4
|
Summary: Censorship-resistant video PoC — discovery/hosting/download over signed relay events, a real Kademlia DHT, or a TLS-capable NAT-traversal tunnel
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: p2p,video,censorship-resistant,discovery,dht,kademlia,nat-traversal
|
|
@@ -20,14 +20,46 @@ Ed25519 signing):
|
|
|
20
20
|
subscribe {target_pubkey} — a viewer follows a creator/signer
|
|
21
21
|
"""
|
|
22
22
|
import json
|
|
23
|
+
import os
|
|
23
24
|
import sys
|
|
25
|
+
import threading
|
|
24
26
|
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
|
25
27
|
from urllib.parse import urlparse, parse_qs
|
|
26
28
|
|
|
27
|
-
sys.path.insert(0,
|
|
29
|
+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
28
30
|
from poc_reputation import verify_attestation, attestation_id
|
|
29
31
|
|
|
30
|
-
|
|
32
|
+
# Events are still held in-memory for serving (a real relay would use a
|
|
33
|
+
# real DB; irrelevant to the design) -- but write-through to a JSONL file
|
|
34
|
+
# too, so a restart (deploy, crash, or Fly scaling this to zero when
|
|
35
|
+
# idle) doesn't silently wipe every event that's ever been posted. Point
|
|
36
|
+
# WEED_RELAY_DATA at a mounted Fly Volume path (e.g. /data/events.jsonl)
|
|
37
|
+
# to survive machine restarts; the local relative-path default is fine
|
|
38
|
+
# for dev/shell.py use where nothing's actually being deployed.
|
|
39
|
+
DATA_PATH = os.environ.get('WEED_RELAY_DATA',
|
|
40
|
+
os.path.join(os.path.dirname(os.path.abspath(__file__)), 'relay_events.jsonl'))
|
|
41
|
+
_events = []
|
|
42
|
+
_lock = threading.Lock()
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _load_events():
|
|
46
|
+
if not os.path.exists(DATA_PATH):
|
|
47
|
+
return
|
|
48
|
+
with open(DATA_PATH) as f:
|
|
49
|
+
for line in f:
|
|
50
|
+
line = line.strip()
|
|
51
|
+
if not line:
|
|
52
|
+
continue
|
|
53
|
+
try:
|
|
54
|
+
_events.append(json.loads(line))
|
|
55
|
+
except json.JSONDecodeError:
|
|
56
|
+
pass # tolerate a truncated last line from a killed-mid-write process
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _append_event(event):
|
|
60
|
+
os.makedirs(os.path.dirname(DATA_PATH) or '.', exist_ok=True)
|
|
61
|
+
with open(DATA_PATH, 'a') as f:
|
|
62
|
+
f.write(json.dumps(event) + '\n')
|
|
31
63
|
|
|
32
64
|
|
|
33
65
|
class RelayHandler(BaseHTTPRequestHandler):
|
|
@@ -50,8 +82,10 @@ class RelayHandler(BaseHTTPRequestHandler):
|
|
|
50
82
|
self.wfile.write(json.dumps({'ok': False, 'reason': reason}).encode())
|
|
51
83
|
return
|
|
52
84
|
eid = attestation_id(event)
|
|
53
|
-
|
|
54
|
-
|
|
85
|
+
with _lock:
|
|
86
|
+
if not any(attestation_id(e) == eid for e in _events):
|
|
87
|
+
_events.append(event)
|
|
88
|
+
_append_event(event)
|
|
55
89
|
self.send_response(200)
|
|
56
90
|
self.send_header('Content-Type', 'application/json')
|
|
57
91
|
self.end_headers()
|
|
@@ -61,7 +95,8 @@ class RelayHandler(BaseHTTPRequestHandler):
|
|
|
61
95
|
if self.path.split('?')[0] != '/events':
|
|
62
96
|
self.send_response(404); self.end_headers(); return
|
|
63
97
|
qs = parse_qs(urlparse(self.path).query)
|
|
64
|
-
|
|
98
|
+
with _lock:
|
|
99
|
+
out = list(_events)
|
|
65
100
|
if 'type' in qs:
|
|
66
101
|
out = [e for e in out if e['payload'].get('type') == qs['type'][0]]
|
|
67
102
|
self.send_response(200)
|
|
@@ -79,9 +114,11 @@ def run_relay_server(port, quiet=False):
|
|
|
79
114
|
read, so the two interleave and the prompt looks like it "disappeared."
|
|
80
115
|
The shell already prints its own equivalent confirmation line, so this
|
|
81
116
|
fixes it at the source instead of patching the visual symptom."""
|
|
117
|
+
_load_events()
|
|
82
118
|
srv = ThreadingHTTPServer(('0.0.0.0', port), RelayHandler)
|
|
83
119
|
if not quiet:
|
|
84
|
-
print(f"[relay:{port}] up, no opinion on content, just store-and-forward"
|
|
120
|
+
print(f"[relay:{port}] up, no opinion on content, just store-and-forward "
|
|
121
|
+
f"({len(_events)} event(s) loaded from {DATA_PATH})", flush=True)
|
|
85
122
|
srv.serve_forever()
|
|
86
123
|
|
|
87
124
|
|
|
@@ -825,7 +825,26 @@ def download_with_auction(content_hash, relay_urls, out_path=None, k=3, use_ligh
|
|
|
825
825
|
|
|
826
826
|
# ── discovery + social signals ──────────────────────────────────────────
|
|
827
827
|
|
|
828
|
+
def _relay_url_hint(relay_url):
|
|
829
|
+
"""Relays are plain HTTP(S) endpoints, hit via urllib -- tls:// is a
|
|
830
|
+
completely different, unrelated convention that only means something
|
|
831
|
+
to --tunnel (a hand-rolled raw-TCP-plus-TLS protocol, see
|
|
832
|
+
_connect_tunnel_socket/connect_via_tunnel). Easy to mix up since both
|
|
833
|
+
flags take a host:port-shaped value and this same tool uses tls://
|
|
834
|
+
for the other one; without this check the failure is just urllib's
|
|
835
|
+
raw 'unknown url type: tls' with no hint about why."""
|
|
836
|
+
if relay_url.startswith('tls://'):
|
|
837
|
+
return (f"{relay_url!r} looks like a --tunnel address, not a relay URL — "
|
|
838
|
+
f"relays are plain HTTP(S) endpoints, try "
|
|
839
|
+
f"'https://{relay_url[len('tls://'):]}' for --relay instead "
|
|
840
|
+
f"(tls:// only means something to --tunnel)")
|
|
841
|
+
return None
|
|
842
|
+
|
|
843
|
+
|
|
828
844
|
def post_event(relay_url, event):
|
|
845
|
+
hint = _relay_url_hint(relay_url)
|
|
846
|
+
if hint:
|
|
847
|
+
return {'ok': False, 'error': hint}
|
|
829
848
|
req = urllib.request.Request(
|
|
830
849
|
f'{relay_url}/event', data=json.dumps(event).encode(),
|
|
831
850
|
headers={'Content-Type': 'application/json'}, method='POST')
|
|
@@ -845,6 +864,10 @@ def post_event(relay_url, event):
|
|
|
845
864
|
|
|
846
865
|
|
|
847
866
|
def fetch_events(relay_url, event_type=None):
|
|
867
|
+
hint = _relay_url_hint(relay_url)
|
|
868
|
+
if hint:
|
|
869
|
+
print(f" {relay_url}: {hint}")
|
|
870
|
+
return None
|
|
848
871
|
url = f'{relay_url}/events' + (f'?type={event_type}' if event_type else '')
|
|
849
872
|
try:
|
|
850
873
|
with urllib.request.urlopen(url, timeout=5) as resp:
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "weed-cli"
|
|
7
|
-
version = "1.2.
|
|
7
|
+
version = "1.2.7"
|
|
8
8
|
description = "Censorship-resistant video PoC — discovery/hosting/download over signed relay events, a real Kademlia DHT, or a TLS-capable NAT-traversal tunnel"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -52,7 +52,15 @@ class WeedShell(cmd.Cmd):
|
|
|
52
52
|
self.identity = node.load_or_create_identity()
|
|
53
53
|
self._last_discovery = [] # cache of the last `discover` results, for tab completion
|
|
54
54
|
self._host_threads = [] # background host() threads started this session
|
|
55
|
-
|
|
55
|
+
# $WEED_RELAY/$WEED_TUNNEL seed the session's defaults, same as
|
|
56
|
+
# weed.py's own CLI subcommands (see its _default_relay) -- so a
|
|
57
|
+
# real relay/tunnel deployment can be set once per shell session
|
|
58
|
+
# (or once in your shell rc) instead of retyped on every `host`/
|
|
59
|
+
# `discover`/`download`/`like`/`subscribe`. Explicit --relay/
|
|
60
|
+
# --tunnel on any command still always wins; `set` (below) can
|
|
61
|
+
# also change either mid-session.
|
|
62
|
+
self.default_relay = os.environ.get('WEED_RELAY', 'http://127.0.0.1:9101')
|
|
63
|
+
self.default_tunnel = os.environ.get('WEED_TUNNEL')
|
|
56
64
|
self.dht_node = None # active dht.DHTNode, once `dht start` has run
|
|
57
65
|
|
|
58
66
|
def preloop(self):
|
|
@@ -103,15 +111,18 @@ class WeedShell(cmd.Cmd):
|
|
|
103
111
|
— serve every archived file in archive_dir in a background thread
|
|
104
112
|
(shell stays usable), one port, downloaders SELECT which by content
|
|
105
113
|
hash. Pass --file to restrict to a single file. Announces each file
|
|
106
|
-
on --relay (default: your session's default relay — see `relay
|
|
107
|
-
unless --no-announce is given. --price
|
|
108
|
-
(default free). --tunnel registers with
|
|
109
|
-
relying on a reachable inbound port —
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
114
|
+
on --relay (default: your session's default relay — see `relay`,
|
|
115
|
+
`set relay`, or $WEED_RELAY) unless --no-announce is given. --price
|
|
116
|
+
sets what download charges (default free). --tunnel registers with
|
|
117
|
+
a tunnel_relay.py instead of relying on a reachable inbound port —
|
|
118
|
+
for hosting behind NAT/CGNAT (default: your session's default
|
|
119
|
+
tunnel — see `set tunnel` or $WEED_TUNNEL). Registers one control
|
|
120
|
+
connection per file (REGISTER's token is each file's own content
|
|
121
|
+
hash), so a whole tree tunnels fine, not just a single file. Prefix
|
|
122
|
+
tls:// if the relay terminates TLS at the edge (e.g. a Fly service
|
|
123
|
+
with handlers = ["tls"]) — the relay process itself never needs to
|
|
124
|
+
know. An explicit --relay/--tunnel here also becomes the new
|
|
125
|
+
session default, same as `discover` already does for --relay."""
|
|
115
126
|
parts = shlex.split(arg)
|
|
116
127
|
if not parts:
|
|
117
128
|
print(' usage: host <archive_dir> [--file NAME] [--port N] [--price SAT] '
|
|
@@ -125,7 +136,7 @@ class WeedShell(cmd.Cmd):
|
|
|
125
136
|
relay = self.default_relay
|
|
126
137
|
no_announce = '--no-announce' in parts
|
|
127
138
|
advertise_host = '127.0.0.1'
|
|
128
|
-
tunnel =
|
|
139
|
+
tunnel = self.default_tunnel
|
|
129
140
|
i = 1
|
|
130
141
|
while i < len(parts):
|
|
131
142
|
if parts[i] == '--file' and i + 1 < len(parts):
|
|
@@ -148,6 +159,11 @@ class WeedShell(cmd.Cmd):
|
|
|
148
159
|
tunnel = parts[i]
|
|
149
160
|
i += 1
|
|
150
161
|
|
|
162
|
+
# remember an explicit --relay/--tunnel for the rest of the
|
|
163
|
+
# session, same as `discover` already does for --relay
|
|
164
|
+
self.default_relay = relay
|
|
165
|
+
self.default_tunnel = tunnel
|
|
166
|
+
|
|
151
167
|
entries = node.load_manifest_entries(archive_dir, file_name)
|
|
152
168
|
# fail fast, before announcing anything — a manifest entry with no
|
|
153
169
|
# matching chunk data would otherwise get announced to the relay
|
|
@@ -201,6 +217,36 @@ class WeedShell(cmd.Cmd):
|
|
|
201
217
|
self.default_relay = f'http://127.0.0.1:{port}'
|
|
202
218
|
print(f' relay running on port {port} in the background — set as your default relay')
|
|
203
219
|
|
|
220
|
+
def complete_set(self, text, line, begidx, endidx):
|
|
221
|
+
parts = shlex.split(line[:begidx])
|
|
222
|
+
if len(parts) == 1:
|
|
223
|
+
return [s for s in ('relay', 'tunnel') if s.startswith(text)]
|
|
224
|
+
return []
|
|
225
|
+
|
|
226
|
+
def do_set(self, arg):
|
|
227
|
+
"""set relay <URL> — set the session's default relay directly,
|
|
228
|
+
without needing to start one (`relay`) or run `discover` first.
|
|
229
|
+
set tunnel <[tls://]HOST:PORT> — same, for the default tunnel.
|
|
230
|
+
set (no args) — show both current defaults.
|
|
231
|
+
Either can also be set once via $WEED_RELAY/$WEED_TUNNEL before
|
|
232
|
+
launching the shell, and an explicit --relay/--tunnel on `host`
|
|
233
|
+
or `discover` updates the session default too."""
|
|
234
|
+
parts = shlex.split(arg)
|
|
235
|
+
if not parts:
|
|
236
|
+
print(f' relay: {self.default_relay or "(none)"}')
|
|
237
|
+
print(f' tunnel: {self.default_tunnel or "(none)"}')
|
|
238
|
+
return
|
|
239
|
+
if len(parts) != 2 or parts[0] not in ('relay', 'tunnel'):
|
|
240
|
+
print(' usage: set relay <URL> | set tunnel <[tls://]HOST:PORT> | set')
|
|
241
|
+
return
|
|
242
|
+
what, value = parts
|
|
243
|
+
if what == 'relay':
|
|
244
|
+
self.default_relay = value
|
|
245
|
+
print(f' default relay set to {value}')
|
|
246
|
+
else:
|
|
247
|
+
self.default_tunnel = value
|
|
248
|
+
print(f' default tunnel set to {value}')
|
|
249
|
+
|
|
204
250
|
def do_serve(self, arg):
|
|
205
251
|
"""serve [bind] [port] — run the local web control UI in the background
|
|
206
252
|
(default 127.0.0.1:8080; pass 0.0.0.0 to reach it from your phone).
|
|
@@ -297,7 +343,7 @@ class WeedShell(cmd.Cmd):
|
|
|
297
343
|
|
|
298
344
|
def do_discover(self, arg):
|
|
299
345
|
"""discover [relay_url ...] — list content announced on one or more relays
|
|
300
|
-
(default: the last relay used, or http://127.0.0.1:9101)."""
|
|
346
|
+
(default: the last relay used, $WEED_RELAY, or http://127.0.0.1:9101)."""
|
|
301
347
|
relays = shlex.split(arg) or [self.default_relay]
|
|
302
348
|
self.default_relay = relays[0]
|
|
303
349
|
results = node.discover(relays)
|
|
@@ -137,7 +137,7 @@ def _rehydrate_jobs_from_library():
|
|
|
137
137
|
'status': 'done', 'idx': 0, 'n_chunks': None,
|
|
138
138
|
'content_hash': content_hash, 'path': rec['path'],
|
|
139
139
|
'title': rec.get('title'), 'size': rec.get('size'), 'bps': rec.get('bps'),
|
|
140
|
-
'
|
|
140
|
+
'error': None,
|
|
141
141
|
}
|
|
142
142
|
_lan_url = None # set once in run_web_ui() -- the base URL a phone on the
|
|
143
143
|
# same LAN can actually reach this server at, or None if
|
|
@@ -211,8 +211,7 @@ def _run_host_job(host_id, archive_dir, file_name, port, price, relay_urls, adve
|
|
|
211
211
|
_hosts[host_id].update(status='error', error=f'{type(e).__name__}: {e}')
|
|
212
212
|
|
|
213
213
|
|
|
214
|
-
def _run_download_job(job_id, content_hash, relay_urls, out_path, k, use_lightning, title=None
|
|
215
|
-
signer_pubkey=None):
|
|
214
|
+
def _run_download_job(job_id, content_hash, relay_urls, out_path, k, use_lightning, title=None):
|
|
216
215
|
def on_progress(idx, n_chunks):
|
|
217
216
|
with _lock:
|
|
218
217
|
_jobs[job_id].update(idx=idx, n_chunks=n_chunks)
|
|
@@ -230,7 +229,6 @@ def _run_download_job(job_id, content_hash, relay_urls, out_path, k, use_lightni
|
|
|
230
229
|
_library['downloads'][content_hash] = {
|
|
231
230
|
'content_hash': content_hash, 'job_id': job_id, 'path': path,
|
|
232
231
|
'title': title, 'downloaded_at': time.time(), 'size': size, 'bps': bps,
|
|
233
|
-
'signer_pubkey': signer_pubkey,
|
|
234
232
|
}
|
|
235
233
|
_save_library()
|
|
236
234
|
except SystemExit as e:
|
|
@@ -358,16 +356,13 @@ class Handler(BaseHTTPRequestHandler):
|
|
|
358
356
|
k = int(body.get('k') or 3)
|
|
359
357
|
use_lightning = bool(body.get('lightning'))
|
|
360
358
|
title = body.get('title')
|
|
361
|
-
signer_pubkey = body.get('signer_pubkey')
|
|
362
359
|
|
|
363
360
|
job_id = uuid.uuid4().hex[:12]
|
|
364
361
|
with _lock:
|
|
365
362
|
_jobs[job_id] = {'status': 'running', 'idx': 0, 'n_chunks': None,
|
|
366
|
-
'content_hash': content_hash, 'path': None, 'title': title,
|
|
367
|
-
'signer_pubkey': signer_pubkey, 'error': None}
|
|
363
|
+
'content_hash': content_hash, 'path': None, 'title': title, 'error': None}
|
|
368
364
|
threading.Thread(target=_run_download_job,
|
|
369
|
-
args=(job_id, content_hash, relay_urls, out_path, k, use_lightning, title,
|
|
370
|
-
signer_pubkey),
|
|
365
|
+
args=(job_id, content_hash, relay_urls, out_path, k, use_lightning, title),
|
|
371
366
|
daemon=True).start()
|
|
372
367
|
self._json({'job_id': job_id})
|
|
373
368
|
|
|
@@ -48,6 +48,26 @@ def run_make(target):
|
|
|
48
48
|
sys.exit(result.returncode)
|
|
49
49
|
|
|
50
50
|
|
|
51
|
+
# $WEED_RELAY/$WEED_TUNNEL let a real relay/tunnel deployment (not just
|
|
52
|
+
# the loopback defaults everything below otherwise falls back to) be set
|
|
53
|
+
# once per shell session instead of retyped on every host/discover/
|
|
54
|
+
# download/like/subscribe invocation -- an explicit --relay/--tunnel
|
|
55
|
+
# flag still always wins, this only changes what happens when neither is
|
|
56
|
+
# given. shell.py's WeedShell reads the same two variables for the same
|
|
57
|
+
# reason (see its own default_relay/default_tunnel).
|
|
58
|
+
def _default_relay():
|
|
59
|
+
return os.environ.get('WEED_RELAY', 'http://127.0.0.1:9101')
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _default_relay_list():
|
|
63
|
+
# --relay is action='append' on p_host specifically, which normally
|
|
64
|
+
# defaults to [] (empty = "don't announce anywhere" is a valid,
|
|
65
|
+
# deliberate choice there — see cmd_host) rather than falling back to
|
|
66
|
+
# loopback; only seed that list from $WEED_RELAY when it's actually set
|
|
67
|
+
relay = os.environ.get('WEED_RELAY')
|
|
68
|
+
return [relay] if relay else []
|
|
69
|
+
|
|
70
|
+
|
|
51
71
|
def build_parser():
|
|
52
72
|
import node
|
|
53
73
|
parser = argparse.ArgumentParser(
|
|
@@ -73,21 +93,24 @@ def build_parser():
|
|
|
73
93
|
p_host.add_argument('--file', help='which archived file, if more than one (default: most recent)')
|
|
74
94
|
p_host.add_argument('--port', type=int, default=9201)
|
|
75
95
|
p_host.add_argument('--price', type=int, default=0, help='sats to charge per download (default: free)')
|
|
76
|
-
p_host.add_argument('--relay', action='append', default=
|
|
96
|
+
p_host.add_argument('--relay', action='append', default=_default_relay_list(),
|
|
97
|
+
help='relay URL to announce on (repeatable; default: $WEED_RELAY if set)')
|
|
77
98
|
p_host.add_argument('--advertise-host', default='127.0.0.1',
|
|
78
99
|
help='address to tell the relay to advertise (set this to your real '
|
|
79
100
|
'reachable IP if hosting off localhost — or use --tunnel if you '
|
|
80
101
|
'have no reachable address at all, e.g. behind NAT/CGNAT)')
|
|
81
|
-
p_host.add_argument('--tunnel', metavar='[tls://]RELAY_HOST:PORT',
|
|
102
|
+
p_host.add_argument('--tunnel', metavar='[tls://]RELAY_HOST:PORT', default=os.environ.get('WEED_TUNNEL'),
|
|
82
103
|
help='tunnel_relay.py address to register with instead of relying on a '
|
|
83
104
|
'reachable inbound port — see tunnel_relay.py. Downloaders connect '
|
|
84
105
|
'through the relay, not to you directly. Prefix with tls:// if the '
|
|
85
106
|
'relay terminates TLS at the edge (e.g. a Fly service with '
|
|
86
|
-
'handlers = ["tls"]) — the relay process itself never needs to know'
|
|
107
|
+
'handlers = ["tls"]) — the relay process itself never needs to know. '
|
|
108
|
+
'Default: $WEED_TUNNEL if set.')
|
|
87
109
|
|
|
88
110
|
p_discover = sub.add_parser('discover', help='list real content announced on one or more relays')
|
|
89
|
-
p_discover.add_argument('--relay', action='append', default=[
|
|
90
|
-
help='relay URL to query (repeatable
|
|
111
|
+
p_discover.add_argument('--relay', action='append', default=[_default_relay()],
|
|
112
|
+
help='relay URL to query (repeatable; default: $WEED_RELAY if set, '
|
|
113
|
+
'else http://127.0.0.1:9101)')
|
|
91
114
|
|
|
92
115
|
p_download = sub.add_parser('download', aliases=['get'],
|
|
93
116
|
help='discover, possession-challenge, auction, optionally pay, '
|
|
@@ -95,8 +118,9 @@ def build_parser():
|
|
|
95
118
|
p_download.add_argument('content_hash', nargs='?', help='content hash to resolve via --relay')
|
|
96
119
|
p_download.add_argument('--from', dest='from_addr', help='host:port to connect to directly, skipping '
|
|
97
120
|
'discovery/auction entirely (no possession challenge, no reputation, no payment)')
|
|
98
|
-
p_download.add_argument('--relay', action='append', default=[
|
|
99
|
-
help='relay URL to resolve content_hash against (repeatable
|
|
121
|
+
p_download.add_argument('--relay', action='append', default=[_default_relay()],
|
|
122
|
+
help='relay URL to resolve content_hash against (repeatable; '
|
|
123
|
+
'default: $WEED_RELAY if set, else http://127.0.0.1:9101)')
|
|
100
124
|
p_download.add_argument('--out', help='output path (default: the advertised filename)')
|
|
101
125
|
p_download.add_argument('--challenge-rounds', type=int, default=3,
|
|
102
126
|
help='chunks to sample-verify per candidate host before trusting it (default: 3)')
|
|
@@ -106,11 +130,13 @@ def build_parser():
|
|
|
106
130
|
|
|
107
131
|
p_like = sub.add_parser('like', help='sign and post a real like event')
|
|
108
132
|
p_like.add_argument('content_hash')
|
|
109
|
-
p_like.add_argument('--relay', default=
|
|
133
|
+
p_like.add_argument('--relay', default=_default_relay(),
|
|
134
|
+
help='default: $WEED_RELAY if set, else http://127.0.0.1:9101')
|
|
110
135
|
|
|
111
136
|
p_subscribe = sub.add_parser('subscribe', help='sign and post a real subscribe event')
|
|
112
137
|
p_subscribe.add_argument('target_pubkey')
|
|
113
|
-
p_subscribe.add_argument('--relay', default=
|
|
138
|
+
p_subscribe.add_argument('--relay', default=_default_relay(),
|
|
139
|
+
help='default: $WEED_RELAY if set, else http://127.0.0.1:9101')
|
|
114
140
|
|
|
115
141
|
p_web = sub.add_parser('web', help='local web UI — discover/host/download/like/subscribe '
|
|
116
142
|
'from a browser instead of the CLI')
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: weed-cli
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.7
|
|
4
4
|
Summary: Censorship-resistant video PoC — discovery/hosting/download over signed relay events, a real Kademlia DHT, or a TLS-capable NAT-traversal tunnel
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: p2p,video,censorship-resistant,discovery,dht,kademlia,nat-traversal
|
|
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
|