mirror of
https://gitlab.com/xmpp-rs/xmpp-rs.git
synced 2024-07-12 22:21:53 +00:00
add a plugin to query and cache caps
This commit is contained in:
parent
1b21ebc6b0
commit
0fbe09ad59
3 changed files with 143 additions and 0 deletions
|
@ -8,6 +8,7 @@ use xmpp::plugins::unhandled_iq::UnhandledIqPlugin;
|
||||||
use xmpp::plugins::messaging::{MessagingPlugin, MessageEvent};
|
use xmpp::plugins::messaging::{MessagingPlugin, MessageEvent};
|
||||||
use xmpp::plugins::presence::{PresencePlugin, Type, Show};
|
use xmpp::plugins::presence::{PresencePlugin, Type, Show};
|
||||||
use xmpp::plugins::disco::DiscoPlugin;
|
use xmpp::plugins::disco::DiscoPlugin;
|
||||||
|
use xmpp::plugins::caps::CapsPlugin;
|
||||||
use xmpp::plugins::ibb::IbbPlugin;
|
use xmpp::plugins::ibb::IbbPlugin;
|
||||||
use xmpp::plugins::ping::PingPlugin;
|
use xmpp::plugins::ping::PingPlugin;
|
||||||
use xmpp::event::{Priority, Propagation};
|
use xmpp::event::{Priority, Propagation};
|
||||||
|
@ -29,6 +30,7 @@ fn main() {
|
||||||
client.register_plugin(MessagingPlugin::new());
|
client.register_plugin(MessagingPlugin::new());
|
||||||
client.register_plugin(PresencePlugin::new());
|
client.register_plugin(PresencePlugin::new());
|
||||||
client.register_plugin(DiscoPlugin::new("client", "bot", "en", "xmpp-rs"));
|
client.register_plugin(DiscoPlugin::new("client", "bot", "en", "xmpp-rs"));
|
||||||
|
client.register_plugin(CapsPlugin::new());
|
||||||
client.register_plugin(IbbPlugin::new());
|
client.register_plugin(IbbPlugin::new());
|
||||||
client.register_plugin(PingPlugin::new());
|
client.register_plugin(PingPlugin::new());
|
||||||
client.plugin::<PingPlugin>().init();
|
client.plugin::<PingPlugin>().init();
|
||||||
|
|
140
src/plugins/caps.rs
Normal file
140
src/plugins/caps.rs
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
use std::sync::{Mutex, Arc};
|
||||||
|
|
||||||
|
use plugin::PluginProxy;
|
||||||
|
use event::{Event, Priority, Propagation};
|
||||||
|
use jid::Jid;
|
||||||
|
use base64;
|
||||||
|
|
||||||
|
use plugins::stanza::{Presence, Iq};
|
||||||
|
use plugins::disco::DiscoInfoResult;
|
||||||
|
use xmpp_parsers::presence::Type as PresenceType;
|
||||||
|
use xmpp_parsers::iq::IqType;
|
||||||
|
use xmpp_parsers::disco::Disco;
|
||||||
|
use xmpp_parsers::caps::Caps;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DiscoInfoRequest {
|
||||||
|
pub from: Jid,
|
||||||
|
pub id: String,
|
||||||
|
pub node: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Event for DiscoInfoRequest {}
|
||||||
|
|
||||||
|
pub struct CapsPlugin {
|
||||||
|
proxy: PluginProxy,
|
||||||
|
pending: Arc<Mutex<HashMap<Jid, (String, String)>>>,
|
||||||
|
cache: Arc<Mutex<HashMap<(Jid, String), Disco>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CapsPlugin {
|
||||||
|
pub fn new() -> CapsPlugin {
|
||||||
|
CapsPlugin {
|
||||||
|
proxy: PluginProxy::new(),
|
||||||
|
pending: Arc::new(Mutex::new(HashMap::new())),
|
||||||
|
cache: Arc::new(Mutex::new(HashMap::new())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_presence(&self, presence: &Presence) -> Propagation {
|
||||||
|
let presence = presence.clone();
|
||||||
|
match presence.type_ {
|
||||||
|
PresenceType::None => for payload in presence.payloads {
|
||||||
|
let caps = match Caps::try_from(payload) {
|
||||||
|
Ok(caps) => caps,
|
||||||
|
Err(_) => continue,
|
||||||
|
};
|
||||||
|
let recipient = presence.from.unwrap();
|
||||||
|
let node = format!("{}#{}", caps.node, base64::encode(&caps.hash.hash));
|
||||||
|
{
|
||||||
|
let cache = self.cache.lock().unwrap();
|
||||||
|
if cache.contains_key(&(recipient.clone(), node.clone())) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let id = self.proxy.gen_id();
|
||||||
|
{
|
||||||
|
let mut pending = self.pending.lock().unwrap();
|
||||||
|
pending.insert(recipient.clone(), (id.clone(), node.clone()));
|
||||||
|
}
|
||||||
|
let disco = Disco {
|
||||||
|
node: Some(node),
|
||||||
|
identities: vec!(),
|
||||||
|
features: vec!(),
|
||||||
|
extensions: vec!(),
|
||||||
|
};
|
||||||
|
self.proxy.send(Iq {
|
||||||
|
to: Some(recipient),
|
||||||
|
from: None,
|
||||||
|
id: Some(id),
|
||||||
|
payload: IqType::Get(disco.into()),
|
||||||
|
}.into());
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
PresenceType::Unavailable
|
||||||
|
| PresenceType::Error => {
|
||||||
|
let recipient = presence.from.unwrap();
|
||||||
|
let mut pending = self.pending.lock().unwrap();
|
||||||
|
let previous = pending.remove(&recipient);
|
||||||
|
if previous.is_none() {
|
||||||
|
// This wasn’t one of our requests.
|
||||||
|
return Propagation::Continue;
|
||||||
|
}
|
||||||
|
// TODO: maybe add a negative cache?
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
Propagation::Continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_result(&self, result: &DiscoInfoResult) -> Propagation {
|
||||||
|
let from = result.from.clone();
|
||||||
|
let mut pending = self.pending.lock().unwrap();
|
||||||
|
let previous = pending.remove(&from.clone());
|
||||||
|
if let Some((id, node)) = previous {
|
||||||
|
if id != result.id {
|
||||||
|
return Propagation::Continue;
|
||||||
|
}
|
||||||
|
if Some(node.clone()) != result.disco.node {
|
||||||
|
// TODO: make that a debug log.
|
||||||
|
println!("Wrong node in result!");
|
||||||
|
return Propagation::Continue;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let mut cache = self.cache.lock().unwrap();
|
||||||
|
cache.insert((from, node), result.disco.clone());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// TODO: make that a debug log.
|
||||||
|
println!("No such request from us.");
|
||||||
|
return Propagation::Continue;
|
||||||
|
}
|
||||||
|
Propagation::Stop
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is only for errors.
|
||||||
|
// TODO: also do the same thing for timeouts.
|
||||||
|
fn handle_iq(&self, iq: &Iq) -> Propagation {
|
||||||
|
let iq = iq.clone();
|
||||||
|
if let IqType::Error(_) = iq.payload {
|
||||||
|
let from = iq.from.unwrap();
|
||||||
|
let mut pending = self.pending.lock().unwrap();
|
||||||
|
let previous = pending.remove(&from.clone());
|
||||||
|
if previous.is_none() {
|
||||||
|
// This wasn’t one of our requests.
|
||||||
|
return Propagation::Continue;
|
||||||
|
}
|
||||||
|
// TODO: maybe add a negative cache?
|
||||||
|
return Propagation::Stop;
|
||||||
|
}
|
||||||
|
Propagation::Continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_plugin!(CapsPlugin, proxy, [
|
||||||
|
(Presence, Priority::Default) => handle_presence,
|
||||||
|
(Iq, Priority::Default) => handle_iq,
|
||||||
|
(DiscoInfoResult, Priority::Default) => handle_result,
|
||||||
|
]);
|
|
@ -2,6 +2,7 @@ pub mod messaging;
|
||||||
pub mod presence;
|
pub mod presence;
|
||||||
pub mod roster;
|
pub mod roster;
|
||||||
pub mod disco;
|
pub mod disco;
|
||||||
|
pub mod caps;
|
||||||
pub mod ping;
|
pub mod ping;
|
||||||
pub mod ibb;
|
pub mod ibb;
|
||||||
pub mod stanza;
|
pub mod stanza;
|
||||||
|
|
Loading…
Reference in a new issue