|
| 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