Merge remote-tracking branch 'pleroma/develop' into notice-routes
[akkoma] / lib / pleroma / migrators / support / base_migrator_state.ex
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
5 defmodule Pleroma.Migrators.Support.BaseMigratorState do
6 @moduledoc """
7 Base background migrator state functionality.
8 """
9
10 @callback data_migration() :: Pleroma.DataMigration.t()
11
12 defmacro __using__(_opts) do
13 quote do
14 use Agent
15
16 alias Pleroma.DataMigration
17
18 @behaviour Pleroma.Migrators.Support.BaseMigratorState
19 @reg_name {:global, __MODULE__}
20
21 def start_link(_) do
22 Agent.start_link(fn -> load_state_from_db() end, name: @reg_name)
23 end
24
25 def data_migration, do: raise("data_migration/0 is not implemented")
26 defoverridable data_migration: 0
27
28 defp load_state_from_db do
29 data_migration = data_migration()
30
31 data =
32 if data_migration do
33 Map.new(data_migration.data, fn {k, v} -> {String.to_atom(k), v} end)
34 else
35 %{}
36 end
37
38 %{
39 data_migration_id: data_migration && data_migration.id,
40 data: data
41 }
42 end
43
44 def persist_to_db do
45 %{data_migration_id: data_migration_id, data: data} = state()
46
47 if data_migration_id do
48 DataMigration.update_one_by_id(data_migration_id, data: data)
49 else
50 {:error, :nil_data_migration_id}
51 end
52 end
53
54 def reset do
55 %{data_migration_id: data_migration_id} = state()
56
57 with false <- is_nil(data_migration_id),
58 :ok <-
59 DataMigration.update_one_by_id(data_migration_id,
60 state: :pending,
61 data: %{}
62 ) do
63 reinit()
64 else
65 true -> {:error, :nil_data_migration_id}
66 e -> e
67 end
68 end
69
70 def reinit do
71 Agent.update(@reg_name, fn _state -> load_state_from_db() end)
72 end
73
74 def state do
75 Agent.get(@reg_name, & &1)
76 end
77
78 def get_data_key(key, default \\ nil) do
79 get_in(state(), [:data, key]) || default
80 end
81
82 def put_data_key(key, value) do
83 _ = persist_non_data_change(key, value)
84
85 Agent.update(@reg_name, fn state ->
86 put_in(state, [:data, key], value)
87 end)
88 end
89
90 def increment_data_key(key, increment \\ 1) do
91 Agent.update(@reg_name, fn state ->
92 initial_value = get_in(state, [:data, key]) || 0
93 updated_value = initial_value + increment
94 put_in(state, [:data, key], updated_value)
95 end)
96 end
97
98 defp persist_non_data_change(:state, value) do
99 with true <- get_data_key(:state) != value,
100 true <- value in Pleroma.DataMigration.State.__valid_values__(),
101 %{data_migration_id: data_migration_id} when not is_nil(data_migration_id) <-
102 state() do
103 DataMigration.update_one_by_id(data_migration_id, state: value)
104 else
105 false -> :ok
106 _ -> {:error, :nil_data_migration_id}
107 end
108 end
109
110 defp persist_non_data_change(_, _) do
111 nil
112 end
113
114 def data_migration_id, do: Map.get(state(), :data_migration_id)
115 end
116 end
117 end