Skip to content

Commit a2d1fcb

Browse files
committed
Add a helper module for PEP
Functionality: - publish an item - determine nodes to publish according to nodes_per_user - count pep notification and register TTD for each of them
1 parent f5a4152 commit a2d1fcb

1 file changed

Lines changed: 88 additions & 0 deletions

File tree

src/helpers/amoc_xmpp_pep.erl

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
-module(amoc_xmpp_pep).
2+
3+
-moduledoc """
4+
Building blocks for PEP (XEP-0163: Personal Eventing Protocol) scenarios:
5+
- Determining the names of nodes to publish (see nodes_per_user)
6+
- Item publishing (auto-create makes separate node creation unnecessary)
7+
- Counting incoming item notifications, and measuring TTD
8+
""".
9+
10+
-include_lib("escalus/include/escalus_xmlns.hrl").
11+
-include_lib("exml/include/exml.hrl").
12+
-include_lib("kernel/include/logger.hrl").
13+
14+
-export([init/0,
15+
publish_item/2,
16+
nodes_to_publish/0,
17+
received_handler_spec/0]).
18+
19+
-define(V(X), (fun amoc_config_validation:X/1)).
20+
21+
-required_variable(#{name => nodes_per_user, default_value => 1,
22+
verification => ?V(nonnegative_integer),
23+
description => "Number of PEP nodes each user publishes to"}).
24+
25+
-spec init() -> ok.
26+
init() ->
27+
amoc_metrics:init(counters, pubsub_items_published),
28+
amoc_metrics:init(counters, pubsub_notifications_received),
29+
amoc_metrics:init(counters, timeouts),
30+
amoc_metrics:init(times, pubsub_item_ttd),
31+
amoc_metrics:init(times, response),
32+
ok.
33+
34+
-spec nodes_to_publish() -> [binary()].
35+
nodes_to_publish() ->
36+
[node_name(NodeId) || NodeId <- lists:seq(1, cfg(nodes_per_user))].
37+
38+
-spec received_handler_spec() -> [amoc_xmpp_handlers:handler_spec()].
39+
received_handler_spec() ->
40+
[{fun is_pep_notification/1,
41+
fun record_pep_notification/3}].
42+
43+
-spec publish_item(escalus:client(), escalus_pubsub_stanza:pubsub_node_name()) -> ok.
44+
publish_item(Client, Node) ->
45+
Id = escalus_stanza:id(),
46+
Req = escalus_pubsub_stanza:publish(item_content(Client), Id, Node),
47+
Pred = fun(Stanza) -> escalus_pred:is_iq_result(Req, Stanza) end,
48+
Resp = amoc_xmpp:send_request_and_get_response(Client, Req, Pred, response, 10000),
49+
?LOG_DEBUG("~s got PEP publish response ~p", [escalus_client:username(Client), Resp]),
50+
amoc_metrics:update_counter(pubsub_items_published).
51+
52+
-spec item_content(escalus:client()) -> exml:element().
53+
item_content(Client) ->
54+
#xmlel{
55+
name = ~"entry",
56+
attrs = #{~"timestamp" => integer_to_binary(os:system_time(microsecond)),
57+
~"jid" => escalus_client:short_jid(Client)},
58+
children = [#xmlcdata{content = cfg(message_body)}]}.
59+
60+
-spec node_name(pos_integer()) -> binary().
61+
node_name(NodeId) ->
62+
iolist_to_binary([~"test-node-", integer_to_binary(NodeId)]).
63+
64+
-spec is_pep_notification(exml:element()) -> boolean().
65+
is_pep_notification(Stanza = #xmlel{name = ~"message"}) ->
66+
EventXmlns = exml_query:path(Stanza, [{element, ~"event"}, {attr, ~"xmlns"}]),
67+
Items = exml_query:path(Stanza, [{element, ~"event"}, {element, ~"items"}]),
68+
EventXmlns =:= ?NS_PUBSUB_EVENT andalso Items =/= undefined;
69+
is_pep_notification(_) ->
70+
false.
71+
72+
-spec record_pep_notification(escalus:client(), exml:element(),
73+
escalus_connection:metadata()) -> ok.
74+
record_pep_notification(Client, Stanza, Metadata) ->
75+
?LOG_DEBUG("~s received PEP notification ~p", [escalus_client:username(Client), Stanza]),
76+
amoc_metrics:update_counter(pubsub_notifications_received),
77+
update_pubsub_item_ttd(Stanza, Metadata).
78+
79+
-spec update_pubsub_item_ttd(exml:element(), escalus_connection:metadata()) -> ok.
80+
update_pubsub_item_ttd(Stanza, #{recv_timestamp := RecvTimestamp}) ->
81+
Timestamp = exml_query:path(Stanza, [{element, ~"event"},
82+
{element, ~"items"},
83+
{element, ~"item"},
84+
{element, ~"entry"},
85+
{attr, ~"timestamp"}]),
86+
amoc_metrics:update_time(pubsub_item_ttd, RecvTimestamp - binary_to_integer(Timestamp)).
87+
88+
cfg(Name) -> amoc_config:get(Name).

0 commit comments

Comments
 (0)