mirror of
https://github.com/yusing/godoxy.git
synced 2026-04-24 09:18:31 +02:00
fix: json store marshaling, api handler
- code clean up - uncomment and simplify api auth handler - fix redirect url for frontend - proper redirect
This commit is contained in:
@@ -1,63 +0,0 @@
|
||||
package jsonstore
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"github.com/puzpuzpuz/xsync/v3"
|
||||
"github.com/yusing/go-proxy/internal/common"
|
||||
"github.com/yusing/go-proxy/internal/logging"
|
||||
"github.com/yusing/go-proxy/internal/task"
|
||||
"github.com/yusing/go-proxy/internal/utils"
|
||||
)
|
||||
|
||||
type jsonStoreInternal struct{ *xsync.MapOf[string, any] }
|
||||
type namespace string
|
||||
|
||||
var stores = make(map[namespace]jsonStoreInternal)
|
||||
var storesMu sync.Mutex
|
||||
var storesPath = filepath.Join(common.DataDir, "data.json")
|
||||
|
||||
func Initialize() {
|
||||
if err := load(); err != nil {
|
||||
logging.Error().Err(err).Msg("failed to load stores")
|
||||
}
|
||||
|
||||
task.OnProgramExit("save_stores", func() {
|
||||
if err := save(); err != nil {
|
||||
logging.Error().Err(err).Msg("failed to save stores")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func load() error {
|
||||
storesMu.Lock()
|
||||
defer storesMu.Unlock()
|
||||
if err := utils.LoadJSONIfExist(storesPath, &stores); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func save() error {
|
||||
storesMu.Lock()
|
||||
defer storesMu.Unlock()
|
||||
return utils.SaveJSON(storesPath, &stores, 0o644)
|
||||
}
|
||||
|
||||
func (s jsonStoreInternal) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(xsync.ToPlainMapOf(s.MapOf))
|
||||
}
|
||||
|
||||
func (s jsonStoreInternal) UnmarshalJSON(data []byte) error {
|
||||
var tmp map[string]any
|
||||
if err := json.Unmarshal(data, &tmp); err != nil {
|
||||
return err
|
||||
}
|
||||
s.MapOf = xsync.NewMapOf[string, any](xsync.WithPresize(len(tmp)))
|
||||
for k, v := range tmp {
|
||||
s.MapOf.Store(k, v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,47 +1,95 @@
|
||||
package jsonstore
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"github.com/puzpuzpuz/xsync/v3"
|
||||
"github.com/yusing/go-proxy/internal/common"
|
||||
"github.com/yusing/go-proxy/internal/gperr"
|
||||
"github.com/yusing/go-proxy/internal/logging"
|
||||
"github.com/yusing/go-proxy/internal/task"
|
||||
"github.com/yusing/go-proxy/internal/utils"
|
||||
)
|
||||
|
||||
type JSONStore[VT any] struct{ m jsonStoreInternal }
|
||||
type namespace string
|
||||
|
||||
func NewStore[VT any](namespace namespace) JSONStore[VT] {
|
||||
storesMu.Lock()
|
||||
defer storesMu.Unlock()
|
||||
if s, ok := stores[namespace]; ok {
|
||||
return JSONStore[VT]{s}
|
||||
type Typed[VT any] struct {
|
||||
*xsync.MapOf[string, VT]
|
||||
}
|
||||
|
||||
type storesMap struct {
|
||||
sync.RWMutex
|
||||
m map[namespace]any
|
||||
}
|
||||
|
||||
var stores = storesMap{m: make(map[namespace]any)}
|
||||
var storesPath = common.DataDir
|
||||
|
||||
func init() {
|
||||
if err := load(); err != nil {
|
||||
logging.Error().Err(err).Msg("failed to load stores")
|
||||
}
|
||||
m := jsonStoreInternal{xsync.NewMapOf[string, any]()}
|
||||
stores[namespace] = m
|
||||
return JSONStore[VT]{m}
|
||||
|
||||
task.OnProgramExit("save_stores", func() {
|
||||
if err := save(); err != nil {
|
||||
logging.Error().Err(err).Msg("failed to save stores")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (s JSONStore[VT]) Load(key string) (_ VT, _ bool) {
|
||||
value, ok := s.m.Load(key)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
return value.(VT), true
|
||||
}
|
||||
|
||||
func (s JSONStore[VT]) Has(key string) bool {
|
||||
_, ok := s.m.Load(key)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (s JSONStore[VT]) Store(key string, value VT) {
|
||||
s.m.Store(key, value)
|
||||
}
|
||||
|
||||
func (s JSONStore[VT]) Delete(key string) {
|
||||
s.m.Delete(key)
|
||||
}
|
||||
|
||||
func (s JSONStore[VT]) Iter(yield func(key string, value VT) bool) {
|
||||
for k, v := range s.m.Range {
|
||||
if !yield(k, v.(VT)) {
|
||||
return
|
||||
func load() error {
|
||||
stores.Lock()
|
||||
defer stores.Unlock()
|
||||
errs := gperr.NewBuilder("failed to load data stores")
|
||||
for ns, store := range stores.m {
|
||||
if err := utils.LoadJSONIfExist(filepath.Join(storesPath, string(ns)+".json"), &store); err != nil {
|
||||
errs.Add(err)
|
||||
}
|
||||
}
|
||||
return errs.Error()
|
||||
}
|
||||
|
||||
func save() error {
|
||||
stores.Lock()
|
||||
defer stores.Unlock()
|
||||
errs := gperr.NewBuilder("failed to save data stores")
|
||||
for ns, store := range stores.m {
|
||||
if err := utils.SaveJSON(filepath.Join(common.DataDir, string(ns)+".json"), &store, 0o644); err != nil {
|
||||
errs.Add(err)
|
||||
}
|
||||
}
|
||||
return errs.Error()
|
||||
}
|
||||
|
||||
func Store[VT any](namespace namespace) Typed[VT] {
|
||||
stores.Lock()
|
||||
defer stores.Unlock()
|
||||
if s, ok := stores.m[namespace]; ok {
|
||||
return s.(Typed[VT])
|
||||
}
|
||||
m := Typed[VT]{MapOf: xsync.NewMapOf[string, VT]()}
|
||||
stores.m[namespace] = m
|
||||
return m
|
||||
}
|
||||
|
||||
func (s Typed[VT]) MarshalJSON() ([]byte, error) {
|
||||
tmp := make(map[string]VT, s.Size())
|
||||
for k, v := range s.Range {
|
||||
tmp[k] = v
|
||||
}
|
||||
return json.Marshal(tmp)
|
||||
}
|
||||
|
||||
func (s Typed[VT]) UnmarshalJSON(data []byte) error {
|
||||
tmp := make(map[string]VT)
|
||||
if err := json.Unmarshal(data, &tmp); err != nil {
|
||||
return err
|
||||
}
|
||||
s.MapOf = xsync.NewMapOf[string, VT](xsync.WithPresize(len(tmp)))
|
||||
for k, v := range tmp {
|
||||
s.MapOf.Store(k, v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
)
|
||||
|
||||
func TestNewJSON(t *testing.T) {
|
||||
store := NewStore[string]("test")
|
||||
store := Store[string]("test")
|
||||
store.Store("a", "1")
|
||||
if v, _ := store.Load("a"); v != "1" {
|
||||
t.Fatal("expected 1, got", v)
|
||||
@@ -16,16 +16,16 @@ func TestNewJSON(t *testing.T) {
|
||||
func TestSaveLoad(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
storesPath = filepath.Join(tmpDir, "data.json")
|
||||
store := NewStore[string]("test")
|
||||
store := Store[string]("test")
|
||||
store.Store("a", "1")
|
||||
if err := save(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
stores = nil
|
||||
stores.m = nil
|
||||
if err := load(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
store = NewStore[string]("test")
|
||||
store = Store[string]("test")
|
||||
if v, _ := store.Load("a"); v != "1" {
|
||||
t.Fatal("expected 1, got", v)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user