def "job recv pending" []: nothing -> list { "marker" | job send (job id) # send a marker to self mut events = [] mut ev = job recv # marker will prevent wait here while $ev != "marker" { $events = $events | append $ev $ev = job recv } $events } # may wait up to two intervals, because event timestamps are not accounted def create-debounce-queue [interval: duration, handler: closure] { job spawn -d "debounce queue" { mut event = job recv loop { sleep $interval let new_events = job recv pending if ($new_events | is-empty) { do $handler $event $event = job recv } else { $event = ($new_events | last) } } } } def single [] { let $data = $in if ($data | length) != 1 { make error "Expected single element" } $data | first } def parse-nft-mon-event [] { mut rest = $in mut result = {} for key_name in ['action', 'type'] { let key = $rest | items {|k, v| $k} | single $rest = $rest | get $key $result = $result | insert $key_name $key } $result | merge $rest } def main [--test] { let debounce_interval = 2sec let debounce_queue = create-debounce-queue $debounce_interval {|ev| print "Triggered" $ev # nu update-netbird-nftables.nu --apply } try { if $test { nu test-data/mock-nft-mon.nu } else { ^nft --json monitor rules } | lines | each { from json | parse-nft-mon-event } | where action == add and type == rule and table == netbird # TODO filter update evenets | each { job send $debounce_queue } | ignore print "Exiting gracefully..." sleep $debounce_interval sleep $debounce_interval } catch { |e| print $e.rendered } finally { job kill $debounce_queue } }