./ct_report/coverage/mod_pubsub_db.COVER.html

1 %%%----------------------------------------------------------------------
2 %%% File : mod_pubsub_db.erl
3 %%% Author : Piotr Nosek <piotr.nosek@erlang-solutions.com>
4 %%% Purpose : PubSub DB behaviour
5 %%% Created : 26 Oct 2018 by Piotr Nosek <piotr.nosek@erlang-solutions.com>
6 %%%----------------------------------------------------------------------
7
8 -module(mod_pubsub_db).
9 -author('piotr.nosek@erlang-solutions.com').
10
11 -include("mongoose_logger.hrl").
12
13 -export([db_error/3, extra_debug_fun/1]).
14
15 -ignore_xref([behaviour_info/1]).
16
17 %%====================================================================
18 %% Behaviour callbacks
19 %%====================================================================
20
21 %% ------------------------ Backend start/stop ------------------------
22
23 -callback init(HostType :: mongooseim:host_type(), gen_mod:module_opts()) -> ok.
24
25 -callback stop() -> ok.
26
27 %% ----------------------- Fun execution ------------------------
28
29 %% `ErrorDebug` are the maps of extra data that will be added to error tuple
30
31 -callback transaction(Fun :: fun(() -> {result | error, any()}),
32 ErrorDebug :: map()) ->
33 {result | error, any()}.
34
35 %% Synchronous
36 -callback dirty(Fun :: fun(() -> {result | error, any()}),
37 ErrorDebug :: map()) ->
38 {result | error, any()}.
39
40 %% ----------------------- Direct #pubsub_state access ------------------------
41
42 %% When a state is not found, returns empty state.
43 %% Maybe can be removed completely later?
44 -callback get_state(Nidx :: mod_pubsub:nodeIdx(),
45 JID :: jid:ljid()) ->
46 {ok, mod_pubsub:pubsubState()}.
47
48 %% Maybe can be removed completely later?
49 -callback get_states(Nidx :: mod_pubsub:nodeIdx()) ->
50 {ok, [mod_pubsub:pubsubState()]}.
51
52 -callback get_states_by_lus(JID :: jid:ljid()) ->
53 {ok, [mod_pubsub:pubsubState()]}.
54
55 -callback get_states_by_bare(JID :: jid:ljid()) ->
56 {ok, [mod_pubsub:pubsubState()]}.
57
58 -callback get_states_by_bare_and_full(JID :: jid:ljid()) ->
59 {ok, [mod_pubsub:pubsubState()]}.
60
61 -callback get_idxs_of_own_nodes_with_pending_subs(JID :: jid:ljid()) ->
62 {ok, [mod_pubsub:nodeIdx()]}.
63
64 %% ----------------------- Node management ------------------------
65 %% TODO this is not really node creation
66 -callback create_node(Nidx :: mod_pubsub:nodeIdx(),
67 Owner :: jid:ljid()) ->
68 ok.
69
70 -callback del_node(Nidx :: mod_pubsub:nodeIdx()) ->
71 {ok, [mod_pubsub:pubsubState()]}.
72
73 -callback set_node(Node :: mod_pubsub:pubsubNode()) -> {ok, mod_pubsub:nodeIdx()}.
74
75 -callback find_node_by_id(Nidx :: mod_pubsub:nodeIdx()) ->
76 {error, not_found} | {ok, mod_pubsub:pubsubNode()}.
77
78 -callback find_node_by_name(Key :: mod_pubsub:hostPubsub() | jid:ljid(), Node :: mod_pubsub:nodeId()) ->
79 mod_pubsub:pubsubNode() | false.
80
81 -callback find_nodes_by_key(Key :: mod_pubsub:hostPubsub() | jid:ljid()) ->
82 [mod_pubsub:pubsubNode()].
83
84 -callback delete_node(Node :: mod_pubsub:pubsubNode()) -> ok.
85
86 -callback get_subnodes(Key :: mod_pubsub:hostPubsub() | jid:ljid(), Node :: mod_pubsub:nodeId() | <<>>) ->
87 [mod_pubsub:pubsubNode()].
88
89 -callback get_parentnodes_tree(Key :: mod_pubsub:hostPubsub() | jid:ljid(), Node :: mod_pubsub:nodeId()) ->
90 [{Depth::non_neg_integer(), Nodes::[mod_pubsub:pubsubNode(), ...]}].
91
92 -callback get_subnodes_tree(Key :: mod_pubsub:hostPubsub() | jid:ljid(), Node :: mod_pubsub:nodeId()) ->
93 [{Depth::non_neg_integer(), Nodes::[mod_pubsub:pubsubNode(), ...]}].
94
95 %% ----------------------- Affiliations ------------------------
96
97 -callback set_affiliation(Nidx :: mod_pubsub:nodeIdx(),
98 JID :: jid:ljid(),
99 Affiliation :: mod_pubsub:affiliation()) ->
100 ok.
101
102 -callback get_affiliation(Nidx :: mod_pubsub:nodeIdx(),
103 JID :: jid:ljid()) ->
104 {ok, mod_pubsub:affiliation()}.
105
106 %% ----------------------- Subscriptions ------------------------
107
108 -callback add_subscription(Nidx :: mod_pubsub:nodeIdx(),
109 JID :: jid:ljid(),
110 Sub :: mod_pubsub:subscription(),
111 SubId :: mod_pubsub:subId(),
112 SubOpts :: mod_pubsub:subOptions()) ->
113 ok.
114
115 -callback update_subscription(Nidx :: mod_pubsub:nodeIdx(),
116 JID :: jid:ljid(),
117 Subscription :: mod_pubsub:subscription(),
118 SubId :: mod_pubsub:subId()) ->
119 ok.
120
121 -callback set_subscription_opts(Nidx :: mod_pubsub:nodeIdx(),
122 JID :: jid:ljid(),
123 SubId :: mod_pubsub:subId(),
124 Opts :: mod_pubsub:subOptions()) ->
125 ok.
126
127 -callback get_node_subscriptions(Nidx :: mod_pubsub:nodeIdx()) ->
128 {ok, [{Entity :: jid:ljid(),
129 Sub :: mod_pubsub:subscription(),
130 SubId :: mod_pubsub:subId(),
131 SubOpts :: mod_pubsub:subOptions()}]}.
132
133 -callback get_node_entity_subscriptions(Nidx :: mod_pubsub:nodeIdx(),
134 JID :: jid:ljid()) ->
135 {ok, [{Sub :: mod_pubsub:subscription(),
136 SubId :: mod_pubsub:subId(),
137 SubOpts :: mod_pubsub:subOptions()}]}.
138
139 -callback delete_subscription(
140 Nidx :: mod_pubsub:nodeIdx(),
141 JID :: jid:ljid(),
142 SubId :: mod_pubsub:subId()) ->
143 ok.
144
145 -callback delete_all_subscriptions(
146 Nidx :: mod_pubsub:nodeIdx(),
147 JID :: jid:ljid()) ->
148 ok.
149
150 %% ----------------------- Items ------------------------
151
152 %% TODO: Refactor to use MaxItems value, so separate remove_items in publishing
153 %% won't be necessary and the whole operation may be optimised in DB layer.
154 -callback add_item(Nidx :: mod_pubsub:nodeIdx(),
155 JID :: jid:ljid(),
156 PubSubItem :: mod_pubsub:pubsubItem()) ->
157 ok.
158
159 -callback remove_items(Nidx :: mod_pubsub:nodeIdx(),
160 JID :: jid:ljid(),
161 ItemIds :: [mod_pubsub:itemId()]) ->
162 ok.
163
164 -callback remove_all_items(Nidx :: mod_pubsub:nodeIdx()) ->
165 ok.
166
167 -callback get_items(Nidx :: mod_pubsub:nodeIdx(), gen_pubsub_node:get_item_options()) ->
168 {ok, {[mod_pubsub:pubsubItem()], jlib:rsm_out() | none}}.
169
170 -callback get_item(Nidx :: mod_pubsub:nodeIdx(), ItemId :: mod_pubsub:itemId()) ->
171 {ok, mod_pubsub:pubsubItem()} | {error, item_not_found}.
172
173 -callback set_item(Item :: mod_pubsub:pubsubItem()) -> ok.
174
175 -callback del_item(Nidx :: mod_pubsub:nodeIdx(), ItemId :: mod_pubsub:itemId()) -> ok.
176
177 -callback del_items(Nidx :: mod_pubsub:nodeIdx(), [ItemId :: mod_pubsub:itemId()]) -> ok.
178
179 %% ----------------------- GDPR-related ------------------------
180
181 -callback get_user_payloads(LUser :: jid:luser(), LServer :: jid:lserver()) ->
182 [NodeNameItemIDAndPayload :: [binary()]].
183
184 -callback get_user_nodes(LUser :: jid:luser(), LServer :: jid:lserver()) ->
185 [NodeNameAndType :: [binary()]].
186
187 -callback get_user_subscriptions(LUser :: jid:luser(), LServer :: jid:lserver()) ->
188 [NodeName :: [binary()]].
189
190 -callback find_nodes_by_affiliated_user(JID :: jid:ljid()) ->
191 [{mod_pubsub:pubsubNode(), mod_pubsub:affiliation()}].
192
193 -callback delete_user_subscriptions(JID :: jid:ljid()) ->
194 ok.
195
196 %%====================================================================
197 %% API
198 %%====================================================================
199
200 % ReasonData may either be a debug map provided by mod_pubsub
201 % or some other term if the crash is serious enough to lose the debug map somewhere.
202 -spec db_error(ReasonData :: map() | any(), ErrorDebug :: map(), Event :: any()) ->
203 {error, Details :: map()}.
204 db_error(ReasonData, ErrorDebug, Event) ->
205
:-(
{error, maps:merge(ErrorDebug#{ event => Event }, sanitize_reason(ReasonData))}.
206
207 %% transaction and sync_dirty return very truncated error data so we add extra
208 %% try to gather stack trace etc.
209 -spec extra_debug_fun(fun()) -> fun().
210 extra_debug_fun(Fun) ->
211 2075 fun() ->
212 2075 try Fun() of
213 2059 Res -> Res
214 catch
215 C:R:S ->
216 16 throw(#{
217 class => C,
218 reason => R,
219 stacktrace => S})
220 end
221 end.
222
223 %%====================================================================
224 %% Internal functions
225 %%====================================================================
226
227 sanitize_reason(Map) when is_map(Map) ->
228
:-(
Map;
229 sanitize_reason(Other) ->
230
:-(
#{ unexpected_reason => Other }.
231
Line Hits Source