Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/chat_app.cc
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ void Chat::on_realize() {
std::cout << "Status label not found\n";
}

inline void Chat::session_connection() {
void Chat::session_connection() {
// Disconnect if connected
if ( session ) {
session = nullptr;
Expand All @@ -101,7 +101,8 @@ inline void Chat::session_connection() {
// Try to connect as client
try {
session = std::make_unique<Client>(host, port);
status_label->set_label("Connected to server " + std::string(host) + ":" + std::to_string(port) + "!");
if ( status_label )
status_label->set_label("Connected to server " + std::string(host) + ":" + std::to_string(port) + "!");
} catch (const std::exception& e) {
session = nullptr;
// If not localhost, give up
Expand Down Expand Up @@ -173,7 +174,7 @@ inline void Chat::session_connection() {
session->set_poster([this]() { dispatcher->emit(); });
}

inline void Chat::message_buffer () {
void Chat::message_buffer () {
if ( !message_entry->get_text_length() ) return;
std::string message{message_entry->get_text()};
session->process_message(message);
Expand Down
4 changes: 2 additions & 2 deletions src/include/chat_app.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class Chat : public Gtk::Box {
*
* Does nothing if Entry is empty, else it adds the message and empties the Entry.
*/
inline void message_buffer();
void message_buffer();

/**
* @brief Tries connecting as client, falls back to hosting if localhost and no server found.
Expand All @@ -64,5 +64,5 @@ class Chat : public Gtk::Box {
* If the host is localhost and the connection fails, starts a Server and
* connects to it.
*/
inline void session_connection();
void session_connection();
};
35 changes: 21 additions & 14 deletions src/include/session.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ struct Connection {

tcp::socket socket;
asio::steady_timer send_timer;
std::mutex send_mutex;
std::mutex send_mutex{};
std::string nickname{};
std::string fingerprint{};
std::string send_buffer{};
Expand All @@ -53,9 +53,13 @@ struct Connection {
* Contains a sender and receiver asio functions and has a poster and disconnecter function so it can interact with GUI.
*/
class Session {
friend class ChatTest;
friend class ChatTest_ChatFunctionalTest_Test;

public:
std::vector<std::string> receive_queue;
std::mutex receive_mutex;
std::vector<std::string> receive_queue{};
std::mutex receive_mutex{};
std::string type{};

/* Default constructor for Session. */
Session() = default;
Expand Down Expand Up @@ -92,13 +96,12 @@ class Session {
virtual void process_message(std::string&, std::shared_ptr<Connection> = nullptr) = 0;

protected:
std::string host;
unsigned port;

asio::io_context ioc;
std::thread ioc_thread;
std::function<void(void)> poster;
std::function<void(void)> disconnecter;
std::string host{};
unsigned port{};
std::function<void(void)> poster{};
std::function<void(void)> disconnecter{};

/**
* @brief Sender function to run so the session sends data.
Expand Down Expand Up @@ -131,13 +134,13 @@ class Session {
* and receives messages from the server.
*/
class Client : public Session {
friend class ChatTest;
friend class ChatTest_ChatFunctionalTest_Test;

public:
/* Constructor for Client, initializes the connection and connects to the server. */
explicit Client(const std::string &host, unsigned port);

/* Destructor for Client. Closes socket if needed. */
~Client() noexcept;

/**
* @brief Processes a message for Client.
*
Expand All @@ -149,7 +152,7 @@ class Client : public Session {
void process_message(std::string&, std::shared_ptr<Connection> = nullptr) override;

private:
std::shared_ptr<Connection> connection;
std::shared_ptr<Connection> connection{};

/**
* @brief Receiver function to run so the connection awaits for data.
Expand Down Expand Up @@ -179,11 +182,14 @@ class Client : public Session {
* clients, and echoes it back to the sender tagged with "(you)".
*/
class Server : public Session {
friend class ChatTest;
friend class ChatTest_ChatFunctionalTest_Test;

public:
/* Constructor for Server, initializes the acceptor and starts the accept loop. */
explicit Server(unsigned port);

/* Destructor for Server. Closes the acceptor and all connections. */
/* Destructor for Server. Closes the acceptor. */
~Server() noexcept;

/**
Expand All @@ -203,7 +209,8 @@ class Server : public Session {

/**
* @brief Receiver function to run so the session awaits for data.
*
* Removes closed connections.
*
* @param[in] socket: Socket connection to receive data from.
*/
awaitable<void> receiver(std::shared_ptr<Connection>) override;
Expand Down
35 changes: 15 additions & 20 deletions src/session.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,9 @@ void Connection::add_to_send_buffer(std::string& message) {


Session::~Session() noexcept {
poster = nullptr;
disconnecter = nullptr;
if ( !ioc.stopped() ) ioc.stop();
if ( ioc_thread.joinable() ) ioc_thread.join();
std::cout << "[Server] stopped\n";
std::cout << "[" + type + "] stopped\n";
}

awaitable<void> Session::sender(std::shared_ptr<Connection> connection) {
Expand All @@ -44,7 +42,7 @@ awaitable<void> Session::sender(std::shared_ptr<Connection> connection) {
co_await asio::async_write(connection->socket, asio::buffer(data), use_awaitable);
}
} catch (const std::exception& e) {
std::cout << "[Server] sender error: " << e.what() << "\n";
std::cout << "[" + type + "] sender error: " << e.what() << "\n";
}
}

Expand All @@ -63,7 +61,7 @@ awaitable<void> Session::receiver(std::shared_ptr<Connection> connection) {
process_message(line, connection);
}
} catch (const std::exception& e) {
std::cout << "[Server] " << connection->nickname << " disconnected: " << e.what() << "\n";
std::cout << "[" + type + "] " << connection->nickname << " disconnected: " << e.what() << "\n";
}
}

Expand All @@ -76,6 +74,7 @@ void Session::set_disconnecter(std::function<void(void)> new_disconnecter)
Client::Client(const std::string &host, unsigned port) :
Session::Session(),
connection (std::make_shared<Connection>(ioc)) {
type = "Client";
connection->nickname = "Server";
this->host = host;
this->port = port;
Expand All @@ -87,19 +86,19 @@ Client::Client(const std::string &host, unsigned port) :
connection->send_timer.expires_at(asio::steady_timer::time_point::min());
tcp::resolver resolver(ioc);

std::cout << "Connecting to " << host << ":" << port << "...\n";
std::cout << "[Client] Connecting to " << host << ":" << port << "...\n";

asio::error_code ec;
auto endpoints = resolver.resolve(host, std::to_string(port), ec);
if (ec) {
std::cerr << "[error] resolve(): " << ec.message()
std::cerr << "[Client] resolve(): " << ec.message()
<< "\nIs the server running?\n";
throw std::runtime_error("Failed to resolve host");
}

asio::connect(connection->socket, endpoints, ec);
if (ec) {
std::cerr << "[error] connect(): " << ec.message()
std::cerr << "[Client] connect(): " << ec.message()
<< "\nIs the server running?\n";
throw std::runtime_error("Failed to connect to server");
}
Expand All @@ -110,14 +109,10 @@ Client::Client(const std::string &host, unsigned port) :

// Run the event loop in separate thread until ioc.stop() is called
ioc_thread = std::thread([this](){ ioc.run(); });
std::cout << "[Client] connected to " << host << ":" << port << "\n";
}


Client::~Client() noexcept {
if ( connection->socket.is_open() )
connection->socket.close();
}

awaitable<void> Client::receiver(std::shared_ptr<Connection> connection) {
co_await Session::receiver(connection);
if ( connection->socket.is_open() )
Expand All @@ -127,7 +122,7 @@ awaitable<void> Client::receiver(std::shared_ptr<Connection> connection) {

void Client::broadcast(const std::string& message, std::shared_ptr<Connection> origin) {
(void) origin;
connection->send_buffer += message + "\n";
connection->send_buffer.append(message + "\n");
connection->send_timer.cancel();
}

Expand All @@ -148,10 +143,10 @@ void Client::process_message(std::string &message, std::shared_ptr<Connection> o

Server::Server(unsigned port) : Session::Session(),
acceptor (tcp::acceptor(ioc, tcp::endpoint(tcp::v4(), static_cast<asio::ip::port_type>(port)))) {
host = "Server";
type = "Server";
asio::co_spawn(ioc, accept_loop(), asio::detached);
ioc_thread = std::thread([this](){ ioc.run(); });
std::cout << "[Server] listening on port " << port << "\n";
std::cout << "[" + type + "] listening on port " << port << "\n";
}

Server::~Server() noexcept {
Expand All @@ -163,9 +158,8 @@ awaitable<void> Server::receiver(std::shared_ptr<Connection> connection) {
if ( connection->socket.is_open() )
connection->socket.close();
connections.remove(connection);
std::string farewell{connection->nickname + " has left the chat!!!"};
std::string farewell{ connection->nickname + " has left the chat!!!" };
process_message(farewell);
if (disconnecter) disconnecter();
}

awaitable<void> Server::accept_loop() {
Expand All @@ -174,15 +168,15 @@ awaitable<void> Server::accept_loop() {
asio::error_code ec;
co_await acceptor.async_accept(connection->socket, asio::redirect_error(use_awaitable, ec));
if (ec) {
std::cout << "[server] accept loop ending: " << ec.message() << "\n";
std::cout << "[" + type + "] accept loop ending: " << ec.message() << "\n";
co_return;
}

try {
auto ep = connection->socket.remote_endpoint();
connection->fingerprint = ep.address().to_string() + ":" + std::to_string(ep.port());
} catch (...) { connection->fingerprint = "unknown"; }
std::cout << "[server] new client: " << connection->nickname << " (" << connection->fingerprint << ")\n";
std::cout << "[" + type + "] new client: " << connection->nickname << " (" << connection->fingerprint << ")\n";

std::string message {connection->nickname + " says Hi!!!\n"};
process_message(message);
Expand All @@ -192,6 +186,7 @@ awaitable<void> Server::accept_loop() {

connections.push_back(connection);
}
if (disconnecter) disconnecter();
}

void Server::broadcast(const std::string& message, std::shared_ptr<Connection> origin) {
Expand Down
2 changes: 0 additions & 2 deletions tests/browser_app_tests.cc
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
#include "include/tests.hpp"

#include <iostream>

#include <gtest/gtest.h>
#include <gmock/gmock.h>

Expand Down
Loading