sermoni

"Service monitor" / cronjob status service
Log | Files | Refs

commit 0eb83c922b4ae5ab280c0d5efb9216f99ba9456c
parent f0aa76eaf2ee2c5a8fc782898668687d84a5f318
Author: Vetle Haflan <vetle@haflan.dev>
Date:   Fri, 10 Apr 2020 16:41:17 +0200

Refactor database operation to use bucket wrapper

Diffstat:
Mdatabase/database.go | 36+++++++++++++++++++++++++++++++-----
Ago.mod | 8++++++++
Mmain.go | 6++++--
Mservices/services.go | 53+++++++++++++++++++++++++----------------------------
4 files changed, 68 insertions(+), 35 deletions(-)

diff --git a/database/database.go b/database/database.go @@ -77,7 +77,7 @@ func Init(dbFileName string) error { // generates hash for the password and updates the database with this // new configuration. func Reconfigure(passphrase string, pageTitle string) error { - + // TODO: Maybe this belongs elsewhere? /* TODO: Generate a random _readable_ password if none is given var passphraseBytes []byte if passphrase == "" { @@ -118,8 +118,34 @@ func Close() { db.Close() } -// GetDB returns the bbolt database struct -// TODO: Not sure how if this is a good way to do it, although it does seem to work -func GetDB() *bbolt.DB { - return db +// BucketOperation operates on the given (root level) bucket if it exists, using the +// DB.Update function if update is set true, otherwise using DB.View. +// An error is returned if no bucket can be found for the bucketKey or any other +// error occurs in the wrapped transaction +func bucketOperation(update bool, bucketKey []byte, fn func(*bbolt.Bucket) error) error { + var operation func(func(*bbolt.Tx) error) error + if update { + operation = db.Update + } else { + operation = db.View + } + return operation(func(tx *bbolt.Tx) error { + bucket := tx.Bucket(bucketKey) + if bucket == nil { + return errors.New("the given bucket does not exist") + } + return fn(bucket) + }) +} + +// BucketUpdate wraps DB.Update with a general way of handling errors +// if the bucket does not exist +func BucketUpdate(bucketKey []byte, fn func(*bbolt.Bucket) error) error { + return bucketOperation(true, bucketKey, fn) +} + +// BucketView wraps DB.View with a general way of handling errors +// if the bucket does not exist +func BucketView(bucketKey []byte, fn func(*bbolt.Bucket) error) error { + return bucketOperation(true, bucketKey, fn) } diff --git a/go.mod b/go.mod @@ -0,0 +1,8 @@ +module sermoni + +go 1.13 + +require ( + go.etcd.io/bbolt v1.3.4 + golang.org/x/crypto v0.0.0-20200406173513-056763e48d71 +) diff --git a/main.go b/main.go @@ -23,6 +23,8 @@ func main() { Name: "Test name", Description: "This is the description, yay", }) - testService := services.Get("testing") - fmt.Printf("test service: %+v\n", testService) + fmt.Printf("ADD ERR: %v\n", services.Add("testing", services.Service{Name: "This"})) + fmt.Printf("none service: %+v\n", services.Get("none")) + fmt.Printf("DELETE ERR: %v\n", services.Delete("none")) + fmt.Printf("test service: %+v\n", services.Get("testing")) } diff --git a/services/services.go b/services/services.go @@ -24,24 +24,20 @@ type Service struct { // Get returns a service struct if the identifier matches any // keys in the services bucket. Returns nil if there are no matching buckets -func Get(identifier string) (service Service) { - db := database.GetDB() - err := db.View(func(tx *bbolt.Tx) error { - serviceBucket := tx.Bucket(database.BucketKeyServices) - if serviceBucket == nil { - log.Fatal("No services bucket found") - } - b := serviceBucket.Bucket([]byte(identifier)) - if b == nil { +func Get(identifier string) *Service { + var service Service + err := database.BucketView(database.BucketKeyServices, func(b *bbolt.Bucket) error { + sb := b.Bucket([]byte(identifier)) + if sb == nil { return errors.New("no bucket found for the given id") } - if name := b.Get(keyServiceName); name != nil { + if name := sb.Get(keyServiceName); name != nil { service.Name = string(name) } - if description := b.Get(keyServiceDescription); description != nil { + if description := sb.Get(keyServiceDescription); description != nil { service.Description = string(description) } - if period := b.Get(keyServicePeriod); period != nil { + if period := sb.Get(keyServicePeriod); period != nil { // Quick fix: Convert to string, then int // If an error occurs (it tho) if intPeriod, err := strconv.Atoi(string(period)); err != nil { @@ -55,43 +51,44 @@ func Get(identifier string) (service Service) { }) if err != nil { log.Println(err) + return nil } - return service + return &service } // Delete deletes the given service if it exists -func Delete(identifier string) { - //db := database.GetDB() +func Delete(identifier string) error { + return database.BucketUpdate(database.BucketKeyServices, func(b *bbolt.Bucket) error { + serviceKey := []byte(identifier) + if b.Bucket(serviceKey) == nil { + return errors.New("no service for the given id") + } + return b.DeleteBucket(serviceKey) + }) } // Add adds a new service to monitor func Add(identifier string, service Service) error { - db := database.GetDB() - return db.Update(func(tx *bbolt.Tx) error { - serviceBucket := tx.Bucket(database.BucketKeyServices) - if serviceBucket == nil { - log.Fatal("No services bucket found") - } + return database.BucketUpdate(database.BucketKeyServices, func(b *bbolt.Bucket) error { serviceKey := []byte(identifier) - if serviceBucket.Bucket(serviceKey) != nil { + if b.Bucket(serviceKey) != nil { return errors.New("a service has already been registered for the given id") } - b, err := serviceBucket.CreateBucket(serviceKey) + // Create the service bucket, sb + sb, err := b.CreateBucket(serviceKey) if err != nil { return err } - if err = b.Put(keyServiceName, []byte(service.Name)); err != nil { + if err = sb.Put(keyServiceName, []byte(service.Name)); err != nil { return err } - if err = b.Put(keyServiceDescription, []byte(service.Description)); err != nil { + if err = sb.Put(keyServiceDescription, []byte(service.Description)); err != nil { return err } periodStr := strconv.Itoa(service.ExpectationPeriod) - if err = b.Put(keyServicePeriod, []byte(periodStr)); err != nil { + if err = sb.Put(keyServicePeriod, []byte(periodStr)); err != nil { return err } return nil }) } - -// TODO: Consider a wrapper that gets the services bucket and operates on it