|
|
@@ -5,104 +5,117 @@ use std::sync::Arc; |
|
|
|
use futures::compat::Stream01CompatExt; |
|
|
|
use futures::prelude::*; |
|
|
|
|
|
|
|
use hyper::client::connect::dns::GaiResolver; |
|
|
|
use hyper::client::connect::HttpConnector; |
|
|
|
use hyper_tls::HttpsConnector; |
|
|
|
|
|
|
|
use inotify::ffi::*; |
|
|
|
|
|
|
|
use tokio::fs as tokiofs; |
|
|
|
use tokio::prelude::*; |
|
|
|
use tokio::sync::mpsc; |
|
|
|
|
|
|
|
use tokio_inotify; |
|
|
|
|
|
|
|
use url::Url; |
|
|
|
//use ruma_client::Client; |
|
|
|
//use ruma_client_api::r0::message as rumamessage; |
|
|
|
//use ruma_events::{self, room::message::*}; |
|
|
|
|
|
|
|
use ruma_client::Client; |
|
|
|
use ruma_client_api::r0::message as rumamessage; |
|
|
|
use ruma_events::{self, room::message::*}; |
|
|
|
use ruma_identifiers::RoomId; |
|
|
|
use matrix_sdk::events::{ |
|
|
|
room::message::{MessageEventContent, TextMessageEventContent}, |
|
|
|
AnyMessageEventContent, |
|
|
|
}; |
|
|
|
use matrix_sdk::identifiers::RoomId; |
|
|
|
use matrix_sdk::uuid::Uuid; |
|
|
|
|
|
|
|
use crate::config::*; |
|
|
|
|
|
|
|
#[derive(Debug)] |
|
|
|
pub enum Error { |
|
|
|
BadUrl, |
|
|
|
MtxClient(ruma_client::Error), |
|
|
|
} |
|
|
|
|
|
|
|
impl From<ruma_client::Error> for Error { |
|
|
|
fn from(f: ruma_client::Error) -> Self { |
|
|
|
Self::MtxClient(f) |
|
|
|
} |
|
|
|
UnknownRoom(RoomId), |
|
|
|
Matrix(matrix_sdk::Error), |
|
|
|
} |
|
|
|
|
|
|
|
type MatrixClient = Client<HttpsConnector<HttpConnector<GaiResolver>>>; |
|
|
|
type MessageRequest = rumamessage::create_message_event::Request; |
|
|
|
|
|
|
|
pub struct Message { |
|
|
|
dest_room: RoomId, |
|
|
|
msg: String, |
|
|
|
text: String, |
|
|
|
delay_secs: u32, |
|
|
|
} |
|
|
|
|
|
|
|
pub type MatrixClient = matrix_sdk::Client; |
|
|
|
|
|
|
|
impl Message { |
|
|
|
pub fn new(dest_room: RoomId, msg: String) -> Self { |
|
|
|
Self::new_delay(dest_room, msg, 0) |
|
|
|
} |
|
|
|
|
|
|
|
pub fn new_delay(dest_room: RoomId, msg: String, delay_secs: u32) -> Self { |
|
|
|
pub fn new_delay(dest_room: RoomId, text: String, delay_secs: u32) -> Self { |
|
|
|
Self { |
|
|
|
dest_room, |
|
|
|
msg, |
|
|
|
text, |
|
|
|
delay_secs, |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
pub async fn create_and_auth_client(acct: Account) -> Result<Arc<MatrixClient>, Error> { |
|
|
|
let hs_url = Url::parse(&acct.homeserver).map_err(|_| Error::BadUrl)?; |
|
|
|
let c = MatrixClient::https(hs_url, None); |
|
|
|
let hs_url = url::Url::parse(&acct.homeserver).map_err(|_| Error::BadUrl)?; |
|
|
|
|
|
|
|
let cc = matrix_sdk::ClientConfig::new() |
|
|
|
.user_agent("mtxspooler") |
|
|
|
.unwrap(); |
|
|
|
let c = matrix_sdk::Client::new_with_config(hs_url, cc).map_err(Error::Matrix)?; |
|
|
|
|
|
|
|
// Now log in. |
|
|
|
match acct.auth { |
|
|
|
Auth::UsernamePass(un, pw) => c.log_in(un, pw, acct.device_id, acct.display).await?, |
|
|
|
}; |
|
|
|
Auth::UsernamePass(un, pw) => { |
|
|
|
let didref = acct.device_id.as_deref(); |
|
|
|
c.login(&un, &pw, didref, didref) |
|
|
|
.map_err(Error::Matrix) |
|
|
|
.await?; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
Ok(Arc::new(c)) |
|
|
|
} |
|
|
|
|
|
|
|
pub async fn submit_messages(cli: Arc<MatrixClient>, mut recv: mpsc::Receiver<Message>) { |
|
|
|
let mut rng = rand::thread_rng(); |
|
|
|
|
|
|
|
while let Some(msg) = recv.recv().await { |
|
|
|
let req = make_text_request(msg.dest_room.clone(), &msg.msg, &mut rng); |
|
|
|
if let Err(e) = cli.request(req).await { |
|
|
|
panic!("[client] error sending request: {:?}", e); |
|
|
|
if let Err(e) = do_submit_msg(&msg, &cli).await { |
|
|
|
panic!("[client] error handling message submission: {:?}", e); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
fn make_text_request<R: rand::Rng>(room_id: RoomId, msg: &str, rng: &mut R) -> MessageRequest { |
|
|
|
let inner = TextMessageEventContent { |
|
|
|
body: String::from(msg), |
|
|
|
format: None, |
|
|
|
formatted_body: None, |
|
|
|
relates_to: None, |
|
|
|
}; |
|
|
|
let mec = MessageEventContent::Text(inner); |
|
|
|
MessageRequest { |
|
|
|
room_id: room_id, |
|
|
|
event_type: ruma_events::EventType::RoomMessage, |
|
|
|
txn_id: make_txn_id(rng), |
|
|
|
data: mec, |
|
|
|
} |
|
|
|
} |
|
|
|
async fn do_submit_msg(msg: &Message, cli: &Arc<MatrixClient>) -> Result<(), Error> { |
|
|
|
let jroom = get_room_try_join(cli, &msg.dest_room).await?; |
|
|
|
|
|
|
|
const TXN_ID_LEN: usize = 20; |
|
|
|
let mec = MessageEventContent::text_plain(&msg.text); |
|
|
|
let ec = AnyMessageEventContent::RoomMessage(mec); |
|
|
|
jroom.send(ec, None).map_err(Error::Matrix).await?; |
|
|
|
|
|
|
|
fn make_txn_id<R: rand::Rng>(rng: &mut R) -> String { |
|
|
|
let mut buf = String::with_capacity(TXN_ID_LEN); |
|
|
|
for _ in 0..TXN_ID_LEN { |
|
|
|
buf.push((rng.gen_range(0, 26) + ('a' as u8)) as char); |
|
|
|
Ok(()) |
|
|
|
} |
|
|
|
|
|
|
|
pub async fn get_room_try_join( |
|
|
|
cli: &Arc<MatrixClient>, |
|
|
|
rid: &RoomId, |
|
|
|
) -> Result<matrix_sdk::room::Joined, Error> { |
|
|
|
use matrix_sdk::room::*; |
|
|
|
match cli |
|
|
|
.get_room(rid) |
|
|
|
.ok_or_else(|| Error::UnknownRoom(rid.clone()))? |
|
|
|
{ |
|
|
|
Room::Joined(j) => Ok(j), |
|
|
|
Room::Invited(i) => { |
|
|
|
i.accept_invitation().map_err(Error::Matrix).await?; |
|
|
|
Ok(cli.get_joined_room(rid).expect("client: get invited room")) |
|
|
|
} |
|
|
|
Room::Left(l) => { |
|
|
|
l.join().map_err(Error::Matrix).await?; |
|
|
|
Ok(cli.get_joined_room(rid).expect("client: get room joined")) |
|
|
|
} |
|
|
|
} |
|
|
|
buf |
|
|
|
} |
|
|
|
|
|
|
|
fn gen_device_id(un: &str, pw: &str) -> String { |
|
|
|
use sha2::Digest; |
|
|
|
let mut hasher = sha2::Sha256::new(); |
|
|
|
hasher.update(un.as_bytes()); |
|
|
|
hasher.update("\0"); |
|
|
|
hasher.update(pw.as_bytes()); |
|
|
|
hasher.update("\0_mtxspooler_salt"); |
|
|
|
let h: [u8; 32] = hasher.finalize().into(); |
|
|
|
hex::encode(h) |
|
|
|
} |