Compare commits
1 Commits
master
...
feature/cu
Author | SHA1 | Date |
---|---|---|
emilis | 4dc210ad2d |
|
@ -17,6 +17,6 @@ uuid = { version = "0.8.2", features = ["v4"] }
|
||||||
anyhow = "1.0.41"
|
anyhow = "1.0.41"
|
||||||
mammut = "0.13.0"
|
mammut = "0.13.0"
|
||||||
thiserror = "1.0.26"
|
thiserror = "1.0.26"
|
||||||
misskey = "0.2.0"
|
misskey = { version = "0.2.0", features = ["aid"] }
|
||||||
url = "2.2.2"
|
url = "2.2.2"
|
||||||
smol = "1.2.5"
|
smol = "1.2.5"
|
||||||
|
|
|
@ -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<dyn Error>;
|
||||||
|
|
||||||
|
type Response = BoxFuture<'static, Result<bool, Self::Error>>;
|
||||||
|
|
||||||
|
fn review(&self, _: String) -> Self::Response {
|
||||||
|
Box::pin(async {Ok(true)})
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,12 +3,12 @@ use std::error::Error;
|
||||||
use async_std::io::stdin;
|
use async_std::io::stdin;
|
||||||
use futures::future::BoxFuture;
|
use futures::future::BoxFuture;
|
||||||
|
|
||||||
use super::Selector;
|
use super::Curator;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct ConsoleSelector;
|
pub struct ConsoleCurator;
|
||||||
|
|
||||||
impl Selector for ConsoleSelector {
|
impl Curator for ConsoleCurator {
|
||||||
type Error = Box<dyn Error>;
|
type Error = Box<dyn Error>;
|
||||||
type Response = BoxFuture<'static, Result<bool, Self::Error>>;
|
type Response = BoxFuture<'static, Result<bool, Self::Error>>;
|
||||||
|
|
|
@ -2,19 +2,21 @@ use futures::{stream::BoxStream, Future, Stream, TryStreamExt};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
mod any;
|
||||||
mod console;
|
mod console;
|
||||||
pub mod telegram;
|
pub mod telegram;
|
||||||
pub use console::ConsoleSelector;
|
pub use any::AnyCurator;
|
||||||
pub use telegram::TelegramSelector;
|
pub use console::ConsoleCurator;
|
||||||
|
pub use telegram::TelegramCurator;
|
||||||
|
|
||||||
pub trait Selector {
|
pub trait Curator: Sync + Send + Clone {
|
||||||
type Error;
|
type Error;
|
||||||
type Response: Future<Output = Result<bool, Self::Error>>;
|
type Response: Future<Output = Result<bool, Self::Error>>;
|
||||||
|
|
||||||
fn review(&self, data: String) -> Self::Response;
|
fn review(&self, data: String) -> Self::Response;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait SelectorExt<E: Debug, S: Stream<Item = Result<String, E>>>: Selector
|
pub trait CuratorExt<E: Debug, S: Stream<Item = Result<String, E>>>: Curator
|
||||||
where
|
where
|
||||||
Self::Error: Debug,
|
Self::Error: Debug,
|
||||||
{
|
{
|
||||||
|
@ -33,9 +35,9 @@ pub enum FilterError<T: Debug, U: Debug> {
|
||||||
|
|
||||||
impl<
|
impl<
|
||||||
E: Debug + 'static,
|
E: Debug + 'static,
|
||||||
T: Selector + Sync + Send + Clone + 'static,
|
T: Curator + Sync + Send + Clone + 'static,
|
||||||
S: Send + Stream<Item = Result<String, E>> + 'static,
|
S: Send + Stream<Item = Result<String, E>> + 'static,
|
||||||
> SelectorExt<E, S> for T
|
> CuratorExt<E, S> for T
|
||||||
where
|
where
|
||||||
T::Response: Send,
|
T::Response: Send,
|
||||||
T::Error: Debug,
|
T::Error: Debug,
|
|
@ -4,7 +4,7 @@ use futures::{
|
||||||
lock::Mutex,
|
lock::Mutex,
|
||||||
Sink, SinkExt, StreamExt,
|
Sink, SinkExt, StreamExt,
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, fmt::Debug, sync::Arc};
|
use std::{collections::HashMap, error::Error, fmt::Debug, sync::Arc};
|
||||||
use telegram_bot::{
|
use telegram_bot::{
|
||||||
self, types::requests::answer_callback_query::CanAnswerCallbackQuery, Api, ChatRef,
|
self, types::requests::answer_callback_query::CanAnswerCallbackQuery, Api, ChatRef,
|
||||||
DeleteMessage, EditMessageReplyMarkup, InlineKeyboardButton, InlineKeyboardMarkup, Message,
|
DeleteMessage, EditMessageReplyMarkup, InlineKeyboardButton, InlineKeyboardMarkup, Message,
|
||||||
|
@ -12,16 +12,16 @@ use telegram_bot::{
|
||||||
};
|
};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use super::Selector;
|
use super::Curator;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct TelegramSelector {
|
pub struct TelegramCurator {
|
||||||
client: Arc<Api>,
|
client: Arc<Api>,
|
||||||
chat_ref: Arc<Mutex<ChatRef>>,
|
chat_ref: Arc<Mutex<ChatRef>>,
|
||||||
pending: Arc<Mutex<HashMap<Uuid, Sender<bool>>>>,
|
pending: Arc<Mutex<HashMap<Uuid, Sender<bool>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TelegramSelector {
|
impl TelegramCurator {
|
||||||
pub fn new<S: Sink<ChatRef> + Send + Unpin + 'static>(
|
pub fn new<S: Sink<ChatRef> + Send + Unpin + 'static>(
|
||||||
api: Arc<Api>,
|
api: Arc<Api>,
|
||||||
chat_ref: Arc<Mutex<ChatRef>>,
|
chat_ref: Arc<Mutex<ChatRef>>,
|
||||||
|
@ -116,8 +116,8 @@ impl TelegramSelector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Selector for TelegramSelector {
|
impl Curator for TelegramCurator {
|
||||||
type Error = telegram_bot::Error;
|
type Error = Box<dyn Error>;
|
||||||
|
|
||||||
type Response = BoxFuture<'static, Result<bool, Self::Error>>;
|
type Response = BoxFuture<'static, Result<bool, Self::Error>>;
|
||||||
|
|
24
src/main.rs
24
src/main.rs
|
@ -11,18 +11,20 @@ use telegram_bot::{Api, ChatId, ChatRef, ToChatRef};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{FediverseConfig, Publisher},
|
config::{FediverseConfig, Publisher},
|
||||||
|
curation::{telegram::get_chat_ref, CuratorExt, TelegramCurator},
|
||||||
publish::MastodonPublisher,
|
publish::MastodonPublisher,
|
||||||
publish::MisskeyPublisher,
|
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;
|
use model::SampleModelExt;
|
||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
|
mod curation;
|
||||||
mod model;
|
mod model;
|
||||||
mod publish;
|
mod publish;
|
||||||
mod selection;
|
|
||||||
|
|
||||||
const CONFIG_PATH: &str = "bot_config.json";
|
const CONFIG_PATH: &str = "bot_config.json";
|
||||||
|
|
||||||
|
@ -40,7 +42,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
||||||
}
|
}
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
let publisher = resolve_publisher(&mut cfg).await?;
|
let publisher = resolve_publisher(&mut cfg).await?;
|
||||||
|
|
||||||
let api = Arc::new(Api::new(cfg.bot_token.clone()));
|
let api = Arc::new(Api::new(cfg.bot_token.clone()));
|
||||||
|
|
||||||
|
@ -66,7 +68,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
||||||
|
|
||||||
let cfg_clone = cfg.clone();
|
let cfg_clone = cfg.clone();
|
||||||
|
|
||||||
let mut model = TelegramSelector::new(
|
let mut model = TelegramCurator::new(
|
||||||
api,
|
api,
|
||||||
chat,
|
chat,
|
||||||
Box::pin(unfold((), move |_, chat_ref| {
|
Box::pin(unfold((), move |_, chat_ref| {
|
||||||
|
@ -145,9 +147,11 @@ async fn resolve_publisher(
|
||||||
config: &mut config::Config,
|
config: &mut config::Config,
|
||||||
) -> Result<Either<MisskeyPublisher, MastodonPublisher>, Box<dyn Error>> {
|
) -> Result<Either<MisskeyPublisher, MastodonPublisher>, Box<dyn Error>> {
|
||||||
let publisher = match &config.publisher {
|
let publisher = match &config.publisher {
|
||||||
config::Publisher::Misskey(cfg) => {
|
config::Publisher::Misskey(cfg) => Either::Left(MisskeyPublisher::new(
|
||||||
Either::Left(MisskeyPublisher::new(&cfg.base_url, cfg.token.clone(), cfg.visibility)?)
|
&cfg.base_url,
|
||||||
}
|
cfg.token.clone(),
|
||||||
|
cfg.visibility,
|
||||||
|
)?),
|
||||||
config::Publisher::Mastodon(cfg) => {
|
config::Publisher::Mastodon(cfg) => {
|
||||||
let app = AppBuilder {
|
let app = AppBuilder {
|
||||||
client_name: "izzilis",
|
client_name: "izzilis",
|
||||||
|
@ -158,7 +162,7 @@ async fn resolve_publisher(
|
||||||
|
|
||||||
let mut registration = Registration::new(cfg.base_url.clone());
|
let mut registration = Registration::new(cfg.base_url.clone());
|
||||||
registration.register(app)?;
|
registration.register(app)?;
|
||||||
let vis = cfg.visibility;
|
let vis = cfg.visibility;
|
||||||
|
|
||||||
let mastodon = if let Some(data) = cfg.token.clone() {
|
let mastodon = if let Some(data) = cfg.token.clone() {
|
||||||
Mastodon::from_data(data.clone())
|
Mastodon::from_data(data.clone())
|
||||||
|
@ -174,7 +178,7 @@ async fn resolve_publisher(
|
||||||
config.publisher = Publisher::Mastodon(FediverseConfig {
|
config.publisher = Publisher::Mastodon(FediverseConfig {
|
||||||
base_url: cfg.base_url.clone(),
|
base_url: cfg.base_url.clone(),
|
||||||
token: Some(fedi.data.clone()),
|
token: Some(fedi.data.clone()),
|
||||||
visibility: vis.clone(),
|
visibility: vis.clone(),
|
||||||
});
|
});
|
||||||
config.save(CONFIG_PATH)?;
|
config.save(CONFIG_PATH)?;
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
use futures::Sink;
|
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 std::{error::Error, task::Poll};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
pub struct MisskeyPublisher {
|
pub struct MisskeyPublisher {
|
||||||
client: HttpClient,
|
client: HttpClient,
|
||||||
post_visibility: Visibility,
|
post_visibility: Visibility,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MisskeyPublisher {
|
impl MisskeyPublisher {
|
||||||
pub fn new(url: &String, token: String, vis: Visibility) -> Result<Self, Box<dyn Error>> {
|
pub fn new(url: &String, token: String, vis: Visibility) -> Result<Self, Box<dyn Error>> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
client: HttpClient::with_token(Url::parse(url)?, token)?,
|
client: HttpClient::with_token(Url::parse(url)?, token)?,
|
||||||
post_visibility: vis,
|
post_visibility: vis,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,9 +28,13 @@ impl Sink<String> for MisskeyPublisher {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_send(self: std::pin::Pin<&mut Self>, item: String) -> Result<(), Self::Error> {
|
fn start_send(self: std::pin::Pin<&mut Self>, item: String) -> Result<(), Self::Error> {
|
||||||
let mut req = self.client.build_note();
|
let mut req = self.client.build_note();
|
||||||
let req = req.text(item).visibility(self.post_visibility).as_request();
|
let req = req.text(item).visibility(self.post_visibility).as_request();
|
||||||
smol::block_on(self.client.request(req))?;
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue