meaningless update cause I want to push

This commit is contained in:
Mark Nadal 2014-09-09 01:53:53 -06:00
parent d001931e38
commit 5c50241007
21 changed files with 2119 additions and 1846 deletions

11
examples/admin/data.json Normal file
View File

@ -0,0 +1,11 @@
{
"_":{
"#":"yVbyf7BqlXVQQUOE5cw9rf8h",
">":{
"hello":1407328713707,
"from":1407328713707
}
},
"hello":"world",
"from":"Mark Nadal"
}

83
examples/admin/index.html Normal file
View File

@ -0,0 +1,83 @@
<!DOCTYPE html>
<html ng-app="admin">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.js"></script>
<!--
<script src="https://ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js"></script>
-->
<script src="../../gun.js"></script>
</head>
<body ng-controller="editor">
<style>
html, body {
font-family: Verdana, Geneva, sans-serif;
}
a {
color: skyblue;
text-decoration: none;
}
ul, li {
list-style-type: none;
}
ul:hover, li:hover {
list-style-type: inherit;
}
input {
border: none;
border-bottom: dashed 1px gainsboro;
}
.none {
display: none;
}
</style>
<h3>Admin Data Editor</h3>
<ul name="list">
<li ng-repeat="(key, val) in data">
<div ng-if="key != '_'">
<b>{{key}}</b>:
<span contenteditable="true" gun>{{val}}</span>
<!--
<br>{{key}}: {{val}}
-->
</div>
</li>
<li>
<form ng-submit="add()">
<label>
<input ng-model="field" placeholder="key" ng-submit="add()">
<a href="#" ng-click="add()">add</a>
<input type="submit" class="none"/>
</label>
</form>
</li>
</ul>
<script>
gun = Gun('http://localhost:8888/gun');
angular.module('admin', [
]).controller('editor', function($scope){
$scope.data = {};
$scope.$data = gun.load('blob/data', function(data){
console.log("got it", data);
$scope.data = data;
$scope.$apply();
});
$scope.add = function(a,b,c){
$scope.$data.path($scope.field).set(
$scope.data[$scope.field] = 'value'
);
$scope.field = '';
};
window.$data = $scope.$data;
}).directive('gun', function(){
return function(scope, elem){
elem.on('keyup', function(){
scope.data[scope.key] = elem.text();
scope.$apply();
});
};
});
</script>
</body>
</html>

View File

@ -12,7 +12,7 @@
</form>
<script src="../../deps/jquery.js"></script>
<script src="../../../as/as.js"></script>
<script src="../../gun2.js"></script>
<script src="../../gun.js"></script>
<script>
$(function(){
$.as($.as('sign'));
@ -46,7 +46,7 @@
$.as('sign.it').val(reply.err || reply.ok);
},'json');
return false;
})
});
});
</script>
<script>
@ -81,5 +81,55 @@
s.src = b; c && a(x='appendChild');
}
</script>
<script>
function send(url, data){
var $ = function(t){ return document.createElement(t) },
frame = $('iframe'),
form = $('form'),
input = $("input");
form.method = "POST";
form.target = 'cb';
form.enctype = 'multipart/form-data';
form.action = url;
form.style = "display:none";
form.style.display = "none";
input.name = "d";
input.value = JSON.stringify(data);
input.type = "hidden";
form.appendChild(input);
frame.name = 'cb';
frame.src = 'javascript:false;';
frame.onload = function(){
frame.onload = function(){
console.log(frame);
return;
var doc = this.contentWindow ? this.contentWindow.document :(this.contentDocument ? this.contentDocument : this.document),
root = doc.documentElement ? doc.documentElement : doc.body,
textarea = root.getElementsByTagName("textarea")[0],
type = textarea && textarea.getAttribute("data-type") || null,
status = textarea && textarea.getAttribute("data-status") || 200,
statusText = textarea && textarea.getAttribute("data-statusText") || "OK",
content = {
html: root.innerHTML,
text: type ?
textarea.value :
root ? (root.textContent || root.innerText) : null
};
console.log(doc, root, textarea, type, status, statusText, content);
return;
cleanUp();
completeCallback(status, statusText, content, type ?("Content-Type: " + type) : null);
}
form.submit();
}
form.appendChild(frame);
document.body.appendChild(form);
}
</script>
</body>
</html>

View File

@ -1,14 +1,14 @@
var fs = require('fs');
var http = require('http');
var qs = require('querystring');
var sync = require('../../test/shotgun');
var gun = require('../../test/shotgun');
http.route = function(url){
console.log(url);
var path = __dirname + url;
if(!url){ return http.route }
if(url === '/gun'){
sync.server(req, res);
if(gun.server.regex.test(url)){
return gun;
}
if(fs.existsSync(path)){
return ((path = require(path)) && path.server)? path : http.route;
@ -21,50 +21,34 @@ http.route = function(url){
http.route.server = function(req, res){
console.log("/ no route found");
}
http.cors = function(req, res){
var headers = {};
headers["Access-Control-Allow-Origin"] = "*";
headers["Access-Control-Allow-Methods"] = "POST, GET, PUT, DELETE, OPTIONS";
headers["Access-Control-Allow-Credentials"] = false;
headers["Access-Control-Max-Age"] = 1000 * 60 * 60 * 24;
headers["Access-Control-Allow-Headers"] = "X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept";
if(res){
res.writeHead(200, headers);
if(req && req.method === 'OPTIONS'){
res.end();
return true;
}
}
}
http.createServer(function(req, res){
console.log(req.headers);
console.log(req.method);
if(http.cors(req, res)){ return }
if(req.method == 'POST'){
var body = {};
body.length = 0;
body.data = new require('buffer').Buffer('');
req.on('data', function(buffer){
if(body.data.length >= body.length + buffer.length){
buffer.copy(body.data, body.length);
} else {
body.data = Buffer.concat([body.data, buffer]);
}
body.length += buffer.length;
});
req.on('end', function(x){
body.text = body.data.toString('utf8');
try{body.json = JSON.parse(body.text);
}catch(e){}
delete body.data;
req.body = body.json || body.text;
http.route(req.url).server(req, res);
});
res.on('end', function(data){
http.cors(null, res);
res.end(JSON.stringify(data));
});
}
console.log(req.method, req.url);
var body = {};
body.length = 0;
body.data = new require('buffer').Buffer('');
req.on('data', function(buffer){
if(body.data.length >= body.length + buffer.length){
buffer.copy(body.data, body.length);
} else {
body.data = Buffer.concat([body.data, buffer]);
}
body.length += buffer.length;
});
req.on('end', function(x){
body.text = body.data.toString('utf8');
try{body.json = JSON.parse(body.text);
}catch(e){}
delete body.data;
req.body = body.json || body.text;
http.route(req.url).server(req, res);
});
res.on('data', function(data){
res.write(JSON.stringify(data) + '\n');
});
res.on('end', function(data){
res.end(JSON.stringify(data));
});
}).listen(8888);
console.log("listening");
//process.on("uncaughtException", function(e){console.log('!!!!!!!!!!!!!!!!!!!!!!');console.log(e);console.log('!!!!!!!!!!!!!!!!!!!!!!')});

View File

@ -7,7 +7,7 @@ sign.user.create = function(form, cb, shell){ // TODO: REDO THIS TO MATCH GUN
if(err || !user){ return cb(err) }
user = {key: user.key, salt: user.salt};
user.account = {email: form.email, registered: new Date().getTime()};
gun.set(user).index('email/' + user.account.email);
gun.set(user).key('email/' + user.account.email);
cb(null, user);
});
};
@ -22,20 +22,20 @@ gun.load('email/mark@accelsor.com')
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){
console.log("sign.server", req.body);
console.log("sign.server", req.headers, req.body);
res.emit('data', {ok: 1});
res.emit('data', {ok: 2});
res.emit('data', {ok: 3});
res.emit('data', {ok: 4});
setTimeout(function(){
res.emit('end', {ok: 5});
}, 5000);
return;
if(!req.body || !req.body.email){ return res.emit('end', {err: "That email does not exist."}) }
var user = gun.load('email/' + req.body.email, function(data){ // this callback is called the magazine, since it holds the clip
console.log("data from index", data);
console.log("data from key", data);
if(!req.body.password){
return res.emit('end', {ok: 'sign in'});
}

View File

@ -5,9 +5,24 @@ var users = require('./users.json').results
, chance = new Chance(1234)
, b
, d = Date.now()
, num = 10000
, num = 50
;
users = users.map(function(user){
user = user.user;
user._ = user._ || {};
user._['#'] = user.sha1;
user.first = user.name.first;
user.last = user.name.last;
user.title = user.name.title;
delete user.name;
user.zip = user.location.zip;
user.street = user.location.street;
user.city = user.location.city;
user.state = user.location.state;
delete user.location;
return user;
})
users = chance.shuffle(users).slice(0, num);
b = chance.shuffle(users.slice(0));
b.forEach(function (user, i) {
@ -15,6 +30,12 @@ b.forEach(function (user, i) {
console.log((Date.now() - d) / 1000, i);
d = Date.now();
}
user.friends = chance.shuffle(users).slice(chance.integer({ min: 20, max: 120 }));
user.friends = chance.shuffle(users).slice(chance.integer({ min: 20, max: (num < 120)? num : 120 }));
});
var gun = require('../test/shotgun');
gun.set(b[0]);
console.log(b[1], b[1].friends.length);
console.log((Date.now() - d) / 1000, num);

View File

@ -1,57 +0,0 @@
module.exports = (function(){
var r = {}
, fs = require('fs')
, child = require('child_process')
, check = (fs.existsSync||require('path').existsSync)
, install = 'redis-install'
, server = 'redis-server';
r.redis = require('redis');
r.client = r.redis.createClient();
r.refis = require('fakeredis');
r.clienf = r.refis.createClient();
process.env[server] = process.env[server] || '/usr/local/bin/redis-server';
r.client.on('error', function(e){
// console.log("redis error", e);
if(!(/ECONNREFUSED/).test(e)){ return }
r.start();
});
r.client.set('_gun_redis_init_', r.key = Math.random().toString().slice(2));
r.start = function(){
if(process.env[install]){
if(!check(process.env[server])){
return r.deploy(r.start);
}
}
if(!check(process.env[server])){
return; // never recover
}
if(process.env.gun_redis_lock){ return }
process.env.gun_redis_lock = process.pid;
console.log('gun', process.pid, 'starting redis');
require('child_process').spawn(process.env[server]).on('exit',function(){
if(process.env.gun_redis_lock == process.pid){
process.env.gun_redis_lock = ''; // 0 and false don't work, cause they are cast to strings!
}
});
r.client.get('_gun_redis_init_', function(e,r){
console.log(">>>> BOOM <<<<", e, r);
});
}
r.deploy = function(done){
var path = process.env[install];
if(!path){ return }
if(check(process.env[server])){
done(process.env[server]);
} else {
child.exec('cd ' + path
+ ' && ' + 'curl -O http://download.redis.io/redis-stable.tar.gz'
+ ' && ' + 'tar xvzf redis-stable.tar.gz'
+ ' && ' + 'cd redis-stable'
+ ' && ' + 'make'
, function(e, r){
done(process.env[server] = path + '/redis-stable/src/redis-server');
});
}
}
return r;
})();

View File

@ -61,7 +61,7 @@
if(!a.fns.is(cb)){ return }
try{ cb(e,d,t,m,r);
}catch(e){
console.log(e)
console.log(e);
}
});
s.batch = s.batch || {};
@ -118,7 +118,7 @@
}
this.S3().listObjects(m, function(e,r){
//console.log('list',e);
a.list.each((r||{}).Contents, function(v){console.log(v);});
a.list.each((r||{}).Contents, function(v){console.log(v)});
//console.log('---end list---');
if(!a.fns.is(cb)) return;
cb(e,r);
@ -126,4 +126,4 @@
return this;
}
return s3;
})(require('../gun2'), {});
})(require('../gun'), {});

