Skip to content

feat: precached webui works in offline mode #782

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Oct 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
11 changes: 7 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@ addons:
install:
- npm run ci:install
script:
- npm run ci:build
- npm run ci:test
- npm run ci:lint
- npm run build
- npm run test
- npm run lint
after_success: npx nyc report --reporter=text-lcov > coverage.lcov && npx codecov
notifications:
email: false
email:
if: branch = master
on_success: never
on_failure: always
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ const chromeDefaultOpts = {
Swarm: [
// optional ws-star signaling provides a backup for non-LAN peer discovery
// (this will be removed when autorelay and DHT are stable in js-ipfs)
'/dns4/ws-star1.par.dwebops.pub.com/tcp/443/wss/p2p-websocket-star',
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this was just a dev alias for ws-star.discovery.libp2p.io

'/dns4/ws-star.discovery.libp2p.io/tcp/443/wss/p2p-websocket-star'
],
// Delegated Content and Peer Routing: https://github.com/ipfs/js-ipfs/pull/2195
Expand Down
13 changes: 3 additions & 10 deletions add-on/src/lib/ipfs-client/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const browser = require('webextension-polyfill')
const external = require('./external')
const embedded = require('./embedded')
const embeddedWithChromeSockets = require('./embedded-chromesockets')
const { webuiCid } = require('../state')
const precache = require('../precache')

let client

Expand Down Expand Up @@ -70,15 +70,8 @@ async function _reloadIpfsClientDependents (instance, opts) {
}
// online only
if (client && instance) {
if (webuiCid && instance.refs) {
// Optimization: preload the root CID to speed up the first time
// Web UI is opened. If embedded js-ipfs is used it will trigger
// remote (always recursive) preload of entire DAG to one of preload nodes.
// This way when embedded node wants to load resource related to webui
// it will get it fast from preload nodes.
log(`preloading webui root at ${webuiCid}`)
instance.refs(webuiCid, { recursive: false })
}
// add important data to local ipfs repo for instant load
precache(instance)
}
}

Expand Down
107 changes: 107 additions & 0 deletions add-on/src/lib/precache.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
'use strict'
/* eslint-env browser, webextensions */
const pull = require('pull-stream/pull')
const drain = require('pull-stream/sinks/drain')
const toStream = require('it-to-stream')
const tar = require('tar-stream')
const CID = require('cids')
const { webuiCid } = require('./state')

const debug = require('debug')
const log = debug('ipfs-companion:precache')
log.error = debug('ipfs-companion:precache:error')

const PRECACHE_ARCHIVES = [
{ tarPath: '/dist/precache/webui.tar', cid: webuiCid }
]

/**
* Adds important assets such as Web UI to the local js-ipfs-repo.
* This ensures they load instantly, even in offline environments.
*/
module.exports = async (ipfs) => {
for (const { cid, tarPath } of PRECACHE_ARCHIVES) {
if (!await inRepo(ipfs, cid)) {
await importTar(ipfs, tarPath, cid)
} else {
log(`${cid} already in local repo, skipping import`)
}
}
}

async function inRepo (ipfs, cid) {
return new Promise((resolve, reject) => {
let local = false
pull(
ipfs.refs.localPullStream(),
drain(block => {
if (block.ref === cid) {
local = true
return false // abort stream
}
}, () => resolve(local))
)
})
}

async function importTar (ipfs, tarPath, expectedCid) {
const stream = toStream.readable(streamTar(tarPath))
// TODO: HTTP 404 means precache is disabled in the current runtime
// (eg. in Firefox, due to https://github.com/ipfs-shipyard/ipfs-webui/issues/959)
const untarAndAdd = tar.extract()

const files = []

untarAndAdd.on('entry', (header, stream, next) => {
// header is the tar header
// stream is the content body (might be an empty stream)
// call next when you are done with this entry

if (header.type !== 'file') {
// skip non-files
stream.on('end', next)
stream.resume() // drain stream
return
}

files.push(new Promise((resolve, reject) => {
let chunks = []
stream.on('data', data => chunks.push(data))
stream.on('end', () => {
resolve({ path: header.name, content: Buffer.concat(chunks) })
chunks = null
next()
})
}))
})

untarAndAdd.on('finish', async () => {
const { version } = new CID(expectedCid)
const opts = { cidVersion: version, pin: false, preload: false }
const results = await ipfs.add(await Promise.all(files), opts)
const root = results.find(e => e.hash === expectedCid)
if (root) {
log(`${tarPath} successfully precached`, root)
} else {
log.error('imported CID does not match expected one (requires new release with updated package.json)')
}
})

log(`importing ${tarPath} to js-ipfs-repo`)
stream.pipe(untarAndAdd)
}

