safing-portbase/database/registry.go

109 lines
2.1 KiB
Go

package database
import (
"encoding/json"
"errors"
"io/ioutil"
"os"
"path"
"regexp"
"sync"
"github.com/tevino/abool"
)
// RegisteredDatabase holds information about registered databases
type RegisteredDatabase struct {
Name string
Description string
StorageType string
PrimaryAPI string
}
// Equal returns whether this instance equals another.
func (r *RegisteredDatabase) Equal(o *RegisteredDatabase) bool {
if r.Name != o.Name ||
r.Description != o.Description ||
r.StorageType != o.StorageType ||
r.PrimaryAPI != o.PrimaryAPI {
return false
}
return true
}
const (
registryFileName = "databases.json"
)
var (
initialized = abool.NewBool(false)
registry map[string]*RegisteredDatabase
registryLock sync.Mutex
nameConstraint = regexp.MustCompile("^[A-Za-z0-9_-]{5,}$")
)
// RegisterDatabase registers a new database.
func RegisterDatabase(new *RegisteredDatabase) error {
if !initialized.IsSet() {
return errors.New("database not initialized")
}
if !nameConstraint.MatchString(new.Name) {
return errors.New("database name must only contain alphanumeric and `_-` characters and must be at least 5 characters long")
}
registryLock.Lock()
defer registryLock.Unlock()
registeredDB, ok := registry[new.Name]
if !ok || !new.Equal(registeredDB) {
registry[new.Name] = new
return saveRegistry()
}
return nil
}
func loadRegistry() error {
registryLock.Lock()
defer registryLock.Unlock()
// read file
filePath := path.Join(rootDir, registryFileName)
data, err := ioutil.ReadFile(filePath)
if err != nil {
if err == os.ErrNotExist {
registry = make(map[string]*RegisteredDatabase)
return nil
}
return err
}
// parse
new := make(map[string]*RegisteredDatabase)
err = json.Unmarshal(data, new)
if err != nil {
return err
}
// set
registry = new
return nil
}
func saveRegistry() error {
registryLock.Lock()
defer registryLock.Unlock()
// marshal
data, err := json.Marshal(registry)
if err != nil {
return err
}
// write file
filePath := path.Join(rootDir, registryFileName)
return ioutil.WriteFile(filePath, data, 0600)
}