Cybersecurity-Projects/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/tui/snapshotter.cr

70 lines
1.6 KiB
Crystal

# ===================
# ©AngelaMos | 2026
# snapshotter.cr
# ===================
require "log"
require "./state"
require "../persistence/persistence"
require "../policy/policy"
module CRE::Tui
# Snapshotter polls the persistence layer at a low frequency and updates
# State#creds_total / due_now / overdue. The TUI render path reads the
# cached snapshot, never the database — so a slow query can't stall
# frame paint.
class Snapshotter
Log = ::Log.for("cre.tui.snapshotter")
@running : Bool
def initialize(
@state : State,
@persistence : Persistence::Persistence,
@policies : Array(Policy::Policy) = Policy.registry,
@interval : Time::Span = 5.seconds,
)
@running = false
end
def start : Nil
@running = true
spawn(name: "tui-snapshotter") do
refresh
while @running
sleep @interval
break unless @running
refresh
end
end
end
def stop : Nil
@running = false
end
def refresh : Nil
now = Time.utc
creds = @persistence.credentials.all
total = creds.size
due_now = 0
overdue = 0
creds.each do |c|
matching = @policies.select(&.matches?(c))
next if matching.empty?
policy = matching.last
if policy.overdue?(c, now)
overdue += 1
elsif policy.in_warning_window?(c, now)
due_now += 1
end
end
@state.update_counts(total, due_now, overdue)
rescue ex
Log.warn(exception: ex) { "tui snapshot refresh failed" }
end
end
end