Basic working version without persistent storage
							parent
							
								
									cae62ce7d2
								
							
						
					
					
						commit
						a2fcbb4224
					
				|  | @ -0,0 +1,3 @@ | ||||||
|  | CMakeFiles/ | ||||||
|  | build/ | ||||||
|  | .git/ | ||||||
|  | @ -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 ] | ||||||
							
								
								
									
										4
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										4
									
								
								Makefile
								
								
								
								
							|  | @ -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: | ||||||
|  |  | ||||||
							
								
								
									
										58
									
								
								src/main.cpp
								
								
								
								
							
							
						
						
									
										58
									
								
								src/main.cpp
								
								
								
								
							|  | @ -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(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -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) | ||||||
|  |  | ||||||
|  | @ -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. | ||||||
|  |  | ||||||
|  | @ -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++; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue