Muck about with room
This commit is contained in:
parent
e5eefd8ada
commit
d642e4851c
1 changed files with 81 additions and 33 deletions
|
|
@ -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) => {}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue