Muck about with room

This commit is contained in:
Joscha 2022-03-01 22:24:17 +01:00
parent e5eefd8ada
commit d642e4851c

View file

@ -1,17 +1,30 @@
/*
Idea:
Identification etc. runs per-connection
Put connection into another Arc<Mutex<_>>
Give reference to connection to identify thread?
On the other hand...
UI may also do weird things when setting nick during identification
Maybe use same mechanism here?
Also...
Maybe have a look at what an euph room would require?
Maybe start working on euph room in parallel?
*/
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use anyhow::bail;
use cove_core::conn::{self, ConnMaintenance, ConnRx, ConnTx}; use cove_core::conn::{self, ConnMaintenance, ConnRx, ConnTx};
use cove_core::packets::{ use cove_core::packets::{
Cmd, IdentifyCmd, IdentifyRpl, NickRpl, Ntf, Packet, RoomCmd, RoomRpl, Rpl, SendRpl, WhoRpl, Cmd, IdentifyCmd, IdentifyRpl, NickRpl, Ntf, Packet, RoomCmd, RoomRpl, Rpl, SendRpl, WhoRpl,
}; };
use cove_core::{Session, SessionId}; use cove_core::{Session, SessionId};
use futures::io::Repeat;
use tokio::sync::oneshot::{self, Sender}; use tokio::sync::oneshot::{self, Sender};
use tokio::sync::Mutex; use tokio::sync::Mutex;
use tokio_tungstenite::connect_async;
use tui::widgets::StatefulWidget;
use crate::config::Config; use crate::config::Config;
use crate::never::Never; use crate::never::Never;
@ -31,6 +44,31 @@ pub enum Error {
Replies(#[from] replies::Error), Replies(#[from] replies::Error),
} }
pub enum Status {
ChoosingRoom,
Identifying,
/// User must enter a nick. May contain error message about previous nick.
NickRequired(Option<String>),
}
pub struct Connected {
status: Status,
tx: ConnTx,
next_id: u64,
replies: Replies<u64, Rpl>,
}
impl Connected {
fn new(tx: ConnTx, timeout: Duration) -> Self {
Self {
status: Status::ChoosingRoom,
tx,
next_id: 0,
replies: Replies::new(timeout),
}
}
}
pub enum StopReason { pub enum StopReason {
CouldNotConnect(conn::Error), CouldNotConnect(conn::Error),
InvalidRoom(String), InvalidRoom(String),
@ -39,34 +77,36 @@ pub enum StopReason {
SomethingWentWrong, SomethingWentWrong,
} }
/// General state of the room connection. pub enum Connection {
pub enum Status {
/// Connecting to the room for the first time.
Connecting, Connecting,
/// Reconnecting to the room after being connected at least once.
Reconnecting, Reconnecting,
/// Identifying with the server after a connection has been established. Connected(Connected),
/// This occurs when an initial nick has been set on room creation.
Identifying,
/// User must enter a nick. May contain error message about previous nick.
NickRequired(Option<String>),
/// Fully connected.
Nominal,
/// Not connected and not attempting any reconnects. This is likely due to
/// factors out of the application's control (e. g. no internet connection,
/// room does not exist), meaning that retrying without user intervention
/// doesn't make sense.
Stopped(StopReason), Stopped(StopReason),
} }
/// State for when a websocket connection exists. impl Connection {
struct Connected { fn connected(&self) -> Option<&Connected> {
tx: ConnTx, match self {
next_id: u64, Connection::Connected(connected) => Some(connected),
replies: Replies<u64, Rpl>, Connection::Connecting | Connection::Reconnecting | Connection::Stopped(_) => None,
}
}
fn connected_mut(&mut self) -> Option<&mut Connected> {
match self {
Connection::Connected(connected) => Some(connected),
Connection::Connecting | Connection::Reconnecting | Connection::Stopped(_) => None,
}
}
fn stopped(&self) -> bool {
match self {
Connection::Stopped(_) => true,
Connection::Connecting | Connection::Reconnecting | Connection::Connected(_) => false,
}
}
} }
/// State for when a client has fully joined a room.
pub struct Present { pub struct Present {
session: Session, session: Session,
others: HashMap<SessionId, Session>, others: HashMap<SessionId, Session>,
@ -75,12 +115,15 @@ pub struct Present {
pub struct RoomState { pub struct RoomState {
identity: String, identity: String,
initial_nick: Option<String>, initial_nick: Option<String>,
status: Status, connection: Connection,
connected: Option<Connected>,
present: Option<Present>, present: Option<Present>,
} }
impl RoomState { impl RoomState {
fn modified(&self) {
// TODO Send render event to main thread
}
fn on_rpl( fn on_rpl(
&mut self, &mut self,
id: u64, id: u64,
@ -241,8 +284,7 @@ impl Room {
state: Arc::new(Mutex::new(RoomState { state: Arc::new(Mutex::new(RoomState {
identity, identity,
initial_nick, initial_nick,
status: Status::Connecting, connection: Connection::Connecting,
connected: None,
present: None, present: None,
})), })),
dead_mans_switch: tx, dead_mans_switch: tx,
@ -268,12 +310,18 @@ impl Room {
// Try to connect and run // Try to connect and run
match Self::connect(&config.cove_url, config.timeout).await { match Self::connect(&config.cove_url, config.timeout).await {
Ok((tx, rx, mt)) => { Ok((tx, rx, mt)) => {
state.lock().await.connected = Some(Connected { // Update state
tx, {
next_id: 0, let mut state = state.lock().await;
replies: Replies::new(config.timeout), if state.connection.stopped() {
}); return;
}
state.connection =
Connection::Connected(Connected::new(tx, config.timeout));
}
// Stay connected
// TODO Start select_room_and_identify task
tokio::select! { tokio::select! {
_ = mt.perform() => {} _ = mt.perform() => {}
_ = Self::receive(&state, rx, &mut room_verified) => {} _ = Self::receive(&state, rx, &mut room_verified) => {}