(local { : split : merge : hash : base64url } (require :anoia)) (local { : mktree : rmtree } (require :anoia.fs)) (local state-directory (assert (os.getenv "SERVICE_STATE"))) (mktree state-directory) (fn write-value [name value] (let [path (.. state-directory "/" name)] (with-open [fout (io.open path :w)] (when value (fout:write value))))) (fn write-value-from-env [name] (write-value name (os.getenv (string.upper name)))) (fn parse-address [str] (fn parse-extra [s] (let [out {}] (each [name val (string.gmatch s ",(.-)=([^,]+)")] (tset out name val)) out)) (let [(address len preferred valid extra) (string.match str "(.-)/(%d+),(%d+),(%d+)(.*)$")] (merge {: address : len :preferred (or preferred "forever") :valid (or valid "forever") } (parse-extra extra)))) (fn write-addresses [prefix addresses] (each [_ a (ipairs (split " " addresses))] (let [address (parse-address a) suffix (base64url (string.pack "n" (hash a))) keydir (.. prefix (-> address.address (: :gsub "::$" "") (: :gsub ":" "-")))] (mktree (.. state-directory "/" keydir)) (each [k v (pairs address)] (write-value (.. keydir "/" k) v))))) ;; we remove state before updating to ensure that consumers don't get ;; a half-updated snapshot (os.remove (.. state-directory "/state")) ;; remove parsed addresses/prefixes from any previous run (rmtree (.. state-directory "/prefix")) (rmtree (.. state-directory "/address")) (let [wanted [ :addresses :aftr :cer :domains :lw406 :mape :mapt :ntp_fqdn :ntp_ip :option_1 :option_2 :option_3 :option_4 :option_5 :passthru :prefixes :ra_addresses :ra_dns :ra_domains :ra_hoplimit :ra_mtu :ra_reachable :ra_retransmit :ra_routes :rdnss :server :sip_domain :sip_ip :sntp_ip :sntp_fqdn ]] (each [_ n (ipairs wanted)] (write-value-from-env n)) (match (os.getenv :ADDRESSES) s (write-addresses "address/" s)) (match (os.getenv :PREFIXES) s (write-addresses "prefix/" s))) (let [[ifname state] arg ready (match state "started" false "unbound" false "stopped" false _ true)] (write-value ".lock" (tostring (os.time))) (write-value "ifname" ifname) (write-value "state" state) (os.remove (.. state-directory "/.lock")) (when ready (with-open [fd (io.open "/proc/self/fd/10" :w)] (fd:write "\n"))))