WIP: code cleanup
This commit is contained in:
parent
a1d96233e8
commit
41c1ba15ef
|
@ -0,0 +1,166 @@
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
|
use jabber::{connection::Tls, jabber_stream::bound_stream::BoundJabberStream};
|
||||||
|
use read::ReadControlHandle;
|
||||||
|
use sqlx::SqlitePool;
|
||||||
|
use tokio::{
|
||||||
|
sync::{mpsc, oneshot},
|
||||||
|
task::{JoinHandle, JoinSet},
|
||||||
|
};
|
||||||
|
use write::{WriteControlHandle, WriteHandle, WriteMessage};
|
||||||
|
|
||||||
|
use crate::UpdateMessage;
|
||||||
|
|
||||||
|
mod read;
|
||||||
|
pub(crate) mod write;
|
||||||
|
|
||||||
|
pub struct Supervisor {
|
||||||
|
connection_commands: mpsc::Receiver<SupervisorCommand>,
|
||||||
|
writer_crash: oneshot::Receiver<(WriteMessage, mpsc::Receiver<WriteMessage>)>,
|
||||||
|
reader_crash: oneshot::Receiver<(
|
||||||
|
SqlitePool,
|
||||||
|
mpsc::Sender<UpdateMessage>,
|
||||||
|
tokio::task::JoinSet<()>,
|
||||||
|
)>,
|
||||||
|
sender: mpsc::Sender<UpdateMessage>,
|
||||||
|
writer_handle: WriteControlHandle,
|
||||||
|
reader_handle: ReadControlHandle,
|
||||||
|
on_shutdown: oneshot::Sender<()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum SupervisorCommand {
|
||||||
|
Disconnect,
|
||||||
|
// for if there was a stream error, require to reconnect
|
||||||
|
Reconnect,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Supervisor {
|
||||||
|
fn new(
|
||||||
|
connection_commands: mpsc::Receiver<SupervisorCommand>,
|
||||||
|
writer_crash: oneshot::Receiver<(WriteMessage, mpsc::Receiver<WriteMessage>)>,
|
||||||
|
reader_crash: oneshot::Receiver<(SqlitePool, mpsc::Sender<UpdateMessage>, JoinSet<()>)>,
|
||||||
|
sender: mpsc::Sender<UpdateMessage>,
|
||||||
|
writer_handle: WriteControlHandle,
|
||||||
|
reader_handle: ReadControlHandle,
|
||||||
|
on_shutdown: oneshot::Sender<()>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
connection_commands,
|
||||||
|
writer_crash,
|
||||||
|
sender,
|
||||||
|
writer_handle,
|
||||||
|
reader_handle,
|
||||||
|
reader_crash,
|
||||||
|
on_shutdown,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_command_message(&mut self, msg: SupervisorCommand) {}
|
||||||
|
|
||||||
|
async fn run(mut self) {
|
||||||
|
loop {
|
||||||
|
tokio::select! {
|
||||||
|
Some(msg) = self.connection_commands.recv() => {
|
||||||
|
self.handle_command_message(msg).await;
|
||||||
|
},
|
||||||
|
error = &mut self.writer_crash => {
|
||||||
|
|
||||||
|
},
|
||||||
|
error = &mut self.reader_crash => {
|
||||||
|
|
||||||
|
},
|
||||||
|
else => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.on_shutdown.send(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SupervisorHandle {
|
||||||
|
sender: SupervisorSender,
|
||||||
|
handle: JoinHandle<()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for SupervisorHandle {
|
||||||
|
type Target = SupervisorSender;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.sender
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for SupervisorHandle {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.sender
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SupervisorSender {
|
||||||
|
sender: mpsc::Sender<SupervisorCommand>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for SupervisorSender {
|
||||||
|
type Target = mpsc::Sender<SupervisorCommand>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.sender
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for SupervisorSender {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.sender
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SupervisorHandle {
|
||||||
|
pub fn new(
|
||||||
|
streams: BoundJabberStream<Tls>,
|
||||||
|
update_sender: mpsc::Sender<UpdateMessage>,
|
||||||
|
db: SqlitePool,
|
||||||
|
on_shutdown: oneshot::Sender<()>,
|
||||||
|
) -> (WriteHandle, Self) {
|
||||||
|
let (command_sender, command_receiver) = mpsc::channel(20);
|
||||||
|
let (writer_error_sender, writer_error_receiver) = oneshot::channel();
|
||||||
|
let (reader_crash_sender, reader_crash_receiver) = oneshot::channel();
|
||||||
|
|
||||||
|
let (reader, writer) = streams.split();
|
||||||
|
let (write_handle, write_control_handle) =
|
||||||
|
WriteControlHandle::new(writer, writer_error_sender);
|
||||||
|
let jabber_reader_control_handle = ReadControlHandle::new(
|
||||||
|
reader,
|
||||||
|
reader_crash_sender,
|
||||||
|
db,
|
||||||
|
update_sender.clone(),
|
||||||
|
command_sender.clone(),
|
||||||
|
write_handle.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let actor = Supervisor::new(
|
||||||
|
command_receiver,
|
||||||
|
writer_error_receiver,
|
||||||
|
reader_crash_receiver,
|
||||||
|
update_sender,
|
||||||
|
write_control_handle,
|
||||||
|
jabber_reader_control_handle,
|
||||||
|
on_shutdown,
|
||||||
|
);
|
||||||
|
|
||||||
|
let handle = tokio::spawn(async move { actor.run().await });
|
||||||
|
|
||||||
|
(
|
||||||
|
write_handle,
|
||||||
|
Self {
|
||||||
|
sender: SupervisorSender {
|
||||||
|
sender: command_sender,
|
||||||
|
},
|
||||||
|
handle,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sender(&self) -> SupervisorSender {
|
||||||
|
self.sender.clone()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,120 @@
|
||||||
|
use jabber::{connection::Tls, jabber_stream::bound_stream::BoundJabberReader};
|
||||||
|
use sqlx::SqlitePool;
|
||||||
|
use stanza::client::Stanza;
|
||||||
|
use tokio::{
|
||||||
|
sync::{mpsc, oneshot},
|
||||||
|
task::{JoinHandle, JoinSet},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::UpdateMessage;
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
write::{WriteHandle, WriteMessage},
|
||||||
|
SupervisorCommand,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Read {
|
||||||
|
// TODO: place iq hashmap here
|
||||||
|
control_receiver: mpsc::Receiver<ReadControl>,
|
||||||
|
stream: BoundJabberReader<Tls>,
|
||||||
|
on_crash: oneshot::Sender<(SqlitePool, mpsc::Sender<UpdateMessage>, JoinSet<()>)>,
|
||||||
|
db: SqlitePool,
|
||||||
|
update_sender: mpsc::Sender<UpdateMessage>,
|
||||||
|
supervisor_control: mpsc::Sender<SupervisorCommand>,
|
||||||
|
write_handle: WriteHandle,
|
||||||
|
tasks: JoinSet<()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Read {
|
||||||
|
fn new(
|
||||||
|
control_receiver: mpsc::Receiver<ReadControl>,
|
||||||
|
stream: BoundJabberReader<Tls>,
|
||||||
|
on_crash: oneshot::Sender<(SqlitePool, mpsc::Sender<UpdateMessage>, JoinSet<()>)>,
|
||||||
|
db: SqlitePool,
|
||||||
|
update_sender: mpsc::Sender<UpdateMessage>,
|
||||||
|
// jabber server must be able to both terminate the connection from error, and ask for data from the client (such as supported XEPs)
|
||||||
|
supervisor_control: mpsc::Sender<SupervisorCommand>,
|
||||||
|
write_sender: WriteHandle,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
control_receiver,
|
||||||
|
stream,
|
||||||
|
on_crash,
|
||||||
|
db,
|
||||||
|
update_sender,
|
||||||
|
supervisor_control,
|
||||||
|
write_handle: write_sender,
|
||||||
|
tasks: JoinSet::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run(mut self) {
|
||||||
|
loop {
|
||||||
|
tokio::select! {
|
||||||
|
Some(msg) = self.control_receiver.recv() => {
|
||||||
|
match msg {
|
||||||
|
ReadControl::Disconnect => todo!(),
|
||||||
|
ReadControl::Abort(sender) => todo!(),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
stanza = self.stream.read::<Stanza>() => {
|
||||||
|
match stanza {
|
||||||
|
Ok(_) => todo!(),
|
||||||
|
Err(_) => todo!(),
|
||||||
|
}
|
||||||
|
self.tasks.spawn();
|
||||||
|
},
|
||||||
|
else => break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Task {
|
||||||
|
async fn handle();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Task for Stanza {
|
||||||
|
async fn handle() {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ReadControl {
|
||||||
|
Disconnect,
|
||||||
|
Abort(oneshot::Sender<mpsc::Receiver<WriteMessage>>),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ReadControlHandle {
|
||||||
|
sender: mpsc::Sender<ReadControl>,
|
||||||
|
handle: JoinHandle<()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReadControlHandle {
|
||||||
|
pub fn new(
|
||||||
|
stream: BoundJabberReader<Tls>,
|
||||||
|
on_crash: oneshot::Sender<(SqlitePool, mpsc::Sender<UpdateMessage>, JoinSet<()>)>,
|
||||||
|
db: SqlitePool,
|
||||||
|
sender: mpsc::Sender<UpdateMessage>,
|
||||||
|
supervisor_control: mpsc::Sender<SupervisorCommand>,
|
||||||
|
jabber_write: WriteHandle,
|
||||||
|
) -> Self {
|
||||||
|
let (control_sender, control_receiver) = mpsc::channel(20);
|
||||||
|
|
||||||
|
let actor = Read::new(
|
||||||
|
control_receiver,
|
||||||
|
stream,
|
||||||
|
on_crash,
|
||||||
|
db,
|
||||||
|
sender,
|
||||||
|
supervisor_control,
|
||||||
|
jabber_write,
|
||||||
|
);
|
||||||
|
let handle = tokio::spawn(async move { actor.run().await });
|
||||||
|
|
||||||
|
Self {
|
||||||
|
sender: control_sender,
|
||||||
|
handle,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,171 @@
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
|
use jabber::{connection::Tls, jabber_stream::bound_stream::BoundJabberWriter};
|
||||||
|
use stanza::client::Stanza;
|
||||||
|
use tokio::{
|
||||||
|
sync::{mpsc, oneshot},
|
||||||
|
task::JoinHandle,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::error::Error;
|
||||||
|
|
||||||
|
// actor that receives jabber stanzas to write, and if there is an error, sends a message back to the supervisor then aborts, so the supervisor can spawn a new stream.
|
||||||
|
pub struct Write {
|
||||||
|
stanza_receiver: mpsc::Receiver<WriteMessage>,
|
||||||
|
control_receiver: mpsc::Receiver<WriteControl>,
|
||||||
|
stream: BoundJabberWriter<Tls>,
|
||||||
|
on_crash: oneshot::Sender<(WriteMessage, mpsc::Receiver<WriteMessage>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct WriteMessage {
|
||||||
|
stanza: Stanza,
|
||||||
|
respond_to: oneshot::Sender<Result<(), Error>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum WriteControl {
|
||||||
|
Disconnect,
|
||||||
|
Abort(oneshot::Sender<mpsc::Receiver<WriteMessage>>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Write {
|
||||||
|
fn new(
|
||||||
|
stanza_receiver: mpsc::Receiver<WriteMessage>,
|
||||||
|
control_receiver: mpsc::Receiver<WriteControl>,
|
||||||
|
stream: BoundJabberWriter<Tls>,
|
||||||
|
supervisor: oneshot::Sender<(WriteMessage, mpsc::Receiver<WriteMessage>)>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
stanza_receiver,
|
||||||
|
control_receiver,
|
||||||
|
stream,
|
||||||
|
on_crash: supervisor,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn write(&mut self, stanza: &Stanza) -> Result<(), peanuts::Error> {
|
||||||
|
Ok(self.stream.write(stanza).await?)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run(mut self) {
|
||||||
|
loop {
|
||||||
|
tokio::select! {
|
||||||
|
Some(msg) = self.control_receiver.recv() => {
|
||||||
|
match msg {
|
||||||
|
WriteControl::Disconnect => {
|
||||||
|
// TODO: close the stanza_receiver channel and drain out all of the remaining stanzas to send
|
||||||
|
self.stanza_receiver.close();
|
||||||
|
// TODO: put this in some kind of function to avoid code duplication
|
||||||
|
for msg in self.stanza_receiver.recv().await {
|
||||||
|
let result = self.stream.write(&msg.stanza).await;
|
||||||
|
match result {
|
||||||
|
Err(e) => match &e {
|
||||||
|
peanuts::Error::ReadError(error) => {
|
||||||
|
// make sure message is not lost from error, supervisor handles retry and reporting
|
||||||
|
self.on_crash.send((msg, self.stanza_receiver));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
msg.respond_to.send(Err(e.into()));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
msg.respond_to.send(Ok(()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.stream.try_close().await;
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
WriteControl::Abort(sender) => {
|
||||||
|
sender.send(self.stanza_receiver);
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Some(msg) = self.stanza_receiver.recv() => {
|
||||||
|
let result = self.stream.write(&msg.stanza).await;
|
||||||
|
match result {
|
||||||
|
Err(e) => match &e {
|
||||||
|
peanuts::Error::ReadError(error) => {
|
||||||
|
// make sure message is not lost from error, supervisor handles retry and reporting
|
||||||
|
self.on_crash.send((msg, self.stanza_receiver));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
msg.respond_to.send(Err(e.into()));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
msg.respond_to.send(Ok(()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// TODO: check if this is ok to do
|
||||||
|
else => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct WriteHandle {
|
||||||
|
sender: mpsc::Sender<WriteMessage>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for WriteHandle {
|
||||||
|
type Target = mpsc::Sender<WriteMessage>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.sender
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for WriteHandle {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.sender
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct WriteControlHandle {
|
||||||
|
sender: mpsc::Sender<WriteControl>,
|
||||||
|
handle: JoinHandle<()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WriteControlHandle {
|
||||||
|
pub fn new(
|
||||||
|
stream: BoundJabberWriter<Tls>,
|
||||||
|
supervisor: oneshot::Sender<(WriteMessage, mpsc::Receiver<WriteMessage>)>,
|
||||||
|
) -> (WriteHandle, Self) {
|
||||||
|
let (control_sender, control_receiver) = mpsc::channel(20);
|
||||||
|
let (stanza_sender, stanza_receiver) = mpsc::channel(20);
|
||||||
|
|
||||||
|
let actor = Write::new(stanza_receiver, control_receiver, stream, supervisor);
|
||||||
|
let handle = tokio::spawn(async move { actor.run().await });
|
||||||
|
|
||||||
|
(
|
||||||
|
WriteHandle {
|
||||||
|
sender: stanza_sender,
|
||||||
|
},
|
||||||
|
Self {
|
||||||
|
sender: control_sender,
|
||||||
|
handle,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reconnect(
|
||||||
|
stream: BoundJabberWriter<Tls>,
|
||||||
|
supervisor: oneshot::Sender<(WriteMessage, mpsc::Receiver<WriteMessage>)>,
|
||||||
|
stanza_receiver: mpsc::Receiver<WriteMessage>,
|
||||||
|
) -> Self {
|
||||||
|
let (control_sender, control_receiver) = mpsc::channel(20);
|
||||||
|
|
||||||
|
let actor = Write::new(stanza_receiver, control_receiver, stream, supervisor);
|
||||||
|
let handle = tokio::spawn(async move { actor.run().await });
|
||||||
|
|
||||||
|
Self {
|
||||||
|
sender: control_sender,
|
||||||
|
handle,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
pub enum Error {
|
||||||
|
AlreadyConnected,
|
||||||
|
Jabber(jabber::Error),
|
||||||
|
XML(peanuts::Error),
|
||||||
|
SQL(sqlx::Error),
|
||||||
|
JID(jid::ParseError),
|
||||||
|
AlreadyDisconnected,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<peanuts::Error> for Error {
|
||||||
|
fn from(e: peanuts::Error) -> Self {
|
||||||
|
Self::XML(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<jid::ParseError> for Error {
|
||||||
|
fn from(e: jid::ParseError) -> Self {
|
||||||
|
Self::JID(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<sqlx::Error> for Error {
|
||||||
|
fn from(e: sqlx::Error) -> Self {
|
||||||
|
Self::SQL(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<jabber::Error> for Error {
|
||||||
|
fn from(e: jabber::Error) -> Self {
|
||||||
|
Self::Jabber(e)
|
||||||
|
}
|
||||||
|
}
|
485
luz/src/lib.rs
485
luz/src/lib.rs
|
@ -1,301 +1,33 @@
|
||||||
use std::{
|
use std::sync::Arc;
|
||||||
collections::{HashMap, HashSet, VecDeque},
|
|
||||||
fmt::Pointer,
|
|
||||||
pin::pin,
|
|
||||||
sync::{atomic::AtomicBool, Arc},
|
|
||||||
task::{ready, Poll},
|
|
||||||
};
|
|
||||||
|
|
||||||
use futures::{
|
use connection::SupervisorSender;
|
||||||
stream::{SplitSink, SplitStream},
|
use jabber::JID;
|
||||||
Sink, SinkExt, Stream, StreamExt,
|
use sqlx::SqlitePool;
|
||||||
};
|
use stanza::roster;
|
||||||
use jabber::{
|
|
||||||
connection::Tls,
|
|
||||||
jabber_stream::bound_stream::{BoundJabberReader, BoundJabberStream, BoundJabberWriter},
|
|
||||||
JID,
|
|
||||||
};
|
|
||||||
use sqlx::{query, Pool, Sqlite, SqlitePool};
|
|
||||||
use stanza::{
|
|
||||||
client::{
|
|
||||||
iq::{Iq, IqType, Query},
|
|
||||||
Stanza,
|
|
||||||
},
|
|
||||||
roster,
|
|
||||||
};
|
|
||||||
use tokio::{
|
use tokio::{
|
||||||
io::AsyncRead,
|
sync::{mpsc, oneshot, Mutex},
|
||||||
select,
|
task::JoinSet,
|
||||||
sync::{
|
|
||||||
mpsc::{self, Receiver, Sender},
|
|
||||||
oneshot, Mutex,
|
|
||||||
},
|
|
||||||
task::{JoinHandle, JoinSet},
|
|
||||||
};
|
};
|
||||||
use tokio_stream::wrappers::ReceiverStream;
|
|
||||||
use tokio_util::sync::{PollSendError, PollSender};
|
|
||||||
|
|
||||||
// actor that receives jabber stanzas to write, and if there is an error, sends a message back to the supervisor then aborts, so the supervisor can spawn a new stream.
|
use crate::connection::write::WriteHandle;
|
||||||
pub struct JabberWriter {
|
use crate::connection::{SupervisorCommand, SupervisorHandle};
|
||||||
stanza_receiver: mpsc::Receiver<JabberWrite>,
|
use crate::error::Error;
|
||||||
control_receiver: mpsc::Receiver<JabberWriterControl>,
|
|
||||||
stream: BoundJabberWriter<Tls>,
|
|
||||||
on_crash: oneshot::Sender<(JabberWrite, mpsc::Receiver<JabberWrite>)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct JabberWrite {
|
mod connection;
|
||||||
stanza: Stanza,
|
mod error;
|
||||||
respond_to: oneshot::Sender<Result<(), Error>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
enum JabberWriterControl {
|
|
||||||
Disconnect,
|
|
||||||
Abort(oneshot::Sender<mpsc::Receiver<JabberWrite>>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl JabberWriter {
|
|
||||||
fn new(
|
|
||||||
stanza_receiver: mpsc::Receiver<JabberWrite>,
|
|
||||||
control_receiver: mpsc::Receiver<JabberWriterControl>,
|
|
||||||
stream: BoundJabberWriter<Tls>,
|
|
||||||
supervisor: oneshot::Sender<(JabberWrite, mpsc::Receiver<JabberWrite>)>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
stanza_receiver,
|
|
||||||
control_receiver,
|
|
||||||
stream,
|
|
||||||
on_crash: supervisor,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn write(&mut self, stanza: &Stanza) -> Result<(), peanuts::Error> {
|
|
||||||
Ok(self.stream.write(stanza).await?)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn run(mut self) {
|
|
||||||
loop {
|
|
||||||
tokio::select! {
|
|
||||||
Some(msg) = self.control_receiver.recv() => {
|
|
||||||
match msg {
|
|
||||||
JabberWriterControl::Disconnect => {
|
|
||||||
// TODO: close the stanza_receiver channel and drain out all of the remaining stanzas to send
|
|
||||||
self.stanza_receiver.close();
|
|
||||||
// TODO: put this in some kind of function to avoid code duplication
|
|
||||||
for msg in self.stanza_receiver.recv().await {
|
|
||||||
let result = self.stream.write(&msg.stanza).await;
|
|
||||||
match result {
|
|
||||||
Err(e) => match &e {
|
|
||||||
peanuts::Error::ReadError(error) => {
|
|
||||||
// make sure message is not lost from error, supervisor handles retry and reporting
|
|
||||||
self.on_crash.send((msg, self.stanza_receiver));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
msg.respond_to.send(Err(e.into()));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
msg.respond_to.send(Ok(()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.stream.try_close().await;
|
|
||||||
break;
|
|
||||||
},
|
|
||||||
JabberWriterControl::Abort(sender) => {
|
|
||||||
sender.send(self.stanza_receiver);
|
|
||||||
break;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Some(msg) = self.stanza_receiver.recv() => {
|
|
||||||
let result = self.stream.write(&msg.stanza).await;
|
|
||||||
match result {
|
|
||||||
Err(e) => match &e {
|
|
||||||
peanuts::Error::ReadError(error) => {
|
|
||||||
// make sure message is not lost from error, supervisor handles retry and reporting
|
|
||||||
self.on_crash.send((msg, self.stanza_receiver));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
msg.respond_to.send(Err(e.into()));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
msg.respond_to.send(Ok(()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// TODO: check if this is ok to do
|
|
||||||
else => break,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct JabberWriteHandle {
|
|
||||||
sender: mpsc::Sender<JabberWrite>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct JabberWriterControlHandle {
|
|
||||||
sender: mpsc::Sender<JabberWriterControl>,
|
|
||||||
handle: JoinHandle<()>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl JabberWriterControlHandle {
|
|
||||||
pub fn new(
|
|
||||||
stream: BoundJabberWriter<Tls>,
|
|
||||||
supervisor: oneshot::Sender<(JabberWrite, mpsc::Receiver<JabberWrite>)>,
|
|
||||||
) -> (JabberWriteHandle, JabberWriterControlHandle) {
|
|
||||||
let (control_sender, control_receiver) = mpsc::channel(20);
|
|
||||||
let (stanza_sender, stanza_receiver) = mpsc::channel(20);
|
|
||||||
|
|
||||||
let actor = JabberWriter::new(stanza_receiver, control_receiver, stream, supervisor);
|
|
||||||
let handle = tokio::spawn(async move { actor.run().await });
|
|
||||||
|
|
||||||
(
|
|
||||||
JabberWriteHandle {
|
|
||||||
sender: stanza_sender,
|
|
||||||
},
|
|
||||||
Self {
|
|
||||||
sender: control_sender,
|
|
||||||
handle,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reconnect(
|
|
||||||
stream: BoundJabberWriter<Tls>,
|
|
||||||
supervisor: oneshot::Sender<(JabberWrite, mpsc::Receiver<JabberWrite>)>,
|
|
||||||
stanza_receiver: mpsc::Receiver<JabberWrite>,
|
|
||||||
) -> Self {
|
|
||||||
let (control_sender, control_receiver) = mpsc::channel(20);
|
|
||||||
|
|
||||||
let actor = JabberWriter::new(stanza_receiver, control_receiver, stream, supervisor);
|
|
||||||
let handle = tokio::spawn(async move { actor.run().await });
|
|
||||||
|
|
||||||
Self {
|
|
||||||
sender: control_sender,
|
|
||||||
handle,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct JabberReader {
|
|
||||||
// TODO: place iq hashmap here
|
|
||||||
control_receiver: mpsc::Receiver<JabberReaderControl>,
|
|
||||||
stream: BoundJabberReader<Tls>,
|
|
||||||
on_crash: oneshot::Sender<(SqlitePool, mpsc::Sender<UpdateMessage>, JoinSet<()>)>,
|
|
||||||
db: SqlitePool,
|
|
||||||
sender: mpsc::Sender<UpdateMessage>,
|
|
||||||
supervisor_control: mpsc::Sender<JabberSupervisorCommand>,
|
|
||||||
write_sender: mpsc::Sender<JabberWrite>,
|
|
||||||
tasks: JoinSet<()>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl JabberReader {
|
|
||||||
fn new(
|
|
||||||
control_receiver: mpsc::Receiver<JabberReaderControl>,
|
|
||||||
stream: BoundJabberReader<Tls>,
|
|
||||||
on_crash: oneshot::Sender<(SqlitePool, mpsc::Sender<UpdateMessage>, JoinSet<()>)>,
|
|
||||||
db: SqlitePool,
|
|
||||||
sender: mpsc::Sender<UpdateMessage>,
|
|
||||||
// jabber server must be able to both terminate the connection from error, and ask for data from the client (such as supported XEPs)
|
|
||||||
supervisor_control: mpsc::Sender<JabberSupervisorCommand>,
|
|
||||||
write_sender: mpsc::Sender<JabberWrite>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
control_receiver,
|
|
||||||
stream,
|
|
||||||
on_crash,
|
|
||||||
db,
|
|
||||||
sender,
|
|
||||||
supervisor_control,
|
|
||||||
write_sender,
|
|
||||||
tasks: JoinSet::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn run(mut self) {
|
|
||||||
loop {
|
|
||||||
tokio::select! {
|
|
||||||
Some(msg) = self.control_receiver.recv() => {
|
|
||||||
match msg {
|
|
||||||
JabberReaderControl::Disconnect => todo!(),
|
|
||||||
JabberReaderControl::Abort(sender) => todo!(),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
stanza = self.stream.read::<Stanza>() => {
|
|
||||||
match stanza {
|
|
||||||
Ok(_) => todo!(),
|
|
||||||
Err(_) => todo!(),
|
|
||||||
}
|
|
||||||
self.tasks.spawn();
|
|
||||||
},
|
|
||||||
else => break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trait Task {
|
|
||||||
async fn handle();
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Task for Stanza {
|
|
||||||
async fn handle() {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum JabberReaderControl {
|
|
||||||
Disconnect,
|
|
||||||
Abort(oneshot::Sender<mpsc::Receiver<JabberWrite>>),
|
|
||||||
}
|
|
||||||
|
|
||||||
struct JabberReaderControlHandle {
|
|
||||||
sender: mpsc::Sender<JabberReaderControl>,
|
|
||||||
handle: JoinHandle<()>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl JabberReaderControlHandle {
|
|
||||||
pub fn new(
|
|
||||||
stream: BoundJabberReader<Tls>,
|
|
||||||
on_crash: oneshot::Sender<(SqlitePool, mpsc::Sender<UpdateMessage>, JoinSet<()>)>,
|
|
||||||
db: SqlitePool,
|
|
||||||
sender: mpsc::Sender<UpdateMessage>,
|
|
||||||
supervisor_control: mpsc::Sender<JabberSupervisorCommand>,
|
|
||||||
jabber_write: mpsc::Sender<JabberWrite>,
|
|
||||||
) -> Self {
|
|
||||||
let (control_sender, control_receiver) = mpsc::channel(20);
|
|
||||||
|
|
||||||
let actor = JabberReader::new(
|
|
||||||
control_receiver,
|
|
||||||
stream,
|
|
||||||
on_crash,
|
|
||||||
db,
|
|
||||||
sender,
|
|
||||||
supervisor_control,
|
|
||||||
jabber_write,
|
|
||||||
);
|
|
||||||
let handle = tokio::spawn(async move { actor.run().await });
|
|
||||||
|
|
||||||
Self {
|
|
||||||
sender: control_sender,
|
|
||||||
handle,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Luz {
|
pub struct Luz {
|
||||||
receiver: mpsc::Receiver<CommandMessage>,
|
receiver: mpsc::Receiver<CommandMessage>,
|
||||||
jid: Arc<Mutex<JID>>,
|
jid: Arc<Mutex<JID>>,
|
||||||
// TODO: use a dyn passwordprovider trait to avoid storing password in memory
|
// TODO: use a dyn passwordprovider trait to avoid storing password in memory
|
||||||
password: String,
|
password: String,
|
||||||
connected: Arc<Mutex<Option<(JabberWriteHandle, JabberSupervisorHandle)>>>,
|
connected: Arc<Mutex<Option<(WriteHandle, SupervisorHandle)>>>,
|
||||||
db: SqlitePool,
|
db: SqlitePool,
|
||||||
sender: mpsc::Sender<UpdateMessage>,
|
sender: mpsc::Sender<UpdateMessage>,
|
||||||
|
/// if connection was shut down due to e.g. server shutdown, supervisor must be able to mark client as disconnected
|
||||||
|
connection_supervisor_shutdown: oneshot::Receiver<()>,
|
||||||
|
// TODO: will need to have an auto reconnect state as well (e.g. in case server shut down, to try and reconnect later)
|
||||||
|
// TODO: will grow forever at this point, maybe not required as tasks will naturally shut down anyway?
|
||||||
tasks: JoinSet<()>,
|
tasks: JoinSet<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,7 +36,8 @@ impl Luz {
|
||||||
receiver: mpsc::Receiver<CommandMessage>,
|
receiver: mpsc::Receiver<CommandMessage>,
|
||||||
jid: Arc<Mutex<JID>>,
|
jid: Arc<Mutex<JID>>,
|
||||||
password: String,
|
password: String,
|
||||||
connected: Arc<Mutex<Option<(JabberWriteHandle, JabberSupervisorHandle)>>>,
|
connected: Arc<Mutex<Option<(WriteHandle, SupervisorHandle)>>>,
|
||||||
|
connection_supervisor_shutdown: oneshot::Receiver<()>,
|
||||||
db: SqlitePool,
|
db: SqlitePool,
|
||||||
sender: mpsc::Sender<UpdateMessage>,
|
sender: mpsc::Sender<UpdateMessage>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
@ -316,12 +49,19 @@ impl Luz {
|
||||||
receiver,
|
receiver,
|
||||||
sender,
|
sender,
|
||||||
tasks: JoinSet::new(),
|
tasks: JoinSet::new(),
|
||||||
|
connection_supervisor_shutdown,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(mut self) {
|
async fn run(mut self) {
|
||||||
while let Some(msg) = self.receiver.recv().await {
|
loop {
|
||||||
|
tokio::select! {
|
||||||
|
_ = &mut self.connection_supervisor_shutdown => {
|
||||||
|
*self.connected.lock().await = None
|
||||||
|
}
|
||||||
|
Some(msg) = self.receiver.recv() => {
|
||||||
// TODO: consider separating disconnect/connect and commands apart from commandmessage
|
// TODO: consider separating disconnect/connect and commands apart from commandmessage
|
||||||
|
// TODO: dispatch commands separate tasks
|
||||||
match msg {
|
match msg {
|
||||||
CommandMessage::Connect => {
|
CommandMessage::Connect => {
|
||||||
match self.connected.lock().await.as_ref() {
|
match self.connected.lock().await.as_ref() {
|
||||||
|
@ -333,13 +73,20 @@ impl Luz {
|
||||||
None => {
|
None => {
|
||||||
let mut jid = self.jid.lock().await;
|
let mut jid = self.jid.lock().await;
|
||||||
let mut domain = jid.domainpart.clone();
|
let mut domain = jid.domainpart.clone();
|
||||||
|
// TODO: check what happens upon reconnection with same resource (this is probably what one wants to do and why jid should be mutated from a bare jid to one with a resource)
|
||||||
let streams_result =
|
let streams_result =
|
||||||
jabber::connect_and_login(&mut jid, &self.password, &mut domain)
|
jabber::connect_and_login(&mut jid, &self.password, &mut domain)
|
||||||
.await;
|
.await;
|
||||||
match streams_result {
|
match streams_result {
|
||||||
Ok(s) => {
|
Ok(s) => {
|
||||||
let (writer, supervisor) =
|
let (shutdown_send, shutdown_recv) = oneshot::channel::<()>();
|
||||||
JabberSupervisorHandle::new(s, self.sender.clone());
|
let (writer, supervisor) = SupervisorHandle::new(
|
||||||
|
s,
|
||||||
|
self.sender.clone(),
|
||||||
|
self.db.clone(),
|
||||||
|
shutdown_send,
|
||||||
|
);
|
||||||
|
self.connection_supervisor_shutdown = shutdown_recv;
|
||||||
*self.connected.lock().await = Some((writer, supervisor));
|
*self.connected.lock().await = Some((writer, supervisor));
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -352,15 +99,12 @@ impl Luz {
|
||||||
CommandMessage::Disconnect => match self.connected.lock().await.as_mut() {
|
CommandMessage::Disconnect => match self.connected.lock().await.as_mut() {
|
||||||
None => {
|
None => {
|
||||||
self.sender
|
self.sender
|
||||||
.send(UpdateMessage::Error(Error::AlreadyDisonnected))
|
.send(UpdateMessage::Error(Error::AlreadyDisconnected))
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
mut c => {
|
mut c => {
|
||||||
if let Some((_write_handle, supervisor_handle)) = c.take() {
|
if let Some((_write_handle, supervisor_handle)) = c.take() {
|
||||||
let _ = supervisor_handle
|
let _ = supervisor_handle.send(SupervisorCommand::Disconnect).await;
|
||||||
.sender
|
|
||||||
.send(JabberSupervisorCommand::Disconnect)
|
|
||||||
.await;
|
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
|
@ -368,11 +112,13 @@ impl Luz {
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
match self.connected.lock().await.as_ref() {
|
match self.connected.lock().await.as_ref() {
|
||||||
Some((w, _)) => self.tasks.spawn(msg.handle_online(
|
Some((w, s)) => self.tasks.spawn(msg.handle_online(
|
||||||
w.clone(),
|
w.clone(),
|
||||||
|
s.sender(),
|
||||||
self.jid.clone(),
|
self.jid.clone(),
|
||||||
self.db.clone(),
|
self.db.clone(),
|
||||||
self.sender.clone(),
|
self.sender.clone(),
|
||||||
|
// TODO: iq hashmap
|
||||||
)),
|
)),
|
||||||
None => self.tasks.spawn(msg.handle_offline(
|
None => self.tasks.spawn(msg.handle_offline(
|
||||||
self.jid.clone(),
|
self.jid.clone(),
|
||||||
|
@ -382,6 +128,9 @@ impl Luz {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
else => break,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -398,7 +147,8 @@ impl CommandMessage {
|
||||||
|
|
||||||
pub async fn handle_online(
|
pub async fn handle_online(
|
||||||
mut self,
|
mut self,
|
||||||
jabber_write_handle: JabberWriteHandle,
|
write_handle: WriteHandle,
|
||||||
|
supervisor_control: SupervisorSender,
|
||||||
// TODO: jid could lose resource by the end
|
// TODO: jid could lose resource by the end
|
||||||
jid: Arc<Mutex<JID>>,
|
jid: Arc<Mutex<JID>>,
|
||||||
db: SqlitePool,
|
db: SqlitePool,
|
||||||
|
@ -418,12 +168,15 @@ impl LuzHandle {
|
||||||
pub fn new(jid: JID, password: String, db: SqlitePool) -> Self {
|
pub fn new(jid: JID, password: String, db: SqlitePool) -> Self {
|
||||||
let (command_sender, command_receiver) = mpsc::channel(20);
|
let (command_sender, command_receiver) = mpsc::channel(20);
|
||||||
let (update_sender, update_receiver) = mpsc::channel(20);
|
let (update_sender, update_receiver) = mpsc::channel(20);
|
||||||
|
// might be bad, first supervisor shutdown notification oneshot is never used (disgusting)
|
||||||
|
let (sup_send, sup_recv) = oneshot::channel();
|
||||||
|
|
||||||
let actor = Luz::new(
|
let actor = Luz::new(
|
||||||
command_receiver,
|
command_receiver,
|
||||||
Arc::new(Mutex::new(jid)),
|
Arc::new(Mutex::new(jid)),
|
||||||
password,
|
password,
|
||||||
Arc::new(Mutex::new(None)),
|
Arc::new(Mutex::new(None)),
|
||||||
|
sup_recv,
|
||||||
db,
|
db,
|
||||||
update_sender,
|
update_sender,
|
||||||
);
|
);
|
||||||
|
@ -436,146 +189,6 @@ impl LuzHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct JabberSupervisor {
|
|
||||||
connection_commands: mpsc::Receiver<JabberSupervisorCommand>,
|
|
||||||
writer_crash: oneshot::Receiver<(JabberWrite, mpsc::Receiver<JabberWrite>)>,
|
|
||||||
reader_crash: oneshot::Receiver<(SqlitePool, mpsc::Sender<UpdateMessage>, JoinSet<()>)>,
|
|
||||||
sender: mpsc::Sender<UpdateMessage>,
|
|
||||||
writer_handle: JabberWriterControlHandle,
|
|
||||||
reader_handle: JabberReaderControlHandle,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum JabberSupervisorCommand {
|
|
||||||
Disconnect,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl JabberSupervisor {
|
|
||||||
fn new(
|
|
||||||
connection_commands: mpsc::Receiver<JabberSupervisorCommand>,
|
|
||||||
writer_crash: oneshot::Receiver<(JabberWrite, mpsc::Receiver<JabberWrite>)>,
|
|
||||||
reader_crash: oneshot::Receiver<(SqlitePool, mpsc::Sender<UpdateMessage>, JoinSet<()>)>,
|
|
||||||
sender: mpsc::Sender<UpdateMessage>,
|
|
||||||
writer_handle: JabberWriterControlHandle,
|
|
||||||
reader_handle: JabberReaderControlHandle,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
connection_commands,
|
|
||||||
writer_crash,
|
|
||||||
sender,
|
|
||||||
writer_handle,
|
|
||||||
reader_handle,
|
|
||||||
reader_crash,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn handle_command_message(&mut self, msg: JabberSupervisorCommand) {}
|
|
||||||
|
|
||||||
async fn run(mut self) {
|
|
||||||
loop {
|
|
||||||
tokio::select! {
|
|
||||||
Some(msg) = self.connection_commands.recv() => {
|
|
||||||
self.handle_command_message(msg).await;
|
|
||||||
},
|
|
||||||
error = self.writer_crash => {
|
|
||||||
|
|
||||||
},
|
|
||||||
error = self.reader_crash => {
|
|
||||||
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct JabberSupervisorHandle {
|
|
||||||
sender: mpsc::Sender<JabberSupervisorCommand>,
|
|
||||||
handle: JoinHandle<()>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl JabberSupervisorHandle {
|
|
||||||
pub fn new(
|
|
||||||
streams: BoundJabberStream<Tls>,
|
|
||||||
sender: mpsc::Sender<UpdateMessage>,
|
|
||||||
db: SqlitePool,
|
|
||||||
update_sender: mpsc::Sender<UpdateMessage>,
|
|
||||||
) -> (JabberWriteHandle, Self) {
|
|
||||||
let (command_sender, command_receiver) = mpsc::channel(20);
|
|
||||||
let (writer_error_sender, writer_error_receiver) = oneshot::channel();
|
|
||||||
let (reader_crash_sender, reader_crash_receiver) = oneshot::channel();
|
|
||||||
|
|
||||||
let (reader, writer) = streams.split();
|
|
||||||
let (jabber_write_handle, jabber_writer_control_handle) =
|
|
||||||
JabberWriterControlHandle::new(writer, writer_error_sender);
|
|
||||||
let jabber_reader_control_handle = JabberReaderControlHandle::new(
|
|
||||||
reader,
|
|
||||||
reader_crash_sender,
|
|
||||||
db,
|
|
||||||
update_sender,
|
|
||||||
command_sender.clone(),
|
|
||||||
jabber_write_handle.sender.clone(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let actor = JabberSupervisor::new(
|
|
||||||
command_receiver,
|
|
||||||
writer_error_receiver,
|
|
||||||
reader_crash_receiver,
|
|
||||||
sender,
|
|
||||||
jabber_writer_control_handle,
|
|
||||||
jabber_reader_control_handle,
|
|
||||||
);
|
|
||||||
|
|
||||||
let handle = tokio::spawn(async move { actor.run().await });
|
|
||||||
|
|
||||||
(
|
|
||||||
jabber_write_handle,
|
|
||||||
Self {
|
|
||||||
sender: command_sender,
|
|
||||||
handle,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Error {
|
|
||||||
AlreadyConnected,
|
|
||||||
PollSend(PollSendError<CommandMessage>),
|
|
||||||
Jabber(jabber::Error),
|
|
||||||
XML(peanuts::Error),
|
|
||||||
SQL(sqlx::Error),
|
|
||||||
JID(jid::ParseError),
|
|
||||||
AlreadyDisonnected,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<peanuts::Error> for Error {
|
|
||||||
fn from(e: peanuts::Error) -> Self {
|
|
||||||
Self::XML(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<jid::ParseError> for Error {
|
|
||||||
fn from(e: jid::ParseError) -> Self {
|
|
||||||
Self::JID(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<sqlx::Error> for Error {
|
|
||||||
fn from(e: sqlx::Error) -> Self {
|
|
||||||
Self::SQL(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<jabber::Error> for Error {
|
|
||||||
fn from(e: jabber::Error) -> Self {
|
|
||||||
Self::Jabber(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<PollSendError<CommandMessage>> for Error {
|
|
||||||
fn from(e: PollSendError<CommandMessage>) -> Self {
|
|
||||||
Self::PollSend(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum CommandMessage {
|
pub enum CommandMessage {
|
||||||
Connect,
|
Connect,
|
||||||
Disconnect,
|
Disconnect,
|
||||||
|
|
Loading…
Reference in New Issue