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::signal::unix::{signal, SignalKind};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[serde(tag = "msgtype")]
|
||||
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(())
|
||||
}
|
||||
use axfive_matrix_dicebot::matrix::SyncCommand;
|
||||
use axfive_matrix_dicebot::bot::{DiceBot, Config};
|
||||
use std::fs::read_to_string;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let key = std::env::args()
|
||||
let config_path = std::env::args()
|
||||
.skip(1)
|
||||
.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())?;
|
||||
|
||||
loop {
|
||||
println!("Loop");
|
||||
select! {
|
||||
_ = sigint.recv() => {
|
||||
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