forked from projectmoon/tenebrous-dicebot
modularize things
This commit is contained in:
parent
8be108a57c
commit
b30eec72b3
|
@ -0,0 +1,84 @@
|
||||||
|
use serde::{self, Deserialize, Serialize};
|
||||||
|
use reqwest::Client;
|
||||||
|
use crate::matrix::SyncCommand;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct MatrixConfig {
|
||||||
|
user: String,
|
||||||
|
password: String,
|
||||||
|
home_server: String,
|
||||||
|
next_batch: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct Config {
|
||||||
|
matrix: MatrixConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DiceBot {
|
||||||
|
config: Config,
|
||||||
|
access_token: String,
|
||||||
|
next_batch: Option<String>,
|
||||||
|
client: Client,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Debug)]
|
||||||
|
struct LoginRequest<'a, 'b, 'c> {
|
||||||
|
#[serde(rename = "type")]
|
||||||
|
type_: &'a str,
|
||||||
|
user: &'b str,
|
||||||
|
password: &'c str,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
struct LoginResponse {
|
||||||
|
access_token: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DiceBot {
|
||||||
|
pub async fn new(config: Config) -> Result<Self, Box<dyn std::error::Error>> {
|
||||||
|
let client = Client::new();
|
||||||
|
let request = LoginRequest {
|
||||||
|
type_: "m.login.password",
|
||||||
|
user: &config.matrix.user,
|
||||||
|
password: &config.matrix.password,
|
||||||
|
};
|
||||||
|
let response = client.post(&format!("https://{}/_matrix/client/r0/login", config.matrix.home_server))
|
||||||
|
.body(serde_json::to_string(&request)?)
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
let body: LoginResponse = serde_json::from_str(&response.text().await?)?;
|
||||||
|
Ok(DiceBot{
|
||||||
|
client,
|
||||||
|
config,
|
||||||
|
access_token: body.access_token,
|
||||||
|
next_batch: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn sync(&mut self) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let mut url = format!("https://{}/_matrix/client/r0/sync?access_token={}&timeout=3000",
|
||||||
|
self.config.matrix.home_server,
|
||||||
|
self.access_token);
|
||||||
|
if let Some(since) = &self.next_batch {
|
||||||
|
url.push_str(&format!("&since={}", since));
|
||||||
|
}
|
||||||
|
let body = self.client.get(&url)
|
||||||
|
.send()
|
||||||
|
.await?
|
||||||
|
.text()
|
||||||
|
.await?;
|
||||||
|
let sync: SyncCommand = serde_json::from_str(&body).unwrap();
|
||||||
|
println!("{:#?}", sync);
|
||||||
|
self.next_batch = Some(sync.next_batch);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn logout(self) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
self.client.post(&format!("https://{}/_matrix/client/r0/logout?access_token={}", self.config.matrix.home_server, self.access_token))
|
||||||
|
.body("{}")
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod matrix;
|
||||||
|
pub mod bot;
|
107
src/main.rs
107
src/main.rs
|
@ -1,109 +1,36 @@
|
||||||
use serde::{self, Deserialize, Serialize};
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::env;
|
|
||||||
use tokio::select;
|
use tokio::select;
|
||||||
use tokio::signal::unix::{signal, SignalKind};
|
use tokio::signal::unix::{signal, SignalKind};
|
||||||
|
use axfive_matrix_dicebot::matrix::SyncCommand;
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
use axfive_matrix_dicebot::bot::{DiceBot, Config};
|
||||||
#[serde(tag = "msgtype")]
|
use std::fs::read_to_string;
|
||||||
enum MessageContent {
|
|
||||||
#[serde(rename = "m.text")]
|
|
||||||
Text { body: String },
|
|
||||||
|
|
||||||
#[serde(other)]
|
|
||||||
Other,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
|
||||||
#[serde(tag = "membership")]
|
|
||||||
enum MemberContent {
|
|
||||||
#[serde(rename = "invite")]
|
|
||||||
Invite {
|
|
||||||
// TODO: maybe leave empty?
|
|
||||||
#[serde(default)]
|
|
||||||
#[serde(alias = "displayname")]
|
|
||||||
display_name: Option<String>,
|
|
||||||
},
|
|
||||||
|
|
||||||
#[serde(other)]
|
|
||||||
Other,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
|
||||||
struct RoomEvent {
|
|
||||||
content: MessageContent,
|
|
||||||
event_id: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
|
||||||
struct MemberEvent {
|
|
||||||
content: MemberContent,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
|
||||||
#[serde(tag = "type")]
|
|
||||||
enum Event {
|
|
||||||
#[serde(rename = "m.room.message")]
|
|
||||||
Room(RoomEvent),
|
|
||||||
#[serde(rename = "m.room.member")]
|
|
||||||
Member(MemberEvent),
|
|
||||||
|
|
||||||
#[serde(other)]
|
|
||||||
Other,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
|
||||||
struct Timeline {
|
|
||||||
events: Vec<Event>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
|
||||||
struct Room {
|
|
||||||
timeline: Timeline,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
|
||||||
struct Rooms {
|
|
||||||
invite: HashMap<String, serde_json::Value>,
|
|
||||||
join: HashMap<String, Room>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
|
||||||
struct SyncCommand {
|
|
||||||
next_batch: String,
|
|
||||||
rooms: Rooms,
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn sync<S: AsRef<str>>(key: S) -> Result<(), Box<dyn std::error::Error>> {
|
|
||||||
let body = reqwest::get(&format!(
|
|
||||||
"https://matrix.org/_matrix/client/r0/sync?access_token={}&timeout=3000",
|
|
||||||
key.as_ref()
|
|
||||||
))
|
|
||||||
.await?
|
|
||||||
.text()
|
|
||||||
.await?;
|
|
||||||
let sync: SyncCommand = serde_json::from_str(&body)?;
|
|
||||||
println!("{:#?}", sync);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let key = std::env::args()
|
let config_path = std::env::args()
|
||||||
.skip(1)
|
.skip(1)
|
||||||
.next()
|
.next()
|
||||||
.expect("Need a key as an argument");
|
.expect("Need a config as an argument");
|
||||||
|
let config = {
|
||||||
|
let contents = read_to_string(config_path)?;
|
||||||
|
toml::from_str(&contents)?
|
||||||
|
};
|
||||||
|
println!("Logging in");
|
||||||
|
let mut bot = DiceBot::new(config).await?;
|
||||||
|
println!("Logged in");
|
||||||
|
|
||||||
let mut sigint = signal(SignalKind::interrupt())?;
|
let mut sigint = signal(SignalKind::interrupt())?;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
println!("Loop");
|
||||||
select! {
|
select! {
|
||||||
_ = sigint.recv() => {
|
_ = sigint.recv() => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_ = sync(&key) => {
|
_ = bot.sync() => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
println!("Logging out");
|
||||||
|
bot.logout().await
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
use serde::{self, Deserialize, Serialize};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(tag = "msgtype")]
|
||||||
|
#[serde(rename = "m.text")]
|
||||||
|
pub struct TextMessage {
|
||||||
|
body: String
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need untagged because redactions are blank
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum MessageContent {
|
||||||
|
Text(TextMessage),
|
||||||
|
Other(serde_json::Value),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(tag = "membership")]
|
||||||
|
pub enum MemberContent {
|
||||||
|
#[serde(rename = "invite")]
|
||||||
|
Invite {
|
||||||
|
// TODO: maybe leave empty?
|
||||||
|
#[serde(default)]
|
||||||
|
#[serde(alias = "displayname")]
|
||||||
|
display_name: Option<String>,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[serde(other)]
|
||||||
|
Other,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct RoomEvent {
|
||||||
|
pub content: MessageContent,
|
||||||
|
pub event_id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct MemberEvent {
|
||||||
|
pub content: MemberContent,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(tag = "type")]
|
||||||
|
pub enum Event {
|
||||||
|
#[serde(rename = "m.room.message")]
|
||||||
|
Room(RoomEvent),
|
||||||
|
#[serde(rename = "m.room.member")]
|
||||||
|
Member(MemberEvent),
|
||||||
|
|
||||||
|
#[serde(other)]
|
||||||
|
Other,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct Timeline {
|
||||||
|
pub events: Vec<Event>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct Room {
|
||||||
|
pub timeline: Timeline,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct Rooms {
|
||||||
|
pub invite: HashMap<String, serde_json::Value>,
|
||||||
|
pub join: HashMap<String, Room>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct SyncCommand {
|
||||||
|
pub next_batch: String,
|
||||||
|
pub rooms: Rooms,
|
||||||
|
}
|
Loading…
Reference in New Issue