mirror of
https://github.com/safing/portbase
synced 2025-09-01 10:09:50 +00:00
109 lines
2.1 KiB
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)
|
|
}
|