Skip to content

Commit

Permalink
chore: Move some from functionality to lib.rs
Browse files Browse the repository at this point in the history
  • Loading branch information
robinsonweng authored and Robinson Weng committed Oct 12, 2023
1 parent 47d4da7 commit d2005b3
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 87 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/target
/irc_config
/.vscode
159 changes: 159 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
use std::net::{SocketAddr};

pub enum Command {
SetNickName,
User,
Ping,
List,
Join,
Topic,
Names,
Part,
Users,
PrivateMessage,
Quit,
// custom
CommandNotFound
}

pub struct User {
nickname: String,
belong_topics: Vec<String>,
ip: SocketAddr,
}

impl User {
pub fn new(ip: SocketAddr) -> User {
User {
nickname: String::new(),
belong_topics: Vec::new(),
ip,
}
}
}

pub struct Server <'a>{
online_users: Vec<&'a mut User>,
topics: Vec<String>,
}

impl <'a> Server <'a> {
pub fn new() -> Server <'a>{
Server {
online_users: Vec::new(),
topics: Vec::new(),
}
}

pub fn user_online(&mut self, user: &'a mut User) {
// self.online_users.contains(user)
self.online_users.push(user);
}

pub fn is_nickname_collision(&self, nickname: &str) -> bool {
for user in &self.online_users {
if nickname == user.nickname {
return true;
}
}
false
}

}

pub struct CommandHandler {
pub command: Command,
pub context: String,
}

impl CommandHandler {
pub fn new(raw_command: &str, raw_context: &str) -> Self {
let command = match raw_command {
"NICK" => Command::SetNickName,
"USER" => Command::User,
"PING" => Command::Ping,
"LIST" => Command::List,
"JOIN" => Command::Join,
"TOPIC" => Command::Topic,
"NAMES" => Command::Names,
"PART" => Command::Part,
"USERS" => Command::Users,
"PRIVMSG" => Command::PrivateMessage,
"QUIT" => Command::Quit,
&_ => Command::CommandNotFound,
};

// what if message has multiple parameter
let context = raw_context
.clone()
.to_string()
.replace("\r\n", "");
CommandHandler {
command,
context,
}
}

pub fn set_nickname(&self, user: &mut User) {
// check if nickname collision in server
// set nickname to user
user.nickname = self.context.clone();
println!("{:?}", self.context);
}

fn new_user(&self) {
todo!()
}

fn ping(&self) {
todo!()
}

fn list_channel(&self) {
// list all channel, if the channel parameter is used, show the channel status only
todo!()
}
fn join_topic(&self) {
// client start listening a specific channel
todo!()
}

fn change_topic() {
// Change the channel topic in a mode +t channel
todo!()
}

fn list_all_nicknames() {
// By using the NAMES command, a user can list all nicknames that are
// visible to them on any channel that they can see.
todo!()
}

fn leave_channel() {
// The PART message causes the client sending the message to be removed
// from the list of active users for all given channels listed in the
// parameter string.
todo!()
}

fn list_users() {
// The USERS command returns a list of users logged into the server in a
// similar format
todo!()
}

fn private_message() {
// PRIVMSG is used to send private messages between users. <receiver>
// is the nickname of the receiver of the message. <receiver> can also
// be a list of names or channels separated with commas.
todo!()
}

fn quit() {
// A client session is ended with a quit message. The server must close
// the connection to a client which sends a QUIT message.
todo!()
}

}

99 changes: 12 additions & 87 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,92 +1,18 @@
use std::net::{TcpListener, Ipv4Addr, SocketAddrV4, TcpStream, SocketAddr};
use std::net::{TcpListener, Ipv4Addr, SocketAddrV4, TcpStream};
use std::time::Duration;
use std::io::{Read, Write};

// from lib
use irc_server::{Server, User, Command, CommandHandler};

const READ_TIMEOUT: (u64, u32) = (10, 0);
const WRITE_TIMEOUT: (u64, u32) = (10, 0);

struct User {
nickname: String,
belong_topics: Vec<String>,
ip: SocketAddr,
}

impl User {
fn new(name: String, ip: SocketAddr) -> User {
User {
nickname: name,
belong_topics: Vec::new(),
ip: ip,
}
}
}

struct Server {
online_users: Vec<User>,
topics: Vec<String>,
}

impl Server {
fn new() -> Server {
Server {
online_users: Vec::new(),
topics: Vec::new(),
}
}
}

struct CommandHandler {
command: Command,
context: String,
}

impl CommandHandler {
fn new(raw_command: &str, raw_context: &str) -> Self {
let command = match raw_command {
"NICK" => Command::SetNickName,
"USER" => Command::User,
"PING" => Command::Ping,
"LIST" => Command::List,
"JOIN" => Command::Join,
"TOPIC" => Command::Topic,
"NAMES" => Command::Names,
"PART" => Command::Part,
"USERS" => Command::Users,
"PRIVMSG" => Command::PrivateMessage,
"QUIT" => Command::Quit,
&_ => Command::CommandNotFound,
};

let context = raw_context.to_string();
CommandHandler {
command,
context,
}
}
}

enum Command {
SetNickName,
User,
Ping,
List,
Join,
Topic,
Names,
Part,
Users,
PrivateMessage,
Quit,
// custom
CommandNotFound
}


fn handle_event(tcp_stream: TcpStream, server: &Server) -> std::io::Result<()> {
fn handle_event(tcp_stream: TcpStream, server: &mut Server) -> std::io::Result<()> {
let mut stream = tcp_stream;
let user_ip = stream.peer_addr().unwrap();
println!("user joined via ip:port {}", user_ip);
let source_ip = stream.peer_addr()?;
println!("user joined via ip:port {:?}", source_ip);

let (r_second, r_micro_second) = READ_TIMEOUT;
let (w_second, w_micro_second) = WRITE_TIMEOUT;
Expand All @@ -99,21 +25,20 @@ fn handle_event(tcp_stream: TcpStream, server: &Server) -> std::io::Result<()> {
let result = stream.read(&mut buf);

let message = String::from_utf8((&buf).to_vec())
.unwrap_or_else(|_| panic!("Cant convert message {:?} to utf-8 from client: {}", &result, user_ip));
.unwrap_or_else(|_| panic!("Cant convert message {:?} to utf-8 from client: {}", &result, source_ip));


let (raw_command, raw_context) = message.trim_matches(char::from(0)).split_once(' ').unwrap();

dbg!(raw_command);
dbg!(raw_context);

let handler = CommandHandler::new(raw_command, raw_context);

// find user by ip, if not found, create user

let handler = CommandHandler::new(raw_command, raw_context);
match handler.command {
Command::SetNickName => {
let mut user = User::new(handler.context, user_ip);
// server.online_users.push(&mut user);
server.is_nickname_collision(&handler.context);
},
_ => !todo!()
}
Expand All @@ -125,9 +50,9 @@ fn main() -> std::io::Result<()> {
let socket_ip = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 6667);

let listener = TcpListener::bind(socket_ip)?;
let server = Server::new();
let server = &mut Server::new();
for stream in listener.incoming() {
handle_event(stream?, &server)?;
handle_event(stream?, server)?;
}

Ok(())
Expand Down

0 comments on commit d2005b3

Please sign in to comment.