Skip to content

Instantly share code, notes, and snippets.

@komori-n
Last active July 25, 2021 13:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save komori-n/f2af10496f220ec89619a6aebb227513 to your computer and use it in GitHub Desktop.
Save komori-n/f2af10496f220ec89619a6aebb227513 to your computer and use it in GitHub Desktop.
nananiji-bot
use anyhow::Context as _;
use anyhow::Result;
use chrono::{FixedOffset, TimeZone, Utc};
use lambda_runtime::{error::HandlerError, lambda, Context};
use log::info;
use reqwest::{blocking::Client, header::CONTENT_TYPE};
use serde::{Deserialize, Serialize};
const NANANIJI_GENERATOR_URL: &'static str =
"https://xxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/beta/";
const CONSUMER_TOKEN_KEY: &'static str = "XXXXXXXXXXXXXXX";
const CONSUMER_TOKEN_SECRET: &'static str = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
const ACCESS_KEY: &'static str = "XXXXXXXXXXXXXXXXXX-XXXXXXXXXXXXXXXXXXXXXXXXXXXX";
const ACCESS_SECRET: &'static str = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
// anyhow = "1.0"
// clap = "2.33"
// log = "0.4"
// env_logger = "0.8"
// lambda_runtime = "0.2"
// serde = {version = "1.0", features = ["derive"]}
// serde_json = "1.0"
// chrono = "0.4"
// reqwest = { version = "0.11", default-features = false, features = ["rustls-tls", "blocking"]}
// egg-mode = { version = "0.16", features = ["rustls"], default-features = false }
// tokio = {version = "1.8", features = ["full"]}
#[derive(Serialize, Deserialize, Clone, Copy, Debug)]
#[serde(tag = "name", content = "split", rename_all = "lowercase")]
enum ListName {
Nananiji,
Hanshin(bool),
Kyojin(bool),
}
#[derive(Serialize, Deserialize, Clone, Debug)]
struct CalculationRequest {
value: String,
list_name: ListName,
}
#[derive(Deserialize, Clone)]
struct RequestResult {
expr: String,
}
#[derive(Deserialize, Clone, Debug)]
struct Request {}
fn main() -> Result<()> {
env_logger::init();
lambda!(move |_: Request, _ctx: Context| handler());
Ok(())
}
fn handler() -> Result<(), HandlerError> {
// todo log req
let num = date_number()
.with_context(|| "Could not parse date number")
.unwrap();
let calc_req = CalculationRequest {
value: num.clone(),
list_name: ListName::Nananiji,
};
let decomposite_ans = calculate(&calc_req)
.with_context(|| "Could not calculate")
.unwrap();
info!("ans: {}", decomposite_ans);
let tweet_text = format!("{} \n={} #nananiji_generator", num, decomposite_ans);
info!("tweet_text: {}", tweet_text);
tweet(tweet_text);
Ok(())
}
fn date_number() -> Result<String> {
let utc_time = Utc::now();
let japan_date = FixedOffset::east(9 * 3600)
.from_utc_datetime(&utc_time.naive_utc())
.date();
let ret = japan_date.format("%Y%m%d").to_string();
Ok(ret)
}
fn calculate(req: &CalculationRequest) -> Result<String> {
let client = Client::new();
let res = client
.post(NANANIJI_GENERATOR_URL)
.body(serde_json::to_string(req)?)
.header(CONTENT_TYPE, "application/json")
.send()?;
let ans: RequestResult = serde_json::from_str(&res.text()?)?;
Ok(ans.expr)
}
fn tweet(tweet_str: String) {
tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap()
.block_on(async {
let con_token = egg_mode::KeyPair::new(CONSUMER_TOKEN_KEY, CONSUMER_TOKEN_SECRET);
let access = egg_mode::KeyPair::new(ACCESS_KEY, ACCESS_SECRET);
let access_token = egg_mode::auth::Token::Access {
consumer: con_token,
access,
};
// Because `DraftTweet` struct requires a static-lifetime reference (I'm not sure of the reason),
// leak the storage intentionally. This operation might be dangerous.
let static_str: &'static str = Box::leak(tweet_str.into_boxed_str());
egg_mode::tweet::DraftTweet::new(static_str)
.send(&access_token)
.await
.unwrap();
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment