Basic working version without persistent storage

trie-skips
Jef Roosens 2022-11-15 21:12:08 +01:00
parent cae62ce7d2
commit a2fcbb4224
Signed by: Jef Roosens
GPG Key ID: B75D4F293C7052DB
8 changed files with 83 additions and 25 deletions

3
.dockerignore 100644
View File

@ -0,0 +1,3 @@
CMakeFiles/
build/
.git/

15
Dockerfile 100644
View File

@ -0,0 +1,15 @@
FROM alpine:3.16.3 AS builder
RUN apk add --update --no-cache \
build-base \
make \
cmake \
boost1.78-static
WORKDIR /app
COPY . ./
RUN make prod && \
strip build/Release/lander && \
[ "$(readelf -d build/Release/lander | grep NEEDED | wc -l)" = 0 ]

View File

@ -4,7 +4,7 @@ SRC_DIR := ./src
TEST_DIR := test TEST_DIR := test
CORES != nproc CORES != nproc
SRCS := $(shell find '$(SRC_DIR)' -iname '*.c') SRCS := $(shell find '$(SRC_DIR)' -iname '*.cpp')
# =====RECIPES===== # =====RECIPES=====
@ -31,7 +31,7 @@ prod: cmake-release
.PHONY: run .PHONY: run
run: build run: build
@ ./build/Debug/lander @ LANDER_API_KEY=test ./build/Debug/lander
.PHONY: clean .PHONY: clean
clean: clean:

View File

@ -4,26 +4,50 @@ extern "C" {
#include "ternarytrie.h" #include "ternarytrie.h"
} }
int main() int main() {
{ // Read in API key
TernaryTrie *trie = ternarytrie_init(); char *api_key = getenv("LANDER_API_KEY");
crow::SimpleApp app; if (api_key == NULL) {
printf("No API key provided.");
return 1;
}
CROW_ROUTE(app, "/<string>").methods(crow::HTTPMethod::Post) TernaryTrie *trie = ternarytrie_init();
([trie](std::string s){
ternarytrie_add(trie, s.c_str());
return "added"; crow::SimpleApp app;
});
CROW_ROUTE(app, "/<string>").methods(crow::HTTPMethod::Get)
([trie](std::string s){
if (ternarytrie_search(trie, s.c_str())) {
return "it's here";
}
return "nope"; CROW_ROUTE(app, "/<string>")
}); .methods(crow::HTTPMethod::Post)(
[api_key, trie](const crow::request &req, std::string s) {
// Authenticate request
std::string provided_api_key = req.get_header_value("X-Api-Key");
app.port(18080).multithreaded().run(); if (strcmp(api_key, provided_api_key.c_str()) != 0) {
return crow::response(crow::status::UNAUTHORIZED);
}
bool res = ternarytrie_add(trie, s.c_str(), req.body.c_str());
if (!res) {
return crow::response(crow::status::CONFLICT);
}
return crow::response(crow::status::NO_CONTENT);
});
CROW_ROUTE(app, "/<string>")
.methods(crow::HTTPMethod::Get)(
[trie](crow::response &res, std::string s) {
char *payload = ternarytrie_search(trie, s.c_str());
if (payload != NULL) {
res.redirect(payload);
} else {
res.code = 404;
}
res.end();
});
app.port(18080).multithreaded().run();
} }

View File

@ -3,10 +3,10 @@ project(ternarytrie C)
set(CMAKE_C_STANDARD 17) set(CMAKE_C_STANDARD 17)
add_library(ternarytrie STATIC src/ternarytrie.c) add_library(ternarytrie STATIC src/ternarytrie.c)
target_include_directories( target_include_directories(
ternarytrie PUBLIC ternarytrie PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
) )
target_compile_options(ternarytrie PRIVATE -O3 -flto)

View File

@ -38,7 +38,7 @@ void ternarytrie_free(TernaryTrie* trie);
* @param string * @param string
* @return true if the string is contained within this trie, false otherwise * @return true if the string is contained within this trie, false otherwise
*/ */
bool ternarytrie_search(TernaryTrie* trie, const char* string); char * ternarytrie_search(TernaryTrie* trie, const char* string);
/** /**
* Add a string to this trie. * Add a string to this trie.
@ -47,7 +47,7 @@ bool ternarytrie_search(TernaryTrie* trie, const char* string);
* @param string * @param string
* @return true if the trie was changed by this operation, false if it was already present * @return true if the trie was changed by this operation, false if it was already present
*/ */
bool ternarytrie_add(TernaryTrie* trie, const char* string); bool ternarytrie_add(TernaryTrie* trie, const char* string, const char *payload);
/** /**
* Remove a string from this trie. * Remove a string from this trie.

View File

@ -94,10 +94,14 @@ SearchResult ternarytrie_search_node(TernaryTrie *trie, const char *string) {
* @param string string to look up * @param string string to look up
* @return true if the string is present in the trie, false otherwise * @return true if the string is present in the trie, false otherwise
*/ */
bool ternarytrie_search(TernaryTrie *trie, const char *string) { char * ternarytrie_search(TernaryTrie *trie, const char *string) {
SearchResult res = ternarytrie_search_node(trie, string); SearchResult res = ternarytrie_search_node(trie, string);
return res.child != NULL; if (res.child != NULL) {
return res.child->payload;
}
return NULL;
} }
/** /**
@ -108,11 +112,12 @@ bool ternarytrie_search(TernaryTrie *trie, const char *string) {
* @return true if the string wasn't present in the trie and thus added, false * @return true if the string wasn't present in the trie and thus added, false
* otherwise * otherwise
*/ */
bool ternarytrie_add(TernaryTrie *trie, const char *string) { bool ternarytrie_add(TernaryTrie *trie, const char *string, const char *payload) {
// Edge case for empty string // Edge case for empty string
if (string[0] == DELIMITER) { if (string[0] == DELIMITER) {
if (trie->root->type == 0) { if (trie->root->type == 0) {
trie->root->type = 1; trie->root->type = 1;
trie->root->payload = my_strdup(payload);
trie->size++; trie->size++;
return true; return true;
@ -159,6 +164,8 @@ bool ternarytrie_add(TernaryTrie *trie, const char *string) {
new_node->type = 1; new_node->type = 1;
} }
new_node->payload = my_strdup(payload);
*node_ptr = new_node; *node_ptr = new_node;
trie->size++; trie->size++;
@ -181,6 +188,7 @@ bool ternarytrie_add(TernaryTrie *trie, const char *string) {
} }
(*node_ptr)->type = 1; (*node_ptr)->type = 1;
(*node_ptr)->payload = my_strdup(payload);
trie->size++; trie->size++;

View File

@ -30,6 +30,7 @@ typedef struct ttnode {
TernaryTrieInnerNode *root; TernaryTrieInnerNode *root;
char *string; char *string;
} ptr; } ptr;
char *payload;
// What type of node this is // What type of node this is
// 0: regular non-representing node // 0: regular non-representing node
// 1: regular representing node // 1: regular representing node
@ -100,6 +101,10 @@ void ttnode_free(TernaryTrieNode *node) {
ttinode_free_cascade(node->ptr.root); ttinode_free_cascade(node->ptr.root);
} }
if (node->payload != NULL) {
free(node->payload);
}
free(node); free(node);
} }
@ -213,8 +218,11 @@ void ttnode_split(TernaryTrieNode *node) {
new_node->type = 1; new_node->type = 1;
} }
new_node->payload = node->payload;
node->type = 0; node->type = 0;
node->size = 0; node->size = 0;
node->payload = NULL;
free(node->ptr.string); free(node->ptr.string);
node->ptr.string = NULL; node->ptr.string = NULL;