mirror of
https://github.com/amark/gun.git
synced 2025-06-06 14:16:44 +00:00
towards recomposition
This commit is contained in:
parent
f63760b81b
commit
baf5a52b7d
Binary file not shown.
@ -1,7 +1,7 @@
|
|||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var http = require('http');
|
var http = require('http');
|
||||||
var qs = require('querystring');
|
var qs = require('querystring');
|
||||||
var sync = require('./shotgun');
|
var sync = require('../../test/shotgun');
|
||||||
|
|
||||||
http.route = function(url){
|
http.route = function(url){
|
||||||
console.log(url);
|
console.log(url);
|
@ -1,5 +1,5 @@
|
|||||||
var sign = {};
|
var sign = {};
|
||||||
var gun = require('./shotgun');
|
var gun = require('../../test/shotgun');
|
||||||
|
|
||||||
sign.user = {}
|
sign.user = {}
|
||||||
sign.user.create = function(form, cb, shell){ // TODO: REDO THIS TO MATCH GUN
|
sign.user.create = function(form, cb, shell){ // TODO: REDO THIS TO MATCH GUN
|
||||||
@ -7,13 +7,30 @@ sign.user.create = function(form, cb, shell){ // TODO: REDO THIS TO MATCH GUN
|
|||||||
if(err || !user){ return cb(err) }
|
if(err || !user){ return cb(err) }
|
||||||
user = {key: user.key, salt: user.salt};
|
user = {key: user.key, salt: user.salt};
|
||||||
user.account = {email: form.email, registered: new Date().getTime()};
|
user.account = {email: form.email, registered: new Date().getTime()};
|
||||||
shell.set(user, function(){
|
gun.set(user).index('email/' + user.account.email);
|
||||||
console.log("yo bro, that user creation totally worked.");
|
|
||||||
}).index('email/' + user.account.email);
|
|
||||||
cb(null, user);
|
cb(null, user);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
gun.load('email/mark@accelsor.com')
|
||||||
|
.path('friends')
|
||||||
|
.match({name: "David Oliveros"})
|
||||||
|
.path('friends')
|
||||||
|
.match({activity: 'surfer'})
|
||||||
|
.get(function(surfer){
|
||||||
|
sendEmail("Mark wants to leanr how ot surf, and you are a friend of a friend");
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
gun.load()
|
||||||
|
|
||||||
|
here is a bunch of node indices
|
||||||
|
now for each combinatoric pair
|
||||||
|
find all possible paths between them
|
||||||
|
*/
|
||||||
|
|
||||||
sign.server = function(req, res){
|
sign.server = function(req, res){
|
||||||
console.log("sign.server", req.body);
|
console.log("sign.server", req.body);
|
||||||
if(!req.body || !req.body.email){ return res.emit('end', {err: "That email does not exist."}) }
|
if(!req.body || !req.body.email){ return res.emit('end', {err: "That email does not exist."}) }
|
94
gun2.js
94
gun2.js
@ -13,9 +13,13 @@
|
|||||||
Gun.chain._.opt = {};
|
Gun.chain._.opt = {};
|
||||||
Gun.chain._.nodes = {};
|
Gun.chain._.nodes = {};
|
||||||
Gun.chain._.chain = {};
|
Gun.chain._.chain = {};
|
||||||
|
Gun.chain._.trace = [];
|
||||||
Gun.chain._.indices = {};
|
Gun.chain._.indices = {};
|
||||||
Gun.chain.init = function(opt, stun){ // idempotently update or set options
|
Gun.chain.init = function(opt, stun){ // idempotently update or set options
|
||||||
var gun = this;
|
var gun = this;
|
||||||
|
gun._.events = gun._.events || Gun.on.split(); // we may not want it global for each gun instance?
|
||||||
|
gun._.events.trace = gun._.events.trace || 0;
|
||||||
|
gun._.events.at = gun._.events.at || 0;
|
||||||
if(Gun.text.is(opt)){ opt = {peers: opt} }
|
if(Gun.text.is(opt)){ opt = {peers: opt} }
|
||||||
if(Gun.list.is(opt)){ opt = {peers: opt} }
|
if(Gun.list.is(opt)){ opt = {peers: opt} }
|
||||||
if(Gun.text.is(opt.peers)){ opt.peers = [opt.peers] }
|
if(Gun.text.is(opt.peers)){ opt.peers = [opt.peers] }
|
||||||
@ -30,11 +34,11 @@
|
|||||||
if(!stun){ Gun.on('init').emit(gun, opt) }
|
if(!stun){ Gun.on('init').emit(gun, opt) }
|
||||||
return gun;
|
return gun;
|
||||||
}
|
}
|
||||||
Gun.chain.load = function(index, cb){
|
Gun.chain.load = function(index, cb, opt){
|
||||||
var gun = this;
|
var gun = this;
|
||||||
cb = cb || function(){};
|
cb = cb || function(){};
|
||||||
if(cb.node = gun._.indices[index]){ // set this to the current node, too!
|
if(cb.node = gun._.indices[index]){ // set this to the current node, too!
|
||||||
console.log("from gun");
|
console.log("from gun"); // remember to do all the same stack stuff here also!
|
||||||
return cb(cb.node), gun;
|
return cb(cb.node), gun;
|
||||||
}
|
}
|
||||||
cb.fn = function(){}
|
cb.fn = function(){}
|
||||||
@ -45,10 +49,13 @@
|
|||||||
gun._.loaded = (gun._.loaded || 0) + 1; // TODO: loading should be idempotent even if we got an err or no data
|
gun._.loaded = (gun._.loaded || 0) + 1; // TODO: loading should be idempotent even if we got an err or no data
|
||||||
if(err){ return (gun._.chain.dud||cb.fn)(err) }
|
if(err){ return (gun._.chain.dud||cb.fn)(err) }
|
||||||
if(!data){ return (gun._.chain.blank||cb.fn)() }
|
if(!data){ return (gun._.chain.blank||cb.fn)() }
|
||||||
var nodes = {}; nodes[data._[own.sym.id]] = data;// missing: transform data, merging it! NO, THIS IS DONE WRONG, do a real check.
|
var nodes = {}, node;
|
||||||
|
nodes[data._[own.sym.id]] = data;// missing: transform data, merging it! NO, THIS IS DONE WRONG, do a real check.
|
||||||
Gun.union(gun._.nodes, nodes);
|
Gun.union(gun._.nodes, nodes);
|
||||||
return cb(gun._.indices[index] = gun._.nodes[data._[own.sym.id]]);
|
node = gun._.indices[index] = gun._.nodes[data._[own.sym.id]];
|
||||||
});
|
cb(node); // WARNING: Need to return a frozen copy of the object! But now the internal system is using this too... :/
|
||||||
|
gun._.events.on(gun._.events.at += 1).emit(node);
|
||||||
|
}, opt);
|
||||||
} else {
|
} else {
|
||||||
console.log("Warning! You have no persistence layer to load from!");
|
console.log("Warning! You have no persistence layer to load from!");
|
||||||
}
|
}
|
||||||
@ -60,7 +67,7 @@
|
|||||||
this._.indices[index] = this._.node;
|
this._.indices[index] = this._.node;
|
||||||
if(Gun.fns.is(this._.opt.hook.index)){
|
if(Gun.fns.is(this._.opt.hook.index)){
|
||||||
this._.opt.hook.index(index, this._.node, function(err, data){
|
this._.opt.hook.index(index, this._.node, function(err, data){
|
||||||
console.log("index made");
|
console.log("index made", index);
|
||||||
if(err){ return cb(err) }
|
if(err){ return cb(err) }
|
||||||
return cb(null);
|
return cb(null);
|
||||||
});
|
});
|
||||||
@ -70,20 +77,51 @@
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
Gun.chain.path = function(path){ // The focal point follows the path
|
Gun.chain.path = function(path){ // The focal point follows the path
|
||||||
|
var gun = this;
|
||||||
|
path = path.split('.');
|
||||||
|
console.log("PATH stack trace", gun._.events.trace + 1);
|
||||||
|
gun._.events.on(gun._.events.trace += 1).event(function trace(node){
|
||||||
|
console.log("stack at", gun._.events.at);
|
||||||
|
if(!path.length){ // if the path resolves to another node, we finish here
|
||||||
|
console.log("PATH resolved with node");
|
||||||
|
gun._.events.on(gun._.events.at += 1).emit(node);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var key = path.shift()
|
||||||
|
, val = node[key];
|
||||||
|
if(key = Gun.ify.is.id(val)){ // we might end on a link, so we must resolve
|
||||||
|
gun.load(key, trace, {id: true}).blank(function(){ }).dud(function(){ }); // TODO: Need to map these to the real blank/dud
|
||||||
|
} else {
|
||||||
|
if(path.length){ // we cannot go any further, despite the fact there is more path, which means the thing we wanted does not exist
|
||||||
|
console.log("PATH failed to resolve");
|
||||||
|
gun._.events.on(gun._.events.at += 1).emit();
|
||||||
|
} else { // we are done, and this should be the value we wanted.
|
||||||
|
console.log("PATH resolved", val);
|
||||||
|
gun._.events.on(gun._.events.at += 1).emit(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return gun;
|
||||||
}
|
}
|
||||||
Gun.chain.get = function(cb){
|
Gun.chain.get = function(cb){ // WARNING! Need to return a frozen copy of the object.
|
||||||
|
var gun = this;
|
||||||
|
console.log("GET stack trace", gun._.events.trace + 1);
|
||||||
|
gun._.events.on(gun._.events.trace += 1).event(function(node){
|
||||||
|
console.log("GOT", node);
|
||||||
|
cb(node);
|
||||||
|
});
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
ACID compliant, unfortunately ACID's vocabulary is confusing:
|
ACID compliant, unfortunately the vocabulary is vague, as such the following is an explicit definition:
|
||||||
A - Atomic, if you set a full node, or nodes of nodes, if any value is in error then nothing will be set.
|
A - Atomic, if you set a full node, or nodes of nodes, if any value is in error then nothing will be set.
|
||||||
If you want sets to be independent of each other, you need to set individual keys with their value.
|
If you want sets to be independent of each other, you need to set each piece of the data individually.
|
||||||
C - Consistency, if you use any reserved symbols or similar, the operation will be rejected.
|
C - Consistency, if you use any reserved symbols or similar, the operation will be rejected as it could lead to an invalid read and thus an invalid state.
|
||||||
I - Isolation, the hypothetical amnesia machine guarantees the relative state of each transaction, across every peer.
|
I - Isolation, the conflict resolution algorithm guarantees idempotent transactions, across every peer, regardless of any partition,
|
||||||
D - Durability, if the acknowledgement receipt is received, then the data is guaranteed to have persisted.
|
including a peer acting by itself or one having been disconnected from the network.
|
||||||
However, by the time it is received, the data that was set may already be out of date.
|
D - Durability, if the acknowledgement receipt is received, then the state at which the final persistence hook was called on is guaranteed to have been written.
|
||||||
The current data is already available to be checked and compared if need be.
|
The live state at point of confirmation may or may not be different than when it was called.
|
||||||
|
If this causes any application-level concern, it can compare against the live data by immediately reading it, or accessing the logs if enabled.
|
||||||
*/
|
*/
|
||||||
Gun.chain.set = function(val, cb){
|
Gun.chain.set = function(val, cb){
|
||||||
var gun = this, set;
|
var gun = this, set;
|
||||||
@ -218,7 +256,7 @@
|
|||||||
Gun.on = (function(){
|
Gun.on = (function(){
|
||||||
function On(on){
|
function On(on){
|
||||||
var e = On.is(this)? this : events;
|
var e = On.is(this)? this : events;
|
||||||
return e._ = e._ || {}, e._.on = on, e;
|
return e._ = e._ || {}, e._.on = Gun.text.ify(on), e;
|
||||||
}
|
}
|
||||||
On.is = function(on){ return (on instanceof On)? true : false }
|
On.is = function(on){ return (on instanceof On)? true : false }
|
||||||
On.split = function(){ return new On() }
|
On.split = function(){ return new On() }
|
||||||
@ -238,11 +276,11 @@
|
|||||||
}))){ delete this._.events[on] }
|
}))){ delete this._.events[on] }
|
||||||
}
|
}
|
||||||
On.echo.event = function(as, i){
|
On.echo.event = function(as, i){
|
||||||
var on = this._.on;
|
var on = this._.on, e;
|
||||||
if(!on || !as){ return }
|
if(!on || !as){ return }
|
||||||
this._.events = this._.events || {};
|
this._.events = this._.events || {};
|
||||||
on = this._.events[on] = this._.events[on] || (this._.events[on] = [])
|
on = this._.events[on] = this._.events[on] || (this._.events[on] = []);
|
||||||
, e = {as: as, i: i || 0, off: function(){ return !(e.as = false) }};
|
e = {as: as, i: i || 0, off: function(){ return !(e.as = false) }};
|
||||||
return on.push(e), on.sort(On.sort), e;
|
return on.push(e), on.sort(On.sort), e;
|
||||||
}
|
}
|
||||||
On.echo.once = function(as, i){
|
On.echo.once = function(as, i){
|
||||||
@ -294,10 +332,17 @@
|
|||||||
return {converge: true, incoming: true};
|
return {converge: true, incoming: true};
|
||||||
}
|
}
|
||||||
if(incomingState === currentState){
|
if(incomingState === currentState){
|
||||||
if(incomingValue === currentValue){
|
if(incomingValue === currentValue){ // Note: while these are practically the same, the deltas could be technically different
|
||||||
// Note: while these are practically the same, the deltas could be technically different
|
|
||||||
return {state: true};
|
return {state: true};
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
The following is a naive implementation, but will always work.
|
||||||
|
Never change it unless you have specific needs that absolutely require it.
|
||||||
|
If changed, your data will diverge unless you guarantee every peer's algorithm has also been changed to be the same.
|
||||||
|
As a result, it is highly discouraged to modify despite the fact that it is naive,
|
||||||
|
because convergence (data integrity) is generally more important.
|
||||||
|
Any difference in this algorithm must be given a new and different name.
|
||||||
|
*/
|
||||||
if(String(incomingValue) < String(currentValue)){ // String only works on primitive values!
|
if(String(incomingValue) < String(currentValue)){ // String only works on primitive values!
|
||||||
return {converge: true, current: true};
|
return {converge: true, current: true};
|
||||||
}
|
}
|
||||||
@ -479,6 +524,13 @@
|
|||||||
|| Gun.text.is(v)){
|
|| Gun.text.is(v)){
|
||||||
return true; // simple values
|
return true; // simple values
|
||||||
}
|
}
|
||||||
|
var yes;
|
||||||
|
if(yes = Gun.ify.is.id(v)){
|
||||||
|
return yes;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Gun.ify.is.id = function(v){
|
||||||
if(Gun.obj.is(v)){
|
if(Gun.obj.is(v)){
|
||||||
var yes;
|
var yes;
|
||||||
Gun.obj.map(v, function(id, key){
|
Gun.obj.map(v, function(id, key){
|
||||||
|
15
shots2.js
15
shots2.js
@ -11,15 +11,20 @@
|
|||||||
s3.nodes = s3.nodes || opt.s3.nodes || '_/nodes/';
|
s3.nodes = s3.nodes || opt.s3.nodes || '_/nodes/';
|
||||||
gun._.opt.batch = opt.batch || gun._.opt.batch || 10;
|
gun._.opt.batch = opt.batch || gun._.opt.batch || 10;
|
||||||
gun._.opt.throttle = opt.throttle || gun._.opt.throttle || 2;
|
gun._.opt.throttle = opt.throttle || gun._.opt.throttle || 2;
|
||||||
if(!gun._.opt.keepDefaultMaxSockets){ require('http').globalAgent.maxSockets = 999 } // because the default is 5, sad face.
|
if(!gun._.opt.keepDefaultMaxSockets){ require('http').globalAgent.maxSockets = 999 } // we shouldn't do this globally! But because the default is 5, sad face.
|
||||||
|
|
||||||
s3.load = s3.load || function(index, cb, direct){
|
s3.load = s3.load || function(index, cb, opt){
|
||||||
cb = cb || function(){};
|
cb = cb || function(){};
|
||||||
s3.get(direct? index : s3.path + s3.indices + index, function(err, data, text, meta){
|
opt = opt || {};
|
||||||
|
if(opt.id){
|
||||||
|
index = s3.path + s3.nodes + index;
|
||||||
|
} else {
|
||||||
|
index = s3.path + s3.indices + index;
|
||||||
|
}
|
||||||
|
s3.get(index, function(err, data, text, meta){
|
||||||
console.log('via s3', index);
|
console.log('via s3', index);
|
||||||
if(meta && (index = meta[Gun.sym.id])){
|
if(meta && (index = meta[Gun.sym.id])){
|
||||||
console.log("fetch pointer");
|
return s3.load(index, cb, {id: true});
|
||||||
return s3.load(s3.path + s3.nodes + index, cb, true);
|
|
||||||
}
|
}
|
||||||
if(err && err.statusCode == 404){
|
if(err && err.statusCode == 404){
|
||||||
err = null; // we want a difference between 'unfound' (data is null) and 'error' (keys are wrong)
|
err = null; // we want a difference between 'unfound' (data is null) and 'error' (keys are wrong)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
describe('Gun', function(){
|
describe('Gun', function(){
|
||||||
var Gun = require('../gun2');
|
var Gun = require('../gun2');
|
||||||
|
|
||||||
it('ify', function(){return;
|
it('ify', function(){
|
||||||
var data, test;
|
var data, test;
|
||||||
|
|
||||||
data = {a: false, b: true, c: 0, d: 1, e: '', f: 'g', h: null};
|
data = {a: false, b: true, c: 0, d: 1, e: '', f: 'g', h: null};
|
||||||
@ -51,7 +51,7 @@ describe('Gun', function(){
|
|||||||
console.log(test.nodes);
|
console.log(test.nodes);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('ify', function(){
|
it('union', function(){
|
||||||
var graph, prime;
|
var graph, prime;
|
||||||
|
|
||||||
graph = Gun.ify({a: false, b: true, c: 0, d: 1, e: '', f: 'g', h: null}).nodes;
|
graph = Gun.ify({a: false, b: true, c: 0, d: 1, e: '', f: 'g', h: null}).nodes;
|
||||||
@ -60,4 +60,16 @@ describe('Gun', function(){
|
|||||||
Gun.union(graph, prime);
|
Gun.union(graph, prime);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('path', function(done){
|
||||||
|
this.timeout(9000);
|
||||||
|
var gun = require('./shotgun');
|
||||||
|
gun.load('email/mark@accelsor.com')
|
||||||
|
.path('account.email')
|
||||||
|
.get(function(val){
|
||||||
|
console.log("val!", val);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
console.log("________________________");
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
@ -4,12 +4,12 @@ if(process.env.LIVE || (process.env.NODE_ENV === 'production')){
|
|||||||
//process.env['redis-install'] = '/tmp';
|
//process.env['redis-install'] = '/tmp';
|
||||||
} else {
|
} else {
|
||||||
// Keys are hosted outside this folder, you must provide your own with environment variables.
|
// Keys are hosted outside this folder, you must provide your own with environment variables.
|
||||||
if((require('fs').existsSync||require('path').existsSync)(keys = '../../../../linux/.ssh/keys-gun.js')){
|
if((require('fs').existsSync||require('path').existsSync)(keys = __dirname + '/../../../linux/.ssh/keys-gun.js')){
|
||||||
keys = require(keys);
|
keys = require(keys);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var Gun = require('../../shots2');
|
var Gun = require('../shots2');
|
||||||
var gun = Gun({
|
var gun = Gun({
|
||||||
peers: 'http://localhost:8888/gun'
|
peers: 'http://localhost:8888/gun'
|
||||||
,s3: keys
|
,s3: keys
|
@ -1,4 +1,4 @@
|
|||||||
module.exports=require('theory')
|
module.exports=require('theory');
|
||||||
('tests',function(a){
|
('tests',function(a){
|
||||||
if(root.node){
|
if(root.node){
|
||||||
console.log("tests live!");
|
console.log("tests live!");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user