mirror of
https://github.com/fluencelabs/dweb-transports
synced 2025-04-24 22:32:16 +00:00
Add streaming to TransportHTTP and p_GET and p_httpfetch
This commit is contained in:
parent
dc32f4c039
commit
041b3b9684
2
API.md
2
API.md
@ -432,7 +432,7 @@ relay If first transport fails, try and retrieve on 2nd, then store on 1s
|
|||||||
A utility class to support HTTP with or without TransportHTTP
|
A utility class to support HTTP with or without TransportHTTP
|
||||||
e.g. `httptools.http().p_httpfetch("http://foo.com/bar", {method: 'GET'} )`
|
e.g. `httptools.http().p_httpfetch("http://foo.com/bar", {method: 'GET'} )`
|
||||||
|
|
||||||
##### p_httpfetch(url, init, verbose)
|
##### p_httpfetch(url, init, {verbose)}
|
||||||
Fetch a url.
|
Fetch a url.
|
||||||
If the result
|
If the result
|
||||||
|
|
||||||
|
@ -144,6 +144,63 @@ class TransportHTTP extends Transport {
|
|||||||
return [u,u];
|
return [u,u];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================== Stream support
|
||||||
|
|
||||||
|
/*
|
||||||
|
Code disabled until have a chance to test it with <VIDEO> tag etc, problem is that it returns p_createReadStream whch is async
|
||||||
|
if need sync, look at WebTorrent and how it buffers through a stream which can be returned immediately
|
||||||
|
*/
|
||||||
|
async p_f_createReadStream(url, {verbose=false, wanturl=false}={}) {
|
||||||
|
/*
|
||||||
|
Fetch bytes progressively, using a node.js readable stream, based on a url of the form:
|
||||||
|
No assumption is made about the data in terms of size or structure.
|
||||||
|
|
||||||
|
This is the initialisation step, which returns a function suitable for <VIDEO>
|
||||||
|
|
||||||
|
Returns a new Promise that resolves to function for a node.js readable stream.
|
||||||
|
|
||||||
|
Node.js readable stream docs: https://nodejs.org/api/stream.html#stream_readable_streams
|
||||||
|
|
||||||
|
:param string url: URL of object being retrieved of form magnet:xyzabc/path/to/file (Where xyzabc is the typical magnet uri contents)
|
||||||
|
:param boolean verbose: true for debugging output
|
||||||
|
:resolves to: f({start, end}) => stream (The readable stream.)
|
||||||
|
:throws: TransportError if url invalid - note this happens immediately, not as a catch in the promise
|
||||||
|
*/
|
||||||
|
if (verbose) console.log(this.name, "p_f_createreadstream %o", Url.parse(url).href);
|
||||||
|
try {
|
||||||
|
let self = this;
|
||||||
|
if (wanturl) {
|
||||||
|
return url;
|
||||||
|
} else {
|
||||||
|
return function (opts) { return self.p_createReadStream(url, opts, verbose); };
|
||||||
|
}
|
||||||
|
} catch(err) {
|
||||||
|
console.warn(`p_f_createReadStream failed on ${Url.parse(url).href} ${err.message}`);
|
||||||
|
throw(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async p_createReadStream(url, opts, verbose) {
|
||||||
|
/*
|
||||||
|
The function, encapsulated and inside another function by p_f_createReadStream (see docs)
|
||||||
|
NOTE THIS PROBABLY WONT WORK FOR <VIDEO> tags, but shouldnt be using it there anyway
|
||||||
|
|
||||||
|
:param file: Webtorrent "file" as returned by webtorrentfindfile
|
||||||
|
:param opts: { start: byte to start from; end: optional end byte }
|
||||||
|
:param boolean verbose: true for debugging output
|
||||||
|
:resolves to stream: The readable stream.
|
||||||
|
*/
|
||||||
|
if (verbose) console.log(this.name, "createreadstream %o %o", Url.parse(url).href, opts);
|
||||||
|
try {
|
||||||
|
return await httptools.p_GET(this._url(url, servercommands.rawfetch), Object.assign({wantstream: true}, opts));
|
||||||
|
} catch(err) {
|
||||||
|
console.warn(this.name, "caught error", err);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ============================== Key Value support
|
// ============================== Key Value support
|
||||||
|
|
||||||
|
|
||||||
|
23
httptools.js
23
httptools.js
@ -22,6 +22,15 @@ if (typeof(fetch) === "undefined") {
|
|||||||
httptools = {};
|
httptools = {};
|
||||||
|
|
||||||
async function loopfetch(req, ms, count, what) {
|
async function loopfetch(req, ms, count, what) {
|
||||||
|
/*
|
||||||
|
A workaround for a nasty Chrome issue which fails if there is a (cross-origin?) fetch of more than 6 files. See other WORKAROUND-CHROME-CROSSORIGINFETCH
|
||||||
|
Loops at longer and longer intervals trying
|
||||||
|
req: Request
|
||||||
|
ms: Initial wait between polls
|
||||||
|
count: Max number of times to try (0 means just once)
|
||||||
|
what: Name of what retrieving for log (usually file name or URL)
|
||||||
|
returns Response:
|
||||||
|
*/
|
||||||
let lasterr;
|
let lasterr;
|
||||||
let loopguard = (typeof window != "undefined") && window.loopguard; // Optional global parameter, will cancel any loops if changes
|
let loopguard = (typeof window != "undefined") && window.loopguard; // Optional global parameter, will cancel any loops if changes
|
||||||
while (count-- && (loopguard === ((typeof window != "undefined") && window.loopguard)) ) {
|
while (count-- && (loopguard === ((typeof window != "undefined") && window.loopguard)) ) {
|
||||||
@ -43,11 +52,12 @@ async function loopfetch(req, ms, count, what) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
httptools.p_httpfetch = async function(httpurl, init, verbose) { // Embrace and extend "fetch" to check result etc.
|
httptools.p_httpfetch = async function(httpurl, init, {verbose=false, wantstream=false}={}) { // Embrace and extend "fetch" to check result etc.
|
||||||
/*
|
/*
|
||||||
Fetch a url
|
Fetch a url
|
||||||
|
|
||||||
url: optional (depends on command)
|
httpurl: optional (depends on command)
|
||||||
|
init: {headers}
|
||||||
resolves to: data as text or json depending on Content-Type header
|
resolves to: data as text or json depending on Content-Type header
|
||||||
throws: TransportError if fails to fetch
|
throws: TransportError if fails to fetch
|
||||||
*/
|
*/
|
||||||
@ -62,7 +72,9 @@ httptools.p_httpfetch = async function(httpurl, init, verbose) { // Embrace and
|
|||||||
// Note response.body gets a stream and response.blob gets a blob and response.arrayBuffer gets a buffer.
|
// Note response.body gets a stream and response.blob gets a blob and response.arrayBuffer gets a buffer.
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
let contenttype = response.headers.get('Content-Type');
|
let contenttype = response.headers.get('Content-Type');
|
||||||
if (contenttype === "application/json") {
|
if (wantstream) {
|
||||||
|
return response.body; // Note property while json() or text() are functions
|
||||||
|
} else if (contenttype === "application/json") {
|
||||||
return response.json(); // promise resolving to JSON
|
return response.json(); // promise resolving to JSON
|
||||||
} else if (contenttype.startsWith("text")) { // Note in particular this is used for responses to store
|
} else if (contenttype.startsWith("text")) { // Note in particular this is used for responses to store
|
||||||
return response.text();
|
return response.text();
|
||||||
@ -89,6 +101,7 @@ httptools.p_GET = async function(httpurl, opts={}) {
|
|||||||
Throws TransportError if fails
|
Throws TransportError if fails
|
||||||
opts {
|
opts {
|
||||||
start, end, // Range of bytes wanted - inclusive i.e. 0,1023 is 1024 bytes
|
start, end, // Range of bytes wanted - inclusive i.e. 0,1023 is 1024 bytes
|
||||||
|
wantstream, // Return a stream rather than data
|
||||||
verbose }
|
verbose }
|
||||||
resolves to: URL that can be used to fetch the resource, of form contenthash:/contenthash/Q123
|
resolves to: URL that can be used to fetch the resource, of form contenthash:/contenthash/Q123
|
||||||
*/
|
*/
|
||||||
@ -102,7 +115,7 @@ httptools.p_GET = async function(httpurl, opts={}) {
|
|||||||
redirect: 'follow', // Chrome defaults to manual
|
redirect: 'follow', // Chrome defaults to manual
|
||||||
keepalive: true // Keep alive - mostly we'll be going back to same places a lot
|
keepalive: true // Keep alive - mostly we'll be going back to same places a lot
|
||||||
};
|
};
|
||||||
return await httptools.p_httpfetch(httpurl, init, opts.verbose); // This s a real http url
|
return await httptools.p_httpfetch(httpurl, init, {verbose: opts.verbose, wantstream: opts.wantstream}); // This s a real http url
|
||||||
}
|
}
|
||||||
httptools.p_POST = async function(httpurl, type, data, verbose) {
|
httptools.p_POST = async function(httpurl, type, data, verbose) {
|
||||||
// Locate and return a block, based on its url
|
// Locate and return a block, based on its url
|
||||||
@ -121,7 +134,7 @@ httptools.p_POST = async function(httpurl, type, data, verbose) {
|
|||||||
redirect: 'follow', // Chrome defaults to manual
|
redirect: 'follow', // Chrome defaults to manual
|
||||||
keepalive: true // Keep alive - mostly we'll be going back to same places a lot
|
keepalive: true // Keep alive - mostly we'll be going back to same places a lot
|
||||||
};
|
};
|
||||||
return await httptools.p_httpfetch(httpurl, init, verbose);
|
return await httptools.p_httpfetch(httpurl, init, {verbose});
|
||||||
}
|
}
|
||||||
|
|
||||||
exports = module.exports = httptools;
|
exports = module.exports = httptools;
|
@ -33,7 +33,7 @@
|
|||||||
"chai": "latest",
|
"chai": "latest",
|
||||||
"uglifyjs-webpack-plugin": "latest",
|
"uglifyjs-webpack-plugin": "latest",
|
||||||
"watchify": "^3.11.0",
|
"watchify": "^3.11.0",
|
||||||
"webpack-cli": "^3.0.8"
|
"webpack-cli": "^3.1.0"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/internetarchive/dweb-transports#readme",
|
"homepage": "https://github.com/internetarchive/dweb-transports#readme",
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user