aboutsummaryrefslogtreecommitdiff
path: root/api/nft-event-listener.nu
blob: 0554c6fc5e592f159418a47132975ac7af7c0e75 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
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
    }
}