implement send_stanza
This commit is contained in:
parent
4886396044
commit
21f10a0b43
|
@ -0,0 +1,10 @@
|
|||
# jabber client library
|
||||
|
||||
## TODO:
|
||||
|
||||
- [ ] error states for all negotiation parts
|
||||
- [ ] better errors
|
||||
- [ ] rename structs
|
||||
- [ ] remove commented code
|
||||
- [ ] asynchronous connect (with take_mut?)
|
||||
- [ ] split into separate crates: stanza, jabber, and luz
|
|
@ -44,6 +44,8 @@ impl JabberClient {
|
|||
pub async fn connect(&mut self) -> Result<()> {
|
||||
match &self.connection {
|
||||
ConnectionState::Disconnected => {
|
||||
// TODO: actually set the self.connection as it is connecting, make more asynchronous (mutex while connecting?)
|
||||
// perhaps use take_mut?
|
||||
self.connection = ConnectionState::Disconnected
|
||||
.connect(&mut self.jid, self.password.clone(), &mut self.server)
|
||||
.await?;
|
||||
|
@ -53,6 +55,16 @@ impl JabberClient {
|
|||
ConnectionState::Connected(_jabber_stream) => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn send_stanza(&mut self, stanza: &Stanza) -> Result<()> {
|
||||
match &mut self.connection {
|
||||
ConnectionState::Disconnected => return Err(Error::Disconnected),
|
||||
ConnectionState::Connecting(_connecting) => return Err(Error::Connecting),
|
||||
ConnectionState::Connected(jabber_stream) => {
|
||||
Ok(jabber_stream.send_stanza(stanza).await?)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Stream for JabberClient {
|
||||
|
@ -217,38 +229,6 @@ pub enum InsecureConnecting {
|
|||
Bound(JabberStream<Tls>),
|
||||
}
|
||||
|
||||
impl Sink<Stanza> for JabberClient {
|
||||
type Error = Error;
|
||||
|
||||
fn poll_ready(
|
||||
self: std::pin::Pin<&mut Self>,
|
||||
cx: &mut std::task::Context<'_>,
|
||||
) -> std::task::Poll<std::result::Result<(), Self::Error>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn start_send(
|
||||
self: std::pin::Pin<&mut Self>,
|
||||
item: Stanza,
|
||||
) -> std::result::Result<(), Self::Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn poll_flush(
|
||||
self: std::pin::Pin<&mut Self>,
|
||||
cx: &mut std::task::Context<'_>,
|
||||
) -> std::task::Poll<std::result::Result<(), Self::Error>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn poll_close(
|
||||
self: std::pin::Pin<&mut Self>,
|
||||
cx: &mut std::task::Context<'_>,
|
||||
) -> std::task::Poll<std::result::Result<(), Self::Error>> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::time::Duration;
|
||||
|
|
|
@ -3,6 +3,7 @@ use std::str::Utf8Error;
|
|||
use rsasl::mechname::MechanismNameError;
|
||||
|
||||
use crate::stanza::client::error::Error as ClientError;
|
||||
use crate::stanza::stream::Error as StreamError;
|
||||
use crate::{jid::ParseError, stanza::sasl::Failure};
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -22,7 +23,10 @@ pub enum Error {
|
|||
JID(ParseError),
|
||||
Authentication(Failure),
|
||||
ClientError(ClientError),
|
||||
StreamError(StreamError),
|
||||
MissingError,
|
||||
Disconnected,
|
||||
Connecting,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
@ -50,6 +50,7 @@ where
|
|||
S: AsyncRead + AsyncWrite + Unpin + Send + std::fmt::Debug,
|
||||
JabberStream<S>: std::fmt::Debug,
|
||||
{
|
||||
#[instrument]
|
||||
pub async fn sasl(mut self, mechanisms: Mechanisms, sasl_config: Arc<SASLConfig>) -> Result<S> {
|
||||
let sasl = SASLClient::new(sasl_config);
|
||||
let mut offered_mechs: Vec<&Mechname> = Vec::new();
|
||||
|
@ -139,6 +140,7 @@ where
|
|||
Ok(stream)
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
pub async fn bind(mut self, jid: &mut JID) -> Result<Self> {
|
||||
let iq_id = nanoid::nanoid!();
|
||||
if let Some(resource) = &jid.resourcepart {
|
||||
|
@ -266,6 +268,7 @@ where
|
|||
Ok(Self { reader, writer })
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
pub async fn get_features(mut self) -> Result<(Features, Self)> {
|
||||
debug!("getting features");
|
||||
let features: Features = self.reader.read().await?;
|
||||
|
@ -276,91 +279,16 @@ where
|
|||
pub fn into_inner(self) -> S {
|
||||
self.reader.into_inner().unsplit(self.writer.into_inner())
|
||||
}
|
||||
|
||||
pub async fn send_stanza(&mut self, stanza: &Stanza) -> Result<()> {
|
||||
self.writer.write(stanza).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl JabberStream<Unencrypted> {
|
||||
// pub async fn negotiate<S: AsyncRead + AsyncWrite + Unpin>(
|
||||
// mut self,
|
||||
// features: Features,
|
||||
// ) -> Result<Feature> {
|
||||
// // TODO: timeout
|
||||
// if let Some(Feature::StartTls(_)) = features
|
||||
// .features
|
||||
// .iter()
|
||||
// .find(|feature| matches!(feature, Feature::StartTls(_s)))
|
||||
// {
|
||||
// return Ok(self);
|
||||
// } else {
|
||||
// // TODO: better error
|
||||
// return Err(Error::TlsRequired);
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[async_recursion]
|
||||
// pub async fn negotiate_tls_optional(mut self) -> Result<Connection> {
|
||||
// self.start_stream().await?;
|
||||
// // TODO: timeout
|
||||
// let features = self.get_features().await?.features;
|
||||
// if let Some(Feature::StartTls(_)) = features
|
||||
// .iter()
|
||||
// .find(|feature| matches!(feature, Feature::StartTls(_s)))
|
||||
// {
|
||||
// let jabber = self.starttls().await?;
|
||||
// let jabber = jabber.negotiate().await?;
|
||||
// return Ok(Connection::Encrypted(jabber));
|
||||
// } else if let (Some(sasl_config), Some(Feature::Sasl(mechanisms))) = (
|
||||
// self.auth.clone(),
|
||||
// features
|
||||
// .iter()
|
||||
// .find(|feature| matches!(feature, Feature::Sasl(_))),
|
||||
// ) {
|
||||
// self.sasl(mechanisms.clone(), sasl_config).await?;
|
||||
// let jabber = self.negotiate_tls_optional().await?;
|
||||
// Ok(jabber)
|
||||
// } else if let Some(Feature::Bind) = features
|
||||
// .iter()
|
||||
// .find(|feature| matches!(feature, Feature::Bind))
|
||||
// {
|
||||
// self.bind().await?;
|
||||
// Ok(Connection::Unencrypted(self))
|
||||
// } else {
|
||||
// // TODO: better error
|
||||
// return Err(Error::Negotiation);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
impl JabberStream<Tls> {
|
||||
// #[async_recursion]
|
||||
// pub async fn negotiate(mut self) -> Result<JabberStream<Tls>> {
|
||||
// self.start_stream().await?;
|
||||
// let features = self.get_features().await?.features;
|
||||
|
||||
// if let (Some(sasl_config), Some(Feature::Sasl(mechanisms))) = (
|
||||
// self.auth.clone(),
|
||||
// features
|
||||
// .iter()
|
||||
// .find(|feature| matches!(feature, Feature::Sasl(_))),
|
||||
// ) {
|
||||
// // TODO: avoid clone
|
||||
// self.sasl(mechanisms.clone(), sasl_config).await?;
|
||||
// let jabber = self.negotiate().await?;
|
||||
// Ok(jabber)
|
||||
// } else if let Some(Feature::Bind) = features
|
||||
// .iter()
|
||||
// .find(|feature| matches!(feature, Feature::Bind))
|
||||
// {
|
||||
// self.bind().await?;
|
||||
// Ok(self)
|
||||
// } else {
|
||||
// // TODO: better error
|
||||
// return Err(Error::Negotiation);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
impl JabberStream<Unencrypted> {
|
||||
pub async fn starttls(mut self, domain: impl AsRef<str>) -> Result<Tls> {
|
||||
#[instrument]
|
||||
pub async fn starttls(mut self, domain: impl AsRef<str> + std::fmt::Debug) -> Result<Tls> {
|
||||
self.writer
|
||||
.write_full(&StartTls { required: false })
|
||||
.await?;
|
||||
|
@ -372,8 +300,6 @@ impl JabberStream<Unencrypted> {
|
|||
.connect(domain.as_ref(), stream)
|
||||
.await
|
||||
{
|
||||
// let (read, write) = tokio::io::split(tlsstream);
|
||||
// let client = JabberStream::new(read, write);
|
||||
return Ok(tls_stream);
|
||||
} else {
|
||||
return Err(Error::Connection);
|
||||
|
|
|
@ -164,6 +164,7 @@ impl FromElement for Feature {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Error {
|
||||
error: StreamError,
|
||||
text: Option<Text>,
|
||||
|
|
|
@ -5,7 +5,7 @@ use peanuts::{
|
|||
|
||||
pub const XMLNS: &str = "urn:ietf:params:xml:ns:xmpp-streams";
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Error {
|
||||
BadFormat,
|
||||
BadNamespacePrefix,
|
||||
|
@ -110,7 +110,7 @@ impl IntoElement for Error {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Text {
|
||||
text: Option<String>,
|
||||
lang: Option<String>,
|
||||
|
|
Loading…
Reference in New Issue