mirror of
https://gitlab.com/xmpp-rs/xmpp-rs.git
synced 2024-07-12 22:21:53 +00:00
doc
This commit is contained in:
parent
0e4941dc7a
commit
b929a3c71e
7 changed files with 57 additions and 3 deletions
|
@ -22,7 +22,9 @@ use self::auth::ClientAuth;
|
||||||
mod bind;
|
mod bind;
|
||||||
use self::bind::ClientBind;
|
use self::bind::ClientBind;
|
||||||
|
|
||||||
|
/// XMPP client connection and state
|
||||||
pub struct Client {
|
pub struct Client {
|
||||||
|
/// The client's current Jabber-Id
|
||||||
pub jid: Jid,
|
pub jid: Jid,
|
||||||
state: ClientState,
|
state: ClientState,
|
||||||
}
|
}
|
||||||
|
@ -38,6 +40,10 @@ enum ClientState {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
|
/// Start a new XMPP client
|
||||||
|
///
|
||||||
|
/// Start polling the returned instance so that it will connect
|
||||||
|
/// and yield events.
|
||||||
pub fn new(jid: &str, password: &str, handle: Handle) -> Result<Self, JidParseError> {
|
pub fn new(jid: &str, password: &str, handle: Handle) -> Result<Self, JidParseError> {
|
||||||
let jid = try!(Jid::from_str(jid));
|
let jid = try!(Jid::from_str(jid));
|
||||||
let password = password.to_owned();
|
let password = password.to_owned();
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
//! Components in XMPP are services/gateways that are logged into an
|
||||||
|
//! XMPP server under a JID consisting of just a domain name. They are
|
||||||
|
//! allowed to use any user and resource identifiers in their stanzas.
|
||||||
use std::mem::replace;
|
use std::mem::replace;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
@ -16,7 +19,9 @@ use super::event::Event;
|
||||||
mod auth;
|
mod auth;
|
||||||
use self::auth::ComponentAuth;
|
use self::auth::ComponentAuth;
|
||||||
|
|
||||||
|
/// Component connection to an XMPP server
|
||||||
pub struct Component {
|
pub struct Component {
|
||||||
|
/// The component's Jabber-Id
|
||||||
pub jid: Jid,
|
pub jid: Jid,
|
||||||
state: ComponentState,
|
state: ComponentState,
|
||||||
}
|
}
|
||||||
|
@ -32,6 +37,10 @@ enum ComponentState {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component {
|
impl Component {
|
||||||
|
/// Start a new XMPP component
|
||||||
|
///
|
||||||
|
/// Start polling the returned instance so that it will connect
|
||||||
|
/// and yield events.
|
||||||
pub fn new(jid: &str, password: &str, server: &str, port: u16, handle: Handle) -> Result<Self, JidParseError> {
|
pub fn new(jid: &str, password: &str, server: &str, port: u16, handle: Handle) -> Result<Self, JidParseError> {
|
||||||
let jid = try!(Jid::from_str(jid));
|
let jid = try!(Jid::from_str(jid));
|
||||||
let password = password.to_owned();
|
let password = password.to_owned();
|
||||||
|
|
|
@ -1,13 +1,18 @@
|
||||||
use minidom::Element;
|
use minidom::Element;
|
||||||
|
|
||||||
|
/// High-level event on the Stream implemented by Client and Component
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
|
/// Stream is connected and initialized
|
||||||
Online,
|
Online,
|
||||||
|
/// Stream end
|
||||||
Disconnected,
|
Disconnected,
|
||||||
|
/// Received stanza/nonza
|
||||||
Stanza(Element),
|
Stanza(Element),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Event {
|
impl Event {
|
||||||
|
/// `Online` event?
|
||||||
pub fn is_online(&self) -> bool {
|
pub fn is_online(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
Event::Online => true,
|
Event::Online => true,
|
||||||
|
@ -15,6 +20,7 @@ impl Event {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `Stanza` event?
|
||||||
pub fn is_stanza(&self, name: &str) -> bool {
|
pub fn is_stanza(&self, name: &str) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
Event::Stanza(ref stanza) => stanza.name() == name,
|
Event::Stanza(ref stanza) => stanza.name() == name,
|
||||||
|
@ -22,6 +28,7 @@ impl Event {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If this is a `Stanza` event, get its data
|
||||||
pub fn as_stanza(&self) -> Option<&Element> {
|
pub fn as_stanza(&self) -> Option<&Element> {
|
||||||
match *self {
|
match *self {
|
||||||
Event::Stanza(ref stanza) => Some(stanza),
|
Event::Stanza(ref stanza) => Some(stanza),
|
||||||
|
@ -29,6 +36,7 @@ impl Event {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If this is a `Stanza` event, unwrap into its data
|
||||||
pub fn into_stanza(self) -> Option<Element> {
|
pub fn into_stanza(self) -> Option<Element> {
|
||||||
match self {
|
match self {
|
||||||
Event::Stanza(stanza) => Some(stanza),
|
Event::Stanza(stanza) => Some(stanza),
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
#![deny(unsafe_code, unused, missing_docs)]
|
||||||
|
|
||||||
|
//! XMPP implemeentation with asynchronous I/O using Tokio.
|
||||||
|
|
||||||
extern crate futures;
|
extern crate futures;
|
||||||
extern crate tokio_core;
|
extern crate tokio_core;
|
||||||
extern crate tokio_io;
|
extern crate tokio_io;
|
||||||
|
|
|
@ -11,10 +11,11 @@ use jid::Jid;
|
||||||
use xmpp_codec::Packet;
|
use xmpp_codec::Packet;
|
||||||
use xmpp_stream::XMPPStream;
|
use xmpp_stream::XMPPStream;
|
||||||
|
|
||||||
|
/// XMPP TLS XML namespace
|
||||||
pub const NS_XMPP_TLS: &str = "urn:ietf:params:xml:ns:xmpp-tls";
|
pub const NS_XMPP_TLS: &str = "urn:ietf:params:xml:ns:xmpp-tls";
|
||||||
|
|
||||||
|
|
||||||
|
/// XMPP stream that switches to TLS if available in received features
|
||||||
pub struct StartTlsClient<S: AsyncRead + AsyncWrite> {
|
pub struct StartTlsClient<S: AsyncRead + AsyncWrite> {
|
||||||
state: StartTlsClientState<S>,
|
state: StartTlsClientState<S>,
|
||||||
jid: Jid,
|
jid: Jid,
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//! XML stream parser for XMPP
|
||||||
|
|
||||||
use std;
|
use std;
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
|
@ -15,17 +17,22 @@ use xml5ever::interface::Attribute;
|
||||||
use bytes::{BytesMut, BufMut};
|
use bytes::{BytesMut, BufMut};
|
||||||
use quick_xml::Writer as EventWriter;
|
use quick_xml::Writer as EventWriter;
|
||||||
|
|
||||||
// const NS_XMLNS: &'static str = "http://www.w3.org/2000/xmlns/";
|
/// Anything that can be sent or received on an XMPP/XML stream
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Packet {
|
pub enum Packet {
|
||||||
|
/// General error (`InvalidInput`)
|
||||||
Error(Box<std::error::Error>),
|
Error(Box<std::error::Error>),
|
||||||
|
/// `<stream:stream>` start tag
|
||||||
StreamStart(HashMap<String, String>),
|
StreamStart(HashMap<String, String>),
|
||||||
|
/// A complete stanza or nonza
|
||||||
Stanza(Element),
|
Stanza(Element),
|
||||||
|
/// Plain text (think whitespace keep-alive)
|
||||||
Text(String),
|
Text(String),
|
||||||
|
/// `</stream:stream>` closing tag
|
||||||
StreamEnd,
|
StreamEnd,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parser state
|
||||||
struct ParserSink {
|
struct ParserSink {
|
||||||
// Ready stanzas, shared with XMPPCodec
|
// Ready stanzas, shared with XMPPCodec
|
||||||
queue: Rc<RefCell<VecDeque<Packet>>>,
|
queue: Rc<RefCell<VecDeque<Packet>>>,
|
||||||
|
@ -47,6 +54,7 @@ impl ParserSink {
|
||||||
self.queue.borrow_mut().push_back(pkt);
|
self.queue.borrow_mut().push_back(pkt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Lookup XML namespace declaration for given prefix (or no prefix)
|
||||||
fn lookup_ns(&self, prefix: &Option<String>) -> Option<&str> {
|
fn lookup_ns(&self, prefix: &Option<String>) -> Option<&str> {
|
||||||
for nss in self.ns_stack.iter().rev() {
|
for nss in self.ns_stack.iter().rev() {
|
||||||
if let Some(ns) = nss.get(prefix) {
|
if let Some(ns) = nss.get(prefix) {
|
||||||
|
@ -166,6 +174,7 @@ impl TokenSink for ParserSink {
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Stateful encoder/decoder for a bytestream from/to XMPP `Packet`
|
||||||
pub struct XMPPCodec {
|
pub struct XMPPCodec {
|
||||||
/// Outgoing
|
/// Outgoing
|
||||||
ns: Option<String>,
|
ns: Option<String>,
|
||||||
|
@ -179,6 +188,7 @@ pub struct XMPPCodec {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl XMPPCodec {
|
impl XMPPCodec {
|
||||||
|
/// Constructor
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let queue = Rc::new(RefCell::new(VecDeque::new()));
|
let queue = Rc::new(RefCell::new(VecDeque::new()));
|
||||||
let sink = ParserSink::new(queue.clone());
|
let sink = ParserSink::new(queue.clone());
|
||||||
|
@ -300,6 +310,7 @@ impl Encoder for XMPPCodec {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Write XML-escaped text string
|
||||||
pub fn write_text<W: Write>(text: &str, writer: &mut W) -> Result<(), std::fmt::Error> {
|
pub fn write_text<W: Write>(text: &str, writer: &mut W) -> Result<(), std::fmt::Error> {
|
||||||
write!(writer, "{}", escape(text))
|
write!(writer, "{}", escape(text))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//! `XMPPStream` is the common container for all XMPP network connections
|
||||||
|
|
||||||
use futures::{Poll, Stream, Sink, StartSend};
|
use futures::{Poll, Stream, Sink, StartSend};
|
||||||
use futures::sink::Send;
|
use futures::sink::Send;
|
||||||
use tokio_io::{AsyncRead, AsyncWrite};
|
use tokio_io::{AsyncRead, AsyncWrite};
|
||||||
|
@ -8,16 +10,26 @@ use jid::Jid;
|
||||||
use xmpp_codec::{XMPPCodec, Packet};
|
use xmpp_codec::{XMPPCodec, Packet};
|
||||||
use stream_start::StreamStart;
|
use stream_start::StreamStart;
|
||||||
|
|
||||||
|
/// <stream:stream> namespace
|
||||||
pub const NS_XMPP_STREAM: &str = "http://etherx.jabber.org/streams";
|
pub const NS_XMPP_STREAM: &str = "http://etherx.jabber.org/streams";
|
||||||
|
|
||||||
|
/// Wraps a `stream`
|
||||||
pub struct XMPPStream<S> {
|
pub struct XMPPStream<S> {
|
||||||
|
/// The local Jabber-Id
|
||||||
pub jid: Jid,
|
pub jid: Jid,
|
||||||
|
/// Codec instance
|
||||||
pub stream: Framed<S, XMPPCodec>,
|
pub stream: Framed<S, XMPPCodec>,
|
||||||
|
/// `<stream:features/>` for XMPP version 1.0
|
||||||
pub stream_features: Element,
|
pub stream_features: Element,
|
||||||
|
/// Root namespace
|
||||||
|
///
|
||||||
|
/// This is different for either c2s, s2s, or component
|
||||||
|
/// connections.
|
||||||
pub ns: String,
|
pub ns: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: AsyncRead + AsyncWrite> XMPPStream<S> {
|
impl<S: AsyncRead + AsyncWrite> XMPPStream<S> {
|
||||||
|
/// Constructor
|
||||||
pub fn new(jid: Jid,
|
pub fn new(jid: Jid,
|
||||||
stream: Framed<S, XMPPCodec>,
|
stream: Framed<S, XMPPCodec>,
|
||||||
ns: String,
|
ns: String,
|
||||||
|
@ -25,15 +37,18 @@ impl<S: AsyncRead + AsyncWrite> XMPPStream<S> {
|
||||||
XMPPStream { jid, stream, stream_features, ns }
|
XMPPStream { jid, stream, stream_features, ns }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Send a `<stream:stream>` start tag
|
||||||
pub fn start(stream: S, jid: Jid, ns: String) -> StreamStart<S> {
|
pub fn start(stream: S, jid: Jid, ns: String) -> StreamStart<S> {
|
||||||
let xmpp_stream = Framed::new(stream, XMPPCodec::new());
|
let xmpp_stream = Framed::new(stream, XMPPCodec::new());
|
||||||
StreamStart::from_stream(xmpp_stream, jid, ns)
|
StreamStart::from_stream(xmpp_stream, jid, ns)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Unwraps the inner stream
|
||||||
pub fn into_inner(self) -> S {
|
pub fn into_inner(self) -> S {
|
||||||
self.stream.into_inner()
|
self.stream.into_inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Re-run `start()`
|
||||||
pub fn restart(self) -> StreamStart<S> {
|
pub fn restart(self) -> StreamStart<S> {
|
||||||
Self::start(self.stream.into_inner(), self.jid, self.ns)
|
Self::start(self.stream.into_inner(), self.jid, self.ns)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue