198 lines
5.2 KiB
Go
198 lines
5.2 KiB
Go
package storage
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"encoding/json"
|
|
"git.timovolkmann.de/gyrogpsc/core"
|
|
"github.com/dgraph-io/badger/v2"
|
|
"github.com/google/uuid"
|
|
"github.com/sirupsen/logrus"
|
|
"os"
|
|
"path/filepath"
|
|
)
|
|
|
|
// Must implement Repo
|
|
type badgerStore struct {
|
|
trackings *badger.DB
|
|
records *badger.DB
|
|
rawdata *badger.DB
|
|
}
|
|
|
|
func NewRepository(c *core.Configuration) *badgerStore {
|
|
dir, _ := os.Getwd()
|
|
logrus.Debug(dir)
|
|
if _, err := os.Stat(filepath.Join(dir,"_db")); os.IsNotExist(err) {
|
|
os.Mkdir(filepath.Join(dir,"_db"), os.ModePerm)
|
|
}
|
|
|
|
tr, err := badger.Open(badger.DefaultOptions("_db/trackings"))
|
|
dp, err := badger.Open(badger.DefaultOptions("_db/records"))
|
|
rd, err := badger.Open(badger.DefaultOptions("_db/raw"))
|
|
|
|
if err != nil {
|
|
logrus.Error(err)
|
|
}
|
|
return &badgerStore{trackings: tr, records: dp, rawdata: rd}
|
|
}
|
|
|
|
func (r *badgerStore) isDbAvailable() bool {
|
|
return r.trackings.IsClosed() || r.records.IsClosed() || r.rawdata.IsClosed()
|
|
}
|
|
|
|
func (r *badgerStore) Save(tr core.Tracking) error {
|
|
if ok := r.isDbAvailable(); ok {
|
|
logrus.Error("unable to write to database. database closed!")
|
|
return badger.ErrDBClosed
|
|
}
|
|
ts, err := tr.TimeCreated.MarshalText()
|
|
if err != nil {
|
|
logrus.Error(err, tr)
|
|
}
|
|
logrus.Info("save tracking:", tr.TimeCreated)
|
|
meta, err := json.Marshal(tr.TrackingMetadata)
|
|
if err != nil {
|
|
logrus.Error(err, tr)
|
|
return err
|
|
}
|
|
err = r.records.Update(func(txn *badger.Txn) error {
|
|
for _, v := range tr.Records {
|
|
k := createDataKey(tr.UUID, v.RecordTime.UnixNano())
|
|
j, err := json.Marshal(v)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
txn.Set(k, j)
|
|
}
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
logrus.Error(err, tr)
|
|
return err
|
|
}
|
|
err = r.records.Update(func(txn *badger.Txn) error {
|
|
for _, v := range tr.Rawdata {
|
|
k := createDataKey(tr.UUID, v.Timestamp)
|
|
j, err := json.Marshal(v)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
txn.Set(k, j)
|
|
}
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
logrus.Error(err, tr)
|
|
return err
|
|
}
|
|
err = r.trackings.Update(func(txn *badger.Txn) error {
|
|
err := txn.Set(ts, meta)
|
|
return err
|
|
})
|
|
if err != nil {
|
|
logrus.Error(err, tr)
|
|
return err
|
|
}
|
|
logrus.Info("sucessfully saved tracking")
|
|
return nil
|
|
}
|
|
|
|
//func (r *badgerStore) Save(tracking *core.Tracking) error {
|
|
// ts, err := tracking.TimeCreated.MarshalText()
|
|
// if err != nil {
|
|
// logrus.Error(err, tracking)
|
|
// }
|
|
// logrus.Info("save tracking:", ts)
|
|
// meta, err := json.Marshal(tracking.TrackingMetadata)
|
|
// if err != nil {
|
|
// logrus.Error(err, tracking)
|
|
// return err
|
|
// }
|
|
// wg := sync.WaitGroup{}
|
|
// wg.Add(3)
|
|
// ch := make(chan error, 3)
|
|
// go func() {
|
|
// defer wg.Done()
|
|
// err = r.records.Update(func(txn *badger.Txn) error {
|
|
// for _, v := range tracking.Records {
|
|
// k := createDataKey(tracking.UUID, v.RecordTime.UnixNano())
|
|
// j, err := json.Marshal(v)
|
|
// if err != nil {
|
|
// return err
|
|
// }
|
|
// txn.Set(k, j)
|
|
// }
|
|
// return nil
|
|
// })
|
|
// ch <- err
|
|
// }()
|
|
// go func() {
|
|
// defer wg.Done()
|
|
// err = r.records.Update(func(txn *badger.Txn) error {
|
|
// for _, v := range tracking.Rawdata {
|
|
// k := createDataKey(tracking.UUID, v.Timestamp)
|
|
// j, err := json.Marshal(v)
|
|
// if err != nil {
|
|
// return err
|
|
// }
|
|
// txn.Set(k, j)
|
|
// }
|
|
// return nil
|
|
// })
|
|
// ch <- err
|
|
// }()
|
|
// go func() {
|
|
// defer wg.Done()
|
|
// err = r.trackings.Update(func(txn *badger.Txn) error {
|
|
// err := txn.Set(ts, meta)
|
|
// return err
|
|
// })
|
|
// ch <- err
|
|
// }()
|
|
// wg.Wait()
|
|
// for {
|
|
// select {
|
|
// case err := <-ch:
|
|
// if err != nil {
|
|
// logrus.Error(err, tracking)
|
|
// return err
|
|
// }
|
|
// default:
|
|
// close(ch)
|
|
// break
|
|
// }
|
|
// }
|
|
// return nil
|
|
//}
|
|
|
|
func (r *badgerStore) LoadAll() ([]core.TrackingMetadata, error) {
|
|
panic("implement me")
|
|
}
|
|
|
|
func (r *badgerStore) Load(id uuid.UUID) (core.Tracking, error) {
|
|
panic("implement me")
|
|
}
|
|
|
|
func createDataKey(uid uuid.UUID, timestamp int64) []byte {
|
|
prefix, err := uid.MarshalText()
|
|
if err != nil || timestamp < 0 {
|
|
logrus.Error("unable to create key", err)
|
|
}
|
|
suffix := make([]byte, 8)
|
|
binary.LittleEndian.PutUint64(suffix, uint64(timestamp))
|
|
return append(prefix, suffix...)
|
|
}
|
|
|
|
func unmarshalDataKey(key []byte) (uuid.UUID, int64) {
|
|
if len(key) != 24 {
|
|
panic("corrupted key")
|
|
}
|
|
prefix := key[0:15]
|
|
suffix := key[15:24]
|
|
uid, err := uuid.FromBytes(prefix)
|
|
if err != nil {
|
|
panic("corrupted key")
|
|
}
|
|
timestamp := int64(binary.LittleEndian.Uint64(suffix))
|
|
return uid, timestamp
|
|
}
|