feat(db): add site store

This commit is contained in:
hexxa 2021-10-09 11:49:47 +08:00 committed by Hexxa
parent 4d8a8999a5
commit a7de2e6399
6 changed files with 260 additions and 27 deletions

View file

@ -0,0 +1,115 @@
package sitestore
import (
"encoding/json"
"errors"
"fmt"
"sync"
"time"
"github.com/ihexxa/quickshare/src/kvstore"
)
const (
InitNs = "SiteInit"
SiteNs = "Site"
InitTimeKey = "initTime"
SiteCfgKey = "siteCfg"
)
var (
ErrNotFound = errors.New("site config not found")
)
func IsNotFound(err error) bool {
return err == ErrNotFound
}
type ISiteStore interface {
SetClientCfg(cfg *ClientConfig) error
GetCfg() (*SiteConfig, error)
}
type ClientConfig struct {
SiteName string `json:"siteName"`
SiteDesc string `json:"siteDesc"`
Bg *BgConfig `json:"bg"`
}
type BgConfig struct {
Url string `json:"url"`
Repeat string `json:"repeat"`
Position string `json:"position"`
Align string `json:"align"`
}
type SiteConfig struct {
ClientCfg *ClientConfig `json:"clientCfg"`
}
type SiteStore struct {
mtx *sync.RWMutex
store kvstore.IKVStore
}
func NewSiteStore(store kvstore.IKVStore) (*SiteStore, error) {
_, ok := store.GetStringIn(InitNs, InitTimeKey)
if !ok {
var err error
for _, nsName := range []string{
InitNs,
SiteNs,
} {
if err = store.AddNamespace(nsName); err != nil {
return nil, err
}
}
}
err := store.SetStringIn(InitNs, InitTimeKey, fmt.Sprintf("%d", time.Now().Unix()))
if err != nil {
return nil, err
}
return &SiteStore{
store: store,
mtx: &sync.RWMutex{},
}, nil
}
func (fi *SiteStore) SetClientCfg(cfg *ClientConfig) error {
fi.mtx.Lock()
defer fi.mtx.Unlock()
siteCfg := &SiteConfig{}
cfgStr, ok := fi.store.GetStringIn(SiteNs, SiteCfgKey)
if ok {
err := json.Unmarshal([]byte(cfgStr), siteCfg)
if err != nil {
return err
}
}
siteCfg.ClientCfg = cfg
cfgBytes, err := json.Marshal(siteCfg)
if err != nil {
return err
}
return fi.store.SetStringIn(SiteNs, SiteCfgKey, string(cfgBytes))
}
func (fi *SiteStore) GetCfg() (*SiteConfig, error) {
fi.mtx.RLock()
defer fi.mtx.RUnlock()
cfgStr, ok := fi.store.GetStringIn(SiteNs, SiteCfgKey)
if !ok {
return nil, ErrNotFound
}
siteCfg := &SiteConfig{}
err := json.Unmarshal([]byte(cfgStr), siteCfg)
if err != nil {
return nil, err
}
return siteCfg, nil
}

View file

@ -0,0 +1,57 @@
package sitestore
import (
"io/ioutil"
"os"
"reflect"
"testing"
"github.com/ihexxa/quickshare/src/kvstore/boltdbpvd"
)
func TestSiteStore(t *testing.T) {
testSiteMethods := func(t *testing.T, store ISiteStore) {
siteCfg := &SiteConfig{
ClientCfg: &ClientConfig{
SiteName: "quickshare",
SiteDesc: "simpel file sharing",
Bg: &BgConfig{
Url: "/imgs/bg.jpg",
Repeat: "no-repeat",
Position: "fixed",
Align: "center",
},
},
}
err := store.SetClientCfg(siteCfg.ClientCfg)
if err != nil {
t.Fatal(err)
}
newSiteCfg, err := store.GetCfg()
if err != nil {
t.Fatal(err)
} else if !reflect.DeepEqual(newSiteCfg, siteCfg) {
t.Fatalf("not equal new(%v) original(%v)", newSiteCfg, siteCfg)
}
}
t.Run("Get/Set", func(t *testing.T) {
rootPath, err := ioutil.TempDir("./", "quickshare_sitestore_test_")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(rootPath)
kvstore := boltdbpvd.New(rootPath, 1024)
defer kvstore.Close()
store, err := NewSiteStore(kvstore)
if err != nil {
t.Fatal("fail to new kvstore", err)
}
testSiteMethods(t, store)
})
}

View file

