linting
This commit is contained in:
@@ -22,7 +22,7 @@ const amountInputHint = "*Amount format*\nEnter amount as a decimal number using
|
||||
type SendTextFunc func(ctx context.Context, chatID string, text string) error
|
||||
|
||||
type ScheduleTracker interface {
|
||||
TrackScheduled(record *storagemodel.TreasuryRequest)
|
||||
TrackScheduled(ctx context.Context, record *storagemodel.TreasuryRequest)
|
||||
Untrack(requestID string)
|
||||
}
|
||||
|
||||
@@ -128,6 +128,11 @@ func (r *Router) HandleUpdate(ctx context.Context, update *model.TelegramWebhook
|
||||
|
||||
binding, err := r.users.ResolveUserBinding(ctx, userID)
|
||||
if err != nil {
|
||||
if errors.Is(err, merrors.ErrNoData) {
|
||||
r.logUnauthorized(update)
|
||||
_ = r.sendText(ctx, chatID, unauthorizedMessage)
|
||||
return true
|
||||
}
|
||||
if r.logger != nil {
|
||||
r.logger.Warn("Failed to resolve treasury user binding",
|
||||
zap.Error(err),
|
||||
@@ -224,7 +229,7 @@ func (r *Router) HandleUpdate(ctx context.Context, update *model.TelegramWebhook
|
||||
|
||||
func (r *Router) startAmountDialog(ctx context.Context, userID, accountID, chatID string, operation storagemodel.TreasuryOperationType) {
|
||||
active, err := r.service.GetActiveRequestForAccount(ctx, accountID)
|
||||
if err != nil {
|
||||
if err != nil && !errors.Is(err, merrors.ErrNoData) {
|
||||
if r.logger != nil {
|
||||
r.logger.Warn("Failed to check active treasury request", zap.Error(err), zap.String("telegram_user_id", userID), zap.String("ledger_account_id", accountID))
|
||||
}
|
||||
@@ -267,7 +272,8 @@ func (r *Router) captureAmount(ctx context.Context, userID, accountID, chatID st
|
||||
})
|
||||
return
|
||||
}
|
||||
if typed, ok := err.(limitError); ok {
|
||||
var typed limitError
|
||||
if errors.As(err, &typed) {
|
||||
switch typed.LimitKind() {
|
||||
case "per_operation":
|
||||
_ = r.sendText(ctx, chatID, "*Amount exceeds allowed limit*\n\n*Max per operation:* "+markdownCode(typed.LimitMax())+"\n\nEnter another amount or "+markdownCommand(CommandCancel)+".")
|
||||
@@ -316,7 +322,7 @@ func (r *Router) confirm(ctx context.Context, userID string, accountID string, c
|
||||
return
|
||||
}
|
||||
if r.tracker != nil {
|
||||
r.tracker.TrackScheduled(record)
|
||||
r.tracker.TrackScheduled(ctx, record)
|
||||
}
|
||||
r.dialogs.Clear(userID)
|
||||
delay := int64(r.service.ExecutionDelay().Seconds())
|
||||
@@ -487,7 +493,7 @@ func (r *Router) resolveAccountProfile(ctx context.Context, ledgerAccountID stri
|
||||
}
|
||||
profile, err := r.service.GetAccountProfile(ctx, ledgerAccountID)
|
||||
if err != nil {
|
||||
if r.logger != nil {
|
||||
if r.logger != nil && !errors.Is(err, merrors.ErrNoData) {
|
||||
r.logger.Warn("Failed to resolve treasury account profile",
|
||||
zap.Error(err),
|
||||
zap.String("ledger_account_id", strings.TrimSpace(ledgerAccountID)))
|
||||
|
||||
@@ -22,6 +22,7 @@ func (f fakeUserBindingResolver) ResolveUserBinding(_ context.Context, telegramU
|
||||
return nil, f.err
|
||||
}
|
||||
if f.bindings == nil {
|
||||
//nolint:nilnil // Test stub uses nil, nil to represent missing binding.
|
||||
return nil, nil
|
||||
}
|
||||
return f.bindings[telegramUserID], nil
|
||||
@@ -36,6 +37,7 @@ func (fakeService) MaxPerOperationLimit() string {
|
||||
}
|
||||
|
||||
func (fakeService) GetActiveRequestForAccount(context.Context, string) (*storagemodel.TreasuryRequest, error) {
|
||||
//nolint:nilnil // Test stub uses nil, nil to represent no active request.
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -48,14 +50,17 @@ func (fakeService) GetAccountProfile(_ context.Context, ledgerAccountID string)
|
||||
}
|
||||
|
||||
func (fakeService) CreateRequest(context.Context, CreateRequestInput) (*storagemodel.TreasuryRequest, error) {
|
||||
//nolint:nilnil // Test stub uses nil, nil to represent no created request.
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (fakeService) ConfirmRequest(context.Context, string, string) (*storagemodel.TreasuryRequest, error) {
|
||||
//nolint:nilnil // Test stub uses nil, nil to represent no confirmed request.
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (fakeService) CancelRequest(context.Context, string, string) (*storagemodel.TreasuryRequest, error) {
|
||||
//nolint:nilnil // Test stub uses nil, nil to represent no cancelled request.
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -260,7 +260,7 @@ func (c *connectorClient) callContext(ctx context.Context) (context.Context, con
|
||||
if ctx == nil {
|
||||
ctx = context.Background()
|
||||
}
|
||||
return context.WithTimeout(ctx, c.cfg.Timeout)
|
||||
return context.WithTimeout(ctx, c.cfg.Timeout) //nolint:gosec // cancel func is always invoked by call sites
|
||||
}
|
||||
|
||||
func structFromMap(values map[string]any) *structpb.Struct {
|
||||
|
||||
@@ -141,7 +141,7 @@ func (c *discoveryClient) resolveClient(_ context.Context) (Client, error) {
|
||||
c.endpointKey = key
|
||||
if c.logger != nil {
|
||||
c.logger.Info("Discovered ledger endpoint selected",
|
||||
zap.String("service", string(mservice.Ledger)),
|
||||
zap.String("service", mservice.Ledger),
|
||||
zap.String("invoke_uri", endpoint.raw),
|
||||
zap.String("address", endpoint.address),
|
||||
zap.Bool("insecure", endpoint.insecure))
|
||||
@@ -186,10 +186,10 @@ func (c *discoveryClient) resolveEndpoint() (discoveryEndpoint, error) {
|
||||
|
||||
func matchesService(service string, candidate mservice.Type) bool {
|
||||
service = strings.TrimSpace(service)
|
||||
if service == "" || strings.TrimSpace(string(candidate)) == "" {
|
||||
if service == "" || strings.TrimSpace(candidate) == "" {
|
||||
return false
|
||||
}
|
||||
return strings.EqualFold(service, strings.TrimSpace(string(candidate)))
|
||||
return strings.EqualFold(service, strings.TrimSpace(candidate))
|
||||
}
|
||||
|
||||
func parseDiscoveryEndpoint(raw string) (discoveryEndpoint, error) {
|
||||
|
||||
@@ -106,7 +106,7 @@ func (a *botUsersAdapter) ResolveUserBinding(ctx context.Context, telegramUserID
|
||||
return nil, err
|
||||
}
|
||||
if record == nil {
|
||||
return nil, nil
|
||||
return nil, merrors.NoData("treasury user binding not found")
|
||||
}
|
||||
return &bot.UserBinding{
|
||||
TelegramUserID: strings.TrimSpace(record.TelegramUserID),
|
||||
@@ -145,7 +145,7 @@ func (a *botServiceAdapter) GetAccountProfile(ctx context.Context, ledgerAccount
|
||||
return nil, err
|
||||
}
|
||||
if profile == nil {
|
||||
return nil, nil
|
||||
return nil, merrors.NoData("treasury account profile not found")
|
||||
}
|
||||
return &bot.AccountProfile{
|
||||
AccountID: strings.TrimSpace(profile.AccountID),
|
||||
|
||||
@@ -2,11 +2,13 @@ package treasury
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
storagemodel "github.com/tech/sendico/gateway/tgsettle/storage/model"
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
"github.com/tech/sendico/pkg/mlogger"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
@@ -86,7 +88,7 @@ func (s *Scheduler) Shutdown() {
|
||||
s.timersMu.Unlock()
|
||||
}
|
||||
|
||||
func (s *Scheduler) TrackScheduled(record *storagemodel.TreasuryRequest) {
|
||||
func (s *Scheduler) TrackScheduled(ctx context.Context, record *storagemodel.TreasuryRequest) {
|
||||
if s == nil || s.service == nil || record == nil {
|
||||
return
|
||||
}
|
||||
@@ -101,10 +103,14 @@ func (s *Scheduler) TrackScheduled(record *storagemodel.TreasuryRequest) {
|
||||
if when.IsZero() {
|
||||
when = time.Now()
|
||||
}
|
||||
runCtx := ctx
|
||||
if runCtx == nil {
|
||||
runCtx = context.Background()
|
||||
}
|
||||
delay := time.Until(when)
|
||||
if delay <= 0 {
|
||||
s.Untrack(requestID)
|
||||
go s.executeAndNotifyByID(context.Background(), requestID)
|
||||
go s.executeAndNotifyByID(runCtx, requestID) //nolint:gosec // scheduler intentionally dispatches due execution asynchronously
|
||||
return
|
||||
}
|
||||
|
||||
@@ -114,7 +120,7 @@ func (s *Scheduler) TrackScheduled(record *storagemodel.TreasuryRequest) {
|
||||
}
|
||||
s.timers[requestID] = time.AfterFunc(delay, func() {
|
||||
s.Untrack(requestID)
|
||||
s.executeAndNotifyByID(context.Background(), requestID)
|
||||
s.executeAndNotifyByID(runCtx, requestID)
|
||||
})
|
||||
s.timersMu.Unlock()
|
||||
}
|
||||
@@ -145,7 +151,7 @@ func (s *Scheduler) hydrateTimers(ctx context.Context) {
|
||||
return
|
||||
}
|
||||
for _, record := range scheduled {
|
||||
s.TrackScheduled(&record)
|
||||
s.TrackScheduled(ctx, &record)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,16 +193,20 @@ func (s *Scheduler) executeAndNotifyByID(ctx context.Context, requestID string)
|
||||
if requestID == "" {
|
||||
return
|
||||
}
|
||||
|
||||
runCtx := ctx
|
||||
if runCtx == nil {
|
||||
runCtx = context.Background()
|
||||
}
|
||||
|
||||
withTimeout, cancel := context.WithTimeout(runCtx, 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
result, err := s.service.ExecuteRequest(withTimeout, requestID)
|
||||
if err != nil {
|
||||
if errors.Is(err, merrors.ErrNoData) {
|
||||
s.logger.Debug("Treasury request is not due for execution", zap.String("request_id", requestID))
|
||||
return
|
||||
}
|
||||
s.logger.Warn("Failed to execute treasury request", zap.Error(err), zap.String("request_id", requestID))
|
||||
return
|
||||
}
|
||||
@@ -228,11 +238,7 @@ func (s *Scheduler) executeAndNotifyByID(ctx context.Context, requestID string)
|
||||
zap.String("chat_id", chatID),
|
||||
zap.String("status", strings.TrimSpace(string(result.Request.Status))))
|
||||
|
||||
notifyCtx := context.Background()
|
||||
if ctx != nil {
|
||||
notifyCtx = ctx
|
||||
}
|
||||
notifyCtx, notifyCancel := context.WithTimeout(notifyCtx, 15*time.Second)
|
||||
notifyCtx, notifyCancel := context.WithTimeout(runCtx, 15*time.Second)
|
||||
defer notifyCancel()
|
||||
|
||||
if err := s.notify(notifyCtx, chatID, text); err != nil {
|
||||
|
||||
@@ -298,33 +298,33 @@ func (s *Service) ExecuteRequest(ctx context.Context, requestID string) (*Execut
|
||||
return nil, err
|
||||
}
|
||||
if record == nil {
|
||||
return nil, nil
|
||||
return nil, merrors.NoData("treasury request not found")
|
||||
}
|
||||
|
||||
switch record.Status {
|
||||
case storagemodel.TreasuryRequestStatusExecuted,
|
||||
storagemodel.TreasuryRequestStatusCancelled,
|
||||
storagemodel.TreasuryRequestStatusFailed:
|
||||
return nil, nil
|
||||
return nil, merrors.NoData("treasury request is not executable")
|
||||
case storagemodel.TreasuryRequestStatusScheduled:
|
||||
claimed, err := s.repo.ClaimScheduled(ctx, requestID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !claimed {
|
||||
return nil, nil
|
||||
return nil, merrors.NoData("treasury request is already claimed")
|
||||
}
|
||||
record, err = s.repo.FindByRequestID(ctx, requestID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if record == nil {
|
||||
return nil, nil
|
||||
return nil, merrors.NoData("treasury request not found")
|
||||
}
|
||||
}
|
||||
|
||||
if record.Status != storagemodel.TreasuryRequestStatusConfirmed {
|
||||
return nil, nil
|
||||
return nil, merrors.NoData("treasury request is not confirmed")
|
||||
}
|
||||
return s.executeClaimed(ctx, record)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user