lander/src/main.cpp

144 lines
4.3 KiB
C++

#include <sys/stat.h>
#include <sys/types.h>
#include "crow.h"
extern "C" {
#include "ternarytrie.h"
}
#define ENV(var, env_var) \
const char *_##var = getenv(env_var); \
if (_##var == NULL) { \
printf("Missing environment variable %s.\n", env_var); \
return 1; \
} \
const std::string var = std::string(_##var);
#define AUTH() \
std::string provided_api_key = req.get_header_value("X-Api-Key"); \
if (api_key.compare(provided_api_key) != 0) { \
return crow::response(crow::status::UNAUTHORIZED); \
}
int main() {
// Initialize random seed for generating URLs
srand(time(NULL));
ENV(api_key, "LANDER_API_KEY");
ENV(base_url, "LANDER_BASE_URL");
// Initialize trie and populate from data file
TernaryTrie *trie = ternarytrie_init();
std::string file_path = "lander.data";
std::cout << "Populating trie from file '" << file_path << "'..."
<< std::endl;
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("pastes", 0700);
crow::SimpleApp app;
app.loglevel(crow::LogLevel::Info);
// Serve an entry
CROW_ROUTE(app, "/<string>")
.methods(crow::HTTPMethod::Get)(
[trie](crow::response &res, std::string key) {
Entry *entry = ternarytrie_search(trie, key.c_str());
if (entry != NULL) {
if (entry->type == Redirect) {
res.redirect(entry->string);
} else if (entry->type == Paste) {
res.set_static_file_info("pastes/" + key);
}
} else {
res.code = 404;
}
res.end();
});
// Add a new Redirect with a randomly generated key
CROW_ROUTE(app, "/s/")
.methods(crow::HTTPMethod::Post)(
[api_key, base_url, trie](const crow::request req) {
AUTH();
Entry *new_entry = entry_new(Redirect, req.body.c_str());
char *key = ternarytrie_add_random(trie, new_entry);
if (key == NULL) {
return crow::response(crow::status::INTERNAL_SERVER_ERROR);
}
std::string res = base_url + key;
free(key);
return crow::response(res);
});
// Add a new Redirect with a given path
CROW_ROUTE(app, "/s/<string>")
.methods(crow::HTTPMethod::Post)(
[api_key, base_url, trie](const crow::request &req, std::string key) {
AUTH();
Entry *new_entry = entry_new(Redirect, req.body.c_str());
bool added = ternarytrie_add(trie, key.c_str(), new_entry);
if (!added) {
return crow::response(crow::status::CONFLICT);
}
return crow::response(base_url + key);
});
// Add a new Paste with a randomly generated key
CROW_ROUTE(app, "/p/")
.methods(crow::HTTPMethod::Post)(
[api_key, base_url, 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(std::string("pastes/") + key, std::ios_base::out);
if (!file.is_open()) {
free(key);
return crow::response(crow::status::INTERNAL_SERVER_ERROR);
}
file << req.body;
file.close();
std::string res = base_url + key;
free(key);
return crow::response(res);
});
app.port(18080).multithreaded().run();
}