Compare commits

...

45 Commits

Author SHA1 Message Date
lash
dd2468a4d7 Http server harness
Add storage retrieval solution for http handler

Successfully executed account regisration using http

Set upstream go-vise dependency version in go.mod

Adapt menuhandler to upstream
2024-09-10 13:59:36 +01:00
63cee42261 Merge pull request 'wip-code-check' (#44) from wip-code-check into master
Reviewed-on: #44
Reviewed-by: lash <accounts-grassrootseconomics@holbrook.no>
2024-09-10 14:25:50 +02:00
9f034967b5
remove resource directory 2024-09-10 12:32:19 +03:00
ad48890a9f
remove deprecated code 2024-09-10 11:24:09 +03:00
c0a3ad7e2b
delete deprecated code 2024-09-10 11:23:41 +03:00
a3dffdf4e9
match code refactor 2024-09-10 11:23:25 +03:00
47d39a1c6f
remove commented test 2024-09-09 17:24:43 +03:00
f5f1cbaaba
cleanup 2024-09-09 17:18:07 +03:00
134aa96194
implement db for user datastore 2024-09-09 17:16:08 +03:00
0cdb23fbea
setupmock for user datastore 2024-09-09 17:15:35 +03:00
ca655b0cdc
add tests 2024-09-09 17:15:04 +03:00
da93444d3f
remove deprecated code 2024-09-09 10:14:40 +03:00
c2564a9b8f
remove go-vise subdirectory 2024-09-09 10:12:29 +03:00
33c6b35f8f
Merge branch 'origin/master' into wip-code-check 2024-09-09 09:56:00 +03:00
ba72b3bf44
Merge branch 'master' into wip-code-check 2024-09-09 09:45:29 +03:00
e961b6cb6a
Merge branch 'wip-code-check' 2024-09-09 09:22:08 +03:00
2c059afa7d
resolve 2024-09-07 22:05:09 +03:00
9aab7d3a9b
Merge branch 'master' into wip-code-check 2024-09-07 22:04:30 +03:00
a25beb5b80
Merge branch 'wip-code-check' 2024-09-07 21:54:00 +03:00
39d27209cd
Merge remote-tracking branch 'refs/remotes/origin/wip-code-check' into wip-code-check 2024-09-07 18:10:40 +03:00
16a56ef29d
add go-vise 2024-09-07 18:09:55 +03:00
6d02ea79ec
add go-vise 2024-09-07 18:09:13 +03:00
deb4706b1d
Test commit 2024-09-07 17:51:30 +03:00
e14fd5e496
Return the response and the error 2024-09-07 17:41:05 +03:00
01c13ec581
make packKey accessible from tests 2024-09-07 16:25:29 +03:00
dd97531861
remove uimplemented tests 2024-09-07 16:24:37 +03:00
be33b7458f
cleanup code 2024-09-07 16:22:08 +03:00
4c3f63a48f
create an account only if not found in gdbm 2024-09-07 10:36:00 +03:00
d1d5c897d1
refactor 2024-09-07 09:55:59 +03:00
04ea11dd6d
setup db mock 2024-09-07 09:55:47 +03:00
5722552395
remove old mocks 2024-09-07 09:55:13 +03:00
421fbe5543
setup mock for the acccount service 2024-09-07 09:55:00 +03:00
de24ca0648
Mock the gdm nd updated the TestSaveFirstname and TestSaveFamilyname 2024-09-07 09:30:20 +03:00
175cbd1983
setup template test 2024-09-06 17:51:07 +03:00
8175d6ac12
setup db mock 2024-09-06 17:50:33 +03:00
d4bae50ff0
Merge remote-tracking branch 'refs/remotes/origin/wip-code-check' into wip-code-check 2024-09-06 16:54:41 +03:00
d7376a4196
format error 2024-09-06 16:53:22 +03:00
eb9f470ac5
Update the GetProfileInfo to get data from gdbm 2024-09-06 16:17:26 +03:00
7a12588744
remove deprecated code 2024-09-06 12:42:24 +03:00
6947b1e4a4
rename getflags to getparser 2024-09-06 11:03:01 +03:00
2cc85379cc
update log 2024-09-06 11:02:33 +03:00
d001c5a7fc
Write and read data from gdbm 2024-09-06 09:33:39 +03:00
de8c7ce34a
Added user data to db.go util 2024-09-06 08:35:01 +03:00
c6c66f956a Merge pull request 'wip-flag-migration' (#28) from wip-flag-migration into master
Reviewed-on: #28
2024-09-04 11:25:33 +02:00
1957606bc2
Added log to show debug the flag loaded 2024-09-04 12:19:34 +03:00
16 changed files with 1097 additions and 1247 deletions

199
cmd/http/main.go Normal file
View File

@ -0,0 +1,199 @@
package main
import (
"context"
"flag"
"fmt"
"net/http"
"os"
"path"
"strconv"
"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/persist"
"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 getStateStore(dbDir string, ctx context.Context) (db.Db, error) {
err := os.MkdirAll(dbDir, 0700)
if err != nil {
return nil, fmt.Errorf("state dir create exited with error: %v\n", err)
}
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 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 resourceDir string
var size uint
var sessionId string
var engineDebug bool
var stateDebug bool
var host string
var port uint
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(&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()
ctx = context.WithValue(ctx, "SessionId",sessionId)
pfp := path.Join(scriptDir, "pp.csv")
flagParser, err := getFlags(pfp, true)
if err != nil {
os.Exit(1)
}
cfg := engine.Config{
Root: "root",
SessionId: sessionId,
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)
}
userdataStore := getUserdataDb(dbDir, ctx)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
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)
}
sh := httpserver.NewSessionHandler(cfg, rs, userdataStore, stateStore, hl.Init)
s := &http.Server{
Addr: fmt.Sprintf("%s:%s", host, strconv.Itoa(int(port))),
Handler: sh,
}
err = s.ListenAndServe()
if err != nil {
fmt.Fprintf(os.Stderr, "Server error: %s", err)
os.Exit(1)
}
}

View File

