lander/src/main.cpp

141 lines
4.3 KiB
C++
Raw Normal View History

#include <sys/stat.h>
#include <sys/types.h>
2022-11-15 16:05:47 +01:00
#include "crow.h"
2022-11-15 17:25:04 +01:00
extern "C" {
2022-11-15 17:05:14 +01:00
#include "ternarytrie.h"
2022-11-15 17:25:04 +01:00
}
2022-11-15 16:05:47 +01:00
2022-11-21 12:03:16 +01:00
#define ENV(var, env_var) \
2022-11-21 14:46:53 +01:00
const char *_##var = getenv(env_var); \
if (_##var == NULL) { \
2022-11-21 12:03:16 +01:00
printf("Missing environment variable %s.\n", env_var); \
return 1; \
2022-11-21 14:46:53 +01:00
} \
2022-11-21 14:19:56 +01:00
const std::string var = std::string(_##var);
2022-11-15 17:05:14 +01:00
2022-11-21 12:03:16 +01:00
#define AUTH() \
std::string provided_api_key = req.get_header_value("X-Api-Key"); \
2022-11-21 14:46:53 +01:00
if (api_key.compare(provided_api_key) != 0) { \
2022-11-21 12:03:16 +01:00
return crow::response(crow::status::UNAUTHORIZED); \
}
2022-11-15 16:05:47 +01:00
2022-11-21 12:03:16 +01:00
int main() {
2022-11-21 12:21:01 +01:00
// Initialize random seed for generating URLs
srand(time(NULL));
2022-11-21 12:03:16 +01:00
ENV(api_key, "LANDER_API_KEY");
ENV(base_url, "LANDER_BASE_URL");
ENV(data_dir, "LANDER_DATA_DIR");
2022-11-21 12:03:16 +01:00
// Initialize trie and populate from data file
TernaryTrie *trie = ternarytrie_init();
2022-11-15 17:25:04 +01:00
std::string file_path = data_dir + "/lander.data";
2022-11-21 14:19:56 +01:00
2022-11-21 14:46:53 +01:00
std::cout << "Populating trie from file '" << file_path << "'..."
<< std::endl;
2022-11-21 14:19:56 +01:00
int count = ternarytrie_populate(trie, file_path.c_str());
if (count == -1) {
std::cout << "An error occured while populating the trie." << std::endl;
exit(1);
} else {
std::cout << "Added " << count << " entries to trie." << std::endl;
}
// Create pastes directory if not present
// TODO don't just ignore errors here
mkdir((data_dir + "/pastes").c_str(), 0700);
crow::SimpleApp app;
2022-11-21 16:22:52 +01:00
app.loglevel(crow::LogLevel::Info);
2022-11-21 16:28:27 +01:00
// Serve an entry
CROW_ROUTE(app, "/<string>")
.methods(crow::HTTPMethod::Get)(
2022-11-21 16:28:27 +01:00
[data_dir, trie](crow::response &res, std::string key) {
Entry *entry = ternarytrie_search(trie, key.c_str());
if (entry != NULL) {
2022-11-21 16:28:27 +01:00
if (entry->type == Redirect) {
res.redirect(entry->string);
} else if (entry->type == Paste) {
res.set_static_file_info(data_dir + "/pastes/" + key);
}
} else {
res.code = 404;
}
res.end();
});
// Add a new Redirect with a randomly generated key
2022-11-21 16:22:52 +01:00
CROW_ROUTE(app, "/s/")
.methods(crow::HTTPMethod::Post)(
[api_key, base_url, trie](const crow::request req) {
AUTH();
2022-11-21 12:03:16 +01:00
2022-11-21 16:22:52 +01:00
Entry *new_entry = entry_new(Redirect, req.body.c_str());
char *key = ternarytrie_add_random(trie, new_entry);
2022-11-21 12:03:16 +01:00
2022-11-21 16:22:52 +01:00
if (key == NULL) {
return crow::response(crow::status::INTERNAL_SERVER_ERROR);
}
2022-11-21 12:03:16 +01:00
2022-11-21 16:22:52 +01:00
std::string res = base_url + key;
free(key);
2022-11-21 12:21:01 +01:00
2022-11-21 16:22:52 +01:00
return crow::response(res);
});
// Add a new Redirect with a given path
CROW_ROUTE(app, "/s/<string>")
2022-11-21 12:03:16 +01:00
.methods(crow::HTTPMethod::Post)(
[api_key, base_url, trie](const crow::request &req, std::string key) {
2022-11-21 12:03:16 +01:00
AUTH();
Entry *new_entry = entry_new(Redirect, req.body.c_str());
bool added = ternarytrie_add(trie, key.c_str(), new_entry);
2022-11-21 12:03:16 +01:00
2022-11-21 12:21:01 +01:00
if (!added) {
2022-11-21 12:03:16 +01:00
return crow::response(crow::status::CONFLICT);
}
2022-11-21 14:19:56 +01:00
return crow::response(base_url + key);
2022-11-21 12:03:16 +01:00
});
2022-11-21 16:22:52 +01:00
// Add a new Paste with a randomly generated key
CROW_ROUTE(app, "/p/")
.methods(crow::HTTPMethod::Post)(
[api_key, base_url, data_dir, trie](const crow::request &req) {
AUTH();
Entry *new_entry = entry_new(Paste, "");
char *key = ternarytrie_add_random(trie, new_entry);
if (key == NULL) {
return crow::response(crow::status::INTERNAL_SERVER_ERROR);
}
// Write paste contents to file
std::fstream file;
file.open(data_dir + "/pastes/" + key, std::ios_base::out);
if (!file.is_open()) {
return crow::response(crow::status::INTERNAL_SERVER_ERROR);
}
file << req.body;
file.close();
return crow::response(base_url + key);
});
app.port(18080).multithreaded().run();
2022-11-15 16:05:47 +01:00
}