Service worker for intercepting URLs and loading them from IPFS.
This commit is contained in:
parent
9b998a6318
commit
acc7964f0e
|
@ -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>
|
||||||
|
|
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
73
src/index.js
73
src/index.js
|
@ -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)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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',
|
||||||
|
|
Reference in New Issue