diff --git a/Cargo.toml b/Cargo.toml index e833586..95913e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,6 @@ uuid = { version = "0.8.2", features = ["v4"] } anyhow = "1.0.41" mammut = "0.13.0" thiserror = "1.0.26" -misskey = "0.2.0" +misskey = { version = "0.2.0", features = ["aid"] } url = "2.2.2" smol = "1.2.5" diff --git a/src/curation/any.rs b/src/curation/any.rs new file mode 100644 index 0000000..ef36a5a --- /dev/null +++ b/src/curation/any.rs @@ -0,0 +1,18 @@ +use std::error::Error; + +use futures::future::BoxFuture; + +use super::Curator; + +#[derive(Clone)] +pub struct AnyCurator; + +impl Curator for AnyCurator { + type Error = Box; + + type Response = BoxFuture<'static, Result>; + + fn review(&self, _: String) -> Self::Response { + Box::pin(async {Ok(true)}) + } +} diff --git a/src/selection/console.rs b/src/curation/console.rs similarity index 88% rename from src/selection/console.rs rename to src/curation/console.rs index 522c609..5f3a36b 100644 --- a/src/selection/console.rs +++ b/src/curation/console.rs @@ -3,12 +3,12 @@ use std::error::Error; use async_std::io::stdin; use futures::future::BoxFuture; -use super::Selector; +use super::Curator; #[derive(Debug, Copy, Clone)] -pub struct ConsoleSelector; +pub struct ConsoleCurator; -impl Selector for ConsoleSelector { +impl Curator for ConsoleCurator { type Error = Box; type Response = BoxFuture<'static, Result>; diff --git a/src/selection/mod.rs b/src/curation/mod.rs similarity index 82% rename from src/selection/mod.rs rename to src/curation/mod.rs index ef81e09..6c4da12 100644 --- a/src/selection/mod.rs +++ b/src/curation/mod.rs @@ -2,19 +2,21 @@ use futures::{stream::BoxStream, Future, Stream, TryStreamExt}; use std::fmt::Debug; use thiserror::Error; +mod any; mod console; pub mod telegram; -pub use console::ConsoleSelector; -pub use telegram::TelegramSelector; +pub use any::AnyCurator; +pub use console::ConsoleCurator; +pub use telegram::TelegramCurator; -pub trait Selector { +pub trait Curator: Sync + Send + Clone { type Error; type Response: Future>; fn review(&self, data: String) -> Self::Response; } -pub trait SelectorExt>>: Selector +pub trait CuratorExt>>: Curator where Self::Error: Debug, { @@ -33,9 +35,9 @@ pub enum FilterError { impl< E: Debug + 'static, - T: Selector + Sync + Send + Clone + 'static, + T: Curator + Sync + Send + Clone + 'static, S: Send + Stream> + 'static, - > SelectorExt for T + > CuratorExt for T where T::Response: Send, T::Error: Debug, diff --git a/src/selection/telegram.rs b/src/curation/telegram.rs similarity index 97% rename from src/selection/telegram.rs rename to src/curation/telegram.rs index 0c607c7..b81f921 100644 --- a/src/selection/telegram.rs +++ b/src/curation/telegram.rs @@ -4,7 +4,7 @@ use futures::{ lock::Mutex, Sink, SinkExt, StreamExt, }; -use std::{collections::HashMap, fmt::Debug, sync::Arc}; +use std::{collections::HashMap, error::Error, fmt::Debug, sync::Arc}; use telegram_bot::{ self, types::requests::answer_callback_query::CanAnswerCallbackQuery, Api, ChatRef, DeleteMessage, EditMessageReplyMarkup, InlineKeyboardButton, InlineKeyboardMarkup, Message, @@ -12,16 +12,16 @@ use telegram_bot::{ }; use uuid::Uuid; -use super::Selector; +use super::Curator; #[derive(Clone)] -pub struct TelegramSelector { +pub struct TelegramCurator { client: Arc, chat_ref: Arc>, pending: Arc>>>, } -impl TelegramSelector { +impl TelegramCurator { pub fn new + Send + Unpin + 'static>( api: Arc, chat_ref: Arc>, @@ -116,8 +116,8 @@ impl TelegramSelector { } } -impl Selector for TelegramSelector { - type Error = telegram_bot::Error; +impl Curator for TelegramCurator { + type Error = Box; type Response = BoxFuture<'static, Result>; diff --git a/src/main.rs b/src/main.rs index 6107038..e3fd36b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,18 +11,20 @@ use telegram_bot::{Api, ChatId, ChatRef, ToChatRef}; use crate::{ config::{FediverseConfig, Publisher}, + curation::{telegram::get_chat_ref, CuratorExt, TelegramCurator}, publish::MastodonPublisher, publish::MisskeyPublisher, - selection::{telegram::get_chat_ref, SelectorExt, TelegramSelector}, }; -use futures::{SinkExt, StreamExt, TryStreamExt, channel::mpsc::channel, future::Either, sink::unfold}; +use futures::{ + channel::mpsc::channel, future::Either, sink::unfold, SinkExt, StreamExt, TryStreamExt, +}; use model::SampleModelExt; mod config; +mod curation; mod model; mod publish; -mod selection; const CONFIG_PATH: &str = "bot_config.json"; @@ -40,7 +42,7 @@ async fn main() -> Result<(), Box> { } }?; - let publisher = resolve_publisher(&mut cfg).await?; + let publisher = resolve_publisher(&mut cfg).await?; let api = Arc::new(Api::new(cfg.bot_token.clone())); @@ -66,7 +68,7 @@ async fn main() -> Result<(), Box> { let cfg_clone = cfg.clone(); - let mut model = TelegramSelector::new( + let mut model = TelegramCurator::new( api, chat, Box::pin(unfold((), move |_, chat_ref| { @@ -145,9 +147,11 @@ async fn resolve_publisher( config: &mut config::Config, ) -> Result, Box> { let publisher = match &config.publisher { - config::Publisher::Misskey(cfg) => { - Either::Left(MisskeyPublisher::new(&cfg.base_url, cfg.token.clone(), cfg.visibility)?) - } + config::Publisher::Misskey(cfg) => Either::Left(MisskeyPublisher::new( + &cfg.base_url, + cfg.token.clone(), + cfg.visibility, + )?), config::Publisher::Mastodon(cfg) => { let app = AppBuilder { client_name: "izzilis", @@ -158,7 +162,7 @@ async fn resolve_publisher( let mut registration = Registration::new(cfg.base_url.clone()); registration.register(app)?; - let vis = cfg.visibility; + let vis = cfg.visibility; let mastodon = if let Some(data) = cfg.token.clone() { Mastodon::from_data(data.clone()) @@ -174,7 +178,7 @@ async fn resolve_publisher( config.publisher = Publisher::Mastodon(FediverseConfig { base_url: cfg.base_url.clone(), token: Some(fedi.data.clone()), - visibility: vis.clone(), + visibility: vis.clone(), }); config.save(CONFIG_PATH)?; diff --git a/src/publish/misskey.rs b/src/publish/misskey.rs index b7aa48a..e6c533c 100644 --- a/src/publish/misskey.rs +++ b/src/publish/misskey.rs @@ -1,18 +1,18 @@ use futures::Sink; -use misskey::{Client, ClientExt, HttpClient, model::note::Visibility}; +use misskey::{model::note::Visibility, Client, ClientExt, HttpClient}; use std::{error::Error, task::Poll}; use url::Url; pub struct MisskeyPublisher { client: HttpClient, - post_visibility: Visibility, + post_visibility: Visibility, } impl MisskeyPublisher { pub fn new(url: &String, token: String, vis: Visibility) -> Result> { Ok(Self { client: HttpClient::with_token(Url::parse(url)?, token)?, - post_visibility: vis, + post_visibility: vis, }) } } @@ -28,9 +28,13 @@ impl Sink for MisskeyPublisher { } fn start_send(self: std::pin::Pin<&mut Self>, item: String) -> Result<(), Self::Error> { - let mut req = self.client.build_note(); - let req = req.text(item).visibility(self.post_visibility).as_request(); - smol::block_on(self.client.request(req))?; + let mut req = self.client.build_note(); + let req = req.text(item).visibility(self.post_visibility).as_request(); + let response = smol::block_on(self.client.request(req))?; + // If there is an ApiResult error, decode it to a regular Result error + if let Option::Some(err) = response.err() { + return Err(Box::new(err)); + } Ok(()) }