Service worker for intercepting URLs and loading them from IPFS.

This commit is contained in:
Dan 2017-12-20 21:21:49 -08:00
parent 9b998a6318
commit acc7964f0e
4 changed files with 33 additions and 79 deletions

View File

@ -4,6 +4,6 @@
<style type="text/css">body {margin: 0}</style> <style type="text/css">body {margin: 0}</style>
</head> </head>
<body> <body>
<script type="text/javascript" src="/dist/bundle.js"></script> <script type="text/javascript" src="/bundle.js"></script>
</body> </body>
</html> </html>

View File

@ -17,6 +17,6 @@
"webpack-dev-server": "^2.4.5" "webpack-dev-server": "^2.4.5"
}, },
"dependencies": { "dependencies": {
"ipfs": "0.27.3" "ipfs": "0.27.1"
} }
} }

View File

@ -3,77 +3,22 @@
const IPFS = require('ipfs') const IPFS = require('ipfs')
function materialize_references_to_ipfs_content(node, element) {
// Given an IPFS node and a DOM element with a relevant attribute referring to content on IPFS,
// load that content and set it into the attribute as a blob.
//
// Return a promise for doing all of that.
for (let attribute_name of ['content', 'href', 'src', 'style']) {
let attribute_value = element.getAttribute(attribute_name)
if (attribute_value && attribute_value.includes('./')) {
let base_hash = window.location.pathname.match(/(^\/ipfs\/\w+)/)[1]
let anchor = document.createElement('a')
let relative_url = attribute_value.match(/(.\/[^)]*)/)[1] // Match "./foo/bar/baz"
anchor.href = base_hash + relative_url.slice(1)
console.log('loading IPFS sub-content for ' + anchor.pathname)
return node.files.cat(anchor.pathname).then(function (contents_buffer) {
let materialized_value = attribute_value.replace(
relative_url,
URL.createObjectURL(new Blob([contents_buffer]))
)
element.setAttribute(attribute_name, materialized_value)
})
}
}
}
function App() { function App() {
let node let node
create() create()
function create() { function create() {
node = new IPFS({ // TODO: After initial registration, trigger a fetch event for the page in the service worker.
config: { if ('serviceWorker' in navigator) {
Addresses: { navigator.serviceWorker.register('/fetcher.js')
Swarm: [ .then((registration) => {
// '/dns4/wrtc-star.discovery.libp2p.io/tcp/443/wss/p2p-websocket-star' console.log('Registered the service worker successfully')
]
}
}
})
node.on('ready', () => {
console.log('IPFS node is ready')
console.log('loading IPFS content for ' + window.location.pathname)
// Load the page contents for the IPFS hash.
node.files.cat(window.location.pathname)
.then(function (contents_buffer) {
let iframe = document.createElement('iframe')
iframe.style = 'width: 100%; height: 100%; border: 0; overflow: hidden'
// TODO: Should only do this if it's actually an HTML document. Need to gracefully skip this for other content types.
let contents_document = new DOMParser().parseFromString(contents_buffer.toString(), 'text/html')
let elements = contents_document.querySelectorAll('div,link,meta,script')
let promises = []
for (let element of elements) {
promises.push(materialize_references_to_ipfs_content(node, element))
}
Promise.all(promises).then(function () {
iframe.src = URL.createObjectURL(
new Blob([contents_document.documentElement.innerHTML])
)
document.body.appendChild(iframe)
})
}) })
}) .catch((err) => {
console.log('Failed to register:', err)
})
}
} }
} }

View File

@ -2,27 +2,36 @@
var path = require('path') var path = require('path')
var webpack = require('webpack') var webpack = require('webpack')
const UglifyJSPlugin = require('uglifyjs-webpack-plugin'); //const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
module.exports = { module.exports = {
devtool: 'eval', devtool: 'source-map',
entry: [ entry: {
'./src/index' 'bundle': './src/index',
], 'fetcher': './src/fetcher'
},
output: { output: {
path: path.join(__dirname, 'dist'), path: path.join(__dirname, 'dist'),
filename: 'bundle.js', filename: '[name].js',
publicPath: '/static/' sourceMapFilename: '[name].js.map',
publicPath: '/'
}, },
plugins: [ plugins: [
new UglifyJSPlugin() // new UglifyJSPlugin()
], ],
module: { module: {
loaders: [{ loaders: [
test: /\.js$/, {
// loaders: ['babel-loader'], test: /\.js$/,
include: path.join(__dirname, 'src') // loaders: ['babel-loader'],
}, /*{ test: /\.json$/, loader: 'json-loader' }*/] include: path.join(__dirname, 'src'),
exclude: [/fetcher/]
}, /*{ test: /\.json$/, loader: 'json-loader' }*/
{
test: /\.js$/,
include: [/fetcher/]
}
]
}, },
node: { node: {
fs: 'empty', fs: 'empty',