IT WORKS HELL YEAH
This commit is contained in:
parent
ad892d913c
commit
a625bb55cd
2 changed files with 159 additions and 33 deletions
|
|
@ -7,7 +7,8 @@ And also my first serious C++ project.
|
||||||
- [X] Basic K/V store
|
- [X] Basic K/V store
|
||||||
- [X] Remove/add entries
|
- [X] Remove/add entries
|
||||||
- [X] Serialisation and saving
|
- [X] Serialisation and saving
|
||||||
- [ ] FUCKING NETWORKING (probably minimal RESP)
|
- [X] FUCKING NETWORKING (probably minimal RESP)
|
||||||
|
- [ ] Proper startup/shutdown w/ load & save
|
||||||
- [ ] Multithreading
|
- [ ] Multithreading
|
||||||
- [ ] More types
|
- [ ] More types
|
||||||
- [ ] Async
|
- [ ] Async
|
||||||
|
|
|
||||||
183
main.cpp
183
main.cpp
|
|
@ -1,8 +1,13 @@
|
||||||
|
#include <asm-generic/socket.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include "json.hpp"
|
#include "json.hpp"
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <format>
|
||||||
|
|
||||||
using Db = std::vector<std::vector<std::string>>;
|
using Db = std::vector<std::vector<std::string>>;
|
||||||
|
|
||||||
|
|
@ -16,10 +21,10 @@ void save_database(Db& database, std::string file_name) {
|
||||||
|
|
||||||
void load_database(Db& database, std::string file_name) {
|
void load_database(Db& database, std::string file_name) {
|
||||||
std::ifstream db_file(file_name);
|
std::ifstream db_file(file_name);
|
||||||
std::string raw_file_text;
|
std::stringstream raw_file_text;
|
||||||
db_file >> raw_file_text;
|
raw_file_text << db_file.rdbuf();
|
||||||
db_file.close();
|
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) {
|
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) {
|
// void prompt_user(Db& database) {
|
||||||
std::string mode;
|
// std::string mode;
|
||||||
std::cin >> mode;
|
// std::cin >> mode;
|
||||||
if (mode == "add") {
|
// if (mode == "add") {
|
||||||
std::string key;
|
// std::string key;
|
||||||
std::string value;
|
// std::string value;
|
||||||
std::cin >> key;
|
// std::cin >> key;
|
||||||
std::cin >> value;
|
// std::cin >> value;
|
||||||
add_entry(database, key, value);
|
// add_entry(database, key, value);
|
||||||
} else if (mode == "rem") {
|
// } else if (mode == "rem") {
|
||||||
std::string key;
|
// std::string key;
|
||||||
std::cin >> key;
|
// std::cin >> key;
|
||||||
remove_entry(database, key);
|
// remove_entry(database, key);
|
||||||
} else if (mode == "save") {
|
// } else if (mode == "save") {
|
||||||
std::string file;
|
// std::string file;
|
||||||
std::cin >> file;
|
// std::cin >> file;
|
||||||
save_database(database, file);
|
// save_database(database, file);
|
||||||
} else if (mode == "load") {
|
// } else if (mode == "load") {
|
||||||
std::string file;
|
// std::string file;
|
||||||
std::cin >> file;
|
// std::cin >> file;
|
||||||
load_database(database, file);
|
// load_database(database, file);
|
||||||
} else {
|
// } else {
|
||||||
prompt_user(database);
|
// prompt_user(database);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
std::vector<std::string> parse_resp_request(char* request) {
|
||||||
|
std::string request_str(request);
|
||||||
|
std::string delimiter = "\r\n";
|
||||||
|
std::vector<std::string> 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() {
|
int main() {
|
||||||
|
std::cout << "[i] Starting blueis server..." << std::endl;
|
||||||
Db database;
|
Db 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) {
|
while (true) {
|
||||||
for (std::vector entry: database) {
|
int client_socket = accept(listening_socket, (sockaddr*)&client_address, &client_size);
|
||||||
std::cout << entry[0] << " | " << entry[1] << std::endl;
|
if (client_socket < 0) {
|
||||||
|
std::cerr << "[E] Failed to accept connection." << std::endl;
|
||||||
|
close(listening_socket);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
prompt_user(database);
|
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<std::string> 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<std::string> 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;
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue