go get -u && gofumpt -w

This commit is contained in:
nikk gitanes
2024-02-26 18:35:19 +03:00
parent e1a2aa7324
commit 45e4ec054a
12 changed files with 384 additions and 382 deletions

View File

@@ -1,70 +1,70 @@
package settings
import "server/log"
type DBReadCache struct {
db TorrServerDB
listCache map[string][]string
dataCache map[[2]string][]byte
}
func NewDBReadCache(db TorrServerDB) TorrServerDB {
cdb := &DBReadCache{
db: db,
listCache: map[string][]string{},
dataCache: map[[2]string][]byte{},
}
return cdb
}
func (v *DBReadCache) CloseDB() {
v.db.CloseDB()
v.db = nil
v.listCache = nil
v.dataCache = nil
}
func (v *DBReadCache) Get(xPath, name string) []byte {
cacheKey := v.makeDataCacheKey(xPath, name)
if data, ok := v.dataCache[cacheKey]; ok {
return data
}
data := v.db.Get(xPath, name)
v.dataCache[cacheKey] = data
return data
}
func (v *DBReadCache) Set(xPath, name string, value []byte) {
if ReadOnly {
log.TLogln("DB.Set: Read-only DB mode!", name)
return
}
cacheKey := v.makeDataCacheKey(xPath, name)
v.dataCache[cacheKey] = value
delete(v.listCache, xPath)
v.db.Set(xPath, name, value)
}
func (v *DBReadCache) List(xPath string) []string {
if names, ok := v.listCache[xPath]; ok {
return names
}
names := v.db.List(xPath)
v.listCache[xPath] = names
return names
}
func (v *DBReadCache) Rem(xPath, name string) {
if ReadOnly {
log.TLogln("DB.Rem: Read-only DB mode!", name)
return
}
cacheKey := v.makeDataCacheKey(xPath, name)
delete(v.dataCache, cacheKey)
delete(v.listCache, xPath)
v.db.Rem(xPath, name)
}
func (v *DBReadCache) makeDataCacheKey(xPath, name string) [2]string {
return [2]string{xPath, name}
}
package settings
import "server/log"
type DBReadCache struct {
db TorrServerDB
listCache map[string][]string
dataCache map[[2]string][]byte
}
func NewDBReadCache(db TorrServerDB) TorrServerDB {
cdb := &DBReadCache{
db: db,
listCache: map[string][]string{},
dataCache: map[[2]string][]byte{},
}
return cdb
}
func (v *DBReadCache) CloseDB() {
v.db.CloseDB()
v.db = nil
v.listCache = nil
v.dataCache = nil
}
func (v *DBReadCache) Get(xPath, name string) []byte {
cacheKey := v.makeDataCacheKey(xPath, name)
if data, ok := v.dataCache[cacheKey]; ok {
return data
}
data := v.db.Get(xPath, name)
v.dataCache[cacheKey] = data
return data
}
func (v *DBReadCache) Set(xPath, name string, value []byte) {
if ReadOnly {
log.TLogln("DB.Set: Read-only DB mode!", name)
return
}
cacheKey := v.makeDataCacheKey(xPath, name)
v.dataCache[cacheKey] = value
delete(v.listCache, xPath)
v.db.Set(xPath, name, value)
}
func (v *DBReadCache) List(xPath string) []string {
if names, ok := v.listCache[xPath]; ok {
return names
}
names := v.db.List(xPath)
v.listCache[xPath] = names
return names
}
func (v *DBReadCache) Rem(xPath, name string) {
if ReadOnly {
log.TLogln("DB.Rem: Read-only DB mode!", name)
return
}
cacheKey := v.makeDataCacheKey(xPath, name)
delete(v.dataCache, cacheKey)
delete(v.listCache, xPath)
v.db.Rem(xPath, name)
}
func (v *DBReadCache) makeDataCacheKey(xPath, name string) [2]string {
return [2]string{xPath, name}
}

View File

