Fork of Pleroma with site-specific changes and feature branches https://git.pleroma.social/pleroma/pleroma
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

187 lines
5.4KB

  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. defmodule Pleroma.Config.TransferTask do
  5. use Task
  6. alias Pleroma.ConfigDB
  7. alias Pleroma.Repo
  8. require Logger
  9. @type env() :: :test | :benchmark | :dev | :prod
  10. @reboot_time_keys [
  11. {:pleroma, :hackney_pools},
  12. {:pleroma, :chat},
  13. {:pleroma, Oban},
  14. {:pleroma, :rate_limit},
  15. {:pleroma, :markup},
  16. {:pleroma, :streamer},
  17. {:pleroma, :pools},
  18. {:pleroma, :connections_pool},
  19. {:tesla, :adapter}
  20. ]
  21. @reboot_time_subkeys [
  22. {:pleroma, Pleroma.Captcha, [:seconds_valid]},
  23. {:pleroma, Pleroma.Upload, [:proxy_remote]},
  24. {:pleroma, :instance, [:upload_limit]},
  25. {:pleroma, :email_notifications, [:digest]},
  26. {:pleroma, :oauth2, [:clean_expired_tokens]},
  27. {:pleroma, Pleroma.ActivityExpiration, [:enabled]},
  28. {:pleroma, Pleroma.ScheduledActivity, [:enabled]},
  29. {:pleroma, :gopher, [:enabled]}
  30. ]
  31. @reject [nil, :prometheus]
  32. def start_link(_) do
  33. load_and_update_env()
  34. if Pleroma.Config.get(:env) == :test, do: Ecto.Adapters.SQL.Sandbox.checkin(Repo)
  35. :ignore
  36. end
  37. @spec load_and_update_env([ConfigDB.t()]) :: :ok | false
  38. def load_and_update_env(deleted \\ [], restart_pleroma? \\ true) do
  39. with {:configurable, true} <-
  40. {:configurable, Pleroma.Config.get(:configurable_from_database)},
  41. true <- Ecto.Adapters.SQL.table_exists?(Repo, "config"),
  42. started_applications <- Application.started_applications() do
  43. # We need to restart applications for loaded settings take effect
  44. in_db = Repo.all(ConfigDB)
  45. with_deleted = in_db ++ deleted
  46. reject_for_restart = if restart_pleroma?, do: @reject, else: [:pleroma | @reject]
  47. applications =
  48. with_deleted
  49. |> Enum.map(&merge_and_update(&1))
  50. |> Enum.uniq()
  51. # TODO: some problem with prometheus after restart!
  52. |> Enum.reject(&(&1 in reject_for_restart))
  53. # to be ensured that pleroma will be restarted last
  54. applications =
  55. if :pleroma in applications do
  56. List.delete(applications, :pleroma) ++ [:pleroma]
  57. else
  58. Restarter.Pleroma.rebooted()
  59. applications
  60. end
  61. Enum.each(applications, &restart(started_applications, &1, Pleroma.Config.get(:env)))
  62. :ok
  63. else
  64. {:configurable, false} -> Restarter.Pleroma.rebooted()
  65. end
  66. end
  67. defp group_for_restart(:logger, key, _, merged_value) do
  68. # change logger configuration in runtime, without restart
  69. if Keyword.keyword?(merged_value) and
  70. key not in [:compile_time_application, :backends, :compile_time_purge_matching] do
  71. Logger.configure_backend(key, merged_value)
  72. else
  73. Logger.configure([{key, merged_value}])
  74. end
  75. nil
  76. end
  77. defp group_for_restart(:tesla, _, _, _), do: :pleroma
  78. defp group_for_restart(group, _, _, _) when group != :pleroma, do: group
  79. defp group_for_restart(group, key, value, _) do
  80. if pleroma_need_restart?(group, key, value) do
  81. group
  82. end
  83. end
  84. defp merge_and_update(setting) do
  85. try do
  86. key = ConfigDB.from_string(setting.key)
  87. group = ConfigDB.from_string(setting.group)
  88. default = Pleroma.Config.Holder.config(group, key)
  89. value = ConfigDB.from_binary(setting.value)
  90. merged_value =
  91. if Ecto.get_meta(setting, :state) == :deleted do
  92. default
  93. else
  94. if can_be_merged?(default, value) do
  95. ConfigDB.merge_group(group, key, default, value)
  96. else
  97. value
  98. end
  99. end
  100. :ok = update_env(group, key, merged_value)
  101. group_for_restart(group, key, value, merged_value)
  102. rescue
  103. error ->
  104. error_msg =
  105. "updating env causes error, group: " <>
  106. inspect(setting.group) <>
  107. " key: " <>
  108. inspect(setting.key) <>
  109. " value: " <>
  110. inspect(ConfigDB.from_binary(setting.value)) <> " error: " <> inspect(error)
  111. Logger.warn(error_msg)
  112. nil
  113. end
  114. end
  115. @spec pleroma_need_restart?(atom(), atom(), any()) :: boolean()
  116. def pleroma_need_restart?(group, key, value) do
  117. group_and_key_need_reboot?(group, key) or group_and_subkey_need_reboot?(group, key, value)
  118. end
  119. defp group_and_key_need_reboot?(group, key) do
  120. Enum.any?(@reboot_time_keys, fn {g, k} -> g == group and k == key end)
  121. end
  122. defp group_and_subkey_need_reboot?(group, key, value) do
  123. Keyword.keyword?(value) and
  124. Enum.any?(@reboot_time_subkeys, fn {g, k, subkeys} ->
  125. g == group and k == key and
  126. Enum.any?(Keyword.keys(value), &(&1 in subkeys))
  127. end)
  128. end
  129. defp update_env(group, key, nil), do: Application.delete_env(group, key)
  130. defp update_env(group, key, value), do: Application.put_env(group, key, value)
  131. defp restart(_, :pleroma, env), do: Restarter.Pleroma.restart_after_boot(env)
  132. defp restart(started_applications, app, _) do
  133. with {^app, _, _} <- List.keyfind(started_applications, app, 0),
  134. :ok <- Application.stop(app) do
  135. :ok = Application.start(app)
  136. else
  137. nil ->
  138. Logger.warn("#{app} is not started.")
  139. error ->
  140. error
  141. |> inspect()
  142. |> Logger.warn()
  143. end
  144. end
  145. defp can_be_merged?(val1, val2) when is_list(val1) and is_list(val2) do
  146. Keyword.keyword?(val1) and Keyword.keyword?(val2)
  147. end
  148. defp can_be_merged?(_val1, _val2), do: false
  149. end