File diff suppressed because one or more lines are too long

1232
gun.js

File diff suppressed because it is too large Load Diff

577
gun0.js Normal file
View File

@ -0,0 +1,577 @@
/**** The Abstact Structure
A JSON graph structure that is lightweight and flexible to describe anything.
The current goal, however, is limited to encompassing HTML and CSS for starters.
Immediately after that is describing code as a state.
A node is something which has relationships and or value.
Relationships and values aren't any different, other than that
a relationship is a reference and a value is embedded.
*****/
module.exports = require('theory')
('gun',function(a){
a.gun = (function(){
function gun(p,v,w){
var args = arguments.length
, cb = a.fns.is(v)? v : null
, g, n, b, w = w || a.time.now();
if(gun.is(this)){
n = this;
g = n._.clip || function(){ return {} };
if(a.text.is(p)){
if(args >= 2){ // set
var u, ref = {}
, val = gun.at(n,p,ref);
if(!ref.cartridge || !ref.cartridge._ || !ref.cartridge._[gun._.id]){
return;
} ref.id = ref.cartridge._[gun._.id] +'.'+ ref.path;
v = gun.ify.be(v);
b = gun.bullet(ref.path,v,w);
console.log("after:", v, b);
if(a.gun.ham){
v = a.gun.ham(ref.cartridge,b,v,w); // TODO: BUG! Need to update when also!
if(v === u){
console.log("HAM REJECTION", p, v, val);
return;
}
}
console.log("HAM set", p, v);
if(ref.at){
if(v === null){
if(a.list.is(ref.at)){
t = o.val || t;
var j = ref.at.indexOf(ref.prop);
if(0 <= j){
ref.at.splice(j,1);
} else {
j = a.list(ref.at).find(gun.id(ref.prop));
if(j){
ref.at.splice(--j,1);
}
}
} else {
delete ref.at[ref.prop];
}
var del = {}; del[ref.id] = null;
gun.fire(del, g[gun._.id], w);
v = ref.at;
} else {
if(a.fns.is(v) && v[gun._.id]){ // then it is a clip!
v = {};
}
v = gun.at(v);
if(gun.is(v)){
v = gun.id(v._[gun._.id]); // update this to handle clip#cart
} else {
v = gun.ify.be(v);
}
if(a.obj.is(v)){
ref.at[ref.prop] = v;
//ref.tmp = ref.at[ref.prop] = gun.ify.obj(v, val);
} else
if(a.list.is(v)){
ref.tmp = ref.at[ref.prop] = gun.ify.list(v, val);
} else {
ref.at[ref.prop] = v;
}
var diff = {}; diff[ref.id] = v;
gun.fire(diff, g[gun._.id], w);
v = ref.tmp || v;
}
return v;
}
return;
}
if(args >= 1){ // get
v = gun.at(n,p);
return v;
}
}
return;
}
n = a.obj.is(v)? v : a.obj.is(p)? p : null;
p = a.text.is(p)? p : gun.id();
if(a.obj.is(n)){ // create a clip from this object
var c;
g = gun.ify(n);
if((c = gun.magazine[p]) && a.fns.is(c)){
console.log("clip already exists in magazine,", p);
a.obj(g).each(function(n,id){
if(!gun.is(n)){ return }
c(id,n);
});
return gun.magazine[p];
}
var clip = gun.magazine[p] = function(p,v,w){
var args, id, path, n, w = w || a.time.now();
if(a.text.is(p)){
id = a.text(p).clip('.',0,1);
path = a.text(p).clip('.',1);
if(a.obj(g).has(id) && gun.is(g[id])){
n = g[id];
p = path;
}
}
args = a.list.slit.call(arguments);
if(!args.length){
return g;
}
if(path){
if(n){
n._.clip = n._.clip || clip;
return gun.apply(n, args);
}
return;
}
var fn = function(p,v,w){
if(!n){ return }
var args = a.list.slit.call(arguments);
return !args.length? n : gun.apply(n,args);
}
if(n){
if(args.length === 1){
n._.clip = n._.clip || clip;
return fn;
}
if(gun.is(v) && gun.ham){
var h = v._[gun._.ham] || {};
a.obj(v).each(function(v,p){
if(p === '_'){ return }
console.log('-------------->', p, h[p], h, 1); // Wait! This isn't correct because it should be '>' not '.'!
fn(p, v, h[p] || (a.num.is(h)? h : 1)); // Wait! This isn't correct because it should be '>' not '.'!
});
return fn;
}
if(v === null){
delete g[n._[gun._.id]];
var del = {}; del[n._[gun._.id]] = n = null;
gun.fire(del, g[gun._.id], w); // TODO: BUG! HAM UPDATES!
return null;
}
return;
}
if(a.text.is(p) && a.obj.is(v)){
v = v;
v._ = gun.id(p);
} else
if(a.obj.is(p)){
v = p;
}
if(a.obj.is(v)){
n = gun.ify(v,u,{}); // a clip cannot be created from this, only a single cartridge
n._ = n._ || gun.id({});
n._.clip = clip; // JSONifying excludes functions.
var add = {}; add[n._[gun._.id]] = g[n._[gun._.id]] = n;
gun.fire(add, clip[gun._.id], w); // TODO: BUG! HAM UPDATES!
return fn;
}
}
clip[gun._.id] = p;
return clip;
}
} var u;
gun._ = {
id: '#' // do not change this!
}
gun.is = function(o){
return (o && o._ && o._[gun._.id])? true : false;
}
gun.id = function(t){
if(t){
var _ = {};_[gun._.id] = a.text.is(t)? t : gun.id();
return _;
}
return a.text.r(9);
}
gun.at = function(n,p,ref){
if(a.fns.is(n)){
n = n();
}
if(!p){
return n;
}
ref = ref || {};
var pp = a.list.is(p)? p : (p||'').split('.')
, g = a.fns.is(n._.clip)? n._.clip() : this
, i = 0, l = pp.length, v = n
, x, y, z;
ref.cartridge = n;
ref.prop = pp[l-1];
ref.path = pp.slice(i).join('.');
while(i < l && v !== u){
x = pp[i++];
if(a.obj.is(v) && a.obj(v).has(x)){
ref.at = v;
v = v[x];
if(v && v[gun._.id]){
v = a.obj(g).has(v[gun._.id])? g[v[gun._.id]] : u;
if(v){
return gun.at.call(g,v,pp.slice(i),ref);
}
}
} else
if(a.list.is(v)){
ref.at = v;
return a.list(v).each(function(w,j){
if(!w) return;
if(!p) return;
w = a.obj(g).has(w[gun._.id]||w)? g[w[gun._.id]||w] : u;
if(!w) return;
if(w._ && x === w._[gun._.id]){
i += 1;
p = false;
}
return gun.at.call(g,w,pp.slice(i-1),ref);
});
} else {
ref.at = v;
v = u;
}
}
if(a.list.is(v)){
ref.at = v;
v = a.list(v).each(function(w,j,t){
if(w){
if(a.obj(g).has(w[gun._.id]||w)) t(g[w[gun._.id]||w]);
}
}) || [];
}
return i < l? u : v;
}
gun.ify = function(o, opt, n){
var g = {};
opt = opt || {};
opt.seen = opt.seen || [];
if(!a.obj.is(o)){ return g }
function ify(o,i,f,n,p){
if(gun.ify.is(o)){
f[i] = o;
return
}
if(a.obj.is(o)){
var seen;
if(seen = ify.seen(o)){
ify.be(seen);
return;
}
if(gun.is(o)){
f[i] = gun.id(o._[gun._.id]);
g[o._[gun._.id]] = n;
} else {
f[i] = n;
}
opt.seen.push({cartridge: n, prop: i, from: f, src: o});
a.obj(o).each(function(v,j){
ify(v,j,n,{},f);
});
if(gun.is(n)){
g[n._[gun._.id]] = n;
f[i] = gun.id(n._[gun._.id]);
}
return;
}
if(a.list.is(o)){
f[i] = a.list(o).each(function(v,j,t){
var seen;
if(a.fns.is(v)){
v = gun.at(v);
}
if(a.obj.is(v)){
if(seen = ify.seen(v)){
ify.be(seen);
if(gun.is(seen.cartridge)){ t(seen.cartridge._[gun._.id]) }
} else {
gun.ify(v, opt, n);
if(gun.is(n)){
t(n._[gun._.id]);
}
}
} else
if(a.text.is(v)){
if(a.obj(g).has(v)){
t(v);
} else {
t(v); // same as above :/ because it could be that this ID just hasn't been indexed yet.
}
}
}) || [];
return;
}
}
ify.be = function(seen){
var n = seen.cartridge;
n._ = n._||{};
n._[gun._.id] = n._[gun._.id]||gun.id();
g[n._[gun._.id]] = n;
if(seen.from){
seen.from[seen.prop] = gun.id(n._[gun._.id]);
}
}
ify.seen = function(o){
return a.list(opt.seen).each(function(v){
if(v && v.src === o){ return v }
}) || false;
}
var is = true, cartridge = n || {};
a.obj(o).each(function(v,i){
if(!gun.is(v)){ is = false }
ify(v, i, cartridge, {});
});
if(!is){
ify.be({cartridge: cartridge});
g[cartridge._[gun._.id]] = cartridge;
}
if(n){
return n;
}
return g;
}
gun.ify.be = function(v,g){ // update this to handle externals!
var r;
g = g || {};
if(gun.ify.is(v)){
r = v;
} else
if(a.obj.is(v)){
r = {};
a.obj(v).each(function(w,i){
w = gun.ify.be(w);
if(w === u){ return }
r[i] = w;
});
} else
if(a.list.is(v)){ // references only
r = a.list(v).each(function(w,i,t){
if(!w){ return }
w = gun.at(w);
if(gun.is(w)){
t(w._[gun._.id]);
} else
if(w[gun._.id]){
t(w[gun._.id]);
} else
if(a.obj(g).has(w)){
t(w);
}
}) || [];
}
return r;
}
gun.ify.is = function(v){ // null, binary, number (!Infinity), text, or a ref.
if(v === null){ return true } // deletes
if(v === Infinity){ return false }
if(a.bi.is(v)
|| a.num.is(v)
|| a.text.is(v)){
return true; // simple values
}
if(a.obj.is(v) && a.text.is(v[gun._.id])){ // ref
return true;
}
return false;
}
gun.ify.obj = function(v, val){
if(a.obj.is(val) && a.obj.is(v)){
a.obj(v).each(function(d, i){
if(a.gun.ham && a.gun.ham.call(g,n,p,v,w,val)){
}
});
}
return v;
}
gun.ify.list = function(v, val){
var r;
r = a.list.is(val)? val.concat(v) : v;
r = a.list(r).each(function(r,i,t){t(r,1)})||{};
r = a.obj(r).each(function(w,r,t){t(r)})||[]; // idempotency of this over latency? TODO! INVESTIGATE!!
return r;
}
gun.duel = function(old,now){
a.obj(now).each(function(g,id){
if(!gun.is(g)){ return }
var c;
if(a.obj(old).has(id) && gun.is(c = old[id])){
a.obj(g).each(function(v,i){
});
} else {
old[id] = g;
}
});
}
gun.bullet = function(p,v,w){
var b = {};
b[p] = v;
if(gun.ham && gun._.ham){
b._ = {};
b._[gun._.ham] = w || a.time.now();
}
return b;
}
gun.fire = function(bullet,c,w,op){
bullet = bullet.what? bullet : {what: bullet};
bullet.where = c || bullet.where;
bullet.when = w || bullet.when;
if(!a.obj.is(bullet.what)){ return gun.fire.jam("No ammo.", bullet) }
if(!a.num.is(bullet.when)){ return gun.fire.jam("No time.", bullet) }
if(!a.text.is(bullet.where)){ return gun.fire.jam("No location.", bullet) }
bullet.how = bullet.how || {};
bullet.how.gun = op || 1;
theory.on(gun.event).emit(bullet);
}
gun.fire.jam = function(s,b){ if(b){ return console.log("Gun jam:",s,b) } console.log("Gun jam:",s) }
gun.shots = function(hear,s){ return theory.on(gun.event+(s?'.'+s:'')).event(hear) }
gun.event = 'gun';
gun.magazine = {};
return gun;
})();
/* Hypothetical Amnesia Machine
A thought experiment in efficient cause, linear time, and knowledge.
Suppose everything you will ever know in your life was already be stored
in your brain. Now suppose we have some machine, which delicately traverses
your mind and gives you amnesia about all these facts. You now no longer can
recall any of this knowledge because that information is disconnected from
all other pieces of knowledge - making it impossible for your mind to then
associate and thus remember things. But the curious fact is that all this
knowledge is still stored within your mind, it is just inaccessible.
Now suppose, this amnesia machine is designed to unlock various bits of
that knowledge, making it connected again to other related tidbits and thus
making it accessible to you. This unlocking process is activated at some pre-
determined value, such as a timestamp. Can it really be said that this is
indistinguishable from the supposed flow of past, present, and future?
Such that future information is not just unknown, but fundamentally does
not exist, and then by actions taken in the present is caused to be. As a
result of your senses, you then experience this effect, and thus 'learning'
that knowledge. Could we truly build a proof that reality is one way or the
other? But if we did, wouldn't that scurrying little machine just race across
our minds and assure it induces amnesia into our remembrance of its existence?
Nay, we cannot. We can only hypothesize about the existence of this crafty
device. For the blindness that it does shed upon us captivates our perception
of how the world really is, us forever duped into thinking time is linear.
And here, in write and code, is this machine used and exploited. Holding
in its power the ability to quarantine and keep secret, until upon some
value, some condition, some scheme or rendition, does it raise its mighty
clutch of deception and expose the truth, shining in its radiance and glory,
all at the ease of making a single connection. Whereupon we do assure that
all conscious actors are agreed upon in a unified spot, synchronized in the
capacity to realize such beautiful information.
*/
a.gun._.ham = '>';
a.gun.ham = function(n,p,v,w){
if(!n){ return }
console.log("HAM:", n, p, v, w);
if(!a.text.is(p)){
if(a.obj.is(p) && p._){
a.obj(p).each(function(sv,i){
if(i === '_'){ return }
v = sv = a.gun.ham(n,i,sv, a.gun.ham.when(p._, i) || w); // works for now, but may not on other non-bullet objects
if(sv === u){
delete p[i];
} else {
p[i] = sv;
}
});
return v;
}
return;
}
var val = a.gun.at(n,p)
, when, age, now, u, q;
q = p.replace('.',a.gun._.ham);
n._ = n._ || {};
n._[a.gun._.ham] = n._[a.gun._.ham] || {};
age = function(q){
if(!q){ return 0 }
var when = n._[a.gun._.ham][q];
if(when || when === 0){
return when;
}
return age(a.text(q).clip(a.gun._.ham,0,-1));
}
when = age(q);
v = (function(){
if(a.gun.ify.is(v)){ // simple values are directly resolved
return v;
} else
if(a.obj.is(v)){
if(a.obj.is(val)){ // resolve sub-values
var change = false;
a.obj(v).each(function(sv,i){
sv = a.gun.ham(n, (p+'.'+i), sv, w, val[i]); // TODO: BUG! Still need to deal with sub-value bullets resolving to container's age.
if(sv === u){ return }
change = true;
val[i] = sv;
});
if(change){
return v = val;
} else {
return;; // nothing new
}
}
a.obj(v).each(function(sv,i){
sv = a.gun.ham(n, (p+'.'+i), sv, w, (val||{})[i]);
if(sv === u){ delete v[i] }
});
return v;
} else
if(a.list.is(v)){
if(!a.list.is(val)){ // TODO: deal with this later.
return v;
}
return v;
} else { // unknown matches are directly resolved
return;
}
})();
if(v === u){ return }
if(w < when){
console.log("new < old");
return;
} else
if(w === when){ // this needs to be updated also!
if(val === v || a.test.is(val,v) || a.text.ify(val) < a.text.ify(v)){
console.log("new === old");
return;
}
} else
if((now = a.time.now() + 1) < w){ // tolerate a threshold of 1ms.
console.log("amnesia", Math.ceil(w - now));
/* Amnesia Quarantine */
a.time.wait(function(){
console.log("run again");
a.gun.call(n,p,v,w);
}, Math.ceil(w - now)); // crude implementation for now.
return;
}
v = (function(){
if(a.obj.is(v)){
w = when; // objects are resolved relative to their previous values.
}
return v;
})();
n._[a.gun._.ham][q] = w; // if properties get deleted it may be nice to eventually delete the HAM, but that could cause problems so we don't for now.
// ps. It may be possible to delete simple values if they are not proceeded by an object?
return v;
}
a.gun.ham.when = function(w, i){
var h;
if(w && w._){
w = w._;
}
if(w && (h = w[a.gun._.ham])){
if(a.obj(h).has(i)){
return h[i];
}
if(a.num.is(h)){
return h;
}
}
}
return a.gun;
});

