mirror of
https://github.com/amark/gun.git
synced 2025-06-03 20:56:43 +00:00
tests pass, drivers fixed!
This commit is contained in:
parent
566c5c1cd6
commit
2abfc17c14
125
README.md
125
README.md
@ -1,10 +1,12 @@
|
||||
gun [](https://travis-ci.org/amark/gun)
|
||||
gun [](https://travis-ci.org/amark/gun) [](https://gitter.im/amark/gun?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
===
|
||||
|
||||
GUN is a realtime, decentralized, embedded, graph database engine.
|
||||
|
||||
## Getting Started
|
||||
|
||||
For the browser, try out this [tutorial](https://dl.dropboxusercontent.com/u/4374976/gun/web/think.html). This README is for GUN servers.
|
||||
|
||||
If you do not have [node](http://nodejs.org/) or [npm](https://www.npmjs.com/), read [this](https://github.com/amark/gun/blob/master/examples/install.sh) first.
|
||||
Then in your terminal, run:
|
||||
|
||||
@ -35,42 +37,21 @@ These are the default persistence layers, they are modular and can be replaced o
|
||||
|
||||
Using S3 is recommended for deployment, and using a file is recommended for local development.
|
||||
|
||||
Now you can save your first object, and create a reference to it.
|
||||
## Demos
|
||||
|
||||
```javascript
|
||||
gun.set({ hello: 'world' }).key('my/first/data');
|
||||
```
|
||||
|
||||
Altogether, try it with the node hello world web server which will reply with your data.
|
||||
|
||||
```javascript
|
||||
var Gun = require('gun');
|
||||
var gun = Gun({ file: 'data.json' });
|
||||
gun.set({ hello: 'world' }).key('my/first/data');
|
||||
|
||||
var http = require('http');
|
||||
http.createServer(function(req, res){
|
||||
gun.load('my/first/data', function(err, data){
|
||||
res.writeHead(200, {'Content-Type': 'application/json'});
|
||||
res.end(JSON.stringify(data));
|
||||
});
|
||||
}).listen(1337, '127.0.0.1');
|
||||
console.log('Server running at http://127.0.0.1:1337/');
|
||||
```
|
||||
|
||||
Fire up your browser and hit that URL - you'll see your data, plus some gun specific metadata.
|
||||
|
||||
## Examples
|
||||
|
||||
Try out some online [examples](http://gunjs.herokuapp.com/) or run them yourself with the following command:
|
||||
The examples included in this repo are online [here](http://gunjs.herokuapp.com/), you can run them locally by:
|
||||
|
||||
```bash
|
||||
git clone http://github.com/amark/gun
|
||||
cd gun/examples && npm install
|
||||
node express.js 8080
|
||||
sudo npm install gun
|
||||
cd node_modules/gun
|
||||
node examples/http.js 8080
|
||||
```
|
||||
Then visit [http://localhost:8080](http://localhost:8080) in your browser.
|
||||
|
||||
Then visit [http://localhost:8080](http://localhost:8080) in your browser. If that did not work it is probably because npm installed to a global directory, to fix this try `mkdir node_modules` in your desired directory and re-run the above commands.
|
||||
|
||||
## WARNINGS
|
||||
|
||||
Version 0.2.0 breaks **everything** from 0.1.x, see [#54](/../../issues/54) to migrate (`.all` is not implemented yet). GUN is not stable, and therefore should not be trusted in a production environment.
|
||||
|
||||
## API
|
||||
|
||||
@ -87,20 +68,20 @@ In gun, it can be helpful to think of everything as field/value pairs. For examp
|
||||
"email": "mark@gunDB.io"
|
||||
}
|
||||
```
|
||||
Now, we want to save this object to a key called `usernames/marknadal`. We can do that like this:
|
||||
Now, we want to save this object to a key called `'usernames/marknadal'`. We can do that like this:
|
||||
|
||||
```javascript
|
||||
gun.set({
|
||||
gun.put({
|
||||
username: "marknadal",
|
||||
name: "Mark Nadal",
|
||||
email: "mark@gunDB.io"
|
||||
}).key('usernames/marknadal');
|
||||
```
|
||||
|
||||
We can also pass `set` a callback that can be used to handle errors:
|
||||
We can also pass `put` a callback that can be used to handle errors:
|
||||
|
||||
```javascript
|
||||
gun.set({
|
||||
gun.put({
|
||||
username: "marknadal",
|
||||
name: "Mark Nadal",
|
||||
email: "mark@gunDB.io"
|
||||
@ -114,33 +95,40 @@ gun.set({
|
||||
Once we have some data stored in gun, we need a way to get them out again. Retrieving the data that we just stored would look like this:
|
||||
|
||||
```javascript
|
||||
gun.load('usernames/marknadal').get(function(user){
|
||||
gun.get('usernames/marknadal').val(function(user){
|
||||
console.log(user.name); // Prints `Mark Nadal` to the console
|
||||
});
|
||||
```
|
||||
|
||||
Basically, this tells gun to check `usernames/marknadal`, and then return the object it finds associated with it. For more information, including how to save relational or document based data, [check out the wiki](https://github.com/amark/gun/wiki).
|
||||
Basically, this tells gun to check `'usernames/marknadal'`, and then return the object it finds associated with it. For more information, including how to save relational or document based data, [check out the wiki](https://github.com/amark/gun/wiki).
|
||||
|
||||
---
|
||||
|
||||
## YOU
|
||||
We're just getting started, so join us! Being lonely is never any fun, especially when programming.
|
||||
I want to help you, because my goal is for GUN to be the easiest database ever.
|
||||
That means if you ever get stuck on something for longer than 5 minutes,
|
||||
you should talk to me so I can help you solve it.
|
||||
Your input will then help me improve gun.
|
||||
We are also really open to contributions! GUN is easy to extend and customize:
|
||||
## YOU
|
||||
Being lonely is never any fun, especially when programming.
|
||||
Our goal is for GUN to be the easiest database ever,
|
||||
which means if you ever get stuck on something for longer than 5 minutes,
|
||||
let us know so we can help you. Your input is invaluable,
|
||||
as it enables us where to refine GUN. So drop us a line in the [](https://gitter.im/amark/gun?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)! Or join the [mail list](https://groups.google.com/forum/#!forum/g-u-n).
|
||||
|
||||
Thanks to the following people who have contributed to GUN, via code, issues, or conversation:
|
||||
|
||||
[agborkowski](https://github.com/agborkowski), [alexlafroscia](https://github.com/alexlafroscia), [anubiann00b](https://github.com/anubiann00b), [bromagosa](https://github.com/bromagosa), [coolaj86](https://github.com/coolaj86), [d-oliveros](https://github.com/d-oliveros), [danscan](https://github.com/danscan), [forrestjt](https://github.com/forrestjt), [gedw99](https://github.com/gedw99), [HelloCodeMing](https://github.com/HelloCodeMing), [JosePedroDias](https://github.com/josepedrodias), [onetom](https://github.com/onetom), [ndarilek](https://github.com/ndarilek), [phpnode](https://github.com/phpnode), [riston](https://github.com/riston), [rootsical](https://github.com/rootsical), [rrrene](https://github.com/rrrene), [ssr1ram](https://github.com/ssr1ram), [Xe](https://github.com/Xe), [zot](https://github.com/zot)
|
||||
|
||||
This list of contributors was manually compiled, alphabetically sorted. If we missed you, please submit an issue so we can get you added!
|
||||
|
||||
## Contribute
|
||||
|
||||
Extending GUN or writing modules for it is as simple as:
|
||||
|
||||
`Gun.on('opt').event(function(gun, opt){ /* Your module here! */ })`
|
||||
|
||||
It is also important to us that your database is not a magical black box.
|
||||
So often our questions get dismissed with "its complicated hard low level stuff, let the experts handle it."
|
||||
And we do not think that attitude will generate any progress for people.
|
||||
Instead, we want to make everyone an expert by actually getting really good at explaining the concepts.
|
||||
So join our community, in the quest of learning cool things and helping yourself and others build awesome technology.
|
||||
We also want our database to be comprehensible, not some magical black box.
|
||||
So often database questions get dismissed with "its complicated hard low level stuff, let the experts handle it".
|
||||
That attitude prevents progress, instead we welcome teaching people and listening to new perspectives.
|
||||
Join along side us in a quest to learn cool things and help others build awesome technology!
|
||||
|
||||
- [](https://gitter.im/amark/gun?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) (all chats relating to GUN and development should be here! IRC style)
|
||||
- Google Group: https://groups.google.com/forum/#!forum/g-u-n (for slower threaded discussions)
|
||||
We need help on the following roadmap.
|
||||
|
||||
## Ahead
|
||||
- ~~Realtime push to the browser~~
|
||||
@ -151,40 +139,11 @@ So join our community, in the quest of learning cool things and helping yourself
|
||||
- Test more
|
||||
- Bug fixes
|
||||
- Data Structures:
|
||||
- ~~Groups~~
|
||||
- Linked Lists
|
||||
- Collections (hybrid: linked-groups/paginated-lists)
|
||||
- ~~Sets~~ (Table/Collections, Unordered Lists)
|
||||
- CRDTs
|
||||
- OT
|
||||
- Query:
|
||||
- SQL
|
||||
- MongoDB Query Documents
|
||||
- Neo4j Cypher
|
||||
- Gremlin Query Language
|
||||
|
||||
|
||||
## Contributors
|
||||
|
||||
Thanks to the following people who have contributed to GUN:
|
||||
- [agborkowski](https://github.com/agborkowski)
|
||||
- [alexlafroscia](https://github.com/alexlafroscia)
|
||||
- [anubiann00b](https://github.com/anubiann00b)
|
||||
- [bromagosa](https://github.com/bromagosa)
|
||||
- [coolaj86](https://github.com/coolaj86)
|
||||
- [d-oliveros](https://github.com/d-oliveros)
|
||||
- [danscan](https://github.com/danscan)
|
||||
- [forrestjt](https://github.com/forrestjt)
|
||||
- [gedw99](https://github.com/gedw99)
|
||||
- [HelloCodeMing](https://github.com/HelloCodeMing)
|
||||
- [JosePedroDias](https://github.com/josepedrodias)
|
||||
- [onetom](https://github.com/onetom)
|
||||
- [ndarilek](https://github.com/ndarilek)
|
||||
- [phpnode](https://github.com/phpnode)
|
||||
- [riston](https://github.com/riston)
|
||||
- [rootsical](https://github.com/rootsical)
|
||||
- [rrrene](https://github.com/rrrene)
|
||||
- [ssr1ram](https://github.com/ssr1ram)
|
||||
- [Xe](https://github.com/Xe)
|
||||
- [zot](https://github.com/zot)
|
||||
|
||||
This list of contributors was manually compiled; if you have contributed in code, issues, or conversation and your GitHub username is not listed, please submit an issue so we can get you added!
|
||||
- Gremlin Query Language
|
@ -11,20 +11,18 @@
|
||||
function ready(){
|
||||
var $ = document.querySelector.bind(document);
|
||||
var gun = Gun(location.origin + '/gun').get('example/todo/data');
|
||||
gun.not(function(){
|
||||
return this.put({hello: "world!"}).key('example/todo/data');
|
||||
}).on(function renderToDo(val){
|
||||
gun.on(function renderToDo(val){
|
||||
var todoHTML = '';
|
||||
for(key in val) {
|
||||
if(!val[key] || key == '_') continue;
|
||||
todoHTML += '<li style="width:400px;height:2em;">' + (val[key]||'').toString().replace(/\</ig, '<') +
|
||||
'<button style="float:right;" onclick=removeToDo("'+key+'")>X</button></li>';
|
||||
for(field in val) {
|
||||
if(!val[field] || field == '_') continue;
|
||||
todoHTML += '<li style="width:400px;height:2em;">'
|
||||
+ (val[field]||'').toString().replace(/\</ig, '<')
|
||||
+ '<button style="float:right;" onclick=removeToDo("'+field+'")>X</button></li>';
|
||||
}
|
||||
$("#todos").innerHTML = todoHTML;
|
||||
});
|
||||
$("#addToDo").onsubmit = function(){
|
||||
var id = randomId();
|
||||
gun.path(id).put(($("#todoItem").value||'').toString().replace(/\</ig, '<'));
|
||||
gun.set(($("#todoItem").value||'').toString().replace(/\</ig, '<'));
|
||||
$("#todoItem").value = "";
|
||||
return false;
|
||||
};
|
||||
|
20
gun.js
20
gun.js
@ -380,6 +380,7 @@
|
||||
}, gun._.at('null').emit({key: ctx.key, GET: 'NULL'});
|
||||
}
|
||||
var dat = ctx.data = {};
|
||||
if(Gun.obj.empty(data)){ return cb.call(gun, null, data) }
|
||||
if(!Gun.is.graph(data, function(node, soul, map){
|
||||
if(err = Gun.union(gun, node).err){ return cb.call(gun, err, data) }
|
||||
/*dat[soul] = Gun.union.pseudo(soul); map(function(val, field){
|
||||
@ -537,10 +538,8 @@
|
||||
ctx[$.soul + $.field] = true; // TODO: unregister instead?
|
||||
return cb.call(gun, node[$.field], $.field || $.at);
|
||||
}
|
||||
console.log("VAL VAL VAL VAL VAL", delta, gun.__.meta($.soul));
|
||||
if(ctx[$.soul] || !gun.__.meta($.soul).end){ return } // TODO: Add opt to change number of terminations.
|
||||
ctx[$.soul] = true; // TODO: unregister instead?
|
||||
console.log("CTX", ctx); // MARK COME BACK HERE!!! TODO!!!
|
||||
if(ctx[$.soul] || ($.key && ctx[$.key]) || !gun.__.meta($.soul).end){ return } // TODO: Add opt to change number of terminations.
|
||||
ctx[$.soul] = ctx[$.key] = true; // TODO: unregister instead?
|
||||
cb.call(gun, Gun.obj.copy(node), $.field || $.at);
|
||||
}, {raw: true});
|
||||
|
||||
@ -555,7 +554,9 @@
|
||||
|
||||
gun._.at('soul').event(function($){ // TODO: once per soul on graph. (?)
|
||||
if(ctx[$.soul]){
|
||||
ctx[$.soul](gun.__.graph[$.soul], $);
|
||||
if(opt.raw){
|
||||
ctx[$.soul](gun.__.graph[$.soul], $); // TODO: we get duplicate ons, once here and once from HAM.
|
||||
}
|
||||
} else {
|
||||
(ctx[$.soul] = function(delta, $$){
|
||||
var $$ = $$ || $, node = gun.__.graph[$$.soul];
|
||||
@ -684,6 +685,7 @@
|
||||
gun._.at('soul').emit({soul: s, field: null, from: soul, at: field, MAP: 'SOUL'});
|
||||
} else {
|
||||
if(opt.node){ return } // {node: true} maps over only sub nodes.
|
||||
console.log("trigger next thing", field, val);
|
||||
cb.call(gun, val, field);
|
||||
gun._.at('soul').emit({soul: soul, field: field, MAP: 'SOUL'});
|
||||
}
|
||||
@ -991,6 +993,7 @@
|
||||
tab.get = tab.get || function(key, cb, opt){
|
||||
if(!key){ return }
|
||||
cb = cb || function(){};
|
||||
cb.GET = true;
|
||||
(opt = opt || {}).url = opt.url || {};
|
||||
opt.headers = Gun.obj.copy(tab.headers);
|
||||
if(Gun.is.soul(key)){
|
||||
@ -1003,7 +1006,8 @@
|
||||
var path = (path = Gun.is.soul(key))? tab.prefix + tab.prenode + path
|
||||
: tab.prefix + tab.prekey + key, node = store.get(path), graph, soul;
|
||||
if(Gun.is.node(node)){
|
||||
(graph = {})[soul = Gun.is.soul.on(node)] = node;
|
||||
(cb.graph = cb.graph || {}
|
||||
)[soul = Gun.is.soul.on(node)] = (graph = {})[soul] = cb.node = node;
|
||||
cb(null, graph);
|
||||
(graph = {})[soul] = Gun.union.pseudo(soul); // end.
|
||||
return cb(null, graph);
|
||||
@ -1019,13 +1023,13 @@
|
||||
if(!p.graph && !Gun.obj.empty(cb.graph)){ // if we have local data
|
||||
tab.put(p.graph = cb.graph, function(e,r){ // then sync it if we haven't already
|
||||
Gun.log("Stateless handshake sync:", e, r);
|
||||
}, {peers: tab.peers(url)}); // to the peer.
|
||||
}, {peers: tab.peers(url)}); // to the peer. // TODO: This forces local to flush again, not necessary.
|
||||
// TODO: What about syncing our keys up?
|
||||
}
|
||||
Gun.is.graph(reply.body, function(node, soul){ // make sure for each received node
|
||||
if(!Gun.is.soul(key)){ tab.key(key, soul, function(){}, {local: true}) } // that the key points to it.
|
||||
});
|
||||
setTimeout(function(){ tab.put(reply.body, function(){}, {local: true}) },1); // and flush the in memory nodes of this graph to localStorage after we've had a chacne to union on it.
|
||||
setTimeout(function(){ tab.put(reply.body, function(){}, {local: true}) },1); // and flush the in memory nodes of this graph to localStorage after we've had a chance to union on it.
|
||||
}), opt);
|
||||
cb.peers = true;
|
||||
});
|
||||
|
17
lib/file.js
17
lib/file.js
@ -9,7 +9,7 @@ Gun.on('opt').event(function(gun, opts) {
|
||||
if ((opts.file === false) || (opts.s3 && opts.s3.key)) {
|
||||
return; // don't use this plugin if S3 is being used.
|
||||
}
|
||||
|
||||
console.log("WARNING! This `file.js` module for gun is intended only for local development testing!")
|
||||
opts.file = opts.file || 'data.json';
|
||||
var fs = require('fs');
|
||||
file.raw = file.raw || (fs.existsSync || require('path').existsSync)(opts.file) ? fs.readFileSync(opts.file).toString() : null;
|
||||
@ -23,15 +23,18 @@ Gun.on('opt').event(function(gun, opts) {
|
||||
get: function get(key, cb, o){
|
||||
var graph, soul;
|
||||
if(soul = Gun.is.soul(key)){
|
||||
(graph = {})[soul] = all.nodes[soul];
|
||||
cb(null, graph);
|
||||
(graph = {})[soul] = Gun.union.pseudo(soul); // end.
|
||||
return cb(null, graph);
|
||||
if(all.nodes[soul]){
|
||||
(graph = {})[soul] = all.nodes[soul];
|
||||
cb(null, graph);
|
||||
(graph = {})[soul] = Gun.union.pseudo(soul);
|
||||
cb(null, graph); // end.
|
||||
}
|
||||
return;
|
||||
}
|
||||
Gun.obj.map(all.keys[key], function(rel){
|
||||
if(Gun.is.soul(rel)){ get(rel, cb, o) }
|
||||
if(Gun.is.soul(rel)){ get(soul = rel, cb, o) }
|
||||
});
|
||||
cb(null, {});
|
||||
return soul? cb(null, {}) : cb(null, null);
|
||||
},
|
||||
put: function(graph, cb, o){
|
||||
all.nodes = gun.__.graph;
|
||||
|
70
lib/s3.js
70
lib/s3.js
@ -15,22 +15,52 @@
|
||||
s3.get = s3.get || function(key, cb, opt){
|
||||
if(!key){ return }
|
||||
cb = cb || function(){};
|
||||
opt = opt || {};
|
||||
(opt = opt || {}).ctx = opt.ctx || {};
|
||||
opt.ctx.load = opt.ctx.load || {};
|
||||
if(key[Gun._.soul]){
|
||||
key = s3.prefix + s3.prenode + key[Gun._.soul];
|
||||
key = s3.prefix + s3.prenode + Gun.is.soul(key);
|
||||
} else {
|
||||
key = s3.prefix + s3.prekey + key;
|
||||
}
|
||||
s3.GET(key, function(err, data, text, meta){
|
||||
Gun.log('via s3', key, err);
|
||||
if(meta && meta[Gun._.soul]){
|
||||
return s3.get(meta, cb); // SUPER SUPER IMPORTANT TODO!!!! Make this get via GUN in case soul is already cached!
|
||||
// HUGE HUGE HUGE performance gains could come from the above line being updated! (not that this module is performant).
|
||||
}
|
||||
if(err && err.statusCode == 404){
|
||||
err = null; // we want a difference between 'unfound' (data is null) and 'error' (auth is wrong).
|
||||
}
|
||||
cb(err, data);
|
||||
// TODO: optimize KEY command to not write data if there is only one soul (which is common).
|
||||
if(meta && (meta.key || meta[Gun._.soul])){
|
||||
if(err){ return cb(err) }
|
||||
if(meta.key && Gun.obj.is(data) && !Gun.is.node(data)){
|
||||
return Gun.obj.map(data, function(rel, soul){
|
||||
if(!(soul = Gun.is.soul(rel))){ return }
|
||||
opt.ctx.load[soul] = false;
|
||||
s3.get(rel, cb, {next: 's3', ctx: opt.ctx}); // TODO: way faster if you use cache.
|
||||
});
|
||||
}
|
||||
if(meta[Gun._.soul]){
|
||||
return s3.get(meta, cb); // TODO: way faster if you use cache.
|
||||
}
|
||||
return cb({err: Gun.log('Cannot determine S3 key data!')});
|
||||
}
|
||||
if(data){
|
||||
meta.soul = Gun.is.soul.on(data);
|
||||
if(!meta.soul){
|
||||
err = {err: Gun.log('No soul on node S3 data!')};
|
||||
}
|
||||
} else {
|
||||
return cb(err, null);
|
||||
}
|
||||
if(err){ return cb(err) }
|
||||
opt.ctx.load[meta.soul] = true;
|
||||
var graph = {};
|
||||
graph[meta.soul] = data;
|
||||
cb(null, graph);
|
||||
(graph = {})[meta.soul] = Gun.union.pseudo(meta.soul);
|
||||
cb(null, graph);
|
||||
if(Gun.obj.map(opt.ctx.load, function(loaded, soul){
|
||||
if(!loaded){ return true }
|
||||
})){ return } // return IF we have nodes still loading.
|
||||
cb(null, {});
|
||||
});
|
||||
}
|
||||
s3.put = s3.put || function(nodes, cb){
|
||||
@ -90,19 +120,25 @@
|
||||
s3.wait = s3.wait || null;
|
||||
|
||||
s3.key = s3.key || function(key, soul, cb){
|
||||
var meta = {};
|
||||
meta[Gun._.soul] = soul = Gun.text.is(soul)? soul : (soul||{})[Gun._.soul];
|
||||
if(!key){
|
||||
return cb({err: "No key!"});
|
||||
}
|
||||
if(!soul){
|
||||
return cb({err: "No soul!"});
|
||||
}
|
||||
s3.PUT(s3.prefix + s3.prekey + key, '', function(err, reply){ // key is 2 bytes??? Should be smaller. Wait HUH? What did I mean by this?
|
||||
Gun.log("s3 put reply", soul, err, reply);
|
||||
if(err || !reply){
|
||||
s3.key(key, soul, cb); // naive implementation of retry TODO: BUG: need backoff and anti-infinite-loop!
|
||||
return;
|
||||
}
|
||||
cb();
|
||||
}, {Metadata: meta});
|
||||
var path = s3.prefix + s3.prekey + key, meta = {key: '0.2'}, rel = {};
|
||||
meta[Gun._.soul] = rel[Gun._.soul] = soul = Gun.is.soul(soul) || soul;
|
||||
s3.GET(path, function(err, data, text, _){
|
||||
var souls = data || {};
|
||||
souls[soul] = rel;
|
||||
s3.PUT(path, souls, function(err, reply){
|
||||
Gun.log("s3 key reply", soul, err, reply);
|
||||
if(err || !reply){
|
||||
return s3.key(key, soul, cb); // naive implementation of retry TODO: BUG: need backoff and anti-infinite-loop!
|
||||
}
|
||||
cb();
|
||||
}, {Metadata: meta});
|
||||
});
|
||||
}
|
||||
|
||||
opt.hooks = opt.hooks || {};
|
||||
|
22
lib/wsp.js
22
lib/wsp.js
@ -115,10 +115,22 @@
|
||||
key[Gun._.soul] = req.url.query[Gun._.soul];
|
||||
}
|
||||
console.log("tran.get", key);
|
||||
gun.get(key, function(err, node){
|
||||
//tran.sub.scribe(req.tab, node._[Gun._.soul]);
|
||||
cb({headers: reply.headers, chunk: (err? (err.err? err : {err: err || "Unknown error."}) : node || null)});
|
||||
cb({headers: reply.headers, body: {_: {'#': Gun.is.soul.on(node) }} }); // TODO: symbol shouldn't be hard coded!
|
||||
gun.get(key, function(err, graph){
|
||||
//tran.sub.scribe(req.tab, graph._[Gun._.soul]);
|
||||
console.log("tran.get", key, "<---", err, graph);
|
||||
if(err || !graph){
|
||||
return cb({headers: reply.headers, body: (err? (err.err? err : {err: err || "Unknown error."}) : null)});
|
||||
}
|
||||
if(Gun.obj.empty(graph)){ return cb({headers: reply.headers, body: graph}) } // we're out of stuff!
|
||||
// TODO: chunk the graph even if it is already chunked. pseudo code below!
|
||||
/*Gun.is.graph(graph, function(node, soul){
|
||||
if(Object.keys(node).length > 100){
|
||||
// split object into many objects that have a fixed size
|
||||
// iterate over each object
|
||||
// cb({headers: reply.headers, chunk: {object} );
|
||||
}
|
||||
});*/
|
||||
return cb({headers: reply.headers, chunk: graph }); // keep streaming
|
||||
});
|
||||
}
|
||||
tran.put = function(req, cb){
|
||||
@ -130,7 +142,7 @@
|
||||
if(tran.put.key(req, cb)){ return }
|
||||
// some NEW code that should get revised.
|
||||
if(Gun.is.node(req.body) || Gun.is.graph(req.body)){
|
||||
console.log("tran.put", req.body);
|
||||
//console.log("tran.put", req.body);
|
||||
if(req.err = Gun.union(gun, req.body, function(err, ctx){ // TODO: BUG? Probably should give me ctx.graph
|
||||
if(err){ return cb({headers: reply.headers, body: {err: err || "Union failed."}}) }
|
||||
var ctx = ctx || {}; ctx.graph = {};
|
||||
|
165
test/chain.js
165
test/chain.js
@ -1,165 +0,0 @@
|
||||
var expect = global.expect = require("./expect");
|
||||
|
||||
var Gun = Gun || require('../gun');
|
||||
Gun.log.squelch = true;
|
||||
|
||||
describe('All', function(){
|
||||
var gun = Gun(), g = function(){
|
||||
return Gun({hooks: {get: ctx.get}});
|
||||
}, ctx = {};
|
||||
|
||||
/*
|
||||
ctx.hook(key, function(err, data){ // multiple times potentially
|
||||
//console.log("chain.get from load", err, data);
|
||||
if(err){ return cb.call(gun, err, data) }
|
||||
if(!data){ return cb.call(gun, null, null), gun._.at('null').emit() }
|
||||
if(ctx.soul = Gun.is.soul.on(data)){
|
||||
gun._.at('soul').emit({soul: ctx.soul});
|
||||
} else { return cb.call(gun, {err: Gun.log('No soul on data!') }, data) }
|
||||
if(err = Gun.union(gun, data).err){ return cb.call(gun, err) }
|
||||
cb.call(gun, null, data);
|
||||
gun._.at('node').emit({soul: ctx.soul});
|
||||
}, opt);
|
||||
*/
|
||||
|
||||
it('prep hook', function(done){
|
||||
var peer = Gun(), ref;
|
||||
ctx.get = function(key, cb){
|
||||
var c = 0;
|
||||
cb = cb || function(){};
|
||||
if('big' !== key){ return cb(null, null) }
|
||||
setTimeout(function badNetwork(){
|
||||
c += 1;
|
||||
var data = {_: {'#': Gun.is.soul.on(ref), '>': {}}};
|
||||
if(!ref['f' + c]){
|
||||
return cb(null, data);
|
||||
}
|
||||
data._[Gun._.HAM]['f' + c] = ref._[Gun._.HAM]['f' + c];
|
||||
data['f' + c] = ref['f' + c];
|
||||
cb(null, data);
|
||||
setTimeout(badNetwork, 5);
|
||||
},5);
|
||||
}
|
||||
ctx.get.fake = {};
|
||||
for(var i = 1; i < 6; i++){
|
||||
ctx.get.fake['f'+i] = i;
|
||||
}
|
||||
var big = peer.put(ctx.get.fake).val(function(val){
|
||||
ref = val;
|
||||
ctx.get('big', function(err, data){
|
||||
var next = Gun.obj.map(data, function(val, field){
|
||||
if(Gun._.meta === field){ return }
|
||||
return true;
|
||||
});
|
||||
//console.log(data);
|
||||
if(!next){ done() }
|
||||
});
|
||||
gun.opt({hooks: {get: ctx.get}});
|
||||
});
|
||||
});
|
||||
|
||||
it('map chain', function(done){
|
||||
var set = gun.put({a: {here: 'you'}, b: {go: 'dear'}, c: {sir: '!'} });
|
||||
set.map().val(function(obj, field){
|
||||
if(obj.here){
|
||||
done.a = obj.here;
|
||||
expect(obj.here).to.be('you');
|
||||
}
|
||||
if(obj.go){
|
||||
done.b = obj.go;
|
||||
expect(obj.go).to.be('dear');
|
||||
}
|
||||
if(obj.sir){
|
||||
done.c = obj.sir;
|
||||
expect(obj.sir).to.be('!');
|
||||
}
|
||||
if(done.a && done.b && done.c){
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('map chain path', function(done){
|
||||
var set = gun.put({
|
||||
a: {name: "Mark",
|
||||
pet: {coat: "tabby", name: "Hobbes"}
|
||||
}, b: {name: "Alice",
|
||||
pet: {coat: "calico", name: "Cali"}
|
||||
}, c: {name: "Bob",
|
||||
pet: {coat: "tux", name: "Casper"}
|
||||
}
|
||||
});
|
||||
set.map().path('pet').val(function(obj, field){
|
||||
if(obj.name === 'Hobbes'){
|
||||
done.hobbes = obj.name;
|
||||
expect(obj.name).to.be('Hobbes');
|
||||
expect(obj.coat).to.be('tabby');
|
||||
}
|
||||
if(obj.name === 'Cali'){
|
||||
done.cali = obj.name;
|
||||
expect(obj.name).to.be('Cali');
|
||||
expect(obj.coat).to.be('calico');
|
||||
}
|
||||
if(obj.name === 'Casper'){
|
||||
done.casper = obj.name;
|
||||
expect(obj.name).to.be('Casper');
|
||||
expect(obj.coat).to.be('tux');
|
||||
}
|
||||
if(done.hobbes && done.cali && done.casper){
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('get big on', function(done){
|
||||
var c = 0;
|
||||
g().get('big').on(function(val){
|
||||
delete val._;
|
||||
c += 1;
|
||||
if(c === 1){
|
||||
expect(val).to.eql({f1: 1});
|
||||
}
|
||||
if(c === 5){
|
||||
expect(val).to.eql({f1: 1, f2: 2, f3: 3, f4: 4, f5: 5});
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('get big on delta', function(done){
|
||||
var c = 0;
|
||||
g().get('big').on(function(val){
|
||||
delete val._;
|
||||
c += 1;
|
||||
if(c === 1){
|
||||
expect(val).to.eql({f1: 1});
|
||||
}
|
||||
if(c === 5){
|
||||
expect(val).to.eql({f5: 5});
|
||||
done();
|
||||
}
|
||||
}, true);
|
||||
});
|
||||
|
||||
it('get val', function(done){
|
||||
g().get('big').val(function(obj){
|
||||
delete obj._;
|
||||
expect(obj.f1).to.be(1);
|
||||
expect(obj.f5).to.be(5);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('get big map val', function(done){
|
||||
g().get('big').map().val(function(val, field){
|
||||
delete val._;
|
||||
if('f1' === field){
|
||||
expect(val).to.be(1);
|
||||
}
|
||||
if('f5' === field){
|
||||
expect(val).to.be(5);
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
170
test/common.js
170
test/common.js
@ -1630,15 +1630,14 @@ describe('Gun', function(){
|
||||
gun.put({a: 1, z: -1}).key('pseudo');
|
||||
gun.put({b: 2, z: 0}).key('pseudo');
|
||||
|
||||
Gun.log.verbose = true;
|
||||
gun.get('pseudo').val(function(val){
|
||||
expect(val.a).to.be(1);
|
||||
expect(val.b).to.be(2);
|
||||
expect(val.z).to.be(0);
|
||||
//done();
|
||||
done();
|
||||
});
|
||||
});
|
||||
return;
|
||||
|
||||
it('get pseudo merge on', function(done){
|
||||
var gun = Gun();
|
||||
|
||||
@ -1646,18 +1645,16 @@ describe('Gun', function(){
|
||||
gun.put({b: 2, z: 0}).key('pseudon');
|
||||
|
||||
gun.get('pseudon').on(function(val){
|
||||
console.log("HOW MANY pseudon TIMES??", val);
|
||||
if(done.val){ return } // TODO: Maybe prevent repeat ons where there is no diff?
|
||||
done.val = val;
|
||||
expect(val.a).to.be(1);
|
||||
expect(val.b).to.be(2);
|
||||
expect(val.z).to.be(0);
|
||||
//done();
|
||||
done();
|
||||
});
|
||||
});
|
||||
return;
|
||||
|
||||
it('get pseudo merge across peers', function(done){
|
||||
alert(1);
|
||||
Gun.on('opt').event(function(gun, o){
|
||||
if(connect){ return }
|
||||
gun.__.opt.hooks = {get: function(key, cb, opt){
|
||||
@ -1718,5 +1715,164 @@ describe('Gun', function(){
|
||||
},10);
|
||||
},10);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Streams', function(){
|
||||
var gun = Gun(), g = function(){
|
||||
return Gun({hooks: {get: ctx.get}});
|
||||
}, ctx = {gen: 5, extra: 45, network: 2};
|
||||
|
||||
it('prep hook', function(done){
|
||||
this.timeout(ctx.gen * ctx.extra);
|
||||
var peer = Gun(), ref;
|
||||
ctx.get = function(key, cb){
|
||||
var c = 0;
|
||||
cb = cb || function(){};
|
||||
if('big' !== key){ return cb(null, null) }
|
||||
setTimeout(function badNetwork(){
|
||||
c += 1;
|
||||
var soul = Gun.is.soul.on(ref);
|
||||
var graph = {};
|
||||
var data = graph[soul] = {_: {'#': soul, '>': {}}};
|
||||
if(!ref['f' + c]){
|
||||
return cb(null, graph), cb(null, {});
|
||||
}
|
||||
data._[Gun._.HAM]['f' + c] = ref._[Gun._.HAM]['f' + c];
|
||||
data['f' + c] = ref['f' + c];
|
||||
cb(null, graph);
|
||||
setTimeout(badNetwork, ctx.network);
|
||||
},ctx.network);
|
||||
}
|
||||
ctx.get.fake = {};
|
||||
for(var i = 1; i < (ctx.gen) + 1; i++){
|
||||
ctx.get.fake['f'+i] = i;
|
||||
ctx.length = i;
|
||||
}
|
||||
var big = peer.put(ctx.get.fake).val(function(val){
|
||||
ref = val;
|
||||
ctx.get('big', function(err, graph){
|
||||
if(Gun.obj.empty(graph)){ done() }
|
||||
});
|
||||
gun.opt({hooks: {get: ctx.get}});
|
||||
});
|
||||
});
|
||||
|
||||
it('map chain', function(done){
|
||||
var set = gun.put({a: {here: 'you'}, b: {go: 'dear'}, c: {sir: '!'} });
|
||||
set.map().val(function(obj, field){
|
||||
if(obj.here){
|
||||
done.a = obj.here;
|
||||
expect(obj.here).to.be('you');
|
||||
}
|
||||
if(obj.go){
|
||||
done.b = obj.go;
|
||||
expect(obj.go).to.be('dear');
|
||||
}
|
||||
if(obj.sir){
|
||||
done.c = obj.sir;
|
||||
expect(obj.sir).to.be('!');
|
||||
}
|
||||
if(done.a && done.b && done.c){
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('map chain path', function(done){
|
||||
var set = gun.put({
|
||||
a: {name: "Mark",
|
||||
pet: {coat: "tabby", name: "Hobbes"}
|
||||
}, b: {name: "Alice",
|
||||
pet: {coat: "calico", name: "Cali"}
|
||||
}, c: {name: "Bob",
|
||||
pet: {coat: "tux", name: "Casper"}
|
||||
}
|
||||
});
|
||||
set.map().path('pet').val(function(obj, field){
|
||||
if(obj.name === 'Hobbes'){
|
||||
done.hobbes = obj.name;
|
||||
expect(obj.name).to.be('Hobbes');
|
||||
expect(obj.coat).to.be('tabby');
|
||||
}
|
||||
if(obj.name === 'Cali'){
|
||||
done.cali = obj.name;
|
||||
expect(obj.name).to.be('Cali');
|
||||
expect(obj.coat).to.be('calico');
|
||||
}
|
||||
if(obj.name === 'Casper'){
|
||||
done.casper = obj.name;
|
||||
expect(obj.name).to.be('Casper');
|
||||
expect(obj.coat).to.be('tux');
|
||||
}
|
||||
if(done.hobbes && done.cali && done.casper){
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('get big on', function(done){
|
||||
this.timeout(ctx.gen * ctx.extra);
|
||||
var test = {c: 0, last: 0};
|
||||
g().get('big').on(function(val){
|
||||
if(test.done){ return console.log("hey yo! you got duplication on your ons!"); }
|
||||
delete val._;
|
||||
if(val['f' + (test.last + 1)]){
|
||||
test.c += 1;
|
||||
test.last += 1;
|
||||
}
|
||||
var obj = {};
|
||||
for(var i = 1; i < test.c + 1; i++){
|
||||
obj['f'+i] = i;
|
||||
}
|
||||
expect(val).to.eql(obj);
|
||||
if(test.c === ctx.length){
|
||||
test.done = true;
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('get big on delta', function(done){
|
||||
this.timeout(ctx.gen * ctx.extra);
|
||||
var test = {c: 0, seen: {}};
|
||||
g().get('big').on(function(val){
|
||||
delete val._;
|
||||
if(test.seen['f' + test.c]){ return }
|
||||
test.seen['f' + test.c] = true;
|
||||
test.c += 1;
|
||||
var obj = {};
|
||||
obj['f' + test.c] = test.c;
|
||||
expect(val).to.eql(obj);
|
||||
if(test.c === ctx.length){
|
||||
done();
|
||||
}
|
||||
}, true);
|
||||
});
|
||||
|
||||
it('get val', function(done){
|
||||
this.timeout(ctx.gen * ctx.extra);
|
||||
g().get('big').val(function(obj){
|
||||
delete obj._;
|
||||
expect(obj.f1).to.be(1);
|
||||
expect(obj['f' + ctx.length]).to.be(ctx.length);
|
||||
expect(obj).to.be.eql(ctx.get.fake);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('get big map val', function(done){
|
||||
this.timeout(ctx.gen * ctx.extra);
|
||||
var test = {c: 0, seen: {}};
|
||||
g().get('big').map().val(function(val, field){
|
||||
if(test.seen[field]){ return }
|
||||
test.seen[field] = true;
|
||||
delete val._;
|
||||
expect(field).to.be('f' + (test.c += 1));
|
||||
expect(val).to.be(test.c);
|
||||
if(test.c === ctx.length){
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user