uBrowserSync/bsync/store.go

114 lines
2.2 KiB
Go

package bsync
import (
"crypto/rand"
"encoding/hex"
"fmt"
"sync"
"time"
)
type StoreDriver interface {
RawSave(s *Blob) error
RawLoad(id string) (*Blob, error)
Exists(id string) bool
Count() int
}
type Store struct {
drv StoreDriver
lock sync.Mutex
}
func NewStore(drv StoreDriver) Store {
return Store{drv: drv}
}
func (store *Store) Create(version string) (*CreateResp, error) {
var sid string
store.lock.Lock()
defer store.lock.Unlock()
failed := true
for i := 0; i < 5; i++ {
var idb = make([]byte, 16)
var ids = make([]byte, 32)
_, err := rand.Read(idb)
if err != nil {
return nil, err
}
hex.Encode(ids, idb)
sid = string(ids[:])
if !store.drv.Exists(sid) {
failed = false
break
}
}
if failed {
return nil, fmt.Errorf("cannot generate unique sync ID")
}
s := new(Blob)
s.ID = sid
s.Version = version
s.Created = time.Now().UTC()
s.LastUpdated = s.Created
s.LastAccessed = s.Created
return &CreateResp{
ID: s.ID,
LastUpdated: s.LastUpdated,
Version: s.Version}, store.drv.RawSave(s)
}
func (store *Store) Update(id string, bookmarks string, lastUpdated time.Time) (time.Time, error) {
store.lock.Lock()
defer store.lock.Unlock()
t, err := store.drv.RawLoad(id)
if err != nil {
return time.Time{}, err
}
if !lastUpdated.IsZero() {
if !t.LastUpdated.Equal(lastUpdated) {
return time.Time{}, SyncConflictError
}
}
t.ID = id
t.Bookmarks = bookmarks
t.LastUpdated = time.Now().UTC()
t.LastAccessed = t.LastUpdated
return t.LastUpdated, store.drv.RawSave(t)
}
func (store *Store) Get(id string) (*GetResp, error) {
store.lock.Lock()
defer store.lock.Unlock()
s, err := store.drv.RawLoad(id)
if err != nil {
return nil, err
}
s.ID = id
s.LastAccessed = time.Now().UTC()
return &GetResp{
Version: s.Version,
Bookmarks: s.Bookmarks,
LastUpdated: s.LastUpdated}, store.drv.RawSave(s)
}
func (store *Store) GetLastUpdated(id string) (time.Time, error) {
r, err := store.Get(id)
if err != nil {
return time.Time{}, err
}
return r.LastUpdated, nil
}
func (store *Store) GetVersion(id string) (string, error) {
r, err := store.Get(id)
if err != nil {
return "", err
}
return r.Version, nil
}
func (store *Store) Count() int {
return store.drv.Count()
}