Compare commits

..

19 Commits

Author SHA1 Message Date
lash
1eb0b15552
Update deps 2025-02-04 13:23:47 +00:00
lash
ef803e0ee2
Enable custom engine factory 2025-02-04 13:08:08 +00:00
lash
03d19283f6
Apply dbconn explicit to all conns by default 2025-01-24 10:09:46 +00:00
lash
15ce29a1a4
Fmt 2025-01-22 18:37:54 +00:00
lash
6749c632b0
Correct handling of db modes 2025-01-22 12:34:24 +00:00
lash
8530c45074
Enable db text/binary mode set in override, config 2025-01-22 09:37:11 +00:00
lash
d5e636fbd6
Gofmt 2025-01-21 15:30:53 +00:00
lash
f7d31e4e81
Update deps 2025-01-21 13:49:12 +00:00
lash
90ecec1798
rehabilitate storage test 2025-01-20 12:31:20 +00:00
lash
874edb3da6
Apply session on the menuhandler store returns 2025-01-20 12:09:09 +00:00
lash
60ff1b0ab3
Set up multiple conns in config 2025-01-19 18:26:39 +00:00
lash
9b3dad579b
Set up multiple conns in config 2025-01-19 15:04:49 +00:00
lash
348fff8936
Allow multiple db connections in menuservice 2025-01-19 15:00:31 +00:00
lash
c5bb1c80a5
Update deps, connbusy fix db postgres 2025-01-19 11:08:07 +00:00
lash
b8a377befb
Implement context for get and put provider 2025-01-19 10:38:41 +00:00
lash
c9b92191f3
Add missing contexts in request handler mocks 2025-01-19 09:40:10 +00:00
lash
ddd8d7cac0
implement missing context 2025-01-19 09:35:09 +00:00
lash
37973a6c9b
Add finish context to mockengine 2025-01-19 09:08:03 +00:00
lash
975720919c
Implement tx enabled db vise 2025-01-19 09:04:37 +00:00
21 changed files with 616 additions and 323 deletions

View File

