Basics working.

This commit is contained in:
Arthur Beck 2025-03-04 15:31:24 +00:00
parent 686d1d74fe
commit 65086a3b3c

View file

@ -1,13 +1,13 @@
#![feature(random)]
#![feature(inline_const_pat)]
use std::io::prelude::*;
use std::io::{ErrorKind, prelude::*};
use std::net::{TcpListener, TcpStream};
use std::random;
use std::sync::{Arc, Mutex};
use std::thread::{self, sleep};
use std::thread::{self, JoinHandle, sleep};
#[derive(Clone)]
#[derive(Clone, PartialEq, Eq)]
enum UserStatus {
ONLINE,
DISCONNECTED,
@ -18,10 +18,10 @@ enum UserStatus {
impl UserStatus {
fn get_status_string(&self) -> String {
match self {
UserStatus::ONLINE => "\x1b[0m\x1b[32mOnline\x1b[0m".to_string(),
UserStatus::IDLE => "\x1b[0m\x1b[33mIdle\x1b[0m".to_string(),
UserStatus::DISCONNECTED => "\x1b[0m\x1b[31mDisconnected\x1b[0m".to_string(),
UserStatus::CUSTOM(val) => format!("\x1b[0m\x1b[34m{}\x1b[0m", val)
UserStatus::ONLINE => "\x1b[0m\x1b[32monline\x1b[0m".to_string(),
UserStatus::IDLE => "\x1b[0m\x1b[33midle\x1b[0m".to_string(),
UserStatus::DISCONNECTED => "\x1b[0m\x1b[31mdisconnected\x1b[0m".to_string(),
UserStatus::CUSTOM(val) => format!("\x1b[0m\x1b[34m{}\x1b[0m", val),
}
}
}
@ -55,7 +55,7 @@ fn handle_client(mut stream: TcpStream, channel: Channel) {
let mut buf = [0u8; 30];
let mut i = 0usize;
let mut buf1 = [0u8];
while buf1[0] != b'\n' || i == 0 {
'bufreadloop: while buf1[0] != b'\n' || i == 0 {
stream.read_exact(&mut buf1).unwrap();
if buf1[0] == b'\n' && i == 0 {
stream.write_all(
@ -73,6 +73,19 @@ fn handle_client(mut stream: TcpStream, channel: Channel) {
i = 0;
continue;
} else if buf1[0] == b'\n' {
for user in &channel.lock().unwrap().online_users {
if user.name == String::from_utf8_lossy(&(buf[..i])).to_string()
&& user.status != UserStatus::DISCONNECTED
{
stream.write_all(
b"\x1b[0m\x1b[31;1mSorry, but that nickname is taken.\n\x1b[0m\x1b[33mEnter your chosen nickname(up to 30 characters):\x1b[0m\x1b[4m\n"
).unwrap();
buf = [0u8; 30];
buf1[0] = b'\0';
i = 0;
continue 'bufreadloop;
}
}
break;
}
if i < 30 {
@ -89,22 +102,34 @@ fn handle_client(mut stream: TcpStream, channel: Channel) {
))
.unwrap();
let user = User {
let mut user = User {
name: String::from_utf8_lossy(&(buf[..i])).to_string(),
status: UserStatus::ONLINE,
};
let netbot = User {
name: "Netbot".to_owned(),
status: UserStatus::ONLINE,
};
channel.lock().unwrap().online_users.push(user.clone());
let (recieve_terminate_send, recieve_terminate_recv) = std::sync::mpsc::channel::<()>();
let recieve_thread: JoinHandle<_>;
{
let channel = channel.clone();
let mut stream = stream.try_clone().unwrap();
let time_format = time::format_description::well_known::Rfc2822;
thread::spawn(move || {
recieve_thread = thread::spawn(move || {
let mut current_message_count = channel.lock().unwrap().messages.len();
loop {
if let Ok(_) = recieve_terminate_recv.try_recv() {
stream.shutdown(std::net::Shutdown::Both).unwrap();
panic!("recieve thread exiting");
}
let new_message_count = channel.lock().unwrap().messages.len();
if current_message_count != new_message_count {
let new_messages = &channel.lock().unwrap().messages[current_message_count..];
@ -133,7 +158,27 @@ fn handle_client(mut stream: TcpStream, channel: Channel) {
let mut buf1 = [0u8];
loop {
stream.read_exact(&mut buf1).unwrap();
if let Err(err) = stream.read_exact(&mut buf1) {
if err.kind() == ErrorKind::UnexpectedEof {
user.status = UserStatus::DISCONNECTED;
for usr in &mut channel.lock().unwrap().online_users {
if usr.name == user.name {
usr.status = user.status.clone();
}
}
channel.lock().unwrap().messages.push(Message {
sender: netbot.clone(),
contents: format!("User {} has left.", user.name),
timestamp: time::OffsetDateTime::now_local().unwrap(),
});
recieve_terminate_send.send(()).unwrap();
let _ = recieve_thread.join();
stream.shutdown(std::net::Shutdown::Both).unwrap();
return;
}
}
if buf1[0] == b'\x08' {
buf.pop();
@ -148,25 +193,107 @@ fn handle_client(mut stream: TcpStream, channel: Channel) {
timestamp: time::OffsetDateTime::now_local().unwrap(),
});
} else {
if contents.starts_with("/help") || contents.starts_with("/?") {
if contents.split(" ").collect::<Vec<&str>>()[0] == "/help" || contents.split(" ").collect::<Vec<&str>>()[0] == "/?" {
stream
.write_all(
b"\x1b[0m\x1b[32mValid commands:\n \
/help, /?: Print this help.\n \
/status online|idle|disconnected|(any value): Set your status.\n \
/user nick: Get information about a user.\x1b[0m",
/status [online|idle|disconnected|(any value)]: Set your status.\n \
/user [nick]: Get information about a user.\n \
/server [new name]: Get or set the server name.\n \
/users: List users.\x1b[0m\n",
)
.unwrap();
} else if contents.starts_with("/status") {
} else if contents.split(" ").collect::<Vec<&str>>()[0] == "/status" || contents == "/user" {
let contents = contents.split(" ").collect::<Vec<&str>>();
if contents.len() == 1 {
stream
.write_fmt(
format_args!("\x1b[0m\x1b[32mYou are currently marked as {}\n\x1b[0m"),
)
.write_fmt(format_args!(
"\x1b[0m\x1b[32mYou are currently marked as {}\n\x1b[0m",
user.clone().status.get_status_string()
))
.unwrap();
} else {
match contents[1] {
"online" => {
user.status = UserStatus::ONLINE;
}
"idle" => {
user.status = UserStatus::IDLE;
}
"disconnected" => {
user.status = UserStatus::DISCONNECTED;
}
other => {
user.status = UserStatus::CUSTOM(other.to_owned());
}
}
for usr in &mut channel.lock().unwrap().online_users {
if usr.name == user.name {
usr.status = user.status.clone();
}
}
stream
.write_fmt(format_args!(
"\x1b[0m\x1b[32mYou are now marked as {}\n\x1b[0m",
user.status.get_status_string()
))
.unwrap();
}
} else if contents.split(" ").collect::<Vec<&str>>()[0] == "/server" {
let contents = contents.split(" ").collect::<Vec<&str>>();
if contents.len() == 1 {
stream
.write_fmt(format_args!(
"\x1b[0m\x1b[32mCurrent server name: {}.\n\x1b[0m",
channel.lock().unwrap().name
))
.unwrap();
} else {
channel.lock().unwrap().name = contents[1].to_owned();
stream
.write_fmt(format_args!(
"\x1b[0m\x1b[32mNew server name: {}.\n\x1b[0m",
channel.lock().unwrap().name
))
.unwrap();
}
} else if contents.split(" ").collect::<Vec<&str>>()[0] == "/user" {
let contents = contents.split(" ").collect::<Vec<&str>>();
let mut found_user = false;
for usr in &mut channel.lock().unwrap().online_users {
if usr.name == contents[1] {
stream
.write_fmt(format_args!(
"\x1b[0m\x1b[32mUser {} is currently {}.\n\x1b[0m",
usr.name,
usr.status.get_status_string()
))
.unwrap();
found_user = true;
break;
}
}
if !found_user {
stream
.write_fmt(format_args!(
"\x1b[0m\x1b[32mUnknown user \"{}\".\n\x1b[0m",
contents[1]
))
.unwrap();
}
} else if contents.starts_with("/users") {
stream.write_all(b"\x1b[0m\x1b[32mUsers:\x1b[0m").unwrap();
for usr in &channel.lock().unwrap().online_users {
stream
.write_fmt(format_args!(
"\n{} (currently {})",
usr.name,
usr.status.get_status_string()
))
.unwrap();
}
stream.write_all(b"\n\x1b[0m").unwrap();
} else {
stream
.write_all(b"\x1b[0m\x1b[31;1mThat's an invalid command!\n\x1b[0m")