mirror of
https://github.com/yusing/godoxy.git
synced 2025-05-19 20:32:35 +02:00
refactor: unify json load/saving with jsonstore
This commit is contained in:
parent
7461344004
commit
4a65de99a8
6 changed files with 38 additions and 88 deletions
|
@ -7,13 +7,11 @@ import (
|
|||
"sync"
|
||||
|
||||
"github.com/yusing/go-proxy/internal"
|
||||
"github.com/yusing/go-proxy/internal/api/v1/favicon"
|
||||
"github.com/yusing/go-proxy/internal/api/v1/query"
|
||||
"github.com/yusing/go-proxy/internal/auth"
|
||||
"github.com/yusing/go-proxy/internal/common"
|
||||
"github.com/yusing/go-proxy/internal/config"
|
||||
"github.com/yusing/go-proxy/internal/gperr"
|
||||
"github.com/yusing/go-proxy/internal/homepage"
|
||||
"github.com/yusing/go-proxy/internal/logging"
|
||||
"github.com/yusing/go-proxy/internal/logging/memlogger"
|
||||
"github.com/yusing/go-proxy/internal/metrics/systeminfo"
|
||||
|
@ -80,8 +78,6 @@ func main() {
|
|||
logging.Trace().Msg("trace enabled")
|
||||
parallel(
|
||||
internal.InitIconListCache,
|
||||
homepage.InitOverridesConfig,
|
||||
favicon.InitIconCache,
|
||||
systeminfo.Poller.Start,
|
||||
)
|
||||
|
||||
|
|
|
@ -2,14 +2,13 @@ package favicon
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/yusing/go-proxy/internal/common"
|
||||
"github.com/yusing/go-proxy/internal/jsonstore"
|
||||
"github.com/yusing/go-proxy/internal/logging"
|
||||
route "github.com/yusing/go-proxy/internal/route/types"
|
||||
"github.com/yusing/go-proxy/internal/task"
|
||||
"github.com/yusing/go-proxy/internal/utils"
|
||||
)
|
||||
|
||||
type cacheEntry struct {
|
||||
|
@ -18,27 +17,14 @@ type cacheEntry struct {
|
|||
}
|
||||
|
||||
// cache key can be absolute url or route name.
|
||||
var (
|
||||
iconCache = make(map[string]*cacheEntry)
|
||||
iconCacheMu sync.RWMutex
|
||||
)
|
||||
var iconCache = jsonstore.Store[*cacheEntry](common.NamespaceIconCache)
|
||||
|
||||
const (
|
||||
iconCacheTTL = 3 * 24 * time.Hour
|
||||
cleanUpInterval = time.Hour
|
||||
)
|
||||
|
||||
func InitIconCache() {
|
||||
iconCacheMu.Lock()
|
||||
defer iconCacheMu.Unlock()
|
||||
|
||||
err := utils.LoadJSONIfExist(common.IconCachePath, &iconCache)
|
||||
if err != nil {
|
||||
logging.Error().Err(err).Msg("failed to load icon cache")
|
||||
} else if len(iconCache) > 0 {
|
||||
logging.Info().Int("count", len(iconCache)).Msg("icon cache loaded")
|
||||
}
|
||||
|
||||
func init() {
|
||||
go func() {
|
||||
cleanupTicker := time.NewTicker(cleanUpInterval)
|
||||
defer cleanupTicker.Stop()
|
||||
|
@ -51,29 +37,13 @@ func InitIconCache() {
|
|||
}
|
||||
}
|
||||
}()
|
||||
|
||||
task.OnProgramExit("save_favicon_cache", func() {
|
||||
iconCacheMu.Lock()
|
||||
defer iconCacheMu.Unlock()
|
||||
|
||||
if len(iconCache) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if err := utils.SaveJSON(common.IconCachePath, &iconCache, 0o644); err != nil {
|
||||
logging.Error().Err(err).Msg("failed to save icon cache")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func pruneExpiredIconCache() {
|
||||
iconCacheMu.Lock()
|
||||
defer iconCacheMu.Unlock()
|
||||
|
||||
nPruned := 0
|
||||
for key, icon := range iconCache {
|
||||
for key, icon := range iconCache.Range {
|
||||
if icon.IsExpired() {
|
||||
delete(iconCache, key)
|
||||
iconCache.Delete(key)
|
||||
nPruned++
|
||||
}
|
||||
}
|
||||
|
@ -87,16 +57,11 @@ func routeKey(r route.HTTPRoute) string {
|
|||
}
|
||||
|
||||
func PruneRouteIconCache(route route.HTTPRoute) {
|
||||
iconCacheMu.Lock()
|
||||
defer iconCacheMu.Unlock()
|
||||
delete(iconCache, routeKey(route))
|
||||
iconCache.Delete(routeKey(route))
|
||||
}
|
||||
|
||||
func loadIconCache(key string) *fetchResult {
|
||||
iconCacheMu.RLock()
|
||||
defer iconCacheMu.RUnlock()
|
||||
|
||||
icon, ok := iconCache[key]
|
||||
icon, ok := iconCache.Load(key)
|
||||
if ok && icon != nil {
|
||||
logging.Debug().
|
||||
Str("key", key).
|
||||
|
@ -108,9 +73,7 @@ func loadIconCache(key string) *fetchResult {
|
|||
}
|
||||
|
||||
func storeIconCache(key string, icon []byte) {
|
||||
iconCacheMu.Lock()
|
||||
defer iconCacheMu.Unlock()
|
||||
iconCache[key] = &cacheEntry{Icon: icon, LastAccess: time.Now()}
|
||||
iconCache.Store(key, &cacheEntry{Icon: icon, LastAccess: time.Now()})
|
||||
}
|
||||
|
||||
func (e *cacheEntry) IsExpired() bool {
|
||||
|
|
|
@ -10,13 +10,16 @@ const (
|
|||
DotEnvPath = ".env"
|
||||
DotEnvExamplePath = ".env.example"
|
||||
|
||||
ConfigBasePath = "config"
|
||||
ConfigFileName = "config.yml"
|
||||
ConfigExampleFileName = "config.example.yml"
|
||||
ConfigPath = ConfigBasePath + "/" + ConfigFileName
|
||||
HomepageJSONConfigPath = ConfigBasePath + "/.homepage.json"
|
||||
IconListCachePath = ConfigBasePath + "/.icon_list_cache.json"
|
||||
IconCachePath = ConfigBasePath + "/.icon_cache.json"
|
||||
ConfigBasePath = "config"
|
||||
ConfigFileName = "config.yml"
|
||||
ConfigExampleFileName = "config.example.yml"
|
||||
ConfigPath = ConfigBasePath + "/" + ConfigFileName
|
||||
|
||||
IconListCachePath = ConfigBasePath + "/.icon_list_cache.json"
|
||||
IconCachePath = ConfigBasePath + "/.icon_cache.json"
|
||||
|
||||
NamespaceHomepageOverrides = ".homepage"
|
||||
NamespaceIconCache = ".icon_cache"
|
||||
|
||||
MiddlewareComposeBasePath = ConfigBasePath + "/middlewares"
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
)
|
||||
|
||||
func TestOverrideItem(t *testing.T) {
|
||||
InitOverridesConfig()
|
||||
a := &Item{
|
||||
Alias: "foo",
|
||||
ItemConfig: &ItemConfig{
|
||||
|
|
|
@ -4,9 +4,7 @@ import (
|
|||
"sync"
|
||||
|
||||
"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"
|
||||
"github.com/yusing/go-proxy/internal/jsonstore"
|
||||
)
|
||||
|
||||
type OverrideConfig struct {
|
||||
|
@ -17,34 +15,7 @@ type OverrideConfig struct {
|
|||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
var overrideConfigInstance = &OverrideConfig{
|
||||
ItemOverrides: make(map[string]*ItemConfig),
|
||||
DisplayOrder: make(map[string]int),
|
||||
CategoryOrder: make(map[string]int),
|
||||
ItemVisibility: make(map[string]bool),
|
||||
}
|
||||
|
||||
func InitOverridesConfig() {
|
||||
overrideConfigInstance.mu.Lock()
|
||||
defer overrideConfigInstance.mu.Unlock()
|
||||
|
||||
err := utils.LoadJSONIfExist(common.HomepageJSONConfigPath, overrideConfigInstance)
|
||||
if err != nil {
|
||||
logging.Error().Err(err).Msg("failed to load homepage overrides config")
|
||||
} else if len(overrideConfigInstance.ItemOverrides) > 0 {
|
||||
logging.Info().
|
||||
Int("count", len(overrideConfigInstance.ItemOverrides)).
|
||||
Msg("homepage overrides config loaded")
|
||||
}
|
||||
task.OnProgramExit("save_homepage_json_config", func() {
|
||||
if len(overrideConfigInstance.ItemOverrides) == 0 {
|
||||
return
|
||||
}
|
||||
if err := utils.SaveJSON(common.HomepageJSONConfigPath, overrideConfigInstance, 0o644); err != nil {
|
||||
logging.Error().Err(err).Msg("failed to save homepage overrides config")
|
||||
}
|
||||
})
|
||||
}
|
||||
var overrideConfigInstance = jsonstore.Object[OverrideConfig](common.NamespaceHomepageOverrides)
|
||||
|
||||
func GetOverrideConfig() *OverrideConfig {
|
||||
return overrideConfigInstance
|
||||
|
|
|
@ -2,6 +2,7 @@ package jsonstore
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
|
@ -46,6 +47,8 @@ func load() error {
|
|||
for ns, store := range stores.m {
|
||||
if err := utils.LoadJSONIfExist(filepath.Join(storesPath, string(ns)+".json"), &store); err != nil {
|
||||
errs.Add(err)
|
||||
} else {
|
||||
logging.Info().Str("name", string(ns)).Msg("store loaded")
|
||||
}
|
||||
}
|
||||
return errs.Error()
|
||||
|
@ -74,6 +77,21 @@ func Store[VT any](namespace namespace) Typed[VT] {
|
|||
return m
|
||||
}
|
||||
|
||||
func Object[VT any](namespace namespace) *VT {
|
||||
stores.Lock()
|
||||
defer stores.Unlock()
|
||||
if s, ok := stores.m[namespace]; ok {
|
||||
v, ok := s.(*VT)
|
||||
if ok {
|
||||
return v
|
||||
}
|
||||
panic(fmt.Errorf("type mismatch: %T != %T", s, v))
|
||||
}
|
||||
v := new(VT)
|
||||
stores.m[namespace] = v
|
||||
return v
|
||||
}
|
||||
|
||||
func (s Typed[VT]) MarshalJSON() ([]byte, error) {
|
||||
tmp := make(map[string]VT, s.Size())
|
||||
for k, v := range s.Range {
|
||||
|
|
Loading…
Add table
Reference in a new issue