"#stream.spl" import "#time.spl" import "#json.spl" import def state, network, connections [ ^bring-up ] =state "johlg" =network 6 =connections include json:_StringyJSON in array func panic-handler { | catch IO { "status" StreamTypes:file:create<1> dup :write-exact<[ ^dead [ ^panic ] ] :sjson<0> "\n" concat :to-bytes> :close; } { with e ; "fuck."; } } func main { exitcode | with args ; start-timer =>? ^ok not if { "error " print :sjson<0> print " in state: " state:sjson<0> concat println "error in timers" panic } 0 } func start-timer { result | def sa time:unixms =sa 1 while { } { 1000 time:unixms sa - - dup 0 lt if { pop 0 } time:sleep; time:unixms =sa def v timer-run dup :sjson<0> dup println =v catch IO { "status" StreamTypes:file:create<1> dup :write-exact :close; } { [ ^err "no fs access" "status" ] 3 stop } dup => [ ^reboot &=v ] if { "" println "reboot requested because " v concat "." concat println catch IO { "deny-reboot" read-file "no" eq not if { "reboot denied because deny-reboot is set. need manual help" pop [ ^err "reboot denied" ] 3 stop } } { pop } catch IO { "deny-reboot" StreamTypes:file:create<1> dup :write-exact<"yes" :to-bytes> :close; } { [ ^err "no fs access" "deny-reboot" ] 3 stop } while { 1 } { fork<| "status" StreamTypes:file:create<1> dup :write-exact<[ ^dead v ] :sjson<0> "\n" concat :to-bytes> :close; catch { [ "sudo" "reboot" ] command-wait; } { pop } > 5000 time:sleep; } } =>? [ ^ok &pop ] } } func timer-run { result | def wait-time device-present not if { [ ^reboot "device not present" ] 2 stop } state => [ ^fix-device ] if { fix-device 2 stop } state => [ ^bring-up ] if { switch-networks =>? [ ^err "nmcli failed" ] if { [ ^fix-device ] =state [ ^ok state ] 3 stop } dup => [ ^ok &pop ] if { 3 stop } } is-network-up not if { [ ^bring-up ] =state [ ^ok state ] 2 stop } state => [ ^waiting &=wait-time ] if { wait-time 0 eq if { [ ^bring-up ] =state [ ^ok state ] 3 stop } [ ^waiting wait-time 1 - ] =state [ ^ok state ] 2 stop } state => [ ^connecting &=wait-time ] if { is-network-up if { [ ^waiting 60 20 * ] =state catch IO { "deny-reboot" StreamTypes:file:create<1> dup :write-exact<"no" :to-bytes> :close; } { [ ^err "no fs access" "deny-reboot" ] 4 stop } [ ^ok ^connected ] 3 stop } wait-time 0 eq if { [ ^bring-up ] =state [ ^ok state ] 3 stop } [ ^connecting wait-time -- ] =state [ ^ok state ] 2 stop } [ ^err "unknown state" state ] } func switch-networks { result | [ ^connecting 10 ] =state def b random-byte =>? [ ^ok &=b ] not if { 2 stop } b connections % =b def conn, hostname network b _str concat =conn conn "-hostname" concat read-file :replace<"\n" ""> =hostname "connecting to " conn concat " with hostname " concat hostname concat println [ "sudo" "hostnamectl" "set-hostname" hostname ] command-wait [ "sudo" "nmcli" "c" "up" conn ] command-wait or if { [ ^err "nmcli failed" ] 2 stop } [ ^ok ^connected ] } func device-present { bool | [ "lsusb" ] StreamTypes:cmd:create dup :read-to-end<1024>:to-str dup :contains<"0bda:c811"> swap:contains<"0bda:1a2b"> or swap :close } func fix-device { result | [ ^bring-up ] =state [ "sudo" "usb_modeswitch" "-v" "0bda" "-p" "1a2b" "-K" ] command-wait; [ ^ok ^fixing-device ] } func is-network-up { | def done 0 =done fork<| 1000 time:sleep; done not if { "ping unsuccessful" println [ "killall" "ping" ] command-wait; } > [ "ping" "-c" "1" "1.1.1.1" ] command-wait 0 _int eq 1 =done } func random-byte { [result,byte] | catch IO { def b "/dev/urandom" StreamTypes:file:create<0> dup :read-one =b :close; [ ^ok b ] } { with err ; [ ^err err ] } }