-
Notifications
You must be signed in to change notification settings - Fork 6
/
store.go
97 lines (80 loc) · 1.81 KB
/
store.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package statestore
import (
"bytes"
"context"
"fmt"
"reflect"
cborutil "github.com/filecoin-project/go-cbor-util"
"github.com/ipfs/go-datastore"
"github.com/ipfs/go-datastore/query"
"go.uber.org/multierr"
"golang.org/x/xerrors"
)
type StateStore struct {
ds datastore.Datastore
}
func New(ds datastore.Datastore) *StateStore {
return &StateStore{ds: ds}
}
func ToKey(k interface{}) datastore.Key {
switch t := k.(type) {
case uint64:
return datastore.NewKey(fmt.Sprint(t))
case fmt.Stringer:
return datastore.NewKey(t.String())
default:
panic("unexpected key type")
}
}
func (st *StateStore) Begin(i interface{}, state interface{}) error {
k := ToKey(i)
has, err := st.ds.Has(context.TODO(), k)
if err != nil {
return err
}
if has {
return xerrors.Errorf("already tracking state for %v", i)
}
b, err := cborutil.Dump(state)
if err != nil {
return err
}
return st.ds.Put(context.TODO(), k, b)
}
func (st *StateStore) Get(i interface{}) *StoredState {
return &StoredState{
ds: st.ds,
name: ToKey(i),
}
}
func (st *StateStore) Has(i interface{}) (bool, error) {
return st.ds.Has(context.TODO(), ToKey(i))
}
// out: *[]T
func (st *StateStore) List(out interface{}) error {
res, err := st.ds.Query(context.TODO(), query.Query{})
if err != nil {
return err
}
defer res.Close()
outT := reflect.TypeOf(out).Elem().Elem()
rout := reflect.ValueOf(out)
var errs error
for {
res, ok := res.NextSync()
if !ok {
break
}
if res.Error != nil {
return res.Error
}
elem := reflect.New(outT)
err := cborutil.ReadCborRPC(bytes.NewReader(res.Value), elem.Interface())
if err != nil {
errs = multierr.Append(errs, xerrors.Errorf("decoding state for key '%s': %w", res.Key, err))
continue
}
rout.Elem().Set(reflect.Append(rout.Elem(), elem.Elem()))
}
return errs
}