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;