aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/mix/pleroma.ex22
-rw-r--r--lib/pleroma/application.ex163
-rw-r--r--lib/pleroma/application/dynamic_supervisor.ex178
-rw-r--r--lib/pleroma/application/hackney_pool_supervisor.ex30
-rw-r--r--lib/pleroma/application/requirements.ex (renamed from lib/pleroma/application_requirements.ex)2
-rw-r--r--lib/pleroma/application/static.ex77
-rw-r--r--lib/pleroma/config/config_db.ex25
-rw-r--r--lib/pleroma/config/environment.ex103
-rw-r--r--lib/pleroma/config/loader.ex8
-rw-r--r--lib/pleroma/config/transfer_task.ex201
-rw-r--r--lib/pleroma/web/admin_api/controllers/admin_api_controller.ex4
-rw-r--r--lib/pleroma/web/admin_api/controllers/config_controller.ex16
12 files changed, 456 insertions, 373 deletions
diff --git a/lib/mix/pleroma.ex b/lib/mix/pleroma.ex
index 49ba2aae4..7c5322ffe 100644
--- a/lib/mix/pleroma.ex
+++ b/lib/mix/pleroma.ex
@@ -39,31 +39,23 @@ defmodule Mix.Pleroma do
children =
[
Pleroma.Repo,
- {Pleroma.Config.TransferTask, false},
+ %{
+ id: :env_updater,
+ start: {Task, :start_link, [&Pleroma.Config.Environment.load_and_update/0]},
+ restart: :temporary
+ },
Pleroma.Web.Endpoint,
{Oban, Pleroma.Config.get(Oban)}
] ++
http_children(adapter)
- cachex_children = Enum.map(@cachex_children, &Pleroma.Application.build_cachex(&1, []))
+ cachex_children =
+ Enum.map(@cachex_children, &Pleroma.Application.Static.build_cachex({&1, []}))
Supervisor.start_link(children ++ cachex_children,
strategy: :one_for_one,
name: Pleroma.Supervisor
)
-
- if Pleroma.Config.get(:env) not in [:test, :benchmark] do
- pleroma_rebooted?()
- end
- end
-
- defp pleroma_rebooted? do
- if Restarter.Pleroma.rebooted?() do
- :ok
- else
- Process.sleep(10)
- pleroma_rebooted?()
- end
end
def load_pleroma do
diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex
index 00ec79a2a..27ed91554 100644
--- a/lib/pleroma/application.ex
+++ b/lib/pleroma/application.ex
@@ -5,8 +5,6 @@
defmodule Pleroma.Application do
use Application
- import Cachex.Spec
-
alias Pleroma.Config
require Logger
@@ -16,6 +14,8 @@ defmodule Pleroma.Application do
@repository Mix.Project.config()[:source_url]
@env Mix.env()
+ @type env() :: :test | :benchmark | :dev | :prod
+
def name, do: @name
def version, do: @version
def named_version, do: @name <> " " <> @version
@@ -53,15 +53,13 @@ defmodule Pleroma.Application do
Pleroma.Config.Oban.warn()
Config.DeprecationWarnings.warn()
Pleroma.Plugs.HTTPSecurityPlug.warn_if_disabled()
- Pleroma.ApplicationRequirements.verify!()
+ Pleroma.Application.Requirements.verify!()
setup_instrumenters()
load_custom_modules()
check_system_commands()
Pleroma.Docs.JSON.compile()
- adapter = Application.get_env(:tesla, :adapter)
-
- if adapter == Tesla.Adapter.Gun do
+ if Application.get_env(:tesla, :adapter) == Tesla.Adapter.Gun do
if version = Pleroma.OTPVersion.version() do
[major, minor] =
version
@@ -84,32 +82,32 @@ defmodule Pleroma.Application do
end
# Define workers and child supervisors to be supervised
- children =
- [
- Pleroma.Repo,
- Config.TransferTask,
- Pleroma.Emoji,
- Pleroma.Plugs.RateLimiter.Supervisor
- ] ++
- cachex_children() ++
- http_children(adapter, @env) ++
- [
- Pleroma.Stats,
- Pleroma.JobQueueMonitor,
- {Oban, Config.get(Oban)}
- ] ++
- task_children(@env) ++
- dont_run_in_test(@env) ++
- chat_child(@env, chat_enabled?()) ++
- [
- Pleroma.Web.Endpoint,
- Pleroma.Gopher.Server
- ]
+ children = [
+ Pleroma.Repo,
+ Pleroma.Application.DynamicSupervisor,
+ {Registry, keys: :duplicate, name: Pleroma.Application.DynamicSupervisor.registry()}
+ ]
# See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
# for other strategies and supported options
- opts = [strategy: :one_for_one, name: Pleroma.Supervisor]
- Supervisor.start_link(children, opts)
+ Supervisor.start_link(children, strategy: :one_for_one, name: Pleroma.Supervisor)
+ end
+
+ def start_phase(:update_env, :normal, _args) do
+ # Load and update the environment from the config settings in the database
+ Pleroma.Config.Environment.load_and_update()
+ end
+
+ def start_phase(:static_children, :normal, _args) do
+ # Start static children,
+ # which don't require any configuration or can be configured in runtime
+ Pleroma.Application.Static.start_children(@env)
+ end
+
+ def start_phase(:dynamic_children, :normal, _args) do
+ # Start dynamic children,
+ # which require restart after some config changes
+ Pleroma.Application.DynamicSupervisor.start_children(@env)
end
def load_custom_modules do
@@ -154,113 +152,6 @@ defmodule Pleroma.Application do
Pleroma.Web.Endpoint.Instrumenter.setup()
end
- defp cachex_children do
- [
- build_cachex("used_captcha", ttl_interval: seconds_valid_interval()),
- build_cachex("user", default_ttl: 25_000, ttl_interval: 1000, limit: 2500),
- build_cachex("object", default_ttl: 25_000, ttl_interval: 1000, limit: 2500),
- build_cachex("rich_media", default_ttl: :timer.minutes(120), limit: 5000),
- build_cachex("scrubber", limit: 2500),
- build_cachex("idempotency", expiration: idempotency_expiration(), limit: 2500),
- build_cachex("web_resp", limit: 2500),
- build_cachex("emoji_packs", expiration: emoji_packs_expiration(), limit: 10),
- build_cachex("failed_proxy_url", limit: 2500),
- build_cachex("banned_urls", default_ttl: :timer.hours(24 * 30), limit: 5_000)
- ]
- end
-
- defp emoji_packs_expiration,
- do: expiration(default: :timer.seconds(5 * 60), interval: :timer.seconds(60))
-
- defp idempotency_expiration,
- do: expiration(default: :timer.seconds(6 * 60 * 60), interval: :timer.seconds(60))
-
- defp seconds_valid_interval,
- do: :timer.seconds(Config.get!([Pleroma.Captcha, :seconds_valid]))
-
- @spec build_cachex(String.t(), keyword()) :: map()
- def build_cachex(type, opts),
- do: %{
- id: String.to_atom("cachex_" <> type),
- start: {Cachex, :start_link, [String.to_atom(type <> "_cache"), opts]},
- type: :worker
- }
-
- defp chat_enabled?, do: Config.get([:chat, :enabled])
-
- defp dont_run_in_test(env) when env in [:test, :benchmark], do: []
-
- defp dont_run_in_test(_) do
- [
- {Registry,
- [
- name: Pleroma.Web.Streamer.registry(),
- keys: :duplicate,
- partitions: System.schedulers_online()
- ]},
- Pleroma.Web.FedSockets.Supervisor
- ]
- end
-
- defp chat_child(_env, true) do
- [Pleroma.Web.ChatChannel.ChatChannelState]
- end
-
- defp chat_child(_, _), do: []
-
- defp task_children(:test) do
- [
- %{
- id: :web_push_init,
- start: {Task, :start_link, [&Pleroma.Web.Push.init/0]},
- restart: :temporary
- }
- ]
- end
-
- defp task_children(_) do
- [
- %{
- id: :web_push_init,
- start: {Task, :start_link, [&Pleroma.Web.Push.init/0]},
- restart: :temporary
- },
- %{
- id: :internal_fetch_init,
- start: {Task, :start_link, [&Pleroma.Web.ActivityPub.InternalFetchActor.init/0]},
- restart: :temporary
- }
- ]
- end
-
- # start hackney and gun pools in tests
- defp http_children(_, :test) do
- http_children(Tesla.Adapter.Hackney, nil) ++ http_children(Tesla.Adapter.Gun, nil)
- end
-
- defp http_children(Tesla.Adapter.Hackney, _) do
- pools = [:federation, :media]
-
- pools =
- if Config.get([Pleroma.Upload, :proxy_remote]) do
- [:upload | pools]
- else
- pools
- end
-
- for pool <- pools do
- options = Config.get([:hackney_pools, pool])
- :hackney_pool.child_spec(pool, options)
- end
- end
-
- defp http_children(Tesla.Adapter.Gun, _) do
- Pleroma.Gun.ConnectionPool.children() ++
- [{Task, &Pleroma.HTTP.AdapterHelper.Gun.limiter_setup/0}]
- end
-
- defp http_children(_, _), do: []
-
defp check_system_commands do
filters = Config.get([Pleroma.Upload, :filters])
diff --git a/lib/pleroma/application/dynamic_supervisor.ex b/lib/pleroma/application/dynamic_supervisor.ex
new file mode 100644
index 000000000..bc56ad0fd
--- /dev/null
+++ b/lib/pleroma/application/dynamic_supervisor.ex
@@ -0,0 +1,178 @@
+# # Pleroma: A lightweight social networking server
+# # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# # SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Application.DynamicSupervisor do
+ use DynamicSupervisor
+
+ @registry Pleroma.Application.DynamicSupervisor.Registry
+
+ @type child() ::
+ Supervisor.child_spec()
+ | {module(), term()}
+ | module()
+
+ def start_link(_), do: DynamicSupervisor.start_link(__MODULE__, :no_arg, name: __MODULE__)
+
+ @impl true
+ def init(_), do: DynamicSupervisor.init(strategy: :one_for_one)
+
+ @spec registry() :: module()
+ def registry, do: @registry
+
+ @spec start_child(child()) :: DynamicSupervisor.on_start_child()
+ def start_child(child), do: DynamicSupervisor.start_child(__MODULE__, child)
+
+ @spec start_children(Pleroma.Application.env()) :: :ok
+ def start_children(env) do
+ start_agent()
+
+ [
+ Pleroma.Plugs.RateLimiter.Supervisor,
+ Oban,
+ Pleroma.Web.Endpoint,
+ Pleroma.Gopher.Server,
+ Pleroma.Web.ChatChannel.ChatChannelState,
+ Pleroma.Web.FedSockets.Supervisor
+ ]
+ |> add_http_children(env)
+ |> add_streamer(env)
+ |> Enum.each(&start_dynamic_child/1)
+ end
+
+ defp start_agent do
+ {:ok, pid} = DynamicSupervisor.start_child(__MODULE__, {Agent, fn -> [] end})
+
+ Registry.register(@registry, "agent", pid)
+ end
+
+ defp find_agent do
+ [{_, pid}] = Registry.lookup(@registry, "agent")
+ pid
+ end
+
+ defp add_http_children(children, :test) do
+ hackney_options = Pleroma.Config.get([:hackney_pools, :federation])
+ hackney_pool = :hackney_pool.child_spec(:federation, hackney_options)
+ [hackney_pool, Pleroma.Pool.Supervisor | children]
+ end
+
+ defp add_http_children(children, _) do
+ adapter = Application.get_env(:tesla, :adapter)
+
+ child =
+ if adapter == Tesla.Adapter.Gun do
+ Pleroma.Pool.Supervisor
+ else
+ Pleroma.Application.HackneyPoolSupervisor
+ end
+
+ [child | children]
+ end
+
+ defp add_streamer(children, env) when env in [:test, :benchmark], do: children
+ defp add_streamer(children, _), do: [Pleroma.Web.StreamerRegistry | children]
+
+ defp start_dynamic_child(child) do
+ with {:ok, pid} <- DynamicSupervisor.start_child(__MODULE__, spec(child)) do
+ config_path_mappings()
+ |> Enum.filter(fn {_key, module} -> child == module end)
+ |> Enum.each(fn {key, _} ->
+ Registry.register(@registry, key, pid)
+ end)
+ end
+ end
+
+ defp spec(Oban), do: {Oban, Pleroma.Config.get(Oban)}
+
+ defp spec(Pleroma.Web.StreamerRegistry) do
+ {Registry,
+ [
+ name: Pleroma.Web.Streamer.registry(),
+ keys: :duplicate,
+ partitions: System.schedulers_online()
+ ]}
+ end
+
+ defp spec(child), do: child
+
+ defp config_path_mappings do
+ adapter_module =
+ if Application.get_env(:tesla, :adapter) == Tesla.Adapter.Gun do
+ Pleroma.Pool.Supervisor
+ else
+ Pleroma.Application.HackneyPoolSupervisor
+ end
+
+ [
+ {{:pleroma, :chat}, Pleroma.Web.ChatChannel.ChatChannelState},
+ {{:pleroma, Oban}, Oban},
+ {{:pleroma, :rate_limit}, Pleroma.Plugs.RateLimiter.Supervisor},
+ {{:pleroma, :streamer}, Pleroma.Web.Streamer.registry()},
+ {{:pleroma, :pools}, Pleroma.Pool.Supervisor},
+ {{:pleroma, :connections_pool}, Pleroma.Pool.Supervisor},
+ {{:pleroma, :hackney_pools}, Pleroma.Application.HackneyPoolSupervisor},
+ {{:pleroma, Pleroma.Captcha, [:seconds_valid]}, Pleroma.Web.Endpoint},
+ {{:pleroma, Pleroma.Upload, [:proxy_remote]}, adapter_module},
+ {{:pleroma, :instance, [:upload_limit]}, Pleroma.Web.Endpoint},
+ {{:pleroma, :gopher, [:enabled]}, Pleroma.Gopher.Server},
+ {{:pleroma, :fed_sockets, [:enabled]}, Pleroma.Web.Endpoint}
+ ]
+ end
+
+ @spec save_need_reboot_paths([Pleroma.ConfigDB.t()]) :: :ok
+ def save_need_reboot_paths([]), do: :ok
+
+ def save_need_reboot_paths(configs) do
+ configs
+ |> Enum.map(&find_path(&1.group, &1.key, &1.value))
+ |> Enum.filter(& &1)
+ |> save_paths()
+ end
+
+ defp find_path(group, key, value) do
+ with {path, _} <-
+ Enum.find(config_path_mappings(), fn
+ {{g, k}, _} ->
+ g == group and k == key
+
+ {{g, k, subkeys}, _} ->
+ Keyword.keyword?(value) and g == group and k == key and
+ Enum.any?(Keyword.keys(value), &(&1 in subkeys))
+ end) do
+ path
+ end
+ end
+
+ defp save_paths([]), do: :ok
+
+ defp save_paths(paths), do: Agent.update(find_agent(), &Enum.uniq(&1 ++ paths))
+
+ @spec need_reboot?() :: boolean()
+ def need_reboot?, do: Agent.get(find_agent(), & &1) != []
+
+ @spec restart_children() :: :ok
+ def restart_children do
+ find_agent()
+ |> Agent.get_and_update(&{&1, []})
+ |> Enum.each(&restart_child/1)
+ end
+
+ defp restart_child(path) do
+ [{_, pid}] = Registry.lookup(@registry, path)
+
+ # main module can have multiple keys
+ # first we search for main module
+ with {_, main_module} <- Enum.find(config_path_mappings(), fn {key, _} -> key == path end) do
+ DynamicSupervisor.terminate_child(__MODULE__, pid)
+ # then we search for keys, which depends on this main module
+ config_path_mappings()
+ |> Enum.filter(fn {_, module} -> main_module == module end)
+ |> Enum.each(fn {key, _} ->
+ Registry.unregister(@registry, key)
+ end)
+
+ start_dynamic_child(main_module)
+ end
+ end
+end
diff --git a/lib/pleroma/application/hackney_pool_supervisor.ex b/lib/pleroma/application/hackney_pool_supervisor.ex
new file mode 100644
index 000000000..3e6c31a9c
--- /dev/null
+++ b/lib/pleroma/application/hackney_pool_supervisor.ex
@@ -0,0 +1,30 @@
+# # Pleroma: A lightweight social networking server
+# # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# # SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Application.HackneyPoolSupervisor do
+ use Supervisor
+
+ def start_link(_) do
+ Supervisor.start_link(__MODULE__, :no_arg)
+ end
+
+ def init(_) do
+ pools = [:federation, :media]
+
+ pools =
+ if Pleroma.Config.get([Pleroma.Upload, :proxy_remote]) do
+ [:upload | pools]
+ else
+ pools
+ end
+
+ children =
+ for pool <- pools do
+ options = Pleroma.Config.get([:hackney_pools, pool])
+ :hackney_pool.child_spec(pool, options)
+ end
+
+ Supervisor.init(children, strategy: :one_for_one)
+ end
+end
diff --git a/lib/pleroma/application_requirements.ex b/lib/pleroma/application/requirements.ex
index 16f62b6f5..70e0aade3 100644
--- a/lib/pleroma/application_requirements.ex
+++ b/lib/pleroma/application/requirements.ex
@@ -2,7 +2,7 @@
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.ApplicationRequirements do
+defmodule Pleroma.Application.Requirements do
@moduledoc """
The module represents the collection of validations to runs before start server.
"""
diff --git a/lib/pleroma/application/static.ex b/lib/pleroma/application/static.ex
new file mode 100644
index 000000000..56667c22c
--- /dev/null
+++ b/lib/pleroma/application/static.ex
@@ -0,0 +1,77 @@
+# # Pleroma: A lightweight social networking server
+# # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# # SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Application.Static do
+ require Cachex.Spec
+
+ @spec start_children(Pleroma.Application.env()) :: :ok
+ def start_children(env) do
+ children =
+ [
+ Pleroma.Emoji,
+ Pleroma.Stats,
+ Pleroma.JobQueueMonitor,
+ %{
+ id: :web_push_init,
+ start: {Task, :start_link, [&Pleroma.Web.Push.init/0]},
+ restart: :temporary
+ }
+ ]
+ |> add_cachex_children()
+ |> add_init_internal_fetch_actor_task(env)
+
+ Enum.each(children, &Pleroma.Application.DynamicSupervisor.start_child/1)
+ end
+
+ @spec build_cachex({String.t(), keyword()}) :: map()
+ def build_cachex({type, opts}) do
+ %{
+ id: String.to_atom("cachex_" <> type),
+ start: {Cachex, :start_link, [String.to_atom(type <> "_cache"), opts]},
+ type: :worker
+ }
+ end
+
+ defp add_cachex_children(children) do
+ cachex_children =
+ [
+ {"used_captcha", ttl_interval: seconds_valid_interval()},
+ {"user", default_ttl: 25_000, ttl_interval: 1000, limit: 2500},
+ {"object", default_ttl: 25_000, ttl_interval: 1000, limit: 2500},
+ {"rich_media", default_ttl: :timer.minutes(120), limit: 5000},
+ {"scrubber", limit: 2500},
+ {"idempotency", expiration: cachex_expiration(6 * 60 * 60, 60), limit: 2500},
+ {"web_resp", limit: 2500},
+ {"emoji_packs", expiration: cachex_expiration(5 * 60, 60), limit: 10},
+ {"failed_proxy_url", limit: 2500},
+ {"banned_urls", default_ttl: :timer.hours(24 * 30), limit: 5_000}
+ ]
+ |> Enum.map(&build_cachex/1)
+
+ children ++ cachex_children
+ end
+
+ defp cachex_expiration(default, interval) do
+ Cachex.Spec.expiration(default: :timer.seconds(default), interval: :timer.seconds(interval))
+ end
+
+ defp seconds_valid_interval do
+ [Pleroma.Captcha, :seconds_valid]
+ |> Pleroma.Config.get!()
+ |> :timer.seconds()
+ end
+
+ defp add_init_internal_fetch_actor_task(children, :test), do: children
+
+ defp add_init_internal_fetch_actor_task(children, _) do
+ children ++
+ [
+ %{
+ id: :internal_fetch_init,
+ start: {Task, :start_link, [&Pleroma.Web.ActivityPub.InternalFetchActor.init/0]},
+ restart: :temporary
+ }
+ ]
+ end
+end
diff --git a/lib/pleroma/config/config_db.ex b/lib/pleroma/config/config_db.ex
index e5b7811aa..862c06f0a 100644
--- a/lib/pleroma/config/config_db.ex
+++ b/lib/pleroma/config/config_db.ex
@@ -379,4 +379,29 @@ defmodule Pleroma.ConfigDB do
Regex.match?(~r/^(Pleroma|Phoenix|Tesla|Quack|Ueberauth|Swoosh)\./, string) or
string in ["Oban", "Ueberauth", "ExSyslogger"]
end
+
+ @spec load_and_merge_with_defaults([t()]) :: [{atom(), atom(), term(), term()}]
+ def load_and_merge_with_defaults(deleted \\ []) do
+ (Repo.all(ConfigDB) ++ deleted)
+ |> Enum.map(&merge_with_defaults/1)
+ end
+
+ defp merge_with_defaults(%{group: group, key: key, value: value} = setting) do
+ default = Pleroma.Config.Holder.default_config(group, key)
+
+ merged =
+ cond do
+ Ecto.get_meta(setting, :state) == :deleted -> default
+ can_be_merged?(default, value) -> merge_group(group, key, default, value)
+ true -> value
+ end
+
+ {group, key, value, merged}
+ end
+
+ defp can_be_merged?(val1, val2) when is_list(val1) and is_list(val2) do
+ Keyword.keyword?(val1) and Keyword.keyword?(val2)
+ end
+
+ defp can_be_merged?(_, _), do: false
end
diff --git a/lib/pleroma/config/environment.ex b/lib/pleroma/config/environment.ex
new file mode 100644
index 000000000..b8fa18855
--- /dev/null
+++ b/lib/pleroma/config/environment.ex
@@ -0,0 +1,103 @@
+# # Pleroma: A lightweight social networking server
+# # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# # SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Config.Environment do
+ require Logger
+
+ @spec load_and_update([ConfigDB.t()]) :: :ok
+ def load_and_update(deleted_settings \\ []) do
+ if Pleroma.Config.get(:configurable_from_database) do
+ # We need to restart applications for loaded settings take effect
+
+ {logger_settings, settings} =
+ Pleroma.ConfigDB.load_and_merge_with_defaults(deleted_settings)
+ |> Enum.split_with(fn {group, _, _, _} -> group in [:logger, :quack] end)
+
+ logger_settings
+ |> Enum.sort()
+ |> Enum.each(&configure_logger/1)
+
+ started_applications = Application.started_applications()
+
+ settings
+ |> Enum.map(&update/1)
+ |> Enum.uniq()
+ |> Enum.reject(&(&1 in [nil, :prometheus, :postgrex]))
+ |> Enum.each(&restart(started_applications, &1))
+ end
+
+ :ok
+ end
+
+ # change logger configuration in runtime, without restart
+ defp configure_logger({:quack, key, _, merged}) do
+ Logger.configure_backend(Quack.Logger, [{key, merged}])
+ update(:quack, key, merged)
+ end
+
+ defp configure_logger({_, :backends, _, merged}) do
+ # removing current backends
+ Enum.each(Application.get_env(:logger, :backends), &Logger.remove_backend/1)
+
+ Enum.each(merged, &Logger.add_backend/1)
+
+ update(:logger, :backends, merged)
+ end
+
+ defp configure_logger({_, key, _, merged}) when key in [:console, :ex_syslogger] do
+ merged =
+ if key == :console do
+ put_in(merged[:format], merged[:format] <> "\n")
+ else
+ merged
+ end
+
+ backend =
+ if key == :ex_syslogger,
+ do: {ExSyslogger, :ex_syslogger},
+ else: key
+
+ Logger.configure_backend(backend, merged)
+ update(:logger, key, merged)
+ end
+
+ defp configure_logger({_, key, _, merged}) do
+ Logger.configure([{key, merged}])
+ update(:logger, key, merged)
+ end
+
+ defp update({group, key, value, merged}) do
+ update(group, key, merged)
+ if group != :pleroma, do: group
+ rescue
+ error ->
+ error_msg =
+ "updating env causes error, group: #{inspect(group)}, key: #{inspect(key)}, value: #{
+ inspect(value)
+ } error: #{inspect(error)}"
+
+ Logger.warn(error_msg)
+
+ nil
+ end
+
+ defp update(group, key, nil), do: Application.delete_env(group, key)
+ defp update(group, key, value), do: Application.put_env(group, key, value)
+
+ defp restart(started_applications, app) do
+ with {^app, _, _} <- List.keyfind(started_applications, app, 0),
+ :ok <- Application.stop(app),
+ :ok <- Application.start(app) do
+ :ok
+ else
+ nil ->
+ Logger.warn("#{app} is not started.")
+
+ error ->
+ error
+ |> inspect()
+ |> Logger.warn()
+ end
+ end
+end
diff --git a/lib/pleroma/config/loader.ex b/lib/pleroma/config/loader.ex
index 64e7de6df..4dd03c9dc 100644
--- a/lib/pleroma/config/loader.ex
+++ b/lib/pleroma/config/loader.ex
@@ -19,19 +19,13 @@ defmodule Pleroma.Config.Loader do
if Code.ensure_loaded?(Config.Reader) do
@reader Config.Reader
-
- def read(path), do: @reader.read!(path)
else
# support for Elixir less than 1.9
@reader Mix.Config
- def read(path) do
- path
- |> @reader.eval!()
- |> elem(0)
- end
end
@spec read(Path.t()) :: keyword()
+ def read(path), do: @reader.read!(path)
@spec merge(keyword(), keyword()) :: keyword()
def merge(c1, c2), do: @reader.merge(c1, c2)
diff --git a/lib/pleroma/config/transfer_task.ex b/lib/pleroma/config/transfer_task.ex
deleted file mode 100644
index a0d7b7d71..000000000
--- a/lib/pleroma/config/transfer_task.ex
+++ /dev/null
@@ -1,201 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Config.TransferTask do
- use Task
-
- alias Pleroma.Config
- alias Pleroma.ConfigDB
- alias Pleroma.Repo
-
- require Logger
-
- @type env() :: :test | :benchmark | :dev | :prod
-
- @reboot_time_keys [
- {:pleroma, :hackney_pools},
- {:pleroma, :chat},
- {:pleroma, Oban},
- {:pleroma, :rate_limit},
- {:pleroma, :markup},
- {:pleroma, :streamer},
- {:pleroma, :pools},
- {:pleroma, :connections_pool}
- ]
-
- @reboot_time_subkeys [
- {:pleroma, Pleroma.Captcha, [:seconds_valid]},
- {:pleroma, Pleroma.Upload, [:proxy_remote]},
- {:pleroma, :instance, [:upload_limit]},
- {:pleroma, :gopher, [:enabled]}
- ]
-
- def start_link(restart_pleroma? \\ true) do
- load_and_update_env([], restart_pleroma?)
- if Config.get(:env) == :test, do: Ecto.Adapters.SQL.Sandbox.checkin(Repo)
- :ignore
- end
-
- @spec load_and_update_env([ConfigDB.t()], boolean()) :: :ok
- def load_and_update_env(deleted_settings \\ [], restart_pleroma? \\ true) do
- with {_, true} <- {:configurable, Config.get(:configurable_from_database)} do
- # We need to restart applications for loaded settings take effect
-
- {logger, other} =
- (Repo.all(ConfigDB) ++ deleted_settings)
- |> Enum.map(&merge_with_default/1)
- |> Enum.split_with(fn {group, _, _, _} -> group in [:logger, :quack] end)
-
- logger
- |> Enum.sort()
- |> Enum.each(&configure/1)
-
- started_applications = Application.started_applications()
-
- # TODO: some problem with prometheus after restart!
- reject = [nil, :prometheus, :postgrex]
-
- reject =
- if restart_pleroma? do
- reject
- else
- [:pleroma | reject]
- end
-
- other
- |> Enum.map(&update/1)
- |> Enum.uniq()
- |> Enum.reject(&(&1 in reject))
- |> maybe_set_pleroma_last()
- |> Enum.each(&restart(started_applications, &1, Config.get(:env)))
-
- :ok
- else
- {:configurable, false} -> Restarter.Pleroma.rebooted()
- end
- end
-
- defp maybe_set_pleroma_last(apps) do
- # to be ensured that pleroma will be restarted last
- if :pleroma in apps do
- apps
- |> List.delete(:pleroma)
- |> List.insert_at(-1, :pleroma)
- else
- Restarter.Pleroma.rebooted()
- apps
- end
- end
-
- defp merge_with_default(%{group: group, key: key, value: value} = setting) do
- default = Config.Holder.default_config(group, key)
-
- merged =
- cond do
- Ecto.get_meta(setting, :state) == :deleted -> default
- can_be_merged?(default, value) -> ConfigDB.merge_group(group, key, default, value)
- true -> value
- end
-
- {group, key, value, merged}
- end
-
- # change logger configuration in runtime, without restart
- defp configure({:quack, key, _, merged}) do
- Logger.configure_backend(Quack.Logger, [{key, merged}])
- :ok = update_env(:quack, key, merged)
- end
-
- defp configure({_, :backends, _, merged}) do
- # removing current backends
- Enum.each(Application.get_env(:logger, :backends), &Logger.remove_backend/1)
-
- Enum.each(merged, &Logger.add_backend/1)
-
- :ok = update_env(:logger, :backends, merged)
- end
-
- defp configure({_, key, _, merged}) when key in [:console, :ex_syslogger] do
- merged =
- if key == :console do
- put_in(merged[:format], merged[:format] <> "\n")
- else
- merged
- end
-
- backend =
- if key == :ex_syslogger,
- do: {ExSyslogger, :ex_syslogger},
- else: key
-
- Logger.configure_backend(backend, merged)
- :ok = update_env(:logger, key, merged)
- end
-
- defp configure({_, key, _, merged}) do
- Logger.configure([{key, merged}])
- :ok = update_env(:logger, key, merged)
- end
-
- defp update({group, key, value, merged}) do
- try do
- :ok = update_env(group, key, merged)
-
- if group != :pleroma or pleroma_need_restart?(group, key, value), do: group
- rescue
- error ->
- error_msg =
- "updating env causes error, group: #{inspect(group)}, key: #{inspect(key)}, value: #{
- inspect(value)
- } error: #{inspect(error)}"
-
- Logger.warn(error_msg)
-
- nil
- end
- end
-
- defp update_env(group, key, nil), do: Application.delete_env(group, key)
- defp update_env(group, key, value), do: Application.put_env(group, key, value)
-
- @spec pleroma_need_restart?(atom(), atom(), any()) :: boolean()
- def pleroma_need_restart?(group, key, value) do
- group_and_key_need_reboot?(group, key) or group_and_subkey_need_reboot?(group, key, value)
- end
-
- defp group_and_key_need_reboot?(group, key) do
- Enum.any?(@reboot_time_keys, fn {g, k} -> g == group and k == key end)
- end
-
- defp group_and_subkey_need_reboot?(group, key, value) do
- Keyword.keyword?(value) and
- Enum.any?(@reboot_time_subkeys, fn {g, k, subkeys} ->
- g == group and k == key and
- Enum.any?(Keyword.keys(value), &(&1 in subkeys))
- end)
- end
-
- defp restart(_, :pleroma, env), do: Restarter.Pleroma.restart_after_boot(env)
-
- defp restart(started_applications, app, _) do
- with {^app, _, _} <- List.keyfind(started_applications, app, 0),
- :ok <- Application.stop(app) do
- :ok = Application.start(app)
- else
- nil ->
- Logger.warn("#{app} is not started.")
-
- error ->
- error
- |> inspect()
- |> Logger.warn()
- end
- end
-
- defp can_be_merged?(val1, val2) when is_list(val1) and is_list(val2) do
- Keyword.keyword?(val1) and Keyword.keyword?(val2)
- end
-
- defp can_be_merged?(_val1, _val2), do: false
-end
diff --git a/lib/pleroma/web/admin_api/controllers/admin_api_controller.ex b/lib/pleroma/web/admin_api/controllers/admin_api_controller.ex
index d5713c3dd..ea14894c7 100644
--- a/lib/pleroma/web/admin_api/controllers/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/controllers/admin_api_controller.ex
@@ -628,14 +628,14 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
def restart(conn, _params) do
with :ok <- configurable_from_database() do
- Restarter.Pleroma.restart(Config.get(:env), 50)
+ Task.start(Pleroma.Application.DynamicSupervisor, :restart_children, [])
json(conn, %{})
end
end
def need_reboot(conn, _params) do
- json(conn, %{need_reboot: Restarter.Pleroma.need_reboot?()})
+ json(conn, %{need_reboot: Pleroma.Application.DynamicSupervisor.need_reboot?()})
end
defp configurable_from_database do
diff --git a/lib/pleroma/web/admin_api/controllers/config_controller.ex b/lib/pleroma/web/admin_api/controllers/config_controller.ex
index 0df13007f..25086172c 100644
--- a/lib/pleroma/web/admin_api/controllers/config_controller.ex
+++ b/lib/pleroma/web/admin_api/controllers/config_controller.ex
@@ -34,7 +34,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigController do
render(conn, "index.json", %{
configs: configs,
- need_reboot: Restarter.Pleroma.need_reboot?()
+ need_reboot: Pleroma.Application.DynamicSupervisor.need_reboot?()
})
end
end
@@ -75,7 +75,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigController do
render(conn, "index.json", %{
configs: merged,
- need_reboot: Restarter.Pleroma.need_reboot?()
+ need_reboot: Pleroma.Application.DynamicSupervisor.need_reboot?()
})
end
end
@@ -101,19 +101,13 @@ defmodule Pleroma.Web.AdminAPI.ConfigController do
end)
|> Enum.split_with(&(Ecto.get_meta(&1, :state) == :deleted))
- Config.TransferTask.load_and_update_env(deleted, false)
+ Config.Environment.load_and_update(deleted)
- if not Restarter.Pleroma.need_reboot?() do
- changed_reboot_settings? =
- (updated ++ deleted)
- |> Enum.any?(&Config.TransferTask.pleroma_need_restart?(&1.group, &1.key, &1.value))
-
- if changed_reboot_settings?, do: Restarter.Pleroma.need_reboot()
- end
+ Pleroma.Application.DynamicSupervisor.save_need_reboot_paths(updated ++ deleted)
render(conn, "index.json", %{
configs: updated,
- need_reboot: Restarter.Pleroma.need_reboot?()
+ need_reboot: Pleroma.Application.DynamicSupervisor.need_reboot?()
})
end
end