diff --git a/dev/api.go b/dev/api.go index 2ab038b..0895a6d 100644 --- a/dev/api.go +++ b/dev/api.go @@ -6,11 +6,15 @@ import ( "encoding/json" "fmt" "math/rand" + "os" "strconv" + "strings" "time" "github.com/gofrs/uuid" "git.defalsify.org/vise.git/logging" + "git.defalsify.org/vise.git/db" + fsdb "git.defalsify.org/vise.git/db/fs" "git.grassecon.net/grassrootseconomics/sarafu-api/models" dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" ) @@ -42,6 +46,7 @@ type Account struct { Nonce int `json: "nonce"` DefaultVoucher string `json: "defaultVoucher"` Balances map[string]int `json: "balances"` + Alias string Txs []string `json: "txs"` } @@ -56,6 +61,8 @@ type Voucher struct { } type DevAccountService struct { + dir string + db db.Db accounts map[string]Account accountsTrack map[string]string accountsAlias map[string]string @@ -70,8 +77,10 @@ type DevAccountService struct { // accountsSession map[string]string } -func NewDevAccountService() *DevAccountService { - return &DevAccountService{ +func NewDevAccountService(ctx context.Context, d string) *DevAccountService { + svc := &DevAccountService{ + dir: d, + db: fsdb.NewFsDb(), accounts: make(map[string]Account), accountsTrack: make(map[string]string), accountsAlias: make(map[string]string), @@ -81,6 +90,65 @@ func NewDevAccountService() *DevAccountService { txsTrack: make(map[string]string), autoVoucherValue: make(map[string]int), } + err := svc.db.Connect(ctx, d) + if err != nil { + panic(err) + } + svc.db.SetPrefix(db.DATATYPE_USERDATA) + err = svc.loadAll(ctx) + if err != nil { + panic(err) + } + return svc +} + +func (das *DevAccountService) loadAccount(ctx context.Context, pubKey string, v []byte) error { + var acc Account + + err := json.Unmarshal(v, &acc) + if err != nil { + return fmt.Errorf("malformed account: %v", pubKey) + } + das.accounts[pubKey] = acc + das.accountsTrack[acc.Track] = pubKey + if acc.Alias != "" { + das.accountsAlias[acc.Alias] = pubKey + } + return nil +} + +func (das *DevAccountService) loadItem(ctx context.Context, k []byte, v []byte) error { + var err error + s := string(k) + ss := strings.SplitN(s, "_", 2) + if len(ss) != 2 { + return fmt.Errorf("malformed key: %s", s) + } + if ss[0] == "account" { + err = das.loadAccount(ctx, ss[1], v) + } + return err +} + +func (das *DevAccountService) loadAll(ctx context.Context) error { + d, err := os.ReadDir(das.dir) + if err != nil { + return err + } + for _, v := range(d) { + // TODO: move decoding to vise + fp := v.Name() + k := []byte(fp[1:]) + v, err := das.db.Get(ctx, k) + if err != nil { + return err + } + err = das.loadItem(ctx, k, v) + if err != nil { + return err + } + } + return nil } func (das *DevAccountService) WithAutoVoucher(ctx context.Context, symbol string, value int) *DevAccountService { @@ -94,6 +162,7 @@ func (das *DevAccountService) WithAutoVoucher(ctx context.Context, symbol string return das } +// TODO: add persistence for vouchers func (das *DevAccountService) AddVoucher(ctx context.Context, symbol string) error { if symbol == "" { return fmt.Errorf("cannot add empty sym voucher") @@ -154,6 +223,15 @@ func (das *DevAccountService) balanceAuto(ctx context.Context, pubKey string) er return nil } +func (das *DevAccountService) saveAccount(ctx context.Context, acc Account) error { + k := "account_" + acc.Address + v, err := json.Marshal(acc) + if err != nil { + return err + } + return das.db.Put(ctx, []byte(k), v) +} + func (das *DevAccountService) CreateAccount(ctx context.Context) (*models.AccountResult, error) { var b [pubKeyLen]byte uid, err := uuid.NewV4() @@ -168,16 +246,25 @@ func (das *DevAccountService) CreateAccount(ctx context.Context) (*models.Accoun return nil, fmt.Errorf("short read: %d", c) } pubKey := fmt.Sprintf("0x%x", b) - das.accounts[pubKey] = Account{ + acc := Account{ Track: uid.String(), Address: pubKey, } + + err = das.saveAccount(ctx, acc) + if err != nil { + return nil, err + } + + das.accounts[pubKey] = acc das.accountsTrack[uid.String()] = pubKey das.balanceAuto(ctx, pubKey) if das.defaultAccount == zeroAccount { das.defaultAccount = pubKey } + + return &models.AccountResult{ PublicKey: pubKey, TrackingId: uid.String(), diff --git a/go.mod b/go.mod index 786c73c..0a55df8 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( ) require ( + github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/joho/godotenv v1.5.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect diff --git a/go.sum b/go.sum index 4c1bd83..9224bd4 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ git.defalsify.org/vise.git v0.2.3-0.20250103172917-3e190a44568d h1:bPAOVZOX4frSG git.defalsify.org/vise.git v0.2.3-0.20250103172917-3e190a44568d/go.mod h1:jyBMe1qTYUz3mmuoC9JQ/TvFeW0vTanCUcPu3H8p4Ck= git.grassecon.net/grassrootseconomics/visedriver v0.8.0-beta.10.0.20250112121325-9e4c65c8b4d1 h1:RfU5/WFfPxDptlkyx4MT+4YmO79sY6HvIngUq5uwQPU= git.grassecon.net/grassrootseconomics/visedriver v0.8.0-beta.10.0.20250112121325-9e4c65c8b4d1/go.mod h1:E6W7ZOa7ZvVr0Bc5ot0LNSwpSPYq4hXlAIvEPy3AJ7U= +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.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=