farside/db/db.go
Ben Busby 6e64a93fd1
Update breezewiki routing behavior, update readme
BreezeWiki requires the subdomain of a fandom link to be preserved when
routing, otherwise the redirect doesn't work correctly.

Cleaned up readme examples
2025-01-27 12:17:20 -07:00

159 lines
2.8 KiB
Go

package db
import (
"encoding/json"
"errors"
"fmt"
"log"
"math/rand"
"os"
"slices"
"strings"
"time"
"github.com/benbusby/farside/services"
"github.com/dgraph-io/badger/v4"
)
var (
badgerDB *badger.DB
selectionMap map[string]string
cachedServiceList []services.Service
cacheUpdated time.Time
)
func InitializeDB() error {
var err error
dbDir := os.Getenv("FARSIDE_DB_DIR")
if len(dbDir) == 0 {
dbDir = "./badger-db"
}
badgerDB, err = badger.Open(badger.DefaultOptions(dbDir))
if err != nil {
return err
}
return nil
}
func SetInstances(service string, instances []string) error {
instancesBytes, err := json.Marshal(instances)
if err != nil {
return err
}
err = badgerDB.Update(func(txn *badger.Txn) error {
err := txn.Set([]byte(service), instancesBytes)
return err
})
if err != nil {
return err
}
return nil
}
func GetInstance(service, path string) (string, error) {
instances, err := GetAllInstances(service)
if err != nil || len(instances) == 0 {
if err != nil {
log.Println("DB err:", err)
}
link, ok := services.FallbackMap[service]
if !ok {
return "", errors.New("invalid service")
}
return link, nil
}
previous, ok := selectionMap[service]
if ok && len(instances) > 2 {
instances = slices.DeleteFunc(instances, func(i string) bool {
return i == previous
})
}
index := rand.Intn(len(instances))
value := instances[index]
selectionMap[service] = value
if len(path) > 0 {
value = strings.TrimSuffix(value, "/")
value = fmt.Sprintf("%s/%s", value, path)
}
return value, nil
}
func GetAllInstances(service string) ([]string, error) {
var instances []string
err := badgerDB.View(func(txn *badger.Txn) error {
item, err := txn.Get([]byte(service))
if err != nil {
return err
}
err = item.Value(func(val []byte) error {
err := json.Unmarshal(val, &instances)
return err
})
return err
})
return instances, err
}
func GetServiceList() []services.Service {
if cacheUpdated.Add(5 * time.Minute).After(time.Now().UTC()) {
return cachedServiceList
}
canCache := true
var serviceList []services.Service
for _, service := range services.ServiceList {
instances, err := GetAllInstances(service.Type)
if err != nil {
canCache = false
instances = []string{service.Fallback}
}
storedService := services.Service{
Type: service.Type,
Instances: instances,
}
serviceList = append(serviceList, storedService)
}
if canCache {
cachedServiceList = serviceList
cacheUpdated = time.Now().UTC()
}
return serviceList
}
func CloseDB() error {
log.Println("Closing database...")
err := badgerDB.Close()
if err != nil {
log.Println("Error closing database", err)
return err
}
log.Println("Database closed!")
return nil
}
func init() {
selectionMap = make(map[string]string)
}