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.

317 lines
9.1KB

  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. defmodule Pleroma.Application do
  5. use Application
  6. import Cachex.Spec
  7. alias Pleroma.Config
  8. require Logger
  9. @name Mix.Project.config()[:name]
  10. @version Mix.Project.config()[:version]
  11. @repository Mix.Project.config()[:source_url]
  12. @mix_env Mix.env()
  13. def name, do: @name
  14. def version, do: @version
  15. def named_version, do: @name <> " " <> @version
  16. def repository, do: @repository
  17. def user_agent do
  18. if Process.whereis(Pleroma.Web.Endpoint) do
  19. case Config.get([:http, :user_agent], :default) do
  20. :default ->
  21. info = "#{Pleroma.Web.Endpoint.url()} <#{Config.get([:instance, :email], "")}>"
  22. named_version() <> "; " <> info
  23. custom ->
  24. custom
  25. end
  26. else
  27. # fallback, if endpoint is not started yet
  28. "Pleroma Data Loader"
  29. end
  30. end
  31. # See http://elixir-lang.org/docs/stable/elixir/Application.html
  32. # for more information on OTP Applications
  33. def start(_type, _args) do
  34. # Scrubbers are compiled at runtime and therefore will cause a conflict
  35. # every time the application is restarted, so we disable module
  36. # conflicts at runtime
  37. Code.compiler_options(ignore_module_conflict: true)
  38. # Disable warnings_as_errors at runtime, it breaks Phoenix live reload
  39. # due to protocol consolidation warnings
  40. Code.compiler_options(warnings_as_errors: false)
  41. Pleroma.Telemetry.Logger.attach()
  42. Config.Holder.save_default()
  43. Pleroma.HTML.compile_scrubbers()
  44. Pleroma.Config.Oban.warn()
  45. Config.DeprecationWarnings.warn()
  46. Pleroma.Web.Plugs.HTTPSecurityPlug.warn_if_disabled()
  47. Pleroma.ApplicationRequirements.verify!()
  48. setup_instrumenters()
  49. load_custom_modules()
  50. Pleroma.Docs.JSON.compile()
  51. limiters_setup()
  52. adapter = Application.get_env(:tesla, :adapter)
  53. if adapter == Tesla.Adapter.Gun do
  54. if version = Pleroma.OTPVersion.version() do
  55. [major, minor] =
  56. version
  57. |> String.split(".")
  58. |> Enum.map(&String.to_integer/1)
  59. |> Enum.take(2)
  60. if (major == 22 and minor < 2) or major < 22 do
  61. raise "
  62. !!!OTP VERSION WARNING!!!
  63. You are using gun adapter with OTP version #{version}, which doesn't support correct handling of unordered certificates chains. Please update your Erlang/OTP to at least 22.2.
  64. "
  65. end
  66. else
  67. raise "
  68. !!!OTP VERSION WARNING!!!
  69. To support correct handling of unordered certificates chains - OTP version must be > 22.2.
  70. "
  71. end
  72. end
  73. # Define workers and child supervisors to be supervised
  74. children =
  75. [
  76. Pleroma.Repo,
  77. Config.TransferTask,
  78. Pleroma.Emoji,
  79. Pleroma.Web.Plugs.RateLimiter.Supervisor
  80. ] ++
  81. cachex_children() ++
  82. http_children(adapter, @mix_env) ++
  83. [
  84. Pleroma.Stats,
  85. Pleroma.JobQueueMonitor,
  86. {Majic.Pool, [name: Pleroma.MajicPool, pool_size: Config.get([:majic_pool, :size], 2)]},
  87. {Oban, Config.get(Oban)},
  88. Pleroma.Web.Endpoint
  89. ] ++
  90. task_children(@mix_env) ++
  91. dont_run_in_test(@mix_env) ++
  92. shout_child(shout_enabled?()) ++
  93. [Pleroma.Gopher.Server]
  94. # See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
  95. # for other strategies and supported options
  96. opts = [strategy: :one_for_one, name: Pleroma.Supervisor]
  97. result = Supervisor.start_link(children, opts)
  98. set_postgres_server_version()
  99. result
  100. end
  101. defp set_postgres_server_version do
  102. version =
  103. with %{rows: [[version]]} <- Ecto.Adapters.SQL.query!(Pleroma.Repo, "show server_version"),
  104. {num, _} <- Float.parse(version) do
  105. num
  106. else
  107. e ->
  108. Logger.warn(
  109. "Could not get the postgres version: #{inspect(e)}.\nSetting the default value of 9.6"
  110. )
  111. 9.6
  112. end
  113. :persistent_term.put({Pleroma.Repo, :postgres_version}, version)
  114. end
  115. def load_custom_modules do
  116. dir = Config.get([:modules, :runtime_dir])
  117. if dir && File.exists?(dir) do
  118. dir
  119. |> Pleroma.Utils.compile_dir()
  120. |> case do
  121. {:error, _errors, _warnings} ->
  122. raise "Invalid custom modules"
  123. {:ok, modules, _warnings} ->
  124. if @mix_env != :test do
  125. Enum.each(modules, fn mod ->
  126. Logger.info("Custom module loaded: #{inspect(mod)}")
  127. end)
  128. end
  129. :ok
  130. end
  131. end
  132. end
  133. defp setup_instrumenters do
  134. require Prometheus.Registry
  135. if Application.get_env(:prometheus, Pleroma.Repo.Instrumenter) do
  136. :ok =
  137. :telemetry.attach(
  138. "prometheus-ecto",
  139. [:pleroma, :repo, :query],
  140. &Pleroma.Repo.Instrumenter.handle_event/4,
  141. %{}
  142. )
  143. Pleroma.Repo.Instrumenter.setup()
  144. end
  145. Pleroma.Web.Endpoint.MetricsExporter.setup()
  146. Pleroma.Web.Endpoint.PipelineInstrumenter.setup()
  147. # Note: disabled until prometheus-phx is integrated into prometheus-phoenix:
  148. # Pleroma.Web.Endpoint.Instrumenter.setup()
  149. PrometheusPhx.setup()
  150. end
  151. defp cachex_children do
  152. [
  153. build_cachex("used_captcha", ttl_interval: seconds_valid_interval()),
  154. build_cachex("user", default_ttl: 25_000, ttl_interval: 1000, limit: 2500),
  155. build_cachex("object", default_ttl: 25_000, ttl_interval: 1000, limit: 2500),
  156. build_cachex("rich_media", default_ttl: :timer.minutes(120), limit: 5000),
  157. build_cachex("scrubber", limit: 2500),
  158. build_cachex("idempotency", expiration: idempotency_expiration(), limit: 2500),
  159. build_cachex("web_resp", limit: 2500),
  160. build_cachex("emoji_packs", expiration: emoji_packs_expiration(), limit: 10),
  161. build_cachex("failed_proxy_url", limit: 2500),
  162. build_cachex("banned_urls", default_ttl: :timer.hours(24 * 30), limit: 5_000),
  163. build_cachex("chat_message_id_idempotency_key",
  164. expiration: chat_message_id_idempotency_key_expiration(),
  165. limit: 500_000
  166. )
  167. ]
  168. end
  169. defp emoji_packs_expiration,
  170. do: expiration(default: :timer.seconds(5 * 60), interval: :timer.seconds(60))
  171. defp idempotency_expiration,
  172. do: expiration(default: :timer.seconds(6 * 60 * 60), interval: :timer.seconds(60))
  173. defp chat_message_id_idempotency_key_expiration,
  174. do: expiration(default: :timer.minutes(2), interval: :timer.seconds(60))
  175. defp seconds_valid_interval,
  176. do: :timer.seconds(Config.get!([Pleroma.Captcha, :seconds_valid]))
  177. @spec build_cachex(String.t(), keyword()) :: map()
  178. def build_cachex(type, opts),
  179. do: %{
  180. id: String.to_atom("cachex_" <> type),
  181. start: {Cachex, :start_link, [String.to_atom(type <> "_cache"), opts]},
  182. type: :worker
  183. }
  184. defp shout_enabled?, do: Config.get([:shout, :enabled])
  185. defp dont_run_in_test(env) when env in [:test, :benchmark], do: []
  186. defp dont_run_in_test(_) do
  187. [
  188. {Registry,
  189. [
  190. name: Pleroma.Web.Streamer.registry(),
  191. keys: :duplicate,
  192. partitions: System.schedulers_online()
  193. ]}
  194. ] ++ background_migrators()
  195. end
  196. defp background_migrators do
  197. [
  198. Pleroma.Migrators.HashtagsTableMigrator
  199. ]
  200. end
  201. defp shout_child(true) do
  202. [
  203. Pleroma.Web.ShoutChannel.ShoutChannelState,
  204. {Phoenix.PubSub, [name: Pleroma.PubSub, adapter: Phoenix.PubSub.PG2]}
  205. ]
  206. end
  207. defp shout_child(_), do: []
  208. defp task_children(:test) do
  209. [
  210. %{
  211. id: :web_push_init,
  212. start: {Task, :start_link, [&Pleroma.Web.Push.init/0]},
  213. restart: :temporary
  214. }
  215. ]
  216. end
  217. defp task_children(_) do
  218. [
  219. %{
  220. id: :web_push_init,
  221. start: {Task, :start_link, [&Pleroma.Web.Push.init/0]},
  222. restart: :temporary
  223. },
  224. %{
  225. id: :internal_fetch_init,
  226. start: {Task, :start_link, [&Pleroma.Web.ActivityPub.InternalFetchActor.init/0]},
  227. restart: :temporary
  228. }
  229. ]
  230. end
  231. # start hackney and gun pools in tests
  232. defp http_children(_, :test) do
  233. http_children(Tesla.Adapter.Hackney, nil) ++ http_children(Tesla.Adapter.Gun, nil)
  234. end
  235. defp http_children(Tesla.Adapter.Hackney, _) do
  236. pools = [:federation, :media]
  237. pools =
  238. if Config.get([Pleroma.Upload, :proxy_remote]) do
  239. [:upload | pools]
  240. else
  241. pools
  242. end
  243. for pool <- pools do
  244. options = Config.get([:hackney_pools, pool])
  245. :hackney_pool.child_spec(pool, options)
  246. end
  247. end
  248. defp http_children(Tesla.Adapter.Gun, _) do
  249. Pleroma.Gun.ConnectionPool.children() ++
  250. [{Task, &Pleroma.HTTP.AdapterHelper.Gun.limiter_setup/0}]
  251. end
  252. defp http_children(_, _), do: []
  253. @spec limiters_setup() :: :ok
  254. def limiters_setup do
  255. config = Config.get(ConcurrentLimiter, [])
  256. [Pleroma.Web.RichMedia.Helpers, Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy]
  257. |> Enum.each(fn module ->
  258. mod_config = Keyword.get(config, module, [])
  259. max_running = Keyword.get(mod_config, :max_running, 5)
  260. max_waiting = Keyword.get(mod_config, :max_waiting, 5)
  261. ConcurrentLimiter.new(module, max_running, max_waiting)
  262. end)
  263. end
  264. end