Compare commits

..

1 Commits

Author SHA1 Message Date
alfred-mk
d2384d3429 Serve the menu on an HTTP server 2024-09-10 13:48:37 +03:00
17 changed files with 390 additions and 2331 deletions

View File

@@ -1,215 +0,0 @@
package main
import (
"context"
"flag"
"fmt"
"net/http"
"os"
"os/signal"
"path"
"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.grassecon.net/urdt/ussd/internal/handlers/ussd"
httpserver "git.grassecon.net/urdt/ussd/internal/http"
)
var (
logg = logging.NewVanilla()
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("select_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)
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
var size uint
var engineDebug bool
var stateDebug bool
var host string
var port uint
flag.StringVar(&dbDir, "dbdir", ".state", "database dir to read from")
flag.StringVar(&resourceDir, "resourcedir", path.Join("services", "registration"), "resource dir")
flag.BoolVar(&engineDebug, "engine-debug", false, "use engine debug output")
flag.BoolVar(&stateDebug, "state-debug", false, "use engine debug output")
flag.UintVar(&size, "s", 160, "max size of output")
flag.StringVar(&host, "h", "127.0.0.1", "http host")
flag.UintVar(&port, "p", 7123, "http port")
flag.Parse()
logg.Infof("start command", "dbdir", dbDir, "resourcedir", resourceDir, "outputsize", size)
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",
OutputSize: uint32(size),
FlagCount: uint32(16),
}
if stateDebug {
cfg.StateDebug = true
}
if engineDebug {
cfg.EngineDebug = true
}
rs, err := getResource(resourceDir, ctx)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
err = ensureDbDir(dbDir)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
userdataStore := getUserdataDb(dbDir, ctx)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
defer userdataStore.Close()
dbResource, ok := rs.(*resource.DbResource)
if !ok {
os.Exit(1)
}
hl, err := getHandler(flagParser, dbResource, userdataStore)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
stateStore, err := getStateStore(dbDir, ctx)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
defer stateStore.Close()
rp := &httpserver.DefaultRequestParser{}
//sh := httpserver.NewSessionHandler(cfg, rs, stateStore, userdataStore, rp, hl.Init)
sh := httpserver.NewSessionHandler(cfg, rs, stateStore, userdataStore, rp, hl)
s := &http.Server{
Addr: fmt.Sprintf("%s:%s", host, strconv.Itoa(int(port))),
Handler: sh,
}
s.RegisterOnShutdown(sh.Shutdown)
cint := make(chan os.Signal)
cterm := make(chan os.Signal)
signal.Notify(cint, os.Interrupt, syscall.SIGINT)
signal.Notify(cterm, os.Interrupt, syscall.SIGTERM)
go func() {
select {
case _ = <-cint:
case _ = <-cterm:
}
s.Shutdown(ctx)
}()
err = s.ListenAndServe()
if err != nil {
logg.Infof("Server closed with error", "err", err)
}
}

View File

