cashless2ecash

cashless2ecash: pay with cards for digital cash (experimental)
Log | Files | Refs | README

proc-retrier.go (3680B)


      1 // This file is part of taler-cashless2ecash.
      2 // Copyright (C) 2024 Joel Häberli
      3 //
      4 // taler-cashless2ecash is free software: you can redistribute it and/or modify it
      5 // under the terms of the GNU Affero General Public License as published
      6 // by the Free Software Foundation, either version 3 of the License,
      7 // or (at your option) any later version.
      8 //
      9 // taler-cashless2ecash is distributed in the hope that it will be useful, but
     10 // WITHOUT ANY WARRANTY; without even the implied warranty of
     11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12 // Affero General Public License for more details.
     13 //
     14 // You should have received a copy of the GNU Affero General Public License
     15 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
     16 //
     17 // SPDX-License-Identifier: AGPL3.0-or-later
     18 
     19 package internal_proc
     20 
     21 import (
     22 	internal_utils "c2ec/internal/utils"
     23 	"c2ec/pkg/config"
     24 	"c2ec/pkg/db"
     25 	"c2ec/pkg/provider"
     26 	"context"
     27 	"errors"
     28 	"fmt"
     29 	"time"
     30 )
     31 
     32 const RETRY_CHANNEL_BUFFER_SIZE = 10
     33 const PS_RETRY_CHANNEL = "retry"
     34 
     35 func RunRetrier(ctx context.Context, errs chan error) {
     36 
     37 	// go RunListener(
     38 	// 	ctx,
     39 	// 	PS_RETRY_CHANNEL,
     40 	// 	retryCallback,
     41 	// 	make(chan *Notification, RETRY_CHANNEL_BUFFER_SIZE),
     42 	// 	errs,
     43 	// )
     44 
     45 	go func() {
     46 		lastlog := time.Now().Add(time.Minute * -3)
     47 		for {
     48 			withdrawals, err := db.DB.GetWithdrawalsForConfirmation()
     49 			time.Sleep(time.Duration(1000 * time.Millisecond))
     50 			if err != nil {
     51 				internal_utils.LogError("proc-retrier", err)
     52 				errs <- err
     53 				continue
     54 			}
     55 			if lastlog.Before(time.Now().Add(time.Second * -30)) {
     56 				internal_utils.LogInfo("proc-retrier", fmt.Sprintf("retrier confirming 'selected' withdrawals. found %d ready for confirmation", len(withdrawals)))
     57 				lastlog = time.Now()
     58 			}
     59 			for _, w := range withdrawals {
     60 				retryOrSkip(w, errs)
     61 			}
     62 		}
     63 	}()
     64 }
     65 
     66 // func retryCallback(n *Notification, errs chan error) {
     67 
     68 // 	withdrawalId, err := strconv.Atoi(n.Payload)
     69 // 	if err != nil {
     70 // 		internal_utils.LogError("proc-retrier", err)
     71 // 		errs <- err
     72 // 		return
     73 // 	}
     74 
     75 // 	w, err := DB.GetWithdrawalById(withdrawalId)
     76 // 	if err != nil {
     77 // 		internal_utils.LogError("proc-retrier", err)
     78 // 		errs <- err
     79 // 		return
     80 // 	}
     81 
     82 // 	retryOrSkip(w, errs)
     83 // }
     84 
     85 func retryOrSkip(w *db.Withdrawal, errs chan error) {
     86 	var lastRetryTs int64 = 0
     87 	if w.LastRetryTs != nil {
     88 		lastRetryTs = *w.LastRetryTs
     89 		if internal_utils.ShouldStartRetry(time.Unix(lastRetryTs, 0), int(w.RetryCounter), config.CONFIG.Server.RetryDelayMs) {
     90 			internal_utils.LogInfo("proc-retrier", "retrying for wopid="+internal_utils.TalerBinaryEncode(w.Wopid))
     91 			confirmRetryOrAbort(w, errs)
     92 		}
     93 	} else {
     94 		internal_utils.LogInfo("proc-retrier", "first retry confirming wopid="+internal_utils.TalerBinaryEncode(w.Wopid))
     95 		confirmRetryOrAbort(w, errs)
     96 	}
     97 }
     98 
     99 func confirmRetryOrAbort(withdrawal *db.Withdrawal, errs chan error) {
    100 
    101 	if withdrawal == nil {
    102 		err := errors.New("withdrawal was null")
    103 		internal_utils.LogError("proc-retrier", err)
    104 		errs <- err
    105 		return
    106 	}
    107 
    108 	prvdr, err := db.DB.GetProviderByTerminal(withdrawal.TerminalId)
    109 	if err != nil {
    110 		internal_utils.LogError("proc-retrier", err)
    111 		errs <- err
    112 		return
    113 	}
    114 
    115 	client := provider.PROVIDER_CLIENTS[prvdr.Name]
    116 	if client == nil {
    117 		err := fmt.Errorf("the provider client for provider with name=%s is not configured", prvdr.Name)
    118 		internal_utils.LogError("proc-retrier", err)
    119 		errs <- err
    120 		return
    121 	}
    122 	transaction, err := client.GetTransaction(*withdrawal.ProviderTransactionId)
    123 	if err != nil {
    124 		internal_utils.LogError("proc-retrier", err)
    125 		errs <- err
    126 		return
    127 	}
    128 
    129 	finaliseOrSetRetry(transaction, int(withdrawal.WithdrawalRowId), errs)
    130 }