diff --git a/README.md b/README.md index 464f9d7..5e8999f 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,52 @@ -# mökv + +
+mokv logo +
+
-`mökv` is a distributed, in-memory key-value store built with [`Raft`](https://github.com/hashicorp/raft) for consensus, [`Serf`](https://github.com/hashicorp/serf) for discovery, and [`gRPC`](https://github.com/grpc/grpc-go) for communication. +[![License](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +[![Tests](https://github.com/sinclairzx81/typedriver/actions/workflows/build.yml/badge.svg)](https://github.com/dynamic-calm/mokv/actions/workflows/test.yml) -Built it following the book [Distributed Services with Go](https://pragprog.com/titles/tjgo/distributed-services-with-go/) by Travis Jeffery. +
+ + + +## Example + + + +```go +package main + +import ( + "context" + + "github.com/dynamic-calm/mokv/mokv" +) + +func main() { + client, _ := mokv.NewClient("localhost:8400") + defer client.Close() + + ctx := context.Background() + + key := `59°19'14.7"N` + val := []byte(`18°03'39.0"E`) + + client.Set(ctx, key, val) + client.Get(ctx, key) + client.Delete(ctx, key) + client.GetServers(ctx) +} +``` + + + +## Overview + +mökv is a distributed key-value store built with [Raft](https://github.com/hashicorp/raft) for consensus, [Serf](https://github.com/hashicorp/serf) for discovery, and [gRPC](https://github.com/grpc/grpc-go) for communication. + +Built following the book [Distributed Services with Go](https://pragprog.com/titles/tjgo/distributed-services-with-go/) by Travis Jeffery. ## Features diff --git a/mokv.png b/mokv.png new file mode 100644 index 0000000..7101c0f Binary files /dev/null and b/mokv.png differ diff --git a/mokv/client.go b/mokv/client.go new file mode 100644 index 0000000..9f97d89 --- /dev/null +++ b/mokv/client.go @@ -0,0 +1,75 @@ +package mokv + +import ( + "context" + + "github.com/dynamic-calm/mokv/api" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/protobuf/types/known/emptypb" +) + +// Client provides access to a mökv cluster. +type Client struct { + conn *grpc.ClientConn + api api.KVClient +} + +// Server represents a node in the cluster. +type Server struct { + RpcAddr string + IsLeader bool + ID string +} + +// NewClient connects to a mökv node at the given address. +func NewClient(addr string) (*Client, error) { + conn, err := grpc.NewClient(addr, + grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + return nil, err + } + return &Client{ + conn: conn, + api: api.NewKVClient(conn), + }, nil +} + +// Get retrieves a value by key. Returns nil if the key does not exist. +func (c *Client) Get(ctx context.Context, key string) ([]byte, error) { + res, err := c.api.Get(ctx, &api.GetRequest{Key: key}) + if err != nil { + return nil, err + } + return res.Value, nil +} + +// Set stores a key-value pair, replicating it across the cluster. +func (c *Client) Set(ctx context.Context, key string, value []byte) (bool, error) { + res, err := c.api.Set(ctx, &api.SetRequest{Key: key, Value: value}) + return res.Ok, err +} + +// Delete removes a key from the cluster. +func (c *Client) Delete(ctx context.Context, key string) (bool, error) { + res, err := c.api.Delete(ctx, &api.DeleteRequest{Key: key}) + return res.Ok, err +} + +// GetServers returns all nodes in the cluster. +func (c *Client) GetServers(ctx context.Context) ([]Server, error) { + res, err := c.api.GetServers(ctx, &emptypb.Empty{}) + if err != nil { + return nil, err + } + servers := make([]Server, len(res.Servers)) + for i, s := range res.Servers { + servers[i] = Server{RpcAddr: s.RpcAddr, IsLeader: s.IsLeader, ID: s.Id} + } + return servers, nil +} + +// Close releases the underlying connection. +func (c *Client) Close() error { + return c.conn.Close() +}