Esgopeta is a Go implementation of the Gun distributed graph database. See the Godoc for API details.
WARNING: This is an early proof-of-concept alpha version. Many pieces are not implemented or don't work.
Features:
- Client for reading and writing w/ rudimentary conflict resolution
- In-memory storage
Not yet implemented:
- Server
- Alternative storage methods
- SEA (i.e. encryption/auth)
The package is github.com/cretz/esgopeta/gun
which can be fetched via go get
. To listen to database changes for a
value, use Fetch
. The example below listens for updates on a key for a minute:
package main
import (
"context"
"log"
"time"
"github.com/cretz/esgopeta/gun"
)
func main() {
// Let's listen for a minute
ctx, cancelFn := context.WithTimeout(context.Background(), 1*time.Minute)
defer cancelFn()
// Create the Gun client connecting to common Gun server
g, err := gun.New(ctx, gun.Config{
PeerURLs: []string{"https://gunjs.herokuapp.com/gun"},
PeerErrorHandler: func(err *gun.ErrPeer) { log.Print(err) },
})
if err != nil {
log.Panic(err)
}
defer g.Close()
// Issue a fetch and get a channel for updates
fetchCh := g.Scoped(ctx, "esgopeta-example", "sample-key").Fetch(ctx)
// Log all updates and exit when context times out
log.Print("Waiting for value")
for {
select {
case <-ctx.Done():
log.Print("Time's up")
return
case fetchResult := <-fetchCh:
if fetchResult.Err != nil {
log.Printf("Error fetching: %v", fetchResult.Err)
} else if fetchResult.ValueExists {
log.Printf("Got value: %v", fetchResult.Value)
}
}
}
}
When that's running, we can send values via a Put
. The example below sends two updates for that key:
package main
import (
"context"
"log"
"time"
"github.com/cretz/esgopeta/gun"
)
func main() {
// Give a 1 minute timeout, but shouldn't get hit
ctx, cancelFn := context.WithTimeout(context.Background(), 1*time.Minute)
defer cancelFn()
// Create the Gun client connecting to common Gun server
g, err := gun.New(ctx, gun.Config{
PeerURLs: []string{"https://gunjs.herokuapp.com/gun"},
PeerErrorHandler: func(err *gun.ErrPeer) { log.Print(err) },
})
if err != nil {
log.Panic(err)
}
defer g.Close()
// Issue a simple put and wait for a single peer ack
putScope := g.Scoped(ctx, "esgopeta-example", "sample-key")
log.Print("Sending first value")
putCh := putScope.Put(ctx, gun.ValueString("first value"))
for {
if result := <-putCh; result.Err != nil {
log.Printf("Error putting: %v", result.Err)
} else if result.Peer != nil {
log.Printf("Got ack from %v", result.Peer)
break
}
}
// Let's send another value
log.Print("Sending second value")
putCh = putScope.Put(ctx, gun.ValueString("second value"))
for {
if result := <-putCh; result.Err != nil {
log.Printf("Error putting: %v", result.Err)
} else if result.Peer != nil {
log.Printf("Got ack from %v", result.Peer)
break
}
}
}
Note, these are just examples and you may want to control the lifetime of the channels better. See the Godoc for more information.