Compare commits

...
Author SHA1 Message Date
Carlosokumu 599f7a2857 add more tests 2024-09-17 15:44:22 +03:00
lash b19188165b Merge pull request 'wip-menu-help' (#56) from wip-menu-help into master
Reviewed-on: urdt/ussd#56
Reviewed-by: lash <accounts-grassrootseconomics@holbrook.no>
2024-09-16 16:21:49 +02:00
Carlosokumu 2ed9f083bb add quit with helpline info
add quit with helpline info
2024-09-16 15:17:56 +01:00
lash e323ffa078 Merge pull request 'Pin reset' (#59) from wip-pin-reset into master
Reviewed-on: urdt/ussd#59
Reviewed-by: lash <accounts-grassrootseconomics@holbrook.no>
2024-09-16 16:14:52 +02:00
lash 68de83af97 Merge pull request 'Allow setting go-vise path for asm executable in makefile' (#57) from lash/vise-make-var into master
Reviewed-on: urdt/ussd#57
2024-09-16 15:49:58 +02:00
Carlosokumu a3f2b23128 add pin reset templates for swahili 2024-09-16 15:17:15 +03:00
Carlosokumu 09f970db9b navigate to main menu after successful pin reset 2024-09-16 14:59:26 +03:00
Carlosokumu 04edd90c21 fix sink issue onback option 2024-09-16 14:58:56 +03:00
Carlosokumu a3f410875a define temporary key value 2024-09-16 14:39:42 +03:00
Carlosokumu 3f3e98e637 add pin reset handlers 2024-09-16 14:39:01 +03:00
Carlosokumu 660f8b7aa2 add pin reset nodes 2024-09-16 14:30:47 +03:00
lash 8ae3372c36 Allow setting go-vise path for asm executable in makefile 2024-09-14 21:34:11 +01:00
lash 3a7c3ffc67 Merge pull request 'wip-unit-tests' (#55) from wip-unit-tests into master
Reviewed-on: urdt/ussd#55
Reviewed-by: lash <accounts-grassrootseconomics@holbrook.no>
2024-09-14 22:29:52 +02:00
Carlosokumu 78c033e61c remove deprecated code 2024-09-14 20:59:08 +03:00
Carlosokumu b5ef483f34 clean up tests 2024-09-14 20:07:17 +03:00
Carlosokumu 006eef0a28 add testdata loader 2024-09-14 20:02:21 +03:00
Carlosokumu e99a788c60 add tests 2024-09-14 20:01:58 +03:00
lash b5d33a98f0 Merge pull request 'Enable CLI driver of async session' (#49) from lash/async-driver into master
Reviewed-on: urdt/ussd#49
2024-09-14 16:52:06 +02:00
lash f4f475bd45 Merge pull request 'africas-talking' (#50) from africas-talking into lash/async-driver
Reviewed-on: urdt/ussd#50
Reviewed-by: lash <accounts-grassrootseconomics@holbrook.no>
2024-09-14 16:28:05 +02:00
Alfred-mk 6fe2e7287f Update the func name to Output
Signed-off-by: Alfred Kamanda <alfredkamandamw@gmail.com>
2024-09-14 16:01:18 +02:00
alfred-mk 1e9c9cf6ad removed AT specific code 2024-09-14 15:57:16 +03:00
alfred-mk 3cb0b099e4 use the new AtSessionHandler 2024-09-14 15:55:45 +03:00
alfred-mk b53658e038 have AtOutput as an option 2024-09-13 16:03:31 +03:00
alfred-mk 512460fdeb Added Custom AtOutput to append CON or END to output 2024-09-13 16:02:04 +03:00
alfred-mk 762f90adf6 Added Continue bool to track whether the execution should be terminated 2024-09-12 23:52:35 +03:00
lash 9b4a4eeaf4 Temporary solution for make sure storage object gets put back in all cases of execution 2024-09-12 16:46:11 +01:00
alfred-mk 5e4e6a21a0 Added africastalking binary 2024-09-12 15:56:57 +03:00
alfred-mk ffeb28e851 Use latest go-vise package 2024-09-12 15:56:34 +03:00
lash 9c751aff30 Update go-vise 2024-09-12 04:19:13 +01:00
lash b31d3b907a Add shutdown to async, rehabilitate http cmd 2024-09-12 04:13:57 +01:00
lash d49f866ca4 Factor out methods common to http and async cli 2024-09-12 04:07:55 +01:00
lash dde9f552a6 Isolate http specific parts to minimal 2024-09-12 03:30:23 +01:00
lash 0f9b5551ec Merge pull request 'Implement http server for the URDT vise engine' (#41) from lash/http-server into master
Reviewed-on: urdt/ussd#41
2024-09-12 00:13:14 +02:00
lash 514e043e38 Fix symptom of handler missing persister 2024-09-11 17:53:12 +01:00
lash 836e5fe8ee Revert africas talking changes in http 2024-09-11 17:32:55 +01:00
lash 660fcaa0b6 Import go-vise fixing missing exit on state reset 2024-09-11 17:25:56 +01:00
alfred-mk 44015b1c76 Parse the request body to get the PhoneNumber and Input text 2024-09-11 15:40:49 +03:00
lash 7438531900 Update govise to include removed dead asm code 2024-09-11 04:10:05 +01:00
lash 681f293d3c Externalize requestparser, flush persister on http request end 2024-09-10 23:09:10 +01:00
lash 8e3ff27bb8 Ensure db close on http signal shutdown, correct stores to provider 2024-09-10 20:44:10 +01:00
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
lash 63cee42261 Merge pull request 'wip-code-check' (#44) from wip-code-check into master
Reviewed-on: urdt/ussd#44
Reviewed-by: lash <accounts-grassrootseconomics@holbrook.no>
2024-09-10 14:25:50 +02:00
Carlosokumu 9f034967b5 remove resource directory 2024-09-10 12:32:19 +03:00
Carlosokumu ad48890a9f remove deprecated code 2024-09-10 11:24:09 +03:00
Carlosokumu c0a3ad7e2b delete deprecated code 2024-09-10 11:23:41 +03:00
Carlosokumu a3dffdf4e9 match code refactor 2024-09-10 11:23:25 +03:00
Carlosokumu 47d39a1c6f remove commented test 2024-09-09 17:24:43 +03:00
Carlosokumu f5f1cbaaba cleanup 2024-09-09 17:18:07 +03:00
Carlosokumu 134aa96194 implement db for user datastore 2024-09-09 17:16:08 +03:00
Carlosokumu 0cdb23fbea setupmock for user datastore 2024-09-09 17:15:35 +03:00
Carlosokumu ca655b0cdc add tests 2024-09-09 17:15:04 +03:00
Carlosokumu da93444d3f remove deprecated code 2024-09-09 10:14:40 +03:00
Carlosokumu c2564a9b8f remove go-vise subdirectory 2024-09-09 10:12:29 +03:00
Carlosokumu 33c6b35f8f Merge branch 'origin/master' into wip-code-check 2024-09-09 09:56:00 +03:00
Carlosokumu ba72b3bf44 Merge branch 'master' into wip-code-check 2024-09-09 09:45:29 +03:00
Carlosokumu e961b6cb6a Merge branch 'wip-code-check' 2024-09-09 09:22:08 +03:00
Carlosokumu 2c059afa7d resolve 2024-09-07 22:05:09 +03:00
Carlosokumu 9aab7d3a9b Merge branch 'master' into wip-code-check 2024-09-07 22:04:30 +03:00
Carlosokumu a25beb5b80 Merge branch 'wip-code-check' 2024-09-07 21:54:00 +03:00
Carlosokumu 39d27209cd Merge remote-tracking branch 'refs/remotes/origin/wip-code-check' into wip-code-check 2024-09-07 18:10:40 +03:00
Carlosokumu 16a56ef29d add go-vise 2024-09-07 18:09:55 +03:00
Carlosokumu 6d02ea79ec add go-vise 2024-09-07 18:09:13 +03:00
alfred-mk deb4706b1d Test commit 2024-09-07 17:51:30 +03:00
alfred-mk e14fd5e496 Return the response and the error 2024-09-07 17:41:05 +03:00
Carlosokumu 01c13ec581 make packKey accessible from tests 2024-09-07 16:25:29 +03:00
Carlosokumu dd97531861 remove uimplemented tests 2024-09-07 16:24:37 +03:00
Carlosokumu be33b7458f cleanup code 2024-09-07 16:22:08 +03:00
Carlosokumu 4c3f63a48f create an account only if not found in gdbm 2024-09-07 10:36:00 +03:00
Carlosokumu d1d5c897d1 refactor 2024-09-07 09:55:59 +03:00
Carlosokumu 04ea11dd6d setup db mock 2024-09-07 09:55:47 +03:00
Carlosokumu 5722552395 remove old mocks 2024-09-07 09:55:13 +03:00
Carlosokumu 421fbe5543 setup mock for the acccount service 2024-09-07 09:55:00 +03:00
alfred-mk de24ca0648 Mock the gdm nd updated the TestSaveFirstname and TestSaveFamilyname 2024-09-07 09:30:20 +03:00
Carlosokumu 175cbd1983 setup template test 2024-09-06 17:51:07 +03:00
Carlosokumu 8175d6ac12 setup db mock 2024-09-06 17:50:33 +03:00
Carlosokumu d4bae50ff0 Merge remote-tracking branch 'refs/remotes/origin/wip-code-check' into wip-code-check 2024-09-06 16:54:41 +03:00
Carlosokumu d7376a4196 format error 2024-09-06 16:53:22 +03:00
alfred-mk eb9f470ac5 Update the GetProfileInfo to get data from gdbm 2024-09-06 16:17:26 +03:00
Carlosokumu 7a12588744 remove deprecated code 2024-09-06 12:42:24 +03:00
Carlosokumu 6947b1e4a4 rename getflags to getparser 2024-09-06 11:03:01 +03:00
Carlosokumu 2cc85379cc update log 2024-09-06 11:02:33 +03:00
alfred-mk d001c5a7fc Write and read data from gdbm 2024-09-06 09:33:39 +03:00
alfred-mk de8c7ce34a Added user data to db.go util 2024-09-06 08:35:01 +03:00
lash cad8e86c8b Remove manual init calls in handler funcs 2024-09-05 23:55:54 +01:00
lash 0feb013c78 Ensure handler init when state and cache is available 2024-09-05 20:40:40 +01:00
Carlosokumu 643b4d87a9 read account pin of gdbm store 2024-09-05 20:30:28 +03:00
Carlosokumu 5abaf28f49 remove explicit attachment of state to engine 2024-09-05 20:26:52 +03:00
alfred-mk 17804e7641 Save the actual PIN and verify it 2024-09-05 19:50:02 +03:00
lash db3ec1991d Remove obsolete store and persister global 2024-09-05 16:45:35 +01:00
lash 62b7adb967 Fix missing byte allocation for typ serialize 2024-09-05 15:41:27 +01:00
lash 6fa5f49bc0 Remove impossible nil check in handler 2024-09-05 15:28:53 +01:00
Carlosokumu 2bf7a5c246 setup db keys 2024-09-05 17:12:38 +03:00
Carlosokumu 98c74dffc4 use state from persister 2024-09-05 17:09:30 +03:00
Carlosokumu 771a1e8169 code refactoring 2024-09-05 17:07:20 +03:00
Alfred Kamanda c6c66f956a Merge pull request 'wip-flag-migration' (#28) from wip-flag-migration into master
Reviewed-on: urdt/ussd#28
2024-09-04 11:25:33 +02:00
alfred-mk 1957606bc2 Added log to show debug the flag loaded 2024-09-04 12:19:34 +03:00
44 changed files with 3730 additions and 1286 deletions
+257
View File
@@ -0,0 +1,257 @@
package main
import (
"context"
"flag"
"fmt"
"net/http"
"os"
"os/signal"
"path"
"strconv"
"strings"
"syscall"
"git.defalsify.org/vise.git/asm"
"git.defalsify.org/vise.git/db"
fsdb "git.defalsify.org/vise.git/db/fs"
gdbmdb "git.defalsify.org/vise.git/db/gdbm"
"git.defalsify.org/vise.git/engine"
"git.defalsify.org/vise.git/logging"
"git.defalsify.org/vise.git/resource"
"git.grassecon.net/urdt/ussd/internal/handlers"
"git.grassecon.net/urdt/ussd/internal/handlers/ussd"
httpserver "git.grassecon.net/urdt/ussd/internal/http"
)
var (
logg = logging.NewVanilla()
scriptDir = path.Join("services", "registration")
)
type atRequestParser struct {}
func(arp *atRequestParser) GetSessionId(rq any) (string, error) {
rqv, ok := rq.(*http.Request)
if !ok {
return "", handlers.ErrInvalidRequest
}
if err := rqv.ParseForm(); err != nil {
return "", fmt.Errorf("failed to parse form data: %v", err)
}
phoneNumber := rqv.FormValue("phoneNumber")
if phoneNumber == "" {
return "", fmt.Errorf("no phone number found")
}
return phoneNumber, nil
}
func(arp *atRequestParser) GetInput(rq any) ([]byte, error) {
rqv, ok := rq.(*http.Request)
if !ok {
return nil, handlers.ErrInvalidRequest
}
if err := rqv.ParseForm(); err != nil {
return nil, fmt.Errorf("failed to parse form data: %v", err)
}
text := rqv.FormValue("text")
parts := strings.Split(text, "*")
if len(parts) == 0 {
return nil, fmt.Errorf("no input found")
}
return []byte(parts[len(parts)-1]), nil
}
func getFlags(fp string, debug bool) (*asm.FlagParser, error) {
flagParser := asm.NewFlagParser().WithDebug()
_, err := flagParser.Load(fp)
if err != nil {
return nil, err
}
return flagParser, nil
}
func getHandler(appFlags *asm.FlagParser, rs *resource.DbResource, userdataStore db.Db) (*ussd.Handlers, error) {
ussdHandlers, err := ussd.NewHandlers(appFlags, userdataStore)
if err != nil {
return nil, err
}
rs.AddLocalFunc("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 := &atRequestParser{}
bsh := handlers.NewBaseSessionHandler(cfg, rs, stateStore, userdataStore, rp, hl)
sh := httpserver.NewATSessionHandler(bsh)
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)
}
}
+251
View File
@@ -0,0 +1,251 @@
package main
import (
"context"
"flag"
"fmt"
"os"
"os/signal"
"path"
"syscall"
"git.defalsify.org/vise.git/asm"
"git.defalsify.org/vise.git/db"
fsdb "git.defalsify.org/vise.git/db/fs"
gdbmdb "git.defalsify.org/vise.git/db/gdbm"
"git.defalsify.org/vise.git/engine"
"git.defalsify.org/vise.git/resource"
"git.defalsify.org/vise.git/logging"
"git.grassecon.net/urdt/ussd/internal/handlers/ussd"
"git.grassecon.net/urdt/ussd/internal/handlers"
)
var (
logg = logging.NewVanilla()
scriptDir = path.Join("services", "registration")
)
type asyncRequestParser struct {
sessionId string
input []byte
}
func(p *asyncRequestParser) GetSessionId(r any) (string, error) {
return p.sessionId, nil
}
func(p *asyncRequestParser) GetInput(r any) ([]byte, error) {
return p.input, nil
}
func getFlags(fp string, debug bool) (*asm.FlagParser, error) {
flagParser := asm.NewFlagParser().WithDebug()
_, err := flagParser.Load(fp)
if err != nil {
return nil, err
}
return flagParser, nil
}
func getHandler(appFlags *asm.FlagParser, rs *resource.DbResource, userdataStore db.Db) (*ussd.Handlers, error) {
ussdHandlers, err := ussd.NewHandlers(appFlags, userdataStore)
if err != nil {
return nil, err
}
rs.AddLocalFunc("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 sessionId string
var dbDir string
var resourceDir string
var size uint
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, "sessionId", sessionId)
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 := &asyncRequestParser{
sessionId: sessionId,
}
sh := handlers.NewBaseSessionHandler(cfg, rs, stateStore, userdataStore, rp, hl)
cfg.SessionId = sessionId
rqs := handlers.RequestSession{
Ctx: ctx,
Writer: os.Stdout,
Config: cfg,
}
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:
}
sh.Shutdown()
}()
for true {
rqs, err = sh.Process(rqs)
if err != nil {
fmt.Errorf("error in process: %v", err)
os.Exit(1)
}
rqs, err = sh.Output(rqs)
if err != nil {
fmt.Errorf("error in output: %v", err)
os.Exit(1)
}
rqs, err = sh.Reset(rqs)
if err != nil {
fmt.Errorf("error in reset: %v", err)
os.Exit(1)
}
fmt.Println("")
_, err = fmt.Scanln(&rqs.Input)
if err != nil {
fmt.Errorf("error in input: %v", err)
os.Exit(1)
}
}
}
+217
View File
@@ -0,0 +1,217 @@
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"
"git.grassecon.net/urdt/ussd/internal/handlers"
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{}
bsh := handlers.NewBaseSessionHandler(cfg, rs, stateStore, userdataStore, rp, hl)
sh := httpserver.ToSessionHandler(bsh)
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)
}
}
+135 -103
View File
@@ -2,159 +2,191 @@ package main
import ( import (
"context" "context"
"encoding/csv"
"flag" "flag"
"fmt" "fmt"
"io"
"os" "os"
"path" "path"
"strconv"
"git.defalsify.org/vise.git/cache" "git.defalsify.org/vise.git/asm"
"git.defalsify.org/vise.git/db"
fsdb "git.defalsify.org/vise.git/db/fs" 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/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/state"
"git.grassecon.net/urdt/ussd/internal/handlers/ussd" "git.grassecon.net/urdt/ussd/internal/handlers/ussd"
) )
var ( var (
logg = logging.NewVanilla()
scriptDir = path.Join("services", "registration") scriptDir = path.Join("services", "registration")
store = fsdb.NewFsDb()
pr = persist.NewPersister(store)
) )
type menuResource struct { func getParser(fp string, debug bool) (*asm.FlagParser, error) {
*resource.DbResource flagParser := asm.NewFlagParser().WithDebug()
_, err := flagParser.Load(fp)
if err != nil {
return nil, err
}
return flagParser, nil
} }
func newMenuResource(rs *resource.DbResource) resource.Resource { func getHandler(appFlags *asm.FlagParser, rs *resource.DbResource, pe *persist.Persister, userdataStore db.Db) (*ussd.Handlers, error) {
return &menuResource{
rs, ussdHandlers, err := ussd.NewHandlers(appFlags, 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)
rs.AddLocalFunc("verify_pin", ussdHandlers.VerifyPin)
rs.AddLocalFunc("check_identifier", ussdHandlers.CheckIdentifier)
rs.AddLocalFunc("check_account_status", ussdHandlers.CheckAccountStatus)
rs.AddLocalFunc("authorize_account", ussdHandlers.Authorize)
rs.AddLocalFunc("quit", ussdHandlers.Quit)
rs.AddLocalFunc("check_balance", ussdHandlers.CheckBalance)
rs.AddLocalFunc("validate_recipient", ussdHandlers.ValidateRecipient)
rs.AddLocalFunc("transaction_reset", ussdHandlers.TransactionReset)
rs.AddLocalFunc("max_amount", ussdHandlers.MaxAmount)
rs.AddLocalFunc("validate_amount", ussdHandlers.ValidateAmount)
rs.AddLocalFunc("reset_transaction_amount", ussdHandlers.ResetTransactionAmount)
rs.AddLocalFunc("get_recipient", ussdHandlers.GetRecipient)
rs.AddLocalFunc("get_sender", ussdHandlers.GetSender)
rs.AddLocalFunc("get_amount", ussdHandlers.GetAmount)
rs.AddLocalFunc("reset_incorrect", ussdHandlers.ResetIncorrectPin)
rs.AddLocalFunc("save_firstname", ussdHandlers.SaveFirstname)
rs.AddLocalFunc("save_familyname", ussdHandlers.SaveFamilyname)
rs.AddLocalFunc("save_gender", ussdHandlers.SaveGender)
rs.AddLocalFunc("save_location", ussdHandlers.SaveLocation)
rs.AddLocalFunc("save_yob", ussdHandlers.SaveYob)
rs.AddLocalFunc("save_offerings", ussdHandlers.SaveOfferings)
rs.AddLocalFunc("quit_with_balance", ussdHandlers.QuitWithBalance)
rs.AddLocalFunc("reset_account_authorized", ussdHandlers.ResetAccountAuthorized)
rs.AddLocalFunc("reset_allow_update", ussdHandlers.ResetAllowUpdate)
rs.AddLocalFunc("get_profile_info", ussdHandlers.GetProfileInfo)
rs.AddLocalFunc("verify_yob", ussdHandlers.VerifyYob)
rs.AddLocalFunc("reset_incorrect_date_format", ussdHandlers.ResetIncorrectYob)
rs.AddLocalFunc("set_reset_single_edit", ussdHandlers.SetResetSingleEdit)
rs.AddLocalFunc("initiate_transaction", ussdHandlers.InitiateTransaction)
rs.AddLocalFunc("save_temporary_pin", ussdHandlers.SaveTemporaryPin)
rs.AddLocalFunc("verify_new_pin", ussdHandlers.VerifyNewPin)
rs.AddLocalFunc("confirm_pin_change", ussdHandlers.ConfirmPinChange)
rs.AddLocalFunc("quit_with_help",ussdHandlers.QuitWithHelp)
return ussdHandlers, nil
}
func ensureDbDir(dbDir string) error {
err := os.MkdirAll(dbDir, 0700)
if err != nil {
return fmt.Errorf("state dir create exited with error: %v\n", err)
}
return nil
}
func getPersister(dbDir string, ctx context.Context) (*persist.Persister, error) {
err := ensureDbDir(dbDir)
if err != nil {
return nil, err
}
store := gdbmdb.NewGdbmDb()
storeFile := path.Join(dbDir, "state.gdbm")
store.Connect(ctx, storeFile)
pr := persist.NewPersister(store)
return pr, nil
}
func getUserdataDb(dbDir string, ctx context.Context) db.Db {
store := gdbmdb.NewGdbmDb()
storeFile := path.Join(dbDir, "userdata.gdbm")
store.Connect(ctx, storeFile)
return store
}
func getResource(resourceDir string, ctx context.Context) (resource.Resource, error) {
store := fsdb.NewFsDb()
err := store.Connect(ctx, resourceDir)
if err != nil {
return nil, err
}
rfs := resource.NewDbResource(store)
return rfs, nil
}
func getEngine(cfg engine.Config, rs resource.Resource, pr *persist.Persister) *engine.DefaultEngine {
en := engine.NewEngine(cfg, rs)
en = en.WithPersister(pr)
return en
} }
func main() { func main() {
var dir string var dbDir string
var root string
var size uint var size uint
var sessionId string var sessionId string
flag.StringVar(&dir, "d", ".", "resource dir to read from") var debug bool
flag.UintVar(&size, "s", 0, "max size of output") flag.StringVar(&sessionId, "session-id", "075xx2123", "session id")
flag.StringVar(&root, "root", "root", "entry point symbol") flag.StringVar(&dbDir, "dbdir", ".state", "database dir to read from")
flag.StringVar(&sessionId, "session-id", "default", "session id") flag.BoolVar(&debug, "d", false, "use engine debug output")
flag.UintVar(&size, "s", 160, "max size of output")
flag.Parse() flag.Parse()
fmt.Fprintf(os.Stderr, "starting session at symbol '%s' using resource dir: %s\n", root, dir)
logg.Infof("start command", "dbdir", dbDir, "outputsize", size)
ctx := context.Background() ctx := context.Background()
ctx = context.WithValue(ctx, "SessionId", sessionId)
pfp := path.Join(scriptDir, "pp.csv") pfp := path.Join(scriptDir, "pp.csv")
file, err := os.Open(pfp) flagParser, err := getParser(pfp, true)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "Failed to open CSV file: %v\n", err)
os.Exit(1) os.Exit(1)
} }
defer file.Close()
reader := csv.NewReader(file)
// Iterate through the CSV records and register the flags
for {
record, err := reader.Read()
if err != nil {
if err == io.EOF {
break
}
fmt.Fprintf(os.Stderr, "Error reading CSV file: %v\n", err)
os.Exit(1)
}
// Ensure the record starts with "flag" and has at least 3 columns
if len(record) < 3 || record[0] != "flag" {
continue
}
flagName := record[1]
flagValue, err := strconv.Atoi(record[2])
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to convert flag value %s to integer: %v\n", record[2], err)
continue
}
// Register the flag
state.FlagDebugger.Register(uint32(flagValue), flagName)
}
ca := cache.NewCache()
cfg := engine.Config{ cfg := engine.Config{
Root: "root", Root: "root",
SessionId: sessionId, SessionId: sessionId,
FlagCount: uint32(16), OutputSize: uint32(size),
FlagCount: uint32(16),
} }
dp := path.Join(scriptDir, ".state") rs, err := getResource(scriptDir, ctx)
err = os.MkdirAll(dp, 0700)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "state dir create exited with error: %v\n", err) fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1) os.Exit(1)
} }
store := fsdb.NewFsDb() pe, err := getPersister(dbDir, ctx)
err = store.Connect(ctx, scriptDir)
if err != nil { if err != nil {
panic(err) fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
} }
rfs := resource.NewDbResource(store) store := getUserdataDb(dbDir, ctx)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
rs, ok := newMenuResource(rfs).(*menuResource) dbResource, ok := rs.(*resource.DbResource)
if !ok { if !ok {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1) os.Exit(1)
} }
en := engine.NewEngine(cfg, rs)
en = en.WithMemory(ca)
en = en.WithPersister(pr)
fp := path.Join(dp, sessionId)
ussdHandlers, err := ussd.NewHandlers(fp, pr.State, sessionId)
hl, err := getHandler(flagParser, dbResource, pe, store)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "handler setup failed with error: %v\n", err) fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
} }
rfs.AddLocalFunc("select_language", ussdHandlers.SetLanguage) en := getEngine(cfg, rs, pe)
rfs.AddLocalFunc("create_account", ussdHandlers.CreateAccount) en = en.WithFirst(hl.Init)
rfs.AddLocalFunc("save_pin", ussdHandlers.SavePin) if debug {
rfs.AddLocalFunc("verify_pin", ussdHandlers.VerifyPin) en = en.WithDebug(nil)
rfs.AddLocalFunc("check_identifier", ussdHandlers.CheckIdentifier) }
rfs.AddLocalFunc("check_account_status", ussdHandlers.CheckAccountStatus)
rfs.AddLocalFunc("authorize_account", ussdHandlers.Authorize)
rfs.AddLocalFunc("quit", ussdHandlers.Quit)
rfs.AddLocalFunc("check_balance", ussdHandlers.CheckBalance)
rfs.AddLocalFunc("validate_recipient", ussdHandlers.ValidateRecipient)
rfs.AddLocalFunc("transaction_reset", ussdHandlers.TransactionReset)
rfs.AddLocalFunc("max_amount", ussdHandlers.MaxAmount)
rfs.AddLocalFunc("validate_amount", ussdHandlers.ValidateAmount)
rfs.AddLocalFunc("reset_transaction_amount", ussdHandlers.ResetTransactionAmount)
rfs.AddLocalFunc("get_recipient", ussdHandlers.GetRecipient)
rfs.AddLocalFunc("get_sender", ussdHandlers.GetSender)
rfs.AddLocalFunc("get_amount", ussdHandlers.GetAmount)
rfs.AddLocalFunc("reset_incorrect", ussdHandlers.ResetIncorrectPin)
rfs.AddLocalFunc("save_firstname", ussdHandlers.SaveFirstname)
rfs.AddLocalFunc("save_familyname", ussdHandlers.SaveFamilyname)
rfs.AddLocalFunc("save_gender", ussdHandlers.SaveGender)
rfs.AddLocalFunc("save_location", ussdHandlers.SaveLocation)
rfs.AddLocalFunc("save_yob", ussdHandlers.SaveYob)
rfs.AddLocalFunc("save_offerings", ussdHandlers.SaveOfferings)
rfs.AddLocalFunc("quit_with_balance", ussdHandlers.QuitWithBalance)
rfs.AddLocalFunc("reset_account_authorized", ussdHandlers.ResetAccountAuthorized)
rfs.AddLocalFunc("reset_allow_update", ussdHandlers.ResetAllowUpdate)
rfs.AddLocalFunc("get_profile_info", ussdHandlers.GetProfileInfo)
rfs.AddLocalFunc("verify_yob", ussdHandlers.VerifyYob)
rfs.AddLocalFunc("reset_incorrect_date_format", ussdHandlers.ResetIncorrectYob)
rfs.AddLocalFunc("set_reset_single_edit", ussdHandlers.SetResetSingleEdit)
rfs.AddLocalFunc("initiate_transaction", ussdHandlers.InitiateTransaction)
_, err = en.Init(ctx) _, err = en.Init(ctx)
if err != nil { if err != nil {
Submodule go-vise deleted from 1f47a674d9
+22 -1
View File
@@ -2,4 +2,25 @@ 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.3.0.20240911231817-0d23e0dbb57f
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 (
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
View File
@@ -1,2 +1,36 @@
git.defalsify.org/vise.git v0.1.0-rc.3.0.20240911231817-0d23e0dbb57f h1:CuJvG3NyMoRtHUim4aZdrfjjJBg2AId7z0yp7Q97bRM=
git.defalsify.org/vise.git v0.1.0-rc.3.0.20240911231817-0d23e0dbb57f/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=
+117
View File
@@ -0,0 +1,117 @@
package handlers
import (
"git.defalsify.org/vise.git/db"
"git.defalsify.org/vise.git/engine"
"git.defalsify.org/vise.git/persist"
"git.defalsify.org/vise.git/resource"
"git.grassecon.net/urdt/ussd/internal/handlers/ussd"
"git.grassecon.net/urdt/ussd/internal/storage"
)
type BaseSessionHandler struct {
cfgTemplate engine.Config
rp RequestParser
rs resource.Resource
hn *ussd.Handlers
provider storage.StorageProvider
}
func NewBaseSessionHandler(cfg engine.Config, rs resource.Resource, stateDb db.Db, userdataDb db.Db, rp RequestParser, hn *ussd.Handlers) *BaseSessionHandler {
return &BaseSessionHandler{
cfgTemplate: cfg,
rs: rs,
hn: hn,
rp: rp,
provider: storage.NewSimpleStorageProvider(stateDb, userdataDb),
}
}
func(f* BaseSessionHandler) Shutdown() {
err := f.provider.Close()
if err != nil {
logg.Errorf("handler shutdown error", "err", err)
}
}
func(f *BaseSessionHandler) GetEngine(cfg engine.Config, rs resource.Resource, pr *persist.Persister) engine.Engine {
en := engine.NewEngine(cfg, rs)
en = en.WithPersister(pr)
return en
}
func(f *BaseSessionHandler) Process(rqs RequestSession) (RequestSession, error) {
var r bool
var err error
var ok bool
logg.InfoCtxf(rqs.Ctx, "new request", rqs)
rqs.Storage, err = f.provider.Get(rqs.Config.SessionId)
if err != nil {
logg.ErrorCtxf(rqs.Ctx, "", "storage get error", err)
return rqs, ErrStorage
}
f.hn = f.hn.WithPersister(rqs.Storage.Persister)
eni := f.GetEngine(rqs.Config, f.rs, rqs.Storage.Persister)
en, ok := eni.(*engine.DefaultEngine)
if !ok {
perr := f.provider.Put(rqs.Config.SessionId, rqs.Storage)
rqs.Storage = nil
if perr != nil {
logg.ErrorCtxf(rqs.Ctx, "", "storage put error", perr)
}
return rqs, ErrEngineType
}
en = en.WithFirst(f.hn.Init)
if rqs.Config.EngineDebug {
en = en.WithDebug(nil)
}
rqs.Engine = en
r, err = rqs.Engine.Init(rqs.Ctx)
if err != nil {
perr := f.provider.Put(rqs.Config.SessionId, rqs.Storage)
rqs.Storage = nil
if perr != nil {
logg.ErrorCtxf(rqs.Ctx, "", "storage put error", perr)
}
return rqs, err
}
if r && len(rqs.Input) > 0 {
r, err = rqs.Engine.Exec(rqs.Ctx, rqs.Input)
}
if err != nil {
perr := f.provider.Put(rqs.Config.SessionId, rqs.Storage)
rqs.Storage = nil
if perr != nil {
logg.ErrorCtxf(rqs.Ctx, "", "storage put error", perr)
}
return rqs, err
}
rqs.Continue = r
return rqs, nil
}
func(f *BaseSessionHandler) Output(rqs RequestSession) (RequestSession, error) {
var err error
_, err = rqs.Engine.WriteResult(rqs.Ctx, rqs.Writer)
return rqs, err
}
func(f *BaseSessionHandler) Reset(rqs RequestSession) (RequestSession, error) {
defer f.provider.Put(rqs.Config.SessionId, rqs.Storage)
return rqs, rqs.Engine.Finish()
}
func(f *BaseSessionHandler) GetConfig() engine.Config {
return f.cfgTemplate
}
func(f *BaseSessionHandler) GetRequestParser() RequestParser {
return f.rp
}
+56
View File
@@ -0,0 +1,56 @@
package handlers
import (
"context"
"errors"
"io"
"git.defalsify.org/vise.git/engine"
"git.defalsify.org/vise.git/resource"
"git.defalsify.org/vise.git/persist"
"git.defalsify.org/vise.git/logging"
"git.grassecon.net/urdt/ussd/internal/storage"
)
var (
logg = logging.NewVanilla().WithDomain("handlers")
)
var (
ErrInvalidRequest = errors.New("invalid request for context")
ErrSessionMissing = errors.New("missing session")
ErrInvalidInput = errors.New("invalid input")
ErrStorage = errors.New("storage retrieval fail")
ErrEngineType = errors.New("incompatible engine")
ErrEngineInit = errors.New("engine init fail")
ErrEngineExec = errors.New("engine exec fail")
)
type RequestSession struct {
Ctx context.Context
Config engine.Config
Engine engine.Engine
Input []byte
Storage *storage.Storage
Writer io.Writer
Continue bool
}
type engineMaker func(cfg engine.Config, rs resource.Resource, pr *persist.Persister) engine.Engine
// TODO: seems like can remove this.
type RequestParser interface {
GetSessionId(rq any) (string, error)
GetInput(rq any) ([]byte, error)
}
type RequestHandler interface {
GetConfig() engine.Config
GetRequestParser() RequestParser
GetEngine(cfg engine.Config, rs resource.Resource, pe *persist.Persister) engine.Engine
Process(rs RequestSession) (RequestSession, error)
Output(rs RequestSession) (RequestSession, error)
Reset(rs RequestSession) (RequestSession, error)
Shutdown()
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+59
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)
}
-44
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)
}
@@ -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)
}
@@ -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)
}
+93
View File
@@ -0,0 +1,93 @@
package http
import (
"io"
"net/http"
"git.grassecon.net/urdt/ussd/internal/handlers"
)
type ATSessionHandler struct {
*SessionHandler
}
func NewATSessionHandler(h handlers.RequestHandler) *ATSessionHandler {
return &ATSessionHandler{
SessionHandler: ToSessionHandler(h),
}
}
func (ash *ATSessionHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
var code int
var err error
rqs := handlers.RequestSession{
Ctx: req.Context(),
Writer: w,
}
rp := ash.GetRequestParser()
cfg := ash.GetConfig()
cfg.SessionId, err = rp.GetSessionId(req)
if err != nil {
logg.ErrorCtxf(rqs.Ctx, "", "header processing error", err)
ash.writeError(w, 400, err)
}
rqs.Config = cfg
rqs.Input, err = rp.GetInput(req)
if err != nil {
logg.ErrorCtxf(rqs.Ctx, "", "header processing error", err)
ash.writeError(w, 400, err)
return
}
rqs, err = ash.Process(rqs)
switch err {
case handlers.ErrStorage:
code = 500
case handlers.ErrEngineInit:
code = 500
case handlers.ErrEngineExec:
code = 500
default:
code = 200
}
if code != 200 {
ash.writeError(w, 500, err)
return
}
w.WriteHeader(200)
w.Header().Set("Content-Type", "text/plain")
rqs, err = ash.Output(rqs)
if err != nil {
ash.writeError(w, 500, err)
return
}
rqs, err = ash.Reset(rqs)
if err != nil {
ash.writeError(w, 500, err)
return
}
}
func (ash *ATSessionHandler) Output(rqs handlers.RequestSession) (handlers.RequestSession, error) {
var err error
var prefix string
if rqs.Continue {
prefix = "CON "
} else {
prefix = "END "
}
_, err = io.WriteString(rqs.Writer, prefix)
if err != nil {
return rqs, err
}
_, err = rqs.Engine.WriteResult(rqs.Ctx, rqs.Writer)
return rqs, err
}
+122
View File
@@ -0,0 +1,122 @@
package http
import (
"io/ioutil"
"net/http"
"strconv"
"git.defalsify.org/vise.git/logging"
"git.grassecon.net/urdt/ussd/internal/handlers"
)
var (
logg = logging.NewVanilla().WithDomain("httpserver")
)
type DefaultRequestParser struct {
}
func(rp *DefaultRequestParser) GetSessionId(rq any) (string, error) {
rqv, ok := rq.(*http.Request)
if !ok {
return "", handlers.ErrInvalidRequest
}
v := rqv.Header.Get("X-Vise-Session")
if v == "" {
return "", handlers.ErrSessionMissing
}
return v, nil
}
func(rp *DefaultRequestParser) GetInput(rq any) ([]byte, error) {
rqv, ok := rq.(*http.Request)
if !ok {
return nil, handlers.ErrInvalidRequest
}
defer rqv.Body.Close()
v, err := ioutil.ReadAll(rqv.Body)
if err != nil {
return nil, err
}
return v, nil
}
type SessionHandler struct {
handlers.RequestHandler
}
func ToSessionHandler(h handlers.RequestHandler) *SessionHandler {
return &SessionHandler{
RequestHandler: h,
}
}
func(f *SessionHandler) writeError(w http.ResponseWriter, code int, err error) {
s := err.Error()
w.Header().Set("Content-Length", strconv.Itoa(len(s)))
w.WriteHeader(code)
_, err = w.Write([]byte{})
if err != nil {
logg.Errorf("error writing error!!", "err", err, "olderr", s)
w.WriteHeader(500)
}
return
}
func(f *SessionHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
var code int
var err error
var perr error
rqs := handlers.RequestSession{
Ctx: req.Context(),
Writer: w,
}
rp := f.GetRequestParser()
cfg := f.GetConfig()
cfg.SessionId, err = rp.GetSessionId(req)
if err != nil {
logg.ErrorCtxf(rqs.Ctx, "", "header processing error", err)
f.writeError(w, 400, err)
}
rqs.Config = cfg
rqs.Input, err = rp.GetInput(req)
if err != nil {
logg.ErrorCtxf(rqs.Ctx, "", "header processing error", err)
f.writeError(w, 400, err)
return
}
rqs, err = f.Process(rqs)
switch err {
case handlers.ErrStorage:
code = 500
case handlers.ErrEngineInit:
code = 500
case handlers.ErrEngineExec:
code = 500
default:
code = 200
}
if code != 200 {
f.writeError(w, 500, err)
return
}
w.WriteHeader(200)
w.Header().Set("Content-Type", "text/plain")
rqs, err = f.Output(rqs)
rqs, perr = f.Reset(rqs)
if err != nil {
f.writeError(w, 500, err)
return
}
if perr != nil {
f.writeError(w, 500, perr)
return
}
}
+44
View File
@@ -0,0 +1,44 @@
package storage
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()
}
-46
View File
@@ -1,46 +0,0 @@
package utils
import (
"encoding/json"
"os"
)
type AccountFileHandler struct {
FilePath string
}
func NewAccountFileHandler(path string) *AccountFileHandler {
return &AccountFileHandler{FilePath: path}
}
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) 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) 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()
}
+37
View File
@@ -0,0 +1,37 @@
package utils
import (
"encoding/binary"
)
type DataTyp uint16
const (
DATA_ACCOUNT DataTyp = iota
DATA_ACCOUNT_CREATED
DATA_TRACKING_ID
DATA_PUBLIC_KEY
DATA_CUSTODIAL_ID
DATA_ACCOUNT_PIN
DATA_ACCOUNT_STATUS
DATA_FIRST_NAME
DATA_FAMILY_NAME
DATA_YOB
DATA_LOCATION
DATA_GENDER
DATA_OFFERINGS
DATA_RECIPIENT
DATA_AMOUNT
DATA_TEMPORARY_PIN
)
func typToBytes(typ DataTyp) []byte {
var b [2]byte
binary.BigEndian.PutUint16(b[:], uint16(typ))
return b[:]
}
func PackKey(typ DataTyp, data []byte) []byte {
v := typToBytes(typ)
return append(v, data...)
}
-13
View File
@@ -1,13 +0,0 @@
package utils
type AccountFileHandlerInterface interface {
EnsureFileExists() error
ReadAccountData() (map[string]string, error)
WriteAccountData(data map[string]string) error
}
+32
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)
}
+2 -1
View File
@@ -1,10 +1,11 @@
# Variables to match files in the current directory # Variables to match files in the current directory
INPUTS = $(wildcard ./*.vis) INPUTS = $(wildcard ./*.vis)
TXTS = $(wildcard ./*.txt.orig) TXTS = $(wildcard ./*.txt.orig)
VISE_PATH := ../../go-vise
# Rule to build .bin files from .vis files # Rule to build .bin files from .vis files
%.vis: %.vis:
go run ../../go-vise/dev/asm -f pp.csv $(basename $@).vis > $(basename $@).bin go run $(VISE_PATH)/dev/asm/main.go -f pp.csv $(basename $@).vis > $(basename $@).bin
@echo "Built $(basename $@).bin from $(basename $@).vis" @echo "Built $(basename $@).bin from $(basename $@).vis"
# Rule to copy .orig files to .txt # Rule to copy .orig files to .txt
+1
View File
@@ -0,0 +1 @@
Confirm your new PIN:
@@ -0,0 +1,7 @@
CATCH invalid_pin flag_valid_pin 0
MOUT back 0
HALT
INCMP _ 0
INCMP * pin_reset_success
@@ -0,0 +1 @@
Thibitisha PIN yako mpya:
+2
View File
@@ -0,0 +1,2 @@
LOAD quit_with_help 0
HALT
+1
View File
@@ -0,0 +1 @@
The PIN you entered is invalid.The PIN must be different from your current PIN.For help call +254757628885
+3
View File
@@ -0,0 +1,3 @@
MOUT back 0
HALT
INCMP _ 0
+1
View File
@@ -0,0 +1 @@
PIN mpya na udhibitisho wa pin mpya hazilingani.Tafadhali jaribu tena.Kwa usaidizi piga simu +254757628885.
@@ -6,3 +6,7 @@ msgstr "Ombi lako limetumwa. %s atapokea %s kutoka kwa %s."
msgid "Thank you for using Sarafu. Goodbye!" msgid "Thank you for using Sarafu. Goodbye!"
msgstr "Asante kwa kutumia huduma ya Sarafu. Kwaheri!" msgstr "Asante kwa kutumia huduma ya Sarafu. Kwaheri!"
msgid "For more help,please call: 0757628885"
msgstr "Kwa usaidizi zaidi,piga: 0757628885"
+1 -1
View File
@@ -10,6 +10,6 @@ HALT
INCMP send 1 INCMP send 1
INCMP quit 2 INCMP quit 2
INCMP my_account 3 INCMP my_account 3
INCMP quit 4 INCMP help 4
INCMP quit 9 INCMP quit 9
INCMP . * INCMP . *
+1
View File
@@ -0,0 +1 @@
Enter a new four number pin
+13
View File
@@ -0,0 +1,13 @@
LOAD authorize_account 12
RELOAD authorize_account
CATCH incorrect_pin flag_incorrect_pin 1
CATCH old_pin flag_allow_update 0
MOUT back 0
HALT
INCMP _ 0
LOAD save_temporary_pin 6
LOAD verify_new_pin 0
RELOAD save_temporary_pin
RELOAD verify_new_pin
INCMP * confirm_pin_change
+2
View File
@@ -0,0 +1,2 @@
Weka PIN mpya ya nne nambari:
+1
View File
@@ -0,0 +1 @@
Enter your old PIN
+7
View File
@@ -0,0 +1,7 @@
LOAD reset_allow_update 0
MOUT back 0
HALT
RELOAD reset_allow_update
INCMP _ 0
INCMP new_pin *
+1
View File
@@ -0,0 +1 @@
Weka PIN yako ya zamani:
+2
View File
@@ -4,3 +4,5 @@ MOUT guard_pin 3
MOUT back 0 MOUT back 0
HALT HALT
INCMP _ 0 INCMP _ 0
INCMP old_pin 1
+1
View File
@@ -0,0 +1 @@
The PIN is not a match. Try again
@@ -0,0 +1,6 @@
MOUT retry 1
MOUT quit 9
HALT
INCMP confirm_pin_change 1
INCMP quit 9
+1
View File
@@ -0,0 +1 @@
Your PIN change request has been successful
@@ -0,0 +1,10 @@
LOAD confirm_pin_change 0
RELOAD confirm_pin_change
CATCH pin_reset_mismatch flag_pin_mismatch 1
MOUT back 0
MOUT quit 9
HALT
INCMP main 0
INCMP quit 9
@@ -0,0 +1 @@
Ombi lako la kubadili PIN limefanikiwa