commit d5af38ccfe6c94218f4d7ab8d6aaf382e7dede80 from: Omar Polo date: Mon Jan 10 23:24:17 2022 UTC add an in-memory cache store see github issue #1 commit - 993a25fc802b17b5bdbb938e8f0d7f5332ada6eb commit + d5af38ccfe6c94218f4d7ab8d6aaf382e7dede80 blob - /dev/null blob + aa3e2186e09bffc8a9dab0eaaa5367afee2de12e (mode 644) --- /dev/null +++ mcache.c @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2022 Omar Polo + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "compat.h" + +#include +#include +#include + +#include "telescope.h" +#include "mcache.h" + +const char *gemtext_prefixes[] = { + [LINE_TEXT] = "", + [LINE_TITLE_1] = "# ", + [LINE_TITLE_2] = "## ", + [LINE_TITLE_3] = "### ", + [LINE_ITEM] = "* ", + [LINE_QUOTE] = "> ", + [LINE_PRE_START] = "``` ", + [LINE_PRE_CONTENT] = "", + [LINE_PRE_END] = "```", +}; + +struct mcache { + struct ohash h; + size_t tot; +} mcache; + +struct mcache_entry { + int trust; + struct evbuffer *evb; + char url[]; +}; + +static void *hash_alloc(size_t, void *); +static void *hash_calloc(size_t, size_t, void *); +static void hash_free(void *, void *); + +static void * +hash_alloc(size_t len, void *d) +{ + if ((d = malloc(len)) == NULL) + abort(); + return d; +} + +static void * +hash_calloc(size_t nmemb, size_t size, void *d) +{ + if ((d = calloc(nmemb, size)) == NULL) + abort(); + return d; +} + +static void +hash_free(void *ptr, void *d) +{ + free(ptr); +} + +void +mcache_init(void) +{ + struct ohash_info info = { + .key_offset = offsetof(struct mcache_entry, url), + .calloc = hash_calloc, + .free = hash_free, + .alloc = hash_alloc, + }; + + ohash_init(&mcache.h, 5, &info); +} + +int +mcache_buffer(const char *url, struct buffer *buf, int trust) +{ + struct mcache_entry *e; + struct line *line; + unsigned int slot; + size_t l, len; + + l = strlen(url); + len = sizeof(*e) + l + 1; + + if ((e = calloc(1, len)) == NULL) + return -1; + e->trust = trust; + memcpy(e->url, url, l); + + if ((e->evb = evbuffer_new()) == NULL) + goto err; + + TAILQ_FOREACH(line, &buf->page.head, lines) { + const char *text, *alt; + int r; + + if ((text = line->line) == NULL) + text = ""; + + if ((alt = line->alt) == NULL) + alt = ""; + + switch (line->type) { + case LINE_TEXT: + case LINE_TITLE_1: + case LINE_TITLE_2: + case LINE_TITLE_3: + case LINE_ITEM: + case LINE_QUOTE: + case LINE_PRE_START: + case LINE_PRE_CONTENT: + case LINE_PRE_END: + r = evbuffer_add_printf(e->evb, "%s%s\n", + gemtext_prefixes[line->type], text); + break; + + case LINE_LINK: + r = evbuffer_add_printf(e->evb, "=> %s %s\n", + alt, text); + break; + + case LINE_PATCH: + case LINE_PATCH_HDR: + case LINE_PATCH_HUNK_HDR: + case LINE_PATCH_ADD: + case LINE_PATCH_DEL: + /* TODO */ + r = -1; + break; + + case LINE_COMPL: + case LINE_COMPL_CURRENT: + case LINE_HELP: + case LINE_DOWNLOAD: + case LINE_DOWNLOAD_DONE: + case LINE_DOWNLOAD_INFO: + case LINE_FRINGE: + /* not reached */ + abort(); + } + + if (r == -1) + goto err; + } + + slot = ohash_qlookup(&mcache.h, url); + ohash_insert(&mcache.h, slot, e); + return 0; + +err: + if (e->evb != NULL) + evbuffer_free(e->evb); + free(e); + return -1; +} + +int +mcache_lookup(const char *url, struct evbuffer **ret, int *trust) +{ + struct mcache_entry *e; + unsigned int slot; + + slot = ohash_qlookup(&mcache.h, url); + if ((e = ohash_find(&mcache.h, slot)) == NULL) + return 0; + + *ret = e->evb; + *trust = e->trust; + return 1; +} blob - /dev/null blob + 0542e67d232dce7f2d73b304bcefa4b8d15614bc (mode 644) --- /dev/null +++ mcache.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2022 Omar Polo + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MCACHE_H +#define MCACHE_H + +struct buffer; + +void mcache_init(void); +int mcache_buffer(const char *, struct buffer *, int); +int mcache_lookup(const char *, struct evbuffer **, int *); + +#endif blob - 264dc170274cd609fe4ad1980614eda5c06e3937 blob + 45a5eddc18a58ecc1515cedb0d163a95d78f8d60 --- telescope.c +++ telescope.c @@ -29,6 +29,7 @@ #include "defaults.h" #include "fs.h" +#include "mcache.h" #include "minibuffer.h" #include "parser.h" #include "session.h" @@ -605,6 +606,7 @@ handle_imsg_eof(struct imsg *imsg, size_t datalen) if (tab != NULL) { if (!parser_free(tab)) die(); + mcache_buffer(tab->hist_cur->h, &tab->buffer, tab->trust); ui_on_tab_refresh(tab); ui_on_tab_loaded(tab); } else { @@ -888,6 +890,30 @@ gopher_send_search_req(struct tab *tab, const char *te parser_init(tab, gophermap_initparser); make_request(tab, &req, PROTO_GOPHER, NULL); +} + +static int +try_load_cache(struct tab *tab) +{ + struct evbuffer *evb; + int trust; + + if (!mcache_lookup(tab->hist_cur->h, &evb, &trust)) + return 0; + + parser_init(tab, gemtext_initparser); + if (!parser_parse(tab, EVBUFFER_DATA(evb), EVBUFFER_LENGTH(evb))) + goto err; + parser_free(tab); + tab->trust = trust; + ui_on_tab_refresh(tab); + ui_on_tab_loaded(tab); + return 1; + +err: + parser_free(tab); + erase_buffer(&tab->buffer); + return 0; } /* @@ -926,6 +952,9 @@ do_load_url(struct tab *tab, const char *url, const ch phos_serialize_uri(&tab->uri, tab->hist_cur->h, sizeof(tab->hist_cur->h)); + if (try_load_cache(tab)) + return 0; + for (p = protos; p->schema != NULL; ++p) { if (!strcmp(tab->uri.scheme, p->schema)) { /* patch the port */ @@ -1249,6 +1278,9 @@ main(int argc, char * const *argv) event_init(); + /* initialize the in-memory cache store */ + mcache_init(); + /* Setup event handler for the autosave */ autosave_init();