aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dedupe.go18
-rw-r--r--dedupe_test.go61
2 files changed, 75 insertions, 4 deletions
diff --git a/dedupe.go b/dedupe.go
index 2b103b8..97934e0 100644
--- a/dedupe.go
+++ b/dedupe.go
@@ -8,13 +8,17 @@ import (
"time"
)
+// PacketDeduplicator is a structure that prevents processing of duplicate packets.
+// It keeps a record of seen packets and the time they were last seen.
type PacketDeduplicator struct {
- hasher hash.Hash
- expiresAfter time.Duration
- sync.RWMutex
- seen map[string]time.Time
+ hasher hash.Hash // hasher is used for generating packet identifiers.
+ expiresAfter time.Duration // expiresAfter defines the duration after which a seen packet record expires.
+ sync.RWMutex // RWMutex is used to protect the seen map from concurrent access.
+ seen map[string]time.Time // seen maps a packet identifier to the last time it was seen.
}
+// NewDeduplicator creates a new PacketDeduplicator with a given hasher and expiration duration for packet records.
+// It starts a background goroutine to periodically clean up expired packet records.
func NewDeduplicator(hasher hash.Hash, expiresAfter time.Duration) *PacketDeduplicator {
pd := PacketDeduplicator{
seen: make(map[string]time.Time),
@@ -36,6 +40,9 @@ func NewDeduplicator(hasher hash.Hash, expiresAfter time.Duration) *PacketDedupl
return &pd
}
+
+// Seen checks whether a packet with the given sender and packetID has been seen before.
+// If not, it records the packet as seen and returns false. Otherwise, it returns true.
func (p *PacketDeduplicator) Seen(sender, packetID uint32) bool {
asString := fmt.Sprintf("%d-%d", sender, packetID)
p.RLock()
@@ -49,6 +56,9 @@ func (p *PacketDeduplicator) Seen(sender, packetID uint32) bool {
p.RUnlock()
return true
}
+
+// SeenData checks whether the data has been seen before based on its hashed value.
+// If not, it records the data as seen and returns false. Otherwise, it returns true.
func (p *PacketDeduplicator) SeenData(data []byte) bool {
hashed := p.hasher.Sum(data)
asHex := hex.EncodeToString(hashed)
diff --git a/dedupe_test.go b/dedupe_test.go
new file mode 100644
index 0000000..6388360
--- /dev/null
+++ b/dedupe_test.go
@@ -0,0 +1,61 @@
+package meshtastic_test
+
+import (
+ "crypto/md5"
+ "github.com/crypto-smoke/meshtastic-go"
+ "testing"
+ "time"
+)
+
+func TestPacketDeduplicatorSeen(t *testing.T) {
+ hasher := md5.New()
+ expiresAfter := 100 * time.Millisecond
+ dedup := meshtastic.NewDeduplicator(hasher, expiresAfter)
+
+ sender := uint32(1)
+ packetID := uint32(1)
+
+ // Test Seen with new packetID
+ if dedup.Seen(sender, packetID) {
+ t.Error("Expected the packet to not have been seen")
+ }
+
+ // Test Seen with same packetID again
+ if !dedup.Seen(sender, packetID) {
+ t.Error("Expected the packet to have been seen")
+ }
+
+ // Wait for expiration
+ time.Sleep(expiresAfter + 100*time.Millisecond)
+
+ // Test Seen with same packetID after expiration
+ if dedup.Seen(sender, packetID) {
+ t.Error("Expected the packet to not have been seen after expiration")
+ }
+}
+
+func TestPacketDeduplicatorSeenData(t *testing.T) {
+ hasher := md5.New()
+ expiresAfter := 100 * time.Millisecond
+ dedup := meshtastic.NewDeduplicator(hasher, expiresAfter)
+
+ data := []byte("test data")
+
+ // Test SeenData with new data
+ if dedup.SeenData(data) {
+ t.Error("Expected the data to not have been seen")
+ }
+
+ // Test SeenData with same data again
+ if !dedup.SeenData(data) {
+ t.Error("Expected the data to have been seen")
+ }
+
+ // Wait for expiration
+ time.Sleep(expiresAfter + 100*time.Millisecond)
+
+ // Test SeenData with same data after expiration
+ if dedup.SeenData(data) {
+ t.Error("Expected the data to not have been seen after expiration")
+ }
+}