rewrite using tokio-xmpp

This commit is contained in:
Travis Burtrum 2019-01-25 21:56:50 -05:00
parent 96278a310e
commit be37b512a5
3 changed files with 1366 additions and 186 deletions

1414
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -10,12 +10,16 @@ keywords = ["xmpp"]
license = "GPL-3.0+" license = "GPL-3.0+"
readme = "README.md" readme = "README.md"
edition = "2018"
[dependencies] [dependencies]
#xmpp = { git = "https://gitlab.com/lumi/xmpp-rs.git" } toml = "0.4.10"
xmpp = { path = "xmpp-rs", version = "0.2.0" } serde_derive = "1.0.85"
#xmpp = "0.2.0" serde = "1.0.85"
toml = "0.4.4" gumdrop = "0.5.0"
serde_derive = "1.0.11" gumdrop_derive = "0.5.0"
serde = "1.0.11" dirs = "1.0.4"
gumdrop = "0.3.0" tokio-xmpp = "0.2.3"
gumdrop_derive = "0.3.0" futures = "0.1"
tokio = "0.1"
xmpp-parsers = "0.12.2"

View File

@ -1,25 +1,19 @@
#[macro_use]
extern crate serde_derive;
extern crate toml;
extern crate gumdrop;
#[macro_use]
extern crate gumdrop_derive;
extern crate xmpp;
use xmpp::jid::Jid;
use xmpp::client::ClientBuilder;
use xmpp::plugins::messaging::MessagingPlugin;
use std::time::Duration;
use std::thread;
use std::env;
use std::iter::Iterator;
use std::io::{Read, stdin};
use std::fs::File;
use std::path::Path;
use std::env::args; use std::env::args;
use std::fs::File;
use std::io::{stdin, Read};
use std::iter::Iterator;
use std::path::Path;
use std::thread;
use std::time::Duration;
use gumdrop::Options; use gumdrop::Options;
use serde_derive::Deserialize;
use futures::{future, Sink, Stream};
use tokio::runtime::current_thread::Runtime;
use tokio_xmpp::Client;
use xmpp_parsers::message::{Body, Message};
use xmpp_parsers::{Element, Jid};
#[derive(Deserialize)] #[derive(Deserialize)]
struct Config { struct Config {
@ -34,12 +28,12 @@ fn parse_cfg<P: AsRef<Path>>(path: P) -> Option<Config> {
match f.read_to_string(&mut input) { match f.read_to_string(&mut input) {
Ok(_) => match toml::from_str(&input) { Ok(_) => match toml::from_str(&input) {
Ok(toml) => Some(toml), Ok(toml) => Some(toml),
Err(_) => None Err(_) => None,
}, },
Err(_) => None Err(_) => None,
} }
} }
Err(_) => None Err(_) => None,
} }
} }
@ -51,7 +45,9 @@ struct MyOptions {
#[options(help = "show this help message and exit")] #[options(help = "show this help message and exit")]
help: bool, help: bool,
#[options(help = "path to config file. default: ~/.config/sendxmpp.toml with fallback to /etc/sendxmpp/sendxmpp.toml")] #[options(
help = "path to config file. default: ~/.config/sendxmpp.toml with fallback to /etc/sendxmpp/sendxmpp.toml"
)]
config: Option<String>, config: Option<String>,
#[options(help = "Force OpenPGP encryption for all recipients", short = "e")] #[options(help = "Force OpenPGP encryption for all recipients", short = "e")]
@ -83,33 +79,77 @@ fn main() {
return; return;
} }
let recipients: Vec<Jid> = opts.recipients.iter().map(|s| s.parse::<Jid>().expect("invalid recipient jid")).collect(); let recipients: Vec<Jid> = opts
.recipients
.iter()
.map(|s| s.parse::<Jid>().expect("invalid recipient jid"))
.collect();
let recipients = &recipients;
let cfg = match opts.config { let cfg = match opts.config {
Some(config) => parse_cfg(&config).expect("provided config cannot be found/parsed"), Some(config) => parse_cfg(&config).expect("provided config cannot be found/parsed"),
None => parse_cfg(env::home_dir().expect("cannot find home directory").join(".config/sendxmpp.toml")) None => parse_cfg(
.or_else(|| parse_cfg("/etc/sendxmpp/sendxmpp.toml")).expect("valid config file not found") dirs::config_dir()
.expect("cannot find home directory")
.join("sendxmpp.toml"),
)
.or_else(|| parse_cfg("/etc/sendxmpp/sendxmpp.toml"))
.expect("valid config file not found"),
}; };
let jid: Jid = cfg.jid.parse().expect("invalid jid in config file");
let mut data = String::new(); let mut data = String::new();
stdin().read_to_string(&mut data).expect("error reading from stdin"); stdin()
.read_to_string(&mut data)
.expect("error reading from stdin");
let data = data.trim();
let mut client = ClientBuilder::new(jid) // tokio_core context
.password(cfg.password) let mut rt = Runtime::new().unwrap();
.connect() // Client instance
.expect("client cannot connect"); let client = Client::new(&cfg.jid, &cfg.password).expect("could not connect to xmpp server");
client.register_plugin(MessagingPlugin::new());
// Make the two interfaces for sending and receiving independent
// of each other so we can move one into a closure.
let (mut sink, stream) = client.split();
// Wrap sink in Option so that we can take() it for the send(self)
// to consume and return it back when ready.
let mut send = move |stanza| {
sink.start_send(stanza).expect("start_send");
};
// Main loop, processes events
let done = stream.for_each(|event| {
if event.is_online() {
for recipient in recipients { for recipient in recipients {
client.plugin::<MessagingPlugin>().send_message(&recipient, &data).expect("error sending message"); let reply = make_reply(recipient.clone(), &data);
send(reply);
} }
}
Box::new(future::ok(()))
});
thread::spawn(|| { thread::spawn(|| {
thread::sleep(Duration::from_millis(4000)); thread::sleep(Duration::from_millis(4000));
std::process::exit(0); std::process::exit(0);
}); });
client.main().expect("error during client main")
// Start polling `done`
match rt.block_on(done) {
Ok(_) => {
println!("successful exiting");
std::process::exit(0);
//()
}
Err(e) => {
println!("Fatal: {}", e);
()
}
};
}
// Construct a chat <message/>
fn make_reply(to: Jid, body: &str) -> Element {
let mut message = Message::new(Some(to));
message.bodies.insert(String::new(), Body(body.to_owned()));
message.into()
} }