async function * streamTar (repoPath) {
const response = await fetch(repoPath)
const reader = response.body.getReader()
try {
while (true) {
const { done, value } = await reader.read()
if (done) return
yield value
}
} finally {
// Firefox only? https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultReader/releaseLock
if (typeof reader.releaseLock === 'function') reader.releaseLock()
}
}
16 changes: 11 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,23 @@
"build:minimize-dist": "shx rm -rf add-on/dist/lib add-on/dist/contentScripts/ add-on/dist/bundles/ipfsProxyContentScriptPayload.bundle.js",
"build:bundle-all": "cross-env RELEASE_CHANNEL=${RELEASE_CHANNEL:=dev} run-s bundle:chromium bundle:brave:$RELEASE_CHANNEL bundle:firefox:$RELEASE_CHANNEL",
"build:rename-artifacts": "./scripts/rename-artifacts.js",
"precache:clean": "shx rm -rf add-on/dist/precache",
"precache:webui:cid": "shx grep 'const webuiCid' add-on/src/lib/state.js | shx sed \"s/^const webuiCid = '//\" | shx sed \"s/'.*$//\"",
"precache:webui": "shx mkdir -p add-on/dist/precache && ipfs-or-gateway -c $(npm run -s precache:webui:cid) -p add-on/dist/precache/webui.tar --archive",
"bundle": "run-s bundle:*",
"bundle:chromium": "shx cat add-on/manifest.common.json add-on/manifest.chromium.json | json --deep-merge > add-on/manifest.json && web-ext build -a build/chromium && run-s build:rename-artifacts",
"bundle:firefox": "shx cat add-on/manifest.common.json add-on/manifest.firefox.json | json --deep-merge > add-on/manifest.json && web-ext build -a build/firefox/ && run-s build:rename-artifacts",
"bundle:chromium": "run-s precache:webui && shx cat add-on/manifest.common.json add-on/manifest.chromium.json | json --deep-merge > add-on/manifest.json && web-ext build -a build/chromium && run-s build:rename-artifacts",
"bundle:firefox": "run-s precache:clean && shx cat add-on/manifest.common.json add-on/manifest.firefox.json | json --deep-merge > add-on/manifest.json && web-ext build -a build/firefox/ && run-s build:rename-artifacts",
"bundle:firefox:dev": "npm run bundle:firefox",
"bundle:firefox:stable": "npm run bundle:firefox",
"bundle:firefox:beta": "shx cat add-on/manifest.common.json add-on/manifest.firefox.json add-on/manifest.firefox-beta.json | json --deep-merge > add-on/manifest.json && web-ext build -a build/firefox/ && run-s build:rename-artifacts",
"bundle:firefox:beta": "run-s precache:clean && shx cat add-on/manifest.common.json add-on/manifest.firefox.json add-on/manifest.firefox-beta.json | json --deep-merge > add-on/manifest.json && web-ext build -a build/firefox/ && run-s build:rename-artifacts",
"bundle:fennec": "npm run bundle:firefox",
"bundle:fennec:dev": "npm run bundle:firefox:dev",
"bundle:fennec:stable": "npm run bundle:firefox:stable",
"bundle:fennec:beta": "npm run bundle:firefox:beta",
"bundle:brave": "shx cat add-on/manifest.common.json add-on/manifest.chromium.json add-on/manifest.brave.json | json --deep-merge > add-on/manifest.json && web-ext build -a build/brave/ && run-s build:rename-artifacts",
"bundle:brave": "run-s precache:webui && shx cat add-on/manifest.common.json add-on/manifest.chromium.json add-on/manifest.brave.json | json --deep-merge > add-on/manifest.json && web-ext build -a build/brave/ && run-s build:rename-artifacts",
"bundle:brave:dev": "npm run bundle:brave",
"bundle:brave:stable": "npm run bundle:brave",
"bundle:brave:beta": "shx cat add-on/manifest.common.json add-on/manifest.chromium.json add-on/manifest.brave.json add-on/manifest.brave-beta.json | json --deep-merge > add-on/manifest.json && web-ext build -a build/brave/ && run-s build:rename-artifacts",
"bundle:brave:beta": "run-s precache:webui && shx cat add-on/manifest.common.json add-on/manifest.chromium.json add-on/manifest.brave.json add-on/manifest.brave-beta.json | json --deep-merge > add-on/manifest.json && web-ext build -a build/brave/ && run-s build:rename-artifacts",
"watch": "npm-run-all build:copy --parallel watch:*",
"watch:js": "run-p watch:js:*",
"watch:js:webpack": "webpack --watch --progress -d --devtool inline-source-map --config ./webpack.config.js",
Expand Down Expand Up @@ -93,6 +96,7 @@
"get-firefox": "2.2.1",
"husky": "3.0.8",
"ignore-styles": "5.0.1",
"ipfs-or-gateway": "2.1.0",
"json": "9.0.6",
"mem-storage-area": "1.0.3",
"mocha": "6.2.1",
Expand Down Expand Up @@ -138,6 +142,7 @@
"is-fqdn": "1.0.1",
"is-ipfs": "0.6.1",
"is-svg": "4.2.0",
"it-to-stream": "0.1.1",
"lru-cache": "5.1.1",
"merge-options": "1.0.1",
"mime-types": "2.1.24",
Expand All @@ -151,6 +156,7 @@
"pull-file-reader": "1.0.2",
"readable-stream": "3.4.0",
"tachyons": "4.11.1",
"tar-stream": "2.1.0",
"timers-browserify-full": "0.0.1",
"uri-to-multiaddr": "3.0.1",
"webextension-polyfill": "0.5.0",
Expand Down
Loading