Skip to content
This repository has been archived by the owner on Feb 12, 2024. It is now read-only.

feat: share IPFS node between browser tabs #3081

Merged
merged 75 commits into from
Jul 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
78f39b8
chore: reset f584f06f5046c9ce234ba6f0832bf5a6aec9b702 to 5e0a18aa07c1…
Gozala Jun 2, 2020
5099f20
Make changes to get tests running.
Gozala Jun 4, 2020
0c176cc
feat: add pure data model interop for dag-pb
Gozala Jun 5, 2020
365779b
chore: swap deps to forks with Uint8Array interop
Gozala Jun 9, 2020
2507741
Stash changes
Gozala Jun 10, 2020
c55571a
fix: encode / decode nodes to preserve CIDs
Gozala Jun 11, 2020
92fa239
chore: swap ipld-block with a fork
Gozala Jun 11, 2020
7ec2aff
chore: activate dag.tree tests
Gozala Jun 11, 2020
9e6ad6c
chore: resolve lint issues
Gozala Jun 11, 2020
139cb26
chore: move server/client shared code to protocol
Gozala Jun 12, 2020
102b1ae
chore: fix test scripts
Gozala Jun 13, 2020
ee2fbcd
Merge remote-tracking branch 'upstream/master' into shared-worker
Gozala Jun 15, 2020
a37fd8e
chore: propagated dependency changes
Gozala Jun 15, 2020
1e4f583
chore: rever unecessary changes in interface-tests
Gozala Jun 16, 2020
f93c402
chore: update reason for disabling test
Gozala Jun 16, 2020
e2cd66d
fix: tests for ipfs.add
Gozala Jun 16, 2020
f43a03a
fix: add files.stat to enable more ipfs.add tests
Gozala Jun 16, 2020
2bf80b2
chore: add echoserver & enable more ipfs.add tests
Gozala Jun 16, 2020
3511641
Merge remote-tracking branch 'upstream/master' into shared-worker
Gozala Jun 18, 2020
3c78c14
chore: disable intermittent failing test
Gozala Jun 18, 2020
3947c54
fix: add ipfs.block to test ipfs.cat
Gozala Jun 18, 2020
bfede92
chore: disable intermittent failing test
Gozala Jun 19, 2020
108f8c9
chore: disable intermittent failing interface test
Gozala Jun 19, 2020
36a5e7b
Merge remote-tracking branch 'upstream/master' into shared-worker
Gozala Jun 19, 2020
fe85bff
chore: disable intermittent failing test
Gozala Jun 19, 2020
132e8e6
fix: remote error transfer in firefox
Gozala Jun 19, 2020
ddd697f
Merge remote-tracking branch 'upstream/master' into shared-worker
Gozala Jun 19, 2020
dc5aaf3
chore: enable test that was fixed by 8808abc
Gozala Jun 19, 2020
b1350eb
chore: workaround mysterious bundle size changes
Gozala Jun 19, 2020
a3ca1ae
chore: disable electron tests until #587 is fixed
Gozala Jun 22, 2020
099557c
chore: expose CID from encoder
Gozala Jun 22, 2020
0483db7
chore: add readme documents
Gozala Jun 22, 2020
f7f8104
chore: cleanup client code
Gozala Jun 23, 2020
5285cf2
chore: cleanup server & protocol code
Gozala Jun 23, 2020
5bfb1d4
chore: remove redundunt code
Gozala Jun 23, 2020
f966c1d
Merge remote-tracking branch 'upstream/master' into shared-worker
Gozala Jun 23, 2020
81269c7
fix: add name to custom error types
Gozala Jun 23, 2020
d08ab3d
fix: error names normalization across threads
Gozala Jun 23, 2020
a9aa9a9
chore: merge 'upstream/master' into shared-worker
Gozala Jun 23, 2020
98db58b
fix: regression introduced by c487207
Gozala Jun 23, 2020
dc5f10d
fix: link to the core APIs
Gozala Jul 6, 2020
cbb3e5b
fix: typo
Gozala Jul 6, 2020
574d30a
fix: typo
Gozala Jul 6, 2020
7b2c7f2
fix: link to core API docs
Gozala Jul 6, 2020
54de1be
chore: update dependencies from forks to releases
Gozala Jul 14, 2020
15813d7
Merge remote-tracking branch 'upstream/master' into shared-worker
Gozala Jul 14, 2020
6e795b4
fix: typo in the readme
Gozala Jul 14, 2020
57ac874
fix: address review comments
Gozala Jul 14, 2020
1e3acde
chore: revert temporary changes to code base
Gozala Jul 15, 2020
e344783
Merge remote-tracking branch 'origin/shared-worker' into shared-worker
Gozala Jul 15, 2020
a126d22
fix: typo
Gozala Jul 15, 2020
e21b5fa
fix: apply suggestions from code review
Gozala Jul 15, 2020
a4b5ffc
chore: add shared worker example
Gozala Jul 16, 2020
e2f333e
Merge remote-tracking branch 'origin/shared-worker' into shared-worker
Gozala Jul 16, 2020
0dc83a5
fix: test overcoming moxystudio/js-class-is#27
Gozala Jul 16, 2020
6175a35
chore: disable electron tests
Gozala Jul 18, 2020
69c6db0
chore: update interface-ipfs-core to lastest
Gozala Jul 20, 2020
f462640
Merge remote-tracking branch 'upstream/master' into shared-worker
Gozala Jul 20, 2020
2302b2f
chore: incorporate changes from [email protected]
Gozala Jul 21, 2020
84264a4
chore: remove lerna.json from example
Gozala Jul 24, 2020
d1d37ae
chore: rever & disbale test for multifile ipfs.add
Gozala Jul 24, 2020
7d3e35c
chore: revert changes to object.put tests
Gozala Jul 24, 2020
6a8e65f
chore: consolidate imports
Gozala Jul 24, 2020
5d8689e
chore: reduce bundle size
Gozala Jul 24, 2020
f0dd758
chore: remove redundant tests
Gozala Jul 24, 2020
115cc95
chore: use browser-readablestream-to-it
Gozala Jul 24, 2020
906fafb
chore: adopt it-all instead of custom function
Gozala Jul 24, 2020
f42cf5a
chore: remove redundunt tests
Gozala Jul 25, 2020
678a061
chore: incorporate review edits
Gozala Jul 25, 2020
77ef623
chore: update my email address
Gozala Jul 25, 2020
3ed0764
fix: cancel timers on request success/failure
Gozala Jul 25, 2020
2f8cc1d
Merge remote-tracking branch 'upstream/master' into shared-worker
Gozala Jul 25, 2020
cb011b5
chore: align dependency versions
Gozala Jul 25, 2020
55acadf
fix: use it-all instead of removed util
Gozala Jul 25, 2020
88f489e
Merge branch 'master' into shared-worker
achingbrain Jul 27, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions examples/browser-sharing-node-across-tabs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Sharing js-ipfs node across browsing contexts (tabs) using [SharedWorker][]

