-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e702125
commit c868dfd
Showing
23 changed files
with
953 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package dht | ||
|
||
import ( | ||
"container/list" | ||
) | ||
|
||
type bucket struct { | ||
list *list.List | ||
} | ||
|
||
func newBucket() *bucket { | ||
bucket := &bucket{} | ||
bucket.list = list.New() | ||
return bucket | ||
} | ||
|
||
func (bucket *bucket) AddContact(contact *Contact) { | ||
var element *list.Element | ||
for e := bucket.list.Front(); e != nil; e = e.Next() { | ||
nodeID := e.Value.(*Contact).ID | ||
|
||
if (contact).ID.Equals(nodeID) { | ||
element = e | ||
} | ||
} | ||
|
||
if element == nil { | ||
if bucket.list.Len() < bucketSize { | ||
bucket.list.PushFront(contact) | ||
} else { | ||
// Check if the last contact is alive | ||
} | ||
} else { | ||
bucket.list.MoveToFront(element) | ||
} | ||
} | ||
|
||
func (bucket *bucket) GetContactAndCalcDistance(target *KademliaID) []*Contact { | ||
var contacts []*Contact | ||
|
||
for elt := bucket.list.Front(); elt != nil; elt = elt.Next() { | ||
contact := elt.Value.(*Contact) | ||
contact.CalcDistance(target) | ||
contacts = append(contacts, contact) | ||
} | ||
|
||
return contacts | ||
} | ||
|
||
func (bucket *bucket) Len() int { | ||
return bucket.list.Len() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package dht | ||
|
||
import ( | ||
"fmt" | ||
"sort" | ||
) | ||
|
||
type Contact struct { | ||
ID *KademliaID `json:"kademliaid"` | ||
Addr string `json:"address"` | ||
distance *KademliaID | ||
} | ||
|
||
func CreateContact(id *KademliaID, address string) *Contact { | ||
return &Contact{id, address, nil} | ||
} | ||
|
||
func (contact *Contact) CalcDistance(target *KademliaID) { | ||
contact.distance = contact.ID.CalcDistance(target) | ||
} | ||
|
||
func (contact *Contact) Less(otherContact *Contact) bool { | ||
return contact.distance.Less(otherContact.distance) | ||
} | ||
|
||
func (contact *Contact) String() string { | ||
return fmt.Sprintf(`contact("%s", "%s")`, contact.ID, contact.Addr) | ||
} | ||
|
||
type ContactCandidates struct { | ||
contacts []*Contact | ||
} | ||
|
||
func (candidates *ContactCandidates) Append(contacts []*Contact) { | ||
candidates.contacts = append(candidates.contacts, contacts...) | ||
} | ||
|
||
func (candidates *ContactCandidates) GetContacts(count int) []*Contact { | ||
return candidates.contacts[:count] | ||
} | ||
|
||
func (candidates *ContactCandidates) Sort() { | ||
sort.Sort(candidates) | ||
} | ||
|
||
func (candidates *ContactCandidates) Len() int { | ||
return len(candidates.contacts) | ||
} | ||
|
||
func (candidates *ContactCandidates) Swap(i, j int) { | ||
candidates.contacts[i], candidates.contacts[j] = candidates.contacts[j], candidates.contacts[i] | ||
} | ||
|
||
func (candidates *ContactCandidates) Less(i, j int) bool { | ||
return candidates.contacts[i].Less(candidates.contacts[j]) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"log" | ||
|
||
"github.com/libp2p/go-libp2p" | ||
dht "github.com/libp2p/go-libp2p-kad-dht" | ||
record "github.com/libp2p/go-libp2p-record" | ||
"github.com/libp2p/go-libp2p/core/host" | ||
"github.com/libp2p/go-libp2p/core/peer" | ||
) | ||
|
||
// chatServiceValidator validates that the value associated with a key is a valid peer ID. | ||
type chatServiceValidator struct{} | ||
|
||
// Validate conforms to the record.Validator interface. | ||
// It checks if the given value is a valid peer ID for the chat service keys. | ||
func (v chatServiceValidator) Validate(key string, value []byte) error { | ||
_, err := peer.Decode(string(value)) | ||
if err != nil { | ||
return fmt.Errorf("invalid peer ID for key '%s'", key) | ||
} | ||
return nil | ||
} | ||
|
||
// Select conforms to the record.Validator interface. | ||
// For this example, it just selects the first value, but you could implement more complex logic. | ||
func (v chatServiceValidator) Select(key string, values [][]byte) (int, error) { | ||
return 0, nil // Simplest implementation: always select the first value. | ||
} | ||
|
||
func setupHostAndDHT(ctx context.Context) (host.Host, *dht.IpfsDHT, error) { | ||
// Create a new libp2p host | ||
h, err := libp2p.New() | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
nsValidator := record.NamespacedValidator{ | ||
//"pk": record.PublicKeyValidator{}, // Validator for public keys | ||
//"ipns": ipns.Validator{}, | ||
"chat": chatServiceValidator{}, // Use your namespace here | ||
} | ||
|
||
// Create a DHT instance with the custom validator | ||
d, err := dht.New(ctx, h, dht.Validator(nsValidator)) | ||
// d, err := dht.New(ctx, h, dht.Validator(chatServiceValidator{})) | ||
if err != nil { | ||
h.Close() | ||
return nil, nil, err | ||
} | ||
|
||
// Bootstrap the DHT (in a real-world scenario, you would connect to known peers) | ||
if err := d.Bootstrap(ctx); err != nil { | ||
h.Close() | ||
return nil, nil, err | ||
} | ||
|
||
// Create a service key | ||
serviceKey := fmt.Sprintf("/myapp/chat/%s", "serviceName") | ||
|
||
// Advertise the service in the DHT | ||
if err := d.PutValue(ctx, serviceKey, []byte(h.ID())); err != nil { | ||
fmt.Println("err", err) | ||
} | ||
|
||
providers, err := d.GetValue(ctx, serviceKey) | ||
if err != nil { | ||
fmt.Println("err", err) | ||
} | ||
|
||
fmt.Println("providers", providers) | ||
|
||
return h, d, nil | ||
} | ||
|
||
func main() { | ||
ctx := context.Background() | ||
h, _, err := setupHostAndDHT(ctx) | ||
if err != nil { | ||
log.Fatalf("Failed to set up host and DHT: %s", err) | ||
} | ||
defer h.Close() | ||
|
||
// Your service advertisement and discovery logic here... | ||
|
||
<-ctx.Done() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"log" | ||
|
||
"github.com/libp2p/go-libp2p" | ||
"github.com/libp2p/go-libp2p-core/peer" | ||
dht "github.com/libp2p/go-libp2p-kad-dht" | ||
) | ||
|
||
func main() { | ||
ctx := context.Background() | ||
|
||
// Create a new libp2p Host that listens on a random TCP port | ||
h, err := libp2p.New() | ||
if err != nil { | ||
log.Fatalf("Failed to create host: %s", err) | ||
} | ||
|
||
// Set up a DHT for peer discovery | ||
kadDHT, err := dht.New(ctx, h) | ||
if err != nil { | ||
log.Fatalf("Failed to create the DHT: %s", err) | ||
} | ||
|
||
// Bootstrap the DHT. In the real world, we would need to connect to bootstrap nodes here. | ||
if err = kadDHT.Bootstrap(ctx); err != nil { | ||
log.Fatalf("Failed to bootstrap the DHT: %s", err) | ||
} | ||
|
||
// Connect to the other libp2p instance using its multiaddress | ||
// Replace <peerMultiAddr> with the actual multiaddress of the peer that stored the value | ||
peerMultiAddr := "<peerMultiAddr>" | ||
peerAddr, err := peer.AddrInfoFromP2pAddr(peerMultiAddr) | ||
if err != nil { | ||
log.Fatalf("Failed to parse peer multiaddr: %s", err) | ||
} | ||
if err := h.Connect(ctx, *peerAddr); err != nil { | ||
log.Fatalf("Failed to connect to peer: %s", err) | ||
} | ||
|
||
// Fetch the value from the DHT | ||
key := "myKey" | ||
value, err := kadDHT.GetValue(ctx, key) | ||
if err != nil { | ||
log.Fatalf("Failed to get value from DHT: %s", err) | ||
} | ||
|
||
fmt.Printf("Fetched value from DHT: %s\n", string(value)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"log" | ||
"time" | ||
"unicode/utf8" | ||
|
||
"github.com/libp2p/go-libp2p" | ||
dht "github.com/libp2p/go-libp2p-kad-dht" | ||
"github.com/libp2p/go-libp2p/core/record" | ||
) | ||
|
||
func main() { | ||
ctx, cancel := context.WithCancel(context.Background()) | ||
defer cancel() | ||
|
||
// Create a new libp2p Host | ||
h, err := libp2p.New() | ||
if err != nil { | ||
log.Fatalf("Failed to create libp2p host: %s", err) | ||
} | ||
defer h.Close() | ||
|
||
// Create a custom validator that includes namespaced validation logic | ||
customValidator := &record.ValidChecker{ | ||
Validator: map[string]record.Validator{ | ||
"utf8": &utf8Validator{}, | ||
}, | ||
Selector: map[string]record.Selector{ | ||
"utf8": &record.CurrentSelector{}, | ||
}, | ||
} | ||
|
||
// Create a new DHT instance with the custom validator | ||
d, err := dht.New(ctx, h, dht.Validator(customValidator)) | ||
if err != nil { | ||
log.Fatalf("Failed to create DHT with custom validator: %s", err) | ||
} | ||
|
||
// Bootstrap the DHT | ||
if err := d.Bootstrap(ctx); err != nil { | ||
log.Fatalf("Failed to bootstrap DHT: %s", err) | ||
} | ||
|
||
// Define the key and value to store in the DHT | ||
key := "/utf8/validKey" | ||
value := "Hello, world!" | ||
|
||
// Store the value in the DHT | ||
if err := storeValue(ctx, d, key, value); err != nil { | ||
log.Fatalf("Failed to store value: %s", err) | ||
} | ||
|
||
// Retrieve the value from the DHT | ||
retrievedValue, err := d.GetValue(ctx, key) | ||
if err != nil { | ||
log.Fatalf("Failed to retrieve value: %s", err) | ||
} | ||
fmt.Printf("Retrieved value: %s\n", string(retrievedValue)) | ||
} | ||
|
||
// utf8Validator is a custom validator that checks for valid UTF-8 encoding. | ||
type utf8Validator struct{} | ||
|
||
func (v *utf8Validator) Validate(key string, value []byte) error { | ||
if !utf8.Valid(value) { | ||
return fmt.Errorf("invalid UTF-8 value for key %s", key) | ||
} | ||
return nil | ||
} | ||
|
||
func (v *utf8Validator) Select(key string, values [][]byte) (int, error) { | ||
return 0, nil // Always select the first value | ||
} | ||
|
||
// storeValue stores a key-value pair in the DHT. | ||
func storeValue(ctx context.Context, d *dht.IpfsDHT, key, value string) error { | ||
ctx, cancel := context.WithTimeout(ctx, 10*time.Second) | ||
defer cancel() | ||
return d.PutValue(ctx, key, []byte(value)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"crypto/sha256" | ||
"encoding/hex" | ||
"fmt" | ||
"log" | ||
|
||
"github.com/libp2p/go-libp2p" | ||
dht "github.com/libp2p/go-libp2p-kad-dht" | ||
) | ||
|
||
func formatKey(originalKey string) string { | ||
hash := sha256.Sum256([]byte(originalKey)) | ||
return hex.EncodeToString(hash[:]) | ||
} | ||
|
||
func main() { | ||
ctx := context.Background() | ||
|
||
// Create a new libp2p Host that listens on a random TCP port | ||
h, err := libp2p.New() | ||
if err != nil { | ||
log.Fatalf("Failed to create h: %s", err) | ||
} | ||
|
||
// Set up a DHT for peer discovery | ||
kadDHT, err := dht.New(ctx, h) | ||
if err != nil { | ||
log.Fatalf("Failed to create the DHT: %s", err) | ||
} | ||
|
||
// Bootstrap the DHT. In the real world, we would need to connect to bootstrap nodes here. | ||
if err = kadDHT.Bootstrap(ctx); err != nil { | ||
log.Fatalf("Failed to bootstrap the DHT: %s", err) | ||
} | ||
|
||
fmt.Println("This node's addresses:") | ||
for _, addr := range h.Addrs() { | ||
fmt.Printf("%s/p2p/%s\n", addr, h.ID()) | ||
} | ||
|
||
// Use a hash function to convert the key to a suitable format for the DHT | ||
key := "myKey" | ||
//hashedKey := sha256.Sum256([]byte(key)) | ||
//keyString := fmt.Sprintf("/record/%x", hashedKey) | ||
formattedKey := formatKey(key) | ||
|
||
value := []byte("Hello World") | ||
err = kadDHT.PutValue(ctx, formattedKey, value) | ||
if err != nil { | ||
log.Fatalf("Failed to put value in DHT: %s", err) | ||
} | ||
|
||
fmt.Println("Successfully stored value in DHT") | ||
|
||
// Keep the host alive until the user interrupts the program | ||
select {} | ||
} |
Oops, something went wrong.