From e3173a279dad89dfce6eae89368ad3ba180c0490 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Wed, 19 May 2021 14:27:02 -0500 Subject: [PATCH 01/10] Put Plugs in runtime mode in :dev, :test to speed up recompilation --- config/dev.exs | 4 ++++ config/test.exs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/config/dev.exs b/config/dev.exs index 4faaeff5b..8e7d5c587 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -54,6 +54,10 @@ config :pleroma, Pleroma.Web.ApiSpec.CastAndValidate, strict: true +# Reduce recompilation time +# https://dashbit.co/blog/speeding-up-re-compilation-of-elixir-projects +config :phoenix, :plug_init_mode, :runtime + if File.exists?("./config/dev.secret.exs") do import_config "dev.secret.exs" else diff --git a/config/test.exs b/config/test.exs index 87396a88d..007951097 100644 --- a/config/test.exs +++ b/config/test.exs @@ -133,6 +133,10 @@ ap_streamer: Pleroma.Web.ActivityPub.ActivityPubMock, logger: Pleroma.LoggerMock +# Reduce recompilation time +# https://dashbit.co/blog/speeding-up-re-compilation-of-elixir-projects +config :phoenix, :plug_init_mode, :runtime + if File.exists?("./config/test.secret.exs") do import_config "test.secret.exs" else From 21787546c01069d1d1d8261f0bc37d13a73122a9 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sun, 23 May 2021 17:25:18 -0500 Subject: [PATCH 02/10] Router: move StaticFEPlug to a pipeline Speed up recompilation by breaking a cycle. Removes StaticFEPlug as a compile-time dep of Router. --- lib/pleroma/web/router.ex | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 72ad14f05..4e7de2b89 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -140,6 +140,10 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Web.Plugs.MappedSignatureToIdentityPlug) end + pipeline :static_fe do + plug(Pleroma.Web.Plugs.StaticFEPlug) + end + scope "/api/v1/pleroma", Pleroma.Web.TwitterAPI do pipe_through(:pleroma_api) @@ -631,7 +635,7 @@ defmodule Pleroma.Web.Router do scope "/", Pleroma.Web do # Note: html format is supported only if static FE is enabled # Note: http signature is only considered for json requests (no auth for non-json requests) - pipe_through([:accepts_html_json, :http_signature, Pleroma.Web.Plugs.StaticFEPlug]) + pipe_through([:accepts_html_json, :http_signature, :static_fe]) get("/objects/:uuid", OStatus.OStatusController, :object) get("/activities/:uuid", OStatus.OStatusController, :activity) @@ -645,7 +649,7 @@ defmodule Pleroma.Web.Router do scope "/", Pleroma.Web do # Note: html format is supported only if static FE is enabled # Note: http signature is only considered for json requests (no auth for non-json requests) - pipe_through([:accepts_html_xml_json, :http_signature, Pleroma.Web.Plugs.StaticFEPlug]) + pipe_through([:accepts_html_xml_json, :http_signature, :static_fe]) # Note: returns user _profile_ for json requests, redirects to user _feed_ for non-json ones get("/users/:nickname", Feed.UserController, :feed_redirect, as: :user_feed) @@ -653,7 +657,7 @@ defmodule Pleroma.Web.Router do scope "/", Pleroma.Web do # Note: html format is supported only if static FE is enabled - pipe_through([:accepts_html_xml, Pleroma.Web.Plugs.StaticFEPlug]) + pipe_through([:accepts_html_xml, :static_fe]) get("/users/:nickname/feed", Feed.UserController, :feed, as: :user_feed) end From fda34591cefad94277385311c6391d1ca2adb36c Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sat, 22 May 2021 15:04:05 -0500 Subject: [PATCH 03/10] Don't make MediaProxy be a compile-dep of Router Speeds up recompilation by removing MediaProxy as a compile-time dep of Router --- lib/pleroma/web/router.ex | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 72ad14f05..257455616 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -764,11 +764,11 @@ defmodule Pleroma.Web.Router do get("/embed/:id", EmbedController, :show) end - scope "/proxy/", Pleroma.Web.MediaProxy do - get("/preview/:sig/:url", MediaProxyController, :preview) - get("/preview/:sig/:url/:filename", MediaProxyController, :preview) - get("/:sig/:url", MediaProxyController, :remote) - get("/:sig/:url/:filename", MediaProxyController, :remote) + scope "/proxy/", Pleroma.Web do + get("/preview/:sig/:url", MediaProxy.MediaProxyController, :preview) + get("/preview/:sig/:url/:filename", MediaProxy.MediaProxyController, :preview) + get("/:sig/:url", MediaProxy.MediaProxyController, :remote) + get("/:sig/:url/:filename", MediaProxy.MediaProxyController, :remote) end if Pleroma.Config.get(:env) == :dev do From c23b81e399d5be6fc30f4acb1d757d5eb291d8e1 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 21 May 2021 14:47:11 -0500 Subject: [PATCH 04/10] Pleroma.Web.get_api_routes/0 --> Pleroma.Web.Router.get_api_routes/0 Reduce recompilation time by breaking compile-time cycles --- lib/pleroma/web.ex | 12 ------------ lib/pleroma/web/plugs/frontend_static.ex | 2 +- lib/pleroma/web/router.ex | 12 ++++++++++++ test/pleroma/web/plugs/frontend_static_plug_test.exs | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/pleroma/web.ex b/lib/pleroma/web.ex index 8630f244b..f1f9d6229 100644 --- a/lib/pleroma/web.ex +++ b/lib/pleroma/web.ex @@ -233,16 +233,4 @@ defmacro __using__(which) when is_atom(which) do def base_url do Pleroma.Web.Endpoint.url() end - - # TODO: Change to Phoenix.Router.routes/1 for Phoenix 1.6.0+ - def get_api_routes do - Pleroma.Web.Router.__routes__() - |> Enum.reject(fn r -> r.plug == Pleroma.Web.Fallback.RedirectController end) - |> Enum.map(fn r -> - r.path - |> String.split("/", trim: true) - |> List.first() - end) - |> Enum.uniq() - end end diff --git a/lib/pleroma/web/plugs/frontend_static.ex b/lib/pleroma/web/plugs/frontend_static.ex index eb385e94d..e7c943b41 100644 --- a/lib/pleroma/web/plugs/frontend_static.ex +++ b/lib/pleroma/web/plugs/frontend_static.ex @@ -10,7 +10,7 @@ defmodule Pleroma.Web.Plugs.FrontendStatic do """ @behaviour Plug - @api_routes Pleroma.Web.get_api_routes() + @api_routes Pleroma.Web.Router.get_api_routes() def file_path(path, frontend_type \\ :primary) do if configuration = Pleroma.Config.get([:frontends, frontend_type]) do diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 72ad14f05..3550088bb 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -821,4 +821,16 @@ defmodule Pleroma.Web.Router do options("/*path", RedirectController, :empty) end + + # TODO: Change to Phoenix.Router.routes/1 for Phoenix 1.6.0+ + def get_api_routes do + __MODULE__.__routes__() + |> Enum.reject(fn r -> r.plug == Pleroma.Web.Fallback.RedirectController end) + |> Enum.map(fn r -> + r.path + |> String.split("/", trim: true) + |> List.first() + end) + |> Enum.uniq() + end end diff --git a/test/pleroma/web/plugs/frontend_static_plug_test.exs b/test/pleroma/web/plugs/frontend_static_plug_test.exs index 100b83d6a..4152cdefe 100644 --- a/test/pleroma/web/plugs/frontend_static_plug_test.exs +++ b/test/pleroma/web/plugs/frontend_static_plug_test.exs @@ -103,6 +103,6 @@ test "api routes are detected correctly" do "check_password" ] - assert expected_routes == Pleroma.Web.get_api_routes() + assert expected_routes == Pleroma.Web.Router.get_api_routes() end end From 3ebede4b514a69b41b34a0fe8e8fc27ce94a2071 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Thu, 20 May 2021 17:23:02 -0500 Subject: [PATCH 05/10] Gun: make Gun.API a runtime dep Speed up recompilation by breaking a compile-time cycle --- lib/pleroma/gun.ex | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/pleroma/gun.ex b/lib/pleroma/gun.ex index f9c828fac..bef1c9872 100644 --- a/lib/pleroma/gun.ex +++ b/lib/pleroma/gun.ex @@ -11,9 +11,7 @@ defmodule Pleroma.Gun do @callback await(pid(), reference()) :: {:response, :fin, 200, []} @callback set_owner(pid(), pid()) :: :ok - @api Pleroma.Config.get([Pleroma.Gun], Pleroma.Gun.API) - - defp api, do: @api + defp api, do: Pleroma.Config.get([Pleroma.Gun], Pleroma.Gun.API) def open(host, port, opts), do: api().open(host, port, opts) From 0ada3fe823a3c2e6c5835431bdacfbdb8b3d02a7 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 21 May 2021 12:31:28 -0500 Subject: [PATCH 06/10] Gun: use runtime deps in ConnectionPool Speed up recompilation time by breaking compile-time cycles --- lib/pleroma/gun/connection_pool/reclaimer.ex | 6 +++--- lib/pleroma/gun/connection_pool/worker.ex | 10 +++++----- lib/pleroma/http/adapter_helper/gun.ex | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/pleroma/gun/connection_pool/reclaimer.ex b/lib/pleroma/gun/connection_pool/reclaimer.ex index c37b62bf2..4c643d7cb 100644 --- a/lib/pleroma/gun/connection_pool/reclaimer.ex +++ b/lib/pleroma/gun/connection_pool/reclaimer.ex @@ -5,11 +5,11 @@ defmodule Pleroma.Gun.ConnectionPool.Reclaimer do use GenServer, restart: :temporary - @registry Pleroma.Gun.ConnectionPool + defp registry, do: Pleroma.Gun.ConnectionPool def start_monitor do pid = - case :gen_server.start(__MODULE__, [], name: {:via, Registry, {@registry, "reclaimer"}}) do + case :gen_server.start(__MODULE__, [], name: {:via, Registry, {registry(), "reclaimer"}}) do {:ok, pid} -> pid @@ -46,7 +46,7 @@ def handle_continue(:reclaim, _) do # {worker_pid, crf, last_reference} end) unused_conns = Registry.select( - @registry, + registry(), [ {{:_, :"$1", {:_, :"$2", :"$3", :"$4"}}, [{:==, :"$2", []}], [{{:"$1", :"$3", :"$4"}}]} ] diff --git a/lib/pleroma/gun/connection_pool/worker.ex b/lib/pleroma/gun/connection_pool/worker.ex index 02bfff274..a3fa75386 100644 --- a/lib/pleroma/gun/connection_pool/worker.ex +++ b/lib/pleroma/gun/connection_pool/worker.ex @@ -6,10 +6,10 @@ defmodule Pleroma.Gun.ConnectionPool.Worker do alias Pleroma.Gun use GenServer, restart: :temporary - @registry Pleroma.Gun.ConnectionPool + defp registry, do: Pleroma.Gun.ConnectionPool def start_link([key | _] = opts) do - GenServer.start_link(__MODULE__, opts, name: {:via, Registry, {@registry, key}}) + GenServer.start_link(__MODULE__, opts, name: {:via, Registry, {registry(), key}}) end @impl true @@ -24,7 +24,7 @@ def handle_continue({:connect, [key, uri, opts, client_pid]}, _) do time = :erlang.monotonic_time(:millisecond) {_, _} = - Registry.update_value(@registry, key, fn _ -> + Registry.update_value(registry(), key, fn _ -> {conn_pid, [client_pid], 1, time} end) @@ -65,7 +65,7 @@ def handle_call(:add_client, {client_pid, _}, %{key: key, protocol: protocol} = time = :erlang.monotonic_time(:millisecond) {{conn_pid, used_by, _, _}, _} = - Registry.update_value(@registry, key, fn {conn_pid, used_by, crf, last_reference} -> + Registry.update_value(registry(), key, fn {conn_pid, used_by, crf, last_reference} -> {conn_pid, [client_pid | used_by], crf(time - last_reference, crf), time} end) @@ -92,7 +92,7 @@ def handle_call(:add_client, {client_pid, _}, %{key: key, protocol: protocol} = @impl true def handle_call(:remove_client, {client_pid, _}, %{key: key} = state) do {{_conn_pid, used_by, _crf, _last_reference}, _} = - Registry.update_value(@registry, key, fn {conn_pid, used_by, crf, last_reference} -> + Registry.update_value(registry(), key, fn {conn_pid, used_by, crf, last_reference} -> {conn_pid, List.delete(used_by, client_pid), crf, last_reference} end) diff --git a/lib/pleroma/http/adapter_helper/gun.ex b/lib/pleroma/http/adapter_helper/gun.ex index 82c7fd654..251539f34 100644 --- a/lib/pleroma/http/adapter_helper/gun.ex +++ b/lib/pleroma/http/adapter_helper/gun.ex @@ -54,8 +54,8 @@ def pool_timeout(pool) do Config.get([:pools, pool, :recv_timeout], default) end - @prefix Pleroma.Gun.ConnectionPool def limiter_setup do + prefix = Pleroma.Gun.ConnectionPool wait = Config.get([:connections_pool, :connection_acquisition_wait]) retries = Config.get([:connections_pool, :connection_acquisition_retries]) @@ -66,7 +66,7 @@ def limiter_setup do max_waiting = Keyword.get(opts, :max_waiting, 10) result = - ConcurrentLimiter.new(:"#{@prefix}.#{name}", max_running, max_waiting, + ConcurrentLimiter.new(:"#{prefix}.#{name}", max_running, max_waiting, wait: wait, max_retries: retries ) From 32d263cb905dd7fffd43a4955295af0b2b378537 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 21 May 2021 13:04:57 -0500 Subject: [PATCH 07/10] Config: use runtime deps instead of module attributes Speeds up recompilation time by breaking compile-time cycles --- lib/pleroma/config/loader.ex | 28 +++++++++++---------- lib/pleroma/config/transfer_task.ex | 38 +++++++++++++++-------------- 2 files changed, 35 insertions(+), 31 deletions(-) diff --git a/lib/pleroma/config/loader.ex b/lib/pleroma/config/loader.ex index b64d06707..9489f58c4 100644 --- a/lib/pleroma/config/loader.ex +++ b/lib/pleroma/config/loader.ex @@ -3,19 +3,21 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Config.Loader do - @reject_keys [ - Pleroma.Repo, - Pleroma.Web.Endpoint, - :env, - :configurable_from_database, - :database, - :swarm - ] + defp reject_keys, + do: [ + Pleroma.Repo, + Pleroma.Web.Endpoint, + :env, + :configurable_from_database, + :database, + :swarm + ] - @reject_groups [ - :postgrex, - :tesla - ] + defp reject_groups, + do: [ + :postgrex, + :tesla + ] if Code.ensure_loaded?(Config.Reader) do @reader Config.Reader @@ -52,7 +54,7 @@ defp filter(configs) do @spec filter_group(atom(), keyword()) :: keyword() def filter_group(group, configs) do Enum.reject(configs[group], fn {key, _v} -> - key in @reject_keys or group in @reject_groups or + key in reject_keys() or group in reject_groups() or (group == :phoenix and key == :serve_endpoints) end) end diff --git a/lib/pleroma/config/transfer_task.ex b/lib/pleroma/config/transfer_task.ex index aad45aab8..1e3ae82d0 100644 --- a/lib/pleroma/config/transfer_task.ex +++ b/lib/pleroma/config/transfer_task.ex @@ -13,23 +13,25 @@ defmodule Pleroma.Config.TransferTask do @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} - ] + defp reboot_time_keys, + do: [ + {: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]} - ] + defp reboot_time_subkeys, + do: [ + {: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?) @@ -165,12 +167,12 @@ def pleroma_need_restart?(group, key, value) do end defp group_and_key_need_reboot?(group, key) do - Enum.any?(@reboot_time_keys, fn {g, k} -> g == group and k == key end) + 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} -> + Enum.any?(reboot_time_subkeys(), fn {g, k, subkeys} -> g == group and k == key and Enum.any?(Keyword.keys(value), &(&1 in subkeys)) end) From c9e4200ed2167772294fceb4f282979b5ea04981 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sat, 22 May 2021 14:59:12 -0500 Subject: [PATCH 08/10] Create real Views for all Controllers This makes views depend on each other at runtime instead of compile-time --- .../web/admin_api/controllers/o_auth_app_controller.ex | 1 - lib/pleroma/web/admin_api/views/o_auth_app_view.ex | 10 ++++++++++ .../controllers/follow_request_controller.ex | 1 - .../web/mastodon_api/controllers/media_controller.ex | 1 - .../mastodon_api/controllers/timeline_controller.ex | 2 -- .../web/mastodon_api/views/follow_request_view.ex | 10 ++++++++++ lib/pleroma/web/mastodon_api/views/media_view.ex | 10 ++++++++++ lib/pleroma/web/mastodon_api/views/timeline_view.ex | 10 ++++++++++ .../web/pleroma_api/controllers/account_controller.ex | 1 - .../pleroma_api/controllers/conversation_controller.ex | 1 - .../pleroma_api/controllers/notification_controller.ex | 2 -- lib/pleroma/web/pleroma_api/views/account_view.ex | 10 ++++++++++ lib/pleroma/web/pleroma_api/views/conversation_view.ex | 10 ++++++++++ lib/pleroma/web/pleroma_api/views/notification_view.ex | 10 ++++++++++ lib/pleroma/web/static_fe/static_fe_controller.ex | 1 - 15 files changed, 70 insertions(+), 10 deletions(-) create mode 100644 lib/pleroma/web/admin_api/views/o_auth_app_view.ex create mode 100644 lib/pleroma/web/mastodon_api/views/follow_request_view.ex create mode 100644 lib/pleroma/web/mastodon_api/views/media_view.ex create mode 100644 lib/pleroma/web/mastodon_api/views/timeline_view.ex create mode 100644 lib/pleroma/web/pleroma_api/views/account_view.ex create mode 100644 lib/pleroma/web/pleroma_api/views/conversation_view.ex create mode 100644 lib/pleroma/web/pleroma_api/views/notification_view.ex diff --git a/lib/pleroma/web/admin_api/controllers/o_auth_app_controller.ex b/lib/pleroma/web/admin_api/controllers/o_auth_app_controller.ex index 005fe67e2..51b17d392 100644 --- a/lib/pleroma/web/admin_api/controllers/o_auth_app_controller.ex +++ b/lib/pleroma/web/admin_api/controllers/o_auth_app_controller.ex @@ -13,7 +13,6 @@ defmodule Pleroma.Web.AdminAPI.OAuthAppController do require Logger plug(Pleroma.Web.ApiSpec.CastAndValidate) - plug(:put_view, Pleroma.Web.MastodonAPI.AppView) plug( OAuthScopesPlug, diff --git a/lib/pleroma/web/admin_api/views/o_auth_app_view.ex b/lib/pleroma/web/admin_api/views/o_auth_app_view.ex new file mode 100644 index 000000000..af046f343 --- /dev/null +++ b/lib/pleroma/web/admin_api/views/o_auth_app_view.ex @@ -0,0 +1,10 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.AdminAPI.OAuthAppView do + use Pleroma.Web, :view + alias Pleroma.Web.MastodonAPI + + def render(view, opts), do: MastodonAPI.AppView.render(view, opts) +end diff --git a/lib/pleroma/web/mastodon_api/controllers/follow_request_controller.ex b/lib/pleroma/web/mastodon_api/controllers/follow_request_controller.ex index 63d0e2c35..d915298f1 100644 --- a/lib/pleroma/web/mastodon_api/controllers/follow_request_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/follow_request_controller.ex @@ -9,7 +9,6 @@ defmodule Pleroma.Web.MastodonAPI.FollowRequestController do alias Pleroma.Web.CommonAPI alias Pleroma.Web.Plugs.OAuthScopesPlug - plug(:put_view, Pleroma.Web.MastodonAPI.AccountView) plug(Pleroma.Web.ApiSpec.CastAndValidate) plug(:assign_follower when action != :index) diff --git a/lib/pleroma/web/mastodon_api/controllers/media_controller.ex b/lib/pleroma/web/mastodon_api/controllers/media_controller.ex index d6949ed80..5918b288d 100644 --- a/lib/pleroma/web/mastodon_api/controllers/media_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/media_controller.ex @@ -13,7 +13,6 @@ defmodule Pleroma.Web.MastodonAPI.MediaController do action_fallback(Pleroma.Web.MastodonAPI.FallbackController) plug(Majic.Plug, [pool: Pleroma.MajicPool] when action in [:create, :create2]) plug(Pleroma.Web.ApiSpec.CastAndValidate) - plug(:put_view, Pleroma.Web.MastodonAPI.StatusView) plug(OAuthScopesPlug, %{scopes: ["read:media"]} when action == :show) plug(OAuthScopesPlug, %{scopes: ["write:media"]} when action != :show) diff --git a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex index cef299aa4..3f5849777 100644 --- a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex @@ -37,8 +37,6 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do when action in [:public, :hashtag] ) - plug(:put_view, Pleroma.Web.MastodonAPI.StatusView) - defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.TimelineOperation # GET /api/v1/timelines/home diff --git a/lib/pleroma/web/mastodon_api/views/follow_request_view.ex b/lib/pleroma/web/mastodon_api/views/follow_request_view.ex new file mode 100644 index 000000000..4c7d9fc65 --- /dev/null +++ b/lib/pleroma/web/mastodon_api/views/follow_request_view.ex @@ -0,0 +1,10 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.FollowRequestView do + use Pleroma.Web, :view + alias Pleroma.Web.MastodonAPI + + def render(view, opts), do: MastodonAPI.AccountView.render(view, opts) +end diff --git a/lib/pleroma/web/mastodon_api/views/media_view.ex b/lib/pleroma/web/mastodon_api/views/media_view.ex new file mode 100644 index 000000000..cf521887e --- /dev/null +++ b/lib/pleroma/web/mastodon_api/views/media_view.ex @@ -0,0 +1,10 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.MediaView do + use Pleroma.Web, :view + alias Pleroma.Web.MastodonAPI + + def render(view, opts), do: MastodonAPI.StatusView.render(view, opts) +end diff --git a/lib/pleroma/web/mastodon_api/views/timeline_view.ex b/lib/pleroma/web/mastodon_api/views/timeline_view.ex new file mode 100644 index 000000000..91226d78e --- /dev/null +++ b/lib/pleroma/web/mastodon_api/views/timeline_view.ex @@ -0,0 +1,10 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.TimelineView do + use Pleroma.Web, :view + alias Pleroma.Web.MastodonAPI + + def render(view, opts), do: MastodonAPI.StatusView.render(view, opts) +end diff --git a/lib/pleroma/web/pleroma_api/controllers/account_controller.ex b/lib/pleroma/web/pleroma_api/controllers/account_controller.ex index 165afd3b4..6e01c5497 100644 --- a/lib/pleroma/web/pleroma_api/controllers/account_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/account_controller.ex @@ -47,7 +47,6 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do plug(RateLimiter, [name: :account_confirmation_resend] when action == :confirmation_resend) plug(:assign_account_by_id when action in [:favourites, :subscribe, :unsubscribe]) - plug(:put_view, Pleroma.Web.MastodonAPI.AccountView) defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaAccountOperation diff --git a/lib/pleroma/web/pleroma_api/controllers/conversation_controller.ex b/lib/pleroma/web/pleroma_api/controllers/conversation_controller.ex index d285e4907..be2f4617d 100644 --- a/lib/pleroma/web/pleroma_api/controllers/conversation_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/conversation_controller.ex @@ -13,7 +13,6 @@ defmodule Pleroma.Web.PleromaAPI.ConversationController do alias Pleroma.Web.Plugs.OAuthScopesPlug plug(Pleroma.Web.ApiSpec.CastAndValidate) - plug(:put_view, Pleroma.Web.MastodonAPI.ConversationView) plug(OAuthScopesPlug, %{scopes: ["read:statuses"]} when action in [:show, :statuses]) plug( diff --git a/lib/pleroma/web/pleroma_api/controllers/notification_controller.ex b/lib/pleroma/web/pleroma_api/controllers/notification_controller.ex index 257bcd550..bcb3a9ae1 100644 --- a/lib/pleroma/web/pleroma_api/controllers/notification_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/notification_controller.ex @@ -14,8 +14,6 @@ defmodule Pleroma.Web.PleromaAPI.NotificationController do %{scopes: ["write:notifications"]} when action == :mark_as_read ) - plug(:put_view, Pleroma.Web.MastodonAPI.NotificationView) - defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaNotificationOperation def mark_as_read(%{assigns: %{user: user}, body_params: %{id: notification_id}} = conn, _) do diff --git a/lib/pleroma/web/pleroma_api/views/account_view.ex b/lib/pleroma/web/pleroma_api/views/account_view.ex new file mode 100644 index 000000000..28941f471 --- /dev/null +++ b/lib/pleroma/web/pleroma_api/views/account_view.ex @@ -0,0 +1,10 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.AccountView do + use Pleroma.Web, :view + alias Pleroma.Web.MastodonAPI + + def render(view, opts), do: MastodonAPI.AccountView.render(view, opts) +end diff --git a/lib/pleroma/web/pleroma_api/views/conversation_view.ex b/lib/pleroma/web/pleroma_api/views/conversation_view.ex new file mode 100644 index 000000000..173006360 --- /dev/null +++ b/lib/pleroma/web/pleroma_api/views/conversation_view.ex @@ -0,0 +1,10 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.ConversationView do + use Pleroma.Web, :view + alias Pleroma.Web.MastodonAPI + + def render(view, opts), do: MastodonAPI.ConversationView.render(view, opts) +end diff --git a/lib/pleroma/web/pleroma_api/views/notification_view.ex b/lib/pleroma/web/pleroma_api/views/notification_view.ex new file mode 100644 index 000000000..36b2fdfe8 --- /dev/null +++ b/lib/pleroma/web/pleroma_api/views/notification_view.ex @@ -0,0 +1,10 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.NotificationView do + use Pleroma.Web, :view + alias Pleroma.Web.MastodonAPI + + def render(view, opts), do: MastodonAPI.NotificationView.render(view, opts) +end diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex index fe485d10d..50f0927a3 100644 --- a/lib/pleroma/web/static_fe/static_fe_controller.ex +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -14,7 +14,6 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do alias Pleroma.Web.Router.Helpers plug(:put_layout, :static_fe) - plug(:put_view, Pleroma.Web.StaticFE.StaticFEView) plug(:assign_id) @page_keys ["max_id", "min_id", "limit", "since_id", "order"] From 3ff9c5e2a67ab83c2abdb14cd246dea059079e75 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sat, 22 May 2021 16:44:51 -0500 Subject: [PATCH 09/10] Break out activity-specific HTML functions into Pleroma.Activity.HTML Fixes cycles in lib/pleroma/ecto_type/activity_pub/object_validators/safe_text.ex --- lib/pleroma/activity/html.ex | 45 +++++++++++++++++++ lib/pleroma/html.ex | 35 --------------- .../web/mastodon_api/views/status_view.ex | 4 +- lib/pleroma/web/metadata/utils.ex | 3 +- 4 files changed, 49 insertions(+), 38 deletions(-) create mode 100644 lib/pleroma/activity/html.ex diff --git a/lib/pleroma/activity/html.ex b/lib/pleroma/activity/html.ex new file mode 100644 index 000000000..0bf393836 --- /dev/null +++ b/lib/pleroma/activity/html.ex @@ -0,0 +1,45 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Activity.HTML do + alias Pleroma.HTML + alias Pleroma.Object + + @cachex Pleroma.Config.get([:cachex, :provider], Cachex) + + def get_cached_scrubbed_html_for_activity( + content, + scrubbers, + activity, + key \\ "", + callback \\ fn x -> x end + ) do + key = "#{key}#{generate_scrubber_signature(scrubbers)}|#{activity.id}" + + @cachex.fetch!(:scrubber_cache, key, fn _key -> + object = Object.normalize(activity, fetch: false) + HTML.ensure_scrubbed_html(content, scrubbers, object.data["fake"] || false, callback) + end) + end + + def get_cached_stripped_html_for_activity(content, activity, key) do + get_cached_scrubbed_html_for_activity( + content, + FastSanitize.Sanitizer.StripTags, + activity, + key, + &HtmlEntities.decode/1 + ) + end + + defp generate_scrubber_signature(scrubber) when is_atom(scrubber) do + generate_scrubber_signature([scrubber]) + end + + defp generate_scrubber_signature(scrubbers) do + Enum.reduce(scrubbers, "", fn scrubber, signature -> + "#{signature}#{to_string(scrubber)}" + end) + end +end diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex index 2dfdca693..bee66169d 100644 --- a/lib/pleroma/html.ex +++ b/lib/pleroma/html.ex @@ -49,31 +49,6 @@ def filter_tags(html, scrubber) do def filter_tags(html), do: filter_tags(html, nil) def strip_tags(html), do: filter_tags(html, FastSanitize.Sanitizer.StripTags) - def get_cached_scrubbed_html_for_activity( - content, - scrubbers, - activity, - key \\ "", - callback \\ fn x -> x end - ) do - key = "#{key}#{generate_scrubber_signature(scrubbers)}|#{activity.id}" - - @cachex.fetch!(:scrubber_cache, key, fn _key -> - object = Pleroma.Object.normalize(activity, fetch: false) - ensure_scrubbed_html(content, scrubbers, object.data["fake"] || false, callback) - end) - end - - def get_cached_stripped_html_for_activity(content, activity, key) do - get_cached_scrubbed_html_for_activity( - content, - FastSanitize.Sanitizer.StripTags, - activity, - key, - &HtmlEntities.decode/1 - ) - end - def ensure_scrubbed_html( content, scrubbers, @@ -92,16 +67,6 @@ def ensure_scrubbed_html( end end - defp generate_scrubber_signature(scrubber) when is_atom(scrubber) do - generate_scrubber_signature([scrubber]) - end - - defp generate_scrubber_signature(scrubbers) do - Enum.reduce(scrubbers, "", fn scrubber, signature -> - "#{signature}#{to_string(scrubber)}" - end) - end - def extract_first_external_url_from_object(%{data: %{"content" => content}} = object) when is_binary(content) do unless object.data["fake"] do diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index bac897a57..da2cf0f95 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -254,7 +254,7 @@ def render("show.json", %{activity: %{data: %{"object" => _object}} = activity} content_html = content - |> HTML.get_cached_scrubbed_html_for_activity( + |> Activity.HTML.get_cached_scrubbed_html_for_activity( User.html_filter_policy(opts[:for]), activity, "mastoapi:content" @@ -262,7 +262,7 @@ def render("show.json", %{activity: %{data: %{"object" => _object}} = activity} content_plaintext = content - |> HTML.get_cached_stripped_html_for_activity( + |> Activity.HTML.get_cached_stripped_html_for_activity( activity, "mastoapi:content" ) diff --git a/lib/pleroma/web/metadata/utils.ex b/lib/pleroma/web/metadata/utils.ex index de7195435..bc31d66b9 100644 --- a/lib/pleroma/web/metadata/utils.ex +++ b/lib/pleroma/web/metadata/utils.ex @@ -3,6 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Metadata.Utils do + alias Pleroma.Activity alias Pleroma.Emoji alias Pleroma.Formatter alias Pleroma.HTML @@ -13,7 +14,7 @@ def scrub_html_and_truncate(%{data: %{"content" => content}} = object) do # html content comes from DB already encoded, decode first and scrub after |> HtmlEntities.decode() |> String.replace(~r//, " ") - |> HTML.get_cached_stripped_html_for_activity(object, "metadata") + |> Activity.HTML.get_cached_stripped_html_for_activity(object, "metadata") |> Emoji.Formatter.demojify() |> HtmlEntities.decode() |> Formatter.truncate() From fa543a936124abee524f9a103c17d2601176dcd4 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 21 May 2021 16:58:20 -0500 Subject: [PATCH 10/10] ActivityPub.Pipeline: switch to runtime deps Speed up recompilation by breaking compile-time cycles --- lib/pleroma/web/activity_pub/pipeline.ex | 31 +++++++++++------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/lib/pleroma/web/activity_pub/pipeline.ex b/lib/pleroma/web/activity_pub/pipeline.ex index 195596f94..f04557a47 100644 --- a/lib/pleroma/web/activity_pub/pipeline.ex +++ b/lib/pleroma/web/activity_pub/pipeline.ex @@ -7,26 +7,23 @@ defmodule Pleroma.Web.ActivityPub.Pipeline do alias Pleroma.Config alias Pleroma.Object alias Pleroma.Repo - alias Pleroma.Web.ActivityPub.ActivityPub - alias Pleroma.Web.ActivityPub.MRF - alias Pleroma.Web.ActivityPub.ObjectValidator - alias Pleroma.Web.ActivityPub.SideEffects + alias Pleroma.Web.ActivityPub alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.Federator - @side_effects Config.get([:pipeline, :side_effects], SideEffects) - @federator Config.get([:pipeline, :federator], Federator) - @object_validator Config.get([:pipeline, :object_validator], ObjectValidator) - @mrf Config.get([:pipeline, :mrf], MRF) - @activity_pub Config.get([:pipeline, :activity_pub], ActivityPub) - @config Config.get([:pipeline, :config], Config) + defp side_effects, do: Config.get([:pipeline, :side_effects], SideEffects) + defp federator, do: Config.get([:pipeline, :federator], Federator) + defp object_validator, do: Config.get([:pipeline, :object_validator], ObjectValidator) + defp mrf, do: Config.get([:pipeline, :mrf], MRF) + defp activity_pub, do: Config.get([:pipeline, :activity_pub], ActivityPub) + defp config, do: Config.get([:pipeline, :config], Config) @spec common_pipeline(map(), keyword()) :: {:ok, Activity.t() | Object.t(), keyword()} | {:error, any()} def common_pipeline(object, meta) do case Repo.transaction(fn -> do_common_pipeline(object, meta) end) do {:ok, {:ok, activity, meta}} -> - @side_effects.handle_after_transaction(meta) + side_effects().handle_after_transaction(meta) {:ok, activity, meta} {:ok, value} -> @@ -42,13 +39,13 @@ def common_pipeline(object, meta) do def do_common_pipeline(object, meta) do with {_, {:ok, validated_object, meta}} <- - {:validate_object, @object_validator.validate(object, meta)}, + {:validate_object, object_validator().validate(object, meta)}, {_, {:ok, mrfd_object, meta}} <- - {:mrf_object, @mrf.pipeline_filter(validated_object, meta)}, + {:mrf_object, mrf().pipeline_filter(validated_object, meta)}, {_, {:ok, activity, meta}} <- - {:persist_object, @activity_pub.persist(mrfd_object, meta)}, + {:persist_object, activity_pub().persist(mrfd_object, meta)}, {_, {:ok, activity, meta}} <- - {:execute_side_effects, @side_effects.handle(activity, meta)}, + {:execute_side_effects, side_effects().handle(activity, meta)}, {_, {:ok, _}} <- {:federation, maybe_federate(activity, meta)} do {:ok, activity, meta} else @@ -61,7 +58,7 @@ defp maybe_federate(%Object{}, _), do: {:ok, :not_federated} defp maybe_federate(%Activity{} = activity, meta) do with {:ok, local} <- Keyword.fetch(meta, :local) do - do_not_federate = meta[:do_not_federate] || !@config.get([:instance, :federating]) + do_not_federate = meta[:do_not_federate] || !config().get([:instance, :federating]) if !do_not_federate and local and not Visibility.is_local_public?(activity) do activity = @@ -71,7 +68,7 @@ defp maybe_federate(%Activity{} = activity, meta) do activity end - @federator.publish(activity) + federator().publish(activity) {:ok, :federated} else {:ok, :not_federated}