-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
212 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
package frigate | ||
|
||
import ( | ||
"slices" | ||
"strings" | ||
"time" | ||
|
||
"github.com/0x2142/frigate-notify/models" | ||
"github.com/rs/zerolog/log" | ||
|
||
"github.com/maypok86/otter" | ||
) | ||
|
||
var zoneCache otter.Cache[string, []string] | ||
|
||
func InitZoneCache() { | ||
var err error | ||
log.Debug().Msg("Setting up zone cache...") | ||
zoneCache, err = otter.MustBuilder[string, []string](500).WithTTL(1 * time.Hour).Build() | ||
if err != nil { | ||
log.Warn(). | ||
Err(err). | ||
Msg("Error setting up zone cache") | ||
} | ||
log.Debug().Msg("Zone cache ready") | ||
} | ||
|
||
func CloseZoneCache() { | ||
log.Debug().Msg("Cache tear down") | ||
zoneCache.Close() | ||
} | ||
|
||
// Add zone to list of zones that have already generated notifications for specified event ID | ||
func setZoneAlerted(event models.Event) { | ||
// Get current list of zones by event ID, if it exists | ||
alreadyAlerted, _ := zoneCache.Get(event.ID) | ||
alreadyAlerted = append(alreadyAlerted, event.CurrentZones...) | ||
// Remove duplicates | ||
slices.Sort(alreadyAlerted) | ||
alreadyAlerted = slices.Compact(alreadyAlerted) | ||
// Update cache with new list | ||
zoneCache.Set(event.ID, alreadyAlerted) | ||
} | ||
|
||
// Query cache to see if zone already generated alert | ||
func zoneAlreadyAlerted(event models.Event) bool { | ||
// Check if event already in cache & if so, get contents | ||
alreadyAlerted, ok := zoneCache.Get(event.ID) | ||
// If event not found, create cache entry & add zones | ||
if !ok { | ||
log.Debug(). | ||
Str("event_id", event.ID). | ||
Str("camera", event.Camera). | ||
Str("zones", strings.Join(event.CurrentZones, ",")). | ||
Msg("Event not in cache, adding...") | ||
setZoneAlerted(event) | ||
return false | ||
} | ||
// If event found, check to see if there are any new zones to notify on | ||
for _, zone := range event.CurrentZones { | ||
if !slices.Contains(alreadyAlerted, zone) { | ||
log.Debug(). | ||
Str("event_id", event.ID). | ||
Str("camera", event.Camera). | ||
Str("zones", strings.Join(event.CurrentZones, ",")). | ||
Msg("Found new zone not in cache") | ||
setZoneAlerted(event) | ||
return false | ||
} | ||
} | ||
// If no new zones, then assume all have been notified already | ||
log.Debug(). | ||
Str("event_id", event.ID). | ||
Str("camera", event.Camera). | ||
Str("zones", strings.Join(event.CurrentZones, ",")). | ||
Msg("All zones in event have already notified") | ||
return true | ||
} | ||
|
||
// Remove zone alert cache for event ID | ||
func delZoneAlerted(event models.Event) { | ||
zoneCache.Delete(event.ID) | ||
log.Debug(). | ||
Str("event_id", event.ID). | ||
Str("camera", event.Camera). | ||
Str("zones", strings.Join(event.CurrentZones, ",")). | ||
Msg("Event removed from cache") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package frigate | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/0x2142/frigate-notify/models" | ||
) | ||
|
||
func TestSetZoneAlerted(t *testing.T) { | ||
// Setup | ||
InitZoneCache() | ||
defer CloseZoneCache() | ||
event := models.Event{ID: "test-event-id", CurrentZones: []string{"test_zone", "test_zone"}} | ||
|
||
setZoneAlerted(event) | ||
|
||
expected := []string{"test_zone"} | ||
result, ok := zoneCache.Get(event.ID) | ||
if !ok { | ||
t.Error("Could not find event ID") | ||
} | ||
|
||
// Check if zone added | ||
if result[0] != expected[0] { | ||
t.Errorf("Expected: %s, Got: %s", expected, result) | ||
} | ||
|
||
// Check if duplicates removed | ||
if len(result) != 1 { | ||
t.Errorf("Expected: %s, Got: %s", expected, result) | ||
} | ||
} | ||
|
||
func TestZoneAlreadyAlerted(t *testing.T) { | ||
// Setup | ||
InitZoneCache() | ||
defer CloseZoneCache() | ||
event := models.Event{ID: "test-event-id", CurrentZones: []string{"test_zone", "test_zone"}} | ||
|
||
// Test new event | ||
result := zoneAlreadyAlerted(event) | ||
if result != false { | ||
t.Errorf("Expected: false, Got: %v", result) | ||
} | ||
|
||
// Test adding new zone to existing event | ||
event.CurrentZones = append(event.CurrentZones, "another_zone") | ||
result = zoneAlreadyAlerted(event) | ||
if result != false { | ||
t.Errorf("Expected: false, Got: %v", result) | ||
} | ||
|
||
// Test event that has already generated alert | ||
result = zoneAlreadyAlerted(event) | ||
if result != true { | ||
t.Errorf("Expected: true, Got: %v", result) | ||
} | ||
} | ||
|
||
func TestDelZoneAlerted(t *testing.T) { | ||
// Setup | ||
InitZoneCache() | ||
defer CloseZoneCache() | ||
event := models.Event{ID: "test-event-id", CurrentZones: []string{"test_zone", "test_zone"}} | ||
|
||
// Create new cache entry | ||
setZoneAlerted(event) | ||
|
||
// Test delete | ||
delZoneAlerted(event) | ||
_, ok := zoneCache.Get(event.ID) | ||
if ok { | ||
t.Errorf("Cache entry not deleted") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters