feat(db): add site store
This commit is contained in:
parent
4d8a8999a5
commit
a7de2e6399
6 changed files with 260 additions and 27 deletions
115
src/db/sitestore/site_store.go
Normal file
115
src/db/sitestore/site_store.go
Normal 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
|
||||||
|
}
|
57
src/db/sitestore/site_store_test.go
Normal file
57
src/db/sitestore/site_store_test.go
Normal 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)
|
||||||
|
})
|
||||||
|
}
|
|
@ -6,11 +6,12 @@ import (
|
||||||
|
|
||||||
"github.com/ihexxa/quickshare/src/cryptoutil"
|
"github.com/ihexxa/quickshare/src/cryptoutil"
|
||||||
"github.com/ihexxa/quickshare/src/db/fileinfostore"
|
"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/fs"
|
||||||
"github.com/ihexxa/quickshare/src/idgen"
|
"github.com/ihexxa/quickshare/src/idgen"
|
||||||
"github.com/ihexxa/quickshare/src/iolimiter"
|
"github.com/ihexxa/quickshare/src/iolimiter"
|
||||||
"github.com/ihexxa/quickshare/src/kvstore"
|
"github.com/ihexxa/quickshare/src/kvstore"
|
||||||
"github.com/ihexxa/quickshare/src/db/userstore"
|
|
||||||
"github.com/ihexxa/quickshare/src/worker"
|
"github.com/ihexxa/quickshare/src/worker"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -28,6 +29,7 @@ type Deps struct {
|
||||||
kv kvstore.IKVStore
|
kv kvstore.IKVStore
|
||||||
users userstore.IUserStore
|
users userstore.IUserStore
|
||||||
fileInfos fileinfostore.IFileInfoStore
|
fileInfos fileinfostore.IFileInfoStore
|
||||||
|
siteStore sitestore.ISiteStore
|
||||||
id idgen.IIDGen
|
id idgen.IIDGen
|
||||||
logger *zap.SugaredLogger
|
logger *zap.SugaredLogger
|
||||||
limiter iolimiter.ILimiter
|
limiter iolimiter.ILimiter
|
||||||
|
@ -94,6 +96,14 @@ func (deps *Deps) SetFileInfos(fileInfos fileinfostore.IFileInfoStore) {
|
||||||
deps.fileInfos = fileInfos
|
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 {
|
func (deps *Deps) Limiter() iolimiter.ILimiter {
|
||||||
return deps.limiter
|
return deps.limiter
|
||||||
}
|
}
|
||||||
|
|
|
@ -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))
|
|
||||||
}
|
|
71
src/handlers/settings/handlers.go
Normal file
71
src/handlers/settings/handlers.go
Normal 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
|
||||||
|
}
|
|
@ -24,6 +24,7 @@ import (
|
||||||
|
|
||||||
"github.com/ihexxa/quickshare/src/cryptoutil/jwt"
|
"github.com/ihexxa/quickshare/src/cryptoutil/jwt"
|
||||||
"github.com/ihexxa/quickshare/src/db/fileinfostore"
|
"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/db/userstore"
|
||||||
"github.com/ihexxa/quickshare/src/depidx"
|
"github.com/ihexxa/quickshare/src/depidx"
|
||||||
"github.com/ihexxa/quickshare/src/fs"
|
"github.com/ihexxa/quickshare/src/fs"
|
||||||
|
@ -124,6 +125,10 @@ func initDeps(cfg gocfg.ICfg) *depidx.Deps {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("fail to init file info store: %s", err))
|
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)
|
limiterCap := cfg.IntOr("Users.LimiterCapacity", 10000)
|
||||||
limiterCyc := cfg.IntOr("Users.LimiterCyc", 1000)
|
limiterCyc := cfg.IntOr("Users.LimiterCyc", 1000)
|
||||||
|
@ -135,6 +140,7 @@ func initDeps(cfg gocfg.ICfg) *depidx.Deps {
|
||||||
deps.SetKV(kv)
|
deps.SetKV(kv)
|
||||||
deps.SetUsers(users)
|
deps.SetUsers(users)
|
||||||
deps.SetFileInfos(fileInfos)
|
deps.SetFileInfos(fileInfos)
|
||||||
|
deps.SetSiteStore(siteStore)
|
||||||
deps.SetID(ider)
|
deps.SetID(ider)
|
||||||
deps.SetLog(logger)
|
deps.SetLog(logger)
|
||||||
deps.SetLimiter(limiter)
|
deps.SetLimiter(limiter)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue