diff --git a/mainline_http_script.js b/mainline_http_script.js deleted file mode 100644 index 5f0091c..0000000 --- a/mainline_http_script.js +++ /dev/null @@ -1,637 +0,0 @@ -function prepend(elem, children) { - var child = elem.firstChild; - - if (child) { - elem.insertBefore(children, child); - } else { - elem.appendChild(children); - } -} - - -function _log() { - for (var arg of arguments) { - var pre = document.createElement('pre'); - pre.appendChild(text(arg.toString())); - document.body.appendChild(pre); - try { - prepend(document.body, pre); - } catch (e) { - var pre = document.createElement('pre'); - pre.appendChild(text(e.toString())); - document.body.appendChild(pre); - } - - } -} - -/* -var console = { - log: _log, - error: _log -}; -*/ - -var CurrentScore = null; - -var global_elements; -var GlobalElemSelectors = - [ 'style' - , 'style.loading' - , '.info' - ] - -var pageInfoText; - -var GlobalCancellableEvents = []; -var cancel = GlobalCancellableEvents.push.bind(GlobalCancellableEvents); - -/** - * Router - */ - -// [ fpart : next ], content -function RoutePart(fparts, content) { - return { - fparts, - content - } -} - -function iter(iarray) { - var i = 0; - - return function (f, g) { - console.log(i, iarray.length, iarray); - if (i < iarray.length) { - console.log("calling", f, "with", iarray[i]); - f(iarray[i++]); - } else { - console.log("calling", g); - g(); - } - } -} - -function resolvePath(routes, path, query_params) { - console.log("resolvePath:", arguments); - var next = iter(path); - - function goRoute(path_data, route_part, path_part) { - var found = false; - - console.log(arguments); - for (var [fpart, next_route_part] of route_part.fparts) { - var parsed_part = fpart(path_part); - - if (parsed_part) { - console.log("parsed part:", parsed_part); - path_data.push(parsed_part); - - next( - goRoute.bind(this, path_data, next_route_part), - resolve.bind(this, path_data, next_route_part) - ); - - found = true; - } - } - - if (!found) { - throw new Error("404 " + path_data.join('/') + '/' + path_part); - } - } - - function resolve(path_data, route_part) { - console.log('calling content'); - console.log(path_data, route_part); - route_part.content(path_data, query_params); - } - - var p = []; - next(goRoute.bind(this, p, routes), resolve.bind(this, p, routes)); -} - -function match(re) { - return function (s) { - if (re.test(s)) { - return s; - } - } -} - -var ROUTES = RoutePart([ - [match(/^s$/), new RoutePart([], handleSearch)], - [match(/^[a-f0-9]{40}$/), new RoutePart([], handleInfo)] -], loadTop); - -/** - * Functions - */ - -function resolveResponse(resolve, reject) { - return function(e) { - var status = e.target.getResponseHeader("Status"); - if (status != null) { - var status_code = Number(status.split(" ")[0]); - if (status_code >= 200 && status_code < 300) { - resolve(e.target.responseText); - } else { - reject(new Error('API responded with ' + status)); - } - } else { - if (e.target.status >= 200 && e.target.status < 300) { - return resolve(e.target.responseText); - } else { - reject(new Error('API responded with ' + e.target.status)); - } - } - } -} - -function cancelGlobalEvts() { - while (GlobalCancellableEvents.length) { - GlobalCancellableEvents.pop().abort(); - } -} - -function get(url, xhr_req_follower) { - return new Promise(function (resolve, reject) { - var req = new XMLHttpRequest(); - xhr_req_follower(req); - req.onload = resolveResponse(resolve, reject); - req.onerror = reject; - req.open('GET', url); - req.send(); - }); -} - -var HexArray = "0123456789abcdef"; - -function bytesToHex(uint8arr) { - var hex_encoded = ""; - - for (var i=0; i < uint8arr.length; i++) { - var j = uint8arr[i] & 0xFF; - hex_encoded += HexArray[j >>> 4]; - hex_encoded += HexArray[j & 0x0F]; - } - - return hex_encoded; -} - -var ESC_STR = '$ESCAPE_PIPE_SYMBOL'; - -function splitRawRow(raw_row) { - return raw_row - .replace('\\|', ESC_STR) - .split('|') - .map(function(s) { - return s.replace(ESC_STR, '|') - .trim(); - }) -} - -function parseTable(results) { - var raw_rows = results.split('\n').slice(0, -1); - var headers = splitRawRow(raw_rows[0]); - - return raw_rows.slice(2, -1) - .map(splitRawRow) - .map(function(row) { - return row.reduce(function(acc, val, i) { - acc[headers[i]] = val; - return acc; - }, - {}); - }) -} - - -function parseFilePath(s) { - return JSON.parse(s); -} - -function FileSize(s) { - this.filesize = s; -} - -function tree(rows) { - var c = {}; - - for (var row of rows) { - var path = parseFilePath(row.path); - var tree = c; - var previous = c; - var filename = 'NOPATH'; - - for (var p of path) { - previous = tree; - - if (p in tree) { - tree = tree[p]; - } else { - var newtree = {}; - tree[p] = newtree; - tree = newtree; - } - - filename = p; - } - - previous[filename] = new FileSize(row.filesize); - } - - console.log(c); - return c; -} - -function renderTree(rows) { - var list_elem = ul(); - - function draw(list_elem, t) { - Object.entries(t) - .forEach(function([key, val]) { - if (val instanceof FileSize) { - var contents = div(span(text(key))); - contents.appendChild(italic(text(val.filesize))); - list_elem.appendChild(contents); - } else { - var new_list = ul(); - var elem = li(text(key)); - elem.appendChild(new_list); - list_elem.appendChild(elem); - draw(new_list, val); - } - }); - } - - draw(list_elem, tree(rows)); - - return list_elem; -} - -function assembleTable(rows) { - var t = document.createElement('table'); - - rows.forEach(function(r) { - var row = t.insertRow(); - - TableHeadings.forEach(function(header) { - var cell = row.insertCell(); - - cell.appendChild(header[1](r)); - }); - }); - - var thead = t.createTHead().insertRow(); - - TableHeadingNames.forEach(function(header) { - var th = document.createElement('th'); - - th.appendChild(text(header)); - thead.appendChild(th); - }); - - var countElem = div(text(rows.length + ' rows')) - - var wrapper = div(); - wrapper.appendChild(t); - wrapper.appendChild(countElem); - - return wrapper; -} - -function text(s) { - return document.createTextNode(s); -} - -function _mkelem(etype, child) { - var elem = document.createElement(etype); - - if (child) { - elem.appendChild(child); - } - - return elem; -} - -var div = _mkelem.bind(this, 'div'); -var li = _mkelem.bind(this, 'li'); -var span = _mkelem.bind(this, 'span'); -var italic = _mkelem.bind(this, 'i'); -var bold = _mkelem.bind(this, 'b'); -var ul = document.createElement.bind(document, 'ul'); - -function magnetLinkHash(m) { - return m.split(':').slice(-1)[0]; -} - -function name(r) { - var info_hash = magnetLinkHash(r.magnet); - var a = document.createElement('a'); - a.href = window.location.origin + - '/' + info_hash + '?dn=' + encodeURIComponent(r.name.slice(0, 75)); - a.addEventListener('click', aClickNav); - a.appendChild(text(r.name)); - - return a; -} - -function magnet(r) { - var a = document.createElement('a'); - - a.href = r.magnet + '&dn=' + encodeURIComponent(r.name.slice(0, 75)); - a.appendChild(text(String.fromCodePoint(129522) + ':?xt')); - - return a; -} - -/* -calculateScore :: Int -> POSIXTime -> Double -calculateScore n t = (e ** ((log maxDbl / endt) * (x - t0)) - 1) * (fromIntegral n) - where - maxDbl = 10 ** 300 - t0 = 1572391617 - endt = t0 + (1.577 * 10**10) - x = realToFrac t - e = exp 1 - -inverseScore :: Double -> Integer -inverseScore score = round $ ((log (score + 1)) / (log maxDbl / endt) + t0) - where - maxDbl = 10 ** 300 - t0 = 1572391617 - endt = t0 + (1.577 * 10**10) -*/ - -function currentScore() { - var t0 = 1572391617; - var x = Date.now() / 1000; - var endt = t0 + (1.577 * 10**10) - - return Math.E ** ((Math.log(10 ** 300) / endt) * ((x - t0) - 1)) -} - -function score(r) { - score = Number(r.score); - return text((Math.log(score / CurrentScore)).toFixed(2)); -} - -function invertScore(score) { - var t0 = 1572391617; - var maxDbl = 10 ** 300 - var endt = t0 + (1.577 * 10 ** 10) - return Math.round((Math.log(score + 1) / (Math.log(maxDbl) / endt)) + t0); -} - -var TableHeadings = - [ ['Name', name ] - , ['Size', function(r) { return text(r.total_size) }] - , ['Files', function(r) { return text(r.filecount) }] - , ['', magnet] - , ['Score', score] - ]; - -var TableHeadingNames = TableHeadings.map(function(t){ return t[0]; }); - -function keepElements(elem_selectors) { - var document_root = document.querySelector('p'); - document_root.innerHTML = ''; - - for (var i=0; i < elem_selectors.length; i++) { - var sel = elem_selectors[i]; - var elem = global_elements[sel]; - - document_root.appendChild(elem); - } -} - -function ensureElementExist(selector) { - var document_root = document.querySelector('p'); - var elem = document_root.querySelector(selector); - - if (!elem) { - document_root.appendChild(global_elements[selector]); - } - -} - -function loadTop() { - //TODO: dispatch changeurl event - cancelGlobalEvts(); - ensureElementExist('style.loading'); - pageInfoText.innerText = 'Loading Top 100...'; - get('/cgi-bin/top_100', cancel) - .then(function(response) { - CurrentScore = currentScore(); - console.log("Current score:", CurrentScore); - - var document_root = document.querySelector('p'); - var t = parseTable(response); - console.log(t); - keepElements(['style', '.info']); - pageInfoText.innerText = 'Top 100'; - document_root.appendChild(assembleTable(t)); - }) - .catch(caught.bind(this, "Failed to load top 100: ")); -} - -function caught(m, e) { - console.error(m); - console.error(e); - alert(new Error(m + e.message)); -}; - -function loadInfo(info_hash) { - var preLoad_executed = false; - var page = document.createElement('div'); - - function preLoad() { - if (preLoad_executed) { - return; - } - - preLoad_executed = true; - keepElements(['style', '.info']); - pageInfoText.innerText = info_hash; - document.querySelector('p').appendChild(page); - } - - ensureElementExist('style.loading'); - pageInfoText.innerText = 'Loading info for ' + info_hash; - - cancelGlobalEvts(); - - get('/cgi-bin/files?i=' + info_hash, cancel) - .then(function(response) { - preLoad(); - var files = parseTable(response); - console.log(files); - var h = document.createElement('h2'); - h.innerText = 'Contents'; - page.appendChild(h); - var t = renderTree(files); - page.appendChild(t); - }) - .catch(caught.bind(this, "Failed to info details. Reason:")); - - get('/cgi-bin/info?i=' + info_hash, cancel) - .then(function(response) { - preLoad(); - var info = parseTable(response)[0]; - pageInfoText.innerText = info.name; - var first_seen = new Date(info.added.split('.')[0]+'Z'); - var mlink = magnet(info); - mlink.innerText = mlink.href; - - var last_seen = new Date(Math.min( - invertScore(Number(info.score)) * 1000, - new Date().getTime()) - ); - - prepend(page, div(text('First Indexed: ' + first_seen))); - prepend(page, div(text('Approximately last seen: ' + last_seen))); - var filecount = div(text('Files: ')); - filecount.appendChild(bold(text(info.filecount))) - prepend(page, filecount); - var total_size = div(text('Total Size: ')); - total_size.appendChild(bold(text(info.total_size))) - prepend(page, total_size); - prepend(page, div(mlink)); - }) - .catch(caught.bind(this, "Failed to load file list. Details:")); -} - -function loadResults(search_query) { - var encoder = new TextEncoder(); - var hex = bytesToHex(encoder.encode(search_query)); - console.log(hex); - cancelGlobalEvts(); - ensureElementExist('style.loading'); - pageInfoText.innerText = 'Loading results for "' + search_query + '"...'; - get('/cgi-bin/search?q=' + hex, cancel) - .then(function(response) { - CurrentScore = currentScore(); - console.log("Current score:", CurrentScore); - - var t = assembleTable(parseTable(response)); - var document_root = document.querySelector('p'); - - keepElements(['style', '.info']) - pageInfoText.innerText = 'Results for "' + search_query + '"'; - document_root.appendChild(t); - }) - .catch(caught.bind(this, "Failed to results: ")); -} - -function changeUrl(path, search_query) { - var event = new CustomEvent( - 'urlchange', - { - detail: { - path: path, - query: search_query - } - }); - - window.dispatchEvent(event); -} - -function searchInputHandler() { - var input = document.querySelector("input"); - var btn = document.querySelector("button"); - - btn.addEventListener('click', function() { - var search_query = input.value; - window.history.pushState(null, "", - window.location.origin + - '/s?q=' + encodeURIComponent(search_query)); - changeUrl('/s', { q: search_query }); - }); - - input.addEventListener('keydown', function(e) { - if (e.keyCode === 13) { - e.preventDefault(); - btn.click(); - } - }); -} - -function handleSearch(_, query_params) { - var search_query = query_params.q; - - if (!search_query) { - console.log("nothing to query"); - return; - } else { - console.log(search_query); - loadResults(search_query); - } -} - -function handleInfo(parts, query_params) { - console.log('info request', parts, query_params); - loadInfo(parts[0]); -} - -function onUrlChange(e) { - var path = e.detail.path.split('/').filter(function(s){ return s.length; }); - console.log(e, e.detail, path); - resolvePath(ROUTES, path, e.detail.query); -} - -function aClickNav(e) { - e.preventDefault(); - e.stopPropagation(); - console.log(this, this.href); - window.history.pushState(null, "", this.href); - onRealUrlChange(); -} - -function bindEventHandlers() { - window.addEventListener('urlchange', onUrlChange); - window.addEventListener('popstate', onRealUrlChange); -} - -function gatherElements() { - global_elements = {}; - var qs; - - for (var i=0; i < GlobalElemSelectors.length; i++) { - var sel = GlobalElemSelectors[i]; - var elem = document.querySelector(sel); - global_elements[sel] = elem; - } -} - -function parseQueryParams(querystring) { - return querystring.split('&') - .map(function(part) { - return part.split('=').map(decodeURIComponent); - }) - .reduce(function(acc, pair) { return { [pair[0]]: pair[1] } }, {}); -} - -function onRealUrlChange() { - var path = window.location.pathname; - var query_params = parseQueryParams(window.location.search.substring(1)); - changeUrl(path, query_params); -} - -function initPageInfoText() { - pageInfoText = document.createElement('div'); - pageInfoText.className = 'info'; - prepend(document.querySelector('p'), pageInfoText); -} - -/** - * Init - */ - -initPageInfoText(); -gatherElements(); -bindEventHandlers(); -searchInputHandler(); -onRealUrlChange(); -