aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfrosty <gabriel@bwaaa.monster>2026-03-10 07:18:53 -0400
committerfrosty <gabriel@bwaaa.monster>2026-03-10 07:18:53 -0400
commitab7244b0f7c7dd5d268a9b5520d28770988f22e7 (patch)
tree4c5cdda98d1bb35e89decf15c67079b745eb586b
parente33310f26351e25fda718a353f8b8e9ece0007b5 (diff)
downloadomnisearch-ab7244b0f7c7dd5d268a9b5520d28770988f22e7.tar.gz
fix: didn't add cache folder in last commitindev
-rw-r--r--src/Cache/Cache.c205
-rw-r--r--src/Cache/Cache.h23
2 files changed, 228 insertions, 0 deletions
diff --git a/src/Cache/Cache.c b/src/Cache/Cache.c
new file mode 100644
index 0000000..59d0ed4
--- /dev/null
+++ b/src/Cache/Cache.c
@@ -0,0 +1,205 @@
+#include "Cache.h"
+#include <dirent.h>
+#include <openssl/evp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <time.h>
+
+static char cache_dir[512] = {0};
+static int cache_ttl_search_val = 3600;
+static int cache_ttl_infobox_val = 86400;
+
+void set_cache_ttl_search(int ttl) { cache_ttl_search_val = ttl; }
+
+void set_cache_ttl_infobox(int ttl) { cache_ttl_infobox_val = ttl; }
+
+int get_cache_ttl_search(void) { return cache_ttl_search_val; }
+
+int get_cache_ttl_infobox(void) { return cache_ttl_infobox_val; }
+
+static void md5_hash(const char *str, char *output) {
+ unsigned char hash[EVP_MAX_MD_SIZE];
+ unsigned int hash_len;
+ EVP_MD_CTX *ctx = EVP_MD_CTX_new();
+ if (!ctx)
+ return;
+ EVP_DigestInit_ex(ctx, EVP_md5(), NULL);
+ EVP_DigestUpdate(ctx, str, strlen(str));
+ EVP_DigestFinal_ex(ctx, hash, &hash_len);
+ EVP_MD_CTX_free(ctx);
+ for (unsigned int i = 0; i < hash_len; i++) {
+ sprintf(output + (i * 2), "%02x", hash[i]);
+ }
+}
+
+static time_t get_file_mtime(const char *filepath) {
+ struct stat st;
+ if (stat(filepath, &st) == 0) {
+ return st.st_mtime;
+ }
+ return 0;
+}
+
+int cache_init(const char *dir) {
+ if (!dir || strlen(dir) == 0) {
+ strcpy(cache_dir, "/tmp/omnisearch_cache");
+ } else {
+ strncpy(cache_dir, dir, sizeof(cache_dir) - 1);
+ cache_dir[sizeof(cache_dir) - 1] = '\0';
+ }
+
+ struct stat st;
+ if (stat(cache_dir, &st) != 0) {
+ if (mkdir(cache_dir, 0755) != 0) {
+ fprintf(stderr, "Failed to create cache directory: %s\n", cache_dir);
+ return -1;
+ }
+ } else if (!S_ISDIR(st.st_mode)) {
+ fprintf(stderr, "Cache path exists but is not a directory: %s\n",
+ cache_dir);
+ return -1;
+ }
+
+ char subdirs[] = "0123456789abcdef";
+ for (int i = 0; subdirs[i]; i++) {
+ char subdir_path[1024];
+ snprintf(subdir_path, sizeof(subdir_path), "%s/%c", cache_dir, subdirs[i]);
+ if (stat(subdir_path, &st) != 0) {
+ mkdir(subdir_path, 0755);
+ }
+ }
+
+ return 0;
+}
+
+void cache_shutdown(void) { cache_dir[0] = '\0'; }
+
+char *cache_compute_key(const char *query, int page, const char *engine_name) {
+ char key_buffer[1024];
+ snprintf(key_buffer, sizeof(key_buffer), "%s_%d_%s", query ? query : "", page,
+ engine_name ? engine_name : "");
+
+ char *hash = malloc(33);
+ if (!hash) {
+ return NULL;
+ }
+ md5_hash(key_buffer, hash);
+ return hash;
+}
+
+int cache_get(const char *key, time_t max_age, char **out_data,
+ size_t *out_size) {
+ if (!key || !out_data || !out_size || cache_dir[0] == '\0') {
+ return -1;
+ }
+
+ char filepath[1024];
+ snprintf(filepath, sizeof(filepath), "%s/%c/%s.cache", cache_dir, key[0],
+ key);
+
+ time_t file_mtime = get_file_mtime(filepath);
+ if (file_mtime == 0) {
+ return -1;
+ }
+
+ time_t now = time(NULL);
+ if (max_age > 0 && (now - file_mtime) > max_age) {
+ remove(filepath);
+ return -1;
+ }
+
+ FILE *fp = fopen(filepath, "rb");
+ if (!fp) {
+ return -1;
+ }
+
+ fseek(fp, 0, SEEK_END);
+ long size = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+
+ if (size <= 0) {
+ fclose(fp);
+ return -1;
+ }
+
+ char *data = malloc(size + 1);
+ if (!data) {
+ fclose(fp);
+ return -1;
+ }
+
+ size_t read_size = fread(data, 1, size, fp);
+ fclose(fp);
+
+ if (read_size != (size_t)size) {
+ free(data);
+ return -1;
+ }
+
+ data[size] = '\0';
+ *out_data = data;
+ *out_size = size;
+ return 0;
+}
+
+int cache_set(const char *key, const char *data, size_t size) {
+ if (!key || !data || size == 0 || cache_dir[0] == '\0') {
+ return -1;
+ }
+
+ char filepath[1024];
+ snprintf(filepath, sizeof(filepath), "%s/%c/%s.cache", cache_dir, key[0],
+ key);
+
+ FILE *fp = fopen(filepath, "wb");
+ if (!fp) {
+ return -1;
+ }
+
+ size_t written = fwrite(data, 1, size, fp);
+ fclose(fp);
+
+ if (written != size) {
+ remove(filepath);
+ return -1;
+ }
+
+ return 0;
+}
+
+void cache_cleanup(time_t max_age) {
+ if (cache_dir[0] == '\0' || max_age <= 0) {
+ return;
+ }
+
+ time_t now = time(NULL);
+ time_t cutoff = now - max_age;
+ char subdirs[] = "0123456789abcdef";
+
+ for (int d = 0; subdirs[d]; d++) {
+ char subdir_path[1024];
+ snprintf(subdir_path, sizeof(subdir_path), "%s/%c", cache_dir, subdirs[d]);
+
+ DIR *dir = opendir(subdir_path);
+ if (!dir)
+ continue;
+
+ struct dirent *entry;
+ while ((entry = readdir(dir)) != NULL) {
+ size_t len = strlen(entry->d_name);
+ if (len > 7 && strcmp(entry->d_name + len - 7, ".cache") == 0) {
+ char filepath[2048];
+ snprintf(filepath, sizeof(filepath), "%s/%s", subdir_path,
+ entry->d_name);
+
+ struct stat st;
+ if (stat(filepath, &st) == 0 && st.st_mtime < cutoff) {
+ remove(filepath);
+ }
+ }
+ }
+ closedir(dir);
+ }
+}
diff --git a/src/Cache/Cache.h b/src/Cache/Cache.h
new file mode 100644
index 0000000..0a84406
--- /dev/null
+++ b/src/Cache/Cache.h
@@ -0,0 +1,23 @@
+#ifndef CACHE_H
+#define CACHE_H
+
+#include <stddef.h>
+#include <time.h>
+
+int cache_init(const char *cache_dir);
+void cache_shutdown(void);
+
+int cache_get(const char *key, time_t max_age, char **out_data,
+ size_t *out_size);
+int cache_set(const char *key, const char *data, size_t size);
+
+void cache_cleanup(time_t max_age);
+
+char *cache_compute_key(const char *query, int page, const char *engine_name);
+
+void set_cache_ttl_search(int ttl);
+void set_cache_ttl_infobox(int ttl);
+int get_cache_ttl_search(void);
+int get_cache_ttl_infobox(void);
+
+#endif