88 PingService ,
99 handle_ping ,
1010)
11+ from libp2p .kad_dht .kad_dht import DHTMode , KadDHT
1112from libp2p .peer .id import ID
1213from libp2p .peer .peerinfo import info_from_p2p_addr
1314from libp2p .pubsub .gossipsub import GossipSub
1415from libp2p .pubsub .pubsub import Pubsub
16+ from libp2p .records .validator import Validator
17+ from libp2p .utils .paths import get_script_dir , join_paths
1518
1619GOSSIPSUB_PROTOCOL_ID = TProtocol ("/meshsub/1.0.0" )
1720COMMANDS = """
2124- join <topic> - Subscribe to a topic
2225- leave <topic> - Unsubscribe to a topic
2326- publish <topic> <message> - Publish a message
27+ - put <key> <value> - Execute PUT_VALUE in DHT
28+ - get <key> - Execute GET_VALUE in DHT
29+ - advertize <content-id> - Execute ADD_PROVIDER in DHT
30+ - get_provider <content-id> - Execute GET_PROVIDERS in DHT
2431- local - List local multiaddr
2532- help - List the existing commands
2633- exit - Shut down
2734"""
2835
2936
37+ class ExampleValidator (Validator ):
38+ def validate (self , key : str , value : bytes ) -> None :
39+ if not value :
40+ raise ValueError ("Value cannot be empty" )
41+
42+ def select (self , key : str , values : list [bytes ]) -> int :
43+ return 0
44+
45+
3046class Node :
31- def __init__ (self , listen_addrs : list [multiaddr .Multiaddr ]):
47+ def __init__ (
48+ self , listen_addrs : list [multiaddr .Multiaddr ], dht_role : str
49+ ):
3250 # Create a libp2p-host
3351 self .host = new_host (listen_addrs = listen_addrs , enable_metrics = True )
3452
35- # Setup PING service
53+ # PING
3654 self .host .set_stream_handler (PING_ID , handle_ping )
3755 self .ping_service = PingService (self .host )
3856
39- # Set up Pubsub/Gossipsub
57+ # Pubsub/Gossipsub
4058 self .gossipsub = GossipSub (
4159 protocols = [GOSSIPSUB_PROTOCOL_ID ],
4260 degree = 3 , # Number of peers to maintain in mesh
@@ -51,6 +69,14 @@ def __init__(self, listen_addrs: list[multiaddr.Multiaddr]):
5169 )
5270 self .pubsub = Pubsub (self .host , self .gossipsub )
5371
72+ # KAD-DHT
73+ if dht_role == "server" :
74+ dht_mode = DHTMode .SERVER
75+ else :
76+ dht_mode = DHTMode .CLIENT
77+ self .dht = KadDHT (self .host , dht_mode )
78+ self .dht .register_validator ("exp" , ExampleValidator ())
79+
5480 # CLI input send/receive channels
5581 self .input_send_channel , self .input_receive_channel = trio .open_memory_channel (
5682 100
@@ -105,7 +131,44 @@ async def command_executor(self, nursery):
105131 if cmd == "publish" and len (parts ) > 2 :
106132 await self .pubsub .publish (parts [1 ], parts [2 ].encode ())
107133 print (f"Published: { parts [2 ]} " )
108-
134+
135+ if cmd == "put" and len (parts ) > 2 :
136+ key = parts [1 ]
137+ value = parts [2 ].encode ()
138+
139+ await self .dht .put_value (key , value )
140+ print (f"Stored value: { value .decode ()} with key: { key } " )
141+
142+ if cmd == "get" and len (parts ) > 1 :
143+ key = parts [1 ]
144+
145+ retrieved_value = await self .dht .get_value (key )
146+ if retrieved_value :
147+ print (f"Retrieved value: { retrieved_value .decode ()} " )
148+ else :
149+ print ("Failed to retrieve" )
150+
151+ if cmd == "advertize" and len (parts ) > 1 :
152+ content_id = parts [1 ]
153+
154+ success = await self .dht .provide (content_id )
155+ if success :
156+ print (f"Advertised as provider for content: { content_id } " )
157+ else :
158+ print ("Failed to advertise as provider" )
159+
160+ if cmd == "get_provider" and len (parts ) > 1 :
161+ content_id = parts [1 ]
162+
163+ providers = await self .dht .find_providers (content_id )
164+ if providers :
165+ print (
166+ f"Found { len (providers )} providers: "
167+ f"{ [p .peer_id for p in providers ]} "
168+ )
169+ else :
170+ print ("No providers found" )
171+
109172 if cmd == "local" :
110173 maddr = self .host .get_addrs ()[0 ]
111174 print (maddr )
0 commit comments