mirror of
https://github.com/livebook-dev/livebook.git
synced 2025-10-08 12:36:36 +08:00
230 lines
6 KiB
Elixir
230 lines
6 KiB
Elixir
defmodule Livebook.Settings do
|
|
@moduledoc false
|
|
|
|
# Keeps all Livebook settings that are backed by storage.
|
|
|
|
import Ecto.Changeset, only: [apply_action: 2]
|
|
|
|
alias Livebook.FileSystem
|
|
alias Livebook.Storage
|
|
alias Livebook.Settings.EnvVar
|
|
|
|
@typedoc """
|
|
An id that is used for filesystem's manipulation, either insertion or removal.
|
|
"""
|
|
@type file_system_id :: String.t()
|
|
|
|
@doc """
|
|
Returns the current autosave path.
|
|
"""
|
|
@spec autosave_path() :: String.t() | nil
|
|
def autosave_path() do
|
|
case Storage.fetch_key(:settings, "global", :autosave_path) do
|
|
{:ok, value} -> value
|
|
:error -> default_autosave_path()
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
Returns the default autosave path.
|
|
"""
|
|
@spec default_autosave_path() :: String.t()
|
|
def default_autosave_path() do
|
|
Path.join(Livebook.Config.data_path(), "autosaved")
|
|
end
|
|
|
|
@doc """
|
|
Sets the current autosave path.
|
|
"""
|
|
@spec set_autosave_path(String.t()) :: :ok
|
|
def set_autosave_path(autosave_path) do
|
|
Storage.insert(:settings, "global", autosave_path: autosave_path)
|
|
end
|
|
|
|
@doc """
|
|
Restores the default autosave path.
|
|
"""
|
|
@spec reset_autosave_path() :: :ok
|
|
def reset_autosave_path() do
|
|
Storage.delete_key(:settings, "global", :autosave_path)
|
|
end
|
|
|
|
@doc """
|
|
Returns all known filesystems with their associated ids.
|
|
|
|
In case of the local filesystem the id resolves to `"local"`.
|
|
"""
|
|
@spec file_systems() :: [{file_system_id(), Filesystem.t()}]
|
|
def file_systems() do
|
|
restored_file_systems =
|
|
Storage.all(:filesystem)
|
|
|> Enum.sort_by(&Map.get(&1, :order, System.os_time()))
|
|
|> Enum.map(fn %{id: fs_id} = raw_fs ->
|
|
{fs_id, storage_to_fs(raw_fs)}
|
|
end)
|
|
|
|
[{"local", Livebook.Config.local_filesystem()} | restored_file_systems]
|
|
end
|
|
|
|
@doc """
|
|
Saves a new file system to the configured ones.
|
|
"""
|
|
@spec save_filesystem(FileSystem.t()) :: file_system_id()
|
|
def save_filesystem(%FileSystem.S3{} = file_system) do
|
|
attributes =
|
|
file_system
|
|
|> FileSystem.S3.to_config()
|
|
|> Map.to_list()
|
|
|
|
id = Livebook.Utils.random_short_id()
|
|
|
|
:ok =
|
|
Storage.insert(:filesystem, id, [{:type, "s3"}, {:order, System.os_time()} | attributes])
|
|
|
|
id
|
|
end
|
|
|
|
@doc """
|
|
Removes the given file system from the configured ones.
|
|
"""
|
|
@spec remove_file_system(file_system_id()) :: :ok
|
|
def remove_file_system(filesystem_id) do
|
|
Storage.delete(:filesystem, filesystem_id)
|
|
end
|
|
|
|
defp storage_to_fs(%{type: "s3"} = config) do
|
|
case FileSystem.S3.from_config(config) do
|
|
{:ok, fs} -> fs
|
|
{:error, message} -> raise ArgumentError, "invalid S3 filesystem: #{message}"
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
Returns whether the update check is enabled.
|
|
"""
|
|
@spec update_check_enabled?() :: boolean()
|
|
def update_check_enabled?() do
|
|
case Storage.fetch_key(:settings, "global", :update_check_enabled) do
|
|
{:ok, value} -> value
|
|
:error -> true
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
Sets whether the update check is enabled.
|
|
"""
|
|
@spec set_update_check_enabled(boolean()) :: :ok
|
|
def set_update_check_enabled(enabled) do
|
|
Storage.insert(:settings, "global", update_check_enabled: enabled)
|
|
end
|
|
|
|
@doc """
|
|
Gets a list of environment variables from storage.
|
|
"""
|
|
@spec fetch_env_vars() :: list(EnvVar.t())
|
|
def fetch_env_vars do
|
|
for fields <- Storage.all(:env_vars) do
|
|
struct!(EnvVar, Map.delete(fields, :id))
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
Gets one environment variable from storage.
|
|
|
|
Raises `RuntimeError` if the environment variable does not exist.
|
|
"""
|
|
@spec fetch_env_var!(String.t()) :: EnvVar.t()
|
|
def fetch_env_var!(id) do
|
|
fields = Storage.fetch!(:env_vars, id)
|
|
struct!(EnvVar, Map.delete(fields, :id))
|
|
end
|
|
|
|
@doc """
|
|
Checks if environment variable already exists.
|
|
"""
|
|
@spec env_var_exists?(String.t()) :: boolean()
|
|
def env_var_exists?(id) do
|
|
Storage.fetch(:env_vars, id) != :error
|
|
end
|
|
|
|
@doc """
|
|
Sets the given environment variable.
|
|
|
|
With success, notifies interested processes about environment variable
|
|
data change. Otherwise, it will return an error tuple with changeset.
|
|
"""
|
|
@spec set_env_var(EnvVar.t(), map()) ::
|
|
{:ok, EnvVar.t()} | {:error, Ecto.Changeset.t()}
|
|
def set_env_var(%EnvVar{} = env_var \\ %EnvVar{}, attrs) do
|
|
changeset = EnvVar.changeset(env_var, attrs)
|
|
|
|
with {:ok, env_var} <- apply_action(changeset, :insert) do
|
|
save_env_var(env_var)
|
|
end
|
|
end
|
|
|
|
defp save_env_var(env_var) do
|
|
attributes = env_var |> Map.from_struct() |> Map.to_list()
|
|
|
|
with :ok <- Storage.insert(:env_vars, env_var.name, attributes),
|
|
:ok <- broadcast_env_vars_change({:env_var_set, env_var}) do
|
|
{:ok, env_var}
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
Unsets an environment variable from given id.
|
|
|
|
With success, notifies interested processes about environment variable
|
|
deletion. Otherwise, it does nothing.
|
|
"""
|
|
@spec unset_env_var(String.t()) :: :ok
|
|
def unset_env_var(id) do
|
|
if env_var_exists?(id) do
|
|
env_var = fetch_env_var!(id)
|
|
Storage.delete(:env_vars, id)
|
|
broadcast_env_vars_change({:env_var_unset, env_var})
|
|
end
|
|
|
|
:ok
|
|
end
|
|
|
|
@doc """
|
|
Returns an `%Ecto.Changeset{}` for tracking environment variable changes.
|
|
"""
|
|
@spec change_env_var(EnvVar.t(), map()) :: Ecto.Changeset.t()
|
|
def change_env_var(%EnvVar{} = env_var, attrs \\ %{}) do
|
|
env_var
|
|
|> EnvVar.changeset(attrs)
|
|
|> Map.put(:action, :validate)
|
|
end
|
|
|
|
@doc """
|
|
Subscribes to updates in settings information.
|
|
|
|
## Messages
|
|
|
|
* `{:env_var_set, env_var}`
|
|
* `{:env_var_unset, env_var}`
|
|
|
|
"""
|
|
@spec subscribe() :: :ok | {:error, term()}
|
|
def subscribe do
|
|
Phoenix.PubSub.subscribe(Livebook.PubSub, "settings")
|
|
end
|
|
|
|
@doc """
|
|
Unsubscribes from `subscribe/0`.
|
|
"""
|
|
@spec unsubscribe() :: :ok
|
|
def unsubscribe do
|
|
Phoenix.PubSub.unsubscribe(Livebook.PubSub, "settings")
|
|
end
|
|
|
|
# Notifies interested processes about environment variables data change.
|
|
#
|
|
# Broadcasts given message under the `"settings"` topic.
|
|
defp broadcast_env_vars_change(message) do
|
|
Phoenix.PubSub.broadcast(Livebook.PubSub, "settings", message)
|
|
end
|
|
end
|