Skip to content
Closed
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
94 changes: 94 additions & 0 deletions include/server/client_info.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#ifndef FENRIS_CLIENT_INFO_HPP
#define FENRIS_CLIENT_INFO_HPP

#include <atomic>
#include <cstdint>
#include <memory>
#include <mutex>
#include <string>
#include <vector>

namespace fenris {
namespace server {

const std::string DEFAULT_SERVER_DIR = "/fenris_server";

struct Node {
std::string name;
bool is_directory;
std::vector<std::shared_ptr<Node>> children;
std::weak_ptr<Node> parent;
std::atomic<int> access_count{0};
std::mutex node_mutex;
};

class FileSystemTree {
public:
FileSystemTree();

// Adds a new node to the tree
bool add_node(const std::string &path, bool is_directory);

// Removes a node from the tree
bool remove_node(const std::string &path);

// Finds a node by its path
std::shared_ptr<Node> find_node(const std::string &path);

// Finds a file in the current node's children
std::shared_ptr<Node> find_file(const std::shared_ptr<Node> &current_node,
const std::string &file);

std::shared_ptr<Node>
find_directory(const std::shared_ptr<Node> &current_node,
const std::string &dir);

std::shared_ptr<Node> root; // Root of the file system tree

private:
std::mutex tree_mutex; // Mutex for thread-safe access to the tree

// Helper function to traverse the tree
std::shared_ptr<Node> traverse(const std::string &path);
};

struct ClientInfo {
uint32_t client_id;
uint32_t socket;
std::string address;
std::string port;
std::string current_directory = "/";
uint32_t depth = 0; // Depth of the current directory in the tree
bool keep_connection;

std::vector<uint8_t> encryption_key;
std::shared_ptr<Node>
current_node; // Pointer to the current node in the file system tree

ClientInfo(uint32_t client_id, uint32_t client_socket)
: client_id(client_id), socket(client_socket), keep_connection(true),
current_node(nullptr)
{
}

// Function to set the current node
void set_current_node(std::shared_ptr<Node> node)
{
if (current_node) {
current_node->access_count++;
}
}

~ClientInfo()
{
// Ensure that current_node is root before deleting the client info
if (current_node) {
current_node->access_count--;
}
}
};

} // namespace server
} // namespace fenris

#endif // FENRIS_CLIENT_INFO_HPP
55 changes: 21 additions & 34 deletions include/server/connection_manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "common/crypto_manager.hpp"
#include "common/logging.hpp"
#include "fenris.pb.h"
#include "server/client_info.hpp"

#include <atomic>
#include <cstdint>
Expand All @@ -19,16 +20,25 @@
namespace fenris {
namespace server {

struct ClientInfo {
uint32_t client_id;
uint32_t socket;
std::string address;
std::string port;
std::string current_directory;
std::vector<uint8_t> encryption_key;
};
/**
* @class IClientHandler
* @brief Interface for handling client requests
*
* Implement this interface to process client requests in your file system
*/
class IClientHandler {
public:
virtual ~IClientHandler() = default;

class ClientHandler;
/**
* @brief Process a client request.
* @param client_socket Socket descriptor for the client connection.
* @param request The deserialized client request.
* @return A Response object to be sent back to the client.
*/
virtual fenris::Response handle_request(const fenris::Request &request,
ClientInfo &client_info) = 0;
};

/**
* @class ConnectionManager
Expand Down Expand Up @@ -75,7 +85,7 @@ class ConnectionManager {
* @brief Set handler for client connections
* @param handler Function that processes client requests
*/
void set_client_handler(std::unique_ptr<ClientHandler> handler);
void set_client_handler(std::unique_ptr<IClientHandler> handler);

/**
* @brief Get number of active clients
Expand Down Expand Up @@ -144,7 +154,7 @@ class ConnectionManager {

std::string m_hostname;
std::string m_port;
std::unique_ptr<ClientHandler> m_client_handler;
std::unique_ptr<IClientHandler> m_client_handler;
int32_t m_server_socket{-1};
std::atomic<bool> m_running{false};
std::thread m_listen_thread;
Expand All @@ -160,29 +170,6 @@ class ConnectionManager {
std::atomic<uint32_t> m_next_client_id{1};
};

/**
* @class ClientHandler
* @brief Interface for handling client requests
*
* Implement this interface to process client requests in your file system
*/
class ClientHandler {
public:
virtual ~ClientHandler() = default;

/**
* @brief Process a client request.
* @param client_socket Socket descriptor for the client connection.
* @param request The deserialized client request.
* @return A Response object to be sent back to the client.
* The 'success' field should indicate if the operation succeeded.
* Return a default or error response if processing fails
* internally.
*/
virtual std::pair<fenris::Response, bool>
handle_request(uint32_t client_socket, const fenris::Request &request) = 0;
};

} // namespace server
} // namespace fenris

Expand Down
36 changes: 36 additions & 0 deletions include/server/request_manager.hpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,45 @@
#ifndef FENRIS_SERVER_REQUEST_MANAGER_HPP
#define FENRIS_SERVER_REQUEST_MANAGER_HPP