559
gun2.js
View File

@ -1,559 +0,0 @@
;(function(own){
function Gun(opt){
var gun = this;
if(!Gun.is(gun)){
return new Gun(opt);
}
gun.init(opt);
}
Gun.is = function(gun){ return (gun instanceof Gun)? true : false }
Gun._ = {};
Gun.chain = Gun.prototype;
Gun.chain._ = {};
Gun.chain._.opt = {};
Gun.chain._.nodes = {};
Gun.chain._.chain = {};
Gun.chain._.trace = [];
Gun.chain._.indices = {};
Gun.chain.init = function(opt, stun){ // idempotently update or set options
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.list.is(opt)){ opt = {peers: opt} }
if(Gun.text.is(opt.peers)){ opt.peers = [opt.peers] }
if(Gun.list.is(opt.peers)){ opt.peers = Gun.obj.map(opt.peers, function(n,f,m){ m(n,{}) }) }
gun._.opt.peers = opt.peers || gun._.opt.peers || {};
gun._.opt.uuid = opt.uuid || gun._.opt.uuid || {};
gun._.opt.hook = gun._.opt.hook || {};
Gun.obj.map(opt.hook, function(h, f){
if(!Gun.fns.is(h)){ return }
gun._.opt.hook[f] = h;
});
if(!stun){ Gun.on('init').emit(gun, opt) }
return gun;
}
Gun.chain.load = function(index, cb, opt){
var gun = this;
cb = cb || function(){};
if(cb.node = gun._.indices[index]){ // set this to the current node, too!
console.log("from gun"); // remember to do all the same stack stuff here also!
return cb(cb.node), gun;
}
cb.fn = function(){}
gun._.index = index;
// missing: hear shots!
if(Gun.fns.is(gun._.opt.hook.load)){
gun._.opt.hook.load(index, function(err, 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(!data){ return (gun._.chain.blank||cb.fn)() }
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);
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 {
console.log("Warning! You have no persistence layer to load from!");
}
return gun;
}
Gun.chain.index = function(index, cb){ // TODO: Need to setImmediate if not loaded yet?
console.log("make index", index);
cb = cb || function(){};
this._.indices[index] = this._.node;
if(Gun.fns.is(this._.opt.hook.index)){
this._.opt.hook.index(index, this._.node, function(err, data){
console.log("index made", index);
if(err){ return cb(err) }
return cb(null);
});
} else {
console.log("Warning! You have no index hook!");
}
return this;
}
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){ // 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;
}
/*
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.
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 as it could lead to an invalid read and thus an invalid state.
I - Isolation, the conflict resolution algorithm guarantees idempotent transactions, across every peer, regardless of any partition,
including a peer acting by itself or one having been disconnected from the network.
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 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){
var gun = this, set;
cb = Gun.fns.is(cb)? cb : function(){};
set = Gun.ify.call(gun, val);
cb.root = set.root;
if(set.err){ return cb(set.err), gun }
set = gun.set.now(set.nodes, Gun.time.is()); // set time state on nodes?
if(set.err){ return cb(set.err), gun }
Gun.union(gun._.nodes, set.nodes); // while this maybe should return a list of the nodes that were changed, we want to send the actual delta
gun._.node = cb.root;
if(Gun.fns.is(this._.opt.hook.set)){
this._.opt.hook.set(set.nodes, function(err, data){ // now iterate through those nodes to S3 and get a callback once all are saved
console.log("gun set hook callback called");
if(err){ return cb(err) }
return cb(null);
});
} else {
console.log("Warning! You have no persistence layer to save to!");
}
return gun;
}
Gun.chain.set.now = function(nodes, now){
var context = {};
context.nodes = nodes;
context.now = now = (now === 0)? now : now || Gun.time.is();
Gun.obj.map(context.nodes, function(node, id){
if(!node || !id || !node._ || !node._[own.sym.id] || node._[own.sym.id] !== id){
return context.err = {err: "There is a corruption of nodes and or their ids", corrupt: true};
}
var states = node._[own.sym.HAM] = node._[own.sym.HAM] || {};
Gun.obj.map(node, function(val, key){
if(key == own.sym.meta){ return }
val = states[key];
states[key] = (val === 0)? val : val || now;
});
});
return context;
}
Gun.chain.match = function(){ // same as path, except using objects
return this;
}
Gun.chain.blank = function(blank){
this._.chain.blank = Gun.fns.is(blank)? blank : function(){};
return this;
}
Gun.chain.dud = function(dud){
this._.chain.dud = Gun.fns.is(dud)? dud : function(){};
return this;
}
Gun.fns = {};
Gun.fns.is = function(fn){ return (fn instanceof Function)? true : false }
Gun.bi = {};
Gun.bi.is = function(b){ return (b instanceof Boolean || typeof b == 'boolean')? true : false }
Gun.num = {};
Gun.num.is = function(n){
return ((n===0)? true : (!isNaN(n) && !Gun.bi.is(n) && !Gun.list.is(n) && !Gun.text.is(n))? true : false );
}
Gun.text = {};
Gun.text.is = function(t){ return typeof t == 'string'? true : false }
Gun.text.ify = function(t){
if(JSON){ return JSON.stringify(t) }
return (t && t.toString)? t.toString() : t;
}
Gun.text.random = function(l, c){
var s = '';
l = l || 24; // you are not going to make a 0 length random number, so no need to check type
c = c || '0123456789ABCDEFGHIJKLMNOPQRSTUVWXZabcdefghiklmnopqrstuvwxyz';
while(l > 0){ s += c.charAt(Math.floor(Math.random() * c.length)); l-- }
return s;
}
Gun.list = {};
Gun.list.is = function(l){ return (l instanceof Array)? true : false }
Gun.list.slit = Array.prototype.slice;
Gun.list.sort = function(k){ // create a new sort function
return function(A,B){
if(!A || !B){ return 0 } A = A[k]; B = B[k];
if(A < B){ return -1 }else if(A > B){ return 1 }
else { return 0 }
}
}
Gun.list.map = function(l, c, _){ return Gun.obj.map(l, c, _) }
Gun.list.index = 1; // change this to 0 if you want non-logical, non-mathematical, non-matrix, non-convenient array notation
Gun.obj = {};
Gun.obj.is = function(o){ return (o instanceof Object && !Gun.list.is(o) && !Gun.fns.is(o))? true : false }
Gun.obj.ify = function(o){
if(Gun.obj.is(o)){ return o }
try{o = JSON.parse(o);
}catch(e){o={}};
return o;
}
Gun.obj.has = function(o, t){ return Object.prototype.hasOwnProperty.call(o, t) }
Gun.obj.map = function(l, c, _){
var u, i = 0, ii = 0, x, r, rr, f = Gun.fns.is(c),
t = function(k,v){
if(v !== u){
rr = rr || {};
rr[k] = v;
return;
} rr = rr || [];
rr.push(k);
};
if(Gun.list.is(l)){
x = l.length;
for(;i < x; i++){
ii = (i + Gun.list.index);
if(f){
r = _? c.call(_, l[i], ii, t) : c(l[i], ii, t);
if(r !== u){ return r }
} else {
//if(gun.test.is(c,l[i])){ return ii } // should implement deep equality testing!
if(c === l[i]){ return ii } // use this for now
}
}
} else {
for(i in l){
if(f){
if(Gun.obj.has(l,i)){
r = _? c.call(_, l[i], i, t) : c(l[i], i, t);
if(r !== u){ return r }
}
} else {
//if(a.test.is(c,l[i])){ return i } // should implement deep equality testing!
if(c === l[i]){ return i }
}
}
}
return f? rr : Gun.list.index? 0 : -1;
}
Gun.time = {};
Gun.time.is = function(t){ return t? t instanceof Date : (+new Date().getTime()) }
Gun.on = (function(){
function On(on){
var e = On.is(this)? this : events;
return e._ = e._ || {}, e._.on = Gun.text.ify(on), e;
}
On.is = function(on){ return (on instanceof On)? true : false }
On.split = function(){ return new On() }
On.sort = Gun.list.sort('i');
On.echo = On.prototype;
On.echo.on = On;
On.echo.emit = function(what){
var on = this._.on;
if(!on){ return }
this._.events = this._.events || {};
var e = this._.events[on] = this._.events[on] || (this._.events[on] = [])
, args = arguments;
if(!(this._.events[on] = Gun.list.map(e, function(hear, i, map){
if(!hear.as){ return }
map(hear);
hear.as.apply(hear, args);
}))){ delete this._.events[on] }
}
On.echo.event = function(as, i){
var on = this._.on, e;
if(!on || !as){ return }
this._.events = this._.events || {};
on = this._.events[on] = this._.events[on] || (this._.events[on] = []);
e = {as: as, i: i || 0, off: function(){ return !(e.as = false) }};
return on.push(e), on.sort(On.sort), e;
}
On.echo.once = function(as, i){
var on = this._.on, once = function(){
this.off();
as.apply(this, arguments);
}
return this.event(once, i);
}
var events = On.split();
return On;
}());
Gun.roulette = function(l, c){
var gun = Gun.is(this)? this : {};
if(gun._ && gun._.opt && gun._.opt.uuid){
if(Gun.fns.is(gun._.opt.uuid)){
return gun._.opt.uuid(l, c);
}
l = l || gun._.opt.uuid.length;
}
return Gun.text.random(l, c);
}
Gun.union = function(graph, prime){
var context = { nodes: {}};
Gun.obj.map(prime, function(node, id){
var vertex = graph[id];
if(!vertex){ // disjoint
context.nodes[node._[own.sym.id]] = graph[node._[own.sym.id]] = node;
return;
}
Gun.HAM(vertex, node, function(){ // partial
vertex[key] = deltaValue;
vertex._[own.sym.HAM][key] = node._[own.sym.HAM][key];
});
});
}
Gun.HAM = function(current, delta, some){
function HAM(machineState, incomingState, currentState, incomingValue, currentValue){
if(machineState < incomingState){
// the incoming value is outside the boundary of the machine's state, it must be reprocessed in another state.
return {amnesiaQuarantine: true};
}
if(incomingState < currentState){
// the incoming value is within the boundary of the machine's state, but not within the range.
return {quarantineState: true};
}
if(currentState < incomingState){
// the incoming value is within both the boundary and the range of the machine's state.
return {converge: true, incoming: true};
}
if(incomingState === currentState){
if(incomingValue === currentValue){ // Note: while these are practically the same, the deltas could be technically different
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!
return {converge: true, current: true};
}
if(String(currentValue) < String(incomingValue)){ // String only works on primitive values!
return {converge: true, incoming: true};
}
}
return {err: "you have not properly handled recursion through your data or filtered it as JSON"};
}
var states = current._[own.sym.HAM] = current._[own.sym.HAM] || {} // TODO: need to cover the state of the node itself, not just the keys?
, deltaStates = current._[own.sym.HAM];
Gun.obj.map(delta, function update(deltaValue, key){
if(!Gun.obj.has(current, key)){
some(current, key, deltaValue);
return;
}
var serverState = Gun.time.is();
// add more checks?
var state = HAM(serverState, deltaStates[key], states[key], deltaValue, current[key]);
if(state.err){
console.log(".!HYPOTHETICAL AMNESIA MACHINE ERR!.", state.err);
return;
}
if(state.state || state.quarantineState || state.current){ return }
if(state.incoming){
some(current, key, deltaValue);
return;
}
if(state.amnesiaQuarantine){
Gun.schedule(deltaStates[key], function(){
update(deltaValue, key);
});
}
});
}
;(function(schedule){
schedule.waiting = [];
schedule.soonest = Infinity;
schedule.sort = Gun.list.sort('when');
schedule.set = function(future){
var now = Gun.time.is();
future = (future <= now)? 0 : (future - now);
clearTimeout(schedule.id);
schedule.id = setTimeout(schedule.check, future);
}
schedule.check = function(){
var now = Gun.time.is(), soonest = Infinity;
schedule.waiting.sort(schedule.sort);
schedule.waiting = Gun.list.map(schedule.waiting, function(wait, i, map){
if(!wait){ return }
if(wait.when <= now){
if(Gun.fns.is(wait.event)){
wait.event();
}
} else {
soonest = (soonest < wait.when)? soonest : wait.when;
map(wait);
}
}) || [];
schedule.set(soonest);
}
Gun.schedule = function(state, cb){
schedule.waiting.push({when: state, event: cb});
if(schedule.soonest < state){ return }
schedule.set(state);
}
}({}));
;(function(Serializer){
Gun.ify = function(data, gun){
var gun = Gun.is(this)? this : {}
, context = {
nodes: {}
,seen: []
,_seen: []
}, nothing;
function ify(data, context, sub){
sub = sub || {};
sub.path = sub.path || '';
context = context || {};
context.nodes = context.nodes || {};
if((sub.simple = Gun.ify.is(data)) && !(sub._ && Gun.text.is(sub.simple))){
return data;
} else
if(Gun.obj.is(data)){
var value = {}, symbol = {}, seen
, err = {err: "Metadata does not support external or circular references at " + sub.path, meta: true};
context.root = context.root || value;
if(seen = ify.seen(context._seen, data)){
//console.log("seen in _", sub._, sub.path, data);
context.err = err;
return;
} else
if(seen = ify.seen(context.seen, data)){
//console.log("seen in data", sub._, sub.path, data);
if(sub._){
context.err = err;
return;
}
symbol = ify.id(gun, symbol, seen);
return symbol;
} else {
//console.log("seen nowhere", sub._, sub.path, data);
if(sub._){
context.seen.push({data: data, node: value});
} else {
value._ = ify.id(gun, {}, data);
context.seen.push({data: data, node: value});
context.nodes[value._[own.sym.id]] = value;
}
}
Gun.obj.map(data, function(val, key){
var subs = {path: sub.path + key + '.', _: sub._ || (key == own.sym.meta)? true : false };
val = ify(val, context, subs);
//console.log('>>>>', sub.path + key, 'is', val);
if(context.err){ return true }
if(nothing === val){ return }
// TODO: check key validity
value[key] = val;
});
if(sub._){ return value }
if(!value._ || !value._[own.sym.id]){ return }
symbol[own.sym.id] = value._[own.sym.id];
return symbol;
} else
if(Gun.list.is(data)){
var unique = {}, edges
, err = {err: "Arrays cause data corruption at " + sub.path, array: true}
edges = Gun.list.map(data, function(val, i, map){
val = ify(val, context, sub);
if(context.err){ return true }
if(!Gun.obj.is(val)){
context.err = err;
return true;
}
return Gun.obj.map(val, function(id, key){
if(key !== own.sym.id){
context.err = err;
return true;
}
if(unique[id]){ return }
unique[id] = 1;
map(val);
});
});
if(context.err){ return }
return edges;
} else {
context.err = {err: "Data type not supported at " + sub.path, invalid: true};
}
}
ify.seen = function(seen, data){
// unfortunately, using seen[data] = true will cause false-positives for data's children
return Gun.list.map(seen, function(check){
if(check.data === data){ return check.node }
});
}
ify.id = function(gun, to, from){
to = to || {};
if(ify.is(from)){
to[own.sym.id] = from._[own.sym.id];
return to;
}
to[own.sym.id] = Gun.roulette.call(gun);
return to;
}
ify.is = function(o){
if(o && o._ && o._[own.sym.id]){
return true;
}
}
ify(data, context);
return context;
}
Gun.ify.is = function(v){ // null, binary, number (!Infinity), text, or a ref.
if(v === null){ return true } // deletes
if(v === Infinity){ return false }
if(Gun.bi.is(v)
|| Gun.num.is(v)
|| Gun.text.is(v)){
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)){
var yes;
Gun.obj.map(v, function(id, key){
if(yes){ return yes = false }
if(key === own.sym.id && Gun.text.is(id)){
yes = id;
}
});
if(yes){
return yes;
}
}
return false;
}
}());
own.sym = Gun.sym = {
id: '#'
,meta: '_'
,HAM: '>'
}
if(typeof window !== "undefined"){
window.Gun = Gun;
} else {
module.exports = Gun;
}
}({}));

View File

@ -1 +1 @@
module.exports = require('./shots2');
module.exports = require('./shots');

View File

@ -7,13 +7,12 @@
}
, "dependencies": {
"mime": "~>1.2.11",
"theory": "~>0.2.6",
"coalesce": "~>0.1.9-bv",
"aws-sdk": "~>2.0.0",
"fakeredis": "~>0.1.3",
"redis": "~>0.10.1",
"hiredis": ""
"request": "~>2.39.0"
}
, "devDependencies": {
"chance": "~>2.39.0"
}
, "scripts": {
"start": "node init.js"
}

View File

@ -1,148 +1,148 @@
module.exports = require('theory')
('shot',function(a){
return function(opt){
opt = opt || {};
opt.path = opt.path || '.'
opt.batch = opt.batch || 0;
opt.throttle = opt.throttle || 0;
opt.src = opt.src || (this && this.com) || '';
opt.cache = a.num.is(opt.cache)? opt.cache : opt.cache || 1;
if(root.node){ return require(opt.path+'/shots')(opt); }
var u, shot = {},
store = window.amplify && window.amplify.store? amplify.store
: function(src, data){
if(data === u){ return store[src] }
return store[src] = data;
}
store.batch = [];
store.last = a.time.now();
store.list = function(){
var g = store(a.gun.event) || {}
, z = function(l,g,i){
if(i !== 0 && !i){ return }
if(!l || !l[i]){ return }
shot.fire(l[i], 1);
console.log("re-sent", l[i]);
a.time.wait(function(){ z(l,g,i+1) },1);
}
a.obj(g).each(function(l,g){
z(l,g,0);
});
}
store.sort = function(A,B){
if(!A || !B){ return 0 }
A = ((A||{})._||{})[a.gun._.ham]; B = ((B||{})._||{})[a.gun._.ham];
if(A < B){ return -1 }
else if(A > B){ return 1 }
else { return 0 }
}
store.add = function(m, g, b){
if(!m){ return }
g = '_' + (a(g,'at') || g || a(m,'where.at') || m.where);
var gs = store(a.gun.event) || {}
, when = shot.when(m);
gs[g] = gs[g] || [];
if(a.list(gs[g]).each(function(v){
var w = shot.when(v);
if(w === when){
return true;
}
})){ return 2; } // already
if(opt.batch && a.list.is(b)){ b.push(m) }
gs[g].push(m);
store(a.gun.event, gs);
return gs[g];
}
store.del = function(m, g){
if(!m){ return }
var gs = store(a.gun.event) || {}
, when = shot.when(m);
g = '_'+(m.where.at || m.where || g);
console.log("clear queue", g, m);
gs[g] = gs[g] || [];
gs[g] = a.list(gs[g]).each(function(v,i,t){
var w = shot.when(v);
if(w === when){
return;
}
t(v);
});
store(a.gun.event, gs);
}
store.set = function(key, val){
var s = store(a.gun.event) || {};
s[key] = val;
store(a.gun.event, s);
}
store.get = function(key, cb){
var s = store(a.gun.event) || {};
s = s[key];
if(cb){
return cb(null, s);
}
return s;
};
a.gun.shots(shot.fire = function(m, r){
if(!m || !m.where){ return }
if(!r){
if(store.add(m, m.where, store.batch) === 2){
return;
}
}
if(opt.src && opt.src.send){
m = opt.src.meta(m);
if(!m.what || !m.where || !m.when){ return }
console.log("to server!", m);
return opt.src.send(m);
}
return; // below should be a fallback. TODO: Unfinished!
});
shot.when = function(m){ return a(m,'what._.'+a.gun._.ham) || a(m,'_.'+a.gun._.ham) || m.when }
shot.load = function(where,cb,o){
if(!where){ return }
o = o || {};
var m = {what: where, how: {gun:3}}
, g = a.gun.magazine[where] || store.get(where);
g = a.fns.is(g)? g : a.obj.is(g)? a.gun(where, g) : null;
if(g){
//cb(g);
}
//console.log("!!! ASK !!!");
if(opt.src && opt.src.ask){
opt.src.ask(m,function(m){
if(g){
//console.log("!!! double load !!!");
//return; // prevent load from calling twice! Add sync comparison.
}
if(!m || !m.what){ cb(null) }
if(o.cache !== 0){
if(o.cache || opt.cache){ // make options more configurable.
store.set(where, m.what);
}
}
m = a.gun(where, m.what);
cb(m);
});
}
}
shot.spray = function(filter){
if(filter && filter.how){
shot.spray.action(filter);
return shot;
}
if(a.fns.is(filter)){
shot.spray.action = filter;
return shot;
}
return shot.spray.action;
}
shot.spray.action = function(m){
if(!m || !m.how || !m.how.gun){ return }
if(m.how.gun === -1){
store.del(m);
}
}
store.list();
return shot;
}
},['./gun'])
module.exports = require('theory')
('shot',function(a){
return function(opt){
opt = opt || {};
opt.path = opt.path || '.'
opt.batch = opt.batch || 0;
opt.throttle = opt.throttle || 0;
opt.src = opt.src || (this && this.com) || '';
opt.cache = a.num.is(opt.cache)? opt.cache : opt.cache || 1;
if(root.node){ return require(opt.path+'/shots0')(opt); }
var u, shot = {},
store = window.amplify && window.amplify.store? amplify.store
: function(src, data){
if(data === u){ return store[src] }
return store[src] = data;
}
store.batch = [];
store.last = a.time.now();
store.list = function(){
var g = store(a.gun.event) || {}
, z = function(l,g,i){
if(i !== 0 && !i){ return }
if(!l || !l[i]){ return }
shot.fire(l[i], 1);
console.log("re-sent", l[i]);
a.time.wait(function(){ z(l,g,i+1) },1);
}
a.obj(g).each(function(l,g){
z(l,g,0);
});
}
store.sort = function(A,B){
if(!A || !B){ return 0 }
A = ((A||{})._||{})[a.gun._.ham]; B = ((B||{})._||{})[a.gun._.ham];
if(A < B){ return -1 }
else if(A > B){ return 1 }
else { return 0 }
}
store.add = function(m, g, b){
if(!m){ return }
g = '_' + (a(g,'at') || g || a(m,'where.at') || m.where);
var gs = store(a.gun.event) || {}
, when = shot.when(m);
gs[g] = gs[g] || [];
if(a.list(gs[g]).each(function(v){
var w = shot.when(v);
if(w === when){
return true;
}
})){ return 2; } // already
if(opt.batch && a.list.is(b)){ b.push(m) }
gs[g].push(m);
store(a.gun.event, gs);
return gs[g];
}
store.del = function(m, g){
if(!m){ return }
var gs = store(a.gun.event) || {}
, when = shot.when(m);
g = '_'+(m.where.at || m.where || g);
console.log("clear queue", g, m);
gs[g] = gs[g] || [];
gs[g] = a.list(gs[g]).each(function(v,i,t){
var w = shot.when(v);
if(w === when){
return;
}
t(v);
});
store(a.gun.event, gs);
}
store.set = function(key, val){
var s = store(a.gun.event) || {};
s[key] = val;
store(a.gun.event, s);
}
store.get = function(key, cb){
var s = store(a.gun.event) || {};
s = s[key];
if(cb){
return cb(null, s);
}
return s;
};
a.gun.shots(shot.fire = function(m, r){
if(!m || !m.where){ return }
if(!r){
if(store.add(m, m.where, store.batch) === 2){
return;
}
}
if(opt.src && opt.src.send){
m = opt.src.meta(m);
if(!m.what || !m.where || !m.when){ return }
console.log("to server!", m);
return opt.src.send(m);
}
return; // below should be a fallback. TODO: Unfinished!
});
shot.when = function(m){ return a(m,'what._.'+a.gun._.ham) || a(m,'_.'+a.gun._.ham) || m.when }
shot.load = function(where,cb,o){
if(!where){ return }
o = o || {};
var m = {what: where, how: {gun:3}}
, g = a.gun.magazine[where] || store.get(where);
g = a.fns.is(g)? g : a.obj.is(g)? a.gun(where, g) : null;
if(g){
//cb(g);
}
//console.log("!!! ASK !!!");
if(opt.src && opt.src.ask){
opt.src.ask(m,function(m){
if(g){
//console.log("!!! double load !!!");
//return; // prevent load from calling twice! Add sync comparison.
}
if(!m || !m.what){ cb(null) }
if(o.cache !== 0){
if(o.cache || opt.cache){ // make options more configurable.
store.set(where, m.what);
}
}
m = a.gun(where, m.what);
cb(m);
});
}
}
shot.spray = function(filter){
if(filter && filter.how){
shot.spray.action(filter);
return shot;
}
if(a.fns.is(filter)){
shot.spray.action = filter;
return shot;
}
return shot.spray.action;
}
shot.spray.action = function(m){
if(!m || !m.how || !m.how.gun){ return }
if(m.how.gun === -1){
store.del(m);
}
}
store.list();
return shot;
}
},['./gun0'])

480
shots.js
View File

@ -1,305 +1,183 @@
module.exports = require('theory')
('shot',function(a){
var s3 = require(__dirname+'/gate/s3')
, store = require(__dirname+'/gate/redis');
function shot(opt){
opt = opt || {};
var u, shot = {};
opt.path = opt.path || '.'
opt.batch = opt.batch || 10;
opt.throttle = opt.throttle || 15;
opt.src = opt.src || (this && this.com) || '';
opt.redis = opt.redis || {};
opt.redis.max = a.num.is(opt.redis.max)? opt.redis.max : .8;
opt.redis.Max = Math.floor(require('os').totalmem() * opt.redis.max);
opt.redis.append = a.obj(opt.redis).has('append')? opt.redis.append : true;
opt.redis.expire = opt.redis.expire || 60*15;
opt.redis.config = function(){
if(opt.redis.config.done === 0){ return }
opt.redis.config.done = 3;
var reply = function(e,r){
if(e){ return }
opt.redis.config.done -= 1;
};
if(opt.redis.max){
store.client.config('set','maxmemory',opt.redis.Max, reply);
store.client.config('set','maxmemory-policy','allkeys-lru', reply);
}
if(opt.redis.append){
store.client.config('set','appendonly','yes', reply);
}
}
opt.s3 = opt.s3 || {};
opt.s3.Bucket = a.text.is(opt.s3.bucket)? opt.s3.bucket : (process.env.s3Bucket || '');
opt.s3.bucket = a.fns.is(opt.s3.bucket)? opt.s3.bucket : function(key){
return opt.s3.Bucket || a.text(key).clip('/',0,1);
}
opt.s3.key = a.fns.is(opt.s3.key)? opt.s3.key : function(key){
if(key.slice(0, opt.s3.Bucket.length) === opt.s3.Bucket){
key = key.slice(opt.s3.Bucket.length)||'';
if(key.charAt(0) === '/'){
key = key.slice(1);
}
}
return key;
}
store.batch = [];
store.last = a.time.now();
store.push = function(key, score, val, cb){
if(!val){ return }
store.client.zadd(key, score, val, function(e,r){
if(e){
store.clienf.zadd(key, score, val, cb);
return;
}
if(cb){ cb(e,r) }
});
}
store.when = function(m){ return a(m,'what._.'+a.gun._.ham) || a(m,'_.'+a.gun._.ham) || m.when }
store.where = function(m){ return a.text.is(m)? m : a.text.is(m.where)? m.where : m.where.at }
store.add = function(m, g){
if(!m){ return }
g = '_' + (g || a(m,'where.at') || m.where);
store.push(g, store.when(m) || 0, a.text.ify(m));
}
store.del = function(m, g){
}
store.sort = function(A,B){
if(!A || !B){ return 0 }
A = A.w; B = B.w;
if(A < B){ return -1 }
else if(A > B){ return 1 }
else { return 0 }
}
store.batching = 0;
store.batched = {};
store.batch = {};
store.persisted = {};
store.wait = null;
store.stay = function(key, val, cb){
store.batching += 1;
store.batch[key] = val;
(store.batched[key] = store.batched[key]||[]).push(cb);
if(opt.batch < store.batching){
return store.stay.now();
}
if(!opt.throttle){
return store.stay.now();
}
store.wait = store.wait || a.time.wait(store.stay.now, opt.throttle * 1000); // to seconds
}
store.stay.now = function(){
store.batching = 0;
a.time.stop(store.wait);
store.wait = null;
a.obj(store.batch).each(function(g,where){
if(!g || !where){ return }
//console.log('*************** save', where, '*******************');
store.stay.put(where,g,function(e,r){
a.list(store.batched[where]).each(function(cb){
if(a.fns.is(cb)){ cb(e,r) }
console.log('*** saved ***');
});
console.log(store.batched[where]);
delete store.batched[where];
});
});
}
store.stay.put = function(where,obj,cb){
s3(opt.s3.bucket(where)).put(opt.s3.key(where),obj,function(e,r){
if(!e){ store.persisted[where] = 's3' }
if(a.fns.is(cb)){ cb(e,r) }
});
}
store.set = function(key, value, cb, fn){
opt.redis.config();
var val = a.text.is(value)? value : a.text.ify(value);
if(a.fns.is(fn)){ store.stay(key, value, fn) }
//console.log("potential setex:", key, opt.redis.expire, val);
if(opt.redis.max){
store.client.set(key, val, function(e,r){
if(e){
store.clienf.setex(key, opt.redis.expire, val, cb);
return;
}
if(cb){ cb(e,r) }
});
} else {
store.client.setex(key, opt.redis.expire, val, function(e,r){
if(e){
store.clienf.setex(key, opt.redis.expire, val, cb);
return;
}
if(cb){ cb(e,r) }
});
}
}
store.get = function(key, cb){
store.clienf.get(key, function(e,r){
if(e || !r){ return store.client.get(key, cb) }
if(cb){ cb(e,r) }
});
}
shot.load = function(where,cb,o){
//console.log("shot.load >", where);
if(!where){ return }
where = store.where(where);
if(!a.text.is(where)){ return }
if(a.fns.is(a.gun.magazine[where])){
console.log('via memory', where);
cb(a.gun.magazine[where], null); // TODO: Need to clear queue these at some point, too!
return;
}
if(opt.src && opt.src.send){
//console.log("Getting and subscribe");
opt.src.send({where:{on: where}, how: {gun: 2}});
}
store.get(where, function(e,r){
if(e || !r){
return s3(opt.s3.bucket(where)).get(opt.s3.key(where),function(e,r,t){
console.log('via s3', where); if(e){ console.log(e) }
if(e || !r){ return cb(null, e) }
store.persisted[where] = 's3';
store.set(where, (t || a.text.ify(r)));
r = shot.load.action(where,r); //a.gun(where,r);
cb(r, e);
},o);
}
console.log('via redis', where);
r = a.obj.ify(r);
r = shot.load.action(where,r); //a.gun(where,r);
cb(r,e);
});
}
shot.load.action = function(w,o){
if(!w || !o){ return }
return a.gun(w,o);
}
shot.spray = function(m){
if(m && m.how){
shot.spray.action(m);
return shot;
}
if(a.fns.is(m)){
shot.spray.transform = m;
return shot.spray.action;
}
return shot.spray.action;
}
shot.spray.transform = function(g,m,d){if(d){d()}}
shot.spray.action = function(m){
console.log("gun spray ---->", m, (opt.src && opt.src.way? opt.src.way : null));
if(!m || !m.how){ return }
var where = store.where(m);
if(m.how.gun === -2){
console.log("gun data from others", m);
if(m && m.what && m.what.session){ console.log(m.what.session) }
return;
}
if(m.how.gun === 2){
if(!a.fns.is(a.gun.magazine[where])){
return;
}
if(opt.src && opt.src.send){
console.log("gun subscribe sync", m);
opt.src.send({what: a.gun.magazine[where](), where: where, how: {gun: -(m.how.gun||2)}});
}
return;
}
if(m.how.gun === 3){
shot.load(m.what, function(g,e){
shot.pump.action(g, m, function(){ // receive custom edited copy here and send it down instead.
if(!opt.src || !opt.src.reply){ return }
m.what = a.fns.is(g)? g() : {};
m.how.gun = -(m.how.gun||3);
opt.src.reply(m);
}, e);
});
return;
}
if(!where){ return }
store.add(m);
var n = a.obj.copy(m);
shot.load(where, function(g,e){
var done = function(){
var u, s, w = store.when(m) || 0, r = {}, cb;
m.how.gun = -(m.how.gun||1);
g = a.fns.is(g)? g : (a.gun.magazine[where] || function(){});
a.obj(m.what).each(function(v,p){
if(g(p,v,w) === u){
r[p] = 0; // Error code
return;
} s = true;
});
m.what = r;
cb = function(){
if(!opt.src || !opt.src.reply || m.where.mid){ return }
opt.src.reply(m);
console.log('reply', m);
}
if(!s){ return cb() }
store.set(where, g(), null, cb);
};
done.end = function(){};
shot.spray.transform(g, m, done, e);
});
if(n.where && !n.where.mid && opt.src.send){
n.who = {};
opt.src.send(n);
}
}
if(opt.src && opt.src.on){
opt.src.on(shot.spray.action);
}
shot.pump = function(fn){
shot.pump.action = fn || shot.pump.action;
return shot;
}
shot.pump.action = function(g,m,d){if(d){d()}}
shot.server = function(req,res){
console.log('shot server', req);
;(function(){
var Gun = require(__dirname+'/gun')
, S3 = require(__dirname+'/gate/s3') // redis has been removed, can be replaced with a disk system
, url = require('url')
, meta = {};
Gun.on('init').event(function(gun, opt){
gun.server = gun.server || function(req, res){ // where is the data? is it JSON? declare contentType=JSON from client?
console.log("gun server has requests!", req.headers, req.body, req.url, req.method);
/*meta.CORS(req, res);
res.emit('data', {way: 'cool'});
res.emit('data', {shish: 'kabob'});
res.emit('data', {I: 'love'});
res.end();
return;*/
if(!req || !res){ return }
var b = shot.server.get(req);
if(!b || !b.b){ return }
b = a.obj.ify((b||{}).b);
if(a.obj.is(b)){ b = [b] }
if(!a.list.is(b)){ return }
//console.log('gun >>>>>>');
a.list(b).each(function(v,i){
//console.log(v);
});
//console.log('<<<<<< gun');
if(req.how && req.when && req.who && a.fns.is(res)){
req.what.body = {ok:1};
res(req);
if(!req.url){ return }
if(!req.method){ return }
var tmp = {};
tmp.url = url.parse(req.url, true);
if(!gun.server.regex.test(tmp.url.pathname)){ return }
tmp.key = tmp.url.pathname.replace(gun.server.regex,'').replace(/^\//i,''); // strip the base
if(!tmp.key){
return meta.JSON(res, {gun: true});
}
if('get' === req.method.toLowerCase()){ // get is used as subscribe
// raw test for now:
s3.load(tmp.key, function(err, data){
console.log("gun subscribed!", err, data);
meta.CORS(req, res);
return meta.JSON(res, data || err);
})
} else
if('post' === req.method.toLowerCase()){ // post is used as patch, sad that patch has such poor support
}
}
gun.server.regex = /^\/gun/i;
var s3 = gun._.opt.s3 = gun._.opt.s3 || S3(opt && opt.s3);
s3.path = s3.path || opt.s3.path || '';
s3.keyed = s3.keyed || opt.s3.keyed || '';
s3.nodes = s3.nodes || opt.s3.nodes || '_/nodes/';
gun._.opt.batch = opt.batch || gun._.opt.batch || 10;
gun._.opt.throttle = opt.throttle || gun._.opt.throttle || 2;
if(!gun._.opt.keepMaxSockets){ require('https').globalAgent.maxSockets = require('http').globalAgent.maxSockets = Infinity } // WARNING: Document this!
s3.load = s3.load || function(key, cb, opt){
cb = cb || function(){};
opt = opt || {};
if(opt.id){
key = s3.path + s3.nodes + key;
} else {
key = s3.path + s3.keyed + key;
}
s3.get(key, function(err, data, text, meta){
console.log('via s3', key);
if(meta && (key = meta[Gun.sym.id])){
return s3.load(key, cb, {id: true});
}
if(err && err.statusCode == 404){
err = null; // we want a difference between 'unfound' (data is null) and 'error' (auth is wrong).
}
cb(err, data);
});
}
s3.set = s3.set || function(nodes, cb){
s3.batching += 1;
cb = cb || function(){};
cb.count = 0;
var next = s3.next
, ack = Gun.text.random(8)
, batch = s3.batch[next] = s3.batch[next] || {};
s3.event.on(ack).once(cb);
Gun.obj.map(nodes, function(node, id){
cb.count += 1;
batch[id] = (batch[id] || 0) + 1;
console.log("set listener for", next + ':' + id, batch[id], cb.count);
s3.event.on(next + ':' + id).event(function(){
cb.count -= 1;
console.log("transaction", cb.count);
if(!cb.count){
s3.event.on(ack).emit();
this.off(); // MEMORY LEAKS EVERYWHERE!!!!!!!!!!!!!!!! FIX THIS!!!!!!!!!
}
});
});
if(gun._.opt.batch < s3.batching){
return s3.set.now();
}
if(!gun._.opt.throttle){
return s3.set.now();
}
s3.wait = s3.wait || setTimeout(s3.set.now, gun._.opt.throttle * 1000); // in seconds
}
s3.set.now = s3.set.now || function(){
clearTimeout(s3.wait);
s3.batching = 0;
s3.wait = null;
var now = s3.next
, batch = s3.batch[s3.next];
s3.next = Gun.time.is();
Gun.obj.map(batch, function put(exists, id){
var node = gun._.nodes[id]; // the batch does not actually have the nodes, but what happens when we do cold data? Could this be gone?
s3.put(s3.path + s3.nodes + id, node, function(err, reply){
console.log("s3 put reply", id, err, reply);
if(err || !reply){
put(exists, id); // naive implementation of retry TODO: BUG: need backoff and anti-infinite-loop!
return;
}
s3.event.on(now + ':' + id).emit(200);
});
});
}
s3.next = s3.next || Gun.time.is();
s3.event = s3.event || Gun.on.split();
s3.batching = s3.batching || 0;
s3.batched = s3.batched || {};
s3.batch = s3.batch || {};
s3.persisted = s3.persisted || {};
s3.wait = s3.wait || null;
s3.key = s3.key || function(key, node, cb){
var id = node._[Gun.sym.id];
if(!id){
return cb({err: "No ID!"});
}
s3.put(s3.path + s3.keyed + key, '', function(err, reply){ // key is 2 bytes??? Should be smaller
console.log("s3 put reply", id, err, reply);
if(err || !reply){
s3.key(key, node, cb); // naive implementation of retry TODO: BUG: need backoff and anti-infinite-loop!
return;
}
cb();
}, {Metadata: {'#': id}});
}
gun.init({hook: {load: s3.load, set: s3.set, key: s3.key}}, true);
});
meta.json = 'application/json';
meta.JSON = function(res, data){
if(!res || res._headerSent){ return }
res.setHeader('Content-Type', meta.json);
return res.end(JSON.stringify(data||''));
};
meta.CORS = function(req, res){
if(!res || res.CORSHeader || res._headerSent){ return }
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", ["POST", "GET", "PUT", "DELETE", "OPTIONS"]);
res.setHeader("Access-Control-Allow-Credentials", true);
res.setHeader("Access-Control-Max-Age", 1000 * 60 * 60 * 24);
res.setHeader("Access-Control-Allow-Headers", ["X-Requested-With", "X-HTTP-Method-Override", "Content-Type", "Accept"]);
res.CORSHeader = true;
if(req && req.method === 'OPTIONS'){
res.end();
return true;
}
shot.server.get = function(m){
return !a.obj.empty(a(m,'what.form'))? a(m,'what.form')
: !a.obj.empty(a(m,'what.url.query'))? a(m,'what.url.query')
: false ;
};
a.gun.shots(function(m){
var w;
if(!store.persisted[w = store.where(m)]){
if(opt.src && opt.src.send){
//console.log("made and subscribed", m);
opt.src.send({where:{on: w}, how: {gun: 2}})
}
store.stay.put(w, m.what, function(e,r){
//console.log("---> gun shots", m, "new graph saved!");
});
return;
}
if(opt.src && opt.src.send){
opt.src.send(m);
}
});
shot.gun = a.gun;
return shot;
}
shot.gun = a.gun;
return shot;
},[__dirname+'/gun'])
};
module.exports = Gun;
}());
/**
Knox S3 Config is:
knox.createClient({
key: ''
, secret: ''
, bucket: ''
, endpoint: 'us-standard'
, port: 0
, secure: true
, token: ''
, style: ''
, agent: ''
});
aws-sdk for s3 is:
{ "accessKeyId": "akid", "secretAccessKey": "secret", "region": "us-west-2" }
AWS.config.loadFromPath('./config.json');
{
accessKeyId: process.env.AWS_ACCESS_KEY_ID = ''
,secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY = ''
,Bucket: process.env.s3Bucket = ''
,region: process.env.AWS_REGION = "us-east-1"
,sslEnabled: ''
}
**/

