support using duplicate checker to prevent duplicate submissions for new transaction record

This commit is contained in:
MaysWind
2024-07-07 21:28:07 +08:00
parent a2d6aff28b
commit 847349dcbd
28 changed files with 371 additions and 31 deletions
@@ -0,0 +1,7 @@
package duplicatechecker
// DuplicateChecker is common duplicate checker interface
type DuplicateChecker interface {
Get(checkerType DuplicateCheckerType, uid int64, identification string) (bool, string)
Set(checkerType DuplicateCheckerType, uid int64, identification string, remark string)
}
@@ -0,0 +1,38 @@
package duplicatechecker
import (
"github.com/mayswind/ezbookkeeping/pkg/errs"
"github.com/mayswind/ezbookkeeping/pkg/settings"
)
// DuplicateCheckerContainer contains the current duplicate checker
type DuplicateCheckerContainer struct {
Current DuplicateChecker
}
// Initialize a duplicate checker container singleton instance
var (
Container = &DuplicateCheckerContainer{}
)
// InitializeDuplicateChecker initializes the current duplicate checker according to the config
func InitializeDuplicateChecker(config *settings.Config) error {
if config.DuplicateCheckerType == settings.InMemoryDuplicateCheckerType {
checker, err := NewInMemoryDuplicateChecker(config)
Container.Current = checker
return err
}
return errs.ErrInvalidDuplicateCheckerType
}
// Get returns whether the same submission has been processed and related remark by the current duplicate checker
func (c *DuplicateCheckerContainer) Get(checkerType DuplicateCheckerType, uid int64, identification string) (bool, string) {
return c.Current.Get(checkerType, uid, identification)
}
// Set saves the identification and remark to in-memory cache by the current duplicate checker
func (c *DuplicateCheckerContainer) Set(checkerType DuplicateCheckerType, uid int64, identification string, remark string) {
c.Current.Set(checkerType, uid, identification, remark)
}
@@ -0,0 +1,12 @@
package duplicatechecker
// DuplicateCheckerType represents duplicate checker type
type DuplicateCheckerType uint8
// Types of uuid
const (
DUPLICATE_CHECKER_TYPE_DEFAULT DuplicateCheckerType = 0
DUPLICATE_CHECKER_TYPE_NEW_ACCOUNT DuplicateCheckerType = 1
DUPLICATE_CHECKER_TYPE_NEW_CATEGORY DuplicateCheckerType = 2
DUPLICATE_CHECKER_TYPE_NEW_TRANSACTION DuplicateCheckerType = 3
)
@@ -0,0 +1,43 @@
package duplicatechecker
import (
"fmt"
"github.com/patrickmn/go-cache"
"github.com/mayswind/ezbookkeeping/pkg/settings"
)
// InMemoryDuplicateChecker represents in-memory duplicate checker
type InMemoryDuplicateChecker struct {
cache *cache.Cache
}
// NewInMemoryDuplicateChecker returns a new in-memory duplicate checker
func NewInMemoryDuplicateChecker(config *settings.Config) (*InMemoryDuplicateChecker, error) {
checker := &InMemoryDuplicateChecker{
cache: cache.New(config.DuplicateSubmissionsIntervalDuration, config.InMemoryDuplicateCheckerCleanupIntervalDuration),
}
return checker, nil
}
// Get returns whether the same submission has been processed and related remark
func (c *InMemoryDuplicateChecker) Get(checkerType DuplicateCheckerType, uid int64, identification string) (bool, string) {
existedRemark, found := c.cache.Get(c.getCacheKey(checkerType, uid, identification))
if found {
return true, existedRemark.(string)
}
return false, ""
}
// Set saves the identification and remark to in-memory cache
func (c *InMemoryDuplicateChecker) Set(checkerType DuplicateCheckerType, uid int64, identification string, remark string) {
c.cache.Set(c.getCacheKey(checkerType, uid, identification), remark, cache.DefaultExpiration)
}
func (c *InMemoryDuplicateChecker) getCacheKey(checkerType DuplicateCheckerType, uid int64, identification string) string {
return fmt.Sprintf("%d|%d|%s", checkerType, uid, identification)
}