Skip to main content

fatline_rs/
posts.rs

1//! Types that are used by the various frontend implementations for posts / casts and their replies
2
3use crate::action::{CastAction, ReactionAction, ReactionInfo};
4use crate::proto::reactions_by_target_request::Target;
5use crate::proto::{CastsByParentRequest, ReactionType, ReactionsByTargetRequest};
6use crate::proto::embed::Embed as ProtoEmbed;
7use crate::utils::{cast_action_from_message, reaction_from_message};
8use crate::HubService;
9use async_trait::async_trait;
10use eyre::Result;
11use serde::{Deserialize, Serialize};
12
13/// The combined cast, holding all necessary values to display and query against
14#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Default)]
15pub struct Cast {
16    pub cast_id: CastId,
17    pub parent: Option<Parent>,
18    pub mentions: Vec<Mention>,
19    pub embeds: Vec<Embed>,
20    pub text: String,
21    /// In seconds
22    pub cast_time: u32
23}
24
25impl Cast {
26
27    fn new(text: Option<String>) -> Self {
28        Cast {
29            text: text.unwrap_or_default(),
30            ..Default::default()
31        }
32    }
33
34
35
36
37}
38
39#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
40pub struct Mention {
41    pub fid: u64,
42    pub start_pos: u32
43}
44
45#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
46pub enum Embed {
47    Url(String),
48    CastId(CastId)
49}
50
51impl Into<crate::proto::Embed> for Embed {
52    fn into(self) -> crate::proto::Embed {
53        let proto_embed = match self {
54            Embed::Url(string) => ProtoEmbed::Url(string),
55            Embed::CastId(cast) => ProtoEmbed::CastId(cast.into())
56        };
57        crate::proto::Embed {
58            embed: Some(proto_embed)
59        }
60    }
61}
62
63#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
64pub enum Parent {
65    Url(String),
66    CastId(CastId)
67}
68
69impl Into<Target> for Parent {
70    fn into(self) -> Target {
71        match self {
72            Parent::Url(url) => {
73                Target::TargetUrl(url)
74            }
75            Parent::CastId(cast_id) => {
76                Target::TargetCastId(cast_id.into())
77            }
78        }
79    }
80}
81
82impl Into<crate::proto::casts_by_parent_request::Parent> for Parent {
83    fn into(self) -> crate::proto::casts_by_parent_request::Parent {
84        match self {
85            Parent::Url(url) => {
86                crate::proto::casts_by_parent_request::Parent::ParentUrl(url)
87            }
88            Parent::CastId(id) => {
89                crate::proto::casts_by_parent_request::Parent::ParentCastId(
90                    crate::proto::CastId {
91                        fid: id.fid,
92                        hash: id.hash
93                    }
94                )
95            }
96        }
97    }
98}
99
100#[derive(Debug, Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Default)]
101pub struct CastId {
102    pub fid: u64,
103    pub hash: Vec<u8>
104}
105
106impl Into<crate::proto::CastId> for CastId {
107    fn into(self) -> crate::proto::CastId {
108        crate::proto::CastId {
109            fid: self.fid,
110            hash: self.hash,
111        }
112    }
113}
114
115/// A service to get merged user info form a hubble grpc service
116#[async_trait]
117pub trait PostService {
118    async fn get_post(&mut self, cast_id: CastId) -> Option<Cast>;
119    /// Get paged posts by a parent / url / cast hash.
120    ///
121    /// returns: `(the paged response, next page token)`
122    async fn get_posts_by_parent(&mut self, parent: Parent, page_token: Option<Vec<u8>>, page_size: Option<u32>, reverse: Option<bool>) -> Result<(Vec<Cast>, Option<Vec<u8>>)>;
123    async fn get_reacts_by_parent(&mut self, reaction_type: ReactionType, parent: Parent, page_token: Option<Vec<u8>>, page_size: Option<u32>, reverse: Option<bool>) -> Result<(Vec<ReactionInfo>, Option<Vec<u8>>)>;
124}
125
126#[async_trait]
127impl PostService for HubService {
128    async fn get_post(&mut self, cast_id: CastId) -> Option<Cast> {
129        let proto = crate::proto::CastId {
130            fid: cast_id.fid,
131            hash: cast_id.hash
132        };
133        let res = self.get_cast(proto).await.ok()?.into_inner();
134        match cast_action_from_message(res)? {
135            CastAction::CastAdd(cast) => Some(cast),
136            CastAction::CastRemove(_) => None
137        }
138    }
139
140    async fn get_posts_by_parent(&mut self, parent: Parent, page_token: Option<Vec<u8>>, page_size: Option<u32>, reverse: Option<bool>) -> Result<(Vec<Cast>, Option<Vec<u8>>)> {
141        let request = CastsByParentRequest {
142            page_size,
143            page_token,
144            reverse,
145            parent: Some(parent.into()),
146        };
147        let res = self.get_casts_by_parent(request).await?.into_inner();
148        let mut messages = Vec::new();
149        for message in res.messages {
150            if let Some(CastAction::CastAdd(add)) = cast_action_from_message(message) {
151                messages.push(add);
152            }
153        }
154        Ok((messages, res.next_page_token))
155    }
156
157    async fn get_reacts_by_parent(&mut self, reaction_type: ReactionType, parent: Parent, page_token: Option<Vec<u8>>, page_size: Option<u32>, reverse: Option<bool>) -> Result<(Vec<ReactionInfo>, Option<Vec<u8>>)> {
158        let request = ReactionsByTargetRequest {
159            reaction_type: Some(reaction_type.into()),
160            page_size,
161            page_token,
162            reverse,
163            target: Some(parent.into()),
164        };
165
166        let res = self.get_reactions_by_target(request).await?.into_inner();
167        let mut reactions = Vec::new();
168        for message in res.messages {
169            if let Some(react) = reaction_from_message(message) {
170                if let ReactionAction::Add(info) = react {
171                    reactions.push(info);
172                }
173            }
174        }
175        Ok((reactions, res.next_page_token))
176    }
177}