2022-04-14 16:32:39 +00:00
|
|
|
package models
|
2015-05-18 14:47:08 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"strings"
|
2015-09-17 16:49:57 +00:00
|
|
|
|
2022-04-14 16:32:39 +00:00
|
|
|
"git.bullercodeworks.com/brian/boltbrowser/util"
|
|
|
|
bolt "go.etcd.io/bbolt"
|
2015-05-18 14:47:08 +00:00
|
|
|
)
|
|
|
|
|
2015-09-17 16:49:57 +00:00
|
|
|
/*
|
|
|
|
BoltDB A Database, basically a collection of buckets
|
|
|
|
*/
|
2015-05-18 14:47:08 +00:00
|
|
|
type BoltDB struct {
|
2022-04-14 16:32:39 +00:00
|
|
|
db *bolt.DB
|
2015-05-18 14:47:08 +00:00
|
|
|
buckets []BoltBucket
|
|
|
|
}
|
|
|
|
|
2022-04-20 21:22:43 +00:00
|
|
|
func NewBoltDB(db *bolt.DB) *BoltDB {
|
|
|
|
b := &BoltDB{db: db}
|
|
|
|
b.RefreshDatabase()
|
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
2022-04-14 16:32:39 +00:00
|
|
|
func (bd *BoltDB) RefreshDatabase() {
|
|
|
|
// Reload the database from the file
|
|
|
|
bd.buckets = []BoltBucket{}
|
|
|
|
bd.db.View(func(tx *bolt.Tx) error {
|
|
|
|
err := tx.ForEach(func(nm []byte, b *bolt.Bucket) error {
|
|
|
|
bb, err := bd.ReadBucket(b)
|
|
|
|
if err == nil {
|
|
|
|
bb.name = string(nm)
|
|
|
|
bb.expanded = false
|
|
|
|
bd.buckets = append(bd.buckets, *bb)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
// Check if there are key/values directly in the root
|
|
|
|
bb, err := bd.ReadBucket(tx.Cursor().Bucket())
|
|
|
|
if err == nil {
|
|
|
|
bb.isRoot = true
|
|
|
|
bb.expanded = true
|
|
|
|
bd.buckets = append(bd.buckets, *bb)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
})
|
2015-05-18 14:47:08 +00:00
|
|
|
}
|
|
|
|
|
2022-04-20 21:22:43 +00:00
|
|
|
func (bd *BoltDB) GetBuckets() []BoltBucket { return bd.buckets }
|
|
|
|
|
2022-04-14 16:32:39 +00:00
|
|
|
func (bd *BoltDB) GetGenericFromPath(path []string) (*BoltBucket, *BoltPair, error) {
|
2015-05-18 14:47:08 +00:00
|
|
|
// Check if 'path' leads to a pair
|
2022-04-14 16:32:39 +00:00
|
|
|
p, err := bd.GetPairFromPath(path)
|
2015-05-18 14:47:08 +00:00
|
|
|
if err == nil {
|
|
|
|
return nil, p, nil
|
|
|
|
}
|
|
|
|
// Nope, check if it leads to a bucket
|
2022-04-14 16:32:39 +00:00
|
|
|
b, err := bd.GetBucketFromPath(path)
|
2015-05-18 14:47:08 +00:00
|
|
|
if err == nil {
|
|
|
|
return b, nil, nil
|
|
|
|
}
|
|
|
|
// Nope, error
|
|
|
|
return nil, nil, errors.New("Invalid Path")
|
|
|
|
}
|
|
|
|
|
2022-04-14 16:32:39 +00:00
|
|
|
func (bd *BoltDB) GetBucketFromPath(path []string) (*BoltBucket, error) {
|
2015-05-18 14:47:08 +00:00
|
|
|
if len(path) > 0 {
|
|
|
|
// Find the BoltBucket with a path == path
|
|
|
|
var b *BoltBucket
|
|
|
|
var err error
|
|
|
|
// Find the root bucket
|
2022-04-14 16:32:39 +00:00
|
|
|
b, err = bd.GetBucket(path[0])
|
2015-05-18 14:47:08 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if len(path) > 1 {
|
|
|
|
for p := 1; p < len(path); p++ {
|
2022-04-14 16:32:39 +00:00
|
|
|
b, err = b.GetBucket(path[p])
|
2015-05-18 14:47:08 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return b, nil
|
|
|
|
}
|
|
|
|
return nil, errors.New("Invalid Path")
|
|
|
|
}
|
|
|
|
|
2022-04-14 16:32:39 +00:00
|
|
|
func (bd *BoltDB) GetPairFromPath(path []string) (*BoltPair, error) {
|
2015-05-18 14:47:08 +00:00
|
|
|
if len(path) <= 0 {
|
|
|
|
return nil, errors.New("No Path")
|
|
|
|
}
|
2022-04-14 16:32:39 +00:00
|
|
|
b, err := bd.GetBucketFromPath(path[:len(path)-1])
|
2015-05-18 14:47:08 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
// Found the bucket, pull out the pair
|
2022-04-14 16:32:39 +00:00
|
|
|
p, err := b.GetPair(path[len(path)-1])
|
2015-05-18 14:47:08 +00:00
|
|
|
return p, err
|
|
|
|
}
|
|
|
|
|
2022-04-14 16:32:39 +00:00
|
|
|
func (bd *BoltDB) GetVisibleItemCount(path []string) (int, error) {
|
2015-05-18 14:47:08 +00:00
|
|
|
vis := 0
|
2015-09-17 16:49:57 +00:00
|
|
|
var retErr error
|
2015-05-18 14:47:08 +00:00
|
|
|
if len(path) == 0 {
|
|
|
|
for i := range bd.buckets {
|
2022-04-14 16:32:39 +00:00
|
|
|
n, err := bd.GetVisibleItemCount(bd.buckets[i].GetPath())
|
2015-05-18 14:47:08 +00:00
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
vis += n
|
|
|
|
}
|
|
|
|
} else {
|
2022-04-14 16:32:39 +00:00
|
|
|
b, err := bd.GetBucketFromPath(path)
|
2015-05-18 14:47:08 +00:00
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
// 1 for the bucket
|
2015-09-17 16:49:57 +00:00
|
|
|
vis++
|
2015-05-18 14:47:08 +00:00
|
|
|
if b.expanded {
|
|
|
|
// This bucket is expanded, add up it's children
|
|
|
|
// * 1 for each pair
|
|
|
|
vis += len(b.pairs)
|
|
|
|
// * recurse for buckets
|
|
|
|
for i := range b.buckets {
|
2022-04-14 16:32:39 +00:00
|
|
|
n, err := bd.GetVisibleItemCount(b.buckets[i].GetPath())
|
2015-05-18 14:47:08 +00:00
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
vis += n
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-09-17 16:49:57 +00:00
|
|
|
return vis, retErr
|
2015-05-18 14:47:08 +00:00
|
|
|
}
|
|
|
|
|
2022-04-14 16:32:39 +00:00
|
|
|
func (bd *BoltDB) BuildVisiblePathSlice(filter string) ([][]string, error) {
|
2017-04-05 16:29:28 +00:00
|
|
|
var retSlice [][]string
|
2015-09-17 16:49:57 +00:00
|
|
|
var retErr error
|
2015-05-18 14:47:08 +00:00
|
|
|
// The root path, recurse for root buckets
|
|
|
|
for i := range bd.buckets {
|
2022-04-14 16:32:39 +00:00
|
|
|
bktS, bktErr := bd.buckets[i].BuildVisiblePathSlice([]string{}, filter)
|
2015-09-17 16:49:57 +00:00
|
|
|
if bktErr == nil {
|
|
|
|
retSlice = append(retSlice, bktS...)
|
2015-05-18 14:47:08 +00:00
|
|
|
} else {
|
|
|
|
// Something went wrong, set the error flag
|
2015-09-17 16:49:57 +00:00
|
|
|
bd.buckets[i].errorFlag = true
|
2015-05-18 14:47:08 +00:00
|
|
|
}
|
|
|
|
}
|
2015-09-17 16:49:57 +00:00
|
|
|
return retSlice, retErr
|
2015-05-18 14:47:08 +00:00
|
|
|
}
|
|
|
|
|
2022-04-14 16:32:39 +00:00
|
|
|
func (bd *BoltDB) IsVisiblePath(path []string, filter string) bool {
|
|
|
|
visPaths, err := bd.BuildVisiblePathSlice(filter)
|
2019-12-23 13:31:44 +00:00
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
for _, pth := range visPaths {
|
|
|
|
if len(pth) != len(path) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
isVisible := true
|
|
|
|
for i := range path {
|
|
|
|
if path[i] != pth[i] {
|
|
|
|
isVisible = false
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if isVisible {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
2022-04-14 16:32:39 +00:00
|
|
|
func (bd *BoltDB) GetPrevVisiblePath(path []string, filter string) []string {
|
|
|
|
visPaths, err := bd.BuildVisiblePathSlice(filter)
|
2015-05-18 14:47:08 +00:00
|
|
|
if path == nil {
|
2015-09-17 16:49:57 +00:00
|
|
|
if len(visPaths) > 0 {
|
2017-04-05 16:29:28 +00:00
|
|
|
return visPaths[len(visPaths)-1]
|
2015-05-18 14:47:08 +00:00
|
|
|
}
|
2015-09-17 16:49:57 +00:00
|
|
|
return nil
|
2015-05-18 14:47:08 +00:00
|
|
|
}
|
|
|
|
if err == nil {
|
2017-04-05 16:29:28 +00:00
|
|
|
for idx, pth := range visPaths {
|
|
|
|
isCurPath := true
|
|
|
|
for i := range path {
|
|
|
|
if len(pth) <= i || path[i] != pth[i] {
|
|
|
|
isCurPath = false
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if isCurPath && idx > 0 {
|
|
|
|
return visPaths[idx-1]
|
2015-05-18 14:47:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2022-04-14 16:32:39 +00:00
|
|
|
func (bd *BoltDB) GetNextVisiblePath(path []string, filter string) []string {
|
|
|
|
visPaths, err := bd.BuildVisiblePathSlice(filter)
|
2015-05-18 14:47:08 +00:00
|
|
|
if path == nil {
|
2015-09-17 16:49:57 +00:00
|
|
|
if len(visPaths) > 0 {
|
2017-04-05 16:29:28 +00:00
|
|
|
return visPaths[0]
|
2015-05-18 14:47:08 +00:00
|
|
|
}
|
2015-09-17 16:49:57 +00:00
|
|
|
return nil
|
2015-05-18 14:47:08 +00:00
|
|
|
}
|
|
|
|
if err == nil {
|
2017-04-05 16:29:28 +00:00
|
|
|
for idx, pth := range visPaths {
|
|
|
|
isCurPath := true
|
|
|
|
for i := range path {
|
|
|
|
if len(pth) <= i || path[i] != pth[i] {
|
|
|
|
isCurPath = false
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if isCurPath && len(visPaths) > idx+1 {
|
|
|
|
return visPaths[idx+1]
|
2015-05-18 14:47:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-04-14 16:32:39 +00:00
|
|
|
func (bd *BoltDB) ToggleOpenBucket(path []string) error {
|
2015-05-18 14:47:08 +00:00
|
|
|
// Find the BoltBucket with a path == path
|
2022-04-14 16:32:39 +00:00
|
|
|
b, err := bd.GetBucketFromPath(path)
|
2015-05-18 14:47:08 +00:00
|
|
|
if err == nil {
|
|
|
|
b.expanded = !b.expanded
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-04-14 16:32:39 +00:00
|
|
|
func (bd *BoltDB) CloseBucket(path []string) error {
|
2015-05-18 14:47:08 +00:00
|
|
|
// Find the BoltBucket with a path == path
|
2022-04-14 16:32:39 +00:00
|
|
|
b, err := bd.GetBucketFromPath(path)
|
2015-05-18 14:47:08 +00:00
|
|
|
if err == nil {
|
|
|
|
b.expanded = false
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-04-14 16:32:39 +00:00
|
|
|
func (bd *BoltDB) OpenBucket(path []string) error {
|
2015-05-18 14:47:08 +00:00
|
|
|
// Find the BoltBucket with a path == path
|
2022-04-14 16:32:39 +00:00
|
|
|
b, err := bd.GetBucketFromPath(path)
|
2015-05-18 14:47:08 +00:00
|
|
|
if err == nil {
|
|
|
|
b.expanded = true
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-04-14 16:32:39 +00:00
|
|
|
func (bd *BoltDB) GetBucket(k string) (*BoltBucket, error) {
|
2015-05-18 14:47:08 +00:00
|
|
|
for i := range bd.buckets {
|
|
|
|
if bd.buckets[i].name == k {
|
|
|
|
return &bd.buckets[i], nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil, errors.New("Bucket Not Found")
|
|
|
|
}
|
|
|
|
|
2022-04-14 16:32:39 +00:00
|
|
|
func (bd *BoltDB) OpenAllBuckets() {
|
2017-05-18 13:17:58 +00:00
|
|
|
for i := range bd.buckets {
|
2022-04-14 16:32:39 +00:00
|
|
|
bd.buckets[i].OpenAllBuckets()
|
2017-05-18 13:17:58 +00:00
|
|
|
bd.buckets[i].expanded = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-14 16:32:39 +00:00
|
|
|
func (bd *BoltDB) SyncOpenBuckets(shadow *BoltDB) {
|
2015-05-18 14:47:08 +00:00
|
|
|
// First test this bucket
|
|
|
|
for i := range bd.buckets {
|
|
|
|
for j := range shadow.buckets {
|
|
|
|
if bd.buckets[i].name == shadow.buckets[j].name {
|
2022-04-14 16:32:39 +00:00
|
|
|
bd.buckets[i].SyncOpenBuckets(&shadow.buckets[j])
|
2015-05-18 14:47:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-14 16:32:39 +00:00
|
|
|
func (bd *BoltDB) DeleteKey(path []string) error {
|
|
|
|
err := bd.db.Update(func(tx *bolt.Tx) error {
|
2015-05-18 14:47:08 +00:00
|
|
|
// len(b.path)-1 is the key we need to delete,
|
|
|
|
// the rest are buckets leading to that key
|
|
|
|
if len(path) == 1 {
|
|
|
|
// Deleting a root bucket
|
|
|
|
return tx.DeleteBucket([]byte(path[0]))
|
2015-09-17 16:49:57 +00:00
|
|
|
}
|
|
|
|
b := tx.Bucket([]byte(path[0]))
|
2021-05-31 14:29:09 +00:00
|
|
|
if b == nil {
|
|
|
|
// Invalid path, try for the root bucket
|
|
|
|
b = tx.Cursor().Bucket()
|
|
|
|
}
|
2015-09-17 16:49:57 +00:00
|
|
|
if b != nil {
|
|
|
|
if len(path) > 1 {
|
|
|
|
for i := range path[1 : len(path)-1] {
|
|
|
|
b = b.Bucket([]byte(path[i+1]))
|
|
|
|
if b == nil {
|
2022-04-14 16:32:39 +00:00
|
|
|
return errors.New("DeleteKey: Invalid Path")
|
2015-05-18 14:47:08 +00:00
|
|
|
}
|
|
|
|
}
|
2015-09-17 16:49:57 +00:00
|
|
|
}
|
|
|
|
// Now delete the last key in the path
|
|
|
|
var err error
|
|
|
|
if deleteBkt := b.Bucket([]byte(path[len(path)-1])); deleteBkt == nil {
|
|
|
|
// Must be a pair
|
|
|
|
err = b.Delete([]byte(path[len(path)-1]))
|
2015-05-18 14:47:08 +00:00
|
|
|
} else {
|
2015-09-17 16:49:57 +00:00
|
|
|
err = b.DeleteBucket([]byte(path[len(path)-1]))
|
2015-05-18 14:47:08 +00:00
|
|
|
}
|
2015-09-17 16:49:57 +00:00
|
|
|
return err
|
2015-05-18 14:47:08 +00:00
|
|
|
}
|
2022-04-14 16:32:39 +00:00
|
|
|
return errors.New("DeleteKey: Invalid Path")
|
2015-05-18 14:47:08 +00:00
|
|
|
})
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-04-14 16:32:39 +00:00
|
|
|
func (bd *BoltDB) ReadBucket(b *bolt.Bucket) (*BoltBucket, error) {
|
2015-05-18 14:47:08 +00:00
|
|
|
bb := new(BoltBucket)
|
2021-05-31 14:29:09 +00:00
|
|
|
if b == nil {
|
|
|
|
return nil, errors.New("No bucket passed")
|
|
|
|
}
|
2015-05-18 14:47:08 +00:00
|
|
|
b.ForEach(func(k, v []byte) error {
|
|
|
|
if v == nil {
|
2022-04-14 16:32:39 +00:00
|
|
|
tb, err := bd.ReadBucket(b.Bucket(k))
|
2015-05-18 14:47:08 +00:00
|
|
|
tb.parent = bb
|
|
|
|
if err == nil {
|
|
|
|
tb.name = string(k)
|
|
|
|
bb.buckets = append(bb.buckets, *tb)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
tp := BoltPair{key: string(k), val: string(v)}
|
|
|
|
tp.parent = bb
|
|
|
|
bb.pairs = append(bb.pairs, tp)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
return bb, nil
|
|
|
|
}
|
|
|
|
|
2022-04-14 16:32:39 +00:00
|
|
|
func (bd *BoltDB) RenameBucket(path []string, name string) error {
|
2015-05-18 14:47:08 +00:00
|
|
|
if name == path[len(path)-1] {
|
|
|
|
// No change requested
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
var bb *BoltBucket // For caching the current bucket
|
2022-04-14 16:32:39 +00:00
|
|
|
err := bd.db.View(func(tx *bolt.Tx) error {
|
2015-05-18 14:47:08 +00:00
|
|
|
// len(b.path)-1 is the key we need to delete,
|
|
|
|
// the rest are buckets leading to that key
|
|
|
|
b := tx.Bucket([]byte(path[0]))
|
2021-05-31 14:29:09 +00:00
|
|
|
if b == nil {
|
|
|
|
// Invalid path, try for the root bucket
|
|
|
|
b = tx.Cursor().Bucket()
|
|
|
|
}
|
2015-05-18 14:47:08 +00:00
|
|
|
if b != nil {
|
|
|
|
if len(path) > 1 {
|
2021-05-31 14:29:09 +00:00
|
|
|
for i := range path[1:] {
|
2015-05-18 14:47:08 +00:00
|
|
|
b = b.Bucket([]byte(path[i+1]))
|
|
|
|
if b == nil {
|
2022-04-14 16:32:39 +00:00
|
|
|
return errors.New("RenameBucket: Invalid Path")
|
2015-05-18 14:47:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
var err error
|
|
|
|
// Ok, cache b
|
2022-04-14 16:32:39 +00:00
|
|
|
bb, err = bd.ReadBucket(b)
|
2015-05-18 14:47:08 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
} else {
|
2022-04-14 16:32:39 +00:00
|
|
|
return errors.New("RenameBucket: Invalid Bucket")
|
2015-05-18 14:47:08 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if bb == nil {
|
2022-04-14 16:32:39 +00:00
|
|
|
return errors.New("RenameBucket: Couldn't find Bucket")
|
2015-05-18 14:47:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Ok, we have the bucket cached, now delete the current instance
|
2022-04-14 16:32:39 +00:00
|
|
|
if err = bd.DeleteKey(path); err != nil {
|
2015-05-18 14:47:08 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
// Rechristen our cached bucket
|
|
|
|
bb.name = name
|
|
|
|
// And re-add it
|
|
|
|
|
2015-09-17 16:49:57 +00:00
|
|
|
parentPath := path[:len(path)-1]
|
2022-04-14 16:32:39 +00:00
|
|
|
if err = bd.AddBucketFromBoltBucket(parentPath, bb); err != nil {
|
2015-05-18 14:47:08 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-04-14 16:32:39 +00:00
|
|
|
func (bd *BoltDB) UpdatePairKey(path []string, k string) error {
|
|
|
|
err := bd.db.Update(func(tx *bolt.Tx) error {
|
2015-05-18 14:47:08 +00:00
|
|
|
// len(b.path)-1 is the key for the pair we're updating,
|
|
|
|
// the rest are buckets leading to that key
|
|
|
|
b := tx.Bucket([]byte(path[0]))
|
2021-05-31 14:29:09 +00:00
|
|
|
if b == nil {
|
|
|
|
// Invalid path, try for the root bucket
|
|
|
|
b = tx.Cursor().Bucket()
|
|
|
|
}
|
2015-05-18 14:47:08 +00:00
|
|
|
if b != nil {
|
|
|
|
if len(path) > 0 {
|
|
|
|
for i := range path[1 : len(path)-1] {
|
|
|
|
b = b.Bucket([]byte(path[i+1]))
|
|
|
|
if b == nil {
|
2022-04-14 16:32:39 +00:00
|
|
|
return errors.New("UpdatePairKey: Invalid Path")
|
2015-05-18 14:47:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bk := []byte(path[len(path)-1])
|
|
|
|
v := b.Get(bk)
|
|
|
|
err := b.Delete(bk)
|
|
|
|
if err == nil {
|
|
|
|
// Old pair has been deleted, now add the new one
|
|
|
|
err = b.Put([]byte(k), v)
|
|
|
|
}
|
|
|
|
// Now update the last key in the path
|
|
|
|
return err
|
|
|
|
}
|
2022-04-14 16:32:39 +00:00
|
|
|
return errors.New("UpdatePairKey: Invalid Path")
|
2015-05-18 14:47:08 +00:00
|
|
|
})
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-04-14 16:32:39 +00:00
|
|
|
func (bd *BoltDB) UpdatePairValue(path []string, v string) error {
|
|
|
|
err := bd.db.Update(func(tx *bolt.Tx) error {
|
2015-05-18 14:47:08 +00:00
|
|
|
// len(b.GetPath())-1 is the key for the pair we're updating,
|
|
|
|
// the rest are buckets leading to that key
|
|
|
|
b := tx.Bucket([]byte(path[0]))
|
2021-05-31 14:29:09 +00:00
|
|
|
if b == nil {
|
|
|
|
// Invalid path, try for the root bucket
|
|
|
|
b = tx.Cursor().Bucket()
|
|
|
|
}
|
2015-05-18 14:47:08 +00:00
|
|
|
if b != nil {
|
|
|
|
if len(path) > 0 {
|
|
|
|
for i := range path[1 : len(path)-1] {
|
|
|
|
b = b.Bucket([]byte(path[i+1]))
|
|
|
|
if b == nil {
|
2022-04-14 16:32:39 +00:00
|
|
|
return errors.New("UpdatePairValue: Invalid Path")
|
2015-05-18 14:47:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Now update the last key in the path
|
|
|
|
err := b.Put([]byte(path[len(path)-1]), []byte(v))
|
|
|
|
return err
|
|
|
|
}
|
2022-04-14 16:32:39 +00:00
|
|
|
return errors.New("UpdatePairValue: Invalid Path")
|
2015-05-18 14:47:08 +00:00
|
|
|
})
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-04-14 16:32:39 +00:00
|
|
|
func (bd *BoltDB) InsertBucket(path []string, n string) error {
|
2015-05-18 14:47:08 +00:00
|
|
|
// Inserts a new bucket named 'n' at 'path'
|
2022-04-14 16:32:39 +00:00
|
|
|
err := bd.db.Update(func(tx *bolt.Tx) error {
|
2021-05-31 14:29:09 +00:00
|
|
|
if len(path) == 0 || path[0] == "" {
|
2015-05-18 14:47:08 +00:00
|
|
|
// insert at root
|
|
|
|
_, err := tx.CreateBucket([]byte(n))
|
|
|
|
if err != nil {
|
2022-04-14 16:32:39 +00:00
|
|
|
return fmt.Errorf("InsertBucket: %s", err)
|
2015-05-18 14:47:08 +00:00
|
|
|
}
|
|
|
|
} else {
|
2015-09-17 16:49:57 +00:00
|
|
|
rootBucket, path := path[0], path[1:]
|
|
|
|
b := tx.Bucket([]byte(rootBucket))
|
2015-05-18 14:47:08 +00:00
|
|
|
if b != nil {
|
|
|
|
for len(path) > 0 {
|
2015-09-17 16:49:57 +00:00
|
|
|
tstBucket := ""
|
|
|
|
tstBucket, path = path[0], path[1:]
|
|
|
|
nB := b.Bucket([]byte(tstBucket))
|
|
|
|
if nB == nil {
|
2015-05-18 14:47:08 +00:00
|
|
|
// Not a bucket, if we're out of path, just move on
|
|
|
|
if len(path) != 0 {
|
|
|
|
// Out of path, error
|
2022-04-14 16:32:39 +00:00
|
|
|
return errors.New("InsertBucket: Invalid Path 1")
|
2015-05-18 14:47:08 +00:00
|
|
|
}
|
|
|
|
} else {
|
2015-09-17 16:49:57 +00:00
|
|
|
b = nB
|
2015-05-18 14:47:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
_, err := b.CreateBucket([]byte(n))
|
|
|
|
return err
|
|
|
|
}
|
2015-09-17 16:49:57 +00:00
|
|
|
return fmt.Errorf("insertBucket: Invalid Path %s", rootBucket)
|
2015-05-18 14:47:08 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-04-14 16:32:39 +00:00
|
|
|
func (bd *BoltDB) InsertPair(path []string, k string, v string) error {
|
2015-05-18 14:47:08 +00:00
|
|
|
// Insert a new pair k => v at path
|
2022-04-14 16:32:39 +00:00
|
|
|
err := bd.db.Update(func(tx *bolt.Tx) error {
|
2015-05-18 14:47:08 +00:00
|
|
|
if len(path) == 0 {
|
|
|
|
// We cannot insert a pair at root
|
2022-04-14 16:32:39 +00:00
|
|
|
return errors.New("InsertPair: Cannot insert pair at root")
|
2015-09-17 16:49:57 +00:00
|
|
|
}
|
|
|
|
var err error
|
|
|
|
b := tx.Bucket([]byte(path[0]))
|
2021-05-31 14:29:09 +00:00
|
|
|
if b == nil {
|
|
|
|
// Invalid path, try for the root bucket
|
|
|
|
b = tx.Cursor().Bucket()
|
|
|
|
}
|
2015-09-17 16:49:57 +00:00
|
|
|
if b != nil {
|
|
|
|
if len(path) > 0 {
|
|
|
|
for i := 1; i < len(path); i++ {
|
|
|
|
b = b.Bucket([]byte(path[i]))
|
|
|
|
if b == nil {
|
2022-04-14 16:32:39 +00:00
|
|
|
return fmt.Errorf("InsertPair: %s", err)
|
2015-05-18 14:47:08 +00:00
|
|
|
}
|
|
|
|
}
|
2015-09-17 16:49:57 +00:00
|
|
|
}
|
|
|
|
err := b.Put([]byte(k), []byte(v))
|
|
|
|
if err != nil {
|
2022-04-14 16:32:39 +00:00
|
|
|
return fmt.Errorf("InsertPair: %s", err)
|
2015-05-18 14:47:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-04-14 16:32:39 +00:00
|
|
|
func (bd *BoltDB) exportValue(path []string, fName string) error {
|
|
|
|
return bd.db.View(func(tx *bolt.Tx) error {
|
2016-12-29 21:23:58 +00:00
|
|
|
// len(b.path)-1 is the key whose value we want to export
|
|
|
|
// the rest are buckets leading to that key
|
|
|
|
b := tx.Bucket([]byte(path[0]))
|
2021-05-31 14:29:09 +00:00
|
|
|
if b == nil {
|
|
|
|
// Invalid path, try for the root bucket
|
|
|
|
b = tx.Cursor().Bucket()
|
|
|
|
}
|
2016-12-29 21:23:58 +00:00
|
|
|
if b != nil {
|
|
|
|
if len(path) > 1 {
|
|
|
|
for i := range path[1 : len(path)-1] {
|
|
|
|
b = b.Bucket([]byte(path[i+1]))
|
|
|
|
if b == nil {
|
2022-04-14 16:32:39 +00:00
|
|
|
return errors.New("ExportValue: Invalid Path: " + strings.Join(path, "/"))
|
2016-12-29 21:23:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bk := []byte(path[len(path)-1])
|
|
|
|
v := b.Get(bk)
|
2022-04-14 16:32:39 +00:00
|
|
|
return util.WriteToFile(fName, string(v)+"\n", os.O_CREATE|os.O_WRONLY|os.O_TRUNC)
|
2016-12-29 21:23:58 +00:00
|
|
|
}
|
2022-04-14 16:32:39 +00:00
|
|
|
return errors.New("ExportValue: Invalid Bucket")
|
2016-12-29 21:23:58 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-04-14 16:32:39 +00:00
|
|
|
func (bd *BoltDB) ExportJSON(path []string, fName string) error {
|
|
|
|
return bd.db.View(func(tx *bolt.Tx) error {
|
2016-12-29 21:23:58 +00:00
|
|
|
// len(b.path)-1 is the key whose value we want to export
|
|
|
|
// the rest are buckets leading to that key
|
|
|
|
b := tx.Bucket([]byte(path[0]))
|
2021-05-31 14:29:09 +00:00
|
|
|
if b == nil {
|
|
|
|
// Invalid path, try for the root bucket
|
|
|
|
b = tx.Cursor().Bucket()
|
|
|
|
}
|
2016-12-29 21:23:58 +00:00
|
|
|
if b != nil {
|
|
|
|
if len(path) > 1 {
|
|
|
|
for i := range path[1 : len(path)-1] {
|
|
|
|
b = b.Bucket([]byte(path[i+1]))
|
|
|
|
if b == nil {
|
2022-04-14 16:32:39 +00:00
|
|
|
return errors.New("ExportJSON: Invalid Path: " + strings.Join(path, "/"))
|
2016-12-29 21:23:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bk := []byte(path[len(path)-1])
|
|
|
|
if v := b.Get(bk); v != nil {
|
2022-04-14 16:32:39 +00:00
|
|
|
return util.WriteToFile(fName, "{\""+string(bk)+"\":\""+string(v)+"\"}", os.O_CREATE|os.O_WRONLY|os.O_TRUNC)
|
2016-12-29 21:23:58 +00:00
|
|
|
}
|
|
|
|
if b.Bucket(bk) != nil {
|
2022-04-14 16:32:39 +00:00
|
|
|
return util.WriteToFile(fName, util.ToJsonString(b.Bucket(bk)), os.O_CREATE|os.O_WRONLY|os.O_TRUNC)
|
2016-12-29 21:23:58 +00:00
|
|
|
}
|
2022-04-14 16:32:39 +00:00
|
|
|
return util.WriteToFile(fName, util.ToJsonString(b), os.O_CREATE|os.O_WRONLY|os.O_TRUNC)
|
2016-12-29 21:23:58 +00:00
|
|
|
}
|
2022-04-14 16:32:39 +00:00
|
|
|
return errors.New("ExportJSON: Invalid Bucket")
|
2016-12-29 21:23:58 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-04-14 16:32:39 +00:00
|
|
|
func (bd *BoltDB) AddBucketFromBoltBucket(path []string, bb *BoltBucket) error {
|
|
|
|
if err := bd.InsertBucket(path, bb.name); err == nil {
|
|
|
|
bucketPath := append(path, bb.name)
|
|
|
|
for i := range bb.pairs {
|
|
|
|
if err = bd.InsertPair(bucketPath, bb.pairs[i].key, bb.pairs[i].val); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for i := range bb.buckets {
|
|
|
|
if err = bd.AddBucketFromBoltBucket(bucketPath, &bb.buckets[i]); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-12-29 21:23:58 +00:00
|
|
|
}
|
2015-05-18 14:47:08 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2022-04-20 21:22:43 +00:00
|
|
|
|
|
|
|
func (bd BoltDB) Lines() []string {
|
|
|
|
var ret []string
|
|
|
|
for i := range bd.buckets {
|
|
|
|
ret = append(ret, bd.buckets[i].Lines()...)
|
|
|
|
}
|
|
|
|
return ret
|
|
|
|
}
|