mirror of
https://github.com/amark/gun.git
synced 2025-06-05 21:56:51 +00:00
meaningless update cause I want to push
This commit is contained in:
parent
d001931e38
commit
5c50241007
11
examples/admin/data.json
Normal file
11
examples/admin/data.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"_":{
|
||||
"#":"yVbyf7BqlXVQQUOE5cw9rf8h",
|
||||
">":{
|
||||
"hello":1407328713707,
|
||||
"from":1407328713707
|
||||
}
|
||||
},
|
||||
"hello":"world",
|
||||
"from":"Mark Nadal"
|
||||
}
|
83
examples/admin/index.html
Normal file
83
examples/admin/index.html
Normal 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>
|
@ -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>
|
@ -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('!!!!!!!!!!!!!!!!!!!!!!')});
|
@ -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'});
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
})();
|
@ -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'), {});
|
27
gate/sock.js
27
gate/sock.js
File diff suppressed because one or more lines are too long
577
gun0.js
Normal file
577
gun0.js
Normal 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
559
gun2.js
@ -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;
|
||||
}
|
||||
}({}));
|
2
index.js
2
index.js
@ -1 +1 @@
|
||||
module.exports = require('./shots2');
|
||||
module.exports = require('./shots');
|
@ -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"
|
||||
}
|
||||
|
@ -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
480
shots.js
@ -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
305
shots0.js
Normal 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
134
shots2.js
@ -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: ''
|
||||
}
|
||||
**/
|
@ -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();
|
||||
|
@ -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']);
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user