@ -12,18 +12,18 @@ import (
fsdb "git.defalsify.org/vise.git/db/fs" fsdb "git.defalsify.org/vise.git/db/fs"
gdbmdb "git.defalsify.org/vise.git/db/gdbm" gdbmdb "git.defalsify.org/vise.git/db/gdbm"
"git.defalsify.org/vise.git/engine" "git.defalsify.org/vise.git/engine"
"git.defalsify.org/vise.git/logging"
"git.defalsify.org/vise.git/persist" "git.defalsify.org/vise.git/persist"
"git.defalsify.org/vise.git/resource" "git.defalsify.org/vise.git/resource"
"git.defalsify.org/vise.git/logging"
"git.grassecon.net/urdt/ussd/internal/handlers/ussd" "git.grassecon.net/urdt/ussd/internal/handlers/ussd"
) )
var ( var (
logg = logging.NewVanilla() logg = logging.NewVanilla()
scriptDir = path.Join("services", "registration") scriptDir = path.Join("services", "registration")
) )
func getFlags(fp string, debug bool) (*asm.FlagParser, error) { func getParser(fp string, debug bool) (*asm.FlagParser, error) {
flagParser := asm.NewFlagParser().WithDebug() flagParser := asm.NewFlagParser().WithDebug()
_, err := flagParser.Load(fp) _, err := flagParser.Load(fp)
if err != nil { if err != nil {
@ -34,10 +34,11 @@ func getFlags(fp string, debug bool) (*asm.FlagParser, error) {
func getHandler(appFlags *asm.FlagParser, rs *resource.DbResource, pe *persist.Persister, userdataStore db.Db) (*ussd.Handlers, error) { func getHandler(appFlags *asm.FlagParser, rs *resource.DbResource, pe *persist.Persister, userdataStore db.Db) (*ussd.Handlers, error) {
ussdHandlers, err := ussd.NewHandlers(appFlags, pe, userdataStore) ussdHandlers, err := ussd.NewHandlers(appFlags, userdataStore)
if err != nil { if err != nil {
return nil, err return nil, err
} }
ussdHandlers = ussdHandlers.WithPersister(pe)
rs.AddLocalFunc("select_language", ussdHandlers.SetLanguage) rs.AddLocalFunc("select_language", ussdHandlers.SetLanguage)
rs.AddLocalFunc("create_account", ussdHandlers.CreateAccount) rs.AddLocalFunc("create_account", ussdHandlers.CreateAccount)
rs.AddLocalFunc("save_pin", ussdHandlers.SavePin) rs.AddLocalFunc("save_pin", ussdHandlers.SavePin)
@ -90,7 +91,7 @@ func getUserdataDb(dbDir string, ctx context.Context) db.Db {
store := gdbmdb.NewGdbmDb() store := gdbmdb.NewGdbmDb()
storeFile := path.Join(dbDir, "userdata.gdbm") storeFile := path.Join(dbDir, "userdata.gdbm")
store.Connect(ctx, storeFile) store.Connect(ctx, storeFile)
return store return store
} }
@ -112,23 +113,21 @@ func getEngine(cfg engine.Config, rs resource.Resource, pr *persist.Persister) *
func main() { func main() {
var dbDir string var dbDir string
var resourceDir string
var size uint var size uint
var sessionId string var sessionId string
var debug bool var debug bool
flag.StringVar(&sessionId, "session-id", "075xx2123", "session id") flag.StringVar(&sessionId, "session-id", "075xx2123", "session id")
flag.StringVar(&dbDir, "dbdir", ".state", "database dir to read from") 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.BoolVar(&debug, "d", false, "use engine debug output")
flag.UintVar(&size, "s", 160, "max size of output") flag.UintVar(&size, "s", 160, "max size of output")
flag.Parse() flag.Parse()
logg.Infof("start command", "dbdir", dbDir, "resourcedir", resourceDir, "outputsize", size) logg.Infof("start command", "dbdir", dbDir, "outputsize", size)
ctx := context.Background() ctx := context.Background()
ctx = context.WithValue(ctx, "SessionId",sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
pfp := path.Join(scriptDir, "pp.csv") pfp := path.Join(scriptDir, "pp.csv")
flagParser, err := getFlags(pfp, true) flagParser, err := getParser(pfp, true)
if err != nil { if err != nil {
os.Exit(1) os.Exit(1)
@ -141,13 +140,13 @@ func main() {
FlagCount: uint32(16), FlagCount: uint32(16),
} }
rs, err := getResource(resourceDir, ctx) rs, err := getResource(scriptDir, ctx)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, err.Error()) fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1) os.Exit(1)
} }
pr, err := getPersister(dbDir, ctx) pe, err := getPersister(dbDir, ctx)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, err.Error()) fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1) os.Exit(1)
@ -161,16 +160,17 @@ func main() {
dbResource, ok := rs.(*resource.DbResource) dbResource, ok := rs.(*resource.DbResource)
if !ok { if !ok {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1) os.Exit(1)
} }
hl, err := getHandler(flagParser, dbResource, pr, store) hl, err := getHandler(flagParser, dbResource, pe, store)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, err.Error()) fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1) os.Exit(1)
} }
en := getEngine(cfg, rs, pr) en := getEngine(cfg, rs, pe)
en = en.WithFirst(hl.Init) en = en.WithFirst(hl.Init)
if debug { if debug {
en = en.WithDebug(nil) en = en.WithDebug(nil)

@ -1 +0,0 @@
Subproject commit 2bddc363f20210ab019eec29d8ba4104d147e9b7

22
go.mod
View File

@ -2,4 +2,24 @@ module git.grassecon.net/urdt/ussd
go 1.22.6 go 1.22.6
require github.com/stretchr/testify v1.9.0 // indirect require (
git.defalsify.org/vise.git v0.1.0-rc.2.0.20240907200911-15fe28c9d5b0
github.com/alecthomas/assert/v2 v2.2.2
gopkg.in/leonelquinteros/gotext.v1 v1.3.1
)
require (
github.com/alecthomas/participle/v2 v2.0.0 // indirect
github.com/alecthomas/repr v0.2.0 // indirect
github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fxamacker/cbor/v2 v2.4.0 // indirect
github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4 // indirect
github.com/hexops/gotextdiff v1.0.3 // indirect
github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/stretchr/testify v1.9.0
github.com/x448/float16 v0.8.4 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

34
go.sum
View File

@ -1,2 +1,36 @@
git.defalsify.org/vise.git v0.1.0-rc.2.0.20240907200911-15fe28c9d5b0 h1:B9kE2XXjrYmHNIgRV6fR1WLWE8+z8OvDhJSc96lbGPQ=
git.defalsify.org/vise.git v0.1.0-rc.2.0.20240907200911-15fe28c9d5b0/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=
github.com/alecthomas/participle/v2 v2.0.0/go.mod h1:rAKZdJldHu8084ojcWevWAL8KmEU+AT+Olodb+WoN2Y=
github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk=
github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c h1:H9Nm+I7Cg/YVPpEV1RzU3Wq2pjamPc/UtHDgItcb7lE=
github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c/go.mod h1:rGod7o6KPeJ+hyBpHfhi4v7blx9sf+QsHsA7KAsdN6U=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88=
github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4 h1:U4kkNYryi/qfbBF8gh7Vsbuz+cVmhf5kt6pE9bYYyLo=
github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4/go.mod h1:zpZDgZFzeq9s0MIeB1P50NIEWDFFHSFBohI/NbaTD/Y=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a h1:0Q3H0YXzMHiciXtRcM+j0jiCe8WKPQHoRgQiRTnfcLY=
github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a/go.mod h1:CdTTBOYzS5E4mWS1N8NWP6AHI19MP0A2B18n3hLzRMk=
github.com/peteole/testdata-loader v0.3.0 h1:8jckE9KcyNHgyv/VPoaljvKZE0Rqr8+dPVYH6rfNr9I=
github.com/peteole/testdata-loader v0.3.0/go.mod h1:Mt0ZbRtb56u8SLJpNP+BnQbENljMorYBpqlvt3cS83U=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
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/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=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -29,23 +29,6 @@ var (
translationDir = path.Join(scriptDir, "locale") translationDir = path.Join(scriptDir, "locale")
) )
const (
TrackingIdKey = "TRACKINGID"
PublicKeyKey = "PUBLICKEY"
CustodialIdKey = "CUSTODIALID"
AccountPin = "ACCOUNTPIN"
AccountStatus = "ACCOUNTSTATUS"
FirstName = "FIRSTNAME"
FamilyName = "FAMILYNAME"
YearOfBirth = "YOB"
Location = "LOCATION"
Gender = "GENDER"
Offerings = "OFFERINGS"
Recipient = "RECIPIENT"
Amount = "AMOUNT"
AccountCreated = "ACCOUNTCREATED"
)
type FSData struct { type FSData struct {
Path string Path string
St *state.State St *state.State
@ -75,27 +58,24 @@ func (fm *FlagManager) GetFlag(label string) (uint32, error) {
} }
type Handlers struct { type Handlers struct {
pe *persist.Persister pe *persist.Persister
st *state.State st *state.State
ca cache.Memory ca cache.Memory
userdataStore db.Db userdataStore utils.DataStore
flagManager *asm.FlagParser flagManager *asm.FlagParser
accountFileHandler *utils.AccountFileHandler accountService server.AccountServiceInterface
accountService server.AccountServiceInterface
} }
func NewHandlers(appFlags *asm.FlagParser, pe *persist.Persister, userdataStore db.Db) (*Handlers, error) { func NewHandlers(appFlags *asm.FlagParser, userdataStore db.Db) (*Handlers, error) {
if pe == nil {
return nil, fmt.Errorf("cannot create handler with nil persister")
}
if userdataStore == nil { if userdataStore == nil {
return nil, fmt.Errorf("cannot create handler with nil userdata store") return nil, fmt.Errorf("cannot create handler with nil userdata store")
} }
userDb := &utils.UserDataStore{
Db: userdataStore,
}
h := &Handlers{ h := &Handlers{
pe: pe, userdataStore: userDb,
userdataStore: userdataStore,
flagManager: appFlags, flagManager: appFlags,
accountFileHandler: utils.NewAccountFileHandler(userdataStore),
accountService: &server.AccountService{}, accountService: &server.AccountService{},
} }
return h, nil return h, nil
@ -110,6 +90,14 @@ func isValidPIN(pin string) bool {
return match 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) { func (h *Handlers) Init(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var r resource.Result var r resource.Result
@ -122,7 +110,7 @@ func (h *Handlers) Init(ctx context.Context, sym string, input []byte) (resource
if h.st == nil || h.ca == nil { if h.st == nil || h.ca == nil {
logg.ErrorCtxf(ctx, "perister fail in handler", "state", h.st, "cache", h.ca) logg.ErrorCtxf(ctx, "perister fail in handler", "state", h.st, "cache", h.ca)
return r, fmt.Errorf("cannot get state and memory for handler") return r, fmt.Errorf("cannot get state and memory for handler")
} }
h.pe = nil h.pe = nil
logg.DebugCtxf(ctx, "handler has been initialized", "state", h.st, "cache", h.ca) logg.DebugCtxf(ctx, "handler has been initialized", "state", h.st, "cache", h.ca)
@ -164,7 +152,8 @@ func (h *Handlers) createAccountNoExist(ctx context.Context, sessionId string, r
} }
for key, value := range data { for key, value := range data {
err := utils.WriteEntry(ctx, h.userdataStore, sessionId, key, []byte(value)) store := h.userdataStore
err := store.WriteEntry(ctx, sessionId, key, []byte(value))
if err != nil { if err != nil {
return err return err
} }
@ -181,20 +170,15 @@ func (h *Handlers) createAccountNoExist(ctx context.Context, sessionId string, r
func (h *Handlers) CreateAccount(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) CreateAccount(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
var err error var err error
sessionId, ok := ctx.Value("SessionId").(string) sessionId, ok := ctx.Value("SessionId").(string)
if !ok { if !ok {
return res, fmt.Errorf("missing session") return res, fmt.Errorf("missing session")
} }
_, err = utils.ReadEntry(ctx, h.userdataStore, sessionId, utils.DATA_ACCOUNT_CREATED) store := h.userdataStore
_, err = store.ReadEntry(ctx, sessionId, utils.DATA_ACCOUNT_CREATED)
if err != nil { if err != nil {
if db.IsNotFound(err) { if db.IsNotFound(err) {
fmt.Println("Creating an account because it doesn't exist") logg.Printf(logging.LVL_INFO, "Creating an account because it doesn't exist")
err = h.createAccountNoExist(ctx, sessionId, &res)
if err != nil {
return res, err
}
} else {
err = h.createAccountNoExist(ctx, sessionId, &res) err = h.createAccountNoExist(ctx, sessionId, &res)
if err != nil { if err != nil {
return res, err return res, err
@ -208,7 +192,7 @@ func (h *Handlers) CreateAccount(ctx context.Context, sym string, input []byte)
func (h *Handlers) SavePin(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) SavePin(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
var err error var err error
sessionId, ok := ctx.Value("SessionId").(string) sessionId, ok := ctx.Value("SessionId").(string)
if !ok { if !ok {
return res, fmt.Errorf("missing session") return res, fmt.Errorf("missing session")
@ -224,19 +208,18 @@ func (h *Handlers) SavePin(ctx context.Context, sym string, input []byte) (resou
} }
res.FlagReset = append(res.FlagReset, flag_incorrect_pin) res.FlagReset = append(res.FlagReset, flag_incorrect_pin)
store := h.userdataStore
err = utils.WriteEntry(ctx, h.userdataStore, sessionId, utils.DATA_ACCOUNT_PIN, []byte(accountPIN)) err = store.WriteEntry(ctx, sessionId, utils.DATA_ACCOUNT_PIN, []byte(accountPIN))
if err != nil { if err != nil {
return res, nil return res, err
} }
return res, nil return res, nil
} }
// SetResetSingleEdit sets and resets flags to allow gradual editing of profile information. // SetResetSingleEdit sets and resets flags to allow gradual editing of profile information.
func (h *Handlers) SetResetSingleEdit(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) SetResetSingleEdit(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
menuOption := string(input) menuOption := string(input)
flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update")
@ -274,7 +257,12 @@ func (h *Handlers) VerifyPin(ctx context.Context, sym string, input []byte) (res
return res, fmt.Errorf("missing session") return res, fmt.Errorf("missing session")
} }
AccountPin, _ := utils.ReadEntry(ctx, h.userdataStore, sessionId, utils.DATA_ACCOUNT_PIN) //AccountPin, _ := utils.ReadEntry(ctx, h.userdataStore, sessionId, utils.DATA_ACCOUNT_PIN)
store := h.userdataStore
AccountPin, err := store.ReadEntry(ctx, sessionId, utils.DATA_ACCOUNT_PIN)
if err != nil {
return res, err
}
if bytes.Equal(input, AccountPin) { if bytes.Equal(input, AccountPin) {
res.FlagSet = []uint32{flag_valid_pin} res.FlagSet = []uint32{flag_valid_pin}
@ -297,67 +285,103 @@ func codeFromCtx(ctx context.Context) string {
return code return code
} }
// SaveFirstname updates the first name in a JSON data file with the provided input. // SaveFirstname updates the first name in the gdbm with the provided input.
func (h *Handlers) SaveFirstname(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) SaveFirstname(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
var err error
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
if len(input) > 0 { if len(input) > 0 {
//name := string(input) firstName := string(input)
//key := []byte(FirstName) store := h.userdataStore
//value := []byte(name) err = store.WriteEntry(ctx, sessionId, utils.DATA_FIRST_NAME, []byte(firstName))
//h.db.Store(key, value, true) if err != nil {
return res, err
}
} }
return res, nil return res, nil
} }
// SaveFamilyname updates the family name in a JSON data file with the provided input. // SaveFamilyname updates the family name in the gdbm with the provided input.
func (h *Handlers) SaveFamilyname(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) SaveFamilyname(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
var err error
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
if len(input) > 0 { if len(input) > 0 {
//secondname := string(input) familyName := string(input)
//key := []byte(FamilyName) store := h.userdataStore
//value := []byte(secondname) err = store.WriteEntry(ctx, sessionId, utils.DATA_FAMILY_NAME, []byte(familyName))
//h.db.Store(key, value, true) if err != nil {
return res, err
}
if err != nil {
return res, nil
}
} else {
return res, fmt.Errorf("a family name cannot be less than one character")
} }
return res, nil return res, nil
} }
// SaveYOB updates the Year of Birth(YOB) in a JSON data file with the provided input. // SaveYOB updates the Year of Birth(YOB) in the gdbm with the provided input.
func (h *Handlers) SaveYob(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) SaveYob(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
var err error
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
yob := string(input) if len(input) == 4 {
if len(yob) == 4 { yob := string(input)
//yob := string(input) store := h.userdataStore
//key := []byte(YearOfBirth) err = store.WriteEntry(ctx, sessionId, utils.DATA_YOB, []byte(yob))
//value := []byte(yob) if err != nil {
//h.db.Store(key, value, true) return res, err
}
} }
return res, nil return res, nil
} }
// SaveLocation updates the location in a JSON data file with the provided input. // SaveLocation updates the location in the gdbm with the provided input.
func (h *Handlers) SaveLocation(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) SaveLocation(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
var err error
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
if len(input) > 0 { if len(input) > 0 {
//location := string(input) location := string(input)
//key := []byte(Location) store := h.userdataStore
//value := []byte(location) err = store.WriteEntry(ctx, sessionId, utils.DATA_LOCATION, []byte(location))
if err != nil {
//h.db.Store(key, value, true) return res, err
}
} }
return res, nil return res, nil
} }
// SaveGender updates the gender in a JSON data file with the provided input. // SaveGender updates the gender in the gdbm with the provided input.
func (h *Handlers) SaveGender(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) SaveGender(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
var err error
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
if len(input) > 0 { if len(input) > 0 {
gender := string(input) gender := string(input)
@ -369,23 +393,34 @@ func (h *Handlers) SaveGender(ctx context.Context, sym string, input []byte) (re
case "3": case "3":
gender = "Unspecified" gender = "Unspecified"
} }
//key := []byte(Gender) store := h.userdataStore
//value := []byte(gender) err = store.WriteEntry(ctx, sessionId, utils.DATA_GENDER, []byte(gender))
//h.db.Store(key, value, true) if err != nil {
return res, nil
}
} }
return res, nil return res, nil
} }
// SaveOfferings updates the offerings(goods and services provided by the user) in a JSON data file with the provided input. // SaveOfferings updates the offerings(goods and services provided by the user) in the gdbm with the provided input.
func (h *Handlers) SaveOfferings(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) SaveOfferings(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
var err error
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
if len(input) > 0 { if len(input) > 0 {
//offerings := string(input) offerings := string(input)
//key := []byte(Offerings) store := h.userdataStore
//value := []byte(offerings) err = store.WriteEntry(ctx, sessionId, utils.DATA_OFFERINGS, []byte(offerings))
//h.db.Store(key, value, true) if err != nil {
return res, nil
}
} }
return res, nil return res, nil
} }
@ -413,11 +448,16 @@ func (h *Handlers) ResetAccountAuthorized(ctx context.Context, sym string, input
func (h *Handlers) CheckIdentifier(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) CheckIdentifier(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
//publicKey, err := h.db.Fetch([]byte(PublicKeyKey)) sessionId, ok := ctx.Value("SessionId").(string)
// if err != nil { if !ok {
// return res, err return res, fmt.Errorf("missing session")
// } }
res.Content = "string(publicKey)"
store := h.userdataStore
publicKey, _ := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY)
res.Content = string(publicKey)
return res, nil return res, nil
} }
@ -427,14 +467,20 @@ func (h *Handlers) Authorize(ctx context.Context, sym string, input []byte) (res
var res resource.Result var res resource.Result
var err error var err error
flag_incorrect_pin, _ := h.flagManager.GetFlag("flag_incorrect_pin")
flag_account_authorized, _ := h.flagManager.GetFlag("flag_account_authorized")
flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update")
sessionId, ok := ctx.Value("SessionId").(string) sessionId, ok := ctx.Value("SessionId").(string)
if !ok { if !ok {
return res, fmt.Errorf("missing session") return res, fmt.Errorf("missing session")
} }
AccountPin, err := utils.ReadEntry(ctx, h.userdataStore, sessionId, utils.DATA_ACCOUNT_PIN)
flag_incorrect_pin, _ := h.flagManager.GetFlag("flag_incorrect_pin")
flag_account_authorized, _ := h.flagManager.GetFlag("flag_account_authorized")
flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update")
store := h.userdataStore
AccountPin, err := store.ReadEntry(ctx, sessionId, utils.DATA_ACCOUNT_PIN)
if err != nil {
return res, err
}
if err == nil { if err == nil {
if len(input) == 4 { if len(input) == 4 {
@ -481,26 +527,22 @@ func (h *Handlers) CheckAccountStatus(ctx context.Context, sym string, input []b
if !ok { if !ok {
return res, fmt.Errorf("missing session") return res, fmt.Errorf("missing session")
} }
store := h.userdataStore
trackingId, _ := utils.ReadEntry(ctx, h.userdataStore, sessionId, utils.DATA_TRACKING_ID) trackingId, err := store.ReadEntry(ctx, sessionId, utils.DATA_TRACKING_ID)
if err != nil {
return res, err
}
status, err := h.accountService.CheckAccountStatus(string(trackingId)) status, err := h.accountService.CheckAccountStatus(string(trackingId))
if err != nil { if err != nil {
fmt.Println("Error checking account status:", err) fmt.Println("Error checking account status:", err)
return res, err return res, err
} }
// err = h.db.Store(toBytes(AccountStatus), toBytes(status), true) err = store.WriteEntry(ctx, sessionId, utils.DATA_ACCOUNT_STATUS, []byte(status))
// if err != nil { if err != nil {
// return res, nil return res, nil
// } }
// err = h.db.Store(toBytes(TrackingIdKey), toBytes(status), true)
// if err != nil {
// return res, nil
// }
if status == "SUCCESS" { if status == "SUCCESS" {
res.FlagSet = append(res.FlagSet, flag_account_success) res.FlagSet = append(res.FlagSet, flag_account_success)
@ -567,14 +609,16 @@ func (h *Handlers) CheckBalance(ctx context.Context, sym string, input []byte) (
var res resource.Result var res resource.Result
var err error var err error
// publicKey, err := h.db.Fetch([]byte(PublicKeyKey))
sessionId, ok := ctx.Value("SessionId").(string) sessionId, ok := ctx.Value("SessionId").(string)
if !ok { if !ok {
return res, fmt.Errorf("missing session") return res, fmt.Errorf("missing session")
} }
publicKey, _ := utils.ReadEntry(ctx, h.userdataStore, sessionId, utils.DATA_PUBLIC_KEY) store := h.userdataStore
publicKey, err := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY)
if err != nil {
return res, err
}
balance, err := h.accountService.CheckBalance(string(publicKey)) balance, err := h.accountService.CheckBalance(string(publicKey))
if err != nil { if err != nil {
@ -588,6 +632,12 @@ func (h *Handlers) CheckBalance(ctx context.Context, sym string, input []byte) (
// ValidateRecipient validates that the given input is a valid phone number. // ValidateRecipient validates that the given input is a valid phone number.
func (h *Handlers) ValidateRecipient(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) ValidateRecipient(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
var err error
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
recipient := string(input) recipient := string(input)
@ -601,12 +651,11 @@ func (h *Handlers) ValidateRecipient(ctx context.Context, sym string, input []by
return res, nil return res, nil
} }
store := h.userdataStore
// accountData["Recipient"] = recipient err = store.WriteEntry(ctx, sessionId, utils.DATA_RECIPIENT, []byte(recipient))
// key := []byte(Recipient) if err != nil {
// value := []byte(recipient) return res, nil
}
// h.db.Store(key, value, true)
} }
return res, nil return res, nil
@ -616,18 +665,25 @@ func (h *Handlers) ValidateRecipient(ctx context.Context, sym string, input []by
// as well as the invalid flags // as well as the invalid flags
func (h *Handlers) TransactionReset(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) TransactionReset(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
var err error
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
flag_invalid_recipient, _ := h.flagManager.GetFlag("flag_invalid_recipient") flag_invalid_recipient, _ := h.flagManager.GetFlag("flag_invalid_recipient")
flag_invalid_recipient_with_invite, _ := h.flagManager.GetFlag("flag_invalid_recipient_with_invite") flag_invalid_recipient_with_invite, _ := h.flagManager.GetFlag("flag_invalid_recipient_with_invite")
store := h.userdataStore
err = store.WriteEntry(ctx, sessionId, utils.DATA_AMOUNT, []byte(""))
if err != nil {
return res, nil
}
// err := h.db.Delete([]byte(Amount)) err = store.WriteEntry(ctx, sessionId, utils.DATA_RECIPIENT, []byte(""))
// if err != nil && !errors.Is(err, gdbm.ErrItemNotFound) { if err != nil {
// return res, err return res, nil
// } }
// err = h.db.Delete([]byte(Recipient))
// if err != nil && !errors.Is(err, gdbm.ErrItemNotFound) {
// return res, err
// }
res.FlagReset = append(res.FlagReset, flag_invalid_recipient, flag_invalid_recipient_with_invite) res.FlagReset = append(res.FlagReset, flag_invalid_recipient, flag_invalid_recipient_with_invite)
@ -637,13 +693,19 @@ func (h *Handlers) TransactionReset(ctx context.Context, sym string, input []byt
// ResetTransactionAmount resets the transaction amount and invalid flag // ResetTransactionAmount resets the transaction amount and invalid flag
func (h *Handlers) ResetTransactionAmount(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) ResetTransactionAmount(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
var err error
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
flag_invalid_amount, _ := h.flagManager.GetFlag("flag_invalid_amount") flag_invalid_amount, _ := h.flagManager.GetFlag("flag_invalid_amount")
store := h.userdataStore
// err := h.db.Delete([]byte(Amount)) err = store.WriteEntry(ctx, sessionId, utils.DATA_AMOUNT, []byte(""))
// if err != nil && !errors.Is(err, gdbm.ErrItemNotFound) { if err != nil {
// return res, err return res, nil
// } }
res.FlagReset = append(res.FlagReset, flag_invalid_amount) res.FlagReset = append(res.FlagReset, flag_invalid_amount)
@ -656,12 +718,14 @@ func (h *Handlers) MaxAmount(ctx context.Context, sym string, input []byte) (res
var res resource.Result var res resource.Result
var err error var err error
// publicKey, err := h.db.Fetch([]byte(PublicKeyKey)) sessionId, ok := ctx.Value("SessionId").(string)
// if err != nil { if !ok {
// return res, err return res, fmt.Errorf("missing session")
// } }
store := h.userdataStore
publicKey, _ := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY)
balance, err := h.accountService.CheckBalance(string("publicKey")) balance, err := h.accountService.CheckBalance(string(publicKey))
if err != nil { if err != nil {
return res, nil return res, nil
} }
@ -677,16 +741,18 @@ func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte)
var res resource.Result var res resource.Result
var err error var err error
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
flag_invalid_amount, _ := h.flagManager.GetFlag("flag_invalid_amount") flag_invalid_amount, _ := h.flagManager.GetFlag("flag_invalid_amount")
publicKey, _ := utils.ReadEntry(ctx, h.userdataStore, sessionId, utils.DATA_PUBLIC_KEY)
amountStr := string(input) amountStr := string(input)
// publicKey, err := h.db.Fetch([]byte(PublicKeyKey))
// if err != nil { balanceStr, err := h.accountService.CheckBalance(string(publicKey))
// return res, err
// }
balanceStr, err := h.accountService.CheckBalance(string("publicKey"))
if err != nil { if err != nil {
return res, err return res, err
@ -726,10 +792,8 @@ func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte)
} }
res.Content = fmt.Sprintf("%.3f", inputAmount) // Format to 3 decimal places res.Content = fmt.Sprintf("%.3f", inputAmount) // Format to 3 decimal places
// key := []byte(Amount) store := h.userdataStore
// value := []byte(res.Content) err = store.WriteEntry(ctx, sessionId, utils.DATA_AMOUNT, []byte(amountStr))
// h.db.Store(key, value, true)
if err != nil { if err != nil {
return res, err return res, err
} }
@ -737,16 +801,18 @@ func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte)
return res, nil return res, nil
} }
// GetRecipient returns the transaction recipient from a JSON data file. // GetRecipient returns the transaction recipient from the gdbm.
func (h *Handlers) GetRecipient(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) GetRecipient(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
// recipient, err := h.db.Fetch([]byte(Recipient)) sessionId, ok := ctx.Value("SessionId").(string)
// if err != nil { if !ok {
// return res, err return res, fmt.Errorf("missing session")
// } }
store := h.userdataStore
recipient, _ := store.ReadEntry(ctx, sessionId, utils.DATA_RECIPIENT)
res.Content = string("recipient") res.Content = string(recipient)
return res, nil return res, nil
} }
@ -755,12 +821,15 @@ func (h *Handlers) GetRecipient(ctx context.Context, sym string, input []byte) (
func (h *Handlers) GetSender(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) GetSender(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
// publicKey, err := h.db.Fetch([]byte(PublicKeyKey)) sessionId, ok := ctx.Value("SessionId").(string)
// if err != nil { if !ok {
// return res, err return res, fmt.Errorf("missing session")
// } }
res.Content = string("publicKey") store := h.userdataStore
publicKey, _ := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY)
res.Content = string(publicKey)
return res, nil return res, nil
} }
@ -769,11 +838,14 @@ func (h *Handlers) GetSender(ctx context.Context, sym string, input []byte) (res
func (h *Handlers) GetAmount(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) GetAmount(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
// amount, err := h.db.Fetch([]byte(Amount)) sessionId, ok := ctx.Value("SessionId").(string)
// if err != nil { if !ok {
// return res, err return res, fmt.Errorf("missing session")
// } }
res.Content = string("amount") store := h.userdataStore
amount, _ := store.ReadEntry(ctx, sessionId, utils.DATA_AMOUNT)
res.Content = string(amount)
return res, nil return res, nil
} }
@ -783,17 +855,23 @@ func (h *Handlers) GetAmount(ctx context.Context, sym string, input []byte) (res
func (h *Handlers) QuitWithBalance(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) QuitWithBalance(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
var err error var err error
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
flag_account_authorized, _ := h.flagManager.GetFlag("flag_account_authorized") flag_account_authorized, _ := h.flagManager.GetFlag("flag_account_authorized")
code := codeFromCtx(ctx) code := codeFromCtx(ctx)
l := gotext.NewLocale(translationDir, code) l := gotext.NewLocale(translationDir, code)
l.AddDomain("default") l.AddDomain("default")
// publicKey, err := h.db.Fetch([]byte(PublicKeyKey))
// if err != nil { store := h.userdataStore
// return res, err publicKey, err := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY)
// } if err != nil {
balance, err := h.accountService.CheckBalance(string("publicKey")) return res, err
}
balance, err := h.accountService.CheckBalance(string(publicKey))
if err != nil { if err != nil {
return res, nil return res, nil
} }
@ -803,31 +881,28 @@ func (h *Handlers) QuitWithBalance(ctx context.Context, sym string, input []byte
} }
// InitiateTransaction returns a confirmation and resets the transaction data // InitiateTransaction returns a confirmation and resets the transaction data
// on the JSON file. // on the gdbm store.
func (h *Handlers) InitiateTransaction(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) InitiateTransaction(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
var err error var err error
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
code := codeFromCtx(ctx) code := codeFromCtx(ctx)
l := gotext.NewLocale(translationDir, code) l := gotext.NewLocale(translationDir, code)
l.AddDomain("default") l.AddDomain("default")
// TODO // TODO
// Use the amount, recipient and sender to call the API and initialize the transaction // Use the amount, recipient and sender to call the API and initialize the transaction
store := h.userdataStore
publicKey, _ := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY)
// publicKey, err := h.db.Fetch([]byte(PublicKeyKey)) amount, _ := store.ReadEntry(ctx, sessionId, utils.DATA_AMOUNT)
// if err != nil {
// return res, err
// }
// amount, err := h.db.Fetch([]byte(Amount))
// if err != nil {
// return res, err
// }
// recipient, err := h.db.Fetch([]byte(Recipient))
// if err != nil {
// return res, err
// }
//res.Content = l.Get("Your request has been sent. %s will receive %s from %s.", string(recipient), string(amount), string(publicKey)) recipient, _ := store.ReadEntry(ctx, sessionId, utils.DATA_RECIPIENT)
res.Content = l.Get("Your request has been sent. %s will receive %s from %s.", string(recipient), string(amount), string(publicKey))
account_authorized_flag, err := h.flagManager.GetFlag("flag_account_authorized") account_authorized_flag, err := h.flagManager.GetFlag("flag_account_authorized")
if err != nil { if err != nil {
@ -841,62 +916,55 @@ func (h *Handlers) InitiateTransaction(ctx context.Context, sym string, input []
// GetProfileInfo retrieves and formats the profile information of a user from a Gdbm backed storage. // GetProfileInfo retrieves and formats the profile information of a user from a Gdbm backed storage.
func (h *Handlers) GetProfileInfo(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) GetProfileInfo(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
// Define default values // Default value when an entry is not found
defaultValue := "Not provided" defaultValue := "Not Provided"
name := defaultValue
familyName := defaultValue
yob := defaultValue
gender := defaultValue
location := defaultValue
offerings := defaultValue
// Fetch data using a map for better organization // Helper function to handle nil byte slices and convert them to string
// dataKeys := map[string]*string{ getEntryOrDefault := func(entry []byte, err error) string {
// FirstName: &name, if err != nil || entry == nil {
// FamilyName: &familyName, return defaultValue
// YearOfBirth: &yob, }
// Location: &location, return string(entry)
// Gender: &gender, }
// Offerings: &offerings, store := h.userdataStore
// } // Retrieve user data as strings with fallback to defaultValue
firstName := getEntryOrDefault(store.ReadEntry(ctx, sessionId, utils.DATA_FIRST_NAME))
// Iterate over keys and fetch values familyName := getEntryOrDefault(store.ReadEntry(ctx, sessionId, utils.DATA_FAMILY_NAME))
//iter := h.db.Iterator() yob := getEntryOrDefault(store.ReadEntry(ctx, sessionId, utils.DATA_YOB))
// next := h.db.Iterator() gender := getEntryOrDefault(store.ReadEntry(ctx, sessionId, utils.DATA_GENDER))
// //defer iter.Close() // Ensure the iterator is closed location := getEntryOrDefault(store.ReadEntry(ctx, sessionId, utils.DATA_LOCATION))
// for key, err := next(); err == nil; key, err = next() { offerings := getEntryOrDefault(store.ReadEntry(ctx, sessionId, utils.DATA_OFFERINGS))
// if valuePointer, ok := dataKeys[string(key)]; ok {
// // value, fetchErr := h.db.Fetch(key)
// // if fetchErr == nil {
// // *valuePointer = string(value)
// // }
// }
// }
// Construct the full name // Construct the full name
name := defaultValue
if familyName != defaultValue { if familyName != defaultValue {
if name == defaultValue { if firstName == defaultValue {
name = familyName name = familyName
} else { } else {
name = name + " " + familyName name = firstName + " " + familyName
} }
} }
// Calculate age from year of birth // Calculate age from year of birth
var age string age := defaultValue
if yob != defaultValue { if yob != defaultValue {
yobInt, err := strconv.Atoi(yob) if yobInt, err := strconv.Atoi(yob); err == nil {
if err != nil { age = strconv.Itoa(utils.CalculateAgeWithYOB(yobInt))
} else {
return res, fmt.Errorf("invalid year of birth: %v", err) return res, fmt.Errorf("invalid year of birth: %v", err)
} }
age = strconv.Itoa(utils.CalculateAgeWithYOB(yobInt))
} else {
age = defaultValue
} }
// Format the result // Format the result
formattedData := fmt.Sprintf("Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\n", name, gender, age, location, offerings) res.Content = fmt.Sprintf(
res.Content = formattedData "Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\n",
name, gender, age, location, offerings,
)
return res, nil return res, nil
} }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,59 @@
package mocks
import (
"context"
"git.defalsify.org/vise.git/lang"
"github.com/stretchr/testify/mock"
)
type MockDb struct {
mock.Mock
}
func (m *MockDb) SetPrefix(prefix uint8) {
m.Called(prefix)
}
func (m *MockDb) Prefix() uint8 {
args := m.Called()
return args.Get(0).(uint8)
}
func (m *MockDb) Safe() bool {
args := m.Called()
return args.Get(0).(bool)
}
func (m *MockDb) SetLanguage(language *lang.Language) {
m.Called(language)
}
func (m *MockDb) SetLock(uint8, bool) error {
args := m.Called()
return args.Error(0)
}
func (m *MockDb) Connect(ctx context.Context, connectionStr string) error {
args := m.Called(ctx, connectionStr)
return args.Error(0)
}
func (m *MockDb) SetSession(sessionId string) {
m.Called(sessionId)
}
func (m *MockDb) Put(ctx context.Context, key, value []byte) error {
args := m.Called(ctx, key, value)
return args.Error(0)
}
func (m *MockDb) Get(ctx context.Context, key []byte) ([]byte, error) {
args := m.Called(ctx, key)
return nil, args.Error(0)
}
func (m *MockDb) Close() error {
args := m.Called(nil)
return args.Error(0)
}

View File

@ -1,44 +0,0 @@
package mocks
import (
"git.grassecon.net/urdt/ussd/internal/models"
"github.com/stretchr/testify/mock"
)
type MockAccountFileHandler struct {
mock.Mock
}
func (m *MockAccountFileHandler) EnsureFileExists() error {
args := m.Called()
return args.Error(0)
}
func (m *MockAccountFileHandler) ReadAccountData() (map[string]string, error) {
args := m.Called()
return args.Get(0).(map[string]string), args.Error(1)
}
func (m *MockAccountFileHandler) WriteAccountData(data map[string]string) error {
args := m.Called(data)
return args.Error(0)
}
type MockAccountService struct {
mock.Mock
}
func (m *MockAccountService) CreateAccount() (*models.AccountResponse, error) {
args := m.Called()
return args.Get(0).(*models.AccountResponse), args.Error(1)
}
func (m *MockAccountService) CheckAccountStatus(TrackingId string) (string, error) {
args := m.Called()
return args.Get(0).(string), args.Error(1)
}
func (m *MockAccountService) CheckBalance(PublicKey string) (string, error) {
args := m.Called()
return args.Get(0).(string), args.Error(1)
}

View File

@ -0,0 +1,26 @@
package mocks
import (
"git.grassecon.net/urdt/ussd/internal/models"
"github.com/stretchr/testify/mock"
)
// MockAccountService implements AccountServiceInterface for testing
type MockAccountService struct {
mock.Mock
}
func (m *MockAccountService) CreateAccount() (*models.AccountResponse, error) {
args := m.Called()
return args.Get(0).(*models.AccountResponse), args.Error(1)
}
func (m *MockAccountService) CheckBalance(publicKey string) (string, error) {
args := m.Called(publicKey)
return args.String(0), args.Error(1)
}
func (m *MockAccountService) CheckAccountStatus(trackingId string) (string, error) {
args := m.Called(trackingId)
return args.String(0), args.Error(1)
}

View File

@ -0,0 +1,24 @@
package mocks
import (
"context"
"git.defalsify.org/vise.git/db"
"git.grassecon.net/urdt/ussd/internal/utils"
"github.com/stretchr/testify/mock"
)
type MockUserDataStore struct {
db.Db
mock.Mock
}
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)
}
func (m *MockUserDataStore) WriteEntry(ctx context.Context, sessionId string, typ utils.DataTyp, value []byte) error {
args := m.Called(ctx, sessionId, typ, value)
return args.Error(0)
}

130
internal/http/server.go Normal file
View File

@ -0,0 +1,130 @@
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"
)
var (
logg = logging.NewVanilla().WithDomain("httpserver")
)
type RequestParser struct {
}
func(rp *RequestParser) 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 *RequestParser) 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
provider StorageProvider
}
func NewSessionHandler(cfg engine.Config, rs resource.Resource, stateDb db.Db, userdataDb db.Db, first resource.EntryFunc) *SessionHandler {
return &SessionHandler{
cfgTemplate: cfg,
rs: rs,
first: first,
rp: RequestParser{},
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) 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
}
en := getEngine(cfg, f.rs, storage.Persister)
en = en.WithFirst(f.first)
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
}

43
internal/http/storage.go Normal file
View File

@ -0,0 +1,43 @@
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)
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 nil
}

View File

@ -1,77 +0,0 @@
package utils
import (
"context"
"encoding/json"
"git.defalsify.org/vise.git/db"
)
type AccountFileHandler struct {
//FilePath string
store db.Db
}
// func NewAccountFileHandler(path string) *AccountFileHandler {
// return &AccountFileHandler{FilePath: path}
// }
func NewAccountFileHandler(store db.Db) *AccountFileHandler {
return &AccountFileHandler{
store: store,
}
}
// func (afh *AccountFileHandler) ReadAccountData() (map[string]string, error) {
// jsonData, err := os.ReadFile(afh.FilePath)
// if err != nil {
// return nil, err
// }
// var accountData map[string]string
// err = json.Unmarshal(jsonData, &accountData)
// if err != nil {
// return nil, err
// }
// return accountData, nil
// }
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)
err = json.Unmarshal(jsonData, &accountData)
if err != nil {
return nil, err
}
return accountData, nil
}
// func (afh *AccountFileHandler) WriteAccountData(accountData map[string]string) error {
// jsonData, err := json.Marshal(accountData)
// if err != nil {
// return err
// }
// return os.WriteFile(afh.FilePath, jsonData, 0644)
// }
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 {
// f, err := os.OpenFile(afh.FilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
// if err != nil {
// return err
// }
// return f.Close()
// }
func (afh *AccountFileHandler) EnsureFileExists() error {
return nil
}

View File

@ -16,6 +16,15 @@ const (
DATA_PUBLIC_KEY DATA_PUBLIC_KEY
DATA_CUSTODIAL_ID DATA_CUSTODIAL_ID
DATA_ACCOUNT_PIN DATA_ACCOUNT_PIN
DATA_ACCOUNT_STATUS
DATA_FIRST_NAME
DATA_FAMILY_NAME
DATA_YOB
DATA_LOCATION
DATA_GENDER
DATA_OFFERINGS
DATA_RECIPIENT
DATA_AMOUNT
) )
func typToBytes(typ DataTyp) []byte { func typToBytes(typ DataTyp) []byte {
@ -24,15 +33,16 @@ func typToBytes(typ DataTyp) []byte {
return b[:] return b[:]
} }
func packKey(typ DataTyp, data []byte) []byte { func PackKey(typ DataTyp, data []byte) []byte {
v := typToBytes(typ) v := typToBytes(typ)
return append(v, data...) return append(v, data...)
} }
func ReadEntry(ctx context.Context, store db.Db, sessionId string, typ DataTyp) ([]byte, error) { func ReadEntry(ctx context.Context, store db.Db, sessionId string, typ DataTyp) ([]byte, error) {
store.SetPrefix(db.DATATYPE_USERDATA) store.SetPrefix(db.DATATYPE_USERDATA)
store.SetSession(sessionId) store.SetSession(sessionId)
k := packKey(typ, []byte(sessionId)) k := PackKey(typ, []byte(sessionId))
b, err := store.Get(ctx, k) b, err := store.Get(ctx, k)
if err != nil { if err != nil {
return nil, err return nil, err
@ -43,6 +53,6 @@ func ReadEntry(ctx context.Context, store db.Db, sessionId string, typ DataTyp)
func WriteEntry(ctx context.Context, store db.Db, sessionId string, typ DataTyp, value []byte) error { func WriteEntry(ctx context.Context, store db.Db, sessionId string, typ DataTyp, value []byte) error {
store.SetPrefix(db.DATATYPE_USERDATA) store.SetPrefix(db.DATATYPE_USERDATA)
store.SetSession(sessionId) store.SetSession(sessionId)
k := packKey(typ, []byte(sessionId)) k := PackKey(typ, []byte(sessionId))
return store.Put(ctx, k, value) return store.Put(ctx, k, value)
} }

View File

@ -0,0 +1,32 @@
package utils
import (
"context"
"git.defalsify.org/vise.git/db"
)
type DataStore interface {
db.Db
ReadEntry(ctx context.Context, sessionId string, typ DataTyp) ([]byte, error)
WriteEntry(ctx context.Context, sessionId string, typ DataTyp, value []byte) error
}
type UserDataStore struct {
db.Db
}
// 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)
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)
k := PackKey(typ, []byte(sessionId))
return store.Put(ctx, k, value)
}