Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 47 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,52 @@
# mökv
<!-- markdownlint-disable MD033 MD041 -->
<div align='center'>
<img src="mokv.png" alt="mokv logo"/>
<br />
<br />

`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.
</div>

<!-- markdownlint-enable MD033 MD041 -->

## Example

<!-- markdownlint-disable MD010 -->

```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)
}
```

<!-- markdownlint-enable MD010 -->

## 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

Expand Down
Binary file added mokv.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
75 changes: 75 additions & 0 deletions mokv/client.go
Original file line number Diff line number Diff line change
@@ -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()
}