start FindSuccessor query
This commit is contained in:
parent
45efc85a6e
commit
ce8d109039
62
chord/httpnode/client.go
Normal file
62
chord/httpnode/client.go
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package httpnode
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/netip"
|
||||||
|
"net/url"
|
||||||
|
"path"
|
||||||
|
|
||||||
|
"github.com/go-json-experiment/json"
|
||||||
|
|
||||||
|
"git.sunturtle.xyz/zephyr/chord/chord"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
// HTTP is the client used to make requests.
|
||||||
|
HTTP http.Client
|
||||||
|
// APIBase is the path under which the Chord API is served.
|
||||||
|
APIBase string
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindSuccessor asks s to find the first peer in the network preceding id.
|
||||||
|
func (cl *Client) FindSuccessor(ctx context.Context, s chord.Peer, id chord.ID) (chord.Peer, error) {
|
||||||
|
_, addr := s.Values()
|
||||||
|
if !addr.IsValid() {
|
||||||
|
return chord.Peer{}, errors.New("FindSuccessor with invalid peer")
|
||||||
|
}
|
||||||
|
url := url.URL{
|
||||||
|
Scheme: "http",
|
||||||
|
Host: addr.String(),
|
||||||
|
Path: path.Join("/", cl.APIBase, "succ"),
|
||||||
|
RawQuery: url.Values{"s": {id.String()}}.Encode(),
|
||||||
|
}
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "GET", url.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return chord.Peer{}, err
|
||||||
|
}
|
||||||
|
resp, err := cl.HTTP.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return chord.Peer{}, err
|
||||||
|
}
|
||||||
|
var r response[netip.AddrPort]
|
||||||
|
if err := json.UnmarshalRead(resp.Body, &r); err != nil {
|
||||||
|
return chord.Peer{}, err
|
||||||
|
}
|
||||||
|
if r.Error != "" {
|
||||||
|
return chord.Peer{}, fmt.Errorf("%s (%s)", r.Error, resp.Status)
|
||||||
|
}
|
||||||
|
return chord.Address(*r.Data), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify tells s we believe n to be its predecessor.
|
||||||
|
func (cl *Client) Notify(ctx context.Context, n *chord.Node, s chord.Peer) error {
|
||||||
|
panic("not implemented") // TODO: Implement
|
||||||
|
}
|
||||||
|
|
||||||
|
// Neighbors requests a peer's beliefs about its own neighbors.
|
||||||
|
func (cl *Client) Neighbors(ctx context.Context, p chord.Peer) (pred chord.Peer, succ []chord.Peer, err error) {
|
||||||
|
panic("not implemented") // TODO: Implement
|
||||||
|
}
|
15
chord/httpnode/httpnode.go
Normal file
15
chord/httpnode/httpnode.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// Package httpnode provides an implementation of a Chord client and server
|
||||||
|
// using JSON over HTTP.
|
||||||
|
package httpnode
|
||||||
|
|
||||||
|
import "net/netip"
|
||||||
|
|
||||||
|
type response[T any] struct {
|
||||||
|
Data *T `json:"data,omitzero"`
|
||||||
|
Error string `json:"error,omitzero"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type neighbors struct {
|
||||||
|
Succ []netip.AddrPort `json:"succ"`
|
||||||
|
Pred netip.AddrPort `json:"pred"`
|
||||||
|
}
|
@ -3,6 +3,7 @@ package chord
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
|
"encoding/hex"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -42,3 +43,9 @@ func contains(left, right, x ID) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (id ID) String() string {
|
||||||
|
b := make([]byte, 0, len(ID{})*2)
|
||||||
|
b = hex.AppendEncode(b, id[:])
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
@ -79,6 +79,13 @@ func Address(addr netip.AddrPort) Peer {
|
|||||||
// which was valid.
|
// which was valid.
|
||||||
func (p Peer) IsValid() bool { return p.addr.IsValid() && p.addr.Port() != 0 }
|
func (p Peer) IsValid() bool { return p.addr.IsValid() && p.addr.Port() != 0 }
|
||||||
|
|
||||||
|
// Values returns the peer's ID and address.
|
||||||
|
func (p Peer) Values() (ID, netip.AddrPort) {
|
||||||
|
// We do this instead of exporting Peer's fields to ensure those fields
|
||||||
|
// are never mutable. If p.IsValid() then p.id == addrID(p.addr) always.
|
||||||
|
return p.id, p.addr
|
||||||
|
}
|
||||||
|
|
||||||
// Create creates a new Chord network using the given address as the initial node.
|
// Create creates a new Chord network using the given address as the initial node.
|
||||||
func Create(addr netip.AddrPort) (*Node, error) {
|
func Create(addr netip.AddrPort) (*Node, error) {
|
||||||
if !addr.IsValid() {
|
if !addr.IsValid() {
|
||||||
|
5
go.mod
5
go.mod
@ -2,4 +2,7 @@ module git.sunturtle.xyz/zephyr/chord
|
|||||||
|
|
||||||
go 1.24.1
|
go 1.24.1
|
||||||
|
|
||||||
require github.com/urfave/cli/v3 v3.0.0-beta1
|
require (
|
||||||
|
github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874
|
||||||
|
github.com/urfave/cli/v3 v3.0.0-beta1
|
||||||
|
)
|
||||||
|
2
go.sum
2
go.sum
@ -1,5 +1,7 @@
|
|||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874 h1:F8d1AJ6M9UQCavhwmO6ZsrYLfG8zVFWfEfMS2MXPkSY=
|
||||||
|
github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874/go.mod h1:TiCD2a1pcmjd7YnhGH0f/zKNcCD06B029pHhzV23c2M=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
|
Loading…
Reference in New Issue
Block a user