hitbox_actix/messages.rs
1//! QueryCache message declaration and converting.
2use actix::{dev::MessageResponse, prelude::*};
3use hitbox::{CacheError, Cacheable};
4
5/// Trait describes coversion from any [actix::Message] into QueryCache message.
6pub trait IntoCache: Cacheable {
7 /// Helper method to convert Message into [QueryCache] message.
8 ///
9 /// # Examples
10 /// ```
11 /// use actix::prelude::*;
12 /// use hitbox_actix::prelude::*;
13 /// use serde::Serialize;
14 ///
15 /// struct Upstream;
16 ///
17 /// impl Actor for Upstream {
18 /// type Context = Context<Self>;
19 /// }
20 ///
21 /// #[derive(Cacheable, Serialize, Message, Debug, PartialEq)]
22 /// #[rtype(result = "()")]
23 /// struct QueryNothing {
24 /// id: Option<i32>,
25 /// }
26 ///
27 /// #[actix_rt::main]
28 /// async fn main() {
29 /// let upstream = Upstream.start();
30 /// let query = QueryNothing { id: Some(1) }
31 /// .into_cache(&upstream);
32 /// }
33 /// ```
34 fn into_cache<A>(self, upstream: &Addr<A>) -> QueryCache<A, Self>
35 where
36 A: Actor,
37 Self: Message + Send + Sized,
38 Self::Result: MessageResponse<A, Self> + Send + 'static,
39 {
40 QueryCache {
41 upstream: upstream.clone(),
42 message: self,
43 }
44 }
45}
46
47impl<M: Message + Cacheable> IntoCache for M {}
48
49/// Intermediate actix message which handled by Cache actor.
50///
51/// This message a product of upstream message and upstream actor address.
52/// In other words, QueryCache is a struct that includes base message with user data
53/// and address of an actor that is a recipient of this message.
54/// You can only send QueryCache messages to Cache actor.
55pub struct QueryCache<A, M>
56where
57 M: Message + Cacheable + Send,
58 M::Result: MessageResponse<A, M> + Send,
59 A: Actor,
60{
61 pub(crate) upstream: Addr<A>,
62 pub(crate) message: M,
63}
64
65impl<A, M> QueryCache<A, M>
66where
67 M: Message + Cacheable + Send,
68 M::Result: MessageResponse<A, M> + Send,
69 A: Actor,
70{
71 /// Returns upstream actor type name or <Unknown>.
72 pub(crate) fn upstream_name(&self) -> &'static str {
73 std::any::type_name::<A>()
74 .rsplit("::")
75 .next()
76 .unwrap_or("<Unknown>")
77 }
78
79 /// Returns final cache key.
80 ///
81 /// This method compose final cache key from Cacheable::cache_key
82 /// and Upstream actor type name.
83 pub fn cache_key(&self) -> Result<String, CacheError> {
84 Ok(format!(
85 "{}::{}",
86 self.upstream_name(),
87 self.message.cache_key()?
88 ))
89 }
90}
91
92impl<'a, A, M> Message for QueryCache<A, M>
93where
94 A: Actor,
95 M: Message + Cacheable + Send,
96 M::Result: MessageResponse<A, M> + Send,
97{
98 type Result = Result<<M as Message>::Result, CacheError>;
99}