Merge pull request #13 from rodneywitcher/master

Adding WOLK Transport
This commit is contained in:
Mitra Ardron 2019-03-20 16:35:17 -07:00 committed by GitHub
commit 003efedb4d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 286 additions and 11 deletions

View File

@ -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
View 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;

View File

@ -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)

View File

@ -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;

View File

@ -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: {