Packages

Terminal emulation and driver infrastructure for Raxol. ANSI parsing, screen buffers, command processing, cursor management, input handling, session management, and termbox2 NIF integration.

Current section

Files

Jump to
raxol_terminal lib raxol terminal session_manager persistence.ex
Raw

lib/raxol/terminal/session_manager/persistence.ex

defmodule Raxol.Terminal.SessionManager.Persistence do
@moduledoc """
Session persistence: save/restore sessions to/from disk.
"""
alias Raxol.Core.Runtime.Log
@doc """
Initializes the persistence manager with a directory path.
"""
def init(persistence_dir) do
%{directory: persistence_dir, enabled: true}
end
@doc """
Saves a session to disk if persistence is enabled.
"""
def save_session(_session, %{enabled: false}), do: :ok
def save_session(session, %{enabled: true, directory: dir}) do
filename = Path.join(dir, "#{session.id}.session")
data = serialize(session)
File.write(filename, data)
end
@doc """
Restores all persisted sessions from disk.
Returns a map of session_id => session.
"""
def restore_all(false, _state), do: %{}
def restore_all(true, state) do
persistence_dir = state.config.persistence_directory |> Path.expand()
case File.ls(persistence_dir) do
{:ok, files} ->
files
|> Enum.filter(&String.ends_with?(&1, ".session"))
|> Enum.reduce(%{}, fn file, acc ->
file_path = Path.join(persistence_dir, file)
case restore_from_file(file_path) do
{:ok, session} -> Map.put(acc, session.id, session)
{:error, _reason} -> acc
end
end)
{:error, reason} ->
Log.warning("Could not list persistence directory: #{inspect(reason)}")
%{}
end
end
@doc """
Restores a single session from a file path.
"""
def restore_from_file(file) do
with {:ok, data} <- File.read(file),
{:ok, session} <- deserialize(data) do
Log.info("Restored session '#{session.name}' from #{file}")
{:ok, session}
else
{:error, reason} ->
Log.warning("Failed to restore session from #{file}: #{inspect(reason)}")
{:error, reason}
end
end
defp serialize(session) do
session
|> Map.from_struct()
|> :erlang.term_to_binary()
end
defp deserialize(data) do
case Raxol.Core.ErrorHandling.safe_call(fn ->
session_map = :erlang.binary_to_term(data, [:safe])
struct(Raxol.Terminal.SessionManager.Session, session_map)
end) do
{:ok, session} -> {:ok, session}
{:error, reason} -> {:error, reason}
end
end
end