From 5cbaa841d0bf07f75614205059324e5d2adbc5dd Mon Sep 17 00:00:00 2001 From: Joursoir Date: Fri, 27 Nov 2020 01:41:09 +0300 Subject: server: add different messages, support commands('/') and spec-messages --- src/const_vars.hpp | 7 ++ src/server/chat.cpp | 91 ++++++++++++++++++++--- src/server/chat.hpp | 18 +++-- src/server/rooms.cpp | 205 ++++++++++++++++++++++++++++++++++----------------- src/server/rooms.hpp | 12 +-- 5 files changed, 246 insertions(+), 87 deletions(-) diff --git a/src/const_vars.hpp b/src/const_vars.hpp index 9c7b1c5..d41f800 100644 --- a/src/const_vars.hpp +++ b/src/const_vars.hpp @@ -13,4 +13,11 @@ const int max_usermsg_len = oneline_len * 3 - max_name_len - 2; // ": " = 2 // 57 * 3 - 18 - 2 = 151 const int max_msg_len = oneline_len * 3; // 57*3 = 171 +const int key_enter = 10; +const int key_escape = 27; +const int key_backspace = 127; + +const int usually_msg = 0; // no first char +const int system_msg = 1; // first char: '#' + #endif \ No newline at end of file diff --git a/src/server/chat.cpp b/src/server/chat.cpp index a9ecda1..0d6eef8 100644 --- a/src/server/chat.cpp +++ b/src/server/chat.cpp @@ -8,7 +8,7 @@ #include "chat.hpp" #include "rooms.hpp" -static const int qlen_for_listen = 6; +const int qlen_for_listen = 6; void ChatSession::Send(const char *msg) { @@ -61,7 +61,6 @@ void ChatSession::ReadAndCheck() int rc = read(GetFd(), buffer+buf_used, sizeof(buffer)-buf_used); CONSOLE_LOG("readC return %d bytes\n", rc); if(rc < 1) { - the_master->LeaveMessage(this); the_master->CloseSession(this); return; } @@ -94,27 +93,39 @@ void ChatSession::CheckLines() } } -void ChatSession::ChangeName(const char *n_name) +const char *ChatSession::GetName() +{ + if(name[0]) + return name; + return 0; +} + +void ChatSession::SetName(const char *n_name) { for(int i = 0; i < max_name_len; i++) name[i] = 0; strcpy(name, n_name); char *msg = new char[max_msg_len]; - sprintf(msg, "Now your name is %s\n", name); + sprintf(msg, "#Your name: %s\n", name); this->Send(msg); delete[] msg; } +void ChatSession::SetRoom(ChatRoom *new_master) +{ + this->the_master = new_master; +} + ////////////////////////////////////////////////////////////// Server::Server(EventSelector *sel, int fd) : FdHandler(fd), the_selector(sel) { the_selector->Add(this); - lobby = new ChatRoom(this, true); + lobby = new ChatRoom(this, std_id_lobby); } Server::~Server() @@ -150,6 +161,14 @@ Server *Server::Start(EventSelector *sel, int port) return new Server(sel, in_d); } +bool Server::RoomExist(int id) const +{ + if(!room[id]) + return false; + + return true; +} + void Server::Handle(bool r, bool w) { if(!r) @@ -164,6 +183,24 @@ void Server::Handle(bool r, bool w) ChatSession *s = new ChatSession(lobby, sd); lobby->AddSession(s); the_selector->Add(s); + + // welcome messages: + s->Send("#Welcome to WantChat!\n"); + s->Send(" \n"); + s->Send("#It is anonymous chat in retro-style 80s.\n"); + s->Send("#Use our chat-client for more immersed.\n"); + s->Send(" \n"); + s->Send("#This project is open source :)\n"); + s->Send("#Github: github.com/Joursoir/want-chat\n"); + s->Send(" \n"); + s->Send("#First, come up with a nickname using /name your_good_name\n"); + s->Send("#Thereafter you can join to room using /join room_id\n"); + s->Send("#You can find rooms using /rooms\n"); + s->Send(" \n"); + s->Send("#For more detailed info: /help. Good chatting!\n"); + s->Send(" \n"); + + } int Server::AddRoom() @@ -178,19 +215,53 @@ int Server::AddRoom() int id = -1; for(int i = 0; i < room_len; i++) { if(room[i] == 0) { - id = 0; - room[i] = new ChatRoom(this, false); + id = i; + room[i] = new ChatRoom(this, id); + break; } } if(id == -1) { ChatRoom **tmp = new ChatRoom*[room_len+1]; - for(int i = 0; i < room_len; i++) { + for(int i = 0; i < room_len; i++) tmp[i] = room[i]; - } - tmp[room_len] = new ChatRoom(this, false); + + id = room_len; + tmp[room_len] = new ChatRoom(this, id); room_len += 1; + + delete[] room; + room = tmp; } return id; +} + +bool Server::DeleteRoom(int id) +{ + if(!room[id]) + return false; + + delete room[id]; + room[id] = 0; + + return true; +} + +void Server::GotoLobby(ChatRoom *cur_room, ChatSession *s) +{ + cur_room->RemoveSession(s); + lobby->AddSession(s); + s->SetRoom(lobby); +} + +bool Server::ChangeSessionRoom(ChatRoom *cur_room, ChatSession *s, int id) +{ + if(id >= room_len || !room[id]) + return false; + + cur_room->RemoveSession(s); + room[id]->AddSession(s); + s->SetRoom(room[id]); + return true; } \ No newline at end of file diff --git a/src/server/chat.hpp b/src/server/chat.hpp index ca22519..6abfc48 100644 --- a/src/server/chat.hpp +++ b/src/server/chat.hpp @@ -27,29 +27,35 @@ class ChatSession : FdHandler { void ReadAndIgnore(); void ReadAndCheck(); void CheckLines(); + + void SetRoom(ChatRoom *new_master); public: - const char *GetName() const { return name; } + const char *GetName(); - void ChangeName(const char *n_name); + void SetName(const char *n_name); void Send(const char *msg); }; class Server : public FdHandler { EventSelector *the_selector; ChatRoom **room; - ChatRoom *lobby; - int room_len; + ChatRoom *lobby; + Server(EventSelector *sel, int fd); public: ~Server(); static Server *Start(EventSelector *sel, int port); + bool RoomExist(int id) const; + int AddRoom(); - // RemoveRoom(); - // void AddSessionToRoom(ChatSession *s, int id); + bool DeleteRoom(int id); // call only if room is empty + + void GotoLobby(ChatRoom *cur_room, ChatSession *s); + bool ChangeSessionRoom(ChatRoom *cur_room, ChatSession *s, int id); void CloseConnection(ChatSession *s) { the_selector->Remove(s); delete s; } private: diff --git a/src/server/rooms.cpp b/src/server/rooms.cpp index 624eb88..1ffb89a 100644 --- a/src/server/rooms.cpp +++ b/src/server/rooms.cpp @@ -1,23 +1,44 @@ #include #include +#include #include "rooms.hpp" #include "chat.hpp" // hash of commands: -#define CMD_NAME 210647350421 -#define CMD_CREATE 229394553991880 - -const int cmd_num = 2; -const char *commands[cmd_num] = { - "/name", - "/create" - // /rooms - print all public rooms -}; +#define CMD_NAME 0 +#define CMD_CREATE 1 +#define CMD_JOIN 2 +#define CMD_EXIT 3 +#define CMD_ROOMS 4 + +#define USE_IN_ROOM 0 +#define USE_IN_LOBBY 1 +#define USE_ANYWHERE 2 -char **ParseCommand(const char *input, int &arrc); +char **ParseToArg(const char *input, int &arrc); unsigned long hash(const char *str); +struct cmd_info { + char name[15]; + unsigned long name_hash; + int lobby_cmd; // USE_IN_ROOM, USE_IN_LOBBY, USE_ANYWHERE + int min_argc; + char usage[64]; +}; + +const int cmd_count = 5; +const struct cmd_info cmd[cmd_count] = { + {"/name", hash("/name"), USE_IN_LOBBY, 1, "#Usage: /name *your_good_name*\n"}, + {"/create", hash("/create"), USE_IN_LOBBY, 0, "#Usage: /create [pass-key]\n"}, + {"/join", hash("/join"), USE_IN_LOBBY, 1, "#Usage: /join *id* [pass-key]\n"}, + {"/exit", hash("/exit"), USE_IN_ROOM, 0, "#Usage: /exit\n"}, + {"/rooms", hash("/rooms"), USE_IN_LOBBY, 0, "#Usage: /rooms\n"} // print all public rooms + // if u add cmd, then add define too (see above) + + // IDEA: /clear - clear screen +}; + ChatRoom::~ChatRoom() { while(first) { @@ -37,31 +58,18 @@ void ChatRoom::SendAll(const char *msg, ChatSession *except) p->s->Send(msg); } -void ChatRoom::LeaveMessage(ChatSession *except) -{ - if(it_lobby) - return; - - const char left_msg[] = " has left the chat"; - const char *name = except->GetName(); - - int len = strlen(name); - char *lmsg = new char[len + sizeof(left_msg) + 2]; - sprintf(lmsg, "%s%s\n", name, left_msg); - this->SendAll(lmsg, except); - delete[] lmsg; -} - void ChatRoom::HandleMessage(ChatSession *ses, const char *str) { if(str[0] == '/') { // if user sent a command int argc = 0; - char **argv = 0; - argv = ParseCommand(str, argc); - + char **argv = ParseToArg(str, argc); this->HandleCommand(ses, argc, argv); + + for(int i = 0; i < argc; i++) + delete[] argv[i]; + delete[] argv; } - else if(!it_lobby) { + else if(code != std_id_lobby) { char *msg = new char[max_msg_len]; sprintf(msg, "%s: %s\n", ses->GetName(), str); @@ -71,54 +79,83 @@ void ChatRoom::HandleMessage(ChatSession *ses, const char *str) } } -void ChatRoom::HandleCommand(ChatSession *s, int cmd_counter, - char **commands) +void ChatRoom::HandleCommand(ChatSession *ses, int count, + char **argvar) { - unsigned long cmd = -1; - cmd = hash(commands[0]); + unsigned long hash_cmd = -1; + hash_cmd = hash(argvar[0]); - switch(cmd) - { - case CMD_NAME: { - if(!it_lobby) { - s->Send("You can use this command only in lobby\n"); - break; - } + int what_command = -1; + for(int i = 0; i < cmd_count; i++) { + if(cmd[i].name_hash == hash_cmd) { + what_command = i; + break; + } + } - if(cmd_counter == 1) { - s->Send("Usage: /name your_good_name\n"); - break; - } + if(what_command == -1) + return ses->Send("#Unknown command. Use: /help\n"); - int len = strlen(commands[1]); - if(len > max_name_len || len < 3) { - s->Send("Incorrect name. Name length from 3 to 18 chars\n"); - break; - } + const char onlyroom_msg[] = "#You can use this command only in rooms!\n"; + const char onlylobby_msg[] = "#You can use this command only in lobby!\n"; + const char initname_msg[] = "#First come up with name!\n"; + + // scope of command: + if(cmd[what_command].lobby_cmd == USE_IN_ROOM && code == std_id_lobby) + return ses->Send(onlyroom_msg); + else if(cmd[what_command].lobby_cmd == USE_IN_LOBBY && code != std_id_lobby) + return ses->Send(onlylobby_msg); + + // right usage: + if(cmd[what_command].min_argc > count-1) + return ses->Send(cmd[what_command].usage); - s->ChangeName(commands[1]); + // name check: + if((!ses->GetName()) && what_command != CMD_NAME) + return ses->Send(initname_msg); + + switch(what_command) { + case CMD_NAME: { + int len = strlen(argvar[1]); + if(len > max_name_len || len < 3) + return ses->Send("#Incorrect name. Name length from 3 to 18 chars\n"); + + ses->SetName(argvar[1]); break; } case CMD_CREATE: { - if(!it_lobby) { - s->Send("You can use this command only in lobby\n"); - break; - } - if(!s->GetName()) { - s->Send("Before you can use this command, use /name\n"); - break; - } + int id = the_server->AddRoom(); - //int id = the_s->AddRoom(); - //the_s->AddSessionToRoom(s, id); + const char fcmsg[] = "#You create a room #"; + const char scmsg[] = " with password "; + char *cmsg = new char[strlen(fcmsg)+strlen(scmsg)+4]; + sprintf(cmsg, "%s%d\n", fcmsg, id); + ses->Send(cmsg); + delete[] cmsg; + the_server->ChangeSessionRoom(this, ses, id); + break; + } + case CMD_JOIN: { + int id = atoi(argvar[1]); + bool success = false; + if(id >= 0) + success = the_server->ChangeSessionRoom(this, ses, id); + + if(!success) + ses->Send("#Room with that id didn't exist\n"); + + break; + } + case CMD_EXIT: { + the_server->GotoLobby(this, ses); break; } + case CMD_ROOMS: { - default: { - s->Send("Unknown command. Use: /help\n"); break; } + default: break; } } @@ -128,10 +165,40 @@ void ChatRoom::AddSession(ChatSession *ses) p->next = first; p->s = ses; first = p; + + if(code == std_id_lobby) + return; + + const char welcome_msg[] = "Welcome to the room #"; + const char entered_msg[] = " has entered the room"; + + const char *name = ses->GetName(); + + char *wmsg = new char[sizeof(welcome_msg) + 2]; + sprintf(wmsg, "#%s%d\n", welcome_msg, code); + ses->Send(wmsg); + delete[] wmsg; + + char *emsg = new char[strlen(name) + sizeof(entered_msg) + 2]; + sprintf(emsg, "#%s%s\n", name, entered_msg); + this->SendAll(emsg, ses); + delete[] emsg; + } void ChatRoom::RemoveSession(ChatSession *ses) { + if(code != std_id_lobby) { + const char left_msg[] = " has left the room"; + const char *name = ses->GetName(); + + int len = strlen(name); + char *lmsg = new char[len + sizeof(left_msg) + 2]; + sprintf(lmsg, "#%s%s\n", name, left_msg); + this->SendAll(lmsg, ses); + delete[] lmsg; + } + item **p; for(p = &first; *p; p = &((*p)->next)) { if( ((*p)->s) == ses ) { @@ -139,6 +206,10 @@ void ChatRoom::RemoveSession(ChatSession *ses) *p = tmp->next; // not delete ChatSession! delete tmp; + + if(code != std_id_lobby && !first) + the_server->DeleteRoom(code); + return; } } @@ -146,13 +217,14 @@ void ChatRoom::RemoveSession(ChatSession *ses) void ChatRoom::CloseSession(ChatSession *ses) { + Server *serv = the_server; this->RemoveSession(ses); - the_server->CloseConnection(ses); + serv->CloseConnection(ses); } ////////////////////////////////////////////////////////////// -char **ParseCommand(const char *input, int &arrc) +char **ParseToArg(const char *input, int &arrc) { int max_argv = 5; arrc = 0; @@ -161,12 +233,13 @@ char **ParseCommand(const char *input, int &arrc) int start = 0; for(int i = 0; i < (int) strlen(input)+1; i++) { if(input[i] == ' ' || input[i] == '\0' || input[i] == '\n') { // end - if(start == -1) + if(start == std_id_lobby) continue; int size = i - start; - arr[arrc] = new char[size]; + arr[arrc] = new char[size+1]; memcpy(arr[arrc], input + start, sizeof(char) * size); + arr[arrc][size] = '\0'; start = -1; arrc++; diff --git a/src/server/rooms.hpp b/src/server/rooms.hpp index 08fffff..9423be1 100644 --- a/src/server/rooms.hpp +++ b/src/server/rooms.hpp @@ -1,12 +1,15 @@ #ifndef ROOMREALIZATION_H #define ROOMREALIZATION_H +const int std_id_lobby = -1; + class Server; class ChatSession; class ChatRoom { Server *the_server; - const bool it_lobby; + const int code; + // code == -1 it's lobby struct item { ChatSession *s; @@ -14,15 +17,14 @@ class ChatRoom { }; item *first; public: - ChatRoom(Server *i_server, bool i_lobby) - : the_server(i_server), it_lobby(i_lobby), first(0) {} + ChatRoom(Server *i_server, int id) + : the_server(i_server), code(id), first(0) {} ~ChatRoom(); void SendAll(const char *msg, ChatSession *except = 0); - void LeaveMessage(ChatSession *except); void HandleMessage(ChatSession *ses, const char *str); - void HandleCommand(ChatSession *s, int cmd_counter, + void HandleCommand(ChatSession *ses, int cmd_counter, char **commands); void AddSession(ChatSession *ses); -- cgit v1.2.3-18-g5258