> In this example, you will find a boilerplate you can use to set up a js-ipfs
> node in the [SharedWorker] and use it from multiple tabs.

## Before you start

First clone this repo, install dependencies in the project root and build the project.

```bash
git clone https://github.com/ipfs/js-ipfs.git
cd js-ipfs/examples/browser-sharing-node-across-tabs
npm install
```

## Running the example

Run the following command within this folder:

```bash
npm start
```

Now open your browser at `http://localhost:3000`

You should see the following:

![Screen Shot](./Screen Shot.png)


### Run tests

```bash
npm test
```


[SharedWorker]:https://developer.mozilla.org/en-US/docs/Web/API/SharedWorker
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions examples/browser-sharing-node-across-tabs/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<html>

<head>
<title>Sample App</title>
</head>

<body>
<div id='root'></div>
<script src="/static/bundle.js"></script>
</body>

</html>
36 changes: 36 additions & 0 deletions examples/browser-sharing-node-across-tabs/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"name": "expample-browser-sharing-node-across-tabs",
"description": "Sharing IPFS node across browsing contexts",
"version": "1.0.0",
"private": true,
"scripts": {
"clean": "rm -rf ./dist",
"build": "webpack",
"start": "node server.js",
"test": "test-ipfs-example"
},
"license": "MIT",
"keywords": [],
"devDependencies": {
"@babel/core": "^7.2.2",
"@babel/preset-env": "^7.3.1",
"babel-loader": "^8.0.5",
"copy-webpack-plugin": "^5.0.4",
"test-ipfs-example": "^2.0.3",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.11.0",
"worker-plugin": "4.0.3"
},
"dependencies": {
"ipfs": "^0.47.0",
"ipfs-message-port-client": "^0.0.1",
"ipfs-message-port-server": "^0.0.1"
},
"browserslist": [
">1%",
"not dead",
"not ie <= 11",
"not op_mini all"
]
}
18 changes: 18 additions & 0 deletions examples/browser-sharing-node-across-tabs/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
'use strict'