305
shots0.js Normal file
View File

@ -0,0 +1,305 @@
module.exports = require('theory')
('shot',function(a){
var s3 = require(__dirname+'/gate/s3')
, store = require(__dirname+'/gate/redis');
function shot(opt){
opt = opt || {};
var u, shot = {};
opt.path = opt.path || '.'
opt.batch = opt.batch || 10;
opt.throttle = opt.throttle || 15;
opt.src = opt.src || (this && this.com) || '';
opt.redis = opt.redis || {};
opt.redis.max = a.num.is(opt.redis.max)? opt.redis.max : .8;
opt.redis.Max = Math.floor(require('os').totalmem() * opt.redis.max);
opt.redis.append = a.obj(opt.redis).has('append')? opt.redis.append : true;
opt.redis.expire = opt.redis.expire || 60*15;
opt.redis.config = function(){
if(opt.redis.config.done === 0){ return }
opt.redis.config.done = 3;
var reply = function(e,r){
if(e){ return }
opt.redis.config.done -= 1;
};
if(opt.redis.max){
store.client.config('set','maxmemory',opt.redis.Max, reply);
store.client.config('set','maxmemory-policy','allkeys-lru', reply);
}
if(opt.redis.append){
store.client.config('set','appendonly','yes', reply);
}
}
opt.s3 = opt.s3 || {};
opt.s3.Bucket = a.text.is(opt.s3.bucket)? opt.s3.bucket : (process.env.s3Bucket || '');
opt.s3.bucket = a.fns.is(opt.s3.bucket)? opt.s3.bucket : function(key){
return opt.s3.Bucket || a.text(key).clip('/',0,1);
}
opt.s3.key = a.fns.is(opt.s3.key)? opt.s3.key : function(key){
if(key.slice(0, opt.s3.Bucket.length) === opt.s3.Bucket){
key = key.slice(opt.s3.Bucket.length)||'';
if(key.charAt(0) === '/'){
key = key.slice(1);
}
}
return key;
}
store.batch = [];
store.last = a.time.now();
store.push = function(key, score, val, cb){
if(!val){ return }
store.client.zadd(key, score, val, function(e,r){
if(e){
store.clienf.zadd(key, score, val, cb);
return;
}
if(cb){ cb(e,r) }
});
}
store.when = function(m){ return a(m,'what._.'+a.gun._.ham) || a(m,'_.'+a.gun._.ham) || m.when }
store.where = function(m){ return a.text.is(m)? m : a.text.is(m.where)? m.where : m.where.at }
store.add = function(m, g){
if(!m){ return }
g = '_' + (g || a(m,'where.at') || m.where);
store.push(g, store.when(m) || 0, a.text.ify(m));
}
store.del = function(m, g){
}
store.sort = function(A,B){
if(!A || !B){ return 0 }
A = A.w; B = B.w;
if(A < B){ return -1 }
else if(A > B){ return 1 }
else { return 0 }
}
store.batching = 0;
store.batched = {};
store.batch = {};
store.persisted = {};
store.wait = null;
store.stay = function(key, val, cb){
store.batching += 1;
store.batch[key] = val;
(store.batched[key] = store.batched[key]||[]).push(cb);
if(opt.batch < store.batching){
return store.stay.now();
}
if(!opt.throttle){
return store.stay.now();
}
store.wait = store.wait || a.time.wait(store.stay.now, opt.throttle * 1000); // to seconds
}
store.stay.now = function(){
store.batching = 0;
a.time.stop(store.wait);
store.wait = null;
a.obj(store.batch).each(function(g,where){
if(!g || !where){ return }
//console.log('*************** save', where, '*******************');
store.stay.put(where,g,function(e,r){
a.list(store.batched[where]).each(function(cb){
if(a.fns.is(cb)){ cb(e,r) }
console.log('*** saved ***');
});
console.log(store.batched[where]);
delete store.batched[where];
});
});
}
store.stay.put = function(where,obj,cb){
s3(opt.s3.bucket(where)).put(opt.s3.key(where),obj,function(e,r){
if(!e){ store.persisted[where] = 's3' }
if(a.fns.is(cb)){ cb(e,r) }
});
}
store.set = function(key, value, cb, fn){
opt.redis.config();
var val = a.text.is(value)? value : a.text.ify(value);
if(a.fns.is(fn)){ store.stay(key, value, fn) }
//console.log("potential setex:", key, opt.redis.expire, val);
if(opt.redis.max){
store.client.set(key, val, function(e,r){
if(e){
store.clienf.setex(key, opt.redis.expire, val, cb);
return;
}
if(cb){ cb(e,r) }
});
} else {
store.client.setex(key, opt.redis.expire, val, function(e,r){
if(e){
store.clienf.setex(key, opt.redis.expire, val, cb);
return;
}
if(cb){ cb(e,r) }
});
}
}
store.get = function(key, cb){
store.clienf.get(key, function(e,r){
if(e || !r){ return store.client.get(key, cb) }
if(cb){ cb(e,r) }
});
}
shot.load = function(where,cb,o){
//console.log("shot.load >", where);
if(!where){ return }
where = store.where(where);
if(!a.text.is(where)){ return }
if(a.fns.is(a.gun.magazine[where])){
console.log('via memory', where);
cb(a.gun.magazine[where], null); // TODO: Need to clear queue these at some point, too!
return;
}
if(opt.src && opt.src.send){
//console.log("Getting and subscribe");
opt.src.send({where:{on: where}, how: {gun: 2}});
}
store.get(where, function(e,r){
if(e || !r){
return s3(opt.s3.bucket(where)).get(opt.s3.key(where),function(e,r,t){
console.log('via s3', where); if(e){ console.log(e) }
if(e || !r){ return cb(null, e) }
store.persisted[where] = 's3';
store.set(where, (t || a.text.ify(r)));
r = shot.load.action(where,r); //a.gun(where,r);
cb(r, e);
},o);
}
console.log('via redis', where);
r = a.obj.ify(r);
r = shot.load.action(where,r); //a.gun(where,r);
cb(r,e);
});
}
shot.load.action = function(w,o){
if(!w || !o){ return }
return a.gun(w,o);
}
shot.spray = function(m){
if(m && m.how){
shot.spray.action(m);
return shot;
}
if(a.fns.is(m)){
shot.spray.transform = m;
return shot.spray.action;
}
return shot.spray.action;
}
shot.spray.transform = function(g,m,d){if(d){d()}}
shot.spray.action = function(m){
console.log("gun spray ---->", m, (opt.src && opt.src.way? opt.src.way : null));
if(!m || !m.how){ return }
var where = store.where(m);
if(m.how.gun === -2){
console.log("gun data from others", m);
if(m && m.what && m.what.session){ console.log(m.what.session) }
return;
}
if(m.how.gun === 2){
if(!a.fns.is(a.gun.magazine[where])){
return;
}
if(opt.src && opt.src.send){
console.log("gun subscribe sync", m);
opt.src.send({what: a.gun.magazine[where](), where: where, how: {gun: -(m.how.gun||2)}});
}
return;
}
if(m.how.gun === 3){
shot.load(m.what, function(g,e){
shot.pump.action(g, m, function(){ // receive custom edited copy here and send it down instead.
if(!opt.src || !opt.src.reply){ return }
m.what = a.fns.is(g)? g() : {};
m.how.gun = -(m.how.gun||3);
opt.src.reply(m);
}, e);
});
return;
}
if(!where){ return }
store.add(m);
var n = a.obj.copy(m);
shot.load(where, function(g,e){
var done = function(){
var u, s, w = store.when(m) || 0, r = {}, cb;
m.how.gun = -(m.how.gun||1);
g = a.fns.is(g)? g : (a.gun.magazine[where] || function(){});
a.obj(m.what).each(function(v,p){
if(g(p,v,w) === u){
r[p] = 0; // Error code
return;
} s = true;
});
m.what = r;
cb = function(){
if(!opt.src || !opt.src.reply || m.where.mid){ return }
opt.src.reply(m);
console.log('reply', m);
}
if(!s){ return cb() }
store.set(where, g(), null, cb);
};
done.end = function(){};
shot.spray.transform(g, m, done, e);
});
if(n.where && !n.where.mid && opt.src.send){
n.who = {};
opt.src.send(n);
}
}
if(opt.src && opt.src.on){
opt.src.on(shot.spray.action);
}
shot.pump = function(fn){
shot.pump.action = fn || shot.pump.action;
return shot;
}
shot.pump.action = function(g,m,d){if(d){d()}}
shot.server = function(req,res){
console.log('shot server', req);
if(!req || !res){ return }
var b = shot.server.get(req);
if(!b || !b.b){ return }
b = a.obj.ify((b||{}).b);
if(a.obj.is(b)){ b = [b] }
if(!a.list.is(b)){ return }
//console.log('gun >>>>>>');
a.list(b).each(function(v,i){
//console.log(v);
});
//console.log('<<<<<< gun');
if(req.how && req.when && req.who && a.fns.is(res)){
req.what.body = {ok:1};
res(req);
}
return true;
}
shot.server.get = function(m){
return !a.obj.empty(a(m,'what.form'))? a(m,'what.form')
: !a.obj.empty(a(m,'what.url.query'))? a(m,'what.url.query')
: false ;
};
a.gun.shots(function(m){
var w;
if(!store.persisted[w = store.where(m)]){
if(opt.src && opt.src.send){
//console.log("made and subscribed", m);
opt.src.send({where:{on: w}, how: {gun: 2}})
}
store.stay.put(w, m.what, function(e,r){
//console.log("---> gun shots", m, "new graph saved!");
});
return;
}
if(opt.src && opt.src.send){
opt.src.send(m);
}
});
shot.gun = a.gun;
return shot;
}
shot.gun = a.gun;
return shot;
},[__dirname+'/gun0'])

