use crate::action::{CastAction, ReactionAction, ReactionInfo};
use crate::proto::reactions_by_target_request::Target;
use crate::proto::{CastsByParentRequest, ReactionType, ReactionsByTargetRequest};
use crate::proto::embed::Embed as ProtoEmbed;
use crate::utils::{cast_action_from_message, reaction_from_message};
use crate::HubService;
use async_trait::async_trait;
use eyre::Result;
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Default)]
pub struct Cast {
pub cast_id: CastId,
pub parent: Option<Parent>,
pub mentions: Vec<Mention>,
pub embeds: Vec<Embed>,
pub text: String,
pub cast_time: u32
}
impl Cast {
fn new(text: Option<String>) -> Self {
Cast {
text: text.unwrap_or_default(),
..Default::default()
}
}
}
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct Mention {
pub fid: u64,
pub start_pos: u32
}
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub enum Embed {
Url(String),
CastId(CastId)
}
impl Into<crate::proto::Embed> for Embed {
fn into(self) -> crate::proto::Embed {
let proto_embed = match self {
Embed::Url(string) => ProtoEmbed::Url(string),
Embed::CastId(cast) => ProtoEmbed::CastId(cast.into())
};
crate::proto::Embed {
embed: Some(proto_embed)
}
}
}
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub enum Parent {
Url(String),
CastId(CastId)
}
impl Into<Target> for Parent {
fn into(self) -> Target {
match self {
Parent::Url(url) => {
Target::TargetUrl(url)
}
Parent::CastId(cast_id) => {
Target::TargetCastId(cast_id.into())
}
}
}
}
impl Into<crate::proto::casts_by_parent_request::Parent> for Parent {
fn into(self) -> crate::proto::casts_by_parent_request::Parent {
match self {
Parent::Url(url) => {
crate::proto::casts_by_parent_request::Parent::ParentUrl(url)
}
Parent::CastId(id) => {
crate::proto::casts_by_parent_request::Parent::ParentCastId(
crate::proto::CastId {
fid: id.fid,
hash: id.hash
}
)
}
}
}
}
#[derive(Debug, Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Default)]
pub struct CastId {
pub fid: u64,
pub hash: Vec<u8>
}
impl Into<crate::proto::CastId> for CastId {
fn into(self) -> crate::proto::CastId {
crate::proto::CastId {
fid: self.fid,
hash: self.hash,
}
}
}
#[async_trait]
pub trait PostService {
async fn get_post(&mut self, cast_id: CastId) -> Option<Cast>;
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>>)>;
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>>)>;
}
#[async_trait]
impl PostService for HubService {
async fn get_post(&mut self, cast_id: CastId) -> Option<Cast> {
let proto = crate::proto::CastId {
fid: cast_id.fid,
hash: cast_id.hash
};
let res = self.get_cast(proto).await.ok()?.into_inner();
match cast_action_from_message(res)? {
CastAction::CastAdd(cast) => Some(cast),
CastAction::CastRemove(_) => None
}
}
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>>)> {
let request = CastsByParentRequest {
page_size,
page_token,
reverse,
parent: Some(parent.into()),
};
let res = self.get_casts_by_parent(request).await?.into_inner();
let mut messages = Vec::new();
for message in res.messages {
if let Some(CastAction::CastAdd(add)) = cast_action_from_message(message) {
messages.push(add);
}
}
Ok((messages, res.next_page_token))
}
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>>)> {
let request = ReactionsByTargetRequest {
reaction_type: Some(reaction_type.into()),
page_size,
page_token,
reverse,
target: Some(parent.into()),
};
let res = self.get_reactions_by_target(request).await?.into_inner();
let mut reactions = Vec::new();
for message in res.messages {
if let Some(react) = reaction_from_message(message) {
if let ReactionAction::Add(info) = react {
reactions.push(info);
}
}
}
Ok((reactions, res.next_page_token))
}
}