#include #include #include #include #include #include "json.hpp" #include #include #include #include #include #include #include using Db = std::vector>; Db database; void save_database(std::string file_name) { nlohmann::json json_data = database; std::string serialised_json_data = json_data.dump(); std::ofstream db_file(file_name); db_file << serialised_json_data; db_file.close(); } void load_database(std::string file_name) { std::ifstream db_file(file_name); std::stringstream raw_file_text; raw_file_text << db_file.rdbuf(); db_file.close(); database = nlohmann::json::parse(raw_file_text.str()); } 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; } void safe_exit(int signum) { std::cout << "[W] Exiting..." << std::endl; save_database("db.json"); exit(signum); } int main() { std::cout << "[i] Starting blueis server..." << std::endl; signal(SIGINT, safe_exit); load_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::vector parsed = parse_resp_request(buffer); if (parsed[0] == "GET") { bool found = false; for (const auto& inner_vec: database) { // Iterate through DB and find the required item 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]); // Serialise to RESP 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); // Not found } } else if (parsed[0] == "SET") { bool found = false; // Avoids SEGFAULT 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); // Temporary catch-all (for more advanced handshake) } } else { close(client_socket); std::cout << "[i] Client disconnected." << std::endl; break; } } } return 0; }