134
shots2.js
View File

@ -1,134 +0,0 @@
;(function(){
var Gun = require(__dirname+'/gun2')
, S3 = require(__dirname+'/gate/s3'); // redis has been removed, to be replaced with a disk system
Gun.server = function(req, res){
console.log("gun server has requests!");
}
Gun.on('init').event(function(gun, opt){
var s3 = gun._.opt.s3 = gun._.opt.s3 || S3(opt && opt.s3);
s3.path = s3.path || opt.s3.path || '';
s3.indices = s3.indices || opt.s3.indices || '';
s3.nodes = s3.nodes || opt.s3.nodes || '_/nodes/';
gun._.opt.batch = opt.batch || gun._.opt.batch || 10;
gun._.opt.throttle = opt.throttle || gun._.opt.throttle || 2;
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, opt){
cb = cb || function(){};
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);
if(meta && (index = meta[Gun.sym.id])){
return s3.load(index, cb, {id: true});
}
if(err && err.statusCode == 404){
err = null; // we want a difference between 'unfound' (data is null) and 'error' (keys are wrong)
}
cb(err, data);
});
}
s3.set = s3.set || function(nodes, cb){
s3.batching += 1;
cb = cb || function(){};
cb.count = 0;
var next = s3.next
, ack = Gun.text.random(8)
, batch = s3.batch[next] = s3.batch[next] || {};
s3.event.on(ack).once(cb);
Gun.obj.map(nodes, function(node, id){
cb.count += 1;
batch[id] = (batch[id] || 0) + 1;
console.log("set listener for", next + ':' + id, batch[id], cb.count);
s3.event.on(next + ':' + id).event(function(){
cb.count -= 1;
console.log("transaction", cb.count);
if(!cb.count){
s3.event.on(ack).emit();
this.off(); // MEMORY LEAKS EVERYWHERE!!!!!!!!!!!!!!!! FIX THIS!!!!!!!!!
}
});
});
if(gun._.opt.batch < s3.batching){
return s3.set.now();
}
if(!gun._.opt.throttle){
return s3.set.now();
}
s3.wait = s3.wait || setTimeout(s3.set.now, gun._.opt.throttle * 1000); // in seconds
}
s3.set.now = s3.set.now || function(){
clearTimeout(s3.wait);
s3.batching = 0;
s3.wait = null;
var now = s3.next
, batch = s3.batch[s3.next];
s3.next = Gun.time.is();
Gun.obj.map(batch, function put(exists, id){
var node = gun._.nodes[id]; // the batch does not actually have the nodes, but what happens when we do cold data? Could this be gone?
s3.put(s3.path + s3.nodes + id, node, function(err, reply){
console.log("s3 put reply", id, err, reply);
if(err || !reply){
put(exists, id); // naive implementation of retry
return;
}
s3.event.on(now + ':' + id).emit(200);
});
});
}
s3.next = s3.next || Gun.time.is();
s3.event = s3.event || Gun.on.split();
s3.batching = s3.batching || 0;
s3.batched = s3.batched || {};
s3.batch = s3.batch || {};
s3.persisted = s3.persisted || {};
s3.wait = s3.wait || null;
s3.index = s3.index || function(index, node, cb){
var id = node._[Gun.sym.id];
if(!id){
return cb({err: "No ID!"});
}
s3.put(s3.path + s3.indices + index, '', function(err, reply){ // index is 2 bytes??? Should be smaller
console.log("s3 put reply", id, err, reply);
if(err || !reply){
put(exists, id); // naive implementation of retry
return;
}
cb();
}, {Metadata: {'#': id}});
}
gun.init({hook: {load: s3.load, set: s3.set, index: s3.index}}, true);
});
module.exports = Gun;
}());
/**
Knox S3 Config is:
knox.createClient({
key: ''
, secret: ''
, bucket: ''
, endpoint: 'us-standard'
, port: 0
, secure: true
, token: ''
, style: ''
, agent: ''
});
aws-sdk for s3 is:
{ "accessKeyId": "akid", "secretAccessKey": "secret", "region": "us-west-2" }
AWS.config.loadFromPath('./config.json');
{
accessKeyId: process.env.AWS_ACCESS_KEY_ID = ''
,secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY = ''
,Bucket: process.env.s3Bucket = ''
,region: process.env.AWS_REGION = "us-east-1"
,sslEnabled: ''
}
**/

