IPFS Support + Loading Improvements (Better local file handling) + Streamlined Collection View (#25)
* support ipfs:// urls! misc: better error message for loading from http:// tabs: don't render pages/story/urls if hidden * ipfs work: remove ww only use sw * electron + ipfs: add ipfs support to electron app, using ipfs-core - route ipfs requests to files proxy with 'ipfs=' query param * file loading: - add support for new Chrome native file system api with file handles, which allows persistent access to files vial file handles - if window.showOpenFilePicker() is available use that, include file handle in load message - support asking permissions for file handles, using similar workflow as google drive auth - attempt to ask for file permission directly, show auth button if fails (user gestured required) - replace auth modal with iframe replacement insert to ask for auth for google drive and local file * ui overhaul for 1.3.0 / condense collection view: - don't show navbar in collection view - add logo to back to home page to location bar - condense location bar buttons - convert terms to general about dialog, available from collection context menu - add info tab to collection view in place of drop-down info - make <wr-coll-info> component, used in both collection list and info tab with additional details - update to wabac.js 2.2.0 * update CHANGES.md
This commit is contained in:
+91
-17
@@ -8,7 +8,7 @@ import fs from 'fs';
|
||||
|
||||
import { ArchiveResponse, Rewriter } from '@webrecorder/wabac/src/rewrite';
|
||||
|
||||
import { PassThrough } from 'stream';
|
||||
import { PassThrough, Readable } from 'stream';
|
||||
|
||||
import mime from 'mime-types';
|
||||
|
||||
@@ -21,6 +21,10 @@ const REPLAY_PREFIX = STATIC_PREFIX + "wabac/";
|
||||
|
||||
const URL_RX = /([^\/]+)\/([\d]+)(?:\w\w_)?\/(.*)$/;
|
||||
|
||||
let IPFS = null;
|
||||
let ipfs = null;
|
||||
let initingIPFS = null;
|
||||
|
||||
|
||||
// ============================================================================
|
||||
class ElectronReplayApp
|
||||
@@ -95,7 +99,7 @@ class ElectronReplayApp
|
||||
app.commandLine.appendSwitch('ppapi-flash-path', this.pluginPath);
|
||||
|
||||
console.log('app path', this.appPath);
|
||||
console.log('dir name', this.__dirname);
|
||||
console.log('dir name', __dirname);
|
||||
console.log('proj path', this.projPath);
|
||||
console.log('plugin path', this.pluginPath);
|
||||
|
||||
@@ -134,7 +138,38 @@ class ElectronReplayApp
|
||||
});
|
||||
}
|
||||
|
||||
static async doInitIPFS() {
|
||||
if (!IPFS) {
|
||||
IPFS = require("ipfs-core");
|
||||
}
|
||||
|
||||
ipfs = await IPFS.create({
|
||||
//repo: "/tmp/test-ipfs"
|
||||
init: {emptyRepo: true},
|
||||
//preload: {enabled: false},
|
||||
});
|
||||
}
|
||||
|
||||
async initIPFS() {
|
||||
if (!ipfs) {
|
||||
try {
|
||||
if (!initingIPFS) {
|
||||
initingIPFS = ElectronReplayApp.doInitIPFS();
|
||||
}
|
||||
|
||||
await initingIPFS;
|
||||
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
}
|
||||
}
|
||||
|
||||
return ipfs;
|
||||
}
|
||||
|
||||
onAppReady() {
|
||||
//ElectronReplayApp.doInitIPFS();
|
||||
|
||||
this.screenSize = screen.getPrimaryDisplay().workAreaSize;
|
||||
|
||||
app.on('web-contents-created', (event, contents) => {
|
||||
@@ -213,27 +248,62 @@ class ElectronReplayApp
|
||||
|
||||
if (request.url.startsWith(__APP_FILE_SERVE_PREFIX__)) {
|
||||
const parsedUrl = new URL(request.url);
|
||||
|
||||
const filename = parsedUrl.searchParams.get("filename");
|
||||
console.log("file serve:", filename);
|
||||
|
||||
const stat = await fs.promises.lstat(filename);
|
||||
|
||||
if (!stat.isFile()) {
|
||||
return this.notFound(filename, callback);
|
||||
}
|
||||
|
||||
const size = stat.size;
|
||||
|
||||
const headers = {"Content-Length": "" + size, "Content-Type": "application/octet-stream"};
|
||||
const ipfsCID = parsedUrl.searchParams.get("ipfs");
|
||||
|
||||
const headers = {"Content-Type": "application/octet-stream"};
|
||||
const reqHeaders = new Headers(request.headers);
|
||||
|
||||
const {statusCode, start, end} = this.parseRange(reqHeaders, headers, size);
|
||||
if (filename) {
|
||||
console.log("file serve:", filename);
|
||||
|
||||
const data = request.method === "HEAD" ? null : fs.createReadStream(filename, {start, end});
|
||||
const stat = await fs.promises.lstat(filename);
|
||||
|
||||
callback({statusCode, headers, data});
|
||||
return;
|
||||
if (!stat.isFile()) {
|
||||
return this.notFound(filename, callback);
|
||||
}
|
||||
|
||||
const size = stat.size;
|
||||
|
||||
const {statusCode, start, end} = this.parseRange(reqHeaders, headers, size);
|
||||
|
||||
const data = request.method === "HEAD" ? null : fs.createReadStream(filename, {start, end});
|
||||
|
||||
callback({statusCode, headers, data});
|
||||
return;
|
||||
|
||||
} else if (ipfsCID) {
|
||||
console.log("ipfs serve:", ipfsCID);
|
||||
|
||||
const ipfs = await this.initIPFS();
|
||||
|
||||
let size = 0;
|
||||
|
||||
for await (const file of ipfs.get(ipfsCID, {timeout: 20000, preload: false})) {
|
||||
if (file.type !== "file") {
|
||||
return this.notFound(ipfsCID, callback);
|
||||
}
|
||||
size = file.size;
|
||||
break;
|
||||
}
|
||||
|
||||
const {statusCode, start, end} = this.parseRange(reqHeaders, headers, size);
|
||||
|
||||
let data = null;
|
||||
|
||||
if (request.method === "GET") {
|
||||
const offset = start || 0;
|
||||
const length = end ? end - start + 1 : size;
|
||||
data = Readable.from(ipfs.cat(ipfsCID, {offset, length}));
|
||||
}
|
||||
|
||||
callback({statusCode, headers, data});
|
||||
return;
|
||||
|
||||
} else {
|
||||
return this.notFound("No Resource Specified", callback);
|
||||
}
|
||||
}
|
||||
|
||||
// possible 'live leak' attempt, just return not found
|
||||
@@ -324,6 +394,9 @@ class ElectronReplayApp
|
||||
const range = reqHeaders.get("range");
|
||||
|
||||
if (!range) {
|
||||
if (headers) {
|
||||
headers["Content-Length"] = "" + size;
|
||||
}
|
||||
return {statusCode};
|
||||
}
|
||||
|
||||
@@ -337,6 +410,7 @@ class ElectronReplayApp
|
||||
statusCode = 206;
|
||||
if (headers) {
|
||||
headers["Content-Range"] = `bytes ${start}-${end}/${size}`;
|
||||
headers["Content-Length"] = `${end - start + 1}`;
|
||||
}
|
||||
return {statusCode, start, end};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user