@@ -4,6 +4,8 @@ import (
"context"
"flag"
"fmt"
"io"
"net/http"
"os"
"path"
@@ -23,6 +25,65 @@ var (
scriptDir = path.Join("services", "registration")
)
type LocalHandler struct {
sessionId string
}
func NewLocalHandler() *LocalHandler {
return &LocalHandler{
sessionId: "",
}
}
type RequestParser interface {
GetSessionId(*http.Request) (string, error)
GetInput(*http.Request) ([]byte, error)
}
type DefaultRequestParser struct {
}
func(rp *DefaultRequestParser) GetSessionId(rq *http.Request) (string, error) {
v := rq.Header.Get("X-Vise-Session")
if v == "" {
return "", fmt.Errorf("no session found")
}
return v, nil
}
func(rp *DefaultRequestParser) GetInput(rq *http.Request) ([]byte, error) {
defer rq.Body.Close()
v, err := io.ReadAll(rq.Body)
if err != nil {
return nil, err
}
return v, nil
}
type DefaultSessionHandler struct {
cfgTemplate engine.Config
rp RequestParser
rh *LocalHandler
dbDir string
resourceDir string
}
func NewDefaultSessionHandler(dbDir string, resourceDir string, rp RequestParser, outputSize uint32, flagCount uint32) *DefaultSessionHandler {
rh := NewLocalHandler()
return &DefaultSessionHandler{
cfgTemplate: engine.Config{
OutputSize: outputSize,
Root: "root",
FlagCount: flagCount,
},
rh: rh,
rp: rp,
dbDir: dbDir,
resourceDir: resourceDir,
}
}
func getParser(fp string, debug bool) (*asm.FlagParser, error) {
flagParser := asm.NewFlagParser().WithDebug()
_, err := flagParser.Load(fp)
@@ -34,11 +95,10 @@ func getParser(fp string, debug bool) (*asm.FlagParser, error) {
func getHandler(appFlags *asm.FlagParser, rs *resource.DbResource, pe *persist.Persister, userdataStore db.Db) (*ussd.Handlers, error) {
ussdHandlers, err := ussd.NewHandlers(appFlags, userdataStore)
ussdHandlers, err := ussd.NewHandlers(appFlags, pe, userdataStore)
if err != nil {
return nil, err
}
ussdHandlers = ussdHandlers.WithPersister(pe)
rs.AddLocalFunc("select_language", ussdHandlers.SetLanguage)
rs.AddLocalFunc("create_account", ussdHandlers.CreateAccount)
rs.AddLocalFunc("save_pin", ussdHandlers.SavePin)
@@ -75,37 +135,29 @@ func getHandler(appFlags *asm.FlagParser, rs *resource.DbResource, pe *persist.P
return ussdHandlers, nil
}
func ensureDbDir(dbDir string) error {
err := os.MkdirAll(dbDir, 0700)
func(f *DefaultSessionHandler) getPersister(ctx context.Context) (*persist.Persister, error) {
err := os.MkdirAll(f.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
return nil, fmt.Errorf("state dir create exited with error: %v\n", err)
}
store := gdbmdb.NewGdbmDb()
storeFile := path.Join(dbDir, "state.gdbm")
storeFile := path.Join(f.dbDir, "state.gdbm")
store.Connect(ctx, storeFile)
pr := persist.NewPersister(store)
return pr, nil
}
func getUserdataDb(dbDir string, ctx context.Context) db.Db {
func(f *DefaultSessionHandler) getUserdataDb(ctx context.Context) db.Db {
store := gdbmdb.NewGdbmDb()
storeFile := path.Join(dbDir, "userdata.gdbm")
storeFile := path.Join(f.dbDir, "userdata.gdbm")
store.Connect(ctx, storeFile)
return store
}
func getResource(resourceDir string, ctx context.Context) (resource.Resource, error) {
func(f *DefaultSessionHandler) getResource(ctx context.Context) (resource.Resource, error) {
store := fsdb.NewFsDb()
err := store.Connect(ctx, resourceDir)
err := store.Connect(ctx, f.resourceDir)
if err != nil {
return nil, err
}
@@ -113,86 +165,144 @@ func getResource(resourceDir string, ctx context.Context) (resource.Resource, er
return rfs, nil
}
func getEngine(cfg engine.Config, rs resource.Resource, pr *persist.Persister) *engine.DefaultEngine {
func(f *DefaultSessionHandler) getEngine(rs resource.Resource, pr *persist.Persister, sessionId string) *engine.DefaultEngine {
cfg := f.cfgTemplate
cfg.SessionId = sessionId
en := engine.NewEngine(cfg, rs)
en = en.WithPersister(pr)
return en
}
func main() {
var dbDir string
var size uint
var sessionId string
var debug bool
flag.StringVar(&sessionId, "session-id", "075xx2123", "session id")
flag.StringVar(&dbDir, "dbdir", ".state", "database dir to read from")
flag.BoolVar(&debug, "d", false, "use engine debug output")
flag.UintVar(&size, "s", 160, "max size of output")
flag.Parse()
func(f *DefaultSessionHandler) writeError(w http.ResponseWriter, code int, msg string, err error) {
w.Header().Set("X-Vise", msg + ": " + err.Error())
w.Header().Set("Content-Length", "0")
w.WriteHeader(code)
_, err = w.Write([]byte{})
if err != nil {
w.WriteHeader(500)
w.Header().Set("X-Vise", err.Error())
}
return
}
logg.Infof("start command", "dbdir", dbDir, "outputsize", size)
func(f *DefaultSessionHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
var r bool
ctx := context.Background()
sessionId, err := f.rp.GetSessionId(req)
if err != nil {
f.writeError(w, 400, "Session missing", err)
return
}
input, err := f.rp.GetInput(req)
if err != nil {
f.writeError(w, 400, "Input read fail", err)
return
}
ctx := req.Context()
ctx = context.WithValue(ctx, "SessionId", sessionId)
pfp := path.Join(scriptDir, "pp.csv")
flagParser, err := getParser(pfp, true)
if err != nil {
os.Exit(1)
f.writeError(w, 500, "flagParser failed with error:", err)
return
}
cfg := engine.Config{
Root: "root",
SessionId: sessionId,
OutputSize: uint32(size),
FlagCount: uint32(16),
}
rs, err := getResource(scriptDir, ctx)
rs, err := f.getResource(ctx)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
f.writeError(w, 500, "getResource failed with error:", err)
return
}
pe, err := getPersister(dbDir, ctx)
pr, err := f.getPersister(ctx)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
store := getUserdataDb(dbDir, ctx)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
f.writeError(w, 500, "getPersister failed with error:", err)
return
}
store := f.getUserdataDb(ctx)
dbResource, ok := rs.(*resource.DbResource)
if !ok {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
f.writeError(w, 500, "getHandler exited with error:", err)
return
}
hl, err := getHandler(flagParser, dbResource, pe, store)
hl, err := getHandler(flagParser, dbResource, pr, store)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
f.writeError(w, 500, "getHandler exited with error:", err)
return
}
en := getEngine(cfg, rs, pe)
en := f.getEngine(rs, pr, sessionId)
en = en.WithFirst(hl.Init)
if debug {
en = en.WithDebug(nil)
if len(input) == 0 {
r, err = en.Init(ctx)
} else {
r, err = en.Exec(ctx, input)
}
if err != nil {
f.writeError(w, 500, "Engine exec fail", err)
return
}
_, err = en.Init(ctx)
// _, err = en.Init(ctx)
// if err != nil {
// f.writeError(w, 500, "Engine exec fail", err)
// return
// }
// err = engine.Loop(ctx, en, os.Stdin, os.Stdout)
// if err != nil {
// f.writeError(w, 500, "Loop exec fail", err)
// return
// }
w.WriteHeader(200)
w.Header().Set("Content-Type", "text/plain")
_, err = en.WriteResult(ctx, w)
if err != nil {
fmt.Fprintf(os.Stderr, "engine init exited with error: %v\n", err)
os.Exit(1)
f.writeError(w, 500, "Write result fail", err)
return
}
err = engine.Loop(ctx, en, os.Stdin, os.Stdout)
_ = r
}
func main() {
var host string
var port string
var dbDir string
var resourceDir string
var size uint
var flagCount uint
var sessionId string
var debug bool
flag.StringVar(&host, "h", "127.0.0.1", "http host")
flag.StringVar(&port, "p", "7123", "http port")
flag.StringVar(&sessionId, "session-id", "075xx2123", "session id")
flag.StringVar(&dbDir, "dbdir", ".state", "database dir to read from")
flag.StringVar(&resourceDir, "resourcedir", path.Join("services", "registration"), "resource dir")
flag.BoolVar(&debug, "d", false, "use engine debug output")
flag.UintVar(&size, "s", 160, "max size of output")
flag.UintVar(&flagCount, "f", 16, "flag count")
flag.Parse()
logg.Infof("starting server", "dbdir", dbDir, "resourcedir", resourceDir, "outputsize", size, "flagCount", flagCount)
rp := &DefaultRequestParser{}
h := NewDefaultSessionHandler(dbDir, resourceDir, rp, uint32(size), uint32(flagCount))
s := &http.Server{
Addr: fmt.Sprintf("%s:%s", host, port),
Handler: h,
}
err := s.ListenAndServe()
if err != nil {
fmt.Fprintf(os.Stderr, "loop exited with error: %v\n", err)
fmt.Fprintf(os.Stderr, "Server error: %s", err)
os.Exit(1)
}
}

15
go.mod
View File

@@ -2,15 +2,6 @@ module git.grassecon.net/urdt/ussd
go 1.22.6
require (
git.defalsify.org/vise.git v0.1.0-rc.3.0.20240911162138-1f2af8672dc7
github.com/alecthomas/assert/v2 v2.2.2
github.com/peteole/testdata-loader v0.3.0
gopkg.in/leonelquinteros/gotext.v1 v1.3.1
)
require gopkg.in/dnaeon/go-vcr.v4 v4.0.1 // indirect
require (
github.com/alecthomas/participle/v2 v2.0.0 // indirect
github.com/alecthomas/repr v0.2.0 // indirect
@@ -26,3 +17,9 @@ require (
github.com/x448/float16 v0.8.4 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
require (
git.defalsify.org/vise.git v0.1.0-rc.1.0.20240906020635-400f69d01a89
github.com/alecthomas/assert/v2 v2.2.2
gopkg.in/leonelquinteros/gotext.v1 v1.3.1
)

6
go.sum
View File

@@ -1,5 +1,5 @@
git.defalsify.org/vise.git v0.1.0-rc.3.0.20240911162138-1f2af8672dc7 h1:embPZDx0Sgpq6jp9vcZ1GVI0eum3PsPCmAfxAa/1KLI=
git.defalsify.org/vise.git v0.1.0-rc.3.0.20240911162138-1f2af8672dc7/go.mod h1:JDguWmcoWBdsnpw7PUjVZAEpdC/ubBmjdUBy3tjP63M=
git.defalsify.org/vise.git v0.1.0-rc.1.0.20240906020635-400f69d01a89 h1:YyQODhMwSM5YD9yKHM5jCF0HC0RQtE3MkVXcTnOhXJo=
git.defalsify.org/vise.git v0.1.0-rc.1.0.20240906020635-400f69d01a89/go.mod h1:JDguWmcoWBdsnpw7PUjVZAEpdC/ubBmjdUBy3tjP63M=
github.com/alecthomas/assert/v2 v2.2.2 h1:Z/iVC0xZfWTaFNE6bA3z07T86hd45Xe2eLt6WVy2bbk=
github.com/alecthomas/assert/v2 v2.2.2/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ=
github.com/alecthomas/participle/v2 v2.0.0 h1:Fgrq+MbuSsJwIkw3fEj9h75vDP0Er5JzepJ0/HNHv0g=
@@ -30,8 +30,6 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/dnaeon/go-vcr.v4 v4.0.1 h1:dIFuOqqDZIJ9BTcK+DXmElzypQ6PV9fBQZSIwY+J1yM=
gopkg.in/dnaeon/go-vcr.v4 v4.0.1/go.mod h1:65yxh9goQVrudqofKtHA4JNFWd6XZRkWfKN4YpMx7KI=
gopkg.in/leonelquinteros/gotext.v1 v1.3.1 h1:8d9/fdTG0kn/B7NNGV1BsEyvektXFAbkMsTZS2sFSCc=
gopkg.in/leonelquinteros/gotext.v1 v1.3.1/go.mod h1:X1WlGDeAFIYsW6GjgMm4VwUwZ2XjI7Zan2InxSUQWrU=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

View File

@@ -1,129 +0,0 @@
//go:build !online
// +build !online
package server
import (
"testing"
"github.com/alecthomas/assert/v2"
"gopkg.in/dnaeon/go-vcr.v4/pkg/recorder"
)
func TestCheckBalanceOffline(t *testing.T) {
r, err := recorder.New("custodial/balance")
if err != nil {
t.Fatal(err)
}
defer r.Stop()
client := r.GetDefaultClient()
as := AccountService{
Client: client,
}
tests := []struct {
name string
balance string
publicKey string
}{
{
name: "Test check balance with correct public key",
publicKey: "0x216a4A64E1e699F9d65Dd9CbD0058dAB21DeF002",
balance: "3.06000000003 CELO",
},
{
name: "Test check balance with public key that doesn't exist in the custodial system",
balance: "",
publicKey: "0x216a4A64E1e699F9d65Dd9CbD0058dAB21DeF00",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
balance, err := as.CheckBalance(tt.publicKey)
if err != nil {
t.Fatalf("Failed to get balance with error %s", err)
}
if err != nil {
return
}
assert.NoError(t, err)
assert.Equal(t, balance, tt.balance, "Expected balance and actual balance should be equal")
})
}
}
func TestCheckAccountStatusOffline(t *testing.T) {
r, err := recorder.New("custodial/status")
if err != nil {
t.Fatal(err)
}
defer r.Stop()
client := r.GetDefaultClient()
as := AccountService{
Client: client,
}
tests := []struct {
name string
status string
trackingId string
}{
{
name: "Test check status with tracking id that exists in the custodial system",
trackingId: "bb23945b-65cd-4110-ac2e-a5df40572e18",
status: "SUCCESS",
},
{
name: "Test check status with tracking id that doesn't exist in the custodial system",
status: "",
trackingId: "bb23945b-65cd-4110-ac2e-a5df40572e1",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
status, err := as.CheckAccountStatus(tt.trackingId)
if err != nil {
t.Fatalf("Failed to account status with error %s", err)
}
if err != nil {
return
}
assert.NoError(t, err)
assert.Equal(t, status, tt.status, "Expected status and actual status should be equal")
})
}
}
func TestCreateAccountOffline(t *testing.T) {
r, err := recorder.New("custodial/create")
if err != nil {
t.Fatal(err)
}
defer r.Stop()
client := r.GetDefaultClient()
as := AccountService{
Client: client,
}
accountRes, err := as.CreateAccount()
if err != nil {
t.Fatalf("Failed to create an account with error %s", err)
}
if err != nil {
return
}
assert.NoError(t, err)
assert.Equal(t, accountRes.Ok, true, "account response status is true")
}

View File

@@ -1,130 +0,0 @@
//go:build online
// +build online
package server
import (
"net/http"
"testing"
"github.com/alecthomas/assert/v2"
"gopkg.in/dnaeon/go-vcr.v4/pkg/recorder"
)
func TestCheckBalance(t *testing.T) {
r, err := recorder.New("custodial/balance")
if err != nil {
t.Fatal(err)
}
defer r.Stop()
client := &http.Client{}
as := AccountService{
Client: client,
}
tests := []struct {
name string
balance string
publicKey string
}{
{
name: "Test check balance with correct public key",
publicKey: "0x216a4A64E1e699F9d65Dd9CbD0058dAB21DeF002",
balance: "3.06000000003 CELO",
},
{
name: "Test check balance with public key that doesn't exist in the custodial system",
balance: "",
publicKey: "0x216a4A64E1e699F9d65Dd9CbD0058dAB21DeF00",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
balance, err := as.CheckBalance(tt.publicKey)
if err != nil {
t.Fatalf("Failed to get balance with error %s", err)
}
if err != nil {
return
}
assert.NoError(t, err)
assert.Equal(t, balance, tt.balance, "Expected balance and actual balance should be equal")
})
}
}
func TestCheckAccountStatus(t *testing.T) {
r, err := recorder.New("custodial/status")
if err != nil {
t.Fatal(err)
}
defer r.Stop()
client := &http.Client{}
as := AccountService{
Client: client,
}
tests := []struct {
name string
status string
trackingId string
}{
{
name: "Test check status with tracking id that exists in the custodial system",
trackingId: "bb23945b-65cd-4110-ac2e-a5df40572e18",
status: "SUCCESS",
},
{
name: "Test check status with tracking id that doesn't exist in the custodial system",
status: "",
trackingId: "bb23945b-65cd-4110-ac2e-a5df40572e1",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
status, err := as.CheckAccountStatus(tt.trackingId)
if err != nil {
t.Fatalf("Failed to account status with error %s", err)
}
if err != nil {
return
}
assert.NoError(t, err)
assert.Equal(t, status, tt.status, "Expected status and actual status should be equal")
})
}
}
func TestCreateAccount(t *testing.T) {
r, err := recorder.New("custodial/create")
if err != nil {
t.Fatal(err)
}
defer r.Stop()
client := &http.Client{}
as := AccountService{
Client: client,
}
accountRes, err := as.CreateAccount()
if err != nil {
t.Fatalf("Failed to create an account with error %s", err)
}
if err != nil {
return
}
assert.NoError(t, err)
assert.Equal(t, accountRes.Ok, true, "account response status is true")
}

View File

@@ -16,7 +16,6 @@ type AccountServiceInterface interface {
}
type AccountService struct {
Client *http.Client
}
@@ -35,8 +34,7 @@ type AccountService struct {
// If no error occurs, this will be nil.
//
func (as *AccountService) CheckAccountStatus(trackingId string) (string, error) {
resp,err := as.Client.Get(config.TrackStatusURL + trackingId)
// resp, err := http.Get(config.TrackStatusURL + trackingId)
resp, err := http.Get(config.TrackStatusURL + trackingId)
if err != nil {
return "", err
}
@@ -64,8 +62,7 @@ func (as *AccountService) CheckAccountStatus(trackingId string) (string, error)
// - publicKey: The public key associated with the account whose balance needs to be checked.
func (as *AccountService) CheckBalance(publicKey string) (string, error) {
//resp, err := http.Get(config.BalanceURL + publicKey)
resp, err := as.Client.Get(config.BalanceURL + publicKey)
resp, err := http.Get(config.BalanceURL + publicKey)
if err != nil {
return "0.0", err
}
@@ -94,8 +91,7 @@ func (as *AccountService) CheckBalance(publicKey string) (string, error) {
// - error: An error if any occurred during the HTTP request, reading the response, or unmarshalling the JSON data.
// If no error occurs, this will be nil.
func (as *AccountService) CreateAccount() (*models.AccountResponse, error) {
//resp, err := http.Post(config.CreateAccountURL, "application/json", nil)
resp, err := as.Client.Post(config.CreateAccountURL, "application/json", nil)
resp, err := http.Post(config.CreateAccountURL, "application/json", nil)
if err != nil {
return nil, err
}

View File

@@ -1,126 +0,0 @@
package server
import (
"testing"
"github.com/alecthomas/assert/v2"
"gopkg.in/dnaeon/go-vcr.v4/pkg/recorder"
)
func TestCheckBalance(t *testing.T) {
r, err := recorder.New("custodial/balance")
if err != nil {
t.Fatal(err)
}
defer r.Stop()
client := r.GetDefaultClient()
as := AccountService{
Client: client,
}
tests := []struct {
name string
balance string
publicKey string
}{
{
name: "Test check balance with correct public key",
publicKey: "0x216a4A64E1e699F9d65Dd9CbD0058dAB21DeF002",
balance: "3.06000000003 CELO",
},
{
name: "Test check balance with public key that doesn't exist in the custodial system",
balance: "",
publicKey: "0x216a4A64E1e699F9d65Dd9CbD0058dAB21DeF00",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
balance, err := as.CheckBalance(tt.publicKey)
if err != nil {
t.Fatalf("Failed to get balance with error %s", err)
}
if err != nil {
return
}
assert.NoError(t, err)
assert.Equal(t, balance, tt.balance, "Expected balance and actual balance should be equal")
})
}
}
func TestCheckAccountStatus(t *testing.T) {
r, err := recorder.New("custodial/status")
if err != nil {
t.Fatal(err)
}
defer r.Stop()
client := r.GetDefaultClient()
as := AccountService{
Client: client,
}
tests := []struct {
name string
status string
trackingId string
}{
{
name: "Test check status with tracking id that exists in the custodial system",
trackingId: "bb23945b-65cd-4110-ac2e-a5df40572e18",
status: "SUCCESS",
},
{
name: "Test check status with tracking id that doesn't exist in the custodial system",
status: "",
trackingId: "bb23945b-65cd-4110-ac2e-a5df40572e1",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
status, err := as.CheckAccountStatus(tt.trackingId)
if err != nil {
t.Fatalf("Failed to account status with error %s", err)
}
if err != nil {
return
}
assert.NoError(t, err)
assert.Equal(t, status, tt.status, "Expected status and actual status should be equal")
})
}
}
func TestCreateAccount(t *testing.T) {
r, err := recorder.New("custodial/create")
if err != nil {
t.Fatal(err)
}
defer r.Stop()
client := r.GetDefaultClient()
as := AccountService{
Client: client,
}
accountRes, err := as.CreateAccount()
if err != nil {
t.Fatalf("Failed to create an account with error %s", err)
}
if err != nil {
return
}
assert.NoError(t, err)
assert.Equal(t, accountRes.Ok, true, "account response status is true")
}

View File

@@ -4,7 +4,6 @@ import (
"bytes"
"context"
"fmt"
"net/http"
"path"
"regexp"
"strconv"
@@ -67,20 +66,21 @@ type Handlers struct {
accountService server.AccountServiceInterface
}
func NewHandlers(appFlags *asm.FlagParser, userdataStore db.Db) (*Handlers, error) {
func NewHandlers(parser *asm.FlagParser, pe *persist.Persister, userdataStore db.Db) (*Handlers, error) {
userDb := utils.UserDataStore{
Store: userdataStore,
}
if pe == nil {
return nil, fmt.Errorf("cannot create handler with nil persister")
}
if userdataStore == nil {
return nil, fmt.Errorf("cannot create handler with nil userdata store")
}
userDb := &utils.UserDataStore{
Db: userdataStore,
}
client := &http.Client{}
h := &Handlers{
userdataStore: userDb,
flagManager: appFlags,
accountService: &server.AccountService{
Client: client,
},
pe: pe,
userdataStore: userDb,
flagManager: parser,
accountService: &server.AccountService{},
}
return h, nil
}
@@ -94,14 +94,6 @@ func isValidPIN(pin string) bool {
return match
}
func (h *Handlers) WithPersister(pe *persist.Persister) *Handlers {
if h.pe != nil {
panic("persister already set")
}
h.pe = pe
return h
}
func (h *Handlers) Init(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var r resource.Result
@@ -262,7 +254,7 @@ func (h *Handlers) VerifyPin(ctx context.Context, sym string, input []byte) (res
}
//AccountPin, _ := utils.ReadEntry(ctx, h.userdataStore, sessionId, utils.DATA_ACCOUNT_PIN)
store := h.userdataStore
store := h.userdataStore.(utils.UserDataStore)
AccountPin, err := store.ReadEntry(ctx, sessionId, utils.DATA_ACCOUNT_PIN)
if err != nil {
return res, err
@@ -485,19 +477,22 @@ func (h *Handlers) Authorize(ctx context.Context, sym string, input []byte) (res
if err != nil {
return res, err
}
if len(input) == 4 {
if bytes.Equal(input, AccountPin) {
if h.st.MatchFlag(flag_account_authorized, false) {
res.FlagReset = append(res.FlagReset, flag_incorrect_pin)
res.FlagSet = append(res.FlagSet, flag_allow_update, flag_account_authorized)
if err == nil {
if len(input) == 4 {
if bytes.Equal(input, AccountPin) {
if h.st.MatchFlag(flag_account_authorized, false) {
res.FlagReset = append(res.FlagReset, flag_incorrect_pin)
res.FlagSet = append(res.FlagSet, flag_allow_update, flag_account_authorized)
} else {
res.FlagSet = append(res.FlagSet, flag_allow_update)
res.FlagReset = append(res.FlagReset, flag_account_authorized)
}
} else {
res.FlagSet = append(res.FlagSet, flag_allow_update)
res.FlagSet = append(res.FlagSet, flag_incorrect_pin)
res.FlagReset = append(res.FlagReset, flag_account_authorized)
return res, nil
}
} else {
res.FlagSet = append(res.FlagSet, flag_incorrect_pin)
res.FlagReset = append(res.FlagReset, flag_account_authorized)
return res, nil
}
} else {
return res, nil
@@ -528,7 +523,7 @@ func (h *Handlers) CheckAccountStatus(ctx context.Context, sym string, input []b
if !ok {
return res, fmt.Errorf("missing session")
}
store := h.userdataStore
store := h.userdataStore.(utils.UserDataStore)
trackingId, err := store.ReadEntry(ctx, sessionId, utils.DATA_TRACKING_ID)
if err != nil {
return res, err
@@ -544,6 +539,7 @@ func (h *Handlers) CheckAccountStatus(ctx context.Context, sym string, input []b
if err != nil {
return res, nil
}
if status == "SUCCESS" {
res.FlagSet = append(res.FlagSet, flag_account_success)
res.FlagReset = append(res.FlagReset, flag_account_pending)
@@ -614,7 +610,7 @@ func (h *Handlers) CheckBalance(ctx context.Context, sym string, input []byte) (
return res, fmt.Errorf("missing session")
}
store := h.userdataStore
store := h.userdataStore.(utils.UserDataStore)
publicKey, err := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY)
if err != nil {
return res, err
@@ -748,8 +744,7 @@ func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte)
flag_invalid_amount, _ := h.flagManager.GetFlag("flag_invalid_amount")
store := h.userdataStore
publicKey, _ := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY)
publicKey, _ := utils.ReadEntry(ctx, h.userdataStore, sessionId, utils.DATA_PUBLIC_KEY)
amountStr := string(input)
@@ -758,7 +753,6 @@ func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte)
if err != nil {
return res, err
}
res.Content = balanceStr
// Parse the balance
@@ -766,7 +760,6 @@ func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte)
if len(balanceParts) != 2 {
return res, fmt.Errorf("unexpected balance format: %s", balanceStr)
}
balanceValue, err := strconv.ParseFloat(balanceParts[0], 64)
if err != nil {
return res, fmt.Errorf("failed to parse balance: %v", err)
@@ -776,7 +769,6 @@ func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte)
re := regexp.MustCompile(`^(\d+(\.\d+)?)\s*(?:CELO)?$`)
matches := re.FindStringSubmatch(strings.TrimSpace(amountStr))
if len(matches) < 2 {
res.FlagSet = append(res.FlagSet, flag_invalid_amount)
res.Content = amountStr
return res, nil
@@ -784,7 +776,6 @@ func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte)
inputAmount, err := strconv.ParseFloat(matches[1], 64)
if err != nil {
res.FlagSet = append(res.FlagSet, flag_invalid_amount)
res.Content = amountStr
return res, nil
@@ -797,7 +788,7 @@ func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte)
}
res.Content = fmt.Sprintf("%.3f", inputAmount) // Format to 3 decimal places
store = h.userdataStore
store := h.userdataStore
err = store.WriteEntry(ctx, sessionId, utils.DATA_AMOUNT, []byte(amountStr))
if err != nil {
return res, err
@@ -871,7 +862,7 @@ func (h *Handlers) QuitWithBalance(ctx context.Context, sym string, input []byte
l := gotext.NewLocale(translationDir, code)
l.AddDomain("default")
store := h.userdataStore
store := h.userdataStore.(utils.UserDataStore)
publicKey, err := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY)
if err != nil {
return res, err

File diff suppressed because it is too large Load Diff

View File

@@ -3,16 +3,28 @@ package mocks
import (
"context"
"git.defalsify.org/vise.git/db"
"git.defalsify.org/vise.git/lang"
"git.grassecon.net/urdt/ussd/internal/utils"
"github.com/stretchr/testify/mock"
)
type MockUserDataStore struct {
db.Db
mock.Mock
}
func (m *MockUserDataStore) SetPrefix(prefix uint8) {
m.Called(prefix)
}
func (m *MockUserDataStore) SetSession(sessionId string) {
m.Called(sessionId)
}
func (m *MockUserDataStore) Get(ctx context.Context, key []byte) ([]byte, error) {
args := m.Called(ctx, key)
return args.Get(0).([]byte), args.Error(1)
}
func (m *MockUserDataStore) ReadEntry(ctx context.Context, sessionId string, typ utils.DataTyp) ([]byte, error) {
args := m.Called(ctx, sessionId, typ)
return args.Get(0).([]byte), args.Error(1)
@@ -22,3 +34,36 @@ func (m *MockUserDataStore) WriteEntry(ctx context.Context, sessionId string, ty
args := m.Called(ctx, sessionId, typ, value)
return args.Error(0)
}
func (m *MockUserDataStore) Prefix() uint8 {
args := m.Called()
return args.Get(0).(uint8)
}
func (m *MockUserDataStore) Safe() bool {
args := m.Called()
return args.Get(0).(bool)
}
func (m *MockUserDataStore) SetLanguage(language *lang.Language) {
m.Called(language)
}
func (m *MockUserDataStore) SetLock(uint8, bool) error {
args := m.Called()
return args.Error(0)
}
func (m *MockUserDataStore) Connect(ctx context.Context, connectionStr string) error {
args := m.Called(ctx, connectionStr)
return args.Error(0)
}
func (m *MockUserDataStore) Put(ctx context.Context, key, value []byte) error {
args := m.Called(ctx, key, value)
return args.Error(0)
}
func (m *MockUserDataStore) Close() error {
args := m.Called(nil)
return args.Error(0)
}

View File

@@ -1,150 +0,0 @@
package http
import (
"fmt"
"io/ioutil"
"net/http"
"git.defalsify.org/vise.git/db"
"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"
)
var (
logg = logging.NewVanilla().WithDomain("httpserver")
)
type RequestParser interface {
GetSessionId(rq *http.Request) (string, error)
GetInput(rq *http.Request) ([]byte, error)
}
type DefaultRequestParser struct {
}
func(rp *DefaultRequestParser) GetSessionId(rq *http.Request) (string, error) {
v := rq.Header.Get("X-Vise-Session")
if v == "" {
return "", fmt.Errorf("no session found")
}
return v, nil
}
func(rp *DefaultRequestParser) GetInput(rq *http.Request) ([]byte, error) {
defer rq.Body.Close()
v, err := ioutil.ReadAll(rq.Body)
if err != nil {
return nil, err
}
return v, nil
}
type SessionHandler struct {
cfgTemplate engine.Config
rp RequestParser
rs resource.Resource
//first resource.EntryFunc
hn *ussd.Handlers
provider StorageProvider
}
//func NewSessionHandler(cfg engine.Config, rs resource.Resource, stateDb db.Db, userdataDb db.Db, rp RequestParser, first resource.EntryFunc) *SessionHandler {
func NewSessionHandler(cfg engine.Config, rs resource.Resource, stateDb db.Db, userdataDb db.Db, rp RequestParser, hn *ussd.Handlers) *SessionHandler {
return &SessionHandler{
cfgTemplate: cfg,
rs: rs,
//first: first,
hn: hn,
rp: rp,
provider: NewSimpleStorageProvider(stateDb, userdataDb),
}
}
func(f *SessionHandler) writeError(w http.ResponseWriter, code int, msg string, err error) {
w.Header().Set("X-Vise", msg + ": " + err.Error())
w.Header().Set("Content-Length", "0")
w.WriteHeader(code)
_, err = w.Write([]byte{})
if err != nil {
w.WriteHeader(500)
w.Header().Set("X-Vise", err.Error())
}
return
}
func(f* SessionHandler) Shutdown() {
err := f.provider.Close()
if err != nil {
logg.Errorf("handler shutdown error", "err", err)
}
}
func(f *SessionHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
var r bool
sessionId, err := f.rp.GetSessionId(req)
if err != nil {
f.writeError(w, 400, "Session missing", err)
return
}
input, err := f.rp.GetInput(req)
if err != nil {
f.writeError(w, 400, "Input read fail", err)
return
}
ctx := req.Context()
cfg := f.cfgTemplate
cfg.SessionId = sessionId
logg.InfoCtxf(ctx, "new request", "session", cfg.SessionId, "input", input)
storage, err := f.provider.Get(cfg.SessionId)
if err != nil {
f.writeError(w, 500, "Storage retrieval fail", err)
return
}
f.hn = f.hn.WithPersister(storage.Persister)
defer f.provider.Put(cfg.SessionId, storage)
en := getEngine(cfg, f.rs, storage.Persister)
en = en.WithFirst(f.hn.Init)
if cfg.EngineDebug {
en = en.WithDebug(nil)
}
r, err = en.Init(ctx)
if err != nil {
f.writeError(w, 500, "Engine init fail", err)
return
}
if r && len(input) > 0 {
r, err = en.Exec(ctx, input)
}
if err != nil {
f.writeError(w, 500, "Engine exec fail", err)
return
}
w.WriteHeader(200)
w.Header().Set("Content-Type", "text/plain")
_, err = en.WriteResult(ctx, w)
if err != nil {
f.writeError(w, 500, "Write result fail", err)
return
}
err = en.Finish()
if err != nil {
f.writeError(w, 500, "Engine finish fail", err)
return
}
_ = r
}
func getEngine(cfg engine.Config, rs resource.Resource, pr *persist.Persister) *engine.DefaultEngine {
en := engine.NewEngine(cfg, rs)
en = en.WithPersister(pr)
return en
}

View File

@@ -1,44 +0,0 @@
package http
import (
"git.defalsify.org/vise.git/db"
"git.defalsify.org/vise.git/persist"
)
type Storage struct {
Persister *persist.Persister
UserdataDb db.Db
}
type StorageProvider interface {
Get(sessionId string) (Storage, error)
Put(sessionId string, storage Storage) error
Close() error
}
type SimpleStorageProvider struct {
Storage
}
func NewSimpleStorageProvider(stateStore db.Db, userdataStore db.Db) StorageProvider {
pe := persist.NewPersister(stateStore)
pe = pe.WithFlush()
return &SimpleStorageProvider{
Storage: Storage{
Persister: pe,
UserdataDb: userdataStore,
},
}
}
func (p *SimpleStorageProvider) Get(sessionId string) (Storage, error) {
return p.Storage, nil
}
func (p *SimpleStorageProvider) Put(sessionId string, storage Storage) error {
return nil
}
func (p *SimpleStorageProvider) Close() error {
return p.Storage.UserdataDb.Close()
}

View File

@@ -0,0 +1,44 @@
package utils
import (
"context"
"encoding/json"
"git.defalsify.org/vise.git/db"
)
type AccountFileHandler struct {
store db.Db
}
func NewAccountFileHandler(store db.Db) *AccountFileHandler {
return &AccountFileHandler{
store: store,
}
}
func (afh *AccountFileHandler) ReadAccountData(ctx context.Context, sessionId string) (map[string]string, error) {
var accountData map[string]string
jsonData, err := ReadEntry(ctx, afh.store, sessionId, DATA_ACCOUNT)
if err != nil {
return nil,err
}
err = json.Unmarshal(jsonData, &accountData)
if err != nil {
return nil, err
}
return accountData, nil
}
func (afh *AccountFileHandler) WriteAccountData(ctx context.Context, sessionId string, accountData map[string]string) error {
_, err := json.Marshal(accountData)
if err != nil {
return err
}
return nil
}
func (afh *AccountFileHandler) EnsureFileExists() error {
return nil
}

View File

@@ -1,7 +1,10 @@
package utils
import (
"context"
"encoding/binary"
"git.defalsify.org/vise.git/db"
)
type DataTyp uint16
@@ -34,3 +37,22 @@ func PackKey(typ DataTyp, data []byte) []byte {
v := typToBytes(typ)
return append(v, data...)
}
func ReadEntry(ctx context.Context, store db.Db, sessionId string, typ DataTyp) ([]byte, error) {
store.SetPrefix(db.DATATYPE_USERDATA)
store.SetSession(sessionId)
k := PackKey(typ, []byte(sessionId))
b, err := store.Get(ctx, k)
if err != nil {
return nil, err
}
return b, nil
}
func WriteEntry(ctx context.Context, store db.Db, sessionId string, typ DataTyp, value []byte) error {
store.SetPrefix(db.DATATYPE_USERDATA)
store.SetSession(sessionId)
k := PackKey(typ, []byte(sessionId))
return store.Put(ctx, k, value)
}

View File

@@ -4,29 +4,78 @@ import (
"context"
"git.defalsify.org/vise.git/db"
"git.defalsify.org/vise.git/lang"
)
type DataStore interface {
db.Db
SetPrefix(prefix uint8)
SetSession(sessionId string)
Get(ctx context.Context, key []byte) ([]byte, error)
ReadEntry(ctx context.Context, sessionId string, typ DataTyp) ([]byte, error)
WriteEntry(ctx context.Context, sessionId string, typ DataTyp, value []byte) error
Connect(ctx context.Context, connStr string) error
SetLanguage(*lang.Language)
Close() error
Prefix() uint8
Put(ctx context.Context, key []byte, val []byte) error
Safe() bool
SetLock(typ uint8, locked bool) error
}
type UserDataStore struct {
db.Db
Store db.Db
}
func (store UserDataStore) SetPrefix(prefix uint8) {
store.Store.SetPrefix(prefix)
}
func (store UserDataStore) SetLanguage(lang *lang.Language) {
store.Store.SetLanguage(lang)
}
func (store UserDataStore) SetLock(typ uint8, locked bool) error {
return store.Store.SetLock(typ, locked)
}
func (store UserDataStore) Safe() bool {
return store.Store.Safe()
}
func (store UserDataStore) Put(ctx context.Context, key []byte, val []byte) error {
return store.Store.Put(ctx, key, val)
}
func (store UserDataStore) Connect(ctx context.Context, connectionStr string) error {
return store.Store.Connect(ctx, connectionStr)
}
func (store UserDataStore) Close() error {
return store.Store.Close()
}
func (store UserDataStore) Prefix() uint8 {
return store.Store.Prefix()
}
func (store UserDataStore) SetSession(sessionId string) {
store.Store.SetSession(sessionId)
}
func (store UserDataStore) Get(ctx context.Context, key []byte) ([]byte, error) {
return store.Store.Get(ctx, key)
}
// ReadEntry retrieves an entry from the store based on the provided parameters.
func (store *UserDataStore) ReadEntry(ctx context.Context, sessionId string, typ DataTyp) ([]byte, error) {
store.SetPrefix(db.DATATYPE_USERDATA)
store.SetSession(sessionId)
func (store UserDataStore) ReadEntry(ctx context.Context, sessionId string, typ DataTyp) ([]byte, error) {
store.Store.SetPrefix(db.DATATYPE_USERDATA)
store.Store.SetSession(sessionId)
k := PackKey(typ, []byte(sessionId))
return store.Get(ctx, k)
}
func (store *UserDataStore) WriteEntry(ctx context.Context, sessionId string, typ DataTyp, value []byte) error {
store.SetPrefix(db.DATATYPE_USERDATA)
store.SetSession(sessionId)
func (store UserDataStore) WriteEntry(ctx context.Context, sessionId string, typ DataTyp, value []byte) error {
store.Store.SetPrefix(db.DATATYPE_USERDATA)
store.Store.SetSession(sessionId)
k := PackKey(typ, []byte(sessionId))
return store.Put(ctx, k, value)
return store.Store.Put(ctx, k, value)
}

View File

@@ -1,4 +1,3 @@
LOAD authorize_account 6
MAP validate_amount
RELOAD get_recipient
MAP get_recipient
@@ -7,9 +6,9 @@ MAP get_sender
MOUT back 0
MOUT quit 9
HALT
LOAD authorize_account 6
RELOAD authorize_account
CATCH incorrect_pin flag_incorrect_pin 1
CATCH transaction_initiated flag_account_authorized 1
INCMP _ 0
INCMP quit 9
INCMP transaction_initiated *