mirror of
https://github.com/amark/gun.git
synced 2026-03-07 17:41:45 +00:00
Hypothetical Amnesia Machine ready!
This commit is contained in:
@@ -17,5 +17,6 @@ app.listen(port);
|
||||
|
||||
console.log('Express started on port ' + port + ' with /gun');
|
||||
gun.load('blob/data').blank(function(){ // in case there is no data on this key
|
||||
gun.set({ hello: "world", from: "Mark Nadal" }).key('blob/data'); // save some sample data
|
||||
console.log("blankety blank");
|
||||
gun.set({ hello: "world", from: "Mark Nadal",_:{'#':'0DFXd0ckJ9cXGczusNf1ovrE'}}).key('blob/data'); // save some sample data
|
||||
});
|
||||
@@ -1,226 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html ng-app="admin">
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<script src="https://ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js"></script>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
|
||||
<script src="../../gun.js"></script>
|
||||
</head>
|
||||
<body ng-controller="editor">
|
||||
<style>
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: Verdana, Geneva, sans-serif;
|
||||
}
|
||||
a {
|
||||
color: skyblue;
|
||||
text-decoration: none;
|
||||
cursor: poiner;
|
||||
}
|
||||
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;
|
||||
}
|
||||
.fight {
|
||||
z-index: 9999;
|
||||
background: brown;
|
||||
color: white;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.player input, .player button {
|
||||
font-size: 18pt;
|
||||
}
|
||||
.hold {
|
||||
padding: .2em;
|
||||
}
|
||||
</style>
|
||||
<div id="duel" class="none fight">
|
||||
<center>
|
||||
<h2>GET READY!</h2>
|
||||
<button id="reset" class="none">
|
||||
Reset the game!
|
||||
</button>
|
||||
</center>
|
||||
</div>
|
||||
|
||||
<div class="hold">
|
||||
<h2><i>GUNSLINGER</i></h2>
|
||||
<span>Old West Duel! Two players are needed, whoever can tap the screen first to draw their pistol and shoot wins!</span><br>
|
||||
<span><b>Fastest gun in the west, <span name="fastest">nut'n</span> seconds, by <span name="slinger">nobody</span>.</b></span>
|
||||
<form id="p1" class="player" onsubmit="return false;">
|
||||
Player 1: <input type="text" name="p1" placeholder="nickname"> <button type="submit">Join!</button>
|
||||
</form>
|
||||
<form id="p2" class="player" onsubmit="return false;">
|
||||
Player 2: <input type="text" name="p2" placeholder="nickname"> <button type="submit">Join!</button>
|
||||
</form>
|
||||
<span><b>Last duel won by <span name="last">no one</span> in <span name="ended">0</span> seconds against <span name="loser">nobody</span>.</b></span>
|
||||
</div>
|
||||
<textarea id="debug" style="position: fixed; bottom: 0; width: 100%; height: 5em; z-index: 99999999999;"></textarea>
|
||||
<script>
|
||||
console._log = console.log;console.log = function(a,s,d,f){ var arg = arguments, s = '';
|
||||
for(var i in arg){ var val = arg[i]; if(typeof val == 'string'){ s += val + ' ' } else { s += JSON.stringify(val) + ' ' } }; $("#debug").prepend(s + '\n\n') }
|
||||
$(function(){
|
||||
var me = window.me = {},
|
||||
game = window.game = {},
|
||||
//gun = window.gun = Gun([location.origin + '/gun'])
|
||||
//gun = window.gun = Gun(['http://localhost:8888/' + 'gun'])
|
||||
gun = window.gun = Gun(['https://gunjs.herokuapp.com/gun'])
|
||||
.load('game/duel', function(data){
|
||||
console.log(data);
|
||||
$(document).on('submit', '.player', function(e){
|
||||
e.preventDefault();
|
||||
var nick = $(this).find('input').val(), id = this.id;
|
||||
console.log(nick, me.player);
|
||||
if(!nick || me.player){ return }
|
||||
gun.path(id).get(function(val){
|
||||
if(val){ return }
|
||||
this.set(me.player = nick);
|
||||
me.took = id;
|
||||
});
|
||||
})
|
||||
Gun.on(data._[Gun.sym.id]).event(function(node, local){
|
||||
if(!node){ return }
|
||||
console.log("change!", node);
|
||||
if(node.start){ game.schedule(node.start) }
|
||||
if(node.dqed){ game.dq(node.dqed) }
|
||||
if(node.sling){ game.sling(node.sling, local) }
|
||||
Gun.obj.map(node, game.set);
|
||||
if(node.p1 || node.p2){
|
||||
gun.path('p1').get(function(p1){ // start game?
|
||||
if(!p1){ return }
|
||||
gun.path('p2').get(function(p2){
|
||||
if(!p2){ return }
|
||||
game.play(p2);
|
||||
})
|
||||
});
|
||||
}
|
||||
game.timeout(true);
|
||||
});
|
||||
Gun.obj.map(data, game.set);
|
||||
game.timeout(20);
|
||||
});
|
||||
game.$duel = $("#duel");
|
||||
game.$duelm = game.$duel.clone();
|
||||
game.play = function(p2){
|
||||
if(!me.player){ return }
|
||||
game.$duel.removeClass("none");
|
||||
if(me.player == p2){ return }
|
||||
me.scheduled = (+new Date()) + Math.round(Math.random() * 2000 + 2700); // MIN is the right number, and MAX is the SUM of both numbers.
|
||||
gun.path('start').set(me.scheduled);
|
||||
}
|
||||
game.schedule = function(at){
|
||||
console.log(" ------------------ START", at);
|
||||
if(me.started){ return }
|
||||
me.started = true;
|
||||
me.scheduled = at;
|
||||
Gun.schedule(at, function(){
|
||||
me.shoot = true;
|
||||
if(me.dqed){ return }
|
||||
game.$duel.css({background: 'lime'}).find('h2').text("FIRE!");
|
||||
});
|
||||
}
|
||||
game.fire = function(){
|
||||
console.log('bang', me);
|
||||
if(!me.started || me.fired){ return }
|
||||
me.fired = (+ new Date());
|
||||
if(me.fired < me.scheduled){ // DQ
|
||||
me.dqed = me.player;
|
||||
gun.path('dqed').set(me.player);
|
||||
alert('DQing you');
|
||||
return;
|
||||
}
|
||||
gun.path('dqed').get(function(yes){
|
||||
alert('dqed ' + yes);
|
||||
if(yes){ return }
|
||||
game.$duel.css({background: 'gold'}).find('h2').text("STOP!");
|
||||
gun.path('sling').set(me.player);
|
||||
me.time = (me.fired - me.scheduled) / 1000; // in seconds
|
||||
});
|
||||
}
|
||||
game.sling = function(){
|
||||
me.count = (me.count || 0) + 1;
|
||||
if(me.count < 2){ return }
|
||||
$('#reset').removeClass('none');
|
||||
gun.path('sling').get(function(sling){
|
||||
if(!sling){ return }
|
||||
if(sling == me.player){
|
||||
game.$duel.css({background: 'red'}).find('h2').text("YOU DIED!!!");
|
||||
gun.path('loser').set(me.player);
|
||||
return;
|
||||
}
|
||||
game.$duel.css({background: 'skyblue'}).find('h2').text("YOU WON!!!");
|
||||
if(!me.time || me.fired < me.scheduled || me.time < 0){ return }
|
||||
gun.path('last').set(me.player);
|
||||
gun.path('ended').set(me.time);
|
||||
gun.path('fastest').get(function(time){
|
||||
if(time <= me.time){ return }
|
||||
gun.path('fastest').set(me.time);
|
||||
gun.path('slinger').set(me.player);
|
||||
});
|
||||
});
|
||||
}
|
||||
game.dq = function(who){
|
||||
$('#reset').removeClass('none');
|
||||
if(who == me.player){
|
||||
return game.$duel.css({background: 'gray'}).find('h2').text("DISQUALIFIED!!!");
|
||||
}
|
||||
if(me.dqed){
|
||||
return game.$duel.find('h2').text("BOTH DISQUALIFIED!");
|
||||
}
|
||||
game.$duel.css({background: 'skyblue'}).find('h2').text("YOU WON!!!");
|
||||
}
|
||||
game.clear = function(){
|
||||
me = {};
|
||||
game.$duel.replaceWith(game.$duel = game.$duelm.clone());
|
||||
gun.path('p1').set("");
|
||||
gun.path('p2').set("");
|
||||
gun.path('sling').set(null);
|
||||
gun.path('start').set(null);
|
||||
gun.path('dqed').set(null);
|
||||
game.$duel.addClass('none');
|
||||
}
|
||||
game.timeout = function(wait){
|
||||
if(true === wait){ return clearTimeout(me.timeout) }
|
||||
wait = wait || 15;
|
||||
clearTimeout(me.timeout);
|
||||
me.timeout = setTimeout(game.clear, wait * 1000);
|
||||
}
|
||||
game.set = function(val, name){
|
||||
if(val == game.nothing){ return }
|
||||
$("[name='" + name + "']").text(val).val(val);
|
||||
Gun.on("duel-" + name).emit(val, name);
|
||||
}
|
||||
game.plock = function(val, id){
|
||||
$("#" + id).find('input').attr("readonly", val? true : false);
|
||||
$("#" + id).find('button').text(val? "Taken!" : "Join!").attr("disabled", val? true : false);
|
||||
}
|
||||
Gun.on("duel-p1").event(game.plock);
|
||||
Gun.on("duel-p2").event(game.plock);
|
||||
$(document).on('click', '#duel', game.fire);
|
||||
$(document).on('click', '#reset', game.clear);
|
||||
}());
|
||||
</script>
|
||||
<script>
|
||||
(function(){
|
||||
return;
|
||||
var game = Gun(location + 'gun').load('game/duel');
|
||||
game.on('change').path('p1').or.path('p2').get(function(val){
|
||||
$("#" + this.field).find('input').val(val? "Taken!" : "Join!").attr("disabled", val? true : false);
|
||||
$("#" + this.field).find('button').val(val? "Taken!" : "Join!").attr("disabled", val? true : false);
|
||||
});
|
||||
}());
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -62,15 +62,12 @@
|
||||
var gun = Gun([location + 'gun']);
|
||||
angular.module('admin', []).controller('editor', function($scope){
|
||||
$scope.data = {};
|
||||
$scope.$data = gun.load('blob/data', function(data){
|
||||
$scope.data = data;
|
||||
$scope.$apply();
|
||||
Gun.on(data._[Gun.sym.id]).event(function(node){ // one liner-ify this!
|
||||
Gun.obj.map(node, function(val, field){
|
||||
$scope.data[field] = val;
|
||||
});
|
||||
$scope.$apply();
|
||||
$scope.$data = gun.load('blob/data').get(function(data){
|
||||
Gun.obj.map(data, function(val, field){
|
||||
if(val === $scope.data[field]){ return }
|
||||
$scope.data[field] = val;
|
||||
});
|
||||
$scope.$apply();
|
||||
});
|
||||
$scope.add = function(a,b,c){
|
||||
$scope.$data.path($scope.field).set( $scope.data[$scope.field] = 'value' );
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
, "dependencies": {
|
||||
"express": "~>4.9.0",
|
||||
"body-parser": "~>1.8.1",
|
||||
"gun": "0.0.6-e"
|
||||
"gun": "0.0.7"
|
||||
}
|
||||
, "scripts": {
|
||||
"start": "node app.js",
|
||||
|
||||
195
examples/admin/slinger.html
Normal file
195
examples/admin/slinger.html
Normal file
@@ -0,0 +1,195 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<script src="https://ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js"></script>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
|
||||
<script src="../../gun.js"></script>
|
||||
</head>
|
||||
<body><center>
|
||||
<style>
|
||||
html, body {
|
||||
font-family: Papyrus, fantasy;
|
||||
font-size: 18pt;
|
||||
}
|
||||
.start .player {
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 1.5em;
|
||||
background: skyblue;
|
||||
font-family: Papyrus, fantasy;
|
||||
}
|
||||
.screen {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.off {
|
||||
display: none;
|
||||
}
|
||||
.white {
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
<div class="start screen">
|
||||
<!--<pre>
|
||||
¦¦¦¦¦¦+ ¦¦+ ¦¦+ ¦¦¦+ ¦¦+ ¦¦¦¦¦¦¦+ ¦¦+ ¦¦+ ¦¦¦+ ¦¦+ ¦¦¦¦¦¦+ ¦¦¦¦¦¦¦+ ¦¦¦¦¦¦+
|
||||
¦¦+----+ ¦¦¦ ¦¦¦ ¦¦¦¦+ ¦¦¦ ¦¦+----+ ¦¦¦ ¦¦¦ ¦¦¦¦+ ¦¦¦ ¦¦+----+ ¦¦+----+ ¦¦+--¦¦+
|
||||
¦¦¦ ¦¦¦+ ¦¦¦ ¦¦¦ ¦¦+¦¦+ ¦¦¦ ¦¦¦¦¦¦¦+ ¦¦¦ ¦¦¦ ¦¦+¦¦+ ¦¦¦ ¦¦¦ ¦¦¦+ ¦¦¦¦¦+ ¦¦¦¦¦¦++
|
||||
¦¦¦ ¦¦¦ ¦¦¦ ¦¦¦ ¦¦¦+¦¦+¦¦¦ +----¦¦¦ ¦¦¦ ¦¦¦ ¦¦¦+¦¦+¦¦¦ ¦¦¦ ¦¦¦ ¦¦+--+ ¦¦+--¦¦+
|
||||
+¦¦¦¦¦¦++ +¦¦¦¦¦¦++ ¦¦¦ +¦¦¦¦¦ ¦¦¦¦¦¦¦¦ ¦¦¦¦¦¦¦+ ¦¦¦ ¦¦¦ +¦¦¦¦¦ +¦¦¦¦¦¦++ ¦¦¦¦¦¦¦+ ¦¦¦ ¦¦¦
|
||||
+-----+ +-----+ +-+ +---+ +------+ +------+ +-+ +-+ +---+ +-----+ +------+ +-+ +-+
|
||||
</pre>-->
|
||||
<h1>GUN SLINGER</h1>
|
||||
<h3>Select!</h3>
|
||||
<button id="one" class="player">Player 1</button>
|
||||
<button id="two" class="player">Player 2</button>
|
||||
<h5>Next game available in 15 seconds or less...<h5>
|
||||
</div>
|
||||
<div class="shoot screen off white" style="background: tan;">
|
||||
<h3>GET READY!</h3>
|
||||
</div>
|
||||
<div class="fire screen off" style="background: lime;">
|
||||
<h3>FIRE!</h3>
|
||||
<h5>by tapping this screen</h5>
|
||||
</div>
|
||||
<div class="stop screen off" style="background: yellow;">
|
||||
<h3>STOP!</h3>
|
||||
<h5>...waiting for the other player...</h5>
|
||||
</div>
|
||||
<div class="disqualified screen off white" style="background: red;">
|
||||
<h3>DISQUALIFIED!</h3>
|
||||
</div>
|
||||
<div class="loser screen off white" style="background: red;">
|
||||
<h3>YOU DIED!</h3>
|
||||
</div>
|
||||
<div class="draw screen off white" style="background: red;">
|
||||
<h3>YOU BOTH DIED!</h3>
|
||||
<button onclick="game.reset()">Reset Game</button>
|
||||
</div>
|
||||
<div class="winner screen off white" style="background: skyblue;">
|
||||
<h3>YOU WON!</h3>
|
||||
<button onclick="game.reset()">Reset Game</button>
|
||||
</div>
|
||||
<script>
|
||||
$(function(){
|
||||
var game = window.game = {me:{}}
|
||||
//, gun = Gun(location.origin + '/gun')
|
||||
, gun = window.gun = Gun('http://localhost:8888' + '/gun')
|
||||
.load('game/duel')
|
||||
;
|
||||
gun.path('name').get(function(val){
|
||||
console.log('gunslinger has results', val);
|
||||
});
|
||||
gun.get(function(player){
|
||||
console.log("Game update", player);
|
||||
if(game.timeout){
|
||||
clearTimeout(game.timeout);
|
||||
} else {
|
||||
game.timeout = setTimeout(game.reset, 15 * 1000);
|
||||
}
|
||||
$('.start').find('#one').text(player.one? 'Taken!' : 'Player 1').attr('disabled', player.one? true : false);
|
||||
$('.start').find('#two').text(player.two? 'Taken!' : 'Player 2').attr('disabled', player.two? true : false);
|
||||
game.start(player);
|
||||
game.compare(player);
|
||||
});
|
||||
gun.path('dqed').get(function(){
|
||||
if(!game.me.player || game.me.dqed){ return }
|
||||
game.me.default = true;
|
||||
game.screen('winner');
|
||||
});
|
||||
gun.path('one').get(function(val){
|
||||
console.log('gun player one', val);
|
||||
if(null === val){
|
||||
game.cancel();
|
||||
}
|
||||
})
|
||||
game.start = function(player){
|
||||
if(game.me.started){ return }
|
||||
if(!player.one || !player.two){ return }
|
||||
if(!player || !game.me || !game.me.player){ return }
|
||||
console.log("start?", player, game.me);
|
||||
if(player[game.me.player] == game.me[game.me.player]){
|
||||
game.screen('shoot');
|
||||
game.coordinate();
|
||||
} else {
|
||||
game.cancel();
|
||||
}
|
||||
}
|
||||
gun.path('coordinate').get(game.coordinate = function(at){
|
||||
if(!game.me.player){ return }
|
||||
var started = game.me.started = Gun.roulette();
|
||||
if(at){
|
||||
Gun.schedule(at, function(){
|
||||
if(game.me.dqed || game.me.default || started != game.me.started){ return }
|
||||
game.screen('fire');
|
||||
game.me.draw = (+new Date());
|
||||
});
|
||||
return;
|
||||
}
|
||||
if(game.me.player != 'two'){ return }
|
||||
game.me.coordinate = (+new Date()) + Math.round(Math.random() * 2000 + 2700); // MIN is the right number, and MAX is the SUM of both numbers.
|
||||
gun.path('coordinate').set(game.me.coordinate);
|
||||
});
|
||||
game.compare = function(score){
|
||||
if(!game.me.player || !score.onespeed || !score.twospeed){ return }
|
||||
if(score.onespeed < score.twospeed){
|
||||
if(game.me.one){
|
||||
game.screen('winner');
|
||||
} else {
|
||||
game.screen('loser');
|
||||
}
|
||||
} else
|
||||
if(score.twospeed < score.onespeed){
|
||||
if(game.me.two){
|
||||
game.screen('winner');
|
||||
} else {
|
||||
game.screen('loser');
|
||||
}
|
||||
} else {
|
||||
game.screen('draw');
|
||||
}
|
||||
}
|
||||
game.reset = function(){
|
||||
console.log("Resetting game");
|
||||
gun.path('one').set(null);
|
||||
gun.path('two').set(null);
|
||||
gun.path('dqed').set(null);
|
||||
gun.path('coordinate').set(null);
|
||||
gun.path('onespeed').set(null);
|
||||
gun.path('twospeed').set(null);
|
||||
game.cancel();
|
||||
}
|
||||
game.cancel = function(){
|
||||
game.screen();
|
||||
game.me = {};
|
||||
}
|
||||
game.screen = function(screen){
|
||||
$('.screen').addClass('off').filter('.' + (screen || 'start')).removeClass('off');
|
||||
}
|
||||
$('.player').on('click', function(){
|
||||
if(game.me.player){ return }
|
||||
game.me = {};
|
||||
gun.path(game.me.player = this.id).set(game.me[game.me.player] = Gun.roulette());
|
||||
});
|
||||
$('.shoot').on('click', function(){
|
||||
if(!game.me.player){ return }
|
||||
game.me.dqed = true;
|
||||
game.screen('disqualified');
|
||||
gun.path('dqed').set(game.me[game.me.player]);
|
||||
});
|
||||
$('.fire').on('click', function(){
|
||||
if(!game.me.player || game.me.fired){ return }
|
||||
game.me.fired = (+new Date());
|
||||
game.me.speed = game.me.fired - game.me.draw;
|
||||
gun.path(game.me.player + 'speed').set(game.me.speed);
|
||||
game.screen('stop');
|
||||
});
|
||||
})
|
||||
</script>
|
||||
</center></body>
|
||||
</html>
|
||||
13
gate/s3.js
13
gate/s3.js
@@ -5,7 +5,7 @@
|
||||
return new s3(opt);
|
||||
}
|
||||
var s = this;
|
||||
s.own = a.on.split();
|
||||
s.on = a.on.create();
|
||||
s.mime = require('mime');
|
||||
s.AWS = require('aws-sdk');
|
||||
s.config = {};
|
||||
@@ -33,7 +33,7 @@
|
||||
s3.chain = s3.prototype;
|
||||
s3.chain.put = function(key, o, cb, m){
|
||||
if(!key){ return }
|
||||
var m = m || {}
|
||||
m = m || {}
|
||||
m.Bucket = m.Bucket || this.config.bucket;
|
||||
m.Key = m.Key || key;
|
||||
if(a.obj.is(o) || a.list.is(o)){
|
||||
@@ -56,7 +56,7 @@
|
||||
Bucket: s.config.bucket
|
||||
,Key: key
|
||||
}, id = s3.id(m);
|
||||
s.own.on(id).once(function(e,d,t,m,r){
|
||||
s.on(id).once(function(e,d,t,m,r){
|
||||
delete s.batch[id];
|
||||
if(!a.fns.is(cb)){ return }
|
||||
try{ cb(e,d,t,m,r);
|
||||
@@ -69,15 +69,16 @@
|
||||
s.batch[id] = (s.batch[id] || 0) + 1;
|
||||
console.log("no batch!");
|
||||
s.S3().getObject(m, function(e,r){
|
||||
var d, t, m, r = r || (this && this.httpResponse);
|
||||
if(e || !r){ return s.own.on(id).emit(e) }
|
||||
var d, t, m;
|
||||
r = r || (this && this.httpResponse);
|
||||
if(e || !r){ return s.on(id).emit(e) }
|
||||
r.Text = r.text = t = (r.Body||r.body||'').toString('utf8');
|
||||
r.Type = r.type = r.ContentType || (r.headers||{})['content-type'];
|
||||
if(r.type && 'json' === s.mime.extension(r.type)){
|
||||
d = a.obj.ify(t);
|
||||
}
|
||||
m = r.Metadata;
|
||||
s.own.on(id).emit(e, d, t, m, r); // Warning about the r parameter, is is the raw response and may result in stupid SAX errors.
|
||||
s.on(id).emit(e, d, t, m, r); // Warning about the r parameter, is is the raw response and may result in stupid SAX errors.
|
||||
});
|
||||
return s;
|
||||
}
|
||||
|
||||
46
on.js
Normal file
46
on.js
Normal file
@@ -0,0 +1,46 @@
|
||||
;(function(){
|
||||
var setImmediate = setImmediate || function(cb){setTimeout(cb,0)}
|
||||
function On(){
|
||||
var chain = new Chain();
|
||||
return chain.$ = function(where){
|
||||
chain.$[where] = function(fn){
|
||||
chain.$[where] = fn;
|
||||
}
|
||||
chain.where = where;
|
||||
return chain;
|
||||
}
|
||||
}
|
||||
On.is = function(On){ return (On instanceof On)? true : false }
|
||||
function Chain(){
|
||||
if(!(this instanceof Chain)){
|
||||
return new Chain();
|
||||
}
|
||||
}
|
||||
Chain.chain = Chain.prototype;
|
||||
Chain.chain.emit = function(a,s,d,f){
|
||||
var me = this
|
||||
, where = me.where
|
||||
, args = Array.prototype.slice.call(arguments);
|
||||
setImmediate(function(){
|
||||
if(!me || !me.$ || !me.$[where]){ return }
|
||||
me.$[where].apply(me, args);
|
||||
});
|
||||
return me;
|
||||
}
|
||||
if(typeof window !== "undefined"){
|
||||
window.On = On;
|
||||
} else {
|
||||
module.exports = On;
|
||||
}
|
||||
|
||||
;(function(){ // test
|
||||
var doSomething = function(){
|
||||
var cb = On();
|
||||
cb('now').emit(1,2,3);
|
||||
return cb;
|
||||
}
|
||||
doSomething('foo', 'bar').now(function(a,b,c){
|
||||
console.log("Oh yeah baby", a,b,c);
|
||||
})
|
||||
}());
|
||||
}());
|
||||
@@ -1,5 +1,5 @@
|
||||
{ "name": "gun"
|
||||
, "version": "0.0.6-e"
|
||||
, "version": "0.0.7"
|
||||
, "author": "Mark Nadal"
|
||||
, "description": "Graph engine."
|
||||
, "engines": {
|
||||
|
||||
215
shots.js
215
shots.js
@@ -38,10 +38,10 @@
|
||||
}
|
||||
}
|
||||
meta.CORS(req, res); // add option to disable this
|
||||
if(reply.chunk){
|
||||
if(Gun.obj.has(reply,'chunk')){
|
||||
res.write(Gun.text.ify(reply.chunk) || '');
|
||||
}
|
||||
if(reply.body){
|
||||
if(Gun.obj.has(reply,'body')){
|
||||
res.end(Gun.text.ify(reply.body) || '');
|
||||
}
|
||||
});
|
||||
@@ -71,17 +71,18 @@
|
||||
if(!gun.__.opt.keepMaxSockets){ require('https').globalAgent.maxSockets = require('http').globalAgent.maxSockets = Infinity } // WARNING: Document this!
|
||||
|
||||
s3.load = s3.load || function(key, cb, opt){
|
||||
if(!key){ return }
|
||||
cb = cb || function(){};
|
||||
opt = opt || {};
|
||||
if(opt.id){
|
||||
key = s3.prefix + s3.prenode + key;
|
||||
if(key[Gun._.soul]){
|
||||
key = s3.prefix + s3.prenode + key[Gun._.soul];
|
||||
} else {
|
||||
key = s3.prefix + s3.prekey + key;
|
||||
}
|
||||
s3.get(key, function(err, data, text, meta){
|
||||
console.log('via s3', key, err);
|
||||
if(meta && (key = meta[Gun.sym.id])){
|
||||
return s3.load(key, cb, {id: true});
|
||||
if(meta && meta[Gun._.soul]){
|
||||
return s3.load(meta, cb);
|
||||
}
|
||||
if(err && err.statusCode == 404){
|
||||
err = null; // we want a difference between 'unfound' (data is null) and 'error' (auth is wrong).
|
||||
@@ -96,16 +97,16 @@
|
||||
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){
|
||||
s3.on(ack).once(cb);
|
||||
Gun.obj.map(nodes, function(node, soul){
|
||||
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(){
|
||||
batch[soul] = (batch[soul] || 0) + 1;
|
||||
//console.log("set listener for", next + ':' + soul, batch[soul], cb.count);
|
||||
s3.on(next + ':' + soul).event(function(){
|
||||
cb.count -= 1;
|
||||
//console.log("transaction", cb.count);
|
||||
if(!cb.count){
|
||||
s3.event.on(ack).emit();
|
||||
s3.on(ack).emit();
|
||||
this.off(); // MEMORY LEAKS EVERYWHERE!!!!!!!!!!!!!!!! FIX THIS!!!!!!!!!
|
||||
}
|
||||
});
|
||||
@@ -125,39 +126,40 @@
|
||||
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.prefix + s3.prenode + id, node, function(err, reply){
|
||||
console.log("s3 put reply", id, err, reply);
|
||||
Gun.obj.map(batch, function put(exists, soul){
|
||||
var node = gun.__.graph[soul]; // the batch does not actually have the nodes, but what happens when we do cold data? Could this be gone?
|
||||
s3.put(s3.prefix + s3.prenode + soul, node, function(err, reply){
|
||||
console.log("s3 put reply", soul, err, reply);
|
||||
if(err || !reply){
|
||||
put(exists, id); // naive implementation of retry TODO: BUG: need backoff and anti-infinite-loop!
|
||||
put(exists, soul); // naive implementation of retry TODO: BUG: need backoff and anti-infinite-loop!
|
||||
return;
|
||||
}
|
||||
s3.event.on(now + ':' + id).emit(200);
|
||||
s3.on(now + ':' + soul).emit(200);
|
||||
});
|
||||
});
|
||||
}
|
||||
s3.next = s3.next || Gun.time.is();
|
||||
s3.event = s3.event || Gun.on.split();
|
||||
s3.on = s3.on || Gun.on.create();
|
||||
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.key = s3.key || function(key, soul, cb){
|
||||
var meta = {};
|
||||
meta[Gun._.soul] = soul = Gun.text.is(soul)? soul : (soul||{})[Gun._.soul];
|
||||
if(!soul){
|
||||
return cb({err: "No soul!"});
|
||||
}
|
||||
s3.put(s3.prefix + s3.prekey + key, '', function(err, reply){ // key is 2 bytes??? Should be smaller
|
||||
console.log("s3 put reply", id, err, reply);
|
||||
console.log("s3 put reply", soul, err, reply);
|
||||
if(err || !reply){
|
||||
s3.key(key, node, cb); // naive implementation of retry TODO: BUG: need backoff and anti-infinite-loop!
|
||||
s3.key(key, soul, cb); // naive implementation of retry TODO: BUG: need backoff and anti-infinite-loop!
|
||||
return;
|
||||
}
|
||||
cb();
|
||||
}, {Metadata: {'#': id}});
|
||||
}, {Metadata: meta});
|
||||
}
|
||||
|
||||
gun.server.transport = (function(){
|
||||
@@ -176,12 +178,13 @@
|
||||
return tran.load(req, req.tran); // else load the state for the tab!
|
||||
}
|
||||
tran.load = function(req, cb){
|
||||
var reply = {};
|
||||
var reply = {}, key;
|
||||
reply.headers = {'Content-Type': tran.json};
|
||||
reply.headers['Gun-Sub'] = req.tab.sub = req.sub;
|
||||
gun.load(req.url.key, function(node){
|
||||
console.log("Loading for", req.tab);
|
||||
tran.sub.scribe(req.tab, node._[Gun.sym.id]);
|
||||
key = (Gun._.meta == req.url.key)? req.url.query : req.url.key;
|
||||
console.log("Loading", req.url.key, 'for', req.tab);
|
||||
gun.load(key, function(node){
|
||||
tran.sub.scribe(req.tab, node._[Gun._.soul]);
|
||||
cb({
|
||||
headers: reply.headers
|
||||
,body: node
|
||||
@@ -202,79 +205,84 @@
|
||||
if(!req.body){ return cb({body: {err: "No body"}}) }
|
||||
// raw test for now, no auth:
|
||||
// should probably load all the nodes first? YES.
|
||||
var context = Gun.chain.set.now.union.call(gun, req.body); // data safely transformed
|
||||
//console.log("body?", req.body, context.err);
|
||||
if(context.err){ return cb({body: {err: context.err}}) }
|
||||
// WARNING! TODO: BUG! Do not send OK confirmation if amnesiaQuaratine is activated! Not until after it has actually been processed!!!
|
||||
if(Gun.fns.is(gun.__.opt.hooks.set)){
|
||||
gun.__.opt.hooks.set(context.nodes, function saved(err, data){ // now iterate through those nodes to S3 and get a callback once all are saved
|
||||
var body = {};
|
||||
if(err){
|
||||
body.err = err ;
|
||||
}
|
||||
if(!req.sub){
|
||||
if(!err){
|
||||
body = defer.map({}, context.nodes, 1);
|
||||
var context = gun.union(req.body, function(err, context){ // data safely transformed
|
||||
cb = cb || function(){};
|
||||
if(err || context.err){ return cb({body: {err: context.err}}) }
|
||||
if(Gun.fns.is(gun.__.opt.hooks.set)){
|
||||
gun.__.opt.hooks.set(context.nodes, function saved(err, data){ // now iterate through those nodes to S3 and get a callback once all are saved
|
||||
var body = {};
|
||||
if(err){
|
||||
body.err = err ;
|
||||
}
|
||||
return cb({body: body});
|
||||
}
|
||||
var now = tran.post.s[req.sub]; // begin our stupid Chrome fix, we should abstract this out into defer (where it belogns) to keep things clean.
|
||||
if(!now){ return } // utoh we've lost our reply to the tab!
|
||||
clearTimeout(now.timeout);
|
||||
now.body = now.body || {}; // make sure we have a body for our multi-response in a single response.
|
||||
if(req.wait){ // did this request get deferred?
|
||||
(now.body.refed = now.body.refed || {})[req.wait] = err? {err: err} : defer.map({}, context.nodes, 1); // then reply to it "here".
|
||||
} else {
|
||||
now.body.reply = err? {err: err} : defer.map({}, context.nodes, 1); // else this is the original POST that had to be upgraded.
|
||||
}
|
||||
if(0 < (now.count = ((now.count || 0) - 1))){ // Don't reply till all deferred POSTs have successfully heard back from S3. (Sarcasm: Like counting guarantees that)
|
||||
return now.timeout = setTimeout(saved, gun.__.opt.throttle * 2 * 1000); // reply not guaranteed, so time it out, in seconds.
|
||||
}
|
||||
if(Gun.fns.is(now)){
|
||||
now({body: now.body}); // FINALLY reply for ALL the POSTs for that session that accumulated.
|
||||
} else {
|
||||
// console.log("Error! We deleted our response!");
|
||||
}
|
||||
Gun.obj.del(tran.post.s, req.sub); // clean up our memory.
|
||||
// need to rewrite that if Stream is enabled that both Stream + State save are guaranteed before replying.
|
||||
});
|
||||
// stuff past this point is just stupid implementation optimizations.
|
||||
function defer(nodes, req){ // because Chrome can only handle 4 requests at a time, sad face.
|
||||
if(!req.sub){
|
||||
return;
|
||||
}
|
||||
var next = tran.post.s[req.sub];
|
||||
if(!next){ // was there a previous POST? If not, we become the previous POST.
|
||||
//cb({chunk: ''}); // because on some services (heroku) you need to reply starting a stream to keep the connection open.
|
||||
return tran.post.s[req.sub] = cb;
|
||||
}
|
||||
next.count = (next.count || 1) + 1; // start counting how many we accumulate
|
||||
next.body = next.body || {}; // this becomes the polyfill for all the posts
|
||||
next.body.refed = next.body.refed || {}; // where we refeed the responses for the deferred POSTs.
|
||||
req.wait = Gun.text.random(); // generate an random id for this deferred POST.
|
||||
next.body.refed[req.wait] = false; // establish that we are incomplete.
|
||||
cb({body: {defer: req.wait}}); // end this POST immediately so Chrome only ever uses a couple connections.
|
||||
cb = null; // null it out so we don't accidentally reply to it once we hear back from S3.
|
||||
}
|
||||
defer.map = function(now, nodes, val){ // shortcut for maping which nodes were saved successfully
|
||||
if(!now){ return }
|
||||
Gun.obj.map(nodes, function(node, id, map){
|
||||
now[id] = val;
|
||||
if(!req.sub){
|
||||
if(!err){
|
||||
body = defer.map({}, context.nodes, 1);
|
||||
}
|
||||
return cb({body: body});
|
||||
}
|
||||
var now = tran.post.s[req.sub]; // begin our stupid Chrome fix, we should abstract this out into defer (where it belogns) to keep things clean.
|
||||
if(!now){ return } // utoh we've lost our reply to the tab!
|
||||
clearTimeout(now.timeout);
|
||||
now.body = now.body || {}; // make sure we have a body for our multi-response in a single response.
|
||||
if(req.wait){ // did this request get deferred?
|
||||
(now.body.refed = now.body.refed || {})[req.wait] = err? {err: err} : defer.map({}, context.nodes, 1); // then reply to it "here".
|
||||
} else {
|
||||
now.body.reply = err? {err: err} : defer.map({}, context.nodes, 1); // else this is the original POST that had to be upgraded.
|
||||
}
|
||||
if(0 < (now.count = ((now.count || 0) - 1))){
|
||||
// Don't reply till all deferred POSTs have successfully heard back from S3. (Sarcasm: Like counting guarantees that)
|
||||
return now.timeout = setTimeout(saved, gun.__.opt.throttle * 2 * 1000); // reply not guaranteed, so time it out, in seconds.
|
||||
}
|
||||
if(Gun.fns.is(now)){
|
||||
now({body: now.body}); // FINALLY reply for ALL the POSTs for that session that accumulated.
|
||||
} else {
|
||||
// console.log("Error! We deleted our response!");
|
||||
}
|
||||
Gun.obj.del(tran.post.s, req.sub); // clean up our memory.
|
||||
// need to rewrite that if Stream is enabled that both Stream + State save are guaranteed before replying.
|
||||
});
|
||||
return now;
|
||||
// stuff past this point is just stupid implementation optimizations.
|
||||
function defer(nodes, req){ // because Chrome can only handle 4 requests at a time, sad face.
|
||||
if(!req.sub){
|
||||
return;
|
||||
}
|
||||
var next = tran.post.s[req.sub];
|
||||
if(!next){ // was there a previous POST? If not, we become the previous POST.
|
||||
//cb({chunk: ''}); // because on some services (heroku) you need to reply starting a stream to keep the connection open.
|
||||
return tran.post.s[req.sub] = cb;
|
||||
}
|
||||
next.count = (next.count || 1) + 1; // start counting how many we accumulate
|
||||
next.body = next.body || {}; // this becomes the polyfill for all the posts
|
||||
next.body.refed = next.body.refed || {}; // where we refeed the responses for the deferred POSTs.
|
||||
req.wait = Gun.text.random(); // generate an random id for this deferred POST.
|
||||
next.body.refed[req.wait] = false; // establish that we are incomplete.
|
||||
cb({body: {defer: req.wait}}); // end this POST immediately so Chrome only ever uses a couple connections.
|
||||
cb = null; // null it out so we don't accidentally reply to it once we hear back from S3.
|
||||
}
|
||||
defer.map = function(now, nodes, val){ // shortcut for maping which nodes were saved successfully
|
||||
if(!now){ return }
|
||||
Gun.obj.map(nodes, function(node, soul, map){
|
||||
now[soul] = val;
|
||||
});
|
||||
return now;
|
||||
}
|
||||
defer(context.nodes, req); // actually do the weird stuff to make Chrome not be slow
|
||||
} else {
|
||||
context.err = "Warning! You have no persistence layer to save to!";
|
||||
Gun.log(context.err);
|
||||
cb({body: {err: "Server has no persistence layer!"}});
|
||||
}
|
||||
defer(context.nodes, req); // actually do the weird stuff to make Chrome not be slow
|
||||
} else {
|
||||
context.err = "Warning! You have no persistence layer to save to!";
|
||||
Gun.log(context.err);
|
||||
cb({body: {err: "Server has no persistence layer!"}});
|
||||
});
|
||||
if(context.err){
|
||||
cb({body: {err: context.err}});
|
||||
return cb = null;
|
||||
}
|
||||
Gun.obj.map(context.nodes, function(node, id){ // live push the stream out in realtime to every tab subscribed
|
||||
Gun.obj.map(context.nodes, function(node, soul){ // live push the stream out in realtime to every tab subscribed
|
||||
var msg = {};
|
||||
msg.headers = req.headers; // polyfill the delta as its own message.
|
||||
msg.body = node;
|
||||
//console.log("emit delta", id);
|
||||
tran.push.on(id).emit(msg);
|
||||
console.log("emit delta", soul);
|
||||
tran.push(soul).emit(msg);
|
||||
});
|
||||
}
|
||||
tran.post.s = {};
|
||||
@@ -282,7 +290,6 @@
|
||||
//console.log("<-- ", req.sub, req.tran ," -->");
|
||||
req.tab = tran.sub.s[req.sub];
|
||||
if(!req.tab){
|
||||
console.log(req.url.query);
|
||||
cb({
|
||||
headers: {'Gun-Sub': ''}
|
||||
,body: {err: "Please re-initialize sub."}
|
||||
@@ -316,10 +323,10 @@
|
||||
Gun.obj.del(tran.sub.s, tab.sub)
|
||||
}, gun.__.opt.disconnect * mult * 1000); // in seconds
|
||||
}
|
||||
tran.sub.scribe = function(tab, id){
|
||||
tran.sub.scribe = function(tab, soul){
|
||||
tran.sub.s[tab.sub] = tab;
|
||||
tab.subs = tab.subs || {};
|
||||
tab.subs[id] = tab.subs[id] || tran.push.on(id).event(function(req){
|
||||
tab.subs[soul] = tab.subs[soul] || tran.push(soul).event(function(req){
|
||||
if(!req){ return }
|
||||
if(!tab){ return this.off() } // resolve any dangling callbacks
|
||||
req.sub = req.sub || req.headers['gun-sub'];
|
||||
@@ -349,13 +356,13 @@
|
||||
});
|
||||
}
|
||||
reply.headers["Content-Type"] = tran.json;
|
||||
if(res.chunk){
|
||||
if(Gun.obj.has(res,'chunk')){
|
||||
cb({
|
||||
headers: reply.headers
|
||||
,chunk: Gun.text.ify(res.chunk) + '\n'
|
||||
})
|
||||
}
|
||||
if(res.body){
|
||||
if(Gun.obj.has(res,'body')){
|
||||
cb({
|
||||
headers: reply.headers
|
||||
,body: Gun.text.ify(res.body)
|
||||
@@ -382,10 +389,10 @@
|
||||
reply.headers[field] = val;
|
||||
});
|
||||
}
|
||||
if(res.chunk && (!reply.body || Gun.list.is(reply.chunks))){
|
||||
if(Gun.obj.has(res,'chunk') && (!reply.body || Gun.list.is(reply.chunks))){
|
||||
(reply.chunks = reply.chunks || []).push(res.chunk);
|
||||
}
|
||||
if(res.body){
|
||||
if(Gun.obj.has(res,'body')){
|
||||
reply.body = res.body; // self-reference yourself so on the client we can get the headers and body.
|
||||
reply.body = ';'+ cb.jsonp + '(' + Gun.text.ify(reply) + ');'; // javascriptify it! can't believe the client trusts us.
|
||||
cb(reply);
|
||||
@@ -393,7 +400,7 @@
|
||||
}
|
||||
}
|
||||
tran.json = 'application/json';
|
||||
tran.push = Gun.on.split();
|
||||
tran.push = Gun.on.create();
|
||||
return tran;
|
||||
}());
|
||||
|
||||
|
||||
150
test/common.js
150
test/common.js
@@ -1,5 +1,153 @@
|
||||
describe('Gun', function(){
|
||||
var Gun = require('../gun');
|
||||
var Gun = require('../gun')
|
||||
, t = {};
|
||||
describe('Utility', function(){
|
||||
describe('Type Check', function(){
|
||||
it('binary', function(){
|
||||
expect(Gun.bi.is(false)).to.be(true);
|
||||
expect(Gun.bi.is(true)).to.be(true);
|
||||
expect(Gun.bi.is('')).to.be(false);
|
||||
expect(Gun.bi.is('a')).to.be(false);
|
||||
expect(Gun.bi.is(0)).to.be(false);
|
||||
expect(Gun.bi.is(1)).to.be(false);
|
||||
expect(Gun.bi.is([])).to.be(false);
|
||||
expect(Gun.bi.is([1])).to.be(false);
|
||||
expect(Gun.bi.is({})).to.be(false);
|
||||
expect(Gun.bi.is({a:1})).to.be(false);
|
||||
expect(Gun.bi.is(function(){})).to.be(false);
|
||||
});
|
||||
it('number',function(){
|
||||
expect(Gun.num.is(0)).to.be(true);
|
||||
expect(Gun.num.is(1)).to.be(true);
|
||||
expect(Gun.num.is(Infinity)).to.be(true);
|
||||
expect(Gun.num.is(NaN)).to.be(false);
|
||||
expect(Gun.num.is('')).to.be(false);
|
||||
expect(Gun.num.is('a')).to.be(false);
|
||||
expect(Gun.num.is([])).to.be(false);
|
||||
expect(Gun.num.is([1])).to.be(false);
|
||||
expect(Gun.num.is({})).to.be(false);
|
||||
expect(Gun.num.is({a:1})).to.be(false);
|
||||
expect(Gun.num.is(false)).to.be(false);
|
||||
expect(Gun.num.is(true)).to.be(false);
|
||||
expect(Gun.num.is(function(){})).to.be(false);
|
||||
});
|
||||
it('text',function(){
|
||||
expect(Gun.text.is('')).to.be(true);
|
||||
expect(Gun.text.is('a')).to.be(true);
|
||||
expect(Gun.text.is(false)).to.be(false);
|
||||
expect(Gun.text.is(true)).to.be(false);
|
||||
expect(Gun.text.is(0)).to.be(false);
|
||||
expect(Gun.text.is(1)).to.be(false);
|
||||
expect(Gun.text.is([])).to.be(false);
|
||||
expect(Gun.text.is([1])).to.be(false);
|
||||
expect(Gun.text.is({})).to.be(false);
|
||||
expect(Gun.text.is({a:1})).to.be(false);
|
||||
expect(Gun.text.is(function(){})).to.be(false);
|
||||
});
|
||||
it('list',function(){
|
||||
expect(Gun.list.is([])).to.be(true);
|
||||
expect(Gun.list.is([1])).to.be(true);
|
||||
expect(Gun.list.is(0)).to.be(false);
|
||||
expect(Gun.list.is(1)).to.be(false);
|
||||
expect(Gun.list.is('')).to.be(false);
|
||||
expect(Gun.list.is('a')).to.be(false);
|
||||
expect(Gun.list.is({})).to.be(false);
|
||||
expect(Gun.list.is({a:1})).to.be(false);
|
||||
expect(Gun.list.is(false)).to.be(false);
|
||||
expect(Gun.list.is(true)).to.be(false);
|
||||
expect(Gun.list.is(function(){})).to.be(false);
|
||||
});
|
||||
it('obj',function(){
|
||||
expect(Gun.obj.is({})).to.be(true);
|
||||
expect(Gun.obj.is({a:1})).to.be(true);
|
||||
expect(Gun.obj.is(0)).to.be(false);
|
||||
expect(Gun.obj.is(1)).to.be(false);
|
||||
expect(Gun.obj.is('')).to.be(false);
|
||||
expect(Gun.obj.is('a')).to.be(false);
|
||||
expect(Gun.obj.is([])).to.be(false);
|
||||
expect(Gun.obj.is([1])).to.be(false);
|
||||
expect(Gun.obj.is(false)).to.be(false);
|
||||
expect(Gun.obj.is(true)).to.be(false);
|
||||
expect(Gun.obj.is(function(){})).to.be(false);
|
||||
});
|
||||
it('fns',function(){
|
||||
expect(Gun.fns.is(function(){})).to.be(true);
|
||||
expect(Gun.fns.is('')).to.be(false);
|
||||
expect(Gun.fns.is('a')).to.be(false);
|
||||
expect(Gun.fns.is(0)).to.be(false);
|
||||
expect(Gun.fns.is(1)).to.be(false);
|
||||
expect(Gun.fns.is([])).to.be(false);
|
||||
expect(Gun.fns.is([1])).to.be(false);
|
||||
expect(Gun.fns.is({})).to.be(false);
|
||||
expect(Gun.fns.is({a:1})).to.be(false);
|
||||
expect(Gun.fns.is(false)).to.be(false);
|
||||
expect(Gun.fns.is(true)).to.be(false);
|
||||
});
|
||||
it('time',function(){
|
||||
t.ts = Gun.time.is();
|
||||
expect(13 <= t.ts.toString().length).to.be.ok();
|
||||
expect(Gun.num.is(t.ts)).to.be.ok();
|
||||
expect(Gun.time.is(new Date())).to.be.ok();
|
||||
});
|
||||
});
|
||||
describe('Text', function(){
|
||||
it('ify',function(){
|
||||
expect(Gun.text.ify(0)).to.be('0');
|
||||
expect(Gun.text.ify(22)).to.be('22');
|
||||
expect(Gun.text.ify([true,33,'yay'])).to.be('[true,33,"yay"]');
|
||||
expect(Gun.text.ify({a:0,b:'1',c:[0,'1'],d:{e:'f'}})).to.be('{"a":0,"b":"1","c":[0,"1"],"d":{"e":"f"}}');
|
||||
expect(Gun.text.ify(false)).to.be('false');
|
||||
expect(Gun.text.ify(true)).to.be('true');
|
||||
});
|
||||
it('random',function(){
|
||||
expect(Gun.text.random().length).to.be(24);
|
||||
expect(Gun.text.random(11).length).to.be(11);
|
||||
expect(Gun.text.random(4).length).to.be(4);
|
||||
t.tr = Gun.text.random(2,'as'); expect((t.tr=='as'||t.tr=='aa'||t.tr=='sa'||t.tr=='ss')).to.be.ok();
|
||||
});
|
||||
});
|
||||
describe('List', function(){
|
||||
it('slit',function(){
|
||||
(function(){
|
||||
expect(Gun.list.slit.call(arguments, 0)).to.eql([1,2,3,'a','b','c']);
|
||||
}(1,2,3,'a','b','c'));
|
||||
});
|
||||
it('sort',function(){
|
||||
expect([{i:9},{i:4},{i:1},{i:-3},{i:0}].sort(Gun.list.sort('i'))).to.eql([{i:-3},{i:0},{i:1},{i:4},{i:9}]);
|
||||
});
|
||||
it('map',function(){
|
||||
expect(Gun.list.map([1,2,3,4,5],function(v,i,t){ t(v+=this.d); this.d=v; },{d:0})).to.eql([1,3,6,10,15]);
|
||||
expect(Gun.list.map([2,3,0,4],function(v,i,t){ if(!v){ return } t(v*=this.d); this.d=v; },{d:1})).to.eql([2,6,24]);
|
||||
expect(Gun.list.map([true,false,NaN,Infinity,'',9],function(v,i,t){ if(i===3){ return 0 }})).to.be(0);
|
||||
});
|
||||
});
|
||||
describe('Object', function(){
|
||||
it('del',function(){
|
||||
var obj = {a:1,b:2};
|
||||
Gun.obj.del(obj,'a');
|
||||
expect(obj).to.eql({b:2});
|
||||
});
|
||||
it('has',function(){
|
||||
var obj = {a:1,b:2};
|
||||
expect(Gun.obj.has(obj,'a')).to.be.ok();
|
||||
});
|
||||
it('copy',function(){
|
||||
var obj = {"a":false,"b":1,"c":"d","e":[0,1],"f":{"g":"h"}};
|
||||
var copy = Gun.obj.copy(obj);
|
||||
expect(copy).to.eql(obj);
|
||||
expect(copy).to.not.be(obj);
|
||||
});
|
||||
it('ify',function(){
|
||||
expect(Gun.obj.ify('[0,1]')).to.eql([0,1]);
|
||||
expect(Gun.obj.ify('{"a":false,"b":1,"c":"d","e":[0,1],"f":{"g":"h"}}')).to.eql({"a":false,"b":1,"c":"d","e":[0,1],"f":{"g":"h"}});
|
||||
});
|
||||
it('map',function(){
|
||||
expect(Gun.obj.map({a:'z',b:'y',c:'x'},function(v,i,t){ t(v,i) })).to.eql({x:'c',y:'b',z:'a'});
|
||||
expect(Gun.obj.map({a:'z',b:false,c:'x'},function(v,i,t){ if(!v){ return } t(i,v) })).to.eql({a:'z',c:'x'});
|
||||
expect(Gun.obj.map({a:'z',b:3,c:'x'},function(v,i,t){ if(v===3){ return 0 }})).to.be(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('ify', function(){
|
||||
var data, test;
|
||||
|
||||
Reference in New Issue
Block a user