@ -5,19 +5,37 @@ import (
"git.defalsify.org/vise.git/logging" "git.defalsify.org/vise.git/logging"
"git.grassecon.net/grassrootseconomics/visedriver/env" "git.grassecon.net/grassrootseconomics/visedriver/env"
"git.grassecon.net/grassrootseconomics/visedriver/storage"
) )
var ( var (
logg = logging.NewVanilla().WithDomain("visedriver-config")
defaultLanguage = "eng" defaultLanguage = "eng"
languages []string languages []string
)
var (
DbConn string
DefaultLanguage string DefaultLanguage string
dbConn string
dbConnMissing bool
dbConnMode storage.DbMode
stateDbConn string
stateDbConnMode storage.DbMode
resourceDbConn string
resourceDbConnMode storage.DbMode
userDbConn string
userDbConnMode storage.DbMode
Languages []string Languages []string
) )
type Override struct {
DbConn string
DbConnMode storage.DbMode
StateConn string
StateConnMode storage.DbMode
ResourceConn string
ResourceConnMode storage.DbMode
UserConn string
UserConnMode storage.DbMode
}
func setLanguage() error { func setLanguage() error {
defaultLanguage = env.GetEnv("DEFAULT_LANGUAGE", defaultLanguage) defaultLanguage = env.GetEnv("DEFAULT_LANGUAGE", defaultLanguage)
languages = strings.Split(env.GetEnv("LANGUAGES", defaultLanguage), ",") languages = strings.Split(env.GetEnv("LANGUAGES", defaultLanguage), ",")
@ -37,31 +55,95 @@ func setLanguage() error {
} }
func setConn() error { func setConn() error {
DbConn = env.GetEnv("DB_CONN", "") dbConn = env.GetEnv("DB_CONN", "?")
stateDbConn = env.GetEnv("DB_CONN_STATE", dbConn)
resourceDbConn = env.GetEnv("DB_CONN_RESOURCE", dbConn)
userDbConn = env.GetEnv("DB_CONN_USER", dbConn)
return nil return nil
} }
func ApplyConn(override *Override) {
if override.DbConn != "?" {
dbConn = override.DbConn
stateDbConn = override.StateConn
resourceDbConn = override.ResourceConn
userDbConn = override.UserConn
}
dbConnMode = override.DbConnMode
if override.StateConn != "?" {
stateDbConn = override.StateConn
}
if override.ResourceConn != "?" {
resourceDbConn = override.ResourceConn
}
if override.UserConn != "?" {
userDbConn = override.UserConn
}
if dbConn == "?" {
dbConn = ""
}
if stateDbConn == "?" {
stateDbConn = dbConn
stateDbConnMode = dbConnMode
}
if resourceDbConn == "?" {
resourceDbConn = dbConn
resourceDbConnMode = dbConnMode
}
if userDbConn == "?" {
userDbConn = dbConn
userDbConnMode = dbConnMode
}
logg.Debugf("conns", "conn", dbConn, "user", userDbConn)
if override.DbConnMode != storage.DBMODE_ANY {
dbConnMode = override.DbConnMode
}
if override.StateConnMode != storage.DBMODE_ANY {
stateDbConnMode = override.StateConnMode
}
if override.ResourceConnMode != storage.DBMODE_ANY {
resourceDbConnMode = override.ResourceConnMode
}
if override.UserConnMode != storage.DBMODE_ANY {
userDbConnMode = override.UserConnMode
}
}
func GetConns() (storage.Conns, error) {
o := storage.NewConns()
c, err := storage.ToConnDataMode(stateDbConn, stateDbConnMode)
if err != nil {
return o, err
}
o.Set(c, storage.STORETYPE_STATE)
c, err = storage.ToConnDataMode(resourceDbConn, resourceDbConnMode)
if err != nil {
return o, err
}
o.Set(c, storage.STORETYPE_RESOURCE)
c, err = storage.ToConnDataMode(userDbConn, userDbConnMode)
if err != nil {
return o, err
}
o.Set(c, storage.STORETYPE_USER)
return o, nil
}
// LoadConfig initializes the configuration values after environment variables are loaded. // LoadConfig initializes the configuration values after environment variables are loaded.
func LoadConfig() error { func LoadConfig() error {
if err := setLanguage(); err != nil { err := setConn()
if err != nil {
return err return err
} }
if err := setConn(); err != nil { err = setLanguage()
if err != nil {
return err return err
} }
DefaultLanguage = defaultLanguage DefaultLanguage = defaultLanguage
Languages = languages Languages = languages
// Create and use reporter
logger := logging.NewVanilla().WithDomain("config")
reporter := NewReporter(logger)
reporter.AddValue("CUSTOM_SETTING", func() string {
return env.GetEnv("CUSTOM_SETTING", "default")
}, false)
reporter.Report("INFO")
return nil return nil
} }

View File

@ -1,75 +0,0 @@
//go:build configreport
package config
import (
"git.defalsify.org/vise.git/logging"
"git.grassecon.net/grassrootseconomics/visedriver/env"
)
// ConfigValue represents a configuration key-value pair
type ConfigValue struct {
Key string
ValueFunc func() string
Sensitive bool
}
// Reporter handles configuration reporting
type Reporter struct {
values []ConfigValue
logger logging.Vanilla
}
func NewReporter(logger logging.Vanilla) *Reporter {
return &Reporter{
values: defaultConfigValues(),
logger: logger,
}
}
func defaultConfigValues() []ConfigValue {
return []ConfigValue{
{"HOST", func() string { return env.GetEnv("HOST", "127.0.0.1") }, false},
{"PORT", func() string { return env.GetEnv("PORT", "7123") }, false},
{"AT_ENDPOINT", func() string { return env.GetEnv("AT_ENDPOINT", "/ussd/africastalking") }, false},
{"DB_CONN", func() string { return env.GetEnv("DB_CONN", "") }, true},
{"DB_TIMEZONE", func() string { return env.GetEnv("DB_TIMEZONE", "") }, false},
{"DB_SCHEMA", func() string { return env.GetEnv("DB_SCHEMA", "") }, false},
{"CUSTODIAL_URL_BASE", func() string { return env.GetEnv("CUSTODIAL_URL_BASE", "") }, false},
{"BEARER_TOKEN", func() string { return env.GetEnv("BEARER_TOKEN", "") }, true},
{"DATA_URL_BASE", func() string { return env.GetEnv("DATA_URL_BASE", "") }, false},
{"DEFAULT_LANGUAGE", func() string { return env.GetEnv("DEFAULT_LANGUAGE", "eng") }, false},
{"LANGUAGES", func() string { return env.GetEnv("LANGUAGES", "eng") }, false},
}
}
func (r *Reporter) AddValue(key string, valueFn func() string, sensitive bool) {
r.values = append(r.values, ConfigValue{
Key: key,
ValueFunc: valueFn,
Sensitive: sensitive,
})
}
// Report outputs all configuration values at the specified log level
func (r *Reporter) Report(level string) {
r.logger.Debugf("Configuration Report:")
for _, cv := range r.values {
value := cv.ValueFunc()
if cv.Sensitive {
value = "****"
}
switch level {
case "DEBUG":
r.logger.Debugf("%s: %s", cv.Key, value)
case "INFO":
r.logger.Infof("%s: %s", cv.Key, value)
case "WARN":
r.logger.Warnf("%s: %s", cv.Key, value)
case "ERROR":
r.logger.Errorf("%s: %s", cv.Key, value)
default:
r.logger.Infof("%s: %s", cv.Key, value)
}
}
}

View File

@ -1,17 +0,0 @@
//go:build !configreport
package config
import (
"git.defalsify.org/vise.git/logging"
)
type Reporter struct{}
func NewReporter(logger logging.Vanilla) *Reporter {
return &Reporter{}
}
func (r *Reporter) AddValue(key string, valueFn func() string, sensitive bool) {}
func (r *Reporter) Report(level string) {}

View File

@ -2,8 +2,9 @@ package entry
import ( import (
"context" "context"
"git.defalsify.org/vise.git/resource"
"git.defalsify.org/vise.git/persist" "git.defalsify.org/vise.git/persist"
"git.defalsify.org/vise.git/resource"
) )
type EntryHandler interface { type EntryHandler interface {

2
go.mod
View File

@ -3,7 +3,7 @@ module git.grassecon.net/grassrootseconomics/visedriver
go 1.23.0 go 1.23.0
require ( require (
git.defalsify.org/vise.git v0.2.3-0.20250114225117-3b5fc85b650b git.defalsify.org/vise.git v0.2.3-0.20250204132233-2bffe532f21e
github.com/jackc/pgx/v5 v5.7.1 github.com/jackc/pgx/v5 v5.7.1
github.com/joho/godotenv v1.5.1 github.com/joho/godotenv v1.5.1
) )

4
go.sum
View File

@ -1,5 +1,5 @@
git.defalsify.org/vise.git v0.2.3-0.20250114225117-3b5fc85b650b h1:rwWXMtNSn7aqhb4p1oVZkCA1vC7pVdohwW61QQM8fUs= git.defalsify.org/vise.git v0.2.3-0.20250204132233-2bffe532f21e h1:gtB9OdX6x5gQRM3W824dEurXuuf/YPInqgtv2KAp5Zo=
git.defalsify.org/vise.git v0.2.3-0.20250114225117-3b5fc85b650b/go.mod h1:jyBMe1qTYUz3mmuoC9JQ/TvFeW0vTanCUcPu3H8p4Ck= git.defalsify.org/vise.git v0.2.3-0.20250204132233-2bffe532f21e/go.mod h1:jyBMe1qTYUz3mmuoC9JQ/TvFeW0vTanCUcPu3H8p4Ck=
github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c h1:H9Nm+I7Cg/YVPpEV1RzU3Wq2pjamPc/UtHDgItcb7lE= github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c h1:H9Nm+I7Cg/YVPpEV1RzU3Wq2pjamPc/UtHDgItcb7lE=
github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c/go.mod h1:rGod7o6KPeJ+hyBpHfhi4v7blx9sf+QsHsA7KAsdN6U= github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c/go.mod h1:rGod7o6KPeJ+hyBpHfhi4v7blx9sf+QsHsA7KAsdN6U=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=

View File

@ -1,84 +1,87 @@
package request package request
import ( import (
"context"
"git.defalsify.org/vise.git/db" "git.defalsify.org/vise.git/db"
"git.defalsify.org/vise.git/engine" "git.defalsify.org/vise.git/engine"
"git.defalsify.org/vise.git/persist" "git.defalsify.org/vise.git/persist"
"git.defalsify.org/vise.git/resource" "git.defalsify.org/vise.git/resource"
"git.grassecon.net/grassrootseconomics/visedriver/storage"
"git.grassecon.net/grassrootseconomics/visedriver/errors"
"git.grassecon.net/grassrootseconomics/visedriver/entry" "git.grassecon.net/grassrootseconomics/visedriver/entry"
"git.grassecon.net/grassrootseconomics/visedriver/errors"
"git.grassecon.net/grassrootseconomics/visedriver/storage"
) )
type EngineFunc func(engine.Config, resource.Resource, *persist.Persister) engine.Engine
type BaseRequestHandler struct { type BaseRequestHandler struct {
cfgTemplate engine.Config cfgTemplate engine.Config
rp RequestParser rp RequestParser
rs resource.Resource rs resource.Resource
hn entry.EntryHandler hn entry.EntryHandler
provider storage.StorageProvider provider storage.StorageProvider
engineFunc EngineFunc
} }
//func NewBaseRequestHandler(cfg engine.Config, rs resource.Resource, stateDb db.Db, userdataDb db.Db, rp request.RequestParser, hn *handlers.Handlers) *BaseRequestHandler {
func NewBaseRequestHandler(cfg engine.Config, rs resource.Resource, stateDb db.Db, userdataDb db.Db, rp RequestParser, hn entry.EntryHandler) *BaseRequestHandler { func NewBaseRequestHandler(cfg engine.Config, rs resource.Resource, stateDb db.Db, userdataDb db.Db, rp RequestParser, hn entry.EntryHandler) *BaseRequestHandler {
return &BaseRequestHandler{ h := &BaseRequestHandler{
cfgTemplate: cfg, cfgTemplate: cfg,
rs: rs, rs: rs,
hn: hn, hn: hn,
rp: rp, rp: rp,
provider: storage.NewSimpleStorageProvider(stateDb, userdataDb), provider: storage.NewSimpleStorageProvider(stateDb, userdataDb),
} }
h.engineFunc = h.getDefaultEngine
return h
} }
func (f *BaseRequestHandler) Shutdown() { func (f *BaseRequestHandler) WithEngineFunc(fn EngineFunc) *BaseRequestHandler {
err := f.provider.Close() f.engineFunc = fn
return f
}
func (f *BaseRequestHandler) Shutdown(ctx context.Context) {
err := f.provider.Close(ctx)
if err != nil { if err != nil {
logg.Errorf("handler shutdown error", "err", err) logg.Errorf("handler shutdown error", "err", err)
} }
} }
func (f *BaseRequestHandler) GetEngine(cfg engine.Config, rs resource.Resource, pr *persist.Persister) engine.Engine { func (f *BaseRequestHandler) GetEngine(cfg engine.Config, rs resource.Resource, pr *persist.Persister) engine.Engine {
return f.engineFunc(cfg, rs, pr)
}
func (f *BaseRequestHandler) getDefaultEngine(cfg engine.Config, rs resource.Resource, pr *persist.Persister) engine.Engine {
en := engine.NewEngine(cfg, rs) en := engine.NewEngine(cfg, rs)
en = en.WithPersister(pr) en = en.WithPersister(pr)
en = en.WithFirst(f.hn.Init)
if f.cfgTemplate.EngineDebug {
en = en.WithDebug(nil)
}
return en return en
} }
func (f *BaseRequestHandler) Process(rqs RequestSession) (RequestSession, error) { func (f *BaseRequestHandler) Process(rqs RequestSession) (RequestSession, error) {
var r bool var r bool
var err error var err error
var ok bool
logg.InfoCtxf(rqs.Ctx, "new request", "data", rqs) logg.InfoCtxf(rqs.Ctx, "new request", "data", rqs)
rqs.Storage, err = f.provider.Get(rqs.Config.SessionId) rqs.Storage, err = f.provider.Get(rqs.Ctx, rqs.Config.SessionId)
if err != nil { if err != nil {
logg.ErrorCtxf(rqs.Ctx, "", "storage get error", err) logg.ErrorCtxf(rqs.Ctx, "", "storage get error", err)
return rqs, errors.ErrStorage return rqs, errors.ErrStorage
} }
//f.hn = f.hn.WithPersister(rqs.Storage.Persister)
f.hn.SetPersister(rqs.Storage.Persister) f.hn.SetPersister(rqs.Storage.Persister)
defer func() { defer func() {
f.hn.Exit() f.hn.Exit()
}() }()
eni := f.GetEngine(rqs.Config, f.rs, rqs.Storage.Persister)
en, ok := eni.(*engine.DefaultEngine)
if !ok {
perr := f.provider.Put(rqs.Config.SessionId, rqs.Storage)
rqs.Storage = nil
if perr != nil {
logg.ErrorCtxf(rqs.Ctx, "", "storage put error", perr)
}
return rqs, errors.ErrEngineType
}
en = en.WithFirst(f.hn.Init)
if rqs.Config.EngineDebug {
en = en.WithDebug(nil)
}
rqs.Engine = en
rqs.Engine = f.GetEngine(rqs.Config, f.rs, rqs.Storage.Persister)
r, err = rqs.Engine.Exec(rqs.Ctx, rqs.Input) r, err = rqs.Engine.Exec(rqs.Ctx, rqs.Input)
if err != nil { if err != nil {
perr := f.provider.Put(rqs.Config.SessionId, rqs.Storage) perr := f.provider.Put(rqs.Ctx, rqs.Config.SessionId, rqs.Storage)
rqs.Storage = nil rqs.Storage = nil
if perr != nil { if perr != nil {
logg.ErrorCtxf(rqs.Ctx, "", "storage put error", perr) logg.ErrorCtxf(rqs.Ctx, "", "storage put error", perr)
@ -96,9 +99,9 @@ func(f *BaseRequestHandler) Output(rqs RequestSession) (RequestSession, error)
return rqs, err return rqs, err
} }
func(f *BaseRequestHandler) Reset(rqs RequestSession) (RequestSession, error) { func (f *BaseRequestHandler) Reset(ctx context.Context, rqs RequestSession) (RequestSession, error) {
defer f.provider.Put(rqs.Config.SessionId, rqs.Storage) defer f.provider.Put(ctx, rqs.Config.SessionId, rqs.Storage)
return rqs, rqs.Engine.Finish() return rqs, rqs.Engine.Finish(ctx)
} }
func (f *BaseRequestHandler) GetConfig() engine.Config { func (f *BaseRequestHandler) GetConfig() engine.Config {

View File

@ -5,8 +5,8 @@ import (
"strconv" "strconv"
"git.defalsify.org/vise.git/logging" "git.defalsify.org/vise.git/logging"
"git.grassecon.net/grassrootseconomics/visedriver/request"
"git.grassecon.net/grassrootseconomics/visedriver/errors" "git.grassecon.net/grassrootseconomics/visedriver/errors"
"git.grassecon.net/grassrootseconomics/visedriver/request"
) )
var ( var (
@ -80,7 +80,7 @@ func (hh *HTTPRequestHandler) ServeHTTP(w http.ResponseWriter, req *http.Request
w.WriteHeader(200) w.WriteHeader(200)
w.Header().Set("Content-Type", "text/plain") w.Header().Set("Content-Type", "text/plain")
rqs, err = hh.Output(rqs) rqs, err = hh.Output(rqs)
rqs, perr = hh.Reset(rqs) rqs, perr = hh.Reset(rqs.Ctx, rqs)
if err != nil { if err != nil {
hh.WriteError(w, 500, err) hh.WriteError(w, 500, err)
return return

View File

@ -10,8 +10,8 @@ import (
"git.defalsify.org/vise.git/engine" "git.defalsify.org/vise.git/engine"
viseerrors "git.grassecon.net/grassrootseconomics/visedriver/errors" viseerrors "git.grassecon.net/grassrootseconomics/visedriver/errors"
"git.grassecon.net/grassrootseconomics/visedriver/testutil/mocks/httpmocks"
"git.grassecon.net/grassrootseconomics/visedriver/request" "git.grassecon.net/grassrootseconomics/visedriver/request"
"git.grassecon.net/grassrootseconomics/visedriver/testutil/mocks/httpmocks"
) )
// invalidRequestType is a custom type to test invalid request scenarios // invalidRequestType is a custom type to test invalid request scenarios
@ -88,7 +88,7 @@ func TestRequestHandler_ServeHTTP(t *testing.T) {
OutputFunc: func(rs request.RequestSession) (request.RequestSession, error) { OutputFunc: func(rs request.RequestSession) (request.RequestSession, error) {
return rs, tt.outputErr return rs, tt.outputErr
}, },
ResetFunc: func(rs request.RequestSession) (request.RequestSession, error) { ResetFunc: func(ctx context.Context, rs request.RequestSession) (request.RequestSession, error) {
return rs, tt.resetErr return rs, tt.resetErr
}, },
GetRequestParserFunc: func() request.RequestParser { GetRequestParserFunc: func() request.RequestParser {

View File

@ -4,10 +4,10 @@ import (
"context" "context"
"io" "io"
"git.defalsify.org/vise.git/resource"
"git.defalsify.org/vise.git/persist"
"git.defalsify.org/vise.git/engine" "git.defalsify.org/vise.git/engine"
"git.defalsify.org/vise.git/logging" "git.defalsify.org/vise.git/logging"
"git.defalsify.org/vise.git/persist"
"git.defalsify.org/vise.git/resource"
"git.grassecon.net/grassrootseconomics/visedriver/storage" "git.grassecon.net/grassrootseconomics/visedriver/storage"
) )
@ -27,16 +27,16 @@ type RequestSession struct {
// TODO: seems like can remove this. // TODO: seems like can remove this.
type RequestParser interface { type RequestParser interface {
GetSessionId(ctx context.Context, rq any) (string, error) GetSessionId(context.Context, any) (string, error)
GetInput(rq any) ([]byte, error) GetInput(any) ([]byte, error)
} }
type RequestHandler interface { type RequestHandler interface {
GetConfig() engine.Config GetConfig() engine.Config
GetRequestParser() RequestParser GetRequestParser() RequestParser
GetEngine(cfg engine.Config, rs resource.Resource, pe *persist.Persister) engine.Engine GetEngine(engine.Config, resource.Resource, *persist.Persister) engine.Engine
Process(rs RequestSession) (RequestSession, error) Process(RequestSession) (RequestSession, error)
Output(rs RequestSession) (RequestSession, error) Output(RequestSession) (RequestSession, error)
Reset(rs RequestSession) (RequestSession, error) Reset(context.Context, RequestSession) (RequestSession, error)
Shutdown() Shutdown(ctx context.Context)
} }

98
storage/conn.go Normal file
View File

@ -0,0 +1,98 @@
package storage
import (
"fmt"
"net/url"
)
type DbMode uint8
const (
DBTYPE_NONE = iota
DBTYPE_MEM
DBTYPE_FS
DBTYPE_GDBM
DBTYPE_POSTGRES
)
const (
DBMODE_ANY DbMode = iota
DBMODE_BINARY
DBMODE_TEXT
)
const (
STORETYPE_STATE = iota
STORETYPE_RESOURCE
STORETYPE_USER
_STORETYPE_MAX
)
var (
DbModeDebug = []string{"ANY", "BIN", "TXT"}
DbTypeDebug = []string{"NONE", "MEM", "FS", "GDBM", "POSTGRES"}
DbStoreDebug = []string{"STATE", "RESOURCE", "USER"}
)
type Conns map[int8]ConnData
func NewConns() Conns {
c := make(Conns)
return c
}
func (c Conns) Set(conn ConnData, typ int8) {
if typ < 0 || typ >= _STORETYPE_MAX {
panic(fmt.Errorf("invalid store type: %d", typ))
}
c[typ] = conn
}
func (c Conns) Have(conn *ConnData) int8 {
for i := range _STORETYPE_MAX {
ii := int8(i)
v, ok := c[ii]
if !ok {
continue
}
if v.Raw() == conn.Raw() {
if v.Mode() == DBMODE_ANY || v.Mode() == conn.Mode() {
return ii
}
}
}
return -1
}
type ConnData struct {
typ int
str string
domain string
mode DbMode
}
func (cd *ConnData) DbType() int {
return cd.typ
}
func (cd ConnData) String() string {
return fmt.Sprintf("conn: %s, mod %s, typ %s", cd.str, DbModeDebug[uint8(cd.mode)], DbTypeDebug[uint8(cd.typ)])
}
func (cd *ConnData) Domain() string {
return cd.domain
}
func (cd *ConnData) Mode() DbMode {
return cd.mode
}
func (cd *ConnData) Path() string {
v, _ := url.Parse(cd.str)
v.RawQuery = ""
return v.String()
}
func (cd *ConnData) Raw() string {
return cd.str
}

View File

@ -111,11 +111,11 @@ func(tdb *ThreadGdbmDb) Get(ctx context.Context, key []byte) ([]byte, error) {
return v, err return v, err
} }
func(tdb *ThreadGdbmDb) Close() error { func (tdb *ThreadGdbmDb) Close(ctx context.Context) error {
tdb.reserve() tdb.reserve()
close(dbC[tdb.connStr]) close(dbC[tdb.connStr])
delete(dbC, tdb.connStr) delete(dbC, tdb.connStr)
err := tdb.db.Close() err := tdb.db.Close(ctx)
tdb.db = nil tdb.db = nil
return err return err
} }
@ -125,3 +125,23 @@ func(tdb *ThreadGdbmDb) Dump(ctx context.Context, key []byte) (*db.Dumper, error
defer tdb.release() defer tdb.release()
return tdb.db.Dump(ctx, key) return tdb.db.Dump(ctx, key)
} }
func (tdb *ThreadGdbmDb) DecodeKey(ctx context.Context, key []byte) ([]byte, error) {
return tdb.db.DecodeKey(ctx, key)
}
func (tdb *ThreadGdbmDb) Abort(ctx context.Context) {
tdb.db.Abort(ctx)
}
func (tdb *ThreadGdbmDb) Start(ctx context.Context) error {
return tdb.db.Start(ctx)
}
func (tdb *ThreadGdbmDb) Stop(ctx context.Context) error {
return tdb.db.Stop(ctx)
}
func (tdb *ThreadGdbmDb) Connection() string {
return tdb.db.Connection()
}

View File

@ -4,40 +4,9 @@ import (
"fmt" "fmt"
"net/url" "net/url"
"path" "path"
"path/filepath"
) )
const (
DBTYPE_NONE = iota
DBTYPE_MEM
DBTYPE_FS
DBTYPE_GDBM
DBTYPE_POSTGRES
)
type ConnData struct {
typ int
str string
domain string
}
func (cd *ConnData) DbType() int {
return cd.typ
}
func (cd *ConnData) String() string {
return cd.str
}
func (cd *ConnData) Domain() string {
return cd.domain
}
func (cd *ConnData) Path() string {
v, _ := url.Parse(cd.str)
v.RawQuery = ""
return v.String()
}
func probePostgres(s string) (string, string, bool) { func probePostgres(s string) (string, string, bool) {
domain := "public" domain := "public"
v, err := url.Parse(s) v, err := url.Parse(s)
@ -68,9 +37,19 @@ func probeGdbm(s string) (string, string, bool) {
} }
func probeFs(s string) (string, string, bool) { func probeFs(s string) (string, string, bool) {
if !path.IsAbs(s) { var err error
v, _ := url.Parse(s)
if v.Scheme != "" && v.Scheme != "file://" {
return "", "", false return "", "", false
} }
if !path.IsAbs(s) {
s, err = filepath.Abs(s)
if err != nil {
panic(err)
}
}
s = path.Clean(s) s = path.Clean(s)
return s, "", true return s, "", true
} }
@ -82,14 +61,25 @@ func probeMem(s string) (string, string, bool) {
return "", "", true return "", "", true
} }
func ToConnData(connStr string) (ConnData, error) { func ToConnDataMode(connStr string, mode DbMode) (ConnData, error) {
var o ConnData o, err := ToConnData(connStr)
if err != nil {
if connStr == "" { return o, err
}
o.mode = mode
return o, nil return o, nil
} }
v, domain, ok := probePostgres(connStr) func ToConnData(connStr string) (ConnData, error) {
var o ConnData
v, domain, ok := probeMem(connStr)
if ok {
o.typ = DBTYPE_MEM
return o, nil
}
v, domain, ok = probePostgres(connStr)
if ok { if ok {
o.typ = DBTYPE_POSTGRES o.typ = DBTYPE_POSTGRES
o.str = v o.str = v
@ -111,11 +101,5 @@ func ToConnData(connStr string) (ConnData, error) {
return o, nil return o, nil
} }
v, _, ok = probeMem(connStr)
if ok {
o.typ = DBTYPE_MEM
return o, nil
}
return o, fmt.Errorf("invalid connection string: %s", connStr) return o, fmt.Errorf("invalid connection string: %s", connStr)
} }

View File

@ -5,24 +5,53 @@ import (
) )
func TestParseConnStr(t *testing.T) { func TestParseConnStr(t *testing.T) {
_, err := ToConnData("postgres://foo:bar@localhost:5432/baz") v, err := ToConnData("postgres://foo:bar@localhost:5432/baz")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
_, err = ToConnData("/foo/bar") if v.DbType() != DBTYPE_POSTGRES {
t.Fatalf("expected type %v, got %v", DBTYPE_POSTGRES, v.DbType())
}
v, err = ToConnData("gdbm:///foo/bar")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
_, err = ToConnData("/foo/bar/") if v.DbType() != DBTYPE_GDBM {
t.Fatalf("expected type %v, got %v", DBTYPE_GDBM, v.DbType())
}
v, err = ToConnData("/foo/bar")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
_, err = ToConnData("foo/bar") if v.DbType() != DBTYPE_FS {
t.Fatalf("expected type %v, got %v", DBTYPE_FS, v.DbType())
}
v, err = ToConnData("/foo/bar/")
if err != nil {
t.Fatal(err)
}
if v.DbType() != DBTYPE_FS {
t.Fatalf("expected type %v, got %v", DBTYPE_FS, v.DbType())
}
v, err = ToConnData("foo/bar")
if err != nil {
t.Fatal(err)
}
if v.DbType() != DBTYPE_FS {
t.Fatalf("expected type %v, got %v", DBTYPE_FS, v.DbType())
}
v, err = ToConnData("")
if err != nil {
t.Fatal(err)
}
if v.DbType() != DBTYPE_MEM {
t.Fatalf("expected type %v, got %v", DBTYPE_MEM, v.DbType())
}
v, err = ToConnData("http://foo/bar")
if err == nil { if err == nil {
t.Fatalf("expected error") t.Fatalf("expected error")
} }
_, err = ToConnData("http://foo/bar") if v.DbType() != DBTYPE_NONE {
if err == nil { t.Fatalf("expected type %v, got %v", DBTYPE_NONE, v.DbType())
t.Fatalf("expected error")
} }
} }

View File

@ -1,6 +1,8 @@
package storage package storage
import ( import (
"context"
"git.defalsify.org/vise.git/db" "git.defalsify.org/vise.git/db"
"git.defalsify.org/vise.git/persist" "git.defalsify.org/vise.git/persist"
) )
@ -14,10 +16,14 @@ type Storage struct {
UserdataDb db.Db UserdataDb db.Db
} }
func (s *Storage) Close(ctx context.Context) error {
return s.UserdataDb.Close(ctx)
}
type StorageProvider interface { type StorageProvider interface {
Get(sessionId string) (*Storage, error) Get(ctx context.Context, sessionId string) (*Storage, error)
Put(sessionId string, storage *Storage) error Put(ctx context.Context, sessionId string, storage *Storage) error
Close() error Close(ctx context.Context) error
} }
type SimpleStorageProvider struct { type SimpleStorageProvider struct {
@ -35,14 +41,16 @@ func NewSimpleStorageProvider(stateStore db.Db, userdataStore db.Db) StorageProv
} }
} }
func (p *SimpleStorageProvider) Get(sessionId string) (*Storage, error) { func (p *SimpleStorageProvider) Get(ctx context.Context, sessionId string) (*Storage, error) {
p.Storage.UserdataDb.Start(ctx)
return p.Storage, nil return p.Storage, nil
} }
func (p *SimpleStorageProvider) Put(sessionId string, storage *Storage) error { func (p *SimpleStorageProvider) Put(ctx context.Context, sessionId string, storage *Storage) error {
storage.UserdataDb.Stop(ctx)
return nil return nil
} }
func (p *SimpleStorageProvider) Close() error { func (p *SimpleStorageProvider) Close(ctx context.Context) error {
return p.Storage.UserdataDb.Close() return p.Storage.Close(ctx)
} }

View File

@ -2,19 +2,21 @@ package storage
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"os" "os"
"path" "path"
"github.com/jackc/pgx/v5/pgxpool"
"git.defalsify.org/vise.git/db" "git.defalsify.org/vise.git/db"
fsdb "git.defalsify.org/vise.git/db/fs" fsdb "git.defalsify.org/vise.git/db/fs"
memdb "git.defalsify.org/vise.git/db/mem"
"git.defalsify.org/vise.git/db/postgres" "git.defalsify.org/vise.git/db/postgres"
"git.defalsify.org/vise.git/lang" "git.defalsify.org/vise.git/lang"
"git.defalsify.org/vise.git/logging" "git.defalsify.org/vise.git/logging"
"git.defalsify.org/vise.git/persist" "git.defalsify.org/vise.git/persist"
"git.defalsify.org/vise.git/resource" "git.defalsify.org/vise.git/resource"
gdbmstorage "git.grassecon.net/grassrootseconomics/visedriver/storage/db/gdbm" gdbmstorage "git.grassecon.net/grassrootseconomics/visedriver/storage/db/gdbm"
"github.com/jackc/pgx/v5/pgxpool"
) )
var ( var (
@ -27,69 +29,100 @@ type StorageService interface {
GetResource(ctx context.Context) (resource.Resource, error) GetResource(ctx context.Context) (resource.Resource, error)
} }
// TODO: Support individual backend for each store (conndata)
type MenuStorageService struct { type MenuStorageService struct {
conn ConnData conns Conns
resourceDir string
poResource resource.Resource poResource resource.Resource
resourceStore db.Db store map[int8]db.Db
stateStore db.Db
userDataStore db.Db
} }
func NewMenuStorageService(conn ConnData, resourceDir string) *MenuStorageService { func NewMenuStorageService(conn Conns) *MenuStorageService {
return &MenuStorageService{ return &MenuStorageService{
conn: conn, conns: conn,
resourceDir: resourceDir, store: make(map[int8]db.Db),
} }
} }
func (ms *MenuStorageService) WithResourceDir(resourceDir string) *MenuStorageService { func (ms *MenuStorageService) WithDb(store db.Db, typ int8) *MenuStorageService {
ms.resourceDir = resourceDir var err error
if ms.store[typ] != nil {
panic(fmt.Errorf("db already set for typ: %d", typ))
}
ms.store[typ] = store
ms.conns[typ], err = ToConnData(store.Connection())
if err != nil {
panic(err)
}
return ms return ms
} }
// TODO: allow fsdb, memdb func (ms *MenuStorageService) checkDb(ctx context.Context, typ int8) db.Db {
func (ms *MenuStorageService) getOrCreateDb(ctx context.Context, existingDb db.Db, section string, typ string) (db.Db, error) { store := ms.store[typ]
var newDb db.Db if store != nil {
var err error return store
}
if existingDb != nil { connData := ms.conns[typ]
return existingDb, nil logg.DebugCtxf(ctx, "db check", "conn", connData, "store", DbStoreDebug[typ])
v := ms.conns.Have(&connData)
if v == -1 {
return nil
}
src := ms.store[v]
if src == nil {
return nil
}
ms.store[typ] = ms.store[v]
logg.DebugCtxf(ctx, "found existing db", "typ", typ, "srctyp", v, "store", ms.store[typ], "srcstore", ms.store[v], "conn", connData)
return ms.store[typ]
} }
connStr := ms.conn.String() func (ms *MenuStorageService) getOrCreateDb(ctx context.Context, section string, typ int8) (db.Db, error) {
dbTyp := ms.conn.DbType() var err error
newDb := ms.checkDb(ctx, typ)
if newDb != nil {
logg.InfoCtxf(ctx, "using existing db", "typ", typ, "db", newDb)
return newDb, nil
}
connData := ms.conns[typ]
connStr := connData.Raw()
dbTyp := connData.DbType()
if dbTyp == DBTYPE_POSTGRES { if dbTyp == DBTYPE_POSTGRES {
// TODO: move to vise // TODO: move to vise
err = ensureSchemaExists(ctx, ms.conn) err = ensureSchemaExists(ctx, connData)
if err != nil { if err != nil {
return nil, err return nil, err
} }
newDb = postgres.NewPgDb().WithSchema(ms.conn.Domain()) newDb = postgres.NewPgDb().WithSchema(connData.Domain())
} else if dbTyp == DBTYPE_GDBM { } else if dbTyp == DBTYPE_GDBM {
err = ms.ensureDbDir() err = ms.ensureDbDir(connStr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
connStr = path.Join(connStr, section) connStr = path.Join(connStr, section)
newDb = gdbmstorage.NewThreadGdbmDb() newDb = gdbmstorage.NewThreadGdbmDb()
} else if dbTyp == DBTYPE_FS { } else if dbTyp == DBTYPE_FS {
err = ms.ensureDbDir() err = ms.ensureDbDir(connStr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
newDb = fsdb.NewFsDb().WithBinary() fsdbInstance := fsdb.NewFsDb()
if connData.Mode() == DBMODE_BINARY {
fsdbInstance = fsdbInstance.WithBinary()
}
newDb = fsdbInstance
} else if dbTyp == DBTYPE_MEM { } else if dbTyp == DBTYPE_MEM {
logg.WarnCtxf(ctx, "using volatile storage (memdb)") logg.WarnCtxf(ctx, "using volatile storage (memdb)")
newDb = memdb.NewMemDb()
} else { } else {
return nil, fmt.Errorf("unsupported connection string: '%s'\n", ms.conn.String()) return nil, fmt.Errorf("unsupported connection string: '%s'\n", connData.Raw())
} }
logg.DebugCtxf(ctx, "connecting to db", "conn", connStr, "conndata", ms.conn, "typ", typ) logg.InfoCtxf(ctx, "connecting to db", "conn", connData, "typ", typ)
err = newDb.Connect(ctx, connStr) err = newDb.Connect(ctx, connStr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
ms.store[typ] = newDb
return newDb, nil return newDb, nil
} }
@ -107,7 +140,7 @@ func (ms *MenuStorageService) WithGettext(path string, lns []lang.Language) *Men
} }
rs := resource.NewPoResource(lns[0], path) rs := resource.NewPoResource(lns[0], path)
for _, ln := range(lns) { for _, ln := range lns {
rs = rs.WithLanguage(ln) rs = rs.WithLanguage(ln)
} }
@ -133,38 +166,49 @@ func ensureSchemaExists(ctx context.Context, conn ConnData) error {
return nil return nil
} }
func applySession(ctx context.Context, store db.Db) error {
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
logg.DebugCtxf(ctx, "missing session to apply", "store", store)
return nil
//return fmt.Errorf("missing session to apply to store: %v", store)
}
store.SetSession(sessionId)
return nil
}
func (ms *MenuStorageService) GetPersister(ctx context.Context) (*persist.Persister, error) { func (ms *MenuStorageService) GetPersister(ctx context.Context) (*persist.Persister, error) {
stateStore, err := ms.GetStateStore(ctx) stateStore, err := ms.GetStateStore(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = applySession(ctx, stateStore)
if err != nil {
return nil, err
}
pr := persist.NewPersister(stateStore) pr := persist.NewPersister(stateStore)
logg.TraceCtxf(ctx, "menu storage service", "persist", pr, "store", stateStore) logg.TraceCtxf(ctx, "menu storage service", "persist", pr, "store", stateStore)
return pr, nil return pr, nil
} }
func (ms *MenuStorageService) GetUserdataDb(ctx context.Context) (db.Db, error) { func (ms *MenuStorageService) GetUserdataDb(ctx context.Context) (db.Db, error) {
if ms.userDataStore != nil { userStore, err := ms.getOrCreateDb(ctx, "userdata.gdbm", STORETYPE_USER)
return ms.userDataStore, nil
}
userDataStore, err := ms.getOrCreateDb(ctx, ms.userDataStore, "userdata.gdbm", "userdata")
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = applySession(ctx, userStore)
ms.userDataStore = userDataStore if err != nil {
return ms.userDataStore, nil return nil, err
}
return userStore, nil
} }
func (ms *MenuStorageService) GetResource(ctx context.Context) (resource.Resource, error) { func (ms *MenuStorageService) GetResource(ctx context.Context) (resource.Resource, error) {
ms.resourceStore = fsdb.NewFsDb() store, err := ms.getOrCreateDb(ctx, "resource.gdbm", STORETYPE_RESOURCE)
err := ms.resourceStore.Connect(ctx, ms.resourceDir)
if err != nil { if err != nil {
return nil, err return nil, err
} }
rfs := resource.NewDbResource(ms.resourceStore) rfs := resource.NewDbResource(store)
if ms.poResource != nil { if ms.poResource != nil {
logg.InfoCtxf(ctx, "using poresource for menu and template") logg.InfoCtxf(ctx, "using poresource for menu and template")
rfs.WithMenuGetter(ms.poResource.GetMenu) rfs.WithMenuGetter(ms.poResource.GetMenu)
@ -174,33 +218,34 @@ func (ms *MenuStorageService) GetResource(ctx context.Context) (resource.Resourc
} }
func (ms *MenuStorageService) GetStateStore(ctx context.Context) (db.Db, error) { func (ms *MenuStorageService) GetStateStore(ctx context.Context) (db.Db, error) {
if ms.stateStore != nil { return ms.getOrCreateDb(ctx, "state.gdbm", STORETYPE_STATE)
return ms.stateStore, nil
} }
stateStore, err := ms.getOrCreateDb(ctx, ms.stateStore, "state.gdbm", "state") func (ms *MenuStorageService) ensureDbDir(path string) error {
err := os.MkdirAll(path, 0700)
if err != nil { if err != nil {
return nil, err return fmt.Errorf("store dir create exited with error: %v\n", err)
}
ms.stateStore = stateStore
return ms.stateStore, nil
}
func (ms *MenuStorageService) ensureDbDir() error {
err := os.MkdirAll(ms.conn.String(), 0700)
if err != nil {
return fmt.Errorf("state dir create exited with error: %v\n", err)
} }
return nil return nil
} }
func (ms *MenuStorageService) Close() error { // TODO: how to handle persister here?
errA := ms.stateStore.Close() func (ms *MenuStorageService) Close(ctx context.Context) error {
errB := ms.userDataStore.Close() var errs []error
errC := ms.resourceStore.Close() var haveErr bool
if errA != nil || errB != nil || errC != nil { for i := range _STORETYPE_MAX {
return fmt.Errorf("%v %v %v", errA, errB, errC) err := ms.store[int8(i)].Close(ctx)
if err != nil {
haveErr = true
}
errs = append(errs, err)
}
if haveErr {
errStr := ""
for i, err := range errs {
errStr += fmt.Sprintf("(%d: %v)", i, err)
}
return errors.New(errStr)
} }
return nil return nil
} }

View File

@ -0,0 +1,114 @@
package storage
import (
"context"
"os"
"testing"
fsdb "git.defalsify.org/vise.git/db/fs"
)
func TestMenuStorageServiceOneSet(t *testing.T) {
d, err := os.MkdirTemp("", "visedriver-menustorageservice")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(d)
conns := NewConns()
connData, err := ToConnData(d)
if err != nil {
t.Fatal(err)
}
conns.Set(connData, STORETYPE_STATE)
ctx := context.Background()
ms := NewMenuStorageService(conns)
_, err = ms.GetStateStore(ctx)
if err != nil {
t.Fatal(err)
}
_, err = ms.GetResource(ctx)
if err == nil {
t.Fatalf("expected error getting resource")
}
_, err = ms.GetUserdataDb(ctx)
if err == nil {
t.Fatalf("expected error getting userdata")
}
}
func TestMenuStorageServiceExplicit(t *testing.T) {
d, err := os.MkdirTemp("", "visedriver-menustorageservice")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(d)
conns := NewConns()
connData, err := ToConnData(d)
if err != nil {
t.Fatal(err)
}
conns.Set(connData, STORETYPE_STATE)
ctx := context.Background()
d, err = os.MkdirTemp("", "visedriver-menustorageservice")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(d)
store := fsdb.NewFsDb()
err = store.Connect(ctx, d)
if err != nil {
t.Fatal(err)
}
ms := NewMenuStorageService(conns)
ms = ms.WithDb(store, STORETYPE_RESOURCE)
_, err = ms.GetStateStore(ctx)
if err != nil {
t.Fatal(err)
}
_, err = ms.GetResource(ctx)
if err != nil {
t.Fatal(err)
}
_, err = ms.GetUserdataDb(ctx)
if err == nil {
t.Fatalf("expected error getting userdata")
}
}
func TestMenuStorageServiceReuse(t *testing.T) {
d, err := os.MkdirTemp("", "visedriver-menustorageservice")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(d)
conns := NewConns()
connData, err := ToConnData(d)
if err != nil {
t.Fatal(err)
}
conns.Set(connData, STORETYPE_STATE)
conns.Set(connData, STORETYPE_USER)
ctx := context.Background()
ctx = context.WithValue(ctx, "SessionId", "foo")
ms := NewMenuStorageService(conns)
stateStore, err := ms.GetStateStore(ctx)
if err != nil {
t.Fatal(err)
}
_, err = ms.GetResource(ctx)
if err == nil {
t.Fatalf("expected error getting resource")
}
userStore, err := ms.GetUserdataDb(ctx)
if err != nil {
t.Fatal(err)
}
if userStore != stateStore {
t.Fatalf("expected same store, but they are %p and %p", userStore, stateStore)
}
}

View File

@ -10,7 +10,7 @@ type MockEngine struct {
InitFunc func(context.Context) (bool, error) InitFunc func(context.Context) (bool, error)
ExecFunc func(context.Context, []byte) (bool, error) ExecFunc func(context.Context, []byte) (bool, error)
FlushFunc func(context.Context, io.Writer) (int, error) FlushFunc func(context.Context, io.Writer) (int, error)
FinishFunc func() error FinishFunc func(context.Context) error
} }
func (m *MockEngine) Init(ctx context.Context) (bool, error) { func (m *MockEngine) Init(ctx context.Context) (bool, error) {
@ -25,6 +25,6 @@ func (m *MockEngine) Flush(ctx context.Context, w io.Writer) (int, error) {
return m.FlushFunc(ctx, w) return m.FlushFunc(ctx, w)
} }
func (m *MockEngine) Finish() error { func (m *MockEngine) Finish(ctx context.Context) error {
return m.FinishFunc() return m.FinishFunc(ctx)
} }

View File

@ -1,6 +1,8 @@
package httpmocks package httpmocks
import ( import (
"context"
"git.defalsify.org/vise.git/engine" "git.defalsify.org/vise.git/engine"
"git.defalsify.org/vise.git/persist" "git.defalsify.org/vise.git/persist"
"git.defalsify.org/vise.git/resource" "git.defalsify.org/vise.git/resource"
@ -13,8 +15,8 @@ type MockRequestHandler struct {
GetConfigFunc func() engine.Config GetConfigFunc func() engine.Config
GetEngineFunc func(cfg engine.Config, rs resource.Resource, pe *persist.Persister) engine.Engine GetEngineFunc func(cfg engine.Config, rs resource.Resource, pe *persist.Persister) engine.Engine
OutputFunc func(rs request.RequestSession) (request.RequestSession, error) OutputFunc func(rs request.RequestSession) (request.RequestSession, error)
ResetFunc func(rs request.RequestSession) (request.RequestSession, error) ResetFunc func(ctx context.Context, rs request.RequestSession) (request.RequestSession, error)
ShutdownFunc func() ShutdownFunc func(ctx context.Context)
GetRequestParserFunc func() request.RequestParser GetRequestParserFunc func() request.RequestParser
} }
@ -34,12 +36,12 @@ func (m *MockRequestHandler) Output(rs request.RequestSession) (request.RequestS
return m.OutputFunc(rs) return m.OutputFunc(rs)
} }
func (m *MockRequestHandler) Reset(rs request.RequestSession) (request.RequestSession, error) { func (m *MockRequestHandler) Reset(ctx context.Context, rs request.RequestSession) (request.RequestSession, error) {
return m.ResetFunc(rs) return m.ResetFunc(ctx, rs)
} }
func (m *MockRequestHandler) Shutdown() { func (m *MockRequestHandler) Shutdown(ctx context.Context) {
m.ShutdownFunc() m.ShutdownFunc(ctx)
} }
func (m *MockRequestHandler) GetRequestParser() request.RequestParser { func (m *MockRequestHandler) GetRequestParser() request.RequestParser {

View File

@ -5,8 +5,8 @@ import (
"git.defalsify.org/vise.git/db" "git.defalsify.org/vise.git/db"
memdb "git.defalsify.org/vise.git/db/mem" memdb "git.defalsify.org/vise.git/db/mem"
"git.defalsify.org/vise.git/resource"
"git.defalsify.org/vise.git/persist" "git.defalsify.org/vise.git/persist"
"git.defalsify.org/vise.git/resource"
) )
type MemStorageService struct { type MemStorageService struct {
@ -39,4 +39,3 @@ func (mss *MemStorageService) GetUserdataDb(ctx context.Context) (db.Db, error)
func (mss *MemStorageService) GetResource(ctx context.Context) (resource.Resource, error) { func (mss *MemStorageService) GetResource(ctx context.Context) (resource.Resource, error) {
return mss.rs, nil return mss.rs, nil
} }