This commit is contained in:
+55
-39
@@ -9,6 +9,7 @@ import (
|
||||
"errors"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"forge.redroom.link/yves/meowlib"
|
||||
"github.com/dgraph-io/badger"
|
||||
@@ -17,11 +18,12 @@ import (
|
||||
|
||||
type PeerStorage struct {
|
||||
DbFile string `json:"db_file,omitempty"`
|
||||
mu sync.RWMutex
|
||||
db *badger.DB
|
||||
cache map[string]*Peer
|
||||
}
|
||||
|
||||
// Open the badger database from struct PeerStorage
|
||||
// open opens the Badger database. Caller must hold mu (write).
|
||||
func (ps *PeerStorage) open() error {
|
||||
if ps.DbFile == "" {
|
||||
ps.DbFile = uuid.New().String()
|
||||
@@ -34,20 +36,27 @@ func (ps *PeerStorage) open() error {
|
||||
opts.Logger = nil
|
||||
var err error
|
||||
ps.db, err = badger.Open(opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
// Store function StorePeer stores a peer in the badger database with Peer.Uid as key
|
||||
// close closes the Badger database. Caller must hold mu (write).
|
||||
func (ps *PeerStorage) close() {
|
||||
ps.db.Close()
|
||||
}
|
||||
|
||||
// StorePeer stores a peer in the Badger database with Peer.Uid as key.
|
||||
func (ps *PeerStorage) StorePeer(peer *Peer) error {
|
||||
err := ps.open()
|
||||
if err != nil {
|
||||
ps.mu.Lock()
|
||||
defer ps.mu.Unlock()
|
||||
return ps.storePeerLocked(peer)
|
||||
}
|
||||
|
||||
// storePeerLocked is StorePeer without acquiring the lock. Caller must hold mu (write).
|
||||
func (ps *PeerStorage) storePeerLocked(peer *Peer) error {
|
||||
if err := ps.open(); err != nil {
|
||||
return err
|
||||
}
|
||||
defer ps.close()
|
||||
// first marshal the Peer to bytes with protobuf
|
||||
jsonsrv, err := json.Marshal(peer)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -65,26 +74,24 @@ func (ps *PeerStorage) StorePeer(peer *Peer) error {
|
||||
}
|
||||
shakey := sha256.Sum256([]byte(peer.Uid))
|
||||
key := shakey[:]
|
||||
// add it to cache
|
||||
ps.cache[peer.Uid] = peer
|
||||
// then store it in the database
|
||||
return ps.db.Update(func(txn *badger.Txn) error {
|
||||
return txn.Set(key, data)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
// LoadPeer function loads a Peer from the badger database with Peer.GetUid() as key
|
||||
// LoadPeer loads a Peer from the Badger database with Peer.GetUid() as key.
|
||||
func (ps *PeerStorage) LoadPeer(uid string, password string) (*Peer, error) {
|
||||
ps.mu.Lock()
|
||||
defer ps.mu.Unlock()
|
||||
var peer Peer
|
||||
err := ps.open()
|
||||
if err != nil {
|
||||
if err := ps.open(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer ps.close()
|
||||
shakey := sha256.Sum256([]byte(uid))
|
||||
key := shakey[:]
|
||||
err = ps.db.View(func(txn *badger.Txn) error {
|
||||
err := ps.db.View(func(txn *badger.Txn) error {
|
||||
item, err := txn.Get(key)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -100,16 +107,17 @@ func (ps *PeerStorage) LoadPeer(uid string, password string) (*Peer, error) {
|
||||
return &peer, err
|
||||
}
|
||||
|
||||
// DeletePeer function deletes a Peer from the badger database with Peer.GetUid() as key
|
||||
// DeletePeer deletes a Peer from the Badger database with Peer.GetUid() as key.
|
||||
func (ps *PeerStorage) DeletePeer(uid string) error {
|
||||
err := ps.open()
|
||||
if err != nil {
|
||||
ps.mu.Lock()
|
||||
defer ps.mu.Unlock()
|
||||
if err := ps.open(); err != nil {
|
||||
return err
|
||||
}
|
||||
defer ps.close()
|
||||
shakey := sha256.Sum256([]byte(uid))
|
||||
key := shakey[:]
|
||||
err = ps.db.Update(func(txn *badger.Txn) error {
|
||||
err := ps.db.Update(func(txn *badger.Txn) error {
|
||||
return txn.Delete(key)
|
||||
})
|
||||
if err == nil {
|
||||
@@ -118,15 +126,16 @@ func (ps *PeerStorage) DeletePeer(uid string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// LoadPeers function loads Peers from the badger database with a specific password
|
||||
// LoadPeers loads all Peers from the Badger database and populates the cache.
|
||||
func (ps *PeerStorage) LoadPeers(password string) ([]*Peer, error) {
|
||||
ps.mu.Lock()
|
||||
defer ps.mu.Unlock()
|
||||
var peers []*Peer
|
||||
err := ps.open()
|
||||
if err != nil {
|
||||
if err := ps.open(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer ps.close()
|
||||
err = ps.db.View(func(txn *badger.Txn) error {
|
||||
err := ps.db.View(func(txn *badger.Txn) error {
|
||||
opts := badger.DefaultIteratorOptions
|
||||
opts.PrefetchSize = 10
|
||||
it := txn.NewIterator(opts)
|
||||
@@ -148,32 +157,29 @@ func (ps *PeerStorage) LoadPeers(password string) ([]*Peer, error) {
|
||||
}
|
||||
return nil
|
||||
})
|
||||
// Sort peers based on peer.Name
|
||||
sort.Slice(peers, func(i, j int) bool {
|
||||
return peers[i].Name < peers[j].Name
|
||||
})
|
||||
return peers, err
|
||||
}
|
||||
|
||||
// GetPeers function returns all peers from the cache as a sorted array
|
||||
// GetPeers returns all peers from the cache as a sorted slice.
|
||||
func (ps *PeerStorage) GetPeers() ([]*Peer, error) {
|
||||
ps.mu.RLock()
|
||||
defer ps.mu.RUnlock()
|
||||
peers := make([]*Peer, 0, len(ps.cache))
|
||||
for _, peer := range ps.cache {
|
||||
peers = append(peers, peer)
|
||||
}
|
||||
// Sort peers based on peer.Name
|
||||
sort.Slice(peers, func(i, j int) bool {
|
||||
return peers[i].Name < peers[j].Name
|
||||
})
|
||||
return peers, nil
|
||||
}
|
||||
|
||||
// close the badger database
|
||||
func (ps *PeerStorage) close() {
|
||||
ps.db.Close()
|
||||
}
|
||||
|
||||
func (ps *PeerStorage) GetFromPublicKey(publickey string) *Peer {
|
||||
ps.mu.RLock()
|
||||
defer ps.mu.RUnlock()
|
||||
for _, peer := range ps.cache {
|
||||
if peer.ContactPublicKey == publickey {
|
||||
return peer
|
||||
@@ -183,6 +189,8 @@ func (ps *PeerStorage) GetFromPublicKey(publickey string) *Peer {
|
||||
}
|
||||
|
||||
func (ps *PeerStorage) GetFromInvitationId(invitationId string) *Peer {
|
||||
ps.mu.RLock()
|
||||
defer ps.mu.RUnlock()
|
||||
for _, peer := range ps.cache {
|
||||
if peer.InvitationId == invitationId {
|
||||
return peer
|
||||
@@ -192,6 +200,8 @@ func (ps *PeerStorage) GetFromInvitationId(invitationId string) *Peer {
|
||||
}
|
||||
|
||||
func (ps *PeerStorage) GetFromMyLookupKey(publickey string) *Peer {
|
||||
ps.mu.RLock()
|
||||
defer ps.mu.RUnlock()
|
||||
for _, peer := range ps.cache {
|
||||
if peer.MyLookupKp.Public == publickey {
|
||||
return peer
|
||||
@@ -201,6 +211,8 @@ func (ps *PeerStorage) GetFromMyLookupKey(publickey string) *Peer {
|
||||
}
|
||||
|
||||
func (ps *PeerStorage) NameExists(name string) bool {
|
||||
ps.mu.RLock()
|
||||
defer ps.mu.RUnlock()
|
||||
for _, peer := range ps.cache {
|
||||
if peer.Name == name {
|
||||
return true
|
||||
@@ -210,6 +222,8 @@ func (ps *PeerStorage) NameExists(name string) bool {
|
||||
}
|
||||
|
||||
func (ps *PeerStorage) GetFromName(name string) *Peer {
|
||||
ps.mu.RLock()
|
||||
defer ps.mu.RUnlock()
|
||||
for _, peer := range ps.cache {
|
||||
if peer.Name == name {
|
||||
return peer
|
||||
@@ -219,26 +233,29 @@ func (ps *PeerStorage) GetFromName(name string) *Peer {
|
||||
}
|
||||
|
||||
func (ps *PeerStorage) GetFromUid(uid string) *Peer {
|
||||
ps.mu.RLock()
|
||||
defer ps.mu.RUnlock()
|
||||
return ps.cache[uid]
|
||||
}
|
||||
|
||||
// Checks if the received contact card is an answer to an invitation, returns true if it is, and the proposed and received nicknames
|
||||
// CheckInvitation checks if the received contact card is an answer to an invitation.
|
||||
func (ps *PeerStorage) CheckInvitation(ReceivedContact *meowlib.ContactCard) (isAnswer bool, proposedNick string, receivedNick string, invitationMessage string) {
|
||||
// invitation Id found, this is an answer to an invitation
|
||||
ps.mu.RLock()
|
||||
defer ps.mu.RUnlock()
|
||||
for _, p := range ps.cache {
|
||||
if p.InvitationId == ReceivedContact.InvitationId {
|
||||
return true, p.Name, ReceivedContact.Name, ReceivedContact.InvitationMessage
|
||||
}
|
||||
}
|
||||
// it's an invitation
|
||||
return false, "", ReceivedContact.Name, ReceivedContact.InvitationMessage
|
||||
}
|
||||
|
||||
// Finalizes an invitation, returns nil if successful
|
||||
// FinalizeInvitation completes an invitation handshake and persists the updated peer.
|
||||
func (ps *PeerStorage) FinalizeInvitation(ReceivedContact *meowlib.ContactCard) error {
|
||||
ps.mu.Lock()
|
||||
defer ps.mu.Unlock()
|
||||
for i, p := range ps.cache {
|
||||
if p.InvitationId == ReceivedContact.InvitationId {
|
||||
//id.Peers[i].Name = ReceivedContact.Name
|
||||
ps.cache[i].ContactEncryption = ReceivedContact.EncryptionPublicKey
|
||||
ps.cache[i].ContactLookupKey = ReceivedContact.LookupPublicKey
|
||||
ps.cache[i].ContactPublicKey = ReceivedContact.ContactPublicKey
|
||||
@@ -250,8 +267,7 @@ func (ps *PeerStorage) FinalizeInvitation(ReceivedContact *meowlib.ContactCard)
|
||||
srvs = append(srvs, ReceivedContact.PullServers[srv].GetUid())
|
||||
}
|
||||
ps.cache[i].ContactPullServers = srvs
|
||||
ps.StorePeer(ps.cache[i])
|
||||
return nil
|
||||
return ps.storePeerLocked(ps.cache[i])
|
||||
}
|
||||
}
|
||||
return errors.New("no matching contact found for invitationId " + ReceivedContact.InvitationId)
|
||||
|
||||
Reference in New Issue
Block a user