#include "common/file_operations.hpp"
#include "fenris.pb.h"
#include "server/client_info.hpp"
#include "server/connection_manager.hpp"

namespace fenris {
namespace server {

class ClientHandler : public IClientHandler {
public:
explicit ClientHandler();

bool step_directory_with_mutex(std::string &current_directory,
const std::string &new_directory,
uint32_t &depth,
std::shared_ptr<Node> &current_node);

void traverse_back(std::string &current_directory,
uint32_t &depth,
std::shared_ptr<Node> &current_node);

std::pair<std::string, uint32_t>
change_directory(std::string current_directory,
std::string path,
uint32_t &depth,
std::shared_ptr<Node> &current_node);

void destroy_node(std::string &current_directory,
uint32_t &depth,
std::shared_ptr<Node> &current_node);

fenris::Response handle_request(const fenris::Request &request,
ClientInfo &client_info);

void initialize_file_system_tree();

FileSystemTree FST;
};

} // namespace server
} // namespace fenris

Expand Down
1 change: 0 additions & 1 deletion include/server/server.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
namespace fenris {
namespace server {


} // namespace server
} // namespace fenris

Expand Down
12 changes: 11 additions & 1 deletion src/server/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ verbose_message("Setting up server executable...")
set(SERVER_SOURCES
main.cpp
cache_manager.cpp
client_info.cpp
connection_manager.cpp
request_manager.cpp
response_manager.cpp
server.cpp
)

Expand All @@ -26,6 +26,16 @@ target_link_libraries(fenris_server
fenris_common
)

# Client executable
add_executable(server main.cpp)

# Link libraries to the client executable
target_link_libraries(server
PRIVATE
fenris_client
fenris_common
fenris_proto
)
# Install the server executable
install(TARGETS fenris_server
RUNTIME DESTINATION bin
Expand Down
125 changes: 125 additions & 0 deletions src/server/client_info.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#include "server/client_info.hpp"
#include <algorithm>
#include <sstream>
#include <stdexcept>

namespace fenris {
namespace server {

FileSystemTree::FileSystemTree()
{
root = std::make_shared<Node>();
root->name = "/";
root->is_directory = true;
root->access_count = 0;
root->parent.reset(); // Use reset() to clear the weak_ptr
}

bool FileSystemTree::add_node(const std::string &path, bool is_directory)
{
std::lock_guard<std::mutex> lock(tree_mutex);
auto parent = traverse(path.substr(0, path.find_last_of('/')));
if (!parent || !parent->is_directory) {
return false;
}

auto new_node = std::make_shared<Node>();
new_node->name = path.substr(path.find_last_of('/') + 1);
new_node->is_directory = is_directory;
new_node->access_count = 0;
new_node->parent = parent;

parent->children.push_back(new_node);

return true;
}

bool FileSystemTree::remove_node(const std::string &path)
{
std::lock_guard<std::mutex> lock(tree_mutex);
auto node = traverse(path);
if (!node || node->access_count > 0) {
return false; // Cannot remove a node being accessed
}

auto parent = node->parent.lock();
if (parent) {
auto it = std::remove_if(parent->children.begin(),
parent->children.end(),
[&node](const std::shared_ptr<Node> &child) {
return child == node;
});
parent->children.erase(it, parent->children.end());
}

return true;
}

std::shared_ptr<Node> FileSystemTree::find_node(const std::string &path)
{
std::lock_guard<std::mutex> lock(tree_mutex);
return traverse(path);
}

std::shared_ptr<Node>
FileSystemTree::find_file(const std::shared_ptr<Node> &current_node,
const std::string &file)
{
std::lock_guard<std::mutex> lock(tree_mutex);
auto it = std::find_if(current_node->children.begin(),
current_node->children.end(),
[&file](const std::shared_ptr<Node> &child) {
return ((child->name == file) &&
(child->is_directory == false));
});
return (it != current_node->children.end()) ? *it : nullptr;
}

std::shared_ptr<Node>
FileSystemTree::find_directory(const std::shared_ptr<Node> &current_node,
const std::string &dir)
{
std::lock_guard<std::mutex> lock(tree_mutex);
auto it = std::find_if(current_node->children.begin(),
current_node->children.end(),
[&dir](const std::shared_ptr<Node> &child) {
return ((child->name == dir) &&
(child->is_directory == true));
});
return (it != current_node->children.end()) ? *it : nullptr;
}

std::shared_ptr<Node> FileSystemTree::traverse(const std::string &path)
{
if (path == "/") {
return root;
}

std::istringstream stream(path);
std::string segment;
auto current = root;

while (std::getline(stream, segment, '/')) {
if (segment.empty()) {
continue;
}

std::lock_guard<std::mutex> lock(current->node_mutex);
auto it = std::find_if(current->children.begin(),
current->children.end(),
[&segment](const std::shared_ptr<Node> &child) {
return child->name == segment;
});

if (it == current->children.end()) {
return nullptr;
}

current = *it;
}

return current;
}

} // namespace server
} // namespace fenris
Loading