Skip to content

Instantly share code, notes, and snippets.

@creationix
Last active October 14, 2017 05:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save creationix/7e221bd3d627db310f4353e44b2cd7a9 to your computer and use it in GitHub Desktop.
Save creationix/7e221bd3d627db310f4353e44b2cd7a9 to your computer and use it in GitHub Desktop.
WIP service worker that serves a dat as http responses.
/* 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