voucher-data #138
@ -1118,7 +1118,7 @@ func (h *Handlers) CheckVouchers(ctx context.Context, sym string, input []byte)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
data := processVouchers(vouchersResp.Result.Holdings)
|
||||
data := utils.ProcessVouchers(vouchersResp.Result.Holdings)
|
||||
|
||||
// Store all voucher data
|
||||
dataMap := map[string]string{
|
||||
@ -1137,31 +1137,6 @@ func (h *Handlers) CheckVouchers(ctx context.Context, sym string, input []byte)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// processVouchers converts holdings into formatted strings
|
||||
func processVouchers(holdings []struct {
|
||||
ContractAddress string `json:"contractAddress"`
|
||||
TokenSymbol string `json:"tokenSymbol"`
|
||||
TokenDecimals string `json:"tokenDecimals"`
|
||||
Balance string `json:"balance"`
|
||||
}) VoucherMetadata {
|
||||
var data VoucherMetadata
|
||||
var symbols, balances, decimals, addresses []string
|
||||
|
||||
for i, h := range holdings {
|
||||
symbols = append(symbols, fmt.Sprintf("%d:%s", i+1, h.TokenSymbol))
|
||||
balances = append(balances, fmt.Sprintf("%d:%s", i+1, h.Balance))
|
||||
decimals = append(decimals, fmt.Sprintf("%d:%s", i+1, h.TokenDecimals))
|
||||
addresses = append(addresses, fmt.Sprintf("%d:%s", i+1, h.ContractAddress))
|
||||
}
|
||||
|
||||
data.Symbol = strings.Join(symbols, "\n")
|
||||
data.Balance = strings.Join(balances, "\n")
|
||||
data.Decimal = strings.Join(decimals, "\n")
|
||||
data.Address = strings.Join(addresses, "\n")
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
// GetVoucherList fetches the list of vouchers and formats them
|
||||
func (h *Handlers) GetVoucherList(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var res resource.Result
|
||||
Alfred-mk marked this conversation as resolved
Outdated
|
||||
@ -1193,8 +1168,7 @@ func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (r
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Retrieve the voucher metadata using the PrefixDb interface
|
||||
metadata, err := getVoucherData(ctx, h.prefixDb, inputStr)
|
||||
metadata, err := utils.GetVoucherData(ctx, h.prefixDb, inputStr)
|
||||
if err != nil {
|
||||
return res, fmt.Errorf("failed to retrieve voucher data: %v", err)
|
||||
}
|
||||
@ -1204,7 +1178,7 @@ func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (r
|
||||
return res, nil
|
||||
}
|
||||
|
||||
if err := h.storeTemporaryVoucher(ctx, sessionId, metadata); err != nil {
|
||||
if err := utils.StoreTemporaryVoucher(ctx, h.userdataStore, sessionId, metadata); err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
@ -1214,86 +1188,9 @@ func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (r
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// getVoucherData retrieves and matches voucher data
|
||||
func getVoucherData(ctx context.Context, db storage.PrefixDb, input string) (*VoucherMetadata, error) {
|
||||
keys := []string{"sym", "bal", "deci", "addr"}
|
||||
data := make(map[string]string)
|
||||
|
||||
for _, key := range keys {
|
||||
value, err := db.Get(ctx, []byte(key))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get %s: %v", key, err)
|
||||
}
|
||||
data[key] = string(value)
|
||||
}
|
||||
|
||||
symbol, balance, decimal, address := matchVoucher(input,
|
||||
data["sym"],
|
||||
data["bal"],
|
||||
data["deci"],
|
||||
data["addr"])
|
||||
|
||||
if symbol == "" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &VoucherMetadata{
|
||||
Symbol: symbol,
|
||||
Balance: balance,
|
||||
Decimal: decimal,
|
||||
Address: address,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// MatchVoucher finds the matching voucher symbol, balance, decimals and contract address based on the input.
|
||||
func matchVoucher(input, symbols, balances, decimals, addresses string) (symbol, balance, decimal, address string) {
|
||||
symList := strings.Split(symbols, "\n")
|
||||
balList := strings.Split(balances, "\n")
|
||||
decList := strings.Split(decimals, "\n")
|
||||
addrList := strings.Split(addresses, "\n")
|
||||
|
||||
for i, sym := range symList {
|
||||
parts := strings.SplitN(sym, ":", 2)
|
||||
if len(parts) != 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
if input == parts[0] || strings.EqualFold(input, parts[1]) {
|
||||
symbol = parts[1]
|
||||
if i < len(balList) {
|
||||
balance = strings.SplitN(balList[i], ":", 2)[1]
|
||||
}
|
||||
if i < len(decList) {
|
||||
decimal = strings.SplitN(decList[i], ":", 2)[1]
|
||||
}
|
||||
if i < len(addrList) {
|
||||
address = strings.SplitN(addrList[i], ":", 2)[1]
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (h *Handlers) storeTemporaryVoucher(ctx context.Context, sessionId string, data *VoucherMetadata) error {
|
||||
entries := map[utils.DataTyp][]byte{
|
||||
utils.DATA_TEMPORARY_SYM: []byte(data.Symbol),
|
||||
utils.DATA_TEMPORARY_BAL: []byte(data.Balance),
|
||||
utils.DATA_TEMPORARY_DECIMAL: []byte(data.Decimal),
|
||||
utils.DATA_TEMPORARY_ADDRESS: []byte(data.Address),
|
||||
}
|
||||
|
||||
for key, value := range entries {
|
||||
if err := h.userdataStore.WriteEntry(ctx, sessionId, key, value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetVoucher retrieves the temp voucher data and sets it as the active data
|
||||
func (h *Handlers) SetVoucher(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var res resource.Result
|
||||
var err error
|
||||
|
||||
sessionId, ok := ctx.Value("SessionId").(string)
|
||||
if !ok {
|
||||
@ -1301,78 +1198,16 @@ func (h *Handlers) SetVoucher(ctx context.Context, sym string, input []byte) (re
|
||||
}
|
||||
|
||||
// Get temporary data
|
||||
tempData, err := h.getTemporaryVoucherData(ctx, sessionId)
|
||||
tempData, err := utils.GetTemporaryVoucherData(ctx, h.userdataStore, sessionId)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
// Set as active and clear temporary
|
||||
if err := h.updateVoucherData(ctx, sessionId, tempData); err != nil {
|
||||
// Set as active and clear temporary data
|
||||
if err := utils.UpdateVoucherData(ctx, h.userdataStore, sessionId, tempData); err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
res.Content = tempData.Symbol
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (h *Handlers) getTemporaryVoucherData(ctx context.Context, sessionId string) (*VoucherMetadata, error) {
|
||||
store := h.userdataStore
|
||||
|
||||
keys := []utils.DataTyp{
|
||||
utils.DATA_TEMPORARY_SYM,
|
||||
utils.DATA_TEMPORARY_BAL,
|
||||
utils.DATA_TEMPORARY_DECIMAL,
|
||||
utils.DATA_TEMPORARY_ADDRESS,
|
||||
}
|
||||
|
||||
data := &VoucherMetadata{}
|
||||
values := make([][]byte, len(keys))
|
||||
|
||||
for i, key := range keys {
|
||||
value, err := store.ReadEntry(ctx, sessionId, key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
values[i] = value
|
||||
}
|
||||
|
||||
data.Symbol = string(values[0])
|
||||
data.Balance = string(values[1])
|
||||
data.Decimal = string(values[2])
|
||||
data.Address = string(values[3])
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (h *Handlers) updateVoucherData(ctx context.Context, sessionId string, data *VoucherMetadata) error {
|
||||
// Set active voucher data
|
||||
activeEntries := map[utils.DataTyp][]byte{
|
||||
utils.DATA_ACTIVE_SYM: []byte(data.Symbol),
|
||||
utils.DATA_ACTIVE_BAL: []byte(data.Balance),
|
||||
utils.DATA_ACTIVE_DECIMAL: []byte(data.Decimal),
|
||||
utils.DATA_ACTIVE_ADDRESS: []byte(data.Address),
|
||||
}
|
||||
|
||||
// Clear temporary voucher data
|
||||
tempEntries := map[utils.DataTyp][]byte{
|
||||
utils.DATA_TEMPORARY_SYM: []byte(""),
|
||||
utils.DATA_TEMPORARY_BAL: []byte(""),
|
||||
utils.DATA_TEMPORARY_DECIMAL: []byte(""),
|
||||
utils.DATA_TEMPORARY_ADDRESS: []byte(""),
|
||||
}
|
||||
|
||||
// Write all entries
|
||||
for key, value := range activeEntries {
|
||||
if err := h.userdataStore.WriteEntry(ctx, sessionId, key, value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for key, value := range tempEntries {
|
||||
if err := h.userdataStore.WriteEntry(ctx, sessionId, key, value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
184
internal/utils/vouchers.go
Normal file
@ -0,0 +1,184 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"context"
|
||||
|
||||
|
||||
"git.grassecon.net/urdt/ussd/internal/storage"
|
||||
)
|
||||
|
||||
// VoucherMetadata helps organize voucher data fields
|
||||
type VoucherMetadata struct {
|
||||
Symbol string
|
||||
Balance string
|
||||
Decimal string
|
||||
Address string
|
||||
}
|
||||
|
||||
// ProcessVouchers converts holdings into formatted strings
|
||||
func ProcessVouchers(holdings []struct {
|
||||
ContractAddress string `json:"contractAddress"`
|
||||
TokenSymbol string `json:"tokenSymbol"`
|
||||
TokenDecimals string `json:"tokenDecimals"`
|
||||
Balance string `json:"balance"`
|
||||
}) VoucherMetadata {
|
||||
var data VoucherMetadata
|
||||
var symbols, balances, decimals, addresses []string
|
||||
|
||||
for i, h := range holdings {
|
||||
symbols = append(symbols, fmt.Sprintf("%d:%s", i+1, h.TokenSymbol))
|
||||
balances = append(balances, fmt.Sprintf("%d:%s", i+1, h.Balance))
|
||||
decimals = append(decimals, fmt.Sprintf("%d:%s", i+1, h.TokenDecimals))
|
||||
addresses = append(addresses, fmt.Sprintf("%d:%s", i+1, h.ContractAddress))
|
||||
}
|
||||
|
||||
data.Symbol = strings.Join(symbols, "\n")
|
||||
data.Balance = strings.Join(balances, "\n")
|
||||
data.Decimal = strings.Join(decimals, "\n")
|
||||
data.Address = strings.Join(addresses, "\n")
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
// GetVoucherData retrieves and matches voucher data
|
||||
func GetVoucherData(ctx context.Context, db storage.PrefixDb, input string) (*VoucherMetadata, error) {
|
||||
keys := []string{"sym", "bal", "deci", "addr"}
|
||||
data := make(map[string]string)
|
||||
|
||||
for _, key := range keys {
|
||||
value, err := db.Get(ctx, []byte(key))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get %s: %v", key, err)
|
||||
}
|
||||
data[key] = string(value)
|
||||
}
|
||||
|
||||
symbol, balance, decimal, address := MatchVoucher(input,
|
||||
data["sym"],
|
||||
data["bal"],
|
||||
data["deci"],
|
||||
data["addr"])
|
||||
|
||||
if symbol == "" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &VoucherMetadata{
|
||||
Symbol: symbol,
|
||||
Balance: balance,
|
||||
Decimal: decimal,
|
||||
Address: address,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// MatchVoucher finds the matching voucher symbol, balance, decimals and contract address based on the input.
|
||||
func MatchVoucher(input, symbols, balances, decimals, addresses string) (symbol, balance, decimal, address string) {
|
||||
symList := strings.Split(symbols, "\n")
|
||||
balList := strings.Split(balances, "\n")
|
||||
decList := strings.Split(decimals, "\n")
|
||||
Alfred-mk marked this conversation as resolved
Outdated
lash
commented
When will this condition occur? When will this condition occur?
Alfred-mk
commented
It will only occur if the string is not well formatted in the "1:SRF" format, such as it being "1SRF" or "1 SRF" Ideally, this will not be encountered but I added this as an edge case in the unlikely event that it does It will only occur if the string is not well formatted in the "1:SRF" format, such as it being "1SRF" or "1 SRF"
Ideally, this will not be encountered but I added this as an edge case in the unlikely event that it does
lash
commented
but shouldnt that raise an error, as it should never happen? but shouldnt that raise an error, as it should never happen?
Alfred-mk
commented
On further assessment, I see it best to remove the code as the condition would never occur. The data being matched comes from the db, and for this condition to occur means an issue lies with the functions that process and store the data On further assessment, I see it best to remove the code as the condition would never occur.
The data being matched comes from the db, and for this condition to occur means an issue lies with the functions that process and store the data
|
||||
addrList := strings.Split(addresses, "\n")
|
||||
|
||||
for i, sym := range symList {
|
||||
parts := strings.SplitN(sym, ":", 2)
|
||||
if len(parts) != 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
if input == parts[0] || strings.EqualFold(input, parts[1]) {
|
||||
symbol = parts[1]
|
||||
if i < len(balList) {
|
||||
balance = strings.SplitN(balList[i], ":", 2)[1]
|
||||
}
|
||||
if i < len(decList) {
|
||||
decimal = strings.SplitN(decList[i], ":", 2)[1]
|
||||
}
|
||||
if i < len(addrList) {
|
||||
address = strings.SplitN(addrList[i], ":", 2)[1]
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// StoreTemporaryVoucher saves voucher metadata as temporary entries in the DataStore.
|
||||
func StoreTemporaryVoucher(ctx context.Context, store DataStore, sessionId string, data *VoucherMetadata) error {
|
||||
entries := map[DataTyp][]byte{
|
||||
DATA_TEMPORARY_SYM: []byte(data.Symbol),
|
||||
DATA_TEMPORARY_BAL: []byte(data.Balance),
|
||||
DATA_TEMPORARY_DECIMAL: []byte(data.Decimal),
|
||||
DATA_TEMPORARY_ADDRESS: []byte(data.Address),
|
||||
}
|
||||
|
||||
for key, value := range entries {
|
||||
if err := store.WriteEntry(ctx, sessionId, key, value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetTemporaryVoucherData retrieves temporary voucher metadata from the DataStore.
|
||||
func GetTemporaryVoucherData(ctx context.Context, store DataStore, sessionId string) (*VoucherMetadata, error) {
|
||||
keys := []DataTyp{
|
||||
DATA_TEMPORARY_SYM,
|
||||
DATA_TEMPORARY_BAL,
|
||||
DATA_TEMPORARY_DECIMAL,
|
||||
DATA_TEMPORARY_ADDRESS,
|
||||
}
|
||||
|
||||
data := &VoucherMetadata{}
|
||||
values := make([][]byte, len(keys))
|
||||
|
||||
for i, key := range keys {
|
||||
value, err := store.ReadEntry(ctx, sessionId, key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
values[i] = value
|
||||
}
|
||||
|
||||
data.Symbol = string(values[0])
|
||||
data.Balance = string(values[1])
|
||||
data.Decimal = string(values[2])
|
||||
data.Address = string(values[3])
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// UpdateVoucherData sets the active voucher data and clears the temporary voucher data in the DataStore.
|
||||
func UpdateVoucherData(ctx context.Context, store DataStore, sessionId string, data *VoucherMetadata) error {
|
||||
// Active voucher data entries
|
||||
activeEntries := map[DataTyp][]byte{
|
||||
DATA_ACTIVE_SYM: []byte(data.Symbol),
|
||||
DATA_ACTIVE_BAL: []byte(data.Balance),
|
||||
DATA_ACTIVE_DECIMAL: []byte(data.Decimal),
|
||||
Alfred-mk marked this conversation as resolved
lash
commented
Do we need to clear them here? Can't we just overwrite later? Do we need to clear them here? Can't we just overwrite later?
Alfred-mk
commented
They can be left and overwritten with any new temporary data I wanted to work on this functionality on a different PR, where we'll make use of a single temporary data row They can be left and overwritten with any new temporary data
I wanted to work on this functionality on a different PR, where we'll make use of a single temporary data row
lash
commented
ok just drop the lines then? ok just drop the lines then?
|
||||
DATA_ACTIVE_ADDRESS: []byte(data.Address),
|
||||
}
|
||||
|
||||
// Clear temporary voucher data entries
|
||||
tempEntries := map[DataTyp][]byte{
|
||||
DATA_TEMPORARY_SYM: []byte(""),
|
||||
DATA_TEMPORARY_BAL: []byte(""),
|
||||
DATA_TEMPORARY_DECIMAL: []byte(""),
|
||||
DATA_TEMPORARY_ADDRESS: []byte(""),
|
||||
}
|
||||
|
||||
// Write active data
|
||||
for key, value := range activeEntries {
|
||||
if err := store.WriteEntry(ctx, sessionId, key, value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Clear temporary data
|
||||
for key, value := range tempEntries {
|
||||
if err := store.WriteEntry(ctx, sessionId, key, value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
this is now the same struct as
VoucherMetadata
can we consolidate please?