commit 2c650804fd9825f4e288c7c460061bae048e3f9e Author: Branden J Brown Date: Thu Mar 6 10:14:58 2025 -0500 initial commit diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..5ad7787 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module git.sunturtle.xyz/zephyr/chord + +go 1.24.1 + +require github.com/urfave/cli/v3 v3.0.0-beta1 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..ebc8bbd --- /dev/null +++ b/go.sum @@ -0,0 +1,10 @@ +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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +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/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/urfave/cli/v3 v3.0.0-beta1 h1:6DTaaUarcM0wX7qj5Hcvs+5Dm3dyUTBbEwIWAjcw9Zg= +github.com/urfave/cli/v3 v3.0.0-beta1/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go new file mode 100644 index 0000000..bb3e187 --- /dev/null +++ b/main.go @@ -0,0 +1,127 @@ +package main + +import ( + "context" + "errors" + "fmt" + "os" + "os/signal" + + "github.com/urfave/cli/v3" +) + +var app = cli.Command{ + Name: "chord", + Usage: "Distributed hash table using the Chord protocol", + + Commands: []*cli.Command{ + { + Name: "join", + Aliases: []string{"init", "initialize"}, + Usage: "Join or initialize a Chord network.", + Flags: []cli.Flag{ + flagIP, + flagPort, + &cli.StringFlag{ + Name: "c", + Usage: "Address of an existing node to join.", + }, + }, + Action: cliJoin, + }, + { + Name: "leave", + Usage: "Instruct a node to leave the network.", + Flags: []cli.Flag{ + flagIP, + flagPort, + &cli.StringFlag{ + Name: "n", + Usage: "Node to leave.", + Required: true, + }, + }, + Action: cliLeave, + }, + { + Name: "lookup", + Usage: "Find the node responsible for a key.", + Flags: []cli.Flag{ + flagKey, + flagNode, + flagLocal, + }, + Action: cliLookup, + }, + { + Name: "put", + Aliases: []string{"store", "set"}, + Usage: "Set a value in the network.", + Flags: []cli.Flag{ + flagKey, + &cli.StringFlag{ + Name: "v", + Usage: "Value to set.", + Required: true, + }, + flagNode, + flagLocal, + }, + Action: cliPut, + }, + { + Name: "get", + Aliases: []string{"load"}, + Usage: "Get a value in the network.", + Flags: []cli.Flag{ + flagKey, + flagNode, + flagLocal, + }, + Action: cliGet, + }, + }, +} + +var ( + flagIP = &cli.StringFlag{ + Name: "ip", + Usage: "IP to bind. May include port.", + Value: "127.0.0.1:3000", + } + flagPort = &cli.UintFlag{ + Name: "p", + Usage: "Port to bind. Overrides port in -ip if given.", + } + flagNode = &cli.StringFlag{ + Name: "n", + Usage: "Address of any node in the network.", + Required: true, + } + flagKey = &cli.StringFlag{ + Name: "k", + Usage: "Key to operate on.", + Required: true, + } + flagLocal = &cli.BoolFlag{ + Name: "l", + Usage: "Stop if the key is not local to the node.", + } +) + +func cliJoin(ctx context.Context, cmd *cli.Command) error { return errors.New("not implemented") } +func cliLeave(ctx context.Context, cmd *cli.Command) error { return errors.New("not implemented") } +func cliLookup(ctx context.Context, cmd *cli.Command) error { return errors.New("not implemented") } +func cliPut(ctx context.Context, cmd *cli.Command) error { return errors.New("not implemented") } +func cliGet(ctx context.Context, cmd *cli.Command) error { return errors.New("not implemented") } + +func main() { + ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt) + go func() { + <-ctx.Done() + stop() + }() + if err := app.Run(ctx, os.Args); err != nil { + fmt.Fprintln(os.Stderr, err) + } +}