svc_agent/
lib.rs

1//! # Overview
2//!
3//! svc-agent is a library implementing common MQTT agent messaging pattern conventions and
4//! abstracting out the protocol's specifics to enable building microservices with full-duplex
5//! communication.
6//!
7//! On the broker side its counterpart is
8//! [mqtt-gateway](https://github.com/netology-group/mqtt-gateway) plugin for
9//! [VerneMQ](https://vernemq.com/).
10//!
11//! # Key concepts
12//!
13//! svc-agent is about exchanging messages between agents using pub-sub model.
14//!
15//! An agent is a service or end user who can publish and [subscribe](struct.Subscription.html)
16//! to messages. Each agent has a unique [AgentId](struct.Agent.Id).
17//!
18//! Message can be of three types:
19//!
20//! 1. **Requests** that end users send to services. Services may call other services too.
21//! 2. **Responses** that services send back.
22//! 3. **Events** that just may happen in services and it pushes a notification to subscribers.
23//!
24//! Each outgoing message has a [Destination](enum.Destination.html) and each incoming message has a
25//! [Source](enum.Source.html) which can also be of three types:
26//!
27//! 1. **Broadcast** that is being received by each of the subscribed agents.
28//! 2. **Multicast** that is being received by only one agent of a
29//! [SharedGroup](struct.SharedGroup.html) of subscribers.
30//! 3. **Unicast** that is intended for a specific agent.
31
32use std::fmt;
33use std::str::FromStr;
34
35////////////////////////////////////////////////////////////////////////////////
36
37/// Something that can be addressed as agent.
38pub trait Addressable: Authenticable {
39    /// Returns the [AgentId](struct.AgentId.html) reference of the addressable object.
40    fn as_agent_id(&self) -> &AgentId;
41}
42
43////////////////////////////////////////////////////////////////////////////////
44
45/// Agent identifier.
46///
47/// It consists of a string `label` and [AccountId](struct.AccountId.html) and must be unique.
48///
49/// Multiple agents may use the same [AccountId](struct.AccountId.html), e.g. multiple instances
50/// of the same service or multiple devices or browser tabs of an end user, but the `label`
51/// must be different across them. An agent identifier has to be unique, otherwise it gets
52/// disconnected by the broker. You can safely use the same `label` if
53/// [AccountId](struct.AccountId.html) is different.
54#[derive(Debug, Clone, PartialEq, Eq, Hash)]
55pub struct AgentId {
56    account_id: AccountId,
57    label: String,
58}
59
60#[cfg(feature = "sqlx")]
61impl sqlx::encode::Encode<'_, sqlx::Postgres> for AgentId
62where
63    AccountId: for<'q> sqlx::encode::Encode<'q, sqlx::Postgres>,
64    AccountId: sqlx::types::Type<sqlx::Postgres>,
65    String: for<'q> sqlx::encode::Encode<'q, sqlx::Postgres>,
66    String: sqlx::types::Type<sqlx::Postgres>,
67{
68    fn encode_by_ref(&self, buf: &mut sqlx::postgres::PgArgumentBuffer) -> sqlx::encode::IsNull {
69        let mut encoder = sqlx::postgres::types::PgRecordEncoder::new(buf);
70        encoder.encode(&self.account_id);
71        encoder.encode(&self.label);
72        encoder.finish();
73        sqlx::encode::IsNull::No
74    }
75    fn size_hint(&self) -> usize {
76        2usize * (4 + 4)
77            + <AccountId as sqlx::encode::Encode<sqlx::Postgres>>::size_hint(&self.account_id)
78            + <String as sqlx::encode::Encode<sqlx::Postgres>>::size_hint(&self.label)
79    }
80}
81
82// This is what `derive(sqlx::Type)` expands to but with fixed lifetime.
83// https://github.com/launchbadge/sqlx/issues/672
84#[cfg(feature = "sqlx")]
85impl<'r> sqlx::decode::Decode<'r, sqlx::Postgres> for AgentId
86where
87    // Originally it was `AccountId: sqlx::decode::Decode<'r, sqlx::Postgres>,`
88    AccountId: for<'q> sqlx::decode::Decode<'q, sqlx::Postgres>,
89    AccountId: sqlx::types::Type<sqlx::Postgres>,
90    String: sqlx::decode::Decode<'r, sqlx::Postgres>,
91    String: sqlx::types::Type<sqlx::Postgres>,
92{
93    fn decode(
94        value: sqlx::postgres::PgValueRef<'r>,
95    ) -> std::result::Result<Self, Box<dyn std::error::Error + 'static + Send + Sync>> {
96        let mut decoder = sqlx::postgres::types::PgRecordDecoder::new(value)?;
97        let account_id = decoder.try_decode::<AccountId>()?;
98        let label = decoder.try_decode::<String>()?;
99        Ok(AgentId { account_id, label })
100    }
101}
102
103#[cfg(feature = "sqlx")]
104impl sqlx::Type<sqlx::Postgres> for AgentId {
105    fn type_info() -> sqlx::postgres::PgTypeInfo {
106        sqlx::postgres::PgTypeInfo::with_name("agent_id")
107    }
108}
109
110#[cfg(feature = "sqlx")]
111impl sqlx::postgres::PgHasArrayType for AgentId {
112    fn array_type_info() -> sqlx::postgres::PgTypeInfo {
113        // https://github.com/launchbadge/sqlx/issues/1004#issuecomment-1019438437
114        sqlx::postgres::PgTypeInfo::with_name("_agent_id")
115    }
116}
117
118#[cfg(feature = "sqlx")]
119impl sqlx::postgres::PgHasArrayType for &AgentId {
120    fn array_type_info() -> sqlx::postgres::PgTypeInfo {
121        // https://github.com/launchbadge/sqlx/issues/1004#issuecomment-1019438437
122        sqlx::postgres::PgTypeInfo::with_name("_agent_id")
123    }
124}
125
126impl AgentId {
127    /// Builds an [AgentId](struct.AgentId.html).
128    ///
129    /// # Arguments
130    ///
131    /// * `label` – a unique string to identify the particular agent.
132    /// For example the name of a service instance or a user device.
133    ///
134    /// * `account_id` – the account identifier of an agent.
135    ///
136    /// # Example
137    ///
138    /// ```
139    /// let agent_id1 = AgentId::new("instance01", AccountId::new("service_name", "svc.example.org"));
140    /// let agent_id2 = AgentId::new("web", AccountId::new("user_name", "usr.example.org"));
141    /// ```
142    pub fn new<S: Into<String>>(label: S, account_id: AccountId) -> Self {
143        Self {
144            label: label.into(),
145            account_id,
146        }
147    }
148
149    pub fn label(&self) -> &str {
150        &self.label
151    }
152}
153
154impl fmt::Display for AgentId {
155    /// Formats [AgentId](struct.AgentId.html) as `LABEL.ACCOUNT_ID`.
156    ///
157    /// # Example
158    ///
159    /// ```
160    /// let agent_id = AgentId::new("instance01", AccountId::new("service_name", "svc.example.org"));
161    /// format!("{}", agent_id); // => "instance01.service_name.svc.example.org"
162    /// ```
163    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
164        write!(fmt, "{}.{}", self.label(), self.account_id)
165    }
166}
167
168impl FromStr for AgentId {
169    type Err = Error;
170
171    /// Parses [AgentId](struct.AgentId.html) from `LABEL.ACCOUNT_ID` format.
172    ///
173    /// # Example
174    ///
175    /// ```
176    /// let agent_id = AgentId::from_str("instance01.service_name.svc.example.org"));
177    /// ```
178    fn from_str(val: &str) -> Result<Self, Self::Err> {
179        let parts: Vec<&str> = val.splitn(2, '.').collect();
180        match parts[..] {
181            [label, rest] => {
182                let account_id = rest.parse::<AccountId>().map_err(|e| {
183                    Error::new(&format!(
184                        "error deserializing shared group from a string, {}",
185                        &e
186                    ))
187                })?;
188                Ok(Self::new(label, account_id))
189            }
190            _ => Err(Error::new(&format!(
191                "invalid value for the agent id: {}",
192                val
193            ))),
194        }
195    }
196}
197
198impl Authenticable for AgentId {
199    fn as_account_id(&self) -> &AccountId {
200        &self.account_id
201    }
202}
203
204impl Addressable for AgentId {
205    fn as_agent_id(&self) -> &Self {
206        self
207    }
208}
209
210////////////////////////////////////////////////////////////////////////////////
211
212/// A group of agents which [shares a subscription](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901250).
213/// Commonly used for balancing requests over a group of instances of some service.
214#[derive(Debug, Clone, PartialEq, Eq, Hash)]
215pub struct SharedGroup {
216    label: String,
217    account_id: AccountId,
218}
219
220impl SharedGroup {
221    /// Builds a [SharedGroup](struct.SharedGroup).
222    ///
223    /// # Arguments
224    ///
225    /// * `label` – shared group label to distinct it from the others if there are any.
226    /// * `account_id` – service account id. All the group's participant agents must have the same.
227    ///
228    /// # Example
229    ///
230    /// ```
231    /// let_account_id = AccountId::new("service_name", "svc.example.org");
232    /// let shared_group = SharedGroup::new("loadbalancer", account_id);
233    /// ```
234    pub fn new(label: &str, account_id: AccountId) -> Self {
235        Self {
236            label: label.to_owned(),
237            account_id,
238        }
239    }
240}
241
242impl fmt::Display for SharedGroup {
243    /// Formats [SharedGroup](struct.SharedGroup.html) as `LABEL.ACCOUNT_ID`.
244    ///
245    /// # Example
246    ///
247    /// ```
248    /// let_account_id = AccountId::new("service_name", "svc.example.org");
249    /// let shared_group = SharedGroup::new("loadbalancer", account_id);
250    /// format!("{}", shared_group); // => "loadbalancer.service_name.svc.example.org"
251    /// ```
252    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
253        write!(f, "{}.{}", self.label, self.account_id)
254    }
255}
256
257impl FromStr for SharedGroup {
258    type Err = Error;
259
260    /// Parses [SharedGroup](struct.SharedGroup.html) from `LABEL.ACCOUNT_ID` format.
261    ///
262    /// # Example
263    ///
264    /// ```
265    /// let shared_group = SharedGroup::from_str("loadbalancer.service_name.svc.example.org"));
266    /// ```
267    fn from_str(val: &str) -> Result<Self, Self::Err> {
268        let parts: Vec<&str> = val.splitn(2, '.').collect();
269        match parts[..] {
270            [label, rest] => {
271                let account_id = rest.parse::<AccountId>().map_err(|e| {
272                    Error::new(&format!(
273                        "error deserializing shared group from a string, {}",
274                        &e
275                    ))
276                })?;
277                Ok(Self::new(label, account_id))
278            }
279            _ => Err(Error::new(&format!(
280                "invalid value for the application group: {}",
281                val
282            ))),
283        }
284    }
285}
286
287////////////////////////////////////////////////////////////////////////////////
288
289/// Message destination.
290///
291/// This is an abstraction over MQTT topic pattern to determine outgoing message's publish topic.
292///
293/// Understanding message routing is the key thing to use svc-agent.
294/// Make sure that you understand the patterns below and their counterparts described in
295/// [Source](enum.Source.html).
296///
297/// ### MQTT topic variables:
298///
299/// * `MY_ACCOUNT_ID` – [AccountId](struct.AccountId) of the current agent that sends the message.
300/// * `MY_VER` – API version string of the current agent. For example: `v1`.
301/// * `MY_BROADCAST_URI`– current agent's API specific path to some resource divided by `/`.
302/// For example: `/rooms/ROOM_ID/events`. If you will want to change its structure in the future
303/// you must also bump `VER(ME)`.
304/// * `ACCOUNT_ID` – destination [AccountId](struct.AccountId) (no specific agent).
305/// * `AGENT_ID` – destination [AgentId](struct.AgentId).
306/// * `VER` – destination agent version.
307#[derive(Debug)]
308pub enum Destination {
309    /// Publish a message to each of the topic subscribers.
310    ///
311    /// Typically being used for publishing notification events from a service.
312    ///
313    /// The string supplied is `MY_BROADCAST_URI`.
314    ///
315    /// ### Patterns
316    ///
317    /// | Type  | Pattern    | MQTT topic                                           |
318    /// |-------|------------|------------------------------------------------------|
319    /// | event | app-to-any | apps/`MY_ACCOUNT_ID`/api/`MY_VER`/`MY_BROADCAST_URI` |
320    Broadcast(String),
321    /// Publish a message to any single of [SharedGroup](struct.SharedGroup.html) agents.
322    ///
323    /// Typically being used for sending requests to services which may have multiple instances.
324    ///
325    /// [AccountId](struct.AccountId.html) is being supplied since we don't care which specific
326    /// instance will process the message.
327    ///
328    /// ### Patterns
329    ///
330    /// | Type     | Pattern     | MQTT topic                                         |
331    /// |----------|-------------|----------------------------------------------------|
332    /// | request  | one-to_app  | agents/`MY_AGENT_ID`/api/`MY_VER`/out/`ACCOUNT_ID` |
333    Multicast(AccountId, String),
334    /// Publish a message to the specific instance with known `AGENT_ID`.
335    ///
336    /// Typically being used for responding to requests.
337    /// Also used for making a request to a specific instance of a stateful service.
338    ///
339    /// Values supplied are `AGENT_ID` and `VER`.
340    ///
341    /// ### Patterns
342    ///
343    /// | Type     | Pattern     | MQTT topic                                     |
344    /// |----------|-------------|------------------------------------------------|
345    /// | request  | one-to-one  | agents/`AGENT_ID`/api/`VER`/in/`MY_ACCOUNT_ID` |
346    /// | response | one-to_one  | agents/`AGENT_ID`/api/`VER`/in/`MY_ACCOUNT_ID` |
347    Unicast(AgentId, String),
348}
349
350////////////////////////////////////////////////////////////////////////////////
351
352/// Message source.
353///
354/// This is an abstraction over MQTT topic pattern to determine the subscription topic to receive
355/// messages.
356///
357/// If you want to subscribe to a topic consider using [Subscription](struct.Subscription.html)
358/// builder or building [RequestSubscription](struct.RequestSubscription.html),
359/// [ResponseSubscription](struct.ResponseSubscription.html) or
360/// [EventSubscription](struct.EventSubscription.html) directly when you need something special.
361///
362/// Understanding message routing is the key thing to use svc-agent.
363/// Make sure that you understand the patterns below and their counterparts described in
364/// [Destination](enum.Destination.html).
365///
366/// ### MQTT topic variables:
367///
368/// * `MY_ACCOUNT_ID` – [AccountId](struct.AccountId) of the current agent that send the message.
369/// * `MY_VER` – API version string of the current agent. For example: `v1`.
370/// * `ACCOUNT_ID` – source [AccountId](struct.AccountId) (no specific agent).
371/// * `AGENT_ID` – source [AgentId](struct.AgentId).
372/// * `VER` – source agent version.
373/// * `BROADCAST_URI` source agent's API specific path to some resource divided by `/`.
374/// For example: `/rooms/ROOM_ID/events`. Use `+` as single-level wildcard like `/room/+/events`
375/// to subscribe to events in all rooms and `#` as multi-level  wildcard like `/rooms/#` to
376/// subscribe to all rooms and their nested resources.
377#[derive(Debug)]
378pub enum Source<'a> {
379    /// Receive a message along with other subscribers.
380    ///
381    /// Typically used for receiving notification events from a service.
382    ///
383    /// Value supplied are `ACCOUNT_ID`, `VER` and `BROADCAST_URI`.
384    ///
385    /// ### Patterns
386    ///
387    /// | Type  | Pattern      | MQTT topic                                  |
388    /// |-------|--------------|---------------------------------------------|
389    /// | event | any-from-app | apps/`ACCOUNT_ID`/api/`VER`/`BROADCAST_URI` |
390    Broadcast(&'a AccountId, &'a str, &'a str),
391    /// Receive a message from any single of [SharedGroup](struct.SharedGroup.html) agents.
392    ///
393    /// Typically used for receiving requests by services which may have multiple instances.
394    ///
395    /// [AccountId](struct.AccountId.html) is being supplied since we don't care which specific
396    /// instance will process the message.
397    ///
398    /// Optional values supplied are `AGENT_ID` and `VER`. If `None` is specified for either of
399    /// the two then wildcard is being used to receive messages from any agent or its API version.
400    ///
401    /// ### Patterns
402    ///
403    /// | Type     | Pattern      | MQTT topic                                    |
404    /// |----------|--------------|-----------------------------------------------|
405    /// | request  | app-from-any | agents/+/api/+/out/`MY_ACCOUNT_ID`            |
406    /// | request  | app-from-any | agents/+/api/VER/out/`MY_ACCOUNT_ID`          |
407    /// | request  | app-from-any | agents/`AGENT_ID`/api/+/out/`MY_ACCOUNT_ID`   |
408    /// | request  | app-from-any | agents/`AGENT_ID`/api/VER/out/`MY_ACCOUNT_ID` |
409    Multicast(Option<&'a AgentId>, Option<&'a str>),
410    /// Receive a message sent specifically to the current agent by its `AGENT_ID`.
411    ///
412    /// Typically being used for receiving responses for requests.
413    /// Also used for receiving a request by a specific instance of a stateful service.
414    ///
415    /// Optional `ACCOUNT_ID` may be supplied to specify an [AccountId](struct.AccountId.html)
416    /// to subscribe to. If `None` is specified then wildcard is being used to receive unicast
417    /// messages from any account.
418    ///
419    /// ### Patterns
420    ///
421    /// | Type     | Pattern      | MQTT topic                                        |
422    /// |----------|--------------|---------------------------------------------------|
423    /// | request  | one-from-one | agents/`MY_AGENT_ID`/api/`MY_VER`/in/`ACCOUNT_ID` |
424    /// | request  | one-from-any | agents/`MY_AGENT_ID`/api/`MY_VER`/in/+            |
425    /// | response | one-from-one | agents/`MY_AGENT_ID`/api/`MY_VER`/in/`ACCOUNT_ID` |
426    /// | response | one-from-any | agents/`MY_AGENT_ID`/api/`MY_VER`/in/+            |
427    Unicast(Option<&'a AccountId>),
428}
429
430////////////////////////////////////////////////////////////////////////////////
431
432/// Messages subscription builder.
433pub struct Subscription {}
434
435impl Subscription {
436    /// Builds an [EventSubscription](struct.EventSubscription) for
437    /// [broadcast events](struct.Source.html#variant.Broadcast).
438    ///
439    /// Use it to subscribe to events from some service,
440    ///
441    /// # Arguments
442    ///
443    /// * `from` – anything [Addressable](trait.Addressable) to receive events from.
444    /// For example service [AgentId](struct.AgentId).
445    /// * `version` – API version string of the `from` agent. Example: `v1`.
446    /// * `uri` – resource path divided by `/` to receive events on. Example: `room/ROOM_ID/events`.
447    ///
448    /// # Example
449    ///
450    /// ```
451    /// let agent = AgentId::new("instance01", AccountId::new("service_name", "svc.example.org"));
452    /// let subscription = Subscription::broadcast_events(&agent, "v1", "rooms/123/events");
453    /// ```
454    pub fn broadcast_events<'a, A>(
455        from: &'a A,
456        version: &'a str,
457        uri: &'a str,
458    ) -> EventSubscription<'a>
459    where
460        A: Authenticable,
461    {
462        EventSubscription::new(Source::Broadcast(from.as_account_id(), version, uri))
463    }
464
465    /// Builds a [RequestSubscription](struct.RequestSubscription) for
466    /// [multicast requests](struct.Source#variant.Multicast) from any agent.
467    ///
468    /// Use it to subscribe a stateless service endpoint to its consumers' requests.
469    ///
470    /// # Arguments
471    ///
472    /// * `version` – API version string of the `from` agent. Example: `v1`.
473    ///
474    /// # Example
475    ///
476    /// ```
477    /// let subscription = Subscription::multicast_requests("v1");
478    /// ```
479    pub fn multicast_requests(version: Option<&str>) -> RequestSubscription {
480        RequestSubscription::new(Source::Multicast(None, version))
481    }
482
483    /// Builds a [RequestSubscription](struct.RequestSubscription) for
484    /// [multicast requests](struct.Source#variant.Multicast) from a specific agent.
485    ///
486    /// This is the same as [multicast_requests](struct.Subscription.html#method.multicast_requests)
487    /// but subscribes only from requests from a specific agent.
488    ///
489    /// # Arguments
490    ///
491    /// * `from` – anything [Addressable](trait.Addressable) to receive requests from.
492    /// For example service [AgentId](struct.AgentId).
493    /// * `version` – API version string of the `from` agent. Example: `v1`.
494    ///
495    /// # Example
496    ///
497    /// ```
498    /// let agent = AgentId::new("instance01", AccountId::new("service_name", "svc.example.org"));
499    /// let subscription = Subscription::multicast_requests_from(&agent, "v1");
500    /// ```
501    pub fn multicast_requests_from<'a, A>(
502        from: &'a A,
503        version: Option<&'a str>,
504    ) -> RequestSubscription<'a>
505    where
506        A: Addressable,
507    {
508        RequestSubscription::new(Source::Multicast(Some(from.as_agent_id()), version))
509    }
510
511    /// Builds a [RequestSubscription](struct.RequestSubscription) for
512    /// [unicast requests](struct.Source#variant.Unicast) from any agent.
513    ///
514    /// Use it to subscribe a stateful service endpoint to its consumers' requests.
515    ///
516    /// # Example
517    ///
518    /// ```
519    /// let subscription = Subscription::unicast_requests();
520    /// ```
521    pub fn unicast_requests<'a>() -> RequestSubscription<'a> {
522        RequestSubscription::new(Source::Unicast(None))
523    }
524
525    /// Builds a [RequestSubscription](struct.RequestSubscription) for
526    /// [unicast requests](struct.Source#variant.Unicast) from a specific agent.
527    ///
528    /// This is the same as [unicast_requests](struct.Subscription.html#method.unicast_requests)
529    /// but subscribes only from requests from a specific agent.
530    ///
531    /// # Arguments
532    ///
533    /// * `from` – anything [Addressable](trait.Addressable) to receive requests from.
534    /// For example service [AgentId](struct.AgentId).
535    ///
536    /// # Example
537    ///
538    /// ```
539    /// let agent = AgentId::new("instance01", AccountId::new("service_name", "svc.example.org"));
540    /// let subscription = Subscription::unicast_requests(&agent);
541    /// ```
542    pub fn unicast_requests_from<A>(from: &A) -> RequestSubscription
543    where
544        A: Authenticable,
545    {
546        RequestSubscription::new(Source::Unicast(Some(from.as_account_id())))
547    }
548
549    /// Builds a [ResponseSubscription](struct.ResponseSubscription) for
550    /// [unicast requests](struct.Source#variant.Unicast) from any agent.
551    ///
552    /// Use it to subscribe to responses from all services.
553    ///
554    /// # Example
555    ///
556    /// ```
557    /// let subscription = Subscription::unicast_responses();
558    /// ```
559    pub fn unicast_responses<'a>() -> ResponseSubscription<'a> {
560        ResponseSubscription::new(Source::Unicast(None))
561    }
562
563    /// Builds a [ResponseSubscription](struct.ResponseSubscription) for
564    /// [unicast requests](struct.Source#variant.Unicast) from a specific agent.
565    ///
566    /// This is the same as [unicast_responses](struct.Subscription.html#method.unicast_responses)
567    /// but subscribes only from requests from a specific agent.
568    ///
569    /// # Example
570    ///
571    /// ```
572    /// let agent = AgentId::new("instance01", AccountId::new("service_name", "svc.example.org"));
573    /// let subscription = Subscription::unicast_responses_from(&agent);
574    /// ```
575    pub fn unicast_responses_from<A>(from: &A) -> ResponseSubscription
576    where
577        A: Authenticable,
578    {
579        ResponseSubscription::new(Source::Unicast(Some(from.as_account_id())))
580    }
581}
582
583pub struct EventSubscription<'a> {
584    source: Source<'a>,
585}
586
587impl<'a> EventSubscription<'a> {
588    /// Builds an [EventSubscription](struct.EventSubscription).
589    ///
590    /// # Arguments
591    ///
592    /// * `source` – events source.
593    ///
594    /// # Example
595    ///
596    /// ```
597    /// let account_id = AccountId::new("service_name", "svc.example.org");
598    /// let source = Source::Broadcast(&account_id, "v1", "rooms/+/events");
599    /// let subscription = EventSubscription::new(source);
600    /// ```
601    pub fn new(source: Source<'a>) -> Self {
602        Self { source }
603    }
604}
605
606pub struct RequestSubscription<'a> {
607    source: Source<'a>,
608}
609
610impl<'a> RequestSubscription<'a> {
611    /// Builds a [RequestSubscription](struct.RequestSubscription).
612    ///
613    /// # Arguments
614    ///
615    /// * `source` – requests source.
616    ///
617    /// # Example
618    ///
619    /// ```
620    /// let subscription = RequestSubscription::new(Source::Multicast(None, "v1"));
621    /// ```
622    pub fn new(source: Source<'a>) -> Self {
623        Self { source }
624    }
625}
626
627pub struct ResponseSubscription<'a> {
628    source: Source<'a>,
629}
630
631impl<'a> ResponseSubscription<'a> {
632    /// Builds a [ResponseSubscription](struct.ResponseSubscription).
633    ///
634    /// # Arguments
635    ///
636    /// * `source` – responses source.
637    ///
638    /// # Example
639    ///
640    /// ```
641    /// let account_id = AccountId::new("service_name", "svc.example.org");
642    /// let subscription = RequestSubscription::new(Source::Unicast(&account_id));
643    /// ```
644    pub fn new(source: Source<'a>) -> Self {
645        Self { source }
646    }
647}
648
649////////////////////////////////////////////////////////////////////////////////
650
651pub use svc_authn::{AccountId, Authenticable};
652
653pub use self::error::Error;
654pub mod error;
655pub mod mqtt;
656#[cfg(feature = "queue-counter")]
657pub mod queue_counter;
658pub mod request;
659pub(crate) mod serde;