wip-menu-select-fix #78
@ -12,17 +12,13 @@ import (
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"git.defalsify.org/vise.git/asm"
|
||||
"git.defalsify.org/vise.git/db"
|
||||
fsdb "git.defalsify.org/vise.git/db/fs"
|
||||
gdbmdb "git.defalsify.org/vise.git/db/gdbm"
|
||||
"git.defalsify.org/vise.git/engine"
|
||||
"git.defalsify.org/vise.git/logging"
|
||||
"git.defalsify.org/vise.git/resource"
|
||||
|
||||
"git.grassecon.net/urdt/ussd/internal/handlers"
|
||||
"git.grassecon.net/urdt/ussd/internal/handlers/ussd"
|
||||
httpserver "git.grassecon.net/urdt/ussd/internal/http"
|
||||
"git.grassecon.net/urdt/ussd/internal/storage"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -68,96 +64,6 @@ func(arp *atRequestParser) GetInput(rq any) ([]byte, error) {
|
||||
return []byte(parts[len(parts)-1]), nil
|
||||
}
|
||||
|
||||
|
||||
func getFlags(fp string, debug bool) (*asm.FlagParser, error) {
|
||||
flagParser := asm.NewFlagParser().WithDebug()
|
||||
_, err := flagParser.Load(fp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return flagParser, nil
|
||||
}
|
||||
|
||||
func getHandler(appFlags *asm.FlagParser, rs *resource.DbResource, userdataStore db.Db) (*ussd.Handlers, error) {
|
||||
|
||||
ussdHandlers, err := ussd.NewHandlers(appFlags, userdataStore)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rs.AddLocalFunc("set_language", ussdHandlers.SetLanguage)
|
||||
rs.AddLocalFunc("create_account", ussdHandlers.CreateAccount)
|
||||
rs.AddLocalFunc("save_pin", ussdHandlers.SavePin)
|
||||
rs.AddLocalFunc("verify_pin", ussdHandlers.VerifyPin)
|
||||
rs.AddLocalFunc("check_identifier", ussdHandlers.CheckIdentifier)
|
||||
rs.AddLocalFunc("check_account_status", ussdHandlers.CheckAccountStatus)
|
||||
rs.AddLocalFunc("authorize_account", ussdHandlers.Authorize)
|
||||
rs.AddLocalFunc("quit", ussdHandlers.Quit)
|
||||
rs.AddLocalFunc("check_balance", ussdHandlers.CheckBalance)
|
||||
rs.AddLocalFunc("validate_recipient", ussdHandlers.ValidateRecipient)
|
||||
rs.AddLocalFunc("transaction_reset", ussdHandlers.TransactionReset)
|
||||
rs.AddLocalFunc("max_amount", ussdHandlers.MaxAmount)
|
||||
rs.AddLocalFunc("validate_amount", ussdHandlers.ValidateAmount)
|
||||
rs.AddLocalFunc("reset_transaction_amount", ussdHandlers.ResetTransactionAmount)
|
||||
rs.AddLocalFunc("get_recipient", ussdHandlers.GetRecipient)
|
||||
rs.AddLocalFunc("get_sender", ussdHandlers.GetSender)
|
||||
rs.AddLocalFunc("get_amount", ussdHandlers.GetAmount)
|
||||
rs.AddLocalFunc("reset_incorrect", ussdHandlers.ResetIncorrectPin)
|
||||
rs.AddLocalFunc("save_firstname", ussdHandlers.SaveFirstname)
|
||||
rs.AddLocalFunc("save_familyname", ussdHandlers.SaveFamilyname)
|
||||
rs.AddLocalFunc("save_gender", ussdHandlers.SaveGender)
|
||||
rs.AddLocalFunc("save_location", ussdHandlers.SaveLocation)
|
||||
rs.AddLocalFunc("save_yob", ussdHandlers.SaveYob)
|
||||
rs.AddLocalFunc("save_offerings", ussdHandlers.SaveOfferings)
|
||||
rs.AddLocalFunc("quit_with_balance", ussdHandlers.QuitWithBalance)
|
||||
rs.AddLocalFunc("reset_account_authorized", ussdHandlers.ResetAccountAuthorized)
|
||||
rs.AddLocalFunc("reset_allow_update", ussdHandlers.ResetAllowUpdate)
|
||||
rs.AddLocalFunc("get_profile_info", ussdHandlers.GetProfileInfo)
|
||||
rs.AddLocalFunc("verify_yob", ussdHandlers.VerifyYob)
|
||||
rs.AddLocalFunc("reset_incorrect_date_format", ussdHandlers.ResetIncorrectYob)
|
||||
rs.AddLocalFunc("set_reset_single_edit", ussdHandlers.SetResetSingleEdit)
|
||||
rs.AddLocalFunc("initiate_transaction", ussdHandlers.InitiateTransaction)
|
||||
rs.AddLocalFunc("save_temporary_pin", ussdHandlers.SaveTemporaryPin)
|
||||
rs.AddLocalFunc("verify_new_pin", ussdHandlers.VerifyNewPin)
|
||||
rs.AddLocalFunc("confirm_pin_change", ussdHandlers.ConfirmPinChange)
|
||||
rs.AddLocalFunc("quit_with_help",ussdHandlers.QuitWithHelp)
|
||||
|
||||
return ussdHandlers, nil
|
||||
}
|
||||
|
||||
func ensureDbDir(dbDir string) error {
|
||||
err := os.MkdirAll(dbDir, 0700)
|
||||
if err != nil {
|
||||
return fmt.Errorf("state dir create exited with error: %v\n", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getStateStore(dbDir string, ctx context.Context) (db.Db, error) {
|
||||
store := gdbmdb.NewGdbmDb()
|
||||
storeFile := path.Join(dbDir, "state.gdbm")
|
||||
store.Connect(ctx, storeFile)
|
||||
return store, nil
|
||||
}
|
||||
|
||||
func getUserdataDb(dbDir string, ctx context.Context) db.Db {
|
||||
store := gdbmdb.NewGdbmDb()
|
||||
storeFile := path.Join(dbDir, "userdata.gdbm")
|
||||
store.Connect(ctx, storeFile)
|
||||
|
||||
return store
|
||||
}
|
||||
|
||||
func getResource(resourceDir string, ctx context.Context) (resource.Resource, error) {
|
||||
store := fsdb.NewFsDb()
|
||||
err := store.Connect(ctx, resourceDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rfs := resource.NewDbResource(store)
|
||||
return rfs, nil
|
||||
}
|
||||
|
||||
|
||||
func main() {
|
||||
var dbDir string
|
||||
var resourceDir string
|
||||
@ -179,11 +85,6 @@ func main() {
|
||||
|
||||
ctx := context.Background()
|
||||
pfp := path.Join(scriptDir, "pp.csv")
|
||||
flagParser, err := getFlags(pfp, true)
|
||||
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
cfg := engine.Config{
|
||||
Root: "root",
|
||||
@ -197,19 +98,21 @@ func main() {
|
||||
cfg.EngineDebug = true
|
||||
}
|
||||
|
||||
rs, err := getResource(resourceDir, ctx)
|
||||
menuStorageService := storage.MenuStorageService{}
|
||||
|
||||
rs, err := menuStorageService.GetResource(scriptDir, ctx)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
err = ensureDbDir(dbDir)
|
||||
err = menuStorageService.EnsureDbDir(dbDir)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
userdataStore := getUserdataDb(dbDir, ctx)
|
||||
userdataStore := menuStorageService.GetUserdataDb(dbDir, ctx)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
@ -221,13 +124,21 @@ func main() {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
hl, err := getHandler(flagParser, dbResource, userdataStore)
|
||||
lhs, err := handlers.NewLocalHandlerService(pfp, true, dbResource, cfg, rs)
|
||||
lhs.WithDataStore(&userdataStore)
|
||||
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
stateStore, err := getStateStore(dbDir, ctx)
|
||||
hl, err := lhs.GetHandler()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
stateStore, err := menuStorageService.GetStateStore(dbDir, ctx)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
|
@ -9,16 +9,12 @@ import (
|
||||
"path"
|
||||
"syscall"
|
||||
|
||||
"git.defalsify.org/vise.git/asm"
|
||||
"git.defalsify.org/vise.git/db"
|
||||
fsdb "git.defalsify.org/vise.git/db/fs"
|
||||
gdbmdb "git.defalsify.org/vise.git/db/gdbm"
|
||||
"git.defalsify.org/vise.git/engine"
|
||||
"git.defalsify.org/vise.git/resource"
|
||||
"git.defalsify.org/vise.git/logging"
|
||||
"git.defalsify.org/vise.git/resource"
|
||||
|
||||
"git.grassecon.net/urdt/ussd/internal/handlers/ussd"
|
||||
"git.grassecon.net/urdt/ussd/internal/handlers"
|
||||
"git.grassecon.net/urdt/ussd/internal/storage"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -39,95 +35,6 @@ func(p *asyncRequestParser) GetInput(r any) ([]byte, error) {
|
||||
return p.input, nil
|
||||
}
|
||||
|
||||
func getFlags(fp string, debug bool) (*asm.FlagParser, error) {
|
||||
flagParser := asm.NewFlagParser().WithDebug()
|
||||
_, err := flagParser.Load(fp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return flagParser, nil
|
||||
}
|
||||
|
||||
func getHandler(appFlags *asm.FlagParser, rs *resource.DbResource, userdataStore db.Db) (*ussd.Handlers, error) {
|
||||
|
||||
ussdHandlers, err := ussd.NewHandlers(appFlags, userdataStore)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rs.AddLocalFunc("set_language", ussdHandlers.SetLanguage)
|
||||
rs.AddLocalFunc("create_account", ussdHandlers.CreateAccount)
|
||||
rs.AddLocalFunc("save_pin", ussdHandlers.SavePin)
|
||||
rs.AddLocalFunc("verify_pin", ussdHandlers.VerifyPin)
|
||||
rs.AddLocalFunc("check_identifier", ussdHandlers.CheckIdentifier)
|
||||
rs.AddLocalFunc("check_account_status", ussdHandlers.CheckAccountStatus)
|
||||
rs.AddLocalFunc("authorize_account", ussdHandlers.Authorize)
|
||||
rs.AddLocalFunc("quit", ussdHandlers.Quit)
|
||||
rs.AddLocalFunc("check_balance", ussdHandlers.CheckBalance)
|
||||
rs.AddLocalFunc("validate_recipient", ussdHandlers.ValidateRecipient)
|
||||
rs.AddLocalFunc("transaction_reset", ussdHandlers.TransactionReset)
|
||||
rs.AddLocalFunc("max_amount", ussdHandlers.MaxAmount)
|
||||
rs.AddLocalFunc("validate_amount", ussdHandlers.ValidateAmount)
|
||||
rs.AddLocalFunc("reset_transaction_amount", ussdHandlers.ResetTransactionAmount)
|
||||
rs.AddLocalFunc("get_recipient", ussdHandlers.GetRecipient)
|
||||
rs.AddLocalFunc("get_sender", ussdHandlers.GetSender)
|
||||
rs.AddLocalFunc("get_amount", ussdHandlers.GetAmount)
|
||||
rs.AddLocalFunc("reset_incorrect", ussdHandlers.ResetIncorrectPin)
|
||||
rs.AddLocalFunc("save_firstname", ussdHandlers.SaveFirstname)
|
||||
rs.AddLocalFunc("save_familyname", ussdHandlers.SaveFamilyname)
|
||||
rs.AddLocalFunc("save_gender", ussdHandlers.SaveGender)
|
||||
rs.AddLocalFunc("save_location", ussdHandlers.SaveLocation)
|
||||
rs.AddLocalFunc("save_yob", ussdHandlers.SaveYob)
|
||||
rs.AddLocalFunc("save_offerings", ussdHandlers.SaveOfferings)
|
||||
rs.AddLocalFunc("quit_with_balance", ussdHandlers.QuitWithBalance)
|
||||
rs.AddLocalFunc("reset_account_authorized", ussdHandlers.ResetAccountAuthorized)
|
||||
rs.AddLocalFunc("reset_allow_update", ussdHandlers.ResetAllowUpdate)
|
||||
rs.AddLocalFunc("get_profile_info", ussdHandlers.GetProfileInfo)
|
||||
rs.AddLocalFunc("verify_yob", ussdHandlers.VerifyYob)
|
||||
rs.AddLocalFunc("reset_incorrect_date_format", ussdHandlers.ResetIncorrectYob)
|
||||
rs.AddLocalFunc("set_reset_single_edit", ussdHandlers.SetResetSingleEdit)
|
||||
rs.AddLocalFunc("initiate_transaction", ussdHandlers.InitiateTransaction)
|
||||
rs.AddLocalFunc("save_temporary_pin", ussdHandlers.SaveTemporaryPin)
|
||||
rs.AddLocalFunc("verify_new_pin", ussdHandlers.VerifyNewPin)
|
||||
rs.AddLocalFunc("confirm_pin_change", ussdHandlers.ConfirmPinChange)
|
||||
rs.AddLocalFunc("quit_with_help",ussdHandlers.QuitWithHelp)
|
||||
|
||||
return ussdHandlers, nil
|
||||
}
|
||||
|
||||
func ensureDbDir(dbDir string) error {
|
||||
err := os.MkdirAll(dbDir, 0700)
|
||||
if err != nil {
|
||||
return fmt.Errorf("state dir create exited with error: %v\n", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getStateStore(dbDir string, ctx context.Context) (db.Db, error) {
|
||||
store := gdbmdb.NewGdbmDb()
|
||||
storeFile := path.Join(dbDir, "state.gdbm")
|
||||
store.Connect(ctx, storeFile)
|
||||
return store, nil
|
||||
}
|
||||
|
||||
func getUserdataDb(dbDir string, ctx context.Context) db.Db {
|
||||
store := gdbmdb.NewGdbmDb()
|
||||
storeFile := path.Join(dbDir, "userdata.gdbm")
|
||||
store.Connect(ctx, storeFile)
|
||||
|
||||
return store
|
||||
}
|
||||
|
||||
func getResource(resourceDir string, ctx context.Context) (resource.Resource, error) {
|
||||
store := fsdb.NewFsDb()
|
||||
err := store.Connect(ctx, resourceDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rfs := resource.NewDbResource(store)
|
||||
return rfs, nil
|
||||
}
|
||||
|
||||
|
||||
func main() {
|
||||
var sessionId string
|
||||
var dbDir string
|
||||
@ -151,11 +58,6 @@ func main() {
|
||||
|
||||
ctx := context.Background()
|
||||
pfp := path.Join(scriptDir, "pp.csv")
|
||||
flagParser, err := getFlags(pfp, true)
|
||||
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
cfg := engine.Config{
|
||||
Root: "root",
|
||||
@ -169,19 +71,20 @@ func main() {
|
||||
cfg.EngineDebug = true
|
||||
}
|
||||
|
||||
rs, err := getResource(resourceDir, ctx)
|
||||
menuStorageService := storage.MenuStorageService{}
|
||||
rs, err := menuStorageService.GetResource(scriptDir, ctx)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
err = ensureDbDir(dbDir)
|
||||
err = menuStorageService.EnsureDbDir(dbDir)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
userdataStore := getUserdataDb(dbDir, ctx)
|
||||
userdataStore := menuStorageService.GetUserdataDb(dbDir, ctx)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
@ -193,13 +96,16 @@ func main() {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
hl, err := getHandler(flagParser, dbResource, userdataStore)
|
||||
lhs, err := handlers.NewLocalHandlerService(pfp, true, dbResource, cfg, rs)
|
||||
lhs.WithDataStore(&userdataStore)
|
||||
|
||||
hl, err := lhs.GetHandler()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
stateStore, err := getStateStore(dbDir, ctx)
|
||||
stateStore, err := menuStorageService.GetStateStore(dbDir, ctx)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
|
121
cmd/http/main.go
121
cmd/http/main.go
@ -11,17 +11,13 @@ import (
|
||||
"strconv"
|
||||
"syscall"
|
||||
|
||||
"git.defalsify.org/vise.git/asm"
|
||||
"git.defalsify.org/vise.git/db"
|
||||
fsdb "git.defalsify.org/vise.git/db/fs"
|
||||
gdbmdb "git.defalsify.org/vise.git/db/gdbm"
|
||||
"git.defalsify.org/vise.git/engine"
|
||||
"git.defalsify.org/vise.git/resource"
|
||||
"git.defalsify.org/vise.git/logging"
|
||||
"git.defalsify.org/vise.git/resource"
|
||||
|
||||
"git.grassecon.net/urdt/ussd/internal/handlers/ussd"
|
||||
"git.grassecon.net/urdt/ussd/internal/handlers"
|
||||
httpserver "git.grassecon.net/urdt/ussd/internal/http"
|
||||
"git.grassecon.net/urdt/ussd/internal/storage"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -29,95 +25,6 @@ var (
|
||||
scriptDir = path.Join("services", "registration")
|
||||
)
|
||||
|
||||
func getFlags(fp string, debug bool) (*asm.FlagParser, error) {
|
||||
flagParser := asm.NewFlagParser().WithDebug()
|
||||
_, err := flagParser.Load(fp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return flagParser, nil
|
||||
}
|
||||
|
||||
func getHandler(appFlags *asm.FlagParser, rs *resource.DbResource, userdataStore db.Db) (*ussd.Handlers, error) {
|
||||
|
||||
ussdHandlers, err := ussd.NewHandlers(appFlags, userdataStore)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rs.AddLocalFunc("set_language", ussdHandlers.SetLanguage)
|
||||
rs.AddLocalFunc("create_account", ussdHandlers.CreateAccount)
|
||||
rs.AddLocalFunc("save_pin", ussdHandlers.SavePin)
|
||||
rs.AddLocalFunc("verify_pin", ussdHandlers.VerifyPin)
|
||||
rs.AddLocalFunc("check_identifier", ussdHandlers.CheckIdentifier)
|
||||
rs.AddLocalFunc("check_account_status", ussdHandlers.CheckAccountStatus)
|
||||
rs.AddLocalFunc("authorize_account", ussdHandlers.Authorize)
|
||||
rs.AddLocalFunc("quit", ussdHandlers.Quit)
|
||||
rs.AddLocalFunc("check_balance", ussdHandlers.CheckBalance)
|
||||
rs.AddLocalFunc("validate_recipient", ussdHandlers.ValidateRecipient)
|
||||
rs.AddLocalFunc("transaction_reset", ussdHandlers.TransactionReset)
|
||||
rs.AddLocalFunc("max_amount", ussdHandlers.MaxAmount)
|
||||
rs.AddLocalFunc("validate_amount", ussdHandlers.ValidateAmount)
|
||||
rs.AddLocalFunc("reset_transaction_amount", ussdHandlers.ResetTransactionAmount)
|
||||
rs.AddLocalFunc("get_recipient", ussdHandlers.GetRecipient)
|
||||
rs.AddLocalFunc("get_sender", ussdHandlers.GetSender)
|
||||
rs.AddLocalFunc("get_amount", ussdHandlers.GetAmount)
|
||||
rs.AddLocalFunc("reset_incorrect", ussdHandlers.ResetIncorrectPin)
|
||||
rs.AddLocalFunc("save_firstname", ussdHandlers.SaveFirstname)
|
||||
rs.AddLocalFunc("save_familyname", ussdHandlers.SaveFamilyname)
|
||||
rs.AddLocalFunc("save_gender", ussdHandlers.SaveGender)
|
||||
rs.AddLocalFunc("save_location", ussdHandlers.SaveLocation)
|
||||
rs.AddLocalFunc("save_yob", ussdHandlers.SaveYob)
|
||||
rs.AddLocalFunc("save_offerings", ussdHandlers.SaveOfferings)
|
||||
rs.AddLocalFunc("quit_with_balance", ussdHandlers.QuitWithBalance)
|
||||
rs.AddLocalFunc("reset_account_authorized", ussdHandlers.ResetAccountAuthorized)
|
||||
rs.AddLocalFunc("reset_allow_update", ussdHandlers.ResetAllowUpdate)
|
||||
rs.AddLocalFunc("get_profile_info", ussdHandlers.GetProfileInfo)
|
||||
rs.AddLocalFunc("verify_yob", ussdHandlers.VerifyYob)
|
||||
rs.AddLocalFunc("reset_incorrect_date_format", ussdHandlers.ResetIncorrectYob)
|
||||
rs.AddLocalFunc("set_reset_single_edit", ussdHandlers.SetResetSingleEdit)
|
||||
rs.AddLocalFunc("initiate_transaction", ussdHandlers.InitiateTransaction)
|
||||
rs.AddLocalFunc("save_temporary_pin", ussdHandlers.SaveTemporaryPin)
|
||||
rs.AddLocalFunc("verify_new_pin", ussdHandlers.VerifyNewPin)
|
||||
rs.AddLocalFunc("confirm_pin_change", ussdHandlers.ConfirmPinChange)
|
||||
rs.AddLocalFunc("quit_with_help",ussdHandlers.QuitWithHelp)
|
||||
|
||||
return ussdHandlers, nil
|
||||
}
|
||||
|
||||
func ensureDbDir(dbDir string) error {
|
||||
err := os.MkdirAll(dbDir, 0700)
|
||||
if err != nil {
|
||||
return fmt.Errorf("state dir create exited with error: %v\n", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getStateStore(dbDir string, ctx context.Context) (db.Db, error) {
|
||||
store := gdbmdb.NewGdbmDb()
|
||||
storeFile := path.Join(dbDir, "state.gdbm")
|
||||
store.Connect(ctx, storeFile)
|
||||
return store, nil
|
||||
}
|
||||
|
||||
func getUserdataDb(dbDir string, ctx context.Context) db.Db {
|
||||
store := gdbmdb.NewGdbmDb()
|
||||
storeFile := path.Join(dbDir, "userdata.gdbm")
|
||||
store.Connect(ctx, storeFile)
|
||||
|
||||
return store
|
||||
}
|
||||
|
||||
func getResource(resourceDir string, ctx context.Context) (resource.Resource, error) {
|
||||
store := fsdb.NewFsDb()
|
||||
err := store.Connect(ctx, resourceDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rfs := resource.NewDbResource(store)
|
||||
return rfs, nil
|
||||
}
|
||||
|
||||
|
||||
func main() {
|
||||
var dbDir string
|
||||
var resourceDir string
|
||||
@ -139,11 +46,6 @@ func main() {
|
||||
|
||||
ctx := context.Background()
|
||||
pfp := path.Join(scriptDir, "pp.csv")
|
||||
flagParser, err := getFlags(pfp, true)
|
||||
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
cfg := engine.Config{
|
||||
Root: "root",
|
||||
@ -157,19 +59,20 @@ func main() {
|
||||
cfg.EngineDebug = true
|
||||
}
|
||||
|
||||
rs, err := getResource(resourceDir, ctx)
|
||||
menuStorageService := storage.MenuStorageService{}
|
||||
rs, err := menuStorageService.GetResource(scriptDir, ctx)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
err = ensureDbDir(dbDir)
|
||||
err = menuStorageService.EnsureDbDir(dbDir)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
userdataStore := getUserdataDb(dbDir, ctx)
|
||||
userdataStore := menuStorageService.GetUserdataDb(dbDir, ctx)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
@ -181,13 +84,21 @@ func main() {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
hl, err := getHandler(flagParser, dbResource, userdataStore)
|
||||
lhs, err := handlers.NewLocalHandlerService(pfp, true, dbResource, cfg, rs)
|
||||
lhs.WithDataStore(&userdataStore)
|
||||
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
stateStore, err := getStateStore(dbDir, ctx)
|
||||
hl, err := lhs.GetHandler()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
stateStore, err := menuStorageService.GetStateStore(dbDir, ctx)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
|
140
cmd/main.go
140
cmd/main.go
@ -7,15 +7,11 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"git.defalsify.org/vise.git/asm"
|
||||
"git.defalsify.org/vise.git/db"
|
||||
fsdb "git.defalsify.org/vise.git/db/fs"
|
||||
gdbmdb "git.defalsify.org/vise.git/db/gdbm"
|
||||
"git.defalsify.org/vise.git/engine"
|
||||
"git.defalsify.org/vise.git/logging"
|
||||
"git.defalsify.org/vise.git/persist"
|
||||
"git.defalsify.org/vise.git/resource"
|
||||
"git.grassecon.net/urdt/ussd/internal/handlers/ussd"
|
||||
"git.grassecon.net/urdt/ussd/internal/handlers"
|
||||
"git.grassecon.net/urdt/ussd/internal/storage"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -23,106 +19,6 @@ var (
|
||||
scriptDir = path.Join("services", "registration")
|
||||
)
|
||||
|
||||
func getParser(fp string, debug bool) (*asm.FlagParser, error) {
|
||||
flagParser := asm.NewFlagParser().WithDebug()
|
||||
_, err := flagParser.Load(fp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return flagParser, nil
|
||||
}
|
||||
|
||||
func getHandler(appFlags *asm.FlagParser, rs *resource.DbResource, pe *persist.Persister, userdataStore db.Db) (*ussd.Handlers, error) {
|
||||
|
||||
ussdHandlers, err := ussd.NewHandlers(appFlags, userdataStore)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ussdHandlers = ussdHandlers.WithPersister(pe)
|
||||
rs.AddLocalFunc("set_language", ussdHandlers.SetLanguage)
|
||||
rs.AddLocalFunc("create_account", ussdHandlers.CreateAccount)
|
||||
rs.AddLocalFunc("save_pin", ussdHandlers.SavePin)
|
||||
rs.AddLocalFunc("verify_pin", ussdHandlers.VerifyPin)
|
||||
rs.AddLocalFunc("check_identifier", ussdHandlers.CheckIdentifier)
|
||||
rs.AddLocalFunc("check_account_status", ussdHandlers.CheckAccountStatus)
|
||||
rs.AddLocalFunc("authorize_account", ussdHandlers.Authorize)
|
||||
rs.AddLocalFunc("quit", ussdHandlers.Quit)
|
||||
rs.AddLocalFunc("check_balance", ussdHandlers.CheckBalance)
|
||||
rs.AddLocalFunc("validate_recipient", ussdHandlers.ValidateRecipient)
|
||||
rs.AddLocalFunc("transaction_reset", ussdHandlers.TransactionReset)
|
||||
rs.AddLocalFunc("max_amount", ussdHandlers.MaxAmount)
|
||||
rs.AddLocalFunc("validate_amount", ussdHandlers.ValidateAmount)
|
||||
rs.AddLocalFunc("reset_transaction_amount", ussdHandlers.ResetTransactionAmount)
|
||||
rs.AddLocalFunc("get_recipient", ussdHandlers.GetRecipient)
|
||||
rs.AddLocalFunc("get_sender", ussdHandlers.GetSender)
|
||||
rs.AddLocalFunc("get_amount", ussdHandlers.GetAmount)
|
||||
rs.AddLocalFunc("reset_incorrect", ussdHandlers.ResetIncorrectPin)
|
||||
rs.AddLocalFunc("save_firstname", ussdHandlers.SaveFirstname)
|
||||
rs.AddLocalFunc("save_familyname", ussdHandlers.SaveFamilyname)
|
||||
rs.AddLocalFunc("save_gender", ussdHandlers.SaveGender)
|
||||
rs.AddLocalFunc("save_location", ussdHandlers.SaveLocation)
|
||||
rs.AddLocalFunc("save_yob", ussdHandlers.SaveYob)
|
||||
rs.AddLocalFunc("save_offerings", ussdHandlers.SaveOfferings)
|
||||
rs.AddLocalFunc("quit_with_balance", ussdHandlers.QuitWithBalance)
|
||||
rs.AddLocalFunc("reset_account_authorized", ussdHandlers.ResetAccountAuthorized)
|
||||
rs.AddLocalFunc("reset_allow_update", ussdHandlers.ResetAllowUpdate)
|
||||
rs.AddLocalFunc("get_profile_info", ussdHandlers.GetProfileInfo)
|
||||
rs.AddLocalFunc("verify_yob", ussdHandlers.VerifyYob)
|
||||
rs.AddLocalFunc("reset_incorrect_date_format", ussdHandlers.ResetIncorrectYob)
|
||||
rs.AddLocalFunc("set_reset_single_edit", ussdHandlers.SetResetSingleEdit)
|
||||
rs.AddLocalFunc("initiate_transaction", ussdHandlers.InitiateTransaction)
|
||||
rs.AddLocalFunc("save_temporary_pin", ussdHandlers.SaveTemporaryPin)
|
||||
rs.AddLocalFunc("verify_new_pin", ussdHandlers.VerifyNewPin)
|
||||
rs.AddLocalFunc("confirm_pin_change", ussdHandlers.ConfirmPinChange)
|
||||
rs.AddLocalFunc("quit_with_help",ussdHandlers.QuitWithHelp)
|
||||
|
||||
return ussdHandlers, nil
|
||||
}
|
||||
|
||||
func ensureDbDir(dbDir string) error {
|
||||
err := os.MkdirAll(dbDir, 0700)
|
||||
if err != nil {
|
||||
return fmt.Errorf("state dir create exited with error: %v\n", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getPersister(dbDir string, ctx context.Context) (*persist.Persister, error) {
|
||||
err := ensureDbDir(dbDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
store := gdbmdb.NewGdbmDb()
|
||||
storeFile := path.Join(dbDir, "state.gdbm")
|
||||
store.Connect(ctx, storeFile)
|
||||
pr := persist.NewPersister(store)
|
||||
return pr, nil
|
||||
}
|
||||
|
||||
func getUserdataDb(dbDir string, ctx context.Context) db.Db {
|
||||
store := gdbmdb.NewGdbmDb()
|
||||
storeFile := path.Join(dbDir, "userdata.gdbm")
|
||||
store.Connect(ctx, storeFile)
|
||||
|
||||
return store
|
||||
}
|
||||
|
||||
func getResource(resourceDir string, ctx context.Context) (resource.Resource, error) {
|
||||
store := fsdb.NewFsDb()
|
||||
err := store.Connect(ctx, resourceDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rfs := resource.NewDbResource(store)
|
||||
return rfs, nil
|
||||
}
|
||||
|
||||
func getEngine(cfg engine.Config, rs resource.Resource, pr *persist.Persister) *engine.DefaultEngine {
|
||||
en := engine.NewEngine(cfg, rs)
|
||||
en = en.WithPersister(pr)
|
||||
return en
|
||||
}
|
||||
|
||||
func main() {
|
||||
var dbDir string
|
||||
var size uint
|
||||
@ -139,11 +35,6 @@ func main() {
|
||||
ctx := context.Background()
|
||||
ctx = context.WithValue(ctx, "SessionId", sessionId)
|
||||
pfp := path.Join(scriptDir, "pp.csv")
|
||||
flagParser, err := getParser(pfp, true)
|
||||
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
cfg := engine.Config{
|
||||
Root: "root",
|
||||
@ -152,19 +43,27 @@ func main() {
|
||||
FlagCount: uint32(16),
|
||||
}
|
||||
|
||||
rs, err := getResource(scriptDir, ctx)
|
||||
menuStorageService := storage.MenuStorageService{}
|
||||
|
||||
err := menuStorageService.EnsureDbDir(dbDir)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
pe, err := getPersister(dbDir, ctx)
|
||||
rs, err := menuStorageService.GetResource(scriptDir, ctx)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
store := getUserdataDb(dbDir, ctx)
|
||||
pe, err := menuStorageService.GetPersister(dbDir, ctx)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
userdatastore := menuStorageService.GetUserdataDb(dbDir, ctx)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
@ -176,13 +75,22 @@ func main() {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
hl, err := getHandler(flagParser, dbResource, pe, store)
|
||||
lhs, err := handlers.NewLocalHandlerService(pfp, true, dbResource, cfg, rs)
|
||||
lhs.WithDataStore(&userdatastore)
|
||||
lhs.WithPersister(pe)
|
||||
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
en := getEngine(cfg, rs, pe)
|
||||
hl, err := lhs.GetHandler()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
en := lhs.GetEngine()
|
||||
en = en.WithFirst(hl.Init)
|
||||
if debug {
|
||||
en = en.WithDebug(nil)
|
||||
|
105
internal/handlers/handlerservice.go
Normal file
105
internal/handlers/handlerservice.go
Normal file
@ -0,0 +1,105 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"git.defalsify.org/vise.git/asm"
|
||||
"git.defalsify.org/vise.git/db"
|
||||
"git.defalsify.org/vise.git/engine"
|
||||
"git.defalsify.org/vise.git/persist"
|
||||
"git.defalsify.org/vise.git/resource"
|
||||
"git.grassecon.net/urdt/ussd/internal/handlers/ussd"
|
||||
)
|
||||
|
||||
type HandlerService interface {
|
||||
GetHandler() (*ussd.Handlers, error)
|
||||
}
|
||||
|
||||
func getParser(fp string, debug bool) (*asm.FlagParser, error) {
|
||||
flagParser := asm.NewFlagParser().WithDebug()
|
||||
_, err := flagParser.Load(fp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return flagParser, nil
|
||||
}
|
||||
|
||||
type LocalHandlerService struct {
|
||||
Parser *asm.FlagParser
|
||||
DbRs *resource.DbResource
|
||||
Pe *persist.Persister
|
||||
UserdataStore *db.Db
|
||||
Cfg engine.Config
|
||||
Rs resource.Resource
|
||||
}
|
||||
|
||||
func NewLocalHandlerService(fp string, debug bool, dbResource *resource.DbResource, cfg engine.Config, rs resource.Resource) (*LocalHandlerService, error) {
|
||||
parser, err := getParser(fp, debug)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &LocalHandlerService{
|
||||
Parser: parser,
|
||||
DbRs: dbResource,
|
||||
Cfg: cfg,
|
||||
Rs: rs,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (localHandlerService *LocalHandlerService) WithPersister(Pe *persist.Persister) {
|
||||
localHandlerService.Pe = Pe
|
||||
}
|
||||
|
||||
func (localHandlerService *LocalHandlerService) WithDataStore(db *db.Db) {
|
||||
localHandlerService.UserdataStore = db
|
||||
}
|
||||
|
||||
func (localHandlerService *LocalHandlerService) GetHandler() (*ussd.Handlers, error) {
|
||||
ussdHandlers, err := ussd.NewHandlers(localHandlerService.Parser, *localHandlerService.UserdataStore)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ussdHandlers = ussdHandlers.WithPersister(localHandlerService.Pe)
|
||||
localHandlerService.DbRs.AddLocalFunc("set_language", ussdHandlers.SetLanguage)
|
||||
localHandlerService.DbRs.AddLocalFunc("create_account", ussdHandlers.CreateAccount)
|
||||
localHandlerService.DbRs.AddLocalFunc("save_pin", ussdHandlers.SavePin)
|
||||
localHandlerService.DbRs.AddLocalFunc("verify_pin", ussdHandlers.VerifyPin)
|
||||
localHandlerService.DbRs.AddLocalFunc("check_identifier", ussdHandlers.CheckIdentifier)
|
||||
localHandlerService.DbRs.AddLocalFunc("check_account_status", ussdHandlers.CheckAccountStatus)
|
||||
localHandlerService.DbRs.AddLocalFunc("authorize_account", ussdHandlers.Authorize)
|
||||
localHandlerService.DbRs.AddLocalFunc("quit", ussdHandlers.Quit)
|
||||
localHandlerService.DbRs.AddLocalFunc("check_balance", ussdHandlers.CheckBalance)
|
||||
localHandlerService.DbRs.AddLocalFunc("validate_recipient", ussdHandlers.ValidateRecipient)
|
||||
localHandlerService.DbRs.AddLocalFunc("transaction_reset", ussdHandlers.TransactionReset)
|
||||
localHandlerService.DbRs.AddLocalFunc("max_amount", ussdHandlers.MaxAmount)
|
||||
localHandlerService.DbRs.AddLocalFunc("validate_amount", ussdHandlers.ValidateAmount)
|
||||
localHandlerService.DbRs.AddLocalFunc("reset_transaction_amount", ussdHandlers.ResetTransactionAmount)
|
||||
localHandlerService.DbRs.AddLocalFunc("get_recipient", ussdHandlers.GetRecipient)
|
||||
localHandlerService.DbRs.AddLocalFunc("get_sender", ussdHandlers.GetSender)
|
||||
localHandlerService.DbRs.AddLocalFunc("get_amount", ussdHandlers.GetAmount)
|
||||
localHandlerService.DbRs.AddLocalFunc("reset_incorrect", ussdHandlers.ResetIncorrectPin)
|
||||
localHandlerService.DbRs.AddLocalFunc("save_firstname", ussdHandlers.SaveFirstname)
|
||||
localHandlerService.DbRs.AddLocalFunc("save_familyname", ussdHandlers.SaveFamilyname)
|
||||
localHandlerService.DbRs.AddLocalFunc("save_gender", ussdHandlers.SaveGender)
|
||||
localHandlerService.DbRs.AddLocalFunc("save_location", ussdHandlers.SaveLocation)
|
||||
localHandlerService.DbRs.AddLocalFunc("save_yob", ussdHandlers.SaveYob)
|
||||
localHandlerService.DbRs.AddLocalFunc("save_offerings", ussdHandlers.SaveOfferings)
|
||||
localHandlerService.DbRs.AddLocalFunc("quit_with_balance", ussdHandlers.QuitWithBalance)
|
||||
localHandlerService.DbRs.AddLocalFunc("reset_account_authorized", ussdHandlers.ResetAccountAuthorized)
|
||||
localHandlerService.DbRs.AddLocalFunc("reset_allow_update", ussdHandlers.ResetAllowUpdate)
|
||||
localHandlerService.DbRs.AddLocalFunc("get_profile_info", ussdHandlers.GetProfileInfo)
|
||||
localHandlerService.DbRs.AddLocalFunc("verify_yob", ussdHandlers.VerifyYob)
|
||||
localHandlerService.DbRs.AddLocalFunc("reset_incorrect_date_format", ussdHandlers.ResetIncorrectYob)
|
||||
localHandlerService.DbRs.AddLocalFunc("set_reset_single_edit", ussdHandlers.SetResetSingleEdit)
|
||||
localHandlerService.DbRs.AddLocalFunc("initiate_transaction", ussdHandlers.InitiateTransaction)
|
||||
localHandlerService.DbRs.AddLocalFunc("save_temporary_pin", ussdHandlers.SaveTemporaryPin)
|
||||
localHandlerService.DbRs.AddLocalFunc("verify_new_pin", ussdHandlers.VerifyNewPin)
|
||||
localHandlerService.DbRs.AddLocalFunc("confirm_pin_change", ussdHandlers.ConfirmPinChange)
|
||||
localHandlerService.DbRs.AddLocalFunc("quit_with_help", ussdHandlers.QuitWithHelp)
|
||||
|
||||
return ussdHandlers, nil
|
||||
}
|
||||
|
||||
func (localHandlerService *LocalHandlerService) GetEngine() *engine.DefaultEngine {
|
||||
en := engine.NewEngine(localHandlerService.Cfg, localHandlerService.Rs)
|
||||
en = en.WithPersister(localHandlerService.Pe)
|
||||
return en
|
||||
}
|
@ -29,11 +29,6 @@ var (
|
||||
translationDir = path.Join(scriptDir, "locale")
|
||||
)
|
||||
|
||||
type FSData struct {
|
||||
Path string
|
||||
St *state.State
|
||||
}
|
||||
|
||||
// FlagManager handles centralized flag management
|
||||
type FlagManager struct {
|
||||
parser *asm.FlagParser
|
||||
|
@ -11,7 +11,7 @@ import (
|
||||
"git.defalsify.org/vise.git/db"
|
||||
"git.defalsify.org/vise.git/resource"
|
||||
"git.defalsify.org/vise.git/state"
|
||||
"git.grassecon.net/urdt/ussd/internal/handlers/ussd/mocks"
|
||||
"git.grassecon.net/urdt/ussd/internal/mocks"
|
||||
"git.grassecon.net/urdt/ussd/internal/models"
|
||||
"git.grassecon.net/urdt/ussd/internal/utils"
|
||||
"github.com/alecthomas/assert/v2"
|
||||
|
@ -32,6 +32,7 @@ func (ash *ATSessionHandler) ServeHTTP(w http.ResponseWriter, req *http.Request)
|
||||
if err != nil {
|
||||
logg.ErrorCtxf(rqs.Ctx, "", "header processing error", err)
|
||||
ash.writeError(w, 400, err)
|
||||
return
|
||||
}
|
||||
rqs.Config = cfg
|
||||
rqs.Input, err = rp.GetInput(req)
|
||||
@ -43,14 +44,12 @@ func (ash *ATSessionHandler) ServeHTTP(w http.ResponseWriter, req *http.Request)
|
||||
|
||||
rqs, err = ash.Process(rqs)
|
||||
switch err {
|
||||
case handlers.ErrStorage:
|
||||
code = 500
|
||||
case handlers.ErrEngineInit:
|
||||
code = 500
|
||||
case handlers.ErrEngineExec:
|
||||
case nil: // set code to 200 if no err
|
||||
code = 200
|
||||
case handlers.ErrStorage, handlers.ErrEngineInit, handlers.ErrEngineExec, handlers.ErrEngineType:
|
||||
code = 500
|
||||
default:
|
||||
code = 200
|
||||
code = 500
|
||||
}
|
||||
|
||||
if code != 200 {
|
||||
|
449
internal/http/http_test.go
Normal file
449
internal/http/http_test.go
Normal file
@ -0,0 +1,449 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.defalsify.org/vise.git/engine"
|
||||
"git.grassecon.net/urdt/ussd/internal/handlers"
|
||||
"git.grassecon.net/urdt/ussd/internal/mocks/httpmocks"
|
||||
)
|
||||
|
||||
// invalidRequestType is a custom type to test invalid request scenarios
|
||||
type invalidRequestType struct{}
|
||||
|
||||
// errorReader is a helper type that always returns an error when Read is called
|
||||
type errorReader struct{}
|
||||
|
||||
func (e *errorReader) Read(p []byte) (n int, err error) {
|
||||
return 0, errors.New("read error")
|
||||
}
|
||||
|
||||
func TestNewATSessionHandler(t *testing.T) {
|
||||
mockHandler := &httpmocks.MockRequestHandler{}
|
||||
ash := NewATSessionHandler(mockHandler)
|
||||
|
||||
if ash == nil {
|
||||
t.Fatal("NewATSessionHandler returned nil")
|
||||
}
|
||||
|
||||
if ash.SessionHandler == nil {
|
||||
t.Fatal("SessionHandler is nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestATSessionHandler_ServeHTTP(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
setupMocks func(*httpmocks.MockRequestHandler, *httpmocks.MockRequestParser, *httpmocks.MockEngine)
|
||||
formData url.Values
|
||||
expectedStatus int
|
||||
expectedBody string
|
||||
}{
|
||||
{
|
||||
name: "Successful request",
|
||||
setupMocks: func(mh *httpmocks.MockRequestHandler, mrp *httpmocks.MockRequestParser, me *httpmocks.MockEngine) {
|
||||
mrp.GetSessionIdFunc = func(rq any) (string, error) {
|
||||
req := rq.(*http.Request)
|
||||
return req.FormValue("phoneNumber"), nil
|
||||
}
|
||||
mrp.GetInputFunc = func(rq any) ([]byte, error) {
|
||||
req := rq.(*http.Request)
|
||||
text := req.FormValue("text")
|
||||
parts := strings.Split(text, "*")
|
||||
return []byte(parts[len(parts)-1]), nil
|
||||
}
|
||||
mh.ProcessFunc = func(rqs handlers.RequestSession) (handlers.RequestSession, error) {
|
||||
rqs.Continue = true
|
||||
rqs.Engine = me
|
||||
return rqs, nil
|
||||
}
|
||||
mh.GetConfigFunc = func() engine.Config { return engine.Config{} }
|
||||
mh.GetRequestParserFunc = func() handlers.RequestParser { return mrp }
|
||||
mh.OutputFunc = func(rs handlers.RequestSession) (handlers.RequestSession, error) { return rs, nil }
|
||||
mh.ResetFunc = func(rs handlers.RequestSession) (handlers.RequestSession, error) { return rs, nil }
|
||||
me.WriteResultFunc = func(context.Context, io.Writer) (int, error) { return 0, nil }
|
||||
},
|
||||
formData: url.Values{
|
||||
"phoneNumber": []string{"+1234567890"},
|
||||
"text": []string{"1*2*3"},
|
||||
},
|
||||
expectedStatus: http.StatusOK,
|
||||
expectedBody: "CON ",
|
||||
},
|
||||
{
|
||||
name: "GetSessionId error",
|
||||
setupMocks: func(mh *httpmocks.MockRequestHandler, mrp *httpmocks.MockRequestParser, me *httpmocks.MockEngine) {
|
||||
mrp.GetSessionIdFunc = func(rq any) (string, error) {
|
||||
return "", errors.New("no phone number found")
|
||||
}
|
||||
mh.GetConfigFunc = func() engine.Config { return engine.Config{} }
|
||||
mh.GetRequestParserFunc = func() handlers.RequestParser { return mrp }
|
||||
},
|
||||
formData: url.Values{
|
||||
"text": []string{"1*2*3"},
|
||||
},
|
||||
expectedStatus: http.StatusBadRequest,
|
||||
expectedBody: "",
|
||||
},
|
||||
{
|
||||
name: "GetInput error",
|
||||
setupMocks: func(mh *httpmocks.MockRequestHandler, mrp *httpmocks.MockRequestParser, me *httpmocks.MockEngine) {
|
||||
mrp.GetSessionIdFunc = func(rq any) (string, error) {
|
||||
req := rq.(*http.Request)
|
||||
return req.FormValue("phoneNumber"), nil
|
||||
}
|
||||
mrp.GetInputFunc = func(rq any) ([]byte, error) {
|
||||
return nil, errors.New("no input found")
|
||||
}
|
||||
mh.GetConfigFunc = func() engine.Config { return engine.Config{} }
|
||||
mh.GetRequestParserFunc = func() handlers.RequestParser { return mrp }
|
||||
},
|
||||
formData: url.Values{
|
||||
"phoneNumber": []string{"+1234567890"},
|
||||
},
|
||||
expectedStatus: http.StatusBadRequest,
|
||||
expectedBody: "",
|
||||
},
|
||||
{
|
||||
name: "Process error",
|
||||
setupMocks: func(mh *httpmocks.MockRequestHandler, mrp *httpmocks.MockRequestParser, me *httpmocks.MockEngine) {
|
||||
mrp.GetSessionIdFunc = func(rq any) (string, error) {
|
||||
req := rq.(*http.Request)
|
||||
return req.FormValue("phoneNumber"), nil
|
||||
}
|
||||
mrp.GetInputFunc = func(rq any) ([]byte, error) {
|
||||
req := rq.(*http.Request)
|
||||
text := req.FormValue("text")
|
||||
parts := strings.Split(text, "*")
|
||||
return []byte(parts[len(parts)-1]), nil
|
||||
}
|
||||
mh.ProcessFunc = func(rqs handlers.RequestSession) (handlers.RequestSession, error) {
|
||||
return rqs, handlers.ErrStorage
|
||||
}
|
||||
mh.GetConfigFunc = func() engine.Config { return engine.Config{} }
|
||||
mh.GetRequestParserFunc = func() handlers.RequestParser { return mrp }
|
||||
},
|
||||
formData: url.Values{
|
||||
"phoneNumber": []string{"+1234567890"},
|
||||
"text": []string{"1*2*3"},
|
||||
},
|
||||
expectedStatus: http.StatusInternalServerError,
|
||||
expectedBody: "",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mockHandler := &httpmocks.MockRequestHandler{}
|
||||
mockRequestParser := &httpmocks.MockRequestParser{}
|
||||
mockEngine := &httpmocks.MockEngine{}
|
||||
tt.setupMocks(mockHandler, mockRequestParser, mockEngine)
|
||||
|
||||
ash := NewATSessionHandler(mockHandler)
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(tt.formData.Encode()))
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
ash.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != tt.expectedStatus {
|
||||
t.Errorf("Expected status %d, got %d", tt.expectedStatus, w.Code)
|
||||
}
|
||||
|
||||
if tt.expectedBody != "" && w.Body.String() != tt.expectedBody {
|
||||
t.Errorf("Expected body %q, got %q", tt.expectedBody, w.Body.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestATSessionHandler_Output(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input handlers.RequestSession
|
||||
expectedPrefix string
|
||||
expectedError bool
|
||||
}{
|
||||
{
|
||||
name: "Continue true",
|
||||
input: handlers.RequestSession{
|
||||
Continue: true,
|
||||
Engine: &httpmocks.MockEngine{
|
||||
WriteResultFunc: func(context.Context, io.Writer) (int, error) {
|
||||
return 0, nil
|
||||
},
|
||||
},
|
||||
Writer: &httpmocks.MockWriter{},
|
||||
},
|
||||
expectedPrefix: "CON ",
|
||||
expectedError: false,
|
||||
},
|
||||
{
|
||||
name: "Continue false",
|
||||
input: handlers.RequestSession{
|
||||
Continue: false,
|
||||
Engine: &httpmocks.MockEngine{
|
||||
WriteResultFunc: func(context.Context, io.Writer) (int, error) {
|
||||
return 0, nil
|
||||
},
|
||||
},
|
||||
Writer: &httpmocks.MockWriter{},
|
||||
},
|
||||
expectedPrefix: "END ",
|
||||
expectedError: false,
|
||||
},
|
||||
{
|
||||
name: "WriteResult error",
|
||||
input: handlers.RequestSession{
|
||||
Continue: true,
|
||||
Engine: &httpmocks.MockEngine{
|
||||
WriteResultFunc: func(context.Context, io.Writer) (int, error) {
|
||||
return 0, errors.New("write error")
|
||||
},
|
||||
},
|
||||
Writer: &httpmocks.MockWriter{},
|
||||
},
|
||||
expectedPrefix: "CON ",
|
||||
expectedError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ash := &ATSessionHandler{}
|
||||
_, err := ash.Output(tt.input)
|
||||
|
||||
if tt.expectedError && err == nil {
|
||||
t.Error("Expected an error, but got nil")
|
||||
}
|
||||
|
||||
if !tt.expectedError && err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
mw := tt.input.Writer.(*httpmocks.MockWriter)
|
||||
if !mw.WriteStringCalled {
|
||||
t.Error("WriteString was not called")
|
||||
}
|
||||
|
||||
if mw.WrittenString != tt.expectedPrefix {
|
||||
t.Errorf("Expected prefix %q, got %q", tt.expectedPrefix, mw.WrittenString)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSessionHandler_ServeHTTP(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
sessionID string
|
||||
input []byte
|
||||
parserErr error
|
||||
processErr error
|
||||
outputErr error
|
||||
resetErr error
|
||||
expectedStatus int
|
||||
}{
|
||||
{
|
||||
name: "Success",
|
||||
sessionID: "123",
|
||||
input: []byte("test input"),
|
||||
expectedStatus: http.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "Missing Session ID",
|
||||
sessionID: "",
|
||||
parserErr: handlers.ErrSessionMissing,
|
||||
expectedStatus: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
name: "Process Error",
|
||||
sessionID: "123",
|
||||
input: []byte("test input"),
|
||||
processErr: handlers.ErrStorage,
|
||||
expectedStatus: http.StatusInternalServerError,
|
||||
},
|
||||
{
|
||||
name: "Output Error",
|
||||
sessionID: "123",
|
||||
input: []byte("test input"),
|
||||
outputErr: errors.New("output error"),
|
||||
expectedStatus: http.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "Reset Error",
|
||||
sessionID: "123",
|
||||
input: []byte("test input"),
|
||||
resetErr: errors.New("reset error"),
|
||||
expectedStatus: http.StatusOK,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mockRequestParser := &httpmocks.MockRequestParser{
|
||||
GetSessionIdFunc: func(any) (string, error) {
|
||||
return tt.sessionID, tt.parserErr
|
||||
},
|
||||
GetInputFunc: func(any) ([]byte, error) {
|
||||
return tt.input, nil
|
||||
},
|
||||
}
|
||||
|
||||
mockRequestHandler := &httpmocks.MockRequestHandler{
|
||||
ProcessFunc: func(rs handlers.RequestSession) (handlers.RequestSession, error) {
|
||||
return rs, tt.processErr
|
||||
},
|
||||
OutputFunc: func(rs handlers.RequestSession) (handlers.RequestSession, error) {
|
||||
return rs, tt.outputErr
|
||||
},
|
||||
ResetFunc: func(rs handlers.RequestSession) (handlers.RequestSession, error) {
|
||||
return rs, tt.resetErr
|
||||
},
|
||||
GetRequestParserFunc: func() handlers.RequestParser {
|
||||
return mockRequestParser
|
||||
},
|
||||
GetConfigFunc: func() engine.Config {
|
||||
return engine.Config{}
|
||||
},
|
||||
}
|
||||
|
||||
sessionHandler := ToSessionHandler(mockRequestHandler)
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, "/", bytes.NewBuffer(tt.input))
|
||||
req.Header.Set("X-Vise-Session", tt.sessionID)
|
||||
|
||||
rr := httptest.NewRecorder()
|
||||
|
||||
sessionHandler.ServeHTTP(rr, req)
|
||||
|
||||
if status := rr.Code; status != tt.expectedStatus {
|
||||
t.Errorf("handler returned wrong status code: got %v want %v",
|
||||
status, tt.expectedStatus)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSessionHandler_writeError(t *testing.T) {
|
||||
handler := &SessionHandler{}
|
||||
mockWriter := &httpmocks.MockWriter{}
|
||||
err := errors.New("test error")
|
||||
|
||||
handler.writeError(mockWriter, http.StatusBadRequest, err)
|
||||
|
||||
if mockWriter.WrittenString != "" {
|
||||
t.Errorf("Expected empty body, got %s", mockWriter.WrittenString)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultRequestParser_GetSessionId(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
request any
|
||||
expectedID string
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "Valid Session ID",
|
||||
request: func() *http.Request {
|
||||
req := httptest.NewRequest(http.MethodPost, "/", nil)
|
||||
req.Header.Set("X-Vise-Session", "123456")
|
||||
return req
|
||||
}(),
|
||||
expectedID: "123456",
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Missing Session ID",
|
||||
request: httptest.NewRequest(http.MethodPost, "/", nil),
|
||||
expectedID: "",
|
||||
expectedError: handlers.ErrSessionMissing,
|
||||
},
|
||||
{
|
||||
name: "Invalid Request Type",
|
||||
request: invalidRequestType{},
|
||||
expectedID: "",
|
||||
expectedError: handlers.ErrInvalidRequest,
|
||||
},
|
||||
}
|
||||
|
||||
parser := &DefaultRequestParser{}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
id, err := parser.GetSessionId(tt.request)
|
||||
|
||||
if id != tt.expectedID {
|
||||
t.Errorf("Expected session ID %s, got %s", tt.expectedID, id)
|
||||
}
|
||||
|
||||
if err != tt.expectedError {
|
||||
t.Errorf("Expected error %v, got %v", tt.expectedError, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultRequestParser_GetInput(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
request any
|
||||
expectedInput []byte
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "Valid Input",
|
||||
request: func() *http.Request {
|
||||
return httptest.NewRequest(http.MethodPost, "/", bytes.NewBufferString("test input"))
|
||||
}(),
|
||||
expectedInput: []byte("test input"),
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Empty Input",
|
||||
request: httptest.NewRequest(http.MethodPost, "/", nil),
|
||||
expectedInput: []byte{},
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Invalid Request Type",
|
||||
request: invalidRequestType{},
|
||||
expectedInput: nil,
|
||||
expectedError: handlers.ErrInvalidRequest,
|
||||
},
|
||||
{
|
||||
name: "Read Error",
|
||||
request: func() *http.Request {
|
||||
return httptest.NewRequest(http.MethodPost, "/", &errorReader{})
|
||||
}(),
|
||||
expectedInput: nil,
|
||||
expectedError: errors.New("read error"),
|
||||
},
|
||||
}
|
||||
|
||||
parser := &DefaultRequestParser{}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
input, err := parser.GetInput(tt.request)
|
||||
|
||||
if !bytes.Equal(input, tt.expectedInput) {
|
||||
t.Errorf("Expected input %s, got %s", tt.expectedInput, input)
|
||||
}
|
||||
|
||||
if err != tt.expectedError && (err == nil || err.Error() != tt.expectedError.Error()) {
|
||||
t.Errorf("Expected error %v, got %v", tt.expectedError, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
30
internal/mocks/httpmocks/enginemock.go
Normal file
30
internal/mocks/httpmocks/enginemock.go
Normal file
@ -0,0 +1,30 @@
|
||||
package httpmocks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
)
|
||||
|
||||
// MockEngine implements the engine.Engine interface for testing
|
||||
type MockEngine struct {
|
||||
InitFunc func(context.Context) (bool, error)
|
||||
ExecFunc func(context.Context, []byte) (bool, error)
|
||||
WriteResultFunc func(context.Context, io.Writer) (int, error)
|
||||
FinishFunc func() error
|
||||
}
|
||||
|
||||
func (m *MockEngine) Init(ctx context.Context) (bool, error) {
|
||||
return m.InitFunc(ctx)
|
||||
}
|
||||
|
||||
func (m *MockEngine) Exec(ctx context.Context, input []byte) (bool, error) {
|
||||
return m.ExecFunc(ctx, input)
|
||||
}
|
||||
|
||||
func (m *MockEngine) WriteResult(ctx context.Context, w io.Writer) (int, error) {
|
||||
return m.WriteResultFunc(ctx, w)
|
||||
}
|
||||
|
||||
func (m *MockEngine) Finish() error {
|
||||
return m.FinishFunc()
|
||||
}
|
47
internal/mocks/httpmocks/requesthandlermock.go
Normal file
47
internal/mocks/httpmocks/requesthandlermock.go
Normal file
@ -0,0 +1,47 @@
|
||||
package httpmocks
|
||||
|
||||
import (
|
||||
"git.defalsify.org/vise.git/engine"
|
||||
"git.defalsify.org/vise.git/persist"
|
||||
"git.defalsify.org/vise.git/resource"
|
||||
"git.grassecon.net/urdt/ussd/internal/handlers"
|
||||
)
|
||||
|
||||
// MockRequestHandler implements handlers.RequestHandler interface for testing
|
||||
type MockRequestHandler struct {
|
||||
ProcessFunc func(handlers.RequestSession) (handlers.RequestSession, error)
|
||||
GetConfigFunc func() engine.Config
|
||||
GetEngineFunc func(cfg engine.Config, rs resource.Resource, pe *persist.Persister) engine.Engine
|
||||
OutputFunc func(rs handlers.RequestSession) (handlers.RequestSession, error)
|
||||
ResetFunc func(rs handlers.RequestSession) (handlers.RequestSession, error)
|
||||
ShutdownFunc func()
|
||||
GetRequestParserFunc func() handlers.RequestParser
|
||||
}
|
||||
|
||||
func (m *MockRequestHandler) Process(rqs handlers.RequestSession) (handlers.RequestSession, error) {
|
||||
return m.ProcessFunc(rqs)
|
||||
}
|
||||
|
||||
func (m *MockRequestHandler) GetConfig() engine.Config {
|
||||
return m.GetConfigFunc()
|
||||
}
|
||||
|
||||
func (m *MockRequestHandler) GetEngine(cfg engine.Config, rs resource.Resource, pe *persist.Persister) engine.Engine {
|
||||
return m.GetEngineFunc(cfg, rs, pe)
|
||||
}
|
||||
|
||||
func (m *MockRequestHandler) Output(rs handlers.RequestSession) (handlers.RequestSession, error) {
|
||||
return m.OutputFunc(rs)
|
||||
}
|
||||
|
||||
func (m *MockRequestHandler) Reset(rs handlers.RequestSession) (handlers.RequestSession, error) {
|
||||
return m.ResetFunc(rs)
|
||||
}
|
||||
|
||||
func (m *MockRequestHandler) Shutdown() {
|
||||
m.ShutdownFunc()
|
||||
}
|
||||
|
||||
func (m *MockRequestHandler) GetRequestParser() handlers.RequestParser {
|
||||
return m.GetRequestParserFunc()
|
||||
}
|
15
internal/mocks/httpmocks/requestparsermock.go
Normal file
15
internal/mocks/httpmocks/requestparsermock.go
Normal file
@ -0,0 +1,15 @@
|
||||
package httpmocks
|
||||
|
||||
// MockRequestParser implements the handlers.RequestParser interface for testing
|
||||
type MockRequestParser struct {
|
||||
GetSessionIdFunc func(any) (string, error)
|
||||
GetInputFunc func(any) ([]byte, error)
|
||||
}
|
||||
|
||||
func (m *MockRequestParser) GetSessionId(rq any) (string, error) {
|
||||
return m.GetSessionIdFunc(rq)
|
||||
}
|
||||
|
||||
func (m *MockRequestParser) GetInput(rq any) ([]byte, error) {
|
||||
return m.GetInputFunc(rq)
|
||||
}
|
25
internal/mocks/httpmocks/writermock.go
Normal file
25
internal/mocks/httpmocks/writermock.go
Normal file
@ -0,0 +1,25 @@
|
||||
package httpmocks
|
||||
|
||||
import "net/http"
|
||||
|
||||
// MockWriter implements a mock io.Writer for testing
|
||||
type MockWriter struct {
|
||||
WriteStringCalled bool
|
||||
WrittenString string
|
||||
}
|
||||
|
||||
func (m *MockWriter) Write(p []byte) (n int, err error) {
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (m *MockWriter) WriteString(s string) (n int, err error) {
|
||||
m.WriteStringCalled = true
|
||||
m.WrittenString = s
|
||||
return len(s), nil
|
||||
}
|
||||
|
||||
func (m *MockWriter) Header() http.Header {
|
||||
return http.Header{}
|
||||
}
|
||||
|
||||
func (m *MockWriter) WriteHeader(statusCode int) {}
|
64
internal/storage/storageservice.go
Normal file
64
internal/storage/storageservice.go
Normal file
@ -0,0 +1,64 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"git.defalsify.org/vise.git/db"
|
||||
fsdb "git.defalsify.org/vise.git/db/fs"
|
||||
gdbmdb "git.defalsify.org/vise.git/db/gdbm"
|
||||
"git.defalsify.org/vise.git/persist"
|
||||
"git.defalsify.org/vise.git/resource"
|
||||
)
|
||||
|
||||
type StorageService interface {
|
||||
GetPersister(dbDir string, ctx context.Context) (*persist.Persister, error)
|
||||
GetUserdataDb(dbDir string, ctx context.Context) db.Db
|
||||
GetResource(resourceDir string, ctx context.Context) (resource.Resource, error)
|
||||
EnsureDbDir(dbDir string) error
|
||||
}
|
||||
|
||||
type MenuStorageService struct{}
|
||||
|
||||
func (menuStorageService *MenuStorageService) GetPersister(dbDir string, ctx context.Context) (*persist.Persister, error) {
|
||||
store := gdbmdb.NewGdbmDb()
|
||||
storeFile := path.Join(dbDir, "state.gdbm")
|
||||
store.Connect(ctx, storeFile)
|
||||
pr := persist.NewPersister(store)
|
||||
return pr, nil
|
||||
}
|
||||
|
||||
func (menuStorageService *MenuStorageService) GetUserdataDb(dbDir string, ctx context.Context) db.Db {
|
||||
store := gdbmdb.NewGdbmDb()
|
||||
storeFile := path.Join(dbDir, "userdata.gdbm")
|
||||
store.Connect(ctx, storeFile)
|
||||
|
||||
return store
|
||||
}
|
||||
|
||||
func (menuStorageService *MenuStorageService) GetResource(resourceDir string, ctx context.Context) (resource.Resource, error) {
|
||||
store := fsdb.NewFsDb()
|
||||
err := store.Connect(ctx, resourceDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rfs := resource.NewDbResource(store)
|
||||
return rfs, nil
|
||||
}
|
||||
|
||||
func (menuStorageService *MenuStorageService) GetStateStore(dbDir string, ctx context.Context) (db.Db, error) {
|
||||
store := gdbmdb.NewGdbmDb()
|
||||
storeFile := path.Join(dbDir, "state.gdbm")
|
||||
store.Connect(ctx, storeFile)
|
||||
return store, nil
|
||||
}
|
||||
|
||||
func (menuStorageService *MenuStorageService) EnsureDbDir(dbDir string) error {
|
||||
err := os.MkdirAll(dbDir, 0700)
|
||||
if err != nil {
|
||||
return fmt.Errorf("state dir create exited with error: %v\n", err)
|
||||
}
|
||||
return nil
|
||||
}
|
Loading…
Reference in New Issue
Block a user