diff --git a/README.md b/README.md index 1522862..f783edf 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,8 @@ And also my first serious C++ project. - [X] Basic K/V store - [X] Remove/add entries - [X] Serialisation and saving -- [ ] FUCKING NETWORKING (probably minimal RESP) +- [X] FUCKING NETWORKING (probably minimal RESP) +- [ ] Proper startup/shutdown w/ load & save - [ ] Multithreading - [ ] More types - [ ] Async diff --git a/main.cpp b/main.cpp index 30711a3..87160a0 100644 --- a/main.cpp +++ b/main.cpp @@ -1,8 +1,13 @@ +#include #include #include #include #include #include "json.hpp" +#include +#include +#include +#include using Db = std::vector>; @@ -16,10 +21,10 @@ void save_database(Db& database, std::string file_name) { void load_database(Db& database, std::string file_name) { std::ifstream db_file(file_name); - std::string raw_file_text; - db_file >> raw_file_text; + std::stringstream raw_file_text; + raw_file_text << db_file.rdbuf(); db_file.close(); - database = nlohmann::json::parse(raw_file_text); + database = nlohmann::json::parse(raw_file_text.str()); } void add_entry(Db& database, std::string key, std::string value) { @@ -36,39 +41,159 @@ void remove_entry(Db& database, std::string key) { } } -void prompt_user(Db& database) { - std::string mode; - std::cin >> mode; - if (mode == "add") { - std::string key; - std::string value; - std::cin >> key; - std::cin >> value; - add_entry(database, key, value); - } else if (mode == "rem") { - std::string key; - std::cin >> key; - remove_entry(database, key); - } else if (mode == "save") { - std::string file; - std::cin >> file; - save_database(database, file); - } else if (mode == "load") { - std::string file; - std::cin >> file; - load_database(database, file); - } else { - prompt_user(database); +// void prompt_user(Db& database) { + // std::string mode; + // std::cin >> mode; + // if (mode == "add") { + // std::string key; + // std::string value; + // std::cin >> key; + // std::cin >> value; + // add_entry(database, key, value); + // } else if (mode == "rem") { + // std::string key; + // std::cin >> key; + // remove_entry(database, key); + // } else if (mode == "save") { + // std::string file; + // std::cin >> file; + // save_database(database, file); + // } else if (mode == "load") { + // std::string file; + // std::cin >> file; + // load_database(database, file); + // } else { + // prompt_user(database); + // } +// } + +std::vector parse_resp_request(char* request) { + std::string request_str(request); + std::string delimiter = "\r\n"; + std::vector split_request; + size_t pos = 0; + + while ((pos = request_str.find(delimiter)) != std::string::npos) { + split_request.push_back(request_str.substr(0, pos)); + request_str.erase(0, pos + delimiter.length()); } + + if (request_str.length() > 0) { + split_request.push_back(request_str); + } + + + for (std::string entry: split_request) { + if (entry.contains("*")) { + split_request.erase(find(split_request.begin(), split_request.end(), entry)); + } + } + for (std::string entry: split_request) { + if (entry.contains("$")) { + split_request.erase(find(split_request.begin(), split_request.end(), entry)); + } + } + + return split_request; } + int main() { + std::cout << "[i] Starting blueis server..." << std::endl; Db database; - - while (true) { - for (std::vector entry: database) { - std::cout << entry[0] << " | " << entry[1] << std::endl; - } - prompt_user(database); + load_database(database, "db.json"); + int listening_socket = socket(AF_INET, SOCK_STREAM, 0 ); + if (listening_socket < 0) { + std::cerr << "[E] Failed to create socket." << std::endl; + return 1; } + + int optval = 1; + if (setsockopt(listening_socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0) { + std::cerr << "[W] Failed to use SO_REUSEADDR. Continuing." << std::endl; + } + + sockaddr_in server_address; + server_address.sin_family = AF_INET; + server_address.sin_port = htons(6379); + server_address.sin_addr.s_addr = INADDR_ANY; + + if (bind(listening_socket, (sockaddr*)&server_address, sizeof(server_address)) < 0) { + std::cerr << "[E] Failed to bind to port 6379. Check for any other running redis or blueis instances." << std::endl; + close(listening_socket); + return 1; + } + + if (listen(listening_socket, 5) < 0) { + std::cerr << "[E] Failed to listen on socket." << std::endl; + close(listening_socket); + return 1; + } + + std::cout << "[i] Server listening on port 6379..." << std::endl; + + sockaddr_in client_address; + socklen_t client_size = sizeof(client_address); + + while (true) { + int client_socket = accept(listening_socket, (sockaddr*)&client_address, &client_size); + if (client_socket < 0) { + std::cerr << "[E] Failed to accept connection." << std::endl; + close(listening_socket); + return 1; + } + std::cout << "[i] Client connected." << std::endl; + while (true) { + char buffer[4096]; + int bytes_received = recv(client_socket, buffer, 4096, 0); + + if (bytes_received > 0) { + buffer[bytes_received] = '\0'; + std::cout << "[i] Received: " << buffer << std::endl; + std::vector parsed = parse_resp_request(buffer); + for (std::string& var: parsed) { + } + if (parsed[0] == "GET") { + bool found = false; + for (const auto& inner_vec: database) { + if (!inner_vec.empty() && inner_vec[0] == parsed[1]) { + int length = inner_vec[1].length(); + std::string return_string = std::format("${}\r\n{}\r\n", length, inner_vec[1]); + std::cout << "[d] Sending: " << return_string << std::endl; + send(client_socket, return_string.data(), return_string.length(), 0); + found = true; + } + } + + if (!found) { + send(client_socket, "$-1\r\n", strlen("$-1\r\n"), 0); + } + } else if (parsed[0] == "SET") { + bool found = false; + for (auto& inner_vec: database) { + if (!inner_vec.empty() && inner_vec[0] == parsed[1]) { + inner_vec[1] = parsed[2]; + send(client_socket, "+OK\r\n", strlen("+OK\r\n"), 0); + found = true; + } + if (!found) { + std::vector new_kv = { parsed[1], parsed[2] }; + database.push_back(new_kv); + send(client_socket, "+OK\r\n", strlen("+OK\r\n"), 0); + found = true; + } + } + } else { + send(client_socket, "+OK\r\n", strlen("+OK\r\n"), 0); + } + } else { + close(client_socket); + std::cout << "[i] Client disconnected." << std::endl; + break; + } + } + } + + + return 0; }