const webpack = require('webpack')
const WebpackDevServer = require('webpack-dev-server')
const config = require('./webpack.config')

const wds = new WebpackDevServer(webpack(config), {
hot: true,
historyApiFallback: true
})

wds.listen(3000, 'localhost', (err) => {
if (err) {
throw err
}

console.log('Listening at localhost:3000')
})
45 changes: 45 additions & 0 deletions examples/browser-sharing-node-across-tabs/src/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
'use strict'

import IPFSClient from "ipfs-message-port-client"


const main = async () => {
// connect / spawn shared ipfs worker & create a client.
const worker = new SharedWorker('./worker.js', { type: 'module' })
const ipfs = IPFSClient.from(worker.port)

const path = location.hash.slice(1)
if (path.startsWith('/ipfs/')) {
await viewer(ipfs, path)
} else {
await uploader(ipfs)
}
}

const uploader = async (ipfs) => {
document.body.outerHTML += '<div>Adding "hello world!" to shared IPFS node</div>'
const entry = await ipfs.add(ipfs, new Blob(['hello world!'], { type: "text/plain" }))
const path = `/ipfs/${entry.cid}/`
document.body.outerHTML += `<div class="ipfs-add">File was added:
<a target="_blank" href="${new URL(`#${path}`, location)}">${path}</a>
</div>`
}

const viewer = async (ipfs, path) => {
document.body.outerHTML += `<div class="loading">Loading ${path}</div>`
try {
const chunks = []
for await (const chunk of await ipfs.cat(path)) {
chunks.push(chunk)
}
const blob = new Blob(chunks)
const url = URL.createObjectURL(blob)
document.body.outerHTML +=
`<iframe id="content" sandbox src=${url} style="background:white;top:0;left:0;border:0;width:100%;height:100%;position:absolute;z-index:2;"></iframe>`

} catch(error) {
document.body.outerHTML += `<div class="error">${error}</div>`
}
}

onload = main
65 changes: 65 additions & 0 deletions examples/browser-sharing-node-across-tabs/src/worker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
'use strict'

import IPFS from 'ipfs'
import { Server, IPFSService } from 'ipfs-message-port-server'

const main = async () => {
// start listening to all the incoming connections (browsing contexts that
// which run new SharedWorker...)
// Note: It is important to start listening before we do any await to ensure
// that connections aren't missed while awaiting.
const connections = listen(self, 'connect')

// Start an IPFS node & create server that will expose it's API to all clients
// over message channel.
const ipfs = await IPFS.create()
const service = new IPFSService(ipfs)
const server = new Server(service)

// connect every queued and future connection to the server.
for await (const event of connections) {
const port = event.ports[0]
if (port) {
server.connect(port)
}
}
}

/**
* Creates an AsyncIterable<Event> for all the events on the given `target` for
* the given event `type`. It is like `target.addEventListener(type, listener, options)`
* but instead of passing listener you get `AsyncIterable<Event>` instead.
* @param {EventTarget} target
* @param {string} type
* @param {AddEventListenerOptions} options
*/
const listen = function (target, type, options) {
const events = []
let resume
let ready = new Promise(resolve => (resume = resolve))

const write = event => {
events.push(event)
resume()
}
const read = async () => {
await ready
ready = new Promise(resolve => (resume = resolve))
return events.splice(0)
}

const reader = async function * () {
try {
while (true) {
yield * await read()
}
} finally {
target.removeEventListener(type, write, options)
}
}

target.addEventListener(type, write, options)
return reader()
}

main()
33 changes: 33 additions & 0 deletions examples/browser-sharing-node-across-tabs/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
'use strict'

const pkg = require('./package.json')

module.exports = {
[pkg.name]: (browser) => {
browser
.url(process.env.IPFS_EXAMPLE_TEST_URL)
.waitForElementVisible('.ipfs-add')

browser.expect.element('.ipfs-add a').text.to.contain('/ipfs/')
browser.click('.ipfs-add a')

browser.windowHandle(({ value }) => {
browser.windowHandles(({ value: handles }) => {
const [handle] = handles.filter(handle => handle != value)
browser.switchWindow(handle)
})
})

browser.waitForElementVisible('.loading')
browser.expect.element('.loading').text.to.contain('Loading /ipfs/')

browser.waitForElementVisible('#content').pause(5000)
browser.element('css selector', '#content', frame => {
browser.frame({ ELEMENT: frame.value.ELEMENT }, () => {
browser.waitForElementPresent('body')
browser.expect.element('body').text.to.contain('hello world!')
browser.end()
})
})
}
}
44 changes: 44 additions & 0 deletions examples/browser-sharing-node-across-tabs/webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
'use strict'

var path = require('path')
var webpack = require('webpack')
const WorkerPlugin = require('worker-plugin')

module.exports = {
devtool: 'source-map',
entry: [
'webpack-dev-server/client?http://localhost:3000',
'webpack/hot/only-dev-server',
'./src/main'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'static/bundle.js'
},
plugins: [
new WorkerPlugin({
sharedWorker: true,
globalObject: 'self'
}),
new webpack.HotModuleReplacementPlugin()
],
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
]
},
node: {
fs: 'empty',
net: 'empty',
tls: 'empty'
}
}
2 changes: 1 addition & 1 deletion examples/traverse-ipld-graphs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"dependencies": {
"cids": "^0.8.3",
"ipfs": "^0.48.0",
"ipld-block": "^0.9.1",
"ipld-block": "^0.9.2",
"ipld-dag-pb": "^0.19.0",
"multihashing-async": "^1.0.0"
}
Expand Down
4 changes: 2 additions & 2 deletions packages/interface-ipfs-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@
"ipfs-unixfs": "^1.0.3",
"ipfs-unixfs-importer": "^2.0.2",
"ipfs-utils": "^2.2.2",
"ipld-block": "^0.9.1",
"ipld-dag-cbor": "^0.15.2",
"ipld-block": "^0.9.2",
"ipld-dag-cbor": "^0.15.3",
"ipld-dag-pb": "^0.19.0",
"is-ipfs": "^1.0.3",
"iso-random-stream": "^1.1.1",
Expand Down
5 changes: 3 additions & 2 deletions packages/interface-ipfs-core/src/object/links.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,9 @@ module.exports = (common, options) => {
const node1bCid = await ipfs.object.put(node1b)

const links = await ipfs.object.links(node1bCid)
expect(links).to.be.an('array').that.has.property('length', 1)
expect(node1b.Links).to.be.deep.equal(links)

expect(links).to.have.lengthOf(1)
expect(node1b.Links).to.deep.equal(links)
})

it('should get links by base58 encoded multihash', async () => {
Expand Down
6 changes: 3 additions & 3 deletions packages/ipfs-http-client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@
"form-data": "^3.0.0",
"ipfs-core-utils": "^0.3.0",
"ipfs-utils": "^2.2.2",
"ipld-block": "^0.9.1",
"ipld-dag-cbor": "^0.15.2",
"ipld-block": "^0.9.2",
"ipld-dag-cbor": "^0.15.3",
"ipld-dag-pb": "^0.19.0",
"ipld-raw": "^5.0.0",
"iso-url": "^0.4.7",
Expand All @@ -67,7 +67,7 @@
"nanoid": "^3.0.2",
"node-fetch": "^2.6.0",
"parse-duration": "^0.4.4",
"stream-to-it": "^0.2.0"
"stream-to-it": "^0.2.1"
},
"devDependencies": {
"aegir": "^23.0.0",
Expand Down
Loading