From e6fb690fc3beeea83fb7f27e6b05bc8c3cfde968 Mon Sep 17 00:00:00 2001 From: Brian Buller Date: Wed, 17 Feb 2016 08:30:43 -0600 Subject: [PATCH] Starting work on server --- boltrest-server/.gitignore | 2 + boltrest-server/main.go | 53 +++++++++++++++ boltrest.go | 128 ++++++++++++++++++++++++++++++++++--- 3 files changed, 175 insertions(+), 8 deletions(-) create mode 100644 boltrest-server/.gitignore create mode 100644 boltrest-server/main.go diff --git a/boltrest-server/.gitignore b/boltrest-server/.gitignore new file mode 100644 index 0000000..789d6af --- /dev/null +++ b/boltrest-server/.gitignore @@ -0,0 +1,2 @@ +# Server Binary +boltrest-server \ No newline at end of file diff --git a/boltrest-server/main.go b/boltrest-server/main.go new file mode 100644 index 0000000..194b2fb --- /dev/null +++ b/boltrest-server/main.go @@ -0,0 +1,53 @@ +package main + +import ( + "errors" + "math/rand" + "os" + + "github.com/br0xen/boltrest" +) + +var adminDB *boltrest.DB + +func main() { + initialize() + adminDB = boltrest.Open("admin.db") +} + +func initialize() error { + // Make sure that the necessary files/directories are in place + var tstDir *os.File + var tstDirInfo os.FileInfo + var err error + if tstDir, err = os.Open("dbs"); err != nil { + if err = os.Mkdir("dbs", 0755); err != nil { + return err + } + if tstDir, err = os.Open("dbs"); err != nil { + return err + } + } + if tstDirInfo, err = tstDir.Stat(); err != nil { + return err + } + if !tstDirInfo.IsDir() { + return errors.New("'dbs' exists and is not a directory") + } + // We were able to open the db path and it was a directory + return nil +} + +const keyChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + +func generateAPIKey() string { + b := make([]byte, 34) + for i := range b { + if i%5 == 4 { + b[i] = '-' + } else { + b[i] = keyChars[rand.Int63()%int64(len(keyChars))] + } + } + return string(b) +} \ No newline at end of file diff --git a/boltrest.go b/boltrest.go index 0fba4e2..f4d19a7 100644 --- a/boltrest.go +++ b/boltrest.go @@ -1,4 +1,4 @@ -package boltrest/lib +package boltrest import ( "encoding/json" @@ -16,9 +16,6 @@ import ( // in a local bolt db and a remote db through a // rest api. -// Custom BoltRest DB keys: -// __BR_LastUpdate: - // DB is a struct for accomplishing this type DB struct { localFile string @@ -68,8 +65,7 @@ func (b *DB) GetValue(path []string, key string) (string, error) { } // SetValue sets the value at path to val -// path is a '/' separated list of tokens -// the last token is a key, all others are buckets +// path is a slice of tokens func (b *DB) SetValue(path []string, key, val string) error { var err error b.localDB.Update(func(tx *bolt.Tx) error { @@ -146,12 +142,128 @@ func (b *DB) SetTimestamp(path []string, key string, val time.Time) error { return b.SetValue(path, key, val.Format(time.RFC3339)) } +// GetBucketList returns a list of all sub-buckets at path +func (b *DB) GetBucketList(path []string) ([]string, error) { + var err error + var ret []string + // TODO: Make sure local db is fresh (or offline) + + err = b.localDB.Update(func(tx *bolt.Tx) error { + bkt := tx.Bucket([]byte(path[0])) + if bkt == nil { + return fmt.Errorf("Couldn't find bucket " + path[0]) + } + var newBkt *bolt.Bucket + for idx := 1; idx < len(path); idx++ { + newBkt = bkt.Bucket([]byte(path[idx])) + if newBkt == nil { + return fmt.Errorf("Couldn't find bucket " + strings.Join(path[:idx], "/")) + } + } + // newBkt should have the last bucket in the path + berr := newBkt.ForEach(func(k, v []byte) error { + if v == nil { + // Must be a bucket + ret = append(ret, string(k)) + } + return nil + }) + return berr + }) + return ret, err +} + +// GetKeyList returns a list of all keys at path +func (b *DB) GetKeyList(path []string) ([]string, error) { + var err error + var ret []string + // TODO: Make sure local db is fresh (or offline) + + err = b.localDB.Update(func(tx *bolt.Tx) error { + bkt := tx.Bucket([]byte(path[0])) + if bkt == nil { + return fmt.Errorf("Couldn't find bucket " + path[0]) + } + var newBkt *bolt.Bucket + for idx := 1; idx < len(path); idx++ { + newBkt = bkt.Bucket([]byte(path[idx])) + if newBkt == nil { + return fmt.Errorf("Couldn't find bucket " + strings.Join(path[:idx], "/")) + } + } + // newBkt should have the last bucket in the path + berr := newBkt.ForEach(func(k, v []byte) error { + if v != nil { + // Not a bucket + ret = append(ret, string(k)) + } + return nil + }) + return berr + }) + return ret, err +} + +// DeletePair deletes the pair with key at path +func (b *DB) DeletePair(path []string, key string) error { + var err error + // TODO: Make sure local db is fresh (or offline) + + err = b.localDB.Update(func(tx *bolt.Tx) error { + bkt := tx.Bucket([]byte(path[0])) + if bkt == nil { + return fmt.Errorf("Couldn't find bucket " + path[0]) + } + var newBkt *bolt.Bucket + for idx := 1; idx < len(path); idx++ { + newBkt = bkt.Bucket([]byte(path[idx])) + if newBkt == nil { + return fmt.Errorf("Couldn't find bucket " + strings.Join(path[:idx], "/")) + } + } + // newBkt should have the last bucket in the path + // Test to make sure that key is a pair, if so, delete it + if tst := newBkt.Bucket([]byte(key)); tst == nil { + return newBkt.Delete([]byte(key)) + } + return nil + }) + return err +} + +// DeleteBucket deletes the bucket key at path +func (b *DB) DeleteBucket(path []string, key string) error { + var err error + // TODO: Make sure local db is fresh (or offline) + + err = b.localDB.Update(func(tx *bolt.Tx) error { + bkt := tx.Bucket([]byte(path[0])) + if bkt == nil { + return fmt.Errorf("Couldn't find bucket " + path[0]) + } + var newBkt *bolt.Bucket + for idx := 1; idx < len(path); idx++ { + newBkt = bkt.Bucket([]byte(path[idx])) + if newBkt == nil { + return fmt.Errorf("Couldn't find bucket " + strings.Join(path[:idx], "/")) + } + } + // newBkt should have the last bucket in the path + // Test to make sure that key is a bucket, if so, delete it + if tst := newBkt.Bucket([]byte(key)); tst != nil { + return newBkt.Delete([]byte(key)) + } + return nil + }) + return err +} + type setURLResponse struct { dbMD5 string } -// SetURL sets the DB's remote URL -func (b *DB) SetURL(url string) (bool, string) { +// SetDBURL sets the DB's remote URL +func (b *DB) SetDBURL(url string) (bool, string) { resp, err := http.Get(url) if err != nil { return false, ""