mirror of
https://github.com/safing/portbase
synced 2025-09-01 18:19:57 +00:00
145 lines
2.7 KiB
Go
145 lines
2.7 KiB
Go
package database
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"path"
|
|
"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
|
|
)
|
|
|
|
// RegisterDatabase registers a new database.
|
|
func RegisterDatabase(new *RegisteredDatabase) error {
|
|
if !initialized.IsSet() {
|
|
return errors.New("database not initialized")
|
|
}
|
|
|
|
registryLock.Lock()
|
|
defer registryLock.Unlock()
|
|
|
|
registeredDB, ok := registry[new.Name]
|
|
if !ok || !new.Equal(registeredDB) {
|
|
registry[new.Name] = new
|
|
return saveRegistry()
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Initialize initialized the database
|
|
func Initialize(location string) error {
|
|
if initialized.SetToIf(false, true) {
|
|
rootDir = location
|
|
|
|
err := checkRootDir()
|
|
if err != nil {
|
|
return fmt.Errorf("could not create/open database directory (%s): %s", rootDir, err)
|
|
}
|
|
|
|
err = loadRegistry()
|
|
if err != nil {
|
|
return fmt.Errorf("could not load database registry (%s): %s", path.Join(rootDir, registryFileName), err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
return errors.New("database already initialized")
|
|
}
|
|
|
|
func checkRootDir() error {
|
|
// open dir
|
|
dir, err := os.Open(rootDir)
|
|
if err != nil {
|
|
if err == os.ErrNotExist {
|
|
return os.MkdirAll(rootDir, 0700)
|
|
}
|
|
return err
|
|
}
|
|
defer dir.Close()
|
|
|
|
fileInfo, err := dir.Stat()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if fileInfo.Mode().Perm() != 0700 {
|
|
return dir.Chmod(0700)
|
|
}
|
|
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)
|
|
}
|