diff --git a/src/musicplayer.gleam b/src/musicplayer.gleam index 0d33896..e243b09 100644 --- a/src/musicplayer.gleam +++ b/src/musicplayer.gleam @@ -8,15 +8,14 @@ import musicplayer/musicplayer import musicplayer/ui/ui pub fn main() -> Nil { - let assert Ok(logger) = logging.new("/tmp/musicplayer.log") + let assert Ok(_) = logging.initialize() let input_keys_name: Name(Key) = process.new_name("input_keys") input.new(input_keys_name) - let assert Ok(ui) = ui.new(logger) + let assert Ok(ui) = ui.new() let assert Ok(mpv) = mpv.new() - let assert Ok(musicplayer_pid) = - musicplayer.new(logger, ui, mpv, input_keys_name) + let assert Ok(musicplayer_pid) = musicplayer.new(ui, mpv, input_keys_name) let monitor = process.monitor(musicplayer_pid) process.new_selector() diff --git a/src/musicplayer/logging/control.gleam b/src/musicplayer/logging/control.gleam index 00a1220..5722b6b 100644 --- a/src/musicplayer/logging/control.gleam +++ b/src/musicplayer/logging/control.gleam @@ -1,7 +1,5 @@ -import gleam/erlang/process.{type Subject} - pub type Control { Write(String) - Exit(reply_to: Subject(Nil)) + Exit } diff --git a/src/musicplayer/logging/logging.gleam b/src/musicplayer/logging/logging.gleam index 26687c8..1d7b8d4 100644 --- a/src/musicplayer/logging/logging.gleam +++ b/src/musicplayer/logging/logging.gleam @@ -1,58 +1,30 @@ -import gleam/erlang/process.{type Subject} -import gleam/otp/actor import gleam/result import gleam/string import gleam/time/calendar import gleam/time/timestamp import simplifile -import musicplayer/logging/control.{type Control} +const filepath = "/tmp/musicplayer.log" -type State { - State(filepath: String) -} - -pub fn new(filepath: String) -> Result(Subject(Control), String) { - use _ <- result.try( - case simplifile.is_file(filepath) { - Ok(True) -> Ok(Nil) - _ -> simplifile.create_file(filepath) - } - |> result.map_error(fn(e) { - "Could not access or create log file: " <> string.inspect(e) - }), - ) - - actor.new(State(filepath:)) - |> actor.on_message(handle_message) - |> actor.start - |> result.map_error(fn(start_error) { - "Could not start logger: " <> string.inspect(start_error) - }) - |> result.map(fn(started) { started.data }) -} - -fn handle_message(state: State, control: Control) -> actor.Next(State, Control) { - case control { - control.Write(content) -> { - let log_line = - timestamp.system_time() - |> timestamp.to_rfc3339(calendar.utc_offset) - <> ": " - <> content - <> "\n" - - // Ignore any logging errors - let _ = simplifile.append(state.filepath, log_line) - actor.continue(state) - } - control.Exit(reply_to) -> { - process.send(reply_to, Nil) - actor.stop() - } +pub fn initialize() -> Result(Nil, String) { + case simplifile.is_file(filepath) { + Ok(True) -> Ok(Nil) + _ -> simplifile.create_file(filepath) } + |> result.map_error(fn(e) { + "Could not access or create log file: " <> string.inspect(e) + }) } -pub fn log(logger: Subject(Control), content: String) -> Nil { - process.send(logger, control.Write(content)) +pub fn log(content: String) -> Nil { + let log_line = + timestamp.system_time() + |> timestamp.to_rfc3339(calendar.utc_offset) + <> ": " + <> content + <> "\n" + + // Ignore any logging errors + let _ = simplifile.append(filepath, log_line) + Nil } diff --git a/src/musicplayer/musicplayer.gleam b/src/musicplayer/musicplayer.gleam index 65c8bfa..266b45b 100644 --- a/src/musicplayer/musicplayer.gleam +++ b/src/musicplayer/musicplayer.gleam @@ -5,7 +5,6 @@ import gleam/string import musicplayer/control.{type Control} import musicplayer/input/key.{type Key} -import musicplayer/logging/control as logging_control import musicplayer/logging/logging import musicplayer/mpv/control as mpv_control import musicplayer/time/time @@ -25,14 +24,12 @@ type State { State( mode: Mode, input: Input, - logger: Subject(logging_control.Control), ui: Subject(ui_control.Control), mpv: Subject(mpv_control.Control), ) } pub fn new( - logger: Subject(logging_control.Control), ui: Subject(ui_control.Control), mpv: Subject(mpv_control.Control), input_keys_name: Name(Key), @@ -42,14 +39,14 @@ pub fn new( let input = Input(False, "") case - actor.new(State(Idle, input, logger, ui, mpv)) + actor.new(State(Idle, input, ui, mpv)) |> actor.on_message(handle_message) |> actor.start { Error(start_error) -> Error("Could not start actor: " <> string.inspect(start_error)) Ok(actor.Started(pid:, data: musicplayer)) -> { - logging.log(logger, "musicplayer - started") + logging.log("musicplayer - started") process.spawn(fn() { let assert Ok(_) = process.register(process.self(), input_keys_name) handle_key(musicplayer, input_keys) @@ -65,7 +62,7 @@ pub fn new( fn handle_message(state: State, control: Control) -> actor.Next(State, Control) { case control { control.Search -> { - logging.log(state.logger, "musicplayer - initiating search") + logging.log("musicplayer - initiating search") update_search(state.ui, "searching: ") @@ -79,7 +76,7 @@ fn handle_message(state: State, control: Control) -> actor.Next(State, Control) } control.Raw(content) -> { - logging.log(state.logger, "musicplayer - recieved raw input: " <> content) + logging.log("musicplayer - recieved raw input: " <> content) let content = case state.mode { Idle -> state.input.content @@ -93,7 +90,7 @@ fn handle_message(state: State, control: Control) -> actor.Next(State, Control) actor.continue(State(..state, input: Input(..state.input, content:))) } control.Backspace -> { - logging.log(state.logger, "musicplayer - recieved backspace") + logging.log("musicplayer - recieved backspace") let content = case state.mode { Idle -> state.input.content @@ -103,11 +100,10 @@ fn handle_message(state: State, control: Control) -> actor.Next(State, Control) } control.Return -> { logging.log( - state.logger, "musicplayer - recieved return. `input.capture`: " - <> "'" - <> state.input.content - <> "'", + <> "'" + <> state.input.content + <> "'", ) // Note: state.input.content is now the final input, use it @@ -123,26 +119,21 @@ fn handle_message(state: State, control: Control) -> actor.Next(State, Control) } control.TogglePlayPause -> { - logging.log(state.logger, "musicplayer - toggling play/pause") + logging.log("musicplayer - toggling play/pause") process.send(state.mpv, mpv_control.TogglePlayPause) update_playback_time(state.mpv, state.ui) actor.continue(state) } control.Exit -> { - logging.log(state.logger, "musicplayer - initiating musicplayer shutdown") + logging.log("musicplayer - initiating musicplayer shutdown") // Close `mpv` socket process.call(state.mpv, 1000, fn(reply_to) { mpv_control.Exit(reply_to) }) // Reset terminal state (show cursor etc.) process.call(state.ui, 1000, fn(reply_to) { ui_control.Exit(reply_to) }) - logging.log(state.logger, "musicplayer - stopped") - - // Close logger (NOOP) - process.call(state.logger, 1000, fn(reply_to) { - logging_control.Exit(reply_to) - }) + logging.log("musicplayer - stopped") actor.stop() } diff --git a/src/musicplayer/ui/ui.gleam b/src/musicplayer/ui/ui.gleam index 0f8a9a7..80765c3 100644 --- a/src/musicplayer/ui/ui.gleam +++ b/src/musicplayer/ui/ui.gleam @@ -5,30 +5,23 @@ import gleam/list import gleam/otp/actor import gleam/string -import musicplayer/logging/control as logging_control import musicplayer/logging/logging import musicplayer/ui/control.{type Control} import musicplayer/ui/internal as ui_internal import musicplayer/ui/layout.{type Layout, type Section} pub type State(redraw, content) { - State( - logger: Subject(logging_control.Control), - redraw: Subject(Layout), - layout: Layout, - ) + State(redraw: Subject(Layout), layout: Layout) } -pub fn new( - logger: Subject(logging_control.Control), -) -> Result(Subject(Control), String) { +pub fn new() -> Result(Subject(Control), String) { let redraw_name = process.new_name("redraw") let redraw: Subject(Layout) = process.named_subject(redraw_name) let layout = layout.new() case - actor.new(State(logger, redraw, layout)) + actor.new(State(redraw, layout)) |> actor.on_message(handle_message) |> actor.start { @@ -37,7 +30,7 @@ pub fn new( Ok(actor.Started(data: ui, ..)) -> { process.spawn(fn() { let update_dimensions_interval_ms = 300 - update_dimensions_on_interval(logger, ui, update_dimensions_interval_ms) + update_dimensions_on_interval(ui, update_dimensions_interval_ms) }) process.spawn(fn() { @@ -69,7 +62,7 @@ fn handle_message( |> list.map(int.to_string) |> string.join(" ") |> string.append("ui - updating dimensions: ", _) - |> logging.log(state.logger, _) + |> logging.log actor.continue( State( @@ -105,20 +98,16 @@ fn redraw_on_update_loop(redraw: Subject(Layout)) -> Nil { redraw_on_update_loop(redraw) } -fn update_dimensions_on_interval( - logger: Subject(logging_control.Control), - ui: Subject(Control), - interval_ms: Int, -) { +fn update_dimensions_on_interval(ui: Subject(Control), interval_ms: Int) { case ui_internal.io_get_columns(), ui_internal.io_get_rows() { Ok(width), Ok(height) -> { process.send(ui, control.UpdateDimensions(width, height)) } - _, _ -> logging.log(logger, "ui - failed to update dimensions") + _, _ -> logging.log("ui - failed to update dimensions") } process.sleep(interval_ms) - update_dimensions_on_interval(logger, ui, interval_ms) + update_dimensions_on_interval(ui, interval_ms) } fn render_layout(layout: Layout, from: Section) -> Nil {