weed-cli 1.8.0__tar.gz → 1.8.2__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.8.0/weed_cli.egg-info → weed_cli-1.8.2}/PKG-INFO +1 -1
- {weed_cli-1.8.0 → weed_cli-1.8.2}/pyproject.toml +1 -1
- weed_cli-1.8.2/tests/test_dht.py +128 -0
- {weed_cli-1.8.0 → weed_cli-1.8.2/weed_cli.egg-info}/PKG-INFO +1 -1
- {weed_cli-1.8.0 → weed_cli-1.8.2}/weed_cli.egg-info/SOURCES.txt +1 -0
- {weed_cli-1.8.0 → weed_cli-1.8.2}/LICENSE +0 -0
- {weed_cli-1.8.0 → weed_cli-1.8.2}/README.md +0 -0
- {weed_cli-1.8.0 → weed_cli-1.8.2}/dht.py +0 -0
- {weed_cli-1.8.0 → weed_cli-1.8.2}/discovery_relay.py +0 -0
- {weed_cli-1.8.0 → weed_cli-1.8.2}/lightning_settle.py +0 -0
- {weed_cli-1.8.0 → weed_cli-1.8.2}/node.py +0 -0
- {weed_cli-1.8.0 → weed_cli-1.8.2}/poc_reputation.py +0 -0
- {weed_cli-1.8.0 → weed_cli-1.8.2}/setup.cfg +0 -0
- {weed_cli-1.8.0 → weed_cli-1.8.2}/shell.py +0 -0
- {weed_cli-1.8.0 → weed_cli-1.8.2}/tests/test_discovery_relay.py +0 -0
- {weed_cli-1.8.0 → weed_cli-1.8.2}/tests/test_node_manifest.py +0 -0
- {weed_cli-1.8.0 → weed_cli-1.8.2}/tests/test_web_ui_api.py +0 -0
- {weed_cli-1.8.0 → weed_cli-1.8.2}/tests/testutil.py +0 -0
- {weed_cli-1.8.0 → weed_cli-1.8.2}/tunnel_relay.py +0 -0
- {weed_cli-1.8.0 → weed_cli-1.8.2}/web_ui.py +0 -0
- {weed_cli-1.8.0 → weed_cli-1.8.2}/weed.py +0 -0
- {weed_cli-1.8.0 → weed_cli-1.8.2}/weed_cli.egg-info/dependency_links.txt +0 -0
- {weed_cli-1.8.0 → weed_cli-1.8.2}/weed_cli.egg-info/entry_points.txt +0 -0
- {weed_cli-1.8.0 → weed_cli-1.8.2}/weed_cli.egg-info/requires.txt +0 -0
- {weed_cli-1.8.0 → weed_cli-1.8.2}/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.8.
|
|
3
|
+
Version: 1.8.2
|
|
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
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "weed-cli"
|
|
7
|
-
version = "1.8.
|
|
7
|
+
version = "1.8.2"
|
|
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" }
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"""
|
|
2
|
+
dht.py's real Kademlia swarm -- multiple real dht.DHTNode instances (each
|
|
3
|
+
its own thread + its own asyncio event loop, see DHTNode's own docstring)
|
|
4
|
+
in one process. Unlike discovery_relay.py, kademlia.network.Server carries
|
|
5
|
+
no module-level global state shared across instances, so running several
|
|
6
|
+
in-process (rather than as separate subprocesses, the way
|
|
7
|
+
tests/conftest.py's `relay` fixture has to for discovery_relay.py) is
|
|
8
|
+
correct here, not a test-isolation shortcut -- kademlia's own test suite
|
|
9
|
+
does the same thing for the same reason.
|
|
10
|
+
"""
|
|
11
|
+
import pytest
|
|
12
|
+
|
|
13
|
+
import dht
|
|
14
|
+
from testutil import free_port
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def make_node(bootstrap_port=None):
|
|
18
|
+
port = free_port()
|
|
19
|
+
bootstrap = [('127.0.0.1', bootstrap_port)] if bootstrap_port else None
|
|
20
|
+
node = dht.DHTNode(port, bootstrap_nodes=bootstrap, quiet=True)
|
|
21
|
+
node.start()
|
|
22
|
+
return node, port
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@pytest.fixture()
|
|
26
|
+
def swarm():
|
|
27
|
+
"""Yields a list callers append (node, port) pairs to; stops every
|
|
28
|
+
node on teardown regardless of how many the test actually created."""
|
|
29
|
+
nodes = []
|
|
30
|
+
yield nodes
|
|
31
|
+
for node, _ in nodes:
|
|
32
|
+
node.stop()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def test_solo_node_with_no_neighbors_cannot_store_or_retrieve_anything(swarm):
|
|
36
|
+
"""Not a trivial "empty DHT" check -- a real, easy-to-miss operational
|
|
37
|
+
gotcha discovered while writing these tests: kademlia's get/set work
|
|
38
|
+
by routing to the nearest *known* nodes, and a node with zero known
|
|
39
|
+
neighbors (the very first node in a swarm, before anyone else has
|
|
40
|
+
bootstrapped to or from it) has nowhere to route to. It doesn't raise
|
|
41
|
+
-- it logs a warning and silently no-ops, so announce()/lookup() both
|
|
42
|
+
just look like "nothing here" instead of "not connected to anything
|
|
43
|
+
yet." A genuinely-empty lookup in a *working* multi-node swarm is
|
|
44
|
+
covered separately below (test_lookup_for_unknown_hash_on_a_real_swarm)."""
|
|
45
|
+
a, _ = make_node()
|
|
46
|
+
swarm.append((a, _))
|
|
47
|
+
a.announce('c' * 64, '127.0.0.1:9201')
|
|
48
|
+
assert a.lookup('c' * 64) == []
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_two_nodes_announce_and_lookup(swarm):
|
|
52
|
+
"""The actual round trip: B joins A's swarm, B announces, A looks it
|
|
53
|
+
up -- A and B never talk except for B's one bootstrap connection, so
|
|
54
|
+
finding it on A proves the DHT's own get/set is doing the work, not
|
|
55
|
+
some direct A<->B shortcut."""
|
|
56
|
+
a, a_port = make_node()
|
|
57
|
+
swarm.append((a, a_port))
|
|
58
|
+
b, b_port = make_node(bootstrap_port=a_port)
|
|
59
|
+
swarm.append((b, b_port))
|
|
60
|
+
|
|
61
|
+
b.announce('c' * 64, '127.0.0.1:9201', title='My Video')
|
|
62
|
+
|
|
63
|
+
results = a.lookup('c' * 64)
|
|
64
|
+
assert results == [{'host': '127.0.0.1:9201', 'title': 'My Video'}]
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def test_lookup_for_unknown_hash_on_a_real_swarm_is_empty(swarm):
|
|
68
|
+
a, a_port = make_node()
|
|
69
|
+
swarm.append((a, a_port))
|
|
70
|
+
b, b_port = make_node(bootstrap_port=a_port)
|
|
71
|
+
swarm.append((b, b_port))
|
|
72
|
+
|
|
73
|
+
b.announce('c' * 64, '127.0.0.1:9201')
|
|
74
|
+
assert a.lookup('d' * 64) == []
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def test_two_hosts_for_same_content_hash_merge_not_overwrite(swarm):
|
|
78
|
+
"""_announce's own contract (see its docstring): a second host
|
|
79
|
+
announcing the same content_hash must show up *alongside* the first,
|
|
80
|
+
not replace it -- multiple peers hosting the same file is real,
|
|
81
|
+
useful redundancy, not a conflict to resolve."""
|
|
82
|
+
a, a_port = make_node()
|
|
83
|
+
swarm.append((a, a_port))
|
|
84
|
+
b, b_port = make_node(bootstrap_port=a_port)
|
|
85
|
+
swarm.append((b, b_port))
|
|
86
|
+
|
|
87
|
+
a.announce('c' * 64, '127.0.0.1:9201', title='v')
|
|
88
|
+
b.announce('c' * 64, '127.0.0.1:9202', title='v')
|
|
89
|
+
|
|
90
|
+
hosts = {e['host'] for e in a.lookup('c' * 64)}
|
|
91
|
+
assert hosts == {'127.0.0.1:9201', '127.0.0.1:9202'}
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def test_reannouncing_same_host_replaces_its_own_entry_not_duplicates(swarm):
|
|
95
|
+
"""A completely solo node (zero known neighbors -- nobody's ever
|
|
96
|
+
bootstrapped to or from it) can't even get/set against itself:
|
|
97
|
+
kademlia's own set/get work by routing to the nearest known nodes, and
|
|
98
|
+
with none known there's nowhere to route to (it logs a warning and
|
|
99
|
+
silently no-ops, discovered the hard way -- an earlier version of
|
|
100
|
+
this test tried exactly that and got [] back instead of real data).
|
|
101
|
+
Two nodes is the minimum for get/set to actually do anything."""
|
|
102
|
+
a, a_port = make_node()
|
|
103
|
+
swarm.append((a, a_port))
|
|
104
|
+
b, b_port = make_node(bootstrap_port=a_port)
|
|
105
|
+
swarm.append((b, b_port))
|
|
106
|
+
|
|
107
|
+
a.announce('c' * 64, '127.0.0.1:9201', title='v1')
|
|
108
|
+
a.announce('c' * 64, '127.0.0.1:9201', title='v2')
|
|
109
|
+
|
|
110
|
+
results = b.lookup('c' * 64)
|
|
111
|
+
assert results == [{'host': '127.0.0.1:9201', 'title': 'v2'}]
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def test_three_node_chain_propagates_through_indirect_bootstrap(swarm):
|
|
115
|
+
"""C bootstraps through B, never touches A directly -- if C can still
|
|
116
|
+
look up something A announced, that's Kademlia's own routing doing
|
|
117
|
+
real work, not just a two-node special case."""
|
|
118
|
+
a, a_port = make_node()
|
|
119
|
+
swarm.append((a, a_port))
|
|
120
|
+
b, b_port = make_node(bootstrap_port=a_port)
|
|
121
|
+
swarm.append((b, b_port))
|
|
122
|
+
c, c_port = make_node(bootstrap_port=b_port)
|
|
123
|
+
swarm.append((c, c_port))
|
|
124
|
+
|
|
125
|
+
a.announce('c' * 64, '127.0.0.1:9201', title='from A')
|
|
126
|
+
|
|
127
|
+
results = c.lookup('c' * 64)
|
|
128
|
+
assert results == [{'host': '127.0.0.1:9201', 'title': 'from A'}]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: weed-cli
|
|
3
|
-
Version: 1.8.
|
|
3
|
+
Version: 1.8.2
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|