@@ -1,159 +1,159 @@
package settings
import (
"encoding/json"
"errors"
"fmt"
"io/fs"
"os"
"path/filepath"
"server/log"
"strings"
"sync"
)
type JsonDB struct {
Path string
filenameDelimiter string
filenameExtension string
fileMode fs.FileMode
xPathDelimeter string
}
var jsonDbLocks = make(map[string]*sync.Mutex)
func NewJsonDB() TorrServerDB {
settingsDB := &JsonDB{
Path: Path,
filenameDelimiter: ".",
filenameExtension: ".json",
fileMode: fs.FileMode(0o666),
xPathDelimeter: "/",
}
return settingsDB
}
func (v *JsonDB) CloseDB() {
// Not necessary
}
func (v *JsonDB) Set(xPath, name string, value []byte) {
var err error = nil
jsonObj := map[string]interface{}{}
if err := json.Unmarshal(value, &jsonObj); err == nil {
if filename, err := v.xPathToFilename(xPath); err == nil {
v.lock(filename)
defer v.unlock(filename)
if root, err := v.readJsonFileAsMap(filename); err == nil {
root[name] = jsonObj
if err = v.writeMapAsJsonFile(filename, root); err == nil {
return
}
}
}
}
v.log(fmt.Sprintf("Set: error writing entry %s->%s", xPath, name), err)
}
func (v *JsonDB) Get(xPath, name string) []byte {
var err error = nil
if filename, err := v.xPathToFilename(xPath); err == nil {
v.lock(filename)
defer v.unlock(filename)
if root, err := v.readJsonFileAsMap(filename); err == nil {
if jsonData, ok := root[name]; ok {
if byteData, err := json.Marshal(jsonData); err == nil {
return byteData
}
} else {
// We assume this is not 'error' but 'no entry' which is normal
return nil
}
}
}
v.log(fmt.Sprintf("Get: error reading entry %s->%s", xPath, name), err)
return nil
}
func (v *JsonDB) List(xPath string) []string {
var err error = nil
if filename, err := v.xPathToFilename(xPath); err == nil {
v.lock(filename)
defer v.unlock(filename)
if root, err := v.readJsonFileAsMap(filename); err == nil {
nameList := make([]string, 0, len(root))
for k := range root {
nameList = append(nameList, k)
}
return nameList
}
}
v.log(fmt.Sprintf("List: error reading entries in xPath %s", xPath), err)
return nil
}
func (v *JsonDB) Rem(xPath, name string) {
var err error = nil
if filename, err := v.xPathToFilename(xPath); err == nil {
v.lock(filename)
defer v.unlock(filename)
if root, err := v.readJsonFileAsMap(filename); err == nil {
delete(root, name)
v.writeMapAsJsonFile(filename, root)
return
}
}
v.log(fmt.Sprintf("Rem: error removing entry %s->%s", xPath, name), err)
}
func (v *JsonDB) lock(filename string) {
var mtx sync.Mutex
if mtx, ok := jsonDbLocks[filename]; !ok {
mtx = new(sync.Mutex)
jsonDbLocks[v.Path] = mtx
}
mtx.Lock()
}
func (v *JsonDB) unlock(filename string) {
if mtx, ok := jsonDbLocks[filename]; ok {
mtx.Unlock()
}
}
func (v *JsonDB) xPathToFilename(xPath string) (string, error) {
if pathComponents := strings.Split(xPath, v.xPathDelimeter); len(pathComponents) > 0 {
return strings.ToLower(strings.Join(pathComponents, v.filenameDelimiter) + v.filenameExtension), nil
}
return "", errors.New("xPath has no components")
}
func (v *JsonDB) readJsonFileAsMap(filename string) (map[string]interface{}, error) {
var err error = nil
jsonData := map[string]interface{}{}
path := filepath.Join(v.Path, filename)
if fileData, err := os.ReadFile(path); err == nil {
err = json.Unmarshal(fileData, &jsonData)
}
return jsonData, err
}
func (v *JsonDB) writeMapAsJsonFile(filename string, o map[string]interface{}) error {
var err error = nil
path := filepath.Join(v.Path, filename)
if fileData, err := json.MarshalIndent(o, "", " "); err == nil {
err = os.WriteFile(path, fileData, v.fileMode)
}
return err
}
func (v *JsonDB) log(s string, params ...interface{}) {
if len(params) > 0 {
log.TLogln(fmt.Sprintf("JsonDB: %s: %s", s, fmt.Sprint(params...)))
} else {
log.TLogln(fmt.Sprintf("JsonDB: %s", s))
}
}
package settings
import (
"encoding/json"
"errors"
"fmt"
"io/fs"
"os"
"path/filepath"
"strings"
"sync"
"server/log"
)
type JsonDB struct {
Path string
filenameDelimiter string
filenameExtension string
fileMode fs.FileMode
xPathDelimeter string
}
var jsonDbLocks = make(map[string]*sync.Mutex)
func NewJsonDB() TorrServerDB {
settingsDB := &JsonDB{
Path: Path,
filenameDelimiter: ".",
filenameExtension: ".json",
fileMode: fs.FileMode(0o666),
xPathDelimeter: "/",
}
return settingsDB
}
func (v *JsonDB) CloseDB() {
// Not necessary
}
func (v *JsonDB) Set(xPath, name string, value []byte) {
var err error = nil
jsonObj := map[string]interface{}{}
if err := json.Unmarshal(value, &jsonObj); err == nil {
if filename, err := v.xPathToFilename(xPath); err == nil {
v.lock(filename)
defer v.unlock(filename)
if root, err := v.readJsonFileAsMap(filename); err == nil {
root[name] = jsonObj
if err = v.writeMapAsJsonFile(filename, root); err == nil {
return
}
}
}
}
v.log(fmt.Sprintf("Set: error writing entry %s->%s", xPath, name), err)
}
func (v *JsonDB) Get(xPath, name string) []byte {
var err error = nil
if filename, err := v.xPathToFilename(xPath); err == nil {
v.lock(filename)
defer v.unlock(filename)
if root, err := v.readJsonFileAsMap(filename); err == nil {
if jsonData, ok := root[name]; ok {
if byteData, err := json.Marshal(jsonData); err == nil {
return byteData
}
} else {
// We assume this is not 'error' but 'no entry' which is normal
return nil
}
}
}
v.log(fmt.Sprintf("Get: error reading entry %s->%s", xPath, name), err)
return nil
}
func (v *JsonDB) List(xPath string) []string {
var err error = nil
if filename, err := v.xPathToFilename(xPath); err == nil {
v.lock(filename)
defer v.unlock(filename)
if root, err := v.readJsonFileAsMap(filename); err == nil {
nameList := make([]string, 0, len(root))
for k := range root {
nameList = append(nameList, k)
}
return nameList
}
}
v.log(fmt.Sprintf("List: error reading entries in xPath %s", xPath), err)
return nil
}
func (v *JsonDB) Rem(xPath, name string) {
var err error = nil
if filename, err := v.xPathToFilename(xPath); err == nil {
v.lock(filename)
defer v.unlock(filename)
if root, err := v.readJsonFileAsMap(filename); err == nil {
delete(root, name)
v.writeMapAsJsonFile(filename, root)
return
}
}
v.log(fmt.Sprintf("Rem: error removing entry %s->%s", xPath, name), err)
}
func (v *JsonDB) lock(filename string) {
var mtx sync.Mutex
if mtx, ok := jsonDbLocks[filename]; !ok {
mtx = new(sync.Mutex)
jsonDbLocks[v.Path] = mtx
}
mtx.Lock()
}
func (v *JsonDB) unlock(filename string) {
if mtx, ok := jsonDbLocks[filename]; ok {
mtx.Unlock()
}
}
func (v *JsonDB) xPathToFilename(xPath string) (string, error) {
if pathComponents := strings.Split(xPath, v.xPathDelimeter); len(pathComponents) > 0 {
return strings.ToLower(strings.Join(pathComponents, v.filenameDelimiter) + v.filenameExtension), nil
}
return "", errors.New("xPath has no components")
}
func (v *JsonDB) readJsonFileAsMap(filename string) (map[string]interface{}, error) {
var err error = nil
jsonData := map[string]interface{}{}
path := filepath.Join(v.Path, filename)
if fileData, err := os.ReadFile(path); err == nil {
err = json.Unmarshal(fileData, &jsonData)
}
return jsonData, err
}
func (v *JsonDB) writeMapAsJsonFile(filename string, o map[string]interface{}) error {
var err error = nil
path := filepath.Join(v.Path, filename)
if fileData, err := json.MarshalIndent(o, "", " "); err == nil {
err = os.WriteFile(path, fileData, v.fileMode)
}
return err
}
func (v *JsonDB) log(s string, params ...interface{}) {
if len(params) > 0 {
log.TLogln(fmt.Sprintf("JsonDB: %s: %s", s, fmt.Sprint(params...)))
} else {
log.TLogln(fmt.Sprintf("JsonDB: %s", s))
}
}

