mirror of
https://github.com/fluencelabs/dweb-transports
synced 2025-04-25 06:42:17 +00:00
commit
003efedb4d
@ -25,7 +25,7 @@ to your package.json file in the dependencies section.
|
|||||||
### Installation and usage in the Browser
|
### Installation and usage in the Browser
|
||||||
* Install npm & node
|
* Install npm & node
|
||||||
* Clone this repo and cd to it.
|
* Clone this repo and cd to it.
|
||||||
* `npm bundle` will create dist/dweb_transports_bundle.js
|
* `npm run build` will create dist/dweb_transports_bundle.js
|
||||||
* Add `<SCRIPT type="text/javascript" src="dweb_transports_bundle.js"></SCRIPT>` to your `<HEAD>`
|
* Add `<SCRIPT type="text/javascript" src="dweb_transports_bundle.js"></SCRIPT>` to your `<HEAD>`
|
||||||
|
|
||||||
Then code like this should work.
|
Then code like this should work.
|
||||||
|
259
TransportWOLK.js
Normal file
259
TransportWOLK.js
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
/*
|
||||||
|
This Transport layers uses Wolk NoSQL + Cloudstore.
|
||||||
|
*/
|
||||||
|
const Url = require('url');
|
||||||
|
const WOLK = require('wolkjs').WOLK; //TODO: change to just WOLK once we understand everything
|
||||||
|
const stringify = require('canonical-json');
|
||||||
|
const debug = require('debug')('dweb-transports:wolk');
|
||||||
|
|
||||||
|
// Other Dweb modules
|
||||||
|
const errors = require('./Errors'); // Standard Dweb Errors
|
||||||
|
const Transport = require('./Transport.js'); // Base class for TransportXyz
|
||||||
|
const Transports = require('./Transports'); // Manage all Transports that are loaded
|
||||||
|
const utils = require('./utils'); // Utility functions
|
||||||
|
|
||||||
|
let defaultoptions = {
|
||||||
|
wolk_addr: "http://cloud.wolk.com:81", //"http://c1.wolk.com:80",
|
||||||
|
};
|
||||||
|
|
||||||
|
class TransportWOLK extends Transport {
|
||||||
|
/* Wolk specific transport */
|
||||||
|
constructor(options) {
|
||||||
|
super(options);
|
||||||
|
this.options = options; // Dictionary of options
|
||||||
|
this.wolk = undefined;
|
||||||
|
this.name = "WOLK"; // For console log etc
|
||||||
|
//TODO: Change name to WOLK once we understand everything
|
||||||
|
this.supportURLs = ['wolk'];
|
||||||
|
this.supportFunctions = [ 'fetch', 'store', 'connection', 'get', 'set', 'createReadStream' ];
|
||||||
|
|
||||||
|
this.status = Transport.STATUS_LOADED;
|
||||||
|
}
|
||||||
|
|
||||||
|
connection(url) {
|
||||||
|
console.log("WOLK connection call")
|
||||||
|
var wolknode = new WOLK();
|
||||||
|
//TODO: cloudstore connection needed
|
||||||
|
return wolknode
|
||||||
|
}
|
||||||
|
|
||||||
|
//stuff that happens b/f using ntwk bandwidth (config/connect/stuff)
|
||||||
|
static setup0(options) {
|
||||||
|
let combinedoptions = Transport.mergeoptions(defaultoptions, options.wolk);
|
||||||
|
debug("setup options=%o", combinedoptions);
|
||||||
|
let t = new TransportWOLK(combinedoptions);
|
||||||
|
t.wolk = new WOLK();
|
||||||
|
//var successinit = await Promise.all(t.wolk.init())
|
||||||
|
t.wolk.setProvider(t.options.wolk_addr);
|
||||||
|
Transports.addtransport(t);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
//make the connection
|
||||||
|
async p_setup1(cb) {
|
||||||
|
await this.wolk.init()
|
||||||
|
.then( async () => {
|
||||||
|
if( this.wolk.ecdsaKey == undefined || this.wolk.ecdsaKey == null ) {
|
||||||
|
var wolkName = "user" + Math.floor((Math.random() * 1000) + 1);
|
||||||
|
console.log("WOLK: createAccount because ecsaKey null")
|
||||||
|
await this.wolk.createAccount(wolkName, (err, hash) => {
|
||||||
|
if(err) { throw new Error("Error Creating Account: " + err); }
|
||||||
|
console.log("[WOLK] Account Created: [" + wolkName + "] hash: " + hash + " KEY: " + this.wolk.ecdsaKey)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
this.status = Transport.STATUS_STARTING; // Should display, but probably not refreshed in most case
|
||||||
|
if (cb) cb(this);
|
||||||
|
await this.p_status();
|
||||||
|
} catch(err) {
|
||||||
|
console.error(this.name, "failed to start" ,err);
|
||||||
|
this.status = Transport.STATUS_FAILED;
|
||||||
|
}
|
||||||
|
if (cb) cb(this);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
async p_status() {
|
||||||
|
/* Return an integer for the status of a transport see Transport */
|
||||||
|
return this.wolk.getLatestBlockNumber()
|
||||||
|
.then( (bn) => {
|
||||||
|
if (bn >= 0) {
|
||||||
|
console.log("[WOLK] STATUS: connected? [1] = BN: " + bn)
|
||||||
|
this.status = Transport.STATUS_CONNECTED;
|
||||||
|
} else {
|
||||||
|
console.log("[WOLK] STATUS: connected? [0] = BN: " + bn)
|
||||||
|
this.status = Transport.STATUS_FAILED;
|
||||||
|
}
|
||||||
|
return this.status;
|
||||||
|
})
|
||||||
|
.catch( (err) => { console.log("Error getting bn: " + err); })
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== DATA ======
|
||||||
|
async p_rawstore(chunk) {
|
||||||
|
/*
|
||||||
|
Store a blob of data onto the decentralised transport.
|
||||||
|
Returns a promise that resolves to the url of the data
|
||||||
|
|
||||||
|
:param string|Buffer data: Data to store - no assumptions made to size or content
|
||||||
|
:resolve string: url of data stored
|
||||||
|
*/
|
||||||
|
|
||||||
|
console.assert(chunk, "TransportWOLK.p_rawstore: requires chunkdata");
|
||||||
|
/* TODO:
|
||||||
|
const rawRes = this.wolk.setChunk(chunk);
|
||||||
|
if (rawRes.err) {
|
||||||
|
throw new errors.TransportError("Error encountered storing chunk: " + rawRes.err);
|
||||||
|
}
|
||||||
|
return "wolk://wolk/" + rawRes.h;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
parseWolkUrl(url) {
|
||||||
|
var url = Url.parse(url);
|
||||||
|
if(url.protocol != "wolk:") {
|
||||||
|
throw new errors.TransportError("WOLK Error encountered retrieving val: url (" + url.href + ") is not a valid WOLK url | protocol = " + url.protocol);
|
||||||
|
}
|
||||||
|
let wolkowner = url.host
|
||||||
|
var urlParts = url.path.split("/");
|
||||||
|
let wolkbucket = urlParts[1];
|
||||||
|
let wolkpath = url.path.substring(wolkbucket.length + 2);
|
||||||
|
var wolkurltype = "key"
|
||||||
|
if( wolkowner == "wolk" && wolkbucket == "chunk" ) {
|
||||||
|
wolkurltype = "chunk"
|
||||||
|
}
|
||||||
|
let wolkquery = url.query
|
||||||
|
return { owner: wolkowner, bucket: wolkbucket, path: wolkpath, urltype: wolkurltype, query: wolkquery }
|
||||||
|
}
|
||||||
|
|
||||||
|
async p_rawfetch(url) {
|
||||||
|
var wolkurl = this.parseWolkUrl(url)
|
||||||
|
/*
|
||||||
|
console.log("WOLK p_rawfetch url: " + JSON.stringify(wolkurl));
|
||||||
|
console.log("WOLK owner: " + wolkurl.owner);
|
||||||
|
console.log("WOLK bucket: " + wolkurl.bucket);
|
||||||
|
console.log("WOLK key: " + wolkurl.path);
|
||||||
|
console.log("WOLK query: " + wolkurl.query);
|
||||||
|
console.log("WOLK urltype: " + wolkurl.urltype);
|
||||||
|
*/
|
||||||
|
|
||||||
|
var responseData = ""
|
||||||
|
if( wolkurl.urltype == "key" ) {
|
||||||
|
console.log("[WOLK] Checking Wolk NoSQL for: " + url)
|
||||||
|
return this.wolk.getKey(wolkurl.owner, wolkurl.bucket, wolkurl.path, "latest")
|
||||||
|
.then(function(responseData) {
|
||||||
|
//TODO: error checking
|
||||||
|
console.log("WOLK Response: " + JSON.stringify(responseData));
|
||||||
|
return responseData;
|
||||||
|
})
|
||||||
|
.catch( (err) => {
|
||||||
|
throw new Error("ERROR: p_rawfetch - " + err);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=======KEY VALUE TABLES ========
|
||||||
|
async p_newdatabase(pubkey) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async p_newtable(pubkey, table) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async p_set(url, keyvalues, value) {
|
||||||
|
/*
|
||||||
|
Set key values
|
||||||
|
keyvalues: string (key) in which case value should be set there OR object in which case value is ignored
|
||||||
|
*/
|
||||||
|
var wolkurl = this.parseWolkUrl(url)
|
||||||
|
/*
|
||||||
|
console.log("WOLK p_set url: " + JSON.stringify(wolkurl));
|
||||||
|
console.log("WOLK owner: " + wolkurl.owner);
|
||||||
|
console.log("WOLK bucket: " + wolkurl.bucket);
|
||||||
|
console.log("WOLK key: " + wolkurl.path);
|
||||||
|
console.log("WOLK query: " + wolkurl.query);
|
||||||
|
console.log("WOLK urltype: " + wolkurl.urltype);
|
||||||
|
*/
|
||||||
|
if (typeof keyvalues === "string") {
|
||||||
|
return this.wolk.setKey(wolkurl.owner, wolkurl.bucket, keyvalues, stringify(value))
|
||||||
|
.then( (hash) => {
|
||||||
|
return hash;
|
||||||
|
})
|
||||||
|
.catch( (err) => {
|
||||||
|
throw new Error("TransportWOLK - Error setting key value pair: " + err)
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Store all key-value pairs without destroying any other key/value pairs previously set
|
||||||
|
//TODO: Why not support Arrays?
|
||||||
|
console.assert(!Array.isArray(keyvalues), "TransportWOLK - shouldnt be passsing an array as the keyvalues");
|
||||||
|
//TODO: better understand dictionary objects
|
||||||
|
/*
|
||||||
|
table.put(
|
||||||
|
Object.keys(keyvalues).reduce(
|
||||||
|
function(previous, key) {
|
||||||
|
previous[key] = stringify(keyvalues[key]);
|
||||||
|
return previous;
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async p_get(url, keys) {
|
||||||
|
var wolkurl = this.parseWolkUrl(url)
|
||||||
|
|
||||||
|
console.log("WOLK: getting url: " + JSON.stringify(wolkurl));
|
||||||
|
/*
|
||||||
|
console.log("WOLK owner: " + wolkurl.owner);
|
||||||
|
console.log("WOLK bucket: " + wolkurl.bucket);
|
||||||
|
console.log("WOLK key: " + wolkurl.path);
|
||||||
|
console.log("WOLK query: " + wolkurl.query);
|
||||||
|
console.log("WOLK urltype: " + wolkurl.urltype);
|
||||||
|
*/
|
||||||
|
if (Array.isArray(keys)) {
|
||||||
|
throw new errors.ToBeImplementedError("p_get(url, [keys]) isn't supported - because of ambiguity better to explicitly loop on set of keys");
|
||||||
|
/*
|
||||||
|
return keys.reduce(function(previous, key) {
|
||||||
|
let val = table.get(key);
|
||||||
|
previous[key] = typeof val === "string" ? JSON.parse(val) : val; // Handle undefined
|
||||||
|
return previous;
|
||||||
|
}, {});
|
||||||
|
*/
|
||||||
|
} else {
|
||||||
|
return this.wolk.getKey(wolkurl.owner, wolkurl.bucket, keys, "latest")
|
||||||
|
.then( (value) => { return value; })
|
||||||
|
.catch( (err) => {
|
||||||
|
throw new errors.TransportError("Error encountered getting keyvalues: " + err);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async p_delete(url, keys) {
|
||||||
|
var wolkurl = this.parseWolkUrl(url)
|
||||||
|
|
||||||
|
if ( typeof keys === "string") {
|
||||||
|
return this.wolk.deleteKey(wolkurl.owner, wolkurl.bucket, keys)
|
||||||
|
.then( (res) => { return res; })
|
||||||
|
.catch( (err) => { throw new errors.TransportError("Error deleting key(s): " + err)})
|
||||||
|
} else {
|
||||||
|
keys.map( (key) => {
|
||||||
|
this.wolk.deleteKey(wolkurl.owner, wolkurl.bucket, key)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async p_keys(url) {
|
||||||
|
var wolkurl = this.parseWolkUrl(url)
|
||||||
|
return this.listCollection(wolkurl.owner, wolkurl.bucket, {})
|
||||||
|
}
|
||||||
|
|
||||||
|
async p_getall(url) {
|
||||||
|
//TODO: difference between this and p_keys
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Transports._transportclasses["WOLK"] = TransportWOLK;
|
||||||
|
exports = module.exports = TransportWOLK;
|
@ -82,6 +82,12 @@ class Transports {
|
|||||||
// Find an http transport if it exists, so for example YJS can use it.
|
// Find an http transport if it exists, so for example YJS can use it.
|
||||||
return Transports._connected().find((t) => t.name === "HTTP")
|
return Transports._connected().find((t) => t.name === "HTTP")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static wolk() {
|
||||||
|
// Find a Wolk transport if it exists, so for example YJS can use it.
|
||||||
|
return Transports._connected().find((t) => t.name === "WOLK")
|
||||||
|
}
|
||||||
|
|
||||||
static ipfs() {
|
static ipfs() {
|
||||||
// Find an ipfs transport if it exists, so for example YJS can use it.
|
// Find an ipfs transport if it exists, so for example YJS can use it.
|
||||||
return Transports._connected().find((t) => t.name === "IPFS")
|
return Transports._connected().find((t) => t.name === "IPFS")
|
||||||
@ -653,7 +659,7 @@ class Transports {
|
|||||||
let tabbrevs = options.transports; // Array of transport abbreviations
|
let tabbrevs = options.transports; // Array of transport abbreviations
|
||||||
this._optionspaused = (options.paused || []).map(n => n.toUpperCase()); // Array of transports paused - defaults to none, upper cased
|
this._optionspaused = (options.paused || []).map(n => n.toUpperCase()); // Array of transports paused - defaults to none, upper cased
|
||||||
if (!(tabbrevs && tabbrevs.length)) { tabbrevs = options.defaulttransports || [] }
|
if (!(tabbrevs && tabbrevs.length)) { tabbrevs = options.defaulttransports || [] }
|
||||||
if (! tabbrevs.length) { tabbrevs = ["HTTP", "YJS", "IPFS", "WEBTORRENT", "GUN"]; } // SEE-OTHER-ADDTRANSPORT
|
if (! tabbrevs.length) { tabbrevs = ["HTTP", "YJS", "IPFS", "WEBTORRENT", "GUN", "WOLK"]; } // SEE-OTHER-ADDTRANSPORT
|
||||||
tabbrevs = tabbrevs.map(n => n.toUpperCase());
|
tabbrevs = tabbrevs.map(n => n.toUpperCase());
|
||||||
let transports = this.setup0(tabbrevs, options);
|
let transports = this.setup0(tabbrevs, options);
|
||||||
["statuscb", "mirror"].forEach(k => { if (options[k]) this[k] = options[k];} )
|
["statuscb", "mirror"].forEach(k => { if (options[k]) this[k] = options[k];} )
|
||||||
@ -667,8 +673,8 @@ class Transports {
|
|||||||
t.name);
|
t.name);
|
||||||
t.statuselement = el; // Save status element on transport
|
t.statuselement = el; // Save status element on transport
|
||||||
return el;
|
return el;
|
||||||
}
|
}))
|
||||||
)));
|
);
|
||||||
}
|
}
|
||||||
await this.p_setup1(this.refreshstatus);
|
await this.p_setup1(this.refreshstatus);
|
||||||
await this.p_setup2(this.refreshstatus);
|
await this.p_setup2(this.refreshstatus);
|
||||||
@ -710,8 +716,8 @@ class Transports {
|
|||||||
*/
|
*/
|
||||||
if (typeof url !== "string") url = Url.parse(url).href;
|
if (typeof url !== "string") url = Url.parse(url).href;
|
||||||
// In patterns below http or https; and :/ or :// are treated the same
|
// In patterns below http or https; and :/ or :// are treated the same
|
||||||
const gateways = ["dweb.me", "ipfs.io"]; // Kniwn gateways, may dynamically load this at some point
|
const gateways = ["dweb.me", "ipfs.io"]; // Known gateways, may dynamically load this at some point
|
||||||
const protocols = ["ipfs","gun","magnet","yjs","arc", "contenthash", "http", "https"];
|
const protocols = ["ipfs","gun","magnet","yjs","wolk","arc", "contenthash", "http", "https"];
|
||||||
const protocolsWantingDomains = ["arc", "http", "https"];
|
const protocolsWantingDomains = ["arc", "http", "https"];
|
||||||
const gatewaypatts = [ // Must be before patts because gateway names often start with a valid proto
|
const gatewaypatts = [ // Must be before patts because gateway names often start with a valid proto
|
||||||
/^http[s]?:[/]+([^/]+)[/](\w+)[/](.*)/i, // https://(gateway)/proto/(internal) + gateway in list (IPFS gateways. dweb.me)
|
/^http[s]?:[/]+([^/]+)[/](\w+)[/](.*)/i, // https://(gateway)/proto/(internal) + gateway in list (IPFS gateways. dweb.me)
|
||||||
|
1
index.js
1
index.js
@ -6,6 +6,7 @@ require("./TransportHTTP.js"); // Can access via window.DwebTransports._transp
|
|||||||
require("./TransportIPFS.js");
|
require("./TransportIPFS.js");
|
||||||
require("./TransportYJS.js");
|
require("./TransportYJS.js");
|
||||||
require("./TransportWEBTORRENT.js");
|
require("./TransportWEBTORRENT.js");
|
||||||
|
require("./TransportWOLK.js");
|
||||||
require("./TransportGUN.js");
|
require("./TransportGUN.js");
|
||||||
if (typeof window !== "undefined") { window.DwebTransports = DwebTransports; }
|
if (typeof window !== "undefined") { window.DwebTransports = DwebTransports; }
|
||||||
exports = module.exports = DwebTransports;
|
exports = module.exports = DwebTransports;
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
|
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
|
||||||
|
const webpack = require('webpack'); //to access built-in plugins
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: {
|
entry: {
|
||||||
'dweb-transports': './index.js',
|
'dweb-transports': './index.js',
|
||||||
@ -20,9 +22,16 @@ module.exports = {
|
|||||||
console: false
|
console: false
|
||||||
},
|
},
|
||||||
|
|
||||||
|
plugins: [
|
||||||
|
new webpack.EnvironmentPlugin({
|
||||||
|
WOLK_ENV: 'idb',
|
||||||
|
})
|
||||||
|
],
|
||||||
|
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
zlib: 'browserify-zlib-next'
|
zlib: 'browserify-zlib-next',
|
||||||
|
zlib: 'zlib'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
optimization: {
|
optimization: {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user