Last active
October 14, 2017 05:59
-
-
Save creationix/7e221bd3d627db310f4353e44b2cd7a9 to your computer and use it in GitHub Desktop.
WIP service worker that serves a dat as http responses.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-env serviceworker */ | |
/* global fetch, ReadableStream, Response */ | |
// Tweak so internal crypto stuff can find `window.crypto` | |
window = self | |
const hyperdrive = require('hyperdrive') | |
const websocket = require('websocket-stream') | |
const ram = require('random-access-memory') | |
const { E, M } = require('promisey') | |
const mime = require('mime') | |
let storage = name => ram() | |
let feeds = { | |
Movies: '75105ac94136ceaded97bac2f78273c6925aafd6ef6d8bcdcc5ca99d6e5f0e66', | |
Music: '9d7d41b19a33003f2703ded94f6bf6e1645df56cce82352663cdc6f14110015d', | |
ISOs: '1eb828a5eddfd6f84fb0d40cd217071798c5ff8a92ce9606b0551d312a31aa1e' | |
} | |
let archive = hyperdrive(storage, feeds.Music, {sparse: true, sparseMetadata: true}) | |
let ready = false | |
archive.on('ready', () => { | |
let ws = websocket('ws://localhost:9000/') | |
ws.pipe(archive.replicate()).pipe(ws) | |
archive.metadata.update(() => { | |
ready = true | |
}) | |
}) | |
self.addEventListener('activate', evt => { | |
evt.waitUntil(self.clients.claim()) | |
}) | |
function rangeParse (str, size) { | |
if (!str) return [0, size] | |
let match = str.match(/bytes=(.*)-(.*)/) | |
if (!match) return [0, size] | |
let start = match[1] ? parseInt(match[1], 10) : 0 | |
let end = match[2] ? parseInt(match[2], 10) : size | |
return [start, end] | |
} | |
let stats = {} | |
self.addEventListener('fetch', evt => { | |
return evt.respondWith(async function () { | |
let match = evt.request.url.match(/\/dat\/(.*)/) | |
if (!ready || !match) return fetch(evt.request) | |
let path = unescape(match[1]) | |
console.log(path) | |
let stat = stats[path] | |
if (!stat) { | |
stat = stats[path] = await M(archive, 'stat', path) | |
} | |
if (stat.isFile()) { | |
let rangeHeader = evt.request.headers.get('Range') | |
let [start, end] = rangeParse(rangeHeader, stat.size) | |
let stream = archive.createReadStream(path, {start, end}) | |
async function pull (controller) { | |
let chunk = stream.read() | |
if (!chunk) { | |
await E(stream, 'readable') | |
chunk = stream.read() | |
} | |
if (chunk) controller.enqueue(chunk) | |
else controller.close() | |
} | |
let body = new ReadableStream({ start: pull, pull }) | |
let status = 200 | |
let headers = { | |
'Content-Type': mime.getType(match[1]), | |
'Content-Length': stat.size | |
} | |
if (rangeHeader) { | |
status = 206 | |
headers['Content-Range'] = `bytes ${start}-${end - 1}/${stat.size}` | |
headers['Content-Length'] = end - start | |
} else { | |
headers['Accept-Ranges'] = 'bytes' | |
} | |
return new Response(body, { status, headers }) | |
} | |
// if (!entry) { | |
// return new Response('No such file in database: ' + match[1] + '\n', { | |
// status: 404, | |
// headers: { 'Content-Type': 'text/plain' } | |
// }) | |
// } | |
// | |
}()) | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment