diff options
Diffstat (limited to 'content/repo_query.js')
-rw-r--r-- | content/repo_query.js | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/content/repo_query.js b/content/repo_query.js new file mode 100644 index 0000000..3708108 --- /dev/null +++ b/content/repo_query.js @@ -0,0 +1,113 @@ +/** + * part of Hachette + * Getting available content for site from remote repositories. + * + * Copyright (C) 2021 Wojtek Kosior + * Redistribution terms are gathered in the `copyright' file. + */ + +/* + * IMPORTS_START + * IMPORT make_ajax_request + * IMPORT observables + * IMPORT TYPE_PREFIX + * IMPORT parse_json_with_schema + * IMPORT matchers + * IMPORTS_END + */ + +const paths = { + [TYPE_PREFIX.PAGE]: "/pattern", + [TYPE_PREFIX.BAG]: "/bag", + [TYPE_PREFIX.SCRIPT]: "/script", + [TYPE_PREFIX.URL]: "/query" +}; + +const queried_items = new Map(); +const observable = observables.make(); + +function repo_query(prefix, item, repo_urls) +{ + const key = prefix + item; + + const results = queried_items.get(key) || {}; + queried_items.set(key, results); + + for (const repo_url of repo_urls) + perform_query_against(key, repo_url, results); +} + +const page_schema = { + pattern: matchers.nonempty_string, + payload: ["optional", matchers.component, "default", undefined] +}; +const bag_schema = { + name: matchers.nonempty_string, + components: ["optional", [matchers.component, "repeat"], "default", []] +}; +const script_schema = { + name: matchers.nonempty_string, + location: matchers.nonempty_string, + sha256: matchers.sha256, +}; +const search_result_schema = [page_schema, "repeat"]; + +const schemas = { + [TYPE_PREFIX.PAGE]: page_schema, + [TYPE_PREFIX.BAG]: bag_schema, + [TYPE_PREFIX.SCRIPT]: script_schema, + [TYPE_PREFIX.URL]: search_result_schema +} + +async function perform_query_against(key, repo_url, results) +{ + if (results[repo_url] !== undefined) + return; + + const prefix = key[0]; + const item = key.substring(1); + const result = {state: "started"}; + results[repo_url] = result; + + const broadcast_msg = {prefix, item, results: {[repo_url]: result}}; + observables.broadcast(observable, broadcast_msg); + + let state = "connection_error"; + const query_url = + `${repo_url}${paths[prefix]}?n=${encodeURIComponent(item)}`; + + try { + let xhttp = await make_ajax_request("GET", query_url); + if (xhttp.status === 200) { + state = "parse_error"; + result.response = + parse_json_with_schema(schemas[prefix], xhttp.responseText); + state = "completed"; + } + } catch (e) { + console.log(e); + } + + result.state = state; + observables.broadcast(observable, broadcast_msg); +} + +function subscribe_repo_query_results(cb) +{ + observables.subscribe(observable, cb); + for (const [key, results] of queried_items.entries()) + cb({prefix: key[0], item: key.substring(1), results}); +} + +function unsubscribe_repo_query_results(cb) +{ + observables.unsubscribe(observable, cb); +} + +/* + * EXPORTS_START + * EXPORT repo_query + * EXPORT subscribe_repo_query_results + * EXPORT unsubscribe_repo_query_results + * EXPORTS_END + */ |