/
store.go
133 lines (110 loc) · 2.7 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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package libp2p
import (
"fmt"
"net/url"
"sync"
"redwood.dev/errors"
"redwood.dev/log"
"redwood.dev/state"
"redwood.dev/types"
)
//go:generate mockery --name Store --output ./mocks/ --case=underscore
type Store interface {
StaticRelays() PeerSet
AddStaticRelay(relayAddr string) error
RemoveStaticRelay(relayAddr string) error
DebugPrint()
}
type store struct {
log.Logger
db *state.DBTree
data storeData
dataMu sync.RWMutex
}
type storeData struct {
StaticRelays PeerSet
}
type storeDataCodec struct {
StaticRelays types.Set[string] `tree:"staticRelays"`
}
func NewStore(db *state.DBTree) (*store, error) {
s := &store{
Logger: log.NewLogger("libp2p store"),
db: db,
}
s.Infof(0, "opening libp2p store")
err := s.loadData()
return s, err
}
func (s *store) loadData() error {
node := s.db.State(false)
defer node.Close()
var codec storeDataCodec
err := node.NodeAt(storeRootKeypath, nil).Scan(&codec)
if errors.Cause(err) == errors.Err404 {
// do nothing
} else if err != nil {
return err
}
var decoded []string
for staticRelayEncoded := range codec.StaticRelays {
staticRelay, err := url.QueryUnescape(staticRelayEncoded)
if err != nil {
s.Errorf("could not unescape static relay '%v'", staticRelayEncoded)
continue
}
decoded = append(decoded, staticRelay)
}
s.data.StaticRelays, err = NewPeerSetFromStrings(decoded)
if err != nil {
return err
}
return nil
}
func (s *store) StaticRelays() PeerSet {
// s.dataMu.RLock()
// defer s.dataMu.RUnlock()
return s.data.StaticRelays
}
func (s *store) AddStaticRelay(staticRelay string) error {
// s.dataMu.Lock()
// defer s.dataMu.Unlock()
err := s.data.StaticRelays.AddString(staticRelay)
if err != nil {
return err
}
node := s.db.State(true)
defer node.Close()
err = node.Set(s.keypathForStaticRelay(staticRelay), nil, true)
if err != nil {
return err
}
return node.Save()
}
func (s *store) RemoveStaticRelay(staticRelay string) error {
// s.dataMu.Lock()
// defer s.dataMu.Unlock()
err := s.data.StaticRelays.RemoveString(staticRelay)
if err != nil {
return err
}
node := s.db.State(true)
defer node.Close()
err = node.Delete(s.keypathForStaticRelay(staticRelay), nil)
if err != nil {
return err
}
return node.Save()
}
var (
storeRootKeypath = state.Keypath("libp2p")
staticRelaysKeypath = storeRootKeypath.Copy().Pushs("staticRelays")
)
func (s *store) keypathForStaticRelay(staticRelay string) state.Keypath {
return staticRelaysKeypath.Copy().Pushs(url.QueryEscape(staticRelay))
}
func (s *store) DebugPrint() {
node := s.db.State(false)
defer node.Close()
node.NodeAt(storeRootKeypath, nil).DebugPrint(func(msg string, args ...interface{}) { fmt.Printf(msg, args...) }, true, 0)
}