@ -6,11 +6,12 @@ import (
"github.com/ihexxa/quickshare/src/cryptoutil"
"github.com/ihexxa/quickshare/src/db/fileinfostore"
"github.com/ihexxa/quickshare/src/db/sitestore"
"github.com/ihexxa/quickshare/src/db/userstore"
"github.com/ihexxa/quickshare/src/fs"
"github.com/ihexxa/quickshare/src/idgen"
"github.com/ihexxa/quickshare/src/iolimiter"
"github.com/ihexxa/quickshare/src/kvstore"
"github.com/ihexxa/quickshare/src/db/userstore"
"github.com/ihexxa/quickshare/src/worker"
)
@ -28,6 +29,7 @@ type Deps struct {
kv kvstore.IKVStore
users userstore.IUserStore
fileInfos fileinfostore.IFileInfoStore
siteStore sitestore.ISiteStore
id idgen.IIDGen
logger *zap.SugaredLogger
limiter iolimiter.ILimiter
@ -94,6 +96,14 @@ func (deps *Deps) SetFileInfos(fileInfos fileinfostore.IFileInfoStore) {
deps.fileInfos = fileInfos
}
func (deps *Deps) SiteStore() sitestore.ISiteStore {
return deps.siteStore
}
func (deps *Deps) SetSiteStore(siteStore sitestore.ISiteStore) {
deps.siteStore = siteStore
}
func (deps *Deps) Limiter() iolimiter.ILimiter {
return deps.limiter
}

View file

@ -1,26 +0,0 @@
package settings
import (
"github.com/gin-gonic/gin"
"github.com/ihexxa/gocfg"
"github.com/ihexxa/quickshare/src/depidx"
q "github.com/ihexxa/quickshare/src/handlers"
)
type SettingsSvc struct {
cfg gocfg.ICfg
deps *depidx.Deps
}
func NewSettingsSvc(cfg gocfg.ICfg, deps *depidx.Deps) (*SettingsSvc, error) {
return &SettingsSvc{
cfg: cfg,
deps: deps,
}, nil
}
func (h *SettingsSvc) Health(c *gin.Context) {
// TODO: currently it checks nothing
c.JSON(q.Resp(200))
}

View file

@ -0,0 +1,71 @@
package settings
import (
"errors"
"github.com/gin-gonic/gin"
"github.com/ihexxa/gocfg"
"github.com/ihexxa/quickshare/src/db/sitestore"
"github.com/ihexxa/quickshare/src/depidx"
q "github.com/ihexxa/quickshare/src/handlers"
)
type SettingsSvc struct {
cfg gocfg.ICfg
deps *depidx.Deps
}
func NewSettingsSvc(cfg gocfg.ICfg, deps *depidx.Deps) (*SettingsSvc, error) {
return &SettingsSvc{
cfg: cfg,
deps: deps,
}, nil
}
func (h *SettingsSvc) Health(c *gin.Context) {
// TODO: currently it checks nothing
c.JSON(q.Resp(200))
}
type ClientCfgMsg struct {
ClientCfg *sitestore.ClientConfig
}
func (h *SettingsSvc) GetClientCfg(c *gin.Context) {
// TODO: add cache
siteCfg, err := h.deps.SiteStore().GetCfg()
if err != nil {
c.JSON(q.ErrResp(c, 500, err))
return
}
c.JSON(200, &ClientCfgMsg{ClientCfg: siteCfg.ClientCfg})
}
func (h *SettingsSvc) SetClientCfg(c *gin.Context) {
var err error
req := &ClientCfgMsg{}
if err = c.ShouldBindJSON(&req); err != nil {
c.JSON(q.ErrResp(c, 400, err))
return
}
if err = validateClientCfg(req.ClientCfg); err != nil {
c.JSON(q.ErrResp(c, 400, err))
return
}
err = h.deps.SiteStore().SetClientCfg(req.ClientCfg)
if err != nil {
c.JSON(q.ErrResp(c, 500, err))
return
}
c.JSON(q.Resp(200))
}
func validateClientCfg(cfg *sitestore.ClientConfig) error {
if cfg.SiteName == "" {
return errors.New("site name is empty")
}
return nil
}

View file

@ -24,6 +24,7 @@ import (
"github.com/ihexxa/quickshare/src/cryptoutil/jwt"
"github.com/ihexxa/quickshare/src/db/fileinfostore"
"github.com/ihexxa/quickshare/src/db/sitestore"
"github.com/ihexxa/quickshare/src/db/userstore"
"github.com/ihexxa/quickshare/src/depidx"
"github.com/ihexxa/quickshare/src/fs"
@ -124,6 +125,10 @@ func initDeps(cfg gocfg.ICfg) *depidx.Deps {
if err != nil {
panic(fmt.Sprintf("fail to init file info store: %s", err))
}
siteStore, err := sitestore.NewSiteStore(kv)
if err != nil {
panic(fmt.Sprintf("fail to init site config store: %s", err))
}
limiterCap := cfg.IntOr("Users.LimiterCapacity", 10000)
limiterCyc := cfg.IntOr("Users.LimiterCyc", 1000)
@ -135,6 +140,7 @@ func initDeps(cfg gocfg.ICfg) *depidx.Deps {
deps.SetKV(kv)
deps.SetUsers(users)
deps.SetFileInfos(fileInfos)
deps.SetSiteStore(siteStore)
deps.SetID(ider)
deps.SetLog(logger)
deps.SetLimiter(limiter)