View File

@@ -8,6 +8,7 @@ import (
"os"
"path/filepath"
"reflect"
"server/log"
"server/web/api/utils"

View File

@@ -54,7 +54,6 @@ func InitSets(readOnly, searchWA bool) {
}
loadBTSets()
Migrate1()
}
func CloseDB() {

View File

@@ -1,9 +1,9 @@
package settings
type TorrServerDB interface {
CloseDB()
Get(xPath, name string) []byte
Set(xPath, name string, value []byte)
List(xPath string) []string
Rem(xPath, name string)
}
package settings
type TorrServerDB interface {
CloseDB()
Get(xPath, name string) []byte
Set(xPath, name string, value []byte)
List(xPath string) []string
Rem(xPath, name string)
}

View File

@@ -1,118 +1,119 @@
package settings
import (
"errors"
"fmt"
"reflect"
"server/log"
"sort"
"strings"
"golang.org/x/exp/slices"
)
type XPathDBRouter struct {
dbs []TorrServerDB
routes []string
route2db map[string]TorrServerDB
dbNames map[TorrServerDB]string
}
func NewXPathDBRouter() *XPathDBRouter {
router := &XPathDBRouter{
dbs: []TorrServerDB{},
dbNames: map[TorrServerDB]string{},
routes: []string{},
route2db: map[string]TorrServerDB{},
}
return router
}
func (v *XPathDBRouter) RegisterRoute(db TorrServerDB, xPath string) error {
newRoute := v.xPathToRoute(xPath)
if slices.Contains(v.routes, newRoute) {
return errors.New(fmt.Sprintf("route \"%s\" already in routing table", newRoute))
}
// First DB becomes Default DB with default route
if len(v.dbs) == 0 && len(newRoute) != 0 {
v.RegisterRoute(db, "")
}
if !slices.Contains(v.dbs, db) {
v.dbs = append(v.dbs, db)
v.dbNames[db] = reflect.TypeOf(db).Elem().Name()
v.log(fmt.Sprintf("Registered new DB \"%s\", total %d DBs registered", v.getDBName(db), len(v.dbs)))
}
v.route2db[newRoute] = db
v.routes = append(v.routes, newRoute)
// Sort routes by length descending.
// It is important later to help selecting
// most suitable route in getDBForXPath(xPath)
sort.Slice(v.routes, func(iLeft, iRight int) bool {
return len(v.routes[iLeft]) > len(v.routes[iRight])
})
v.log(fmt.Sprintf("Registered new route \"%s\" for DB \"%s\", total %d routes", newRoute, v.getDBName(db), len(v.routes)))
return nil
}
func (v *XPathDBRouter) xPathToRoute(xPath string) string {
return strings.ToLower(strings.TrimSpace(xPath))
}
func (v *XPathDBRouter) getDBForXPath(xPath string) TorrServerDB {
if len(v.dbs) == 0 {
return nil
}
lookup_route := v.xPathToRoute(xPath)
var db TorrServerDB = nil
// Expected v.routes sorted by length descending
for _, route_prefix := range v.routes {
if strings.HasPrefix(lookup_route, route_prefix) {
db = v.route2db[route_prefix]
break
}
}
return db
}
func (v *XPathDBRouter) Get(xPath, name string) []byte {
return v.getDBForXPath(xPath).Get(xPath, name)
}
func (v *XPathDBRouter) Set(xPath, name string, value []byte) {
v.getDBForXPath(xPath).Set(xPath, name, value)
}
func (v *XPathDBRouter) List(xPath string) []string {
return v.getDBForXPath(xPath).List(xPath)
}
func (v *XPathDBRouter) Rem(xPath, name string) {
v.getDBForXPath(xPath).Rem(xPath, name)
}
func (v *XPathDBRouter) CloseDB() {
for _, db := range v.dbs {
db.CloseDB()
}
v.dbs = nil
v.routes = nil
v.route2db = nil
v.dbNames = nil
}
func (v *XPathDBRouter) getDBName(db TorrServerDB) string {
return v.dbNames[db]
}
func (v *XPathDBRouter) log(s string, params ...interface{}) {
if len(params) > 0 {
log.TLogln(fmt.Sprintf("XPathDBRouter: %s: %s", s, fmt.Sprint(params...)))
} else {
log.TLogln(fmt.Sprintf("XPathDBRouter: %s", s))
}
}
package settings
import (
"errors"
"fmt"
"reflect"
"sort"
"strings"
"server/log"
"golang.org/x/exp/slices"
)
type XPathDBRouter struct {
dbs []TorrServerDB
routes []string
route2db map[string]TorrServerDB
dbNames map[TorrServerDB]string
}
func NewXPathDBRouter() *XPathDBRouter {
router := &XPathDBRouter{
dbs: []TorrServerDB{},
dbNames: map[TorrServerDB]string{},
routes: []string{},
route2db: map[string]TorrServerDB{},
}
return router
}
func (v *XPathDBRouter) RegisterRoute(db TorrServerDB, xPath string) error {
newRoute := v.xPathToRoute(xPath)
if slices.Contains(v.routes, newRoute) {
return errors.New(fmt.Sprintf("route \"%s\" already in routing table", newRoute))
}
// First DB becomes Default DB with default route
if len(v.dbs) == 0 && len(newRoute) != 0 {
v.RegisterRoute(db, "")
}
if !slices.Contains(v.dbs, db) {
v.dbs = append(v.dbs, db)
v.dbNames[db] = reflect.TypeOf(db).Elem().Name()
v.log(fmt.Sprintf("Registered new DB \"%s\", total %d DBs registered", v.getDBName(db), len(v.dbs)))
}
v.route2db[newRoute] = db
v.routes = append(v.routes, newRoute)
// Sort routes by length descending.
// It is important later to help selecting
// most suitable route in getDBForXPath(xPath)
sort.Slice(v.routes, func(iLeft, iRight int) bool {
return len(v.routes[iLeft]) > len(v.routes[iRight])
})
v.log(fmt.Sprintf("Registered new route \"%s\" for DB \"%s\", total %d routes", newRoute, v.getDBName(db), len(v.routes)))
return nil
}
func (v *XPathDBRouter) xPathToRoute(xPath string) string {
return strings.ToLower(strings.TrimSpace(xPath))
}
func (v *XPathDBRouter) getDBForXPath(xPath string) TorrServerDB {
if len(v.dbs) == 0 {
return nil
}
lookup_route := v.xPathToRoute(xPath)
var db TorrServerDB = nil
// Expected v.routes sorted by length descending
for _, route_prefix := range v.routes {
if strings.HasPrefix(lookup_route, route_prefix) {
db = v.route2db[route_prefix]
break
}
}
return db
}
func (v *XPathDBRouter) Get(xPath, name string) []byte {
return v.getDBForXPath(xPath).Get(xPath, name)
}
func (v *XPathDBRouter) Set(xPath, name string, value []byte) {
v.getDBForXPath(xPath).Set(xPath, name, value)
}
func (v *XPathDBRouter) List(xPath string) []string {
return v.getDBForXPath(xPath).List(xPath)
}
func (v *XPathDBRouter) Rem(xPath, name string) {
v.getDBForXPath(xPath).Rem(xPath, name)
}
func (v *XPathDBRouter) CloseDB() {
for _, db := range v.dbs {
db.CloseDB()
}
v.dbs = nil
v.routes = nil
v.route2db = nil
v.dbNames = nil
}
func (v *XPathDBRouter) getDBName(db TorrServerDB) string {
return v.dbNames[db]
}
func (v *XPathDBRouter) log(s string, params ...interface{}) {
if len(params) > 0 {
log.TLogln(fmt.Sprintf("XPathDBRouter: %s: %s", s, fmt.Sprint(params...)))
} else {
log.TLogln(fmt.Sprintf("XPathDBRouter: %s", s))
}
}