xmpp-rs/src/xmpp_codec.rs

164 lines
4.8 KiB
Rust
Raw Normal View History

2017-06-01 22:42:57 +00:00
use std;
2017-06-04 00:05:08 +00:00
use std::fmt::Write;
2017-06-01 22:42:57 +00:00
use std::str::from_utf8;
use std::io::{Error, ErrorKind};
use std::collections::HashMap;
2017-06-04 22:42:35 +00:00
use tokio_io::{AsyncRead, AsyncWrite};
2017-06-04 00:05:08 +00:00
use tokio_io::codec::{Framed, Encoder, Decoder};
2017-06-01 22:42:57 +00:00
use xml;
2017-06-04 00:05:08 +00:00
use bytes::*;
2017-06-01 22:42:57 +00:00
const NS_XMLNS: &'static str = "http://www.w3.org/2000/xmlns/";
const NS_STREAMS: &'static str = "http://etherx.jabber.org/streams";
const NS_CLIENT: &'static str = "jabber:client";
struct XMPPRoot {
builder: xml::ElementBuilder,
pub attributes: HashMap<(String, Option<String>), String>,
}
impl XMPPRoot {
fn new(root: xml::StartTag) -> Self {
let mut builder = xml::ElementBuilder::new();
let mut attributes = HashMap::new();
println!("root attributes: {:?}", root.attributes);
for (name_ns, value) in root.attributes {
match name_ns {
(ref name, None) if name == "xmlns" =>
builder.set_default_ns(value),
(ref prefix, Some(ref ns)) if ns == NS_XMLNS =>
builder.define_prefix(prefix.to_owned(), value),
_ => {
attributes.insert(name_ns, value);
},
}
}
XMPPRoot {
builder: builder,
attributes: attributes,
}
}
fn handle_event(&mut self, event: Result<xml::Event, xml::ParserError>)
-> Option<Result<xml::Element, xml::BuilderError>> {
self.builder.handle_event(event)
}
}
#[derive(Debug)]
pub enum Packet {
Error(Box<std::error::Error>),
StreamStart,
Stanza(xml::Element),
StreamEnd,
}
2017-06-02 23:58:31 +00:00
pub type XMPPStream<T> = Framed<T, XMPPCodec>;
2017-06-01 22:42:57 +00:00
pub struct XMPPCodec {
parser: xml::Parser,
root: Option<XMPPRoot>,
}
impl XMPPCodec {
pub fn new() -> Self {
XMPPCodec {
parser: xml::Parser::new(),
root: None,
}
}
2017-06-04 22:42:35 +00:00
pub fn frame_stream<S>(stream: S) -> Framed<S, XMPPCodec>
where S: AsyncRead + AsyncWrite
{
AsyncRead::framed(stream, XMPPCodec::new())
}
2017-06-01 22:42:57 +00:00
}
2017-06-04 00:05:08 +00:00
impl Decoder for XMPPCodec {
type Item = Packet;
type Error = Error;
2017-06-01 22:42:57 +00:00
2017-06-04 00:05:08 +00:00
fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
2017-06-02 23:58:31 +00:00
println!("XMPPCodec.decode {:?}", buf.len());
2017-06-04 00:05:08 +00:00
match from_utf8(buf.take().as_ref()) {
2017-06-01 22:42:57 +00:00
Ok(s) =>
self.parser.feed_str(s),
Err(e) =>
return Err(Error::new(ErrorKind::InvalidInput, e)),
}
2017-06-04 00:05:08 +00:00
let mut new_root: Option<XMPPRoot> = None;
let mut result = None;
2017-06-01 22:42:57 +00:00
for event in &mut self.parser {
2017-06-03 00:26:44 +00:00
match self.root {
None => {
2017-06-01 22:42:57 +00:00
// Expecting <stream:stream>
match event {
Ok(xml::Event::ElementStart(start_tag)) => {
2017-06-03 00:26:44 +00:00
self.root = Some(XMPPRoot::new(start_tag));
result = Some(Packet::StreamStart);
break
},
Err(e) => {
result = Some(Packet::Error(Box::new(e)));
break
2017-06-01 22:42:57 +00:00
},
_ =>
(),
}
}
2017-06-03 00:26:44 +00:00
Some(ref mut root) => {
2017-06-01 22:42:57 +00:00
match root.handle_event(event) {
None => (),
Some(Ok(stanza)) => {
println!("stanza: {}", stanza);
result = Some(Packet::Stanza(stanza));
break
2017-06-01 22:42:57 +00:00
},
Some(Err(e)) => {
result = Some(Packet::Error(Box::new(e)));
break
}
2017-06-01 22:42:57 +00:00
};
},
}
match new_root.take() {
None => (),
Some(root) => self.root = Some(root),
}
}
Ok(result)
2017-06-01 22:42:57 +00:00
}
2017-06-04 00:05:08 +00:00
fn decode_eof(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, Error> {
self.decode(buf)
}
}
impl Encoder for XMPPCodec {
type Item = Packet;
type Error = Error;
fn encode(&mut self, item: Self::Item, dst: &mut BytesMut) -> Result<(), Self::Error> {
match item {
2017-06-01 22:42:57 +00:00
Packet::StreamStart => {
2017-06-04 00:05:08 +00:00
write!(dst,
"<?xml version='1.0'?>\n
<stream:stream version='1.0' to='spaceboyz.net' xmlns='{}' xmlns:stream='{}'>\n",
NS_CLIENT, NS_STREAMS)
.map_err(|_| Error::from(ErrorKind::WriteZero))
2017-06-01 22:42:57 +00:00
},
2017-06-04 22:42:35 +00:00
Packet::Stanza(stanza) =>
write!(dst, "{}", stanza)
.map_err(|_| Error::from(ErrorKind::InvalidInput)),
2017-06-01 22:42:57 +00:00
// TODO: Implement all
_ => Ok(())
}
}
}