import gleam/erlang/process.{type Subject} import gleam/float import gleam/otp/actor import gleam/result import gleam/string import input/key import mpv/control.{type Control} import tcp/reason import tcp/tcp.{type Socket} type State(socket, exit) { State(socket: Socket, exit: Subject(Nil)) } pub fn new(exit: Subject(Nil)) -> Result(Nil, String) { // TODO start up mvp here, currently hi-jacking `naviterm`s socket let socket_path = "/tmp/naviterm_mpv" case tcp.connect(socket_path) { Error(r) -> Error("Could not connect to mpv: " <> reason.to_string(r)) Ok(socket) -> { case actor.new(State(socket, exit)) |> actor.on_message(handle_message) |> actor.start { Error(start_error) -> Error("Could not start actor: " <> string.inspect(start_error)) Ok(actor.Started(data:, ..)) -> { echo "waiting for input" key.start_raw_shell() let input = process.new_subject() process.self() process.receive process.spawn(fn() { input_handler(input, data) }) process.spawn(fn() { read_input(data) }) Ok(Nil) } } } } } fn handle_message( state: State(socket, exit), control: Control, ) -> actor.Next(State(socket, exit), Control) { case control { control.Search -> todo control.TogglePlayPause -> { echo "toggling play/pause" let _ = result.map_error(control.toggle_play_pause(state.socket), fn(err) { echo "Could not toggle play/pause: " <> err.details }) let _ = result.map(control.get_playback_time(state.socket), fn(playback) { echo "playback: " <> float.to_string(playback.data) }) actor.continue(state) } control.Exit -> { process.send(state.exit, Nil) actor.stop() } } } // TODO create new input_handler_loop that recieves on a subject and // TODO read_input reads until a key is found, and then sends it to // TODO a function that can recieve on a subject, and it can receive two types of messages: // 1. a Control message from read_input // 2. an injected controlMessage with pre-defined buffer // it then forwards the message to the actor subject fn read_input(input_handler: Subject(Control)) -> Nil { case key.read_input_until_key([]) |> control.from_key { Error(_) -> Nil Ok(control) -> process.send(input_handler, control) } read_input(input_handler) } fn input_handler( input: Subject(Control), actor_subject: Subject(Control), ) -> Nil { case process.receive(input, 1000) { Error(_) -> Nil Ok(control) -> process.send(actor_subject, control) } }