1
1
mirror of https://github.com/NixOS/mobile-nixos.git synced 2024-12-17 04:51:31 +03:00
mobile-nixos/boot/init/lib/progress.rb
Samuel Dionne-Riel a819a8930e boot/init: Cleanup failure
- exit after everything happened, just in case
 - exit the progress display
 - allow a custom delay to be set
2020-11-07 20:13:31 -05:00

125 lines
3.0 KiB
Ruby

# Progress-reporting plumbing
module Progress
SOCKET_PREFIX = "/run/mobile-nixos-init"
# Starts the queue sockets.
# This is waiting for /run/ to be available.
# It needs to be possible to let some consumers (e.g. splash) alive from
# stage-1 and waiting for fresh messages from stage-2.
# A stage-2 process could ask that splash to "hand-off" to a stage-2 splash.
def self.start()
@progress = 0
$logger.debug("Starting progress IPC through ZeroMQ")
$logger.debug(" -> messages: #{SOCKET_PREFIX}")
@messages_socket = ZMQ::Pub.new("ipc://#{SOCKET_PREFIX}-messages")
$logger.debug(" -> replies: #{SOCKET_PREFIX}")
@replies_socket = ZMQ::Sub.new("ipc://#{SOCKET_PREFIX}-replies", "")
end
# Given values (in a Hash), it will update the state with them, and send the
# updated state to the messages queue.
# +nil+ values are compacted out of the state.
def self.update(values)
@state ||= {}
@state.merge!(values).compact!
send_state()
end
# Get a specific value from the state.
# This should be done as little as possible.
def self.get(attr)
@state ||= {}
@state[attr]
end
# See +#get+
def self.[](name)
get(name)
end
# Send the current state over the messages socket.
def self.send_state()
msg = @state.to_json
if @messages_socket
$logger.debug("[send] #{msg}")
@messages_socket.send(msg)
else
$logger.debug("[send] Socket not open yet.")
$logger.debug("[send] Couldn't send: #{msg}")
end
end
# Executes the given block, showing the message beforehand, and removing the
# message once done.
def self.exec_with_message(label)
previous = get(:label)
update({label: label})
ret = yield
update({label: previous})
ret
end
def self.ask(placeholder, label: nil)
identifier = "0x#{Random.rand(0xFFFFF).to_s(16)}"
previous_label = get(:label)
Progress.update({label: label}) if label
update(command: {
name: "ask",
identifier: identifier,
placeholder: placeholder,
})
value = loop do
# Keep progress state updated for processes attaching late.
send_state()
value =
each_replies do |reply|
# A reply for the current question?
if reply and reply["type"] == "reply" and reply["identifier"] == identifier
break reply["value"]
else
nil
end
end
break value if value
# Leave some breathing room to the CPU!
sleep(0.1)
end
update({label: previous_label})
value
end
def self.kill()
Tasks::Splash.instance.kill()
end
# Read one reply
# If none are available, returns nil
def self.read_reply()
begin
msg = @replies_socket.recv(LibZMQ::DONTWAIT).to_str
$logger.debug("[recv] #{msg}")
JSON.parse(msg)
rescue Errno::EWOULDBLOCK
# No message?
nil
end
end
# Reads replies until there are none
def self.each_replies()
loop do
msg = read_reply
break unless msg
yield msg
end
end
end