mirror of
https://framagit.org/veretcle/scootaloo.git
synced 2025-07-21 09:31:19 +02:00
Main mastodon logic, reorganization of the global app to reflect the fact that a subcommand is possible
This commit is contained in:
104
src/lib.rs
104
src/lib.rs
@@ -1,12 +1,11 @@
|
|||||||
// std
|
// std
|
||||||
use std::{
|
use std::{
|
||||||
|
borrow::Cow,
|
||||||
|
io,
|
||||||
fs::{read_to_string, write},
|
fs::{read_to_string, write},
|
||||||
error::Error,
|
error::Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
// clap
|
|
||||||
use clap::{App, Arg};
|
|
||||||
|
|
||||||
// toml
|
// toml
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
@@ -21,10 +20,20 @@ use egg_mode::{
|
|||||||
};
|
};
|
||||||
use tokio::runtime::current_thread::block_on_all;
|
use tokio::runtime::current_thread::block_on_all;
|
||||||
|
|
||||||
|
// mammut
|
||||||
|
use mammut::{Mastodon, Data, Registration};
|
||||||
|
use mammut::apps::{AppBuilder, Scopes};
|
||||||
|
use mammut::status_builder::StatusBuilder;
|
||||||
|
|
||||||
/**********
|
/**********
|
||||||
* Generic usage functions
|
* Generic usage functions
|
||||||
***********/
|
***********/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Those functions are related to the Twitter side of things
|
||||||
|
*/
|
||||||
|
/// Read last tweet id from a file
|
||||||
fn read_state(s: &str) -> Option<u64> {
|
fn read_state(s: &str) -> Option<u64> {
|
||||||
let state = read_to_string(s);
|
let state = read_to_string(s);
|
||||||
|
|
||||||
@@ -35,10 +44,12 @@ fn read_state(s: &str) -> Option<u64> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Write last treated tweet id to a file
|
||||||
fn write_state(f: &str, s: u64) -> Result<(), std::io::Error> {
|
fn write_state(f: &str, s: u64) -> Result<(), std::io::Error> {
|
||||||
write(f, format!("{}", s))
|
write(f, format!("{}", s))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get twitter oauth2 token
|
||||||
fn get_oauth2_token(config: &Config) -> Token {
|
fn get_oauth2_token(config: &Config) -> Token {
|
||||||
let con_token = KeyPair::new(String::from(&config.twitter.consumer_key), String::from(&config.twitter.consumer_secret));
|
let con_token = KeyPair::new(String::from(&config.twitter.consumer_key), String::from(&config.twitter.consumer_secret));
|
||||||
let access_token = KeyPair::new(String::from(&config.twitter.access_key), String::from(&config.twitter.access_secret));
|
let access_token = KeyPair::new(String::from(&config.twitter.access_key), String::from(&config.twitter.access_secret));
|
||||||
@@ -49,6 +60,7 @@ fn get_oauth2_token(config: &Config) -> Token {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get twitter user timeline
|
||||||
fn get_user_timeline(config: &Config, token: Token, lid: Option<u64>) -> Result<Vec<Tweet>, Box<dyn Error>> {
|
fn get_user_timeline(config: &Config, token: Token, lid: Option<u64>) -> Result<Vec<Tweet>, Box<dyn Error>> {
|
||||||
// fix the page size to 200 as it is the maximum Twitter authorizes
|
// fix the page size to 200 as it is the maximum Twitter authorizes
|
||||||
let (_timeline, feed) = block_on_all(user_timeline(&config.twitter.username, false, false, &token)
|
let (_timeline, feed) = block_on_all(user_timeline(&config.twitter.username, false, false, &token)
|
||||||
@@ -58,6 +70,21 @@ fn get_user_timeline(config: &Config, token: Token, lid: Option<u64>) -> Result<
|
|||||||
Ok(feed.to_vec())
|
Ok(feed.to_vec())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Those functions are related to the Mastodon side of things
|
||||||
|
*/
|
||||||
|
/// Get Mastodon Data
|
||||||
|
fn get_mastodon_token(masto: &MastodonConfig) -> Mastodon {
|
||||||
|
let data = Data {
|
||||||
|
base: Cow::from(String::from(&masto.base)),
|
||||||
|
client_id: Cow::from(String::from(&masto.client_id)),
|
||||||
|
client_secret: Cow::from(String::from(&masto.client_secret)),
|
||||||
|
redirect: Cow::from(String::from(&masto.redirect)),
|
||||||
|
token: Cow::from(String::from(&masto.token)),
|
||||||
|
};
|
||||||
|
|
||||||
|
Mastodon::from_data(data)
|
||||||
|
}
|
||||||
/**********
|
/**********
|
||||||
* Config structure
|
* Config structure
|
||||||
***********/
|
***********/
|
||||||
@@ -66,6 +93,7 @@ fn get_user_timeline(config: &Config, token: Token, lid: Option<u64>) -> Result<
|
|||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
twitter: TwitterConfig,
|
twitter: TwitterConfig,
|
||||||
|
mastodon: MastodonConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
@@ -78,22 +106,21 @@ struct TwitterConfig {
|
|||||||
last_tweet_path: String,
|
last_tweet_path: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
#[derive(Debug, Deserialize)]
|
||||||
/// parses configuration from command line and TOML config file
|
struct MastodonConfig {
|
||||||
pub fn new() -> Config {
|
base: String,
|
||||||
let matches = App::new(env!("CARGO_PKG_NAME"))
|
client_id: String,
|
||||||
.version(env!("CARGO_PKG_VERSION"))
|
client_secret: String,
|
||||||
.about("A Twitter to Mastodon bot")
|
redirect: String,
|
||||||
.arg(Arg::with_name("config")
|
token: String,
|
||||||
.short("c")
|
}
|
||||||
.long("config")
|
|
||||||
.value_name("CONFIG_FILE")
|
|
||||||
.help("TOML config file for scootaloo (default /usr/local/etc/scootaloo.toml)")
|
|
||||||
.takes_value(true)
|
|
||||||
.display_order(1))
|
|
||||||
.get_matches();
|
|
||||||
|
|
||||||
let toml_file = matches.value_of("config").unwrap_or("/usr/local/etc/scootaloo.toml");
|
/*********
|
||||||
|
* Main functions
|
||||||
|
*********/
|
||||||
|
|
||||||
|
/// Parses the TOML file into a Config Struct
|
||||||
|
pub fn parse_toml(toml_file: &str) -> Config {
|
||||||
let toml_config = read_to_string(toml_file).unwrap_or_else(|e|
|
let toml_config = read_to_string(toml_file).unwrap_or_else(|e|
|
||||||
panic!("Cannot open config file {}: {}", toml_file, e)
|
panic!("Cannot open config file {}: {}", toml_file, e)
|
||||||
);
|
);
|
||||||
@@ -103,12 +130,36 @@ impl Config {
|
|||||||
);
|
);
|
||||||
|
|
||||||
config
|
config
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*********
|
/// Generic register function
|
||||||
* Main function
|
/// As this function is supposed to be run only once, it will panic for every error it encounters
|
||||||
*********/
|
/// Most of this function is a direct copy/paste of the official `mammut` crate
|
||||||
|
pub fn register(host: &str) {
|
||||||
|
let app = AppBuilder {
|
||||||
|
client_name: env!("CARGO_PKG_NAME"),
|
||||||
|
redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
|
||||||
|
scopes: Scopes::Write,
|
||||||
|
website: Some("https://framagit.org/veretcle/scootaloo"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut registration = Registration::new(host);
|
||||||
|
registration.register(app).expect("Registration failed!");
|
||||||
|
let url = registration.authorise().expect("Cannot generate registration URI!");
|
||||||
|
|
||||||
|
println!("Click this link to authorize on Mastodon: {}", url);
|
||||||
|
println!("Paste the returned authorization code: ");
|
||||||
|
|
||||||
|
let mut input = String::new();
|
||||||
|
io::stdin().read_line(&mut input).expect("Unable to read back registration code!");
|
||||||
|
|
||||||
|
let code = input.trim();
|
||||||
|
let mastodon = registration.create_access_token(code.to_string()).expect("Unable to create access token!");
|
||||||
|
|
||||||
|
let toml = toml::to_string(&*mastodon).unwrap();
|
||||||
|
|
||||||
|
println!("Please insert the following block at the end of your configuration file:\n[mastodon]\n{}", toml);
|
||||||
|
}
|
||||||
|
|
||||||
/// This is where the magic happens
|
/// This is where the magic happens
|
||||||
pub fn run(config: Config) {
|
pub fn run(config: Config) {
|
||||||
@@ -118,6 +169,15 @@ pub fn run(config: Config) {
|
|||||||
// get OAuth2 token
|
// get OAuth2 token
|
||||||
let token = get_oauth2_token(&config);
|
let token = get_oauth2_token(&config);
|
||||||
|
|
||||||
|
// get Mastodon instance
|
||||||
|
let mastodon = get_mastodon_token(&config.mastodon);
|
||||||
|
|
||||||
|
let status = StatusBuilder::new("Hello World!".into());
|
||||||
|
|
||||||
|
mastodon.new_status(status).expect("tamerelol");
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
// get user timeline feed (Vec<tweet>)
|
// get user timeline feed (Vec<tweet>)
|
||||||
let feed = get_user_timeline(&config, token, last_tweet_id).unwrap_or_else(|e|
|
let feed = get_user_timeline(&config, token, last_tweet_id).unwrap_or_else(|e|
|
||||||
panic!("Something went wrong when trying to retrieve {}’s timeline: {}", &config.twitter.username, e)
|
panic!("Something went wrong when trying to retrieve {}’s timeline: {}", &config.twitter.username, e)
|
||||||
|
33
src/main.rs
33
src/main.rs
@@ -1,7 +1,38 @@
|
|||||||
|
// self
|
||||||
use scootaloo::*;
|
use scootaloo::*;
|
||||||
|
|
||||||
|
// clap
|
||||||
|
use clap::{App, Arg, SubCommand};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let config = Config::new();
|
let matches = App::new(env!("CARGO_PKG_NAME"))
|
||||||
|
.version(env!("CARGO_PKG_VERSION"))
|
||||||
|
.about("A Twitter to Mastodon bot")
|
||||||
|
.arg(Arg::with_name("config")
|
||||||
|
.short("c")
|
||||||
|
.long("config")
|
||||||
|
.value_name("CONFIG_FILE")
|
||||||
|
.help("TOML config file for scootaloo (default /usr/local/etc/scootaloo.toml)")
|
||||||
|
.takes_value(true)
|
||||||
|
.display_order(1))
|
||||||
|
.subcommand(SubCommand::with_name("register")
|
||||||
|
.version(env!("CARGO_PKG_VERSION"))
|
||||||
|
.about("Command to register to a Mastodon Instance")
|
||||||
|
.arg(Arg::with_name("host")
|
||||||
|
.short("h")
|
||||||
|
.long("host")
|
||||||
|
.value_name("HOST")
|
||||||
|
.help("Base URL of the Mastodon instance to register to (no default)")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
.display_order(1)))
|
||||||
|
.get_matches();
|
||||||
|
if let Some(matches) = matches.subcommand_matches("register") {
|
||||||
|
register(matches.value_of("host").unwrap());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let config = parse_toml(matches.value_of("config").unwrap());
|
||||||
|
|
||||||
run(config);
|
run(config);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user