Added support for misskey publisher, and switching between publishers via config

This commit is contained in:
emilis 2021-09-01 19:30:20 +02:00
parent 677226a77f
commit bd42f495dc
7 changed files with 864 additions and 94 deletions

792
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -17,3 +17,5 @@ uuid = { version = "0.8.2", features = ["v4"] }
anyhow = "1.0.41"
mammut = "0.13.0"
thiserror = "1.0.26"
misskey = "0.2.0"
url = "2.2.2"

View File

@ -1,6 +1,6 @@
use std::{error::Error, path::Path};
use core::fmt::Debug;
use serde::{Deserialize, Serialize};
use std::{error::Error, path::Path};
use telegram_bot::ChatId;
#[derive(Serialize, Deserialize, Debug, Clone)]
@ -10,12 +10,12 @@ pub struct Config {
pub temperature: String,
pub top_k: String,
pub gpt_code_path: String,
pub fediverse_base_url: String,
pub interval_seconds: MinMax,
pub bot_token: String,
pub chat_ref: ChatId,
pub fediverse_token: Option<mammut::Data>,
pub mastodon_token: Option<mammut::Data>,
pub post_buffer: u32,
pub publisher: Publisher,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
@ -24,6 +24,18 @@ pub struct MinMax {
pub max: u64,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum Publisher {
Misskey(FediverseConfig<String>),
Mastodon(FediverseConfig<Option<mammut::Data>>),
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct FediverseConfig<T> {
pub base_url: String,
pub token: T,
}
impl Default for Config {
fn default() -> Self {
Config {
@ -32,15 +44,18 @@ impl Default for Config {
temperature: String::from("1"),
top_k: String::from("40"),
gpt_code_path: String::from("./gpt/"),
fediverse_base_url: String::from("https://lain.com"),
interval_seconds: MinMax {
min: 60 * 30,
max: 60 * 90,
},
post_buffer: 5,
fediverse_token: None,
mastodon_token: None,
bot_token: "".to_owned(),
chat_ref: ChatId::new(0),
publisher: Publisher::Misskey(FediverseConfig {
base_url: "".to_string(),
token: "".to_string(),
}),
}
}
}

View File

@ -10,11 +10,13 @@ use rand::Rng;
use telegram_bot::{Api, ChatId, ChatRef, ToChatRef};
use crate::{
config::{FediverseConfig, Publisher},
publish::MastodonPublisher,
publish::MisskeyPublisher,
selection::{telegram::get_chat_ref, SelectorExt, TelegramSelector},
};
use futures::{channel::mpsc::channel, sink::unfold, SinkExt, StreamExt, TryStreamExt};
use futures::{SinkExt, StreamExt, TryStreamExt, channel::mpsc::channel, future::Either, sink::unfold};
use model::SampleModelExt;
mod config;
@ -38,34 +40,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
}
}?;
let app = AppBuilder {
client_name: "izzilis",
redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
scopes: Scopes::Write,
website: None,
};
let mut registration = Registration::new(cfg.fediverse_base_url.clone());
registration.register(app)?;
let mastodon = if let Some(data) = &cfg.fediverse_token {
Mastodon::from_data(data.clone())
} else {
let url = registration.authorise()?;
println!("{}", url);
let mut buffer = String::new();
stdin().read_line(&mut buffer).await?;
let fedi = registration.create_access_token(buffer)?;
cfg.fediverse_token = Some(fedi.data.clone());
cfg.save(CONFIG_PATH)?;
fedi
};
let publisher = MastodonPublisher::new(mastodon);
let publisher = resolve_publisher(&mut cfg).await?;
let api = Arc::new(Api::new(cfg.bot_token.clone()));
@ -145,7 +120,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
});
publisher
.sink_map_err(|e| Box::new(e) as Box<dyn Error>)
.sink_map_err(|e| e)
.send_all(
&mut receiver
.then(|item| {
@ -165,3 +140,47 @@ async fn main() -> Result<(), Box<dyn Error>> {
return Ok(());
}
async fn resolve_publisher(
config: &mut config::Config,
) -> Result<Either<MisskeyPublisher, MastodonPublisher>, Box<dyn Error>> {
let publisher = match &config.publisher {
config::Publisher::Misskey(cfg) => {
Either::Left(MisskeyPublisher::new(&cfg.base_url, cfg.token.clone())?)
}
config::Publisher::Mastodon(cfg) => {
let app = AppBuilder {
client_name: "izzilis",
redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
scopes: Scopes::Write,
website: None,
};
let mut registration = Registration::new(cfg.base_url.clone());
registration.register(app)?;
let mastodon = if let Some(data) = cfg.token.clone() {
Mastodon::from_data(data.clone())
} else {
let url = registration.authorise()?;
println!("{}", url);
let mut buffer = String::new();
stdin().read_line(&mut buffer).await?;
let fedi = registration.create_access_token(buffer)?;
config.publisher = Publisher::Mastodon(FediverseConfig {
base_url: cfg.base_url.clone(),
token: Some(fedi.data.clone()),
});
config.save(CONFIG_PATH)?;
fedi
};
Either::Right(MastodonPublisher::new(mastodon))
}
};
Ok(publisher)
}

View File

@ -1,7 +1,4 @@
use std::{
pin::Pin,
task::{Context, Poll},
};
use std::{error::Error, pin::Pin, task::{Context, Poll}};
use futures::Sink;
use mammut::{status_builder::Visibility, Mastodon, StatusBuilder};
@ -17,7 +14,7 @@ impl MastodonPublisher {
}
impl Sink<String> for MastodonPublisher {
type Error = mammut::Error;
type Error = Box<dyn Error>;
fn poll_ready(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))

49
src/publish/misskey.rs Normal file
View File

@ -0,0 +1,49 @@
use futures::Sink;
use misskey::{ClientExt, HttpClient};
use std::{error::Error, task::Poll};
use tokio::runtime::Runtime;
use url::Url;
pub struct MisskeyPublisher {
client: HttpClient,
}
impl MisskeyPublisher {
pub fn new(url: &String, token: String) -> Result<Self, Box<dyn Error>> {
Ok(Self {
client: HttpClient::with_token(Url::parse(url)?, token)?,
})
}
}
impl Sink<String> for MisskeyPublisher {
type Error = Box<dyn Error>;
fn poll_ready(
self: std::pin::Pin<&mut Self>,
_: &mut std::task::Context<'_>,
) -> std::task::Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn start_send(self: std::pin::Pin<&mut Self>, item: String) -> Result<(), Self::Error> {
let mut runtime = Runtime::new()?;
let fut = self.client.create_note(item);
runtime.block_on(fut)?;
Ok(())
}
fn poll_flush(
self: std::pin::Pin<&mut Self>,
_: &mut std::task::Context<'_>,
) -> std::task::Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn poll_close(
self: std::pin::Pin<&mut Self>,
_: &mut std::task::Context<'_>,
) -> std::task::Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
}

View File

@ -1,2 +1,4 @@
mod mastodon;
mod misskey;
pub use mastodon::MastodonPublisher;
pub use crate::publish::misskey::MisskeyPublisher;