package ledgerapiimp import ( "context" "fmt" "os" "strings" "time" ledgerclient "github.com/tech/sendico/ledger/client" api "github.com/tech/sendico/pkg/api/http" "github.com/tech/sendico/pkg/auth" "github.com/tech/sendico/pkg/merrors" "github.com/tech/sendico/pkg/mlogger" "github.com/tech/sendico/pkg/mservice" ledgerv1 "github.com/tech/sendico/pkg/proto/ledger/v1" eapi "github.com/tech/sendico/server/interface/api" mutil "github.com/tech/sendico/server/internal/mutil/param" "go.mongodb.org/mongo-driver/v2/bson" "go.uber.org/zap" ) type ledgerClient interface { CreateAccount(ctx context.Context, req *ledgerv1.CreateAccountRequest) (*ledgerv1.CreateAccountResponse, error) ListAccounts(ctx context.Context, req *ledgerv1.ListAccountsRequest) (*ledgerv1.ListAccountsResponse, error) GetBalance(ctx context.Context, req *ledgerv1.GetBalanceRequest) (*ledgerv1.BalanceResponse, error) Close() error } type LedgerAPI struct { logger mlogger.Logger client ledgerClient enf auth.Enforcer oph mutil.ParamHelper aph mutil.ParamHelper permissionRef bson.ObjectID balancePerm bson.ObjectID } func (a *LedgerAPI) Name() mservice.Type { return mservice.LedgerAccounts } func (a *LedgerAPI) Finish(ctx context.Context) error { if a.client != nil { if err := a.client.Close(); err != nil { a.logger.Warn("Failed to close ledger client", zap.Error(err)) } } return nil } func CreateAPI(apiCtx eapi.API) (*LedgerAPI, error) { p := &LedgerAPI{ logger: apiCtx.Logger().Named(mservice.LedgerAccounts), enf: apiCtx.Permissions().Enforcer(), oph: mutil.CreatePH(mservice.Organizations), aph: mutil.CreatePH("ledger_account"), } desc, err := apiCtx.Permissions().GetPolicyDescription(context.Background(), mservice.LedgerAccounts) if err != nil { p.logger.Warn("Failed to fetch ledger accounts permission description", zap.Error(err)) return nil, err } p.permissionRef = desc.ID bdesc, err := apiCtx.Permissions().GetPolicyDescription(context.Background(), mservice.LedgerBalances) if err != nil { p.logger.Warn("Failed to fetch ledger balances permission description", zap.Error(err)) return nil, err } p.balancePerm = bdesc.ID if err := p.initLedgerClient(apiCtx.Config().Ledger); err != nil { p.logger.Error("Failed to initialize ledger client", zap.Error(err)) return nil, err } apiCtx.Register().AccountHandler(p.Name(), p.oph.AddRef("/"), api.Get, p.listAccounts) apiCtx.Register().AccountHandler(p.Name(), p.oph.AddRef("/"), api.Post, p.createAccount) apiCtx.Register().AccountHandler(p.Name(), p.aph.AddRef(p.oph.AddRef("/"))+"/balance", api.Get, p.getBalance) return p, nil } func (a *LedgerAPI) initLedgerClient(cfg *eapi.LedgerConfig) error { if cfg == nil { return merrors.InvalidArgument("ledger configuration is not provided") } address := strings.TrimSpace(cfg.Address) if address == "" { address = strings.TrimSpace(os.Getenv(cfg.AddressEnv)) } if address == "" { return merrors.InvalidArgument(fmt.Sprintf("ledger address is not specified and address env %s is empty", cfg.AddressEnv)) } clientCfg := ledgerclient.Config{ Address: address, DialTimeout: time.Duration(cfg.DialTimeoutSeconds) * time.Second, CallTimeout: time.Duration(cfg.CallTimeoutSeconds) * time.Second, Insecure: cfg.Insecure, } client, err := ledgerclient.New(context.Background(), clientCfg) if err != nil { return err } a.client = client return nil }