View File

@ -1,5 +1,5 @@
describe('Gun', function(){
var Gun = require('../gun2');
var Gun = require('../gun');
it('ify', function(){
var data, test;
@ -63,8 +63,8 @@ describe('Gun', function(){
it('path', function(done){
this.timeout(9000);
var gun = require('./shotgun');
gun.load('email/mark@accelsor.com')
.path('account.email')
gun.load('d1ed426098eae2bba8c60605e1e4552f66281770', null, {id: true}) // get Rodney Morris
.path('parent.parent.first') // Rodney's parent is Juan Colon, whose parent is Francis Peters
.get(function(val){
console.log("val!", val);
done();

View File

@ -1,7 +1,7 @@
module.exports=require('theory')
('shoot',function(a){
if(root.node){
var shot = require('../shots')({src: a.com, batch: 999}).pump(function(g, m, done){
var shot = require('../../shots0')({src: a.com, batch: 999}).pump(function(g, m, done){
console.log('>>> pump!');
done();
});
@ -195,4 +195,4 @@ module.exports=require('theory')
},'.field');
});
return shot.spray;
},['../shot']);
},['../../shot0']);

View File

@ -9,7 +9,7 @@ if(process.env.LIVE || (process.env.NODE_ENV === 'production')){
}
}
var Gun = require('../shots2');
var Gun = require('../shots');
var gun = Gun({
peers: 'http://localhost:8888/gun'
,s3: keys