mirror of
https://github.com/amark/gun.git
synced 2025-03-30 15:08:33 +00:00
Merge branch 'rnsupport' of https://github.com/gooddollar/gun into rnsupport
This commit is contained in:
commit
0c27b81993
2
.gitignore
vendored
2
.gitignore
vendored
@ -10,4 +10,4 @@ yarn.lock
|
||||
*.DS_store
|
||||
.esm-cache
|
||||
.sessionStorage
|
||||
.localStorage
|
||||
.localStorage
|
@ -116,7 +116,8 @@ Thanks to:<br/>
|
||||
<a href="https://github.com/dfreire">Dário Freire</a>,
|
||||
<a href="http://github.com/velua">John Williamson</a>,
|
||||
<a href="http://github.com/finwo">Robin Bron</a>,
|
||||
<a href="http://github.com/ElieMakhoul">Elie Makhoul</a>
|
||||
<a href="http://github.com/ElieMakhoul">Elie Makhoul</a>,
|
||||
<a href="http://github.com/mikestaub">Mike Staub</a>
|
||||
</p>
|
||||
|
||||
- Join others in sponsoring code: https://www.patreon.com/gunDB !
|
||||
@ -193,7 +194,7 @@ var Gun = require('gun/gun');
|
||||
|
||||
If you also need to install SEA for user auth and crypto, also install some of its dependencies like this:
|
||||
|
||||
`npm install text-encoding node-webcrypto-ossl --save`
|
||||
`npm install text-encoding @peculiar/webcrypto --save`
|
||||
|
||||
You will need to require it too (it will be automatically added to the Gun object):
|
||||
|
||||
|
52
axe.js
52
axe.js
@ -60,6 +60,20 @@
|
||||
// with one common superpeer (with ready failovers)
|
||||
// in case the p2p linear latency is high.
|
||||
// Or there could be plenty of other better options.
|
||||
|
||||
/*
|
||||
AXE should have a couple of threshold items...
|
||||
let's pretend there is a variable max peers connected
|
||||
mob = 10000
|
||||
if we get more peers than that...
|
||||
we should start sending those peers a remote command
|
||||
that they should connect to this or that other peer
|
||||
and then once they (or before they do?) drop them from us.
|
||||
sake of the test... gonna set that peer number to 1.
|
||||
The mob threshold might be determined by other factors,
|
||||
like how much RAM or CPU stress we have.
|
||||
*/
|
||||
opt.mob = opt.mob || Infinity;
|
||||
var mesh = opt.mesh = opt.mesh || Gun.Mesh(at);
|
||||
console.log("AXE enabled.");
|
||||
|
||||
@ -256,7 +270,7 @@
|
||||
this.to.next(peer);
|
||||
if(!peer.url){ return }
|
||||
axe.up[peer.id] = peer;
|
||||
})
|
||||
});
|
||||
at.on('bye', function(peer){ this.to.next(peer);
|
||||
if(peer.url){ delete axe.up[peer.id] }
|
||||
Gun.obj.map(peer.routes, function(route, hash){
|
||||
@ -266,6 +280,42 @@
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// handle rebalancing a mob of peers:
|
||||
at.on('hi', function(peer){
|
||||
this.to.next(peer);
|
||||
if(peer.url){ return } // I am assuming that if we are wanting to make an outbound connection to them, that we don't ever want to drop them unless our actual config settings change.
|
||||
var count = Object.keys(opt.peers).length;
|
||||
if(opt.mob >= count){ return } // TODO: Make dynamic based on RAM/CPU also. Or possibly even weird stuff like opt.mob / axe.up length?
|
||||
var peers = Object.keys(axe.up);
|
||||
if(!peers.length){ return }
|
||||
mesh.say({dam: 'mob', mob: count, peers: peers}, peer);
|
||||
//setTimeout(function(){ mesh.bye(peer) }, 9); // something with better perf? // UNCOMMENT WHEN WE ACTIVATE THIS FEATURE
|
||||
});
|
||||
at.on('bye', function(peer){
|
||||
this.to.next(peer);
|
||||
});
|
||||
|
||||
at.on('hi', function(peer){
|
||||
this.to.next(peer);
|
||||
// this code handles disconnecting from self & duplicates
|
||||
setTimeout(function(){ // must wait
|
||||
if(peer.pid !== opt.pid){
|
||||
// this extra logic checks for duplicate connections between 2 peers.
|
||||
if(!Gun.obj.map(axe.up, function(p){
|
||||
if(peer.pid === p.pid && peer !== p){
|
||||
return yes = true;
|
||||
}
|
||||
})){ return }
|
||||
}
|
||||
mesh.say({dam: '-'}, peer);
|
||||
delete at.dup.s[peer.last];
|
||||
}, Math.random() * 100);
|
||||
});
|
||||
mesh.hear['-'] = function(msg, peer){
|
||||
mesh.bye(peer);
|
||||
peer.url = '';
|
||||
}
|
||||
}
|
||||
|
||||
function joindht(dht, soul, pids) {
|
||||
|
22
examples/basic/paste.html
Normal file
22
examples/basic/paste.html
Normal file
@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<style>html, body, textarea { width: 100%; height: 100%; padding: 0; margin: 0; }</style>
|
||||
<textarea placeholder="paste here!"></textarea>
|
||||
|
||||
<script src="../jquery.js"></script>
|
||||
<script src="../../../gun/gun.js"></script>
|
||||
|
||||
<script>
|
||||
var gun = Gun(location.origin + '/gun');
|
||||
|
||||
var to, paste = gun.get('test').get('paste').on(function(data){
|
||||
$('textarea').val(data);
|
||||
})
|
||||
|
||||
$('textarea').on('input change blur keyup mouseup touchend', function(){
|
||||
clearTimeout(to); // debounce
|
||||
to = setTimeout(function(){
|
||||
paste.put($('textarea').val());
|
||||
}, 100);
|
||||
})
|
||||
</script>
|
@ -1,4 +1,4 @@
|
||||
<html><body>
|
||||
<!DOCTYPE html>
|
||||
<style>
|
||||
html, body {
|
||||
background: rgb(245, 245, 245);
|
||||
@ -136,5 +136,4 @@ $('#search').on('blur', function(e){
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body></html>
|
||||
</script>
|
@ -5,6 +5,7 @@
|
||||
<link href='https://fonts.googleapis.com/css?family=Poiret+One' rel='stylesheet' type='text/css'>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1><button id="left">←</button> <span id="date"></span> Schedule <button id="right">→</button></h1>
|
||||
|
||||
<form id="add">
|
||||
|
59
examples/basic/screen.html
Normal file
59
examples/basic/screen.html
Normal file
@ -0,0 +1,59 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<video id="video" width="100%"></video>
|
||||
<center>
|
||||
<button id="record">Record</button>
|
||||
<button id="play">Play</button>
|
||||
</center>
|
||||
|
||||
<script src="../jquery.js"></script>
|
||||
<script src="../../../gun/gun.js"></script>
|
||||
|
||||
<script>
|
||||
var gun = Gun(location.origin + '/gun');
|
||||
var record = {recorder: null, recording: false};
|
||||
|
||||
$('#record').on('click', ()=>{
|
||||
if(!record.ing){ return record.stream() }
|
||||
$('#record').text("Record");
|
||||
if(record.ing.stop){ record.ing.stop() }
|
||||
record.ing = false;
|
||||
})
|
||||
|
||||
record.stream = function(){
|
||||
navigator.mediaDevices.getDisplayMedia({ video: true }).then(stream => {
|
||||
var chunks = []; // we have a stream, we can record it
|
||||
record.ing = new MediaRecorder(stream);
|
||||
record.ing.ondataavailable = eve => chunks.push(eve.data);
|
||||
record.ing.onstop = eve => record.save(new Blob(chunks));
|
||||
record.ing.start()
|
||||
$('#record').text("End");
|
||||
}, err => { console.log(err) });
|
||||
}
|
||||
|
||||
record.save = function(data){
|
||||
record.file = record.file || new FileReader();
|
||||
record.file.readAsDataURL(data);
|
||||
record.file.onloadend = function(){
|
||||
var b64 = record.file.result;
|
||||
b64 = "data:video/webm" + b64.slice(b64.indexOf(';'));
|
||||
gun.get('test').get('screen').put(b64);
|
||||
}
|
||||
}
|
||||
|
||||
$('#play').on('click', ()=>{
|
||||
if(record.playing){
|
||||
$('#play').text("Play")
|
||||
$('#video').get(0).stop();
|
||||
record.playing = false;
|
||||
return;
|
||||
}
|
||||
$('#play').text("Stop");
|
||||
record.playing = true;
|
||||
gun.get('test').get('screen').once((data)=>{
|
||||
if(!data){ return }
|
||||
$('#video').get(0).src = data;
|
||||
$('#video').get(0).play()
|
||||
})
|
||||
})
|
||||
</script>
|
@ -1,50 +0,0 @@
|
||||
<h1>Search</h1>
|
||||
|
||||
<form id="ask">
|
||||
<input id="search" placeholder="search..." autocomplete="off">
|
||||
</form>
|
||||
|
||||
<div id="answer"></div>
|
||||
<ul></ul>
|
||||
|
||||
<small>Note: No data is indexed by default, you need to add some!</small>
|
||||
|
||||
<script src="../../examples/jquery.js"></script>
|
||||
<script src="../../gun.js"></script>
|
||||
<script src="../../sea.js"></script>
|
||||
<script src="../../lib/space.js"></script>
|
||||
|
||||
<script>
|
||||
var gun = Gun();
|
||||
var ask = {};
|
||||
|
||||
$('#search').on('keyup', function(e){
|
||||
ask.now = (this.value||'').toLowerCase().replace(/[\W_]+/g,"");
|
||||
if(ask.last === ask.now){ return }
|
||||
ask.last = ask.now;
|
||||
clearTimeout(ask.to);
|
||||
ask.to = setTimeout(search, 20);
|
||||
});
|
||||
|
||||
function search(){
|
||||
var key = ask.now;
|
||||
gun.get('Q').space(key, function(ack){
|
||||
if(!ack || key !== ask.now){ return }
|
||||
UI(ack)
|
||||
});
|
||||
}
|
||||
|
||||
function UI(ack){
|
||||
$('#answer').text(ack.data || '');
|
||||
var $ul = $('ul').empty(), tree = ack.tree;
|
||||
Gun.obj.map(tree, function(v,k){
|
||||
$('<li>').text(k +' - ' + v).appendTo($ul);
|
||||
});
|
||||
};
|
||||
|
||||
function load(DATA){
|
||||
Gun.obj.map(DATA, function(v,k){
|
||||
gun.get('Q').space(k, v);
|
||||
});
|
||||
}
|
||||
</script>
|
@ -1,3 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<h1>Tables</h1>
|
||||
|
||||
<form id="sign">
|
||||
|
@ -1,3 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<h1>User</h1>
|
||||
|
||||
<form id="sign">
|
||||
@ -11,8 +13,8 @@
|
||||
<ul></ul>
|
||||
|
||||
<form id="said">
|
||||
<input id="say">
|
||||
<input id="speak" type="submit" value="speak">
|
||||
<input id="say">
|
||||
<input id="speak" type="submit" value="speak">
|
||||
</form>
|
||||
|
||||
<script src="../jquery.js"></script>
|
||||
@ -27,19 +29,19 @@ $('#up').on('click', function(e){
|
||||
user.create($('#alias').val(), $('#pass').val(), login);
|
||||
});
|
||||
function login(e){
|
||||
user.auth($('#alias').val(), $('#pass').val());
|
||||
user.auth($('#alias').val(), $('#pass').val());
|
||||
return false; // e.preventDefault();
|
||||
};
|
||||
$('#sign').on('submit', login);
|
||||
$('#mask').on('click', login);
|
||||
|
||||
gun.on('auth', function(){
|
||||
$('#sign').hide();
|
||||
user.get('said').map().on(UI);
|
||||
$('#sign').hide();
|
||||
user.get('said').map().on(UI);
|
||||
});
|
||||
|
||||
$('#said').on('submit', function(e){
|
||||
e.preventDefault();
|
||||
e.preventDefault();
|
||||
//if(!user.is){ return }
|
||||
user.get('said').set($('#say').val());
|
||||
$('#say').val("");
|
||||
|
241
examples/docs.html
Normal file
241
examples/docs.html
Normal file
@ -0,0 +1,241 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<!-- always start with these two lines to set a clean baseline for different devices -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
<script src="jquery.js"></script>
|
||||
|
||||
<title>Docs</title>
|
||||
</head>
|
||||
<body class="black whitet">
|
||||
<style>
|
||||
/*
|
||||
Choose white text on a black background so you can add color in.
|
||||
Pick your favorite font and choose a font size.
|
||||
*/
|
||||
@import url('https://fonts.googleapis.com/css?family=Oxygen');
|
||||
html, body {
|
||||
font-family: "Oxygen", sans-serif;
|
||||
}
|
||||
|
||||
[contenteditable]:focus {
|
||||
outline: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="hold full hue2">
|
||||
<div id="page" class="max focus gap" style="padding-top: 9%;"></div>
|
||||
</div>
|
||||
<script src="../../gun/gun.js"></script>
|
||||
<script src="../../gun/lib/monotype.js"></script>
|
||||
<script src="../../gun/lib/meta.js"></script>
|
||||
<script src="../../gun/lib/normalize.js"></script>
|
||||
<script async src="../../gun/lib/fun.js"></script>
|
||||
|
||||
<script async src="../../gun/lib/wave.js"></script>
|
||||
<!-- script async src="https://edide.io/music.lib"></script -->
|
||||
|
||||
<script>
|
||||
var gun = Gun(['https://guntest.herokuapp.com/gun', 'http://localhost:8765/gun']);
|
||||
|
||||
;(window.onhashchange = function(){
|
||||
var file = (location.hash||'').slice(1);
|
||||
var S = +new Date;
|
||||
$('#page').empty().attr('contenteditable', 'false');
|
||||
gun.get('test/gun/docs/'+file).get('what').map().on(function render(data, i){
|
||||
if(window.LOCK){ return }
|
||||
var p = $('#page').children().get(i);
|
||||
if(!p){
|
||||
$('#page').append('<p>');
|
||||
setTimeout(function(){ render(data, i) },0);
|
||||
return;
|
||||
}
|
||||
var r = monotype(p);
|
||||
var safe = $.normalize(data);
|
||||
p.outerHTML = safe;
|
||||
r.restore();
|
||||
});
|
||||
})();
|
||||
|
||||
document.execCommand('defaultParagraphSeparator', false, 'p');
|
||||
meta.edit({
|
||||
name: "Edit",
|
||||
combo: ['E'],
|
||||
use: function(eve){
|
||||
console.log('on');
|
||||
}, on: function(eve){
|
||||
if($(eve.target).closest('p').length){ return }
|
||||
var edit = this;
|
||||
setTimeout(function(){ meta.flip(false) },1);
|
||||
edit.init();
|
||||
$(document).on('keydown.tmp', '[contenteditable]', function(eve){
|
||||
if(eve.which != 13){ return }
|
||||
eve.preventDefault();
|
||||
var r = window.getSelection().getRangeAt(0);
|
||||
var c = r.commonAncestorContainer, p;
|
||||
r.deleteContents();
|
||||
var p = c.splitText? $(c.splitText(r.startOffset)).parent() : $(c);
|
||||
var n = $("<"+p.get(0).tagName+">"), f;
|
||||
p.contents().each(function(){
|
||||
if(this === c){ return f = true }
|
||||
if(!f){ return }
|
||||
n.append(this);
|
||||
});
|
||||
p.after(n);
|
||||
edit.select(n.get(0));
|
||||
// make sure we re-save & sync each changed paragraph.
|
||||
edit.save(p);
|
||||
p.nextAll().each(function(){
|
||||
edit.save(this);
|
||||
});
|
||||
}).on('keyup.tmp', '[contenteditable]', function(eve){
|
||||
//$('#debug').val(doc.html());
|
||||
var p = $(window.getSelection().anchorNode).closest('p');
|
||||
var r = monotype(p);
|
||||
var html = p.html() || '';
|
||||
if(!html && !p.prev().length && !p.next().length && !$('#page').html()){
|
||||
edit.init();
|
||||
}
|
||||
var safe = $.normalize(html);
|
||||
p.html(safe);
|
||||
r.restore();
|
||||
edit.save(p);
|
||||
});
|
||||
},
|
||||
up: function(){
|
||||
console.log("UP");
|
||||
$('[contenteditable=true]').off('.tmp');
|
||||
},
|
||||
init: function(){
|
||||
var edit = this;
|
||||
var doc = $('#page').attr('contenteditable', 'true');
|
||||
if(!doc.text()){
|
||||
doc.html('<p class="loud crack"></p>');
|
||||
}
|
||||
edit.select(doc.children().first().get(0));
|
||||
},
|
||||
save: function(p){
|
||||
p = $(p);
|
||||
var i = p.index();// = Array.prototype.indexOf.call(parent.children, child);
|
||||
var file = (location.hash||'').slice(1);
|
||||
var data = (p.get(0)||{}).outerHTML||'';
|
||||
window.LOCK = true;
|
||||
gun.get('test/gun/docs/'+file).get('what').get(i).put(data);
|
||||
window.LOCK = false;
|
||||
},
|
||||
select: function(p){
|
||||
var s = window.getSelection(),
|
||||
r = document.createRange();
|
||||
if(p.innerHTML){
|
||||
r.setStart(p, 0);
|
||||
r.collapse(true);
|
||||
s.removeAllRanges();
|
||||
s.addRange(r);
|
||||
return;
|
||||
}
|
||||
p.innerHTML = '\u00a0';
|
||||
r.selectNodeContents(p);
|
||||
s.removeAllRanges();
|
||||
s.addRange(r);
|
||||
document.execCommand('delete', false, null);
|
||||
}
|
||||
});
|
||||
|
||||
;(function(){
|
||||
|
||||
meta.edit({name: "Layout", combo: ['L']});
|
||||
|
||||
meta.edit({name: "Fill", combo: ['L','F'],
|
||||
use: function(eve){},
|
||||
on: function(eve){
|
||||
var on = meta.tap();
|
||||
meta.ask('Color name, code, or URL?', function(color){
|
||||
on.css('background', color);
|
||||
});
|
||||
},
|
||||
up: function(eve){}
|
||||
});
|
||||
|
||||
meta.edit({name: "Add", combo: ['L','A']});
|
||||
meta.edit({name: "Row", combo: ['L','A', 'R'],
|
||||
on: function(eve){
|
||||
meta.tap().append('<div style="min-height: 9em; padding: 2%;">');
|
||||
}
|
||||
});
|
||||
meta.edit({name: "Columns", combo: ['L','A','C'],
|
||||
on: function(eve){
|
||||
var on = meta.tap().addClass('center'), tmp, c;
|
||||
var html = '<div class="unit col" style="min-height: 9em; padding: 2%;"></div>';
|
||||
if(!on.children('.col').length){ html += html }
|
||||
c = (tmp = on.append(html).children('.col')).length;
|
||||
tmp.each(function(){
|
||||
$(this).css('width', (100/c)+'%');
|
||||
})
|
||||
}
|
||||
});
|
||||
meta.edit({name: "Text", combo: ['L','A','T'],
|
||||
on: function(eve){
|
||||
var tag = $('<p>text</p>');
|
||||
meta.tap().append(tag);
|
||||
tag.focus();
|
||||
}
|
||||
});
|
||||
|
||||
}());
|
||||
|
||||
;(function(){
|
||||
var song = {};
|
||||
// TODO:
|
||||
// 1. Manually OR automatically load music.js API, dependencies, and modules. - FINE for now
|
||||
// 2. only export music API, not meta, not dom, not mouselock system, not UI/html, etc. better module isolation and export.
|
||||
// 3. `var wave = Wave('a').play()` // also on `Music.now`
|
||||
// defaults... instrument: pure tones, volume curve: |\_ , speed curve: 0.5
|
||||
// 4. `wave.blur(0.5).itch(0.5);`
|
||||
// 5. wave.long(2); // how long in seconds each note plays, optionally: wave.pace(60) is bpm
|
||||
// 6. wave.loud(0.5); // 0% to 100% volume loudness of device output.
|
||||
// 7. wave.vary(0.5); // slows down or speeds up wiggle per harmonic
|
||||
// 8:
|
||||
// wave structure, does ToneJS allow us to change the sine wave smoothness/type continuously or is it a pre-fixed type?
|
||||
// wave structure: /\/\/, |_|, /|/, \|\| do some research with ToneJS whether these are dynamic or fixed
|
||||
// wave.itch(); // changes the shape of the wiggle from smooth sine to square or triangle
|
||||
// wave.blur(220hz); // blur may not apply/work on pure notes other than filtering them.
|
||||
|
||||
meta.edit({name: "Music", combo: ['M']});
|
||||
|
||||
meta.edit({name: "Play", combo: ['M','P'],
|
||||
on: function(eve){
|
||||
// TODO: We still need to add to meta API ability to change name.
|
||||
if(song.play){
|
||||
music.stop();
|
||||
song.play = false;
|
||||
return;
|
||||
}
|
||||
song.play = true;
|
||||
music.stop();
|
||||
setTimeout(function(){
|
||||
song.now = wave($('#page').text()).play();
|
||||
},250);
|
||||
}
|
||||
});
|
||||
|
||||
meta.edit({name: "Blur", combo: ['M','B'],
|
||||
on: function(eve){
|
||||
$(document).on('mousemove.tmp', function(eve){
|
||||
var x = eve.pageX;
|
||||
song.now.loud(x/$('body').innerWidth());
|
||||
});
|
||||
},
|
||||
up: function(){
|
||||
$(document).off('.tmp');
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on('keydown', function(eve){
|
||||
music.play(String.fromCharCode(eve.which));
|
||||
});
|
||||
|
||||
}());
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
439
examples/game/furball.html
Normal file
439
examples/game/furball.html
Normal file
@ -0,0 +1,439 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<!-- always start with these two lines to set a clean baseline for different devices -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" type="text/css" href="../style.css">
|
||||
<!-- link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/gun/examples/style.css" -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/gun/examples/jquery.js"></script>
|
||||
|
||||
<title>Furball</title>
|
||||
</head>
|
||||
<body class="black whitet">
|
||||
<style>
|
||||
/*
|
||||
Choose white text on a black background so you can add color in.
|
||||
Pick your favorite font and choose a font size.
|
||||
*/
|
||||
@import url('https://fonts.googleapis.com/css?family=Mali');
|
||||
html, body {
|
||||
font-family: "Mali", sans-serif;
|
||||
}
|
||||
|
||||
.huef {
|
||||
background: #4D79D8;
|
||||
-webkit-animation: huef 9s infinite;
|
||||
animation: huef 9s infinite;
|
||||
} @keyframes huef {
|
||||
0% {background-color: #4D79D8;}
|
||||
25% {background-color: #33cc33;}
|
||||
50% {background-color: #f2b919;}
|
||||
75% {background-color: #ea3224;}
|
||||
100% {background-color: #4D79D8;}
|
||||
} @-webkit-keyframes huef {
|
||||
0% {background-color: #4D79D8;}
|
||||
25% {background-color: #33cc33;}
|
||||
50% {background-color: #f2b919;}
|
||||
75% {background-color: #ea3224;}
|
||||
100% {background-color: #4D79D8;}
|
||||
}
|
||||
|
||||
button, input {
|
||||
padding: 1em;
|
||||
background: transparent;
|
||||
border: 1px solid white;
|
||||
border-radius: 1.5em;
|
||||
color: white;
|
||||
margin: 0.5em;
|
||||
margin-bottom: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
button:hover, input:hover {
|
||||
background: white;
|
||||
color: black;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.air { padding-top: 9%; }
|
||||
.yak button { font-size: 80%; }
|
||||
|
||||
.wag {
|
||||
-webkit-animation: wag 3s infinite;
|
||||
animation: wag 3s infinite;
|
||||
} @keyframes wag {
|
||||
0% {transform: rotate(0deg);}
|
||||
50% {transform: rotate(-1deg);}
|
||||
100% {transform: rotate(0deg);}
|
||||
}
|
||||
|
||||
@keyframes print {
|
||||
0% { overflow: hidden; height: 0vh; }
|
||||
99% { overflow: hidden; height: 100vh; }
|
||||
100% { overflow: visible; height: auto; }
|
||||
}
|
||||
input {
|
||||
outline: none;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
<!-- for educational sites, consider starting with a nice full screen welcome message -->
|
||||
<div class="home hold full huef center air">
|
||||
<div class="focus row">
|
||||
<p><i>Neon ERA presents</i></p>
|
||||
<p class="shout wag">Furball Forces</p>
|
||||
<!-- just like in real life, say who you are and give a concise reason why you add value to someone's life and then make a call to action, if they want to learn more they can always scroll to learn more -->
|
||||
<div>
|
||||
<!-- a class="unit hold" href="#fullscreen"><button>WATCH TRAILER</button></a -->
|
||||
<a class="unit yak" href="#choose"><button>PLAY GAME</button></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="focus center row leak">
|
||||
<!-- just like in real life, looking pretty attracts attention, so show off and look glamorous! -->
|
||||
<img class="unit blink" src="file:///Users/mark/Downloads/supercatdog.png" style="min-width: 10em; width: 80%;">
|
||||
</div>
|
||||
<script>location.hash = ''</script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/gun/lib/fun.js"></script>
|
||||
<script>;(function(){
|
||||
// OPTIONAL MUSIC:
|
||||
$('.home button').on('click', function(){
|
||||
if(window.screen.height > window.screen.width){ return }
|
||||
$('body').append("<div id='audio' onclick='$(this).remove();'><iframe width='0' height='0' src='https://www.youtube-nocookie.com/embed/LLPoZGX0qZk?autoplay=1' frameborder='0'></iframe></div>");
|
||||
})
|
||||
}());
|
||||
</script>
|
||||
<style>#audio { padding: 0.5em; position: fixed; bottom: 0; left: 0; } #audio:before { content: '\25BA'; } #audio:hover:before { content: '\25FC'; }</style>
|
||||
</div>
|
||||
|
||||
<div id="choose" class="hold full hue4 center air">
|
||||
<div class="focus row">
|
||||
<p class="shout wag fur">Choose Team:</p>
|
||||
<div>
|
||||
<a class="unit yak" href="#automecha"><button style="background: white; color: black;">#AutoMecha</button></a>
|
||||
<a class="unit yak" href="#cyberninjas"><button style="background: black; color: white; border-color: black;">#CyberNinjas</button></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="focus center row leak">
|
||||
<img class="unit blink" src="file:///Users/mark/Downloads/supercatdog.png" style="transform: scaleX(-1); filter: invert(1); min-width: 10em; width: 80%;">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="cyberninjas" class="hold full black">
|
||||
<style>
|
||||
#cyberninjas:target .story {
|
||||
animation: print 3s steps(50, end);
|
||||
}
|
||||
</style>
|
||||
<div class="story pad">
|
||||
<p class="loud crack">Episode 1: Waking</p>
|
||||
<p>"How long until they're online?"</p>
|
||||
<p>"We're copying the soul files, almost done."</p>
|
||||
<p>"Monsters are on the bridge, we do not have time!"</p>
|
||||
<p>"The new body is printing now, it'll be able to outrun them all, just hold on."</p>
|
||||
<p>"It won't know where to run! We're risking ruining the whole resistance, I need to talk to it now."</p>
|
||||
<p>"95% done." The voice behind the glass turns to the soul in the body, "My cub, can you hear me?"</p>
|
||||
<p>...</p>
|
||||
<a class="unit yak" href="#cyberninjas2"><button>Reply "Yes, Mom?"</button></a>
|
||||
</div>
|
||||
<script>
|
||||
;(function(){
|
||||
$('#cyberninjas a').on('click', function(){
|
||||
$('#hud .life').removeClass('down');
|
||||
});
|
||||
}());
|
||||
</script>
|
||||
</div>
|
||||
|
||||
<div id="cyberninjas2" class="hold full red">
|
||||
<style>
|
||||
#cyberninjas2:target .story {
|
||||
animation: print 3s steps(50, end);
|
||||
}
|
||||
|
||||
#hud {
|
||||
opacity: 0.4;
|
||||
font-family: 'Audiowide', cursive;
|
||||
z-index: 999999999999;
|
||||
transition: all 3s;
|
||||
}
|
||||
#hud .life {
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
bottom: 0px;
|
||||
padding: 0.25em 1em 0.1em;
|
||||
border-radius: 0.5em 0.5em 0 0;
|
||||
transform: translateX(-50%);
|
||||
background: black;
|
||||
text-shadow: 0em -0.125em 0.75em white;
|
||||
}
|
||||
#hud .score {
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
top: 0px;
|
||||
padding: 0.1em 1em 0.25em;
|
||||
border-radius: 0 0 0.5em 0.5em;
|
||||
transform: translateX(-50%);
|
||||
background: black;
|
||||
text-shadow: 0em 0.1em 0.75em white;
|
||||
}
|
||||
#hud .down {
|
||||
bottom: -2em !important;
|
||||
}
|
||||
#hud .up {
|
||||
top: -2em !important;
|
||||
}
|
||||
</style>
|
||||
<div id="hud">
|
||||
<div class="score shade up">
|
||||
SCORE: <span id="hudscore">0</span>%
|
||||
</div>
|
||||
<div class="life shade down">
|
||||
LIFE: <span id="hudlife">50</span>%
|
||||
</div>
|
||||
</div>
|
||||
<div class="story pad">
|
||||
<p>A fire explodes in the room behind the glass as an AutoMecha blows the door open.</p>
|
||||
<p>The floor shakes and the bed crashes through the wall, flying out of the building.</p>
|
||||
<p class="center">"Mom!!!"</p>
|
||||
<p>There is a total free fall from 10 levels up, water down below.</p>
|
||||
<p>...</p>
|
||||
<a class="unit yak" href="#cyberninjas3"><button>Dive or Die</button></a>
|
||||
</div>
|
||||
<script>
|
||||
;(function(){
|
||||
$('#cyberninjas2 a').on('click', function(){
|
||||
$('#hudlife').text($('#hudlife').data().is = 50);
|
||||
});
|
||||
}());
|
||||
</script>
|
||||
</div>
|
||||
|
||||
<div id="cyberninjas3" class="hold full blue">
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css?family=Audiowide');
|
||||
|
||||
#cyberninjas3:target .story {
|
||||
animation: print 3s steps(50, end);
|
||||
}
|
||||
</style>
|
||||
<div class="story pad">
|
||||
<p>The water splashes, swelling and swirling all around.</p>
|
||||
<p>...</p>
|
||||
<p class="center">Rapidly tap to swim up to air:</p>
|
||||
<a class="unit yak"><button>Swim</button></a>
|
||||
</div>
|
||||
<script>
|
||||
;(function(){
|
||||
var go, life = $('#hudlife').data();
|
||||
$('#cyberninjas3 a').on('click', function(){
|
||||
$('#hudlife').text(life.is += 5);
|
||||
if(100 <= life.is){
|
||||
location.hash = 'cyberninjas4';
|
||||
clearInterval(go);
|
||||
go = false;
|
||||
return;
|
||||
}
|
||||
if(go){ return }
|
||||
go = setInterval(function(){
|
||||
if(0 >= life.is){
|
||||
location.hash = 'cyberninjas2';
|
||||
$('#hudlife').text(life.is = 50);
|
||||
clearInterval(go);
|
||||
go = false;
|
||||
return;
|
||||
}
|
||||
$('#hudlife').text(life.is -= 5);
|
||||
}, 1000); // 1 second
|
||||
});
|
||||
}());
|
||||
</script>
|
||||
</div>
|
||||
|
||||
<div id="cyberninjas4" class="hold full black">
|
||||
<style>
|
||||
#cyberninjas4:target .story {
|
||||
animation: print 3s steps(50, end);
|
||||
}
|
||||
</style>
|
||||
<div class="story pad">
|
||||
<p class="loud crack">Episode 2: Who Am I?</p>
|
||||
<p>"Grab on!" A voice calls out from the darkness.</p>
|
||||
<p>A life vest hits the water and floats within arm's distance.</p>
|
||||
<p>The shivering body is pulled up onto the boat.</p>
|
||||
<p>"Wow, you're heavier than you look. Are you OK? What's your name?"</p>
|
||||
<p>...</p>
|
||||
<p class="center">Write your reply & hit enter:</p>
|
||||
<form class="center">
|
||||
<input class="loud" style="width: 60%;">
|
||||
</form>
|
||||
</div>
|
||||
<script>
|
||||
;(function(){
|
||||
$('form').on('submit', function(eve){ eve.preventDefault() });
|
||||
$('#cyberninjas4').on('submit', function(){
|
||||
var name = $(this).find('input').val();
|
||||
if(!name.length){ return }
|
||||
$('.story-name').text(' '+(window.NAME = name));
|
||||
$('#hud .score').removeClass('up');
|
||||
location.hash = 'cyberninjas5';
|
||||
})
|
||||
}());
|
||||
</script>
|
||||
</div>
|
||||
|
||||
<div id="cyberninjas5" class="hold full green">
|
||||
<style>
|
||||
#cyberninjas5:target .story {
|
||||
animation: print 3s steps(50, end);
|
||||
}
|
||||
</style>
|
||||
<div class="story pad">
|
||||
<p>"Well<span class="story-name"></span>, it's a miracle you did not die in the building explosion or from that fall."</p>
|
||||
<p>"What is going on? What happened?"</p>
|
||||
<p>"You can't remember? Your brain must be knocked up pretty hard."</p>
|
||||
<p>"No, I was mid copy into this body and now my memories are glitching."</p>
|
||||
<p>"Woah, you're one of those pro elite AREION revolutionaries? All flesh & blood! Dense, too. I would've assumed they were stealing AutoMecha tech for that instead."</p>
|
||||
<p>"I was about to be told vital data for the resistance, but then they blew up the build--"</p>
|
||||
<p>...</p>
|
||||
<p>"Hey, what's the matter?"</p>
|
||||
<p>"My mom. She was in there. I need to go back. Please, help me and tell me everything you know."</p>
|
||||
<p>"I'm so sorry. I can only get so close with the boat, you're gonna have to jump over a lot of broken bits. You ready?"</p>
|
||||
<p>...</p>
|
||||
<a class="unit yak" href="#cyberninjas6"><button>GO!</button></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="cyberninjas6" class="hold full green">
|
||||
<style>
|
||||
#cyberninjas6:target .story {
|
||||
animation: print 3s steps(50, end);
|
||||
}
|
||||
</style>
|
||||
<div class="story pad">
|
||||
<p class="center">... to be continued ...</p>
|
||||
<div id="player" style="position: fixed; width: 1em; height: 1em; background: white; left: 50%; top: 50%; border-radius: 100%;"></div>
|
||||
<!-- jumping game ? like offline dinosaur ? -->
|
||||
</div>
|
||||
<script src="../../../gun/lib/meta.js"></script>
|
||||
<script>
|
||||
;(function(){
|
||||
var p = $('#player');
|
||||
p.x = 50;
|
||||
p.y = 50;
|
||||
meta.edit({
|
||||
name: "Up",
|
||||
combo: ["W"],
|
||||
on: function(){
|
||||
console.log("up");
|
||||
this.to = this.to || setInterval(this.on, 100);
|
||||
$("html, body").stop().animate({ scrollTop: $(window).scrollTop()-100 }, 100);
|
||||
p.css({top: --p.y +'%'});
|
||||
},
|
||||
use: function(){},
|
||||
up: function(){ clearTimeout(this.to); this.to = 0 }
|
||||
});
|
||||
meta.edit({
|
||||
name: "Left",
|
||||
combo: ["A"],
|
||||
on: function(){
|
||||
console.log("left");
|
||||
this.to = this.to || setInterval(this.on, 100);
|
||||
p.css({left: --p.x +'%'});
|
||||
},
|
||||
use: function(){},
|
||||
up: function(){ clearTimeout(this.to); this.to = 0 }
|
||||
});
|
||||
meta.edit({
|
||||
name: "Down",
|
||||
combo: ["S"],
|
||||
on: function on(){
|
||||
console.log("down");
|
||||
this.to = this.to || setInterval(this.on, 100);
|
||||
$("html, body").stop().animate({ scrollTop: $(window).scrollTop()+100 }, 100);
|
||||
p.css({top: ++p.y +'%'});
|
||||
},
|
||||
use: function(){},
|
||||
up: function(){ clearTimeout(this.to); this.to = 0 }
|
||||
});
|
||||
meta.edit({
|
||||
name: "Right",
|
||||
combo: ["D"],
|
||||
on: function(){
|
||||
console.log("right");
|
||||
this.to = this.to || setInterval(this.on, 100);
|
||||
p.css({left: ++p.x +'%'});
|
||||
},
|
||||
use: function(){},
|
||||
up: function(){ clearTimeout(this.to); this.to = 0 }
|
||||
});
|
||||
meta.edit({
|
||||
name: "Jump",
|
||||
combo: [32],
|
||||
on: function(){ console.log("jump") },
|
||||
use: function(){},
|
||||
up: function(){}
|
||||
});
|
||||
meta.edit({
|
||||
name: "Crouch",
|
||||
combo: [16],
|
||||
on: function(){ console.log("crouch") },
|
||||
use: function(){},
|
||||
up: function(){}
|
||||
});
|
||||
meta.edit({
|
||||
name: "Use",
|
||||
combo: ["E"],
|
||||
on: function(){ console.log("use") },
|
||||
use: function(){},
|
||||
up: function(){}
|
||||
});
|
||||
meta.edit({
|
||||
name: "Fire",
|
||||
combo: ["F"],
|
||||
on: function(){ console.log("fire") },
|
||||
use: function(){},
|
||||
up: function(){}
|
||||
});
|
||||
meta.edit({
|
||||
name: "Switch",
|
||||
combo: [9],
|
||||
on: function(){ console.log("Switch") },
|
||||
use: function(){},
|
||||
up: function(){}
|
||||
});
|
||||
window.requestAnimationFrame = window.requestAnimationFrame || setTimeout;
|
||||
window.requestAnimationFrame(function frame(){
|
||||
window.requestAnimationFrame(frame, 16);
|
||||
|
||||
}, 16);
|
||||
}());
|
||||
</script>
|
||||
</div>
|
||||
|
||||
<div id="automecha" class="hold full white blackt">
|
||||
<style>
|
||||
#automecha:target .story {
|
||||
animation: print 3s steps(50, end);
|
||||
}
|
||||
</style>
|
||||
<div class="story pad">
|
||||
<p class="loud crack">Episode 1: Training</p>
|
||||
<p>...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="hold black center">
|
||||
<div class="pad">
|
||||
<div class="left">
|
||||
<p class="loud">For <i>You</i>,</p>
|
||||
<p>Crafted with love, <span class="redt">♥</span> by ERA.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<img src="https://era.eco/media/world.png" class="row">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
18
examples/react/.gitignore
vendored
18
examples/react/.gitignore
vendored
@ -1,18 +0,0 @@
|
||||
# See https://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,22 +0,0 @@
|
||||
{
|
||||
"name": "gun-react-examples",
|
||||
"version": "1.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"gun": "file:../..",
|
||||
"react": "^15.5.4",
|
||||
"react-dom": "^15.5.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"express": "^4.15.2",
|
||||
"express-http-proxy": "^0.11.0",
|
||||
"react-scripts": "0.9.5"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test --env=jsdom",
|
||||
"eject": "react-scripts eject",
|
||||
"server": "PORT=8081 node ./server.js"
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
console.log("If modules not found, run `npm install` in /example folder!");
|
||||
var port = process.env.OPENSHIFT_NODEJS_PORT || process.env.VCAP_APP_PORT || process.env.PORT || process.argv[2] || 8765;
|
||||
var host = process.env.OPENSHIFT_NODEJS_HOST || process.env.VCAP_APP_HOST || process.env.HOST || 'localhost';
|
||||
|
||||
var express = require('express');
|
||||
var proxy = require('express-http-proxy');
|
||||
var http = require('http');
|
||||
var app = express();
|
||||
var server = http.createServer(app);
|
||||
|
||||
var Gun = require('gun');
|
||||
var gun = Gun({
|
||||
file: 'data.json',
|
||||
web: server
|
||||
});
|
||||
|
||||
app.use(Gun.serve);
|
||||
app.use(proxy(host + ':8765'));
|
||||
server.listen(port);
|
||||
|
||||
console.log('Server started on port ' + port + ' with /gun');
|
39
examples/react/todo.html
Normal file
39
examples/react/todo.html
Normal file
@ -0,0 +1,39 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
|
||||
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
|
||||
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/gun/gun.js"></script>
|
||||
<script type="text/babel">
|
||||
const gun = Gun();
|
||||
const App = () => {
|
||||
const newTodo = React.useRef()
|
||||
const [todos, setTodos] = React.useState({})
|
||||
|
||||
React.useEffect(() => {
|
||||
gun
|
||||
.get("todos")
|
||||
.map()
|
||||
.on((todo, id) => setTodos(todos => ({...todos, [id]: todo })));
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div>
|
||||
<title>TODOs</title>
|
||||
<ul>{Object.values(todos).map(({title}, i) => <li key={i}>{title}</li>)}</ul>
|
||||
<form onSubmit={e => {
|
||||
e.preventDefault();
|
||||
gun.get("todos").set({ title: newTodo.current.value });
|
||||
ref.current.value = ''
|
||||
}}>
|
||||
<input ref={newTodo} placeholder="new todo"/>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
ReactDOM.render(<App />, document.getElementById("app"));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
1104
examples/smoothie.js
Normal file
1104
examples/smoothie.js
Normal file
File diff suppressed because it is too large
Load Diff
@ -2,161 +2,97 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" type="text/css" href="./style.css">
|
||||
<link rel="stylesheet" href="./style.css">
|
||||
</head>
|
||||
<body>
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css?family=Oxygen');
|
||||
html, body {
|
||||
font-family: "Oxygen", sans-serif;
|
||||
}
|
||||
svg, .ct-chart * {
|
||||
overflow: visible;
|
||||
}
|
||||
.ct-series-a .ct-line,
|
||||
.ct-series-a .ct-point {
|
||||
str-oke: blue !important;
|
||||
body {
|
||||
font-family: helvetica;
|
||||
background-color: rgb(25,25,25);
|
||||
color: rgb(80,135,25) !important;
|
||||
text-shadow: 1px 1px 20px rgb(80,150,25);
|
||||
}
|
||||
|
||||
.ct-series-b .ct-line,
|
||||
.ct-series-b .ct-point {
|
||||
stroke: green !important;
|
||||
}
|
||||
.label {
|
||||
position: absolute;
|
||||
left: 0.5em;
|
||||
top: 1.75em;
|
||||
}
|
||||
|
||||
.tall { height: 10em; }
|
||||
.input {
|
||||
height: 30px;
|
||||
padding:10px;
|
||||
background-color: rgb(50,50,50);
|
||||
color: rgb(250,50,50);
|
||||
}
|
||||
|
||||
.tall { height: 5em; }
|
||||
</style>
|
||||
|
||||
<input id="url" class="center none" placeholder="enter peer stats source url">
|
||||
|
||||
<div class="center"><span class="shout" id="peers">0</span> peers <span class="shout" id="time">0</span> min <span class="shout" id="nodes">0</span> nodes <span class="shout" id="hours">0</span> hours</div>
|
||||
|
||||
<div class="leak" style="padding: 0 2em;">
|
||||
<div class="leak ct-mem ct-chart ct-perfect-fourth tall"></div>
|
||||
<input id="url" class="center input crack" placeholder="enter peer stats source url">
|
||||
|
||||
<div class="center row charts">
|
||||
</div>
|
||||
|
||||
<div class="center leak" style="padding: 0 2em;">
|
||||
<div class="unit col leak ct-damc ct-chart tall" style="width: 49%;"></div>
|
||||
<div class="unit col leak ct-damd ct-chart tall" style="width: 49%;"></div>
|
||||
<div class="model none">
|
||||
<div class="chart"><span class="label"></span><canvas class="tall row"></canvas></div>
|
||||
</div>
|
||||
|
||||
<div class="center leak" style="padding: 0 2em;">
|
||||
<div class="unit col leak ct-radc ct-chart tall" style="width: 49%;"></div>
|
||||
<div class="unit col leak ct-radt ct-chart tall" style="width: 49%;"></div>
|
||||
</div>
|
||||
<div class="center"><span id="rerr"></span></div>
|
||||
|
||||
<div class="center leak" style="padding: 0 2em;">
|
||||
<div class="leak ct-daml ct-chart tall"></div>
|
||||
</div>
|
||||
|
||||
<div class="center leak" style="padding: 0 2em;">
|
||||
<div class="leak ct-cpu ct-chart ct-perfect-fourth tall"></div>
|
||||
</div>
|
||||
|
||||
<script src="./jquery.js"></script>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/chartist.js/latest/chartist.min.css">
|
||||
<script src="https://cdn.jsdelivr.net/chartist.js/latest/chartist.min.js"></script>
|
||||
<script src="./smoothie.js" charset="utf-8"></script>
|
||||
<script>
|
||||
var stats = {slide: [0,0,0,0,0], din: [0,0,0,0,0], dout: [0,0,0,0,0], dind: [0,0,0,0,0], doutd: [0,0,0,0,0], rgetc: [0,0,0,0,0], rputc: [0,0,0,0,0]};
|
||||
setInterval(function(){
|
||||
stats.show();
|
||||
}, 1000 * 15);
|
||||
stats.show = async function(data){ //$.getJSON(url.value||(location.origin+'/gun/stats.radata'), function(data){ console.log(data);
|
||||
data = await (await fetch(url.value||(location.origin+'/gun/stats.radata'), {method: 'GET',mode: 'cors'})).json();
|
||||
console.log(data);
|
||||
$('#peers').text(data.peers.count);
|
||||
$('#time').text((data.peers.time / 1000 / 60).toFixed(0));
|
||||
$('#nodes').text(data.node.count);
|
||||
$('#hours').text((data.up.time / 60 / 60).toFixed(0));
|
||||
var fetchData = async function(){
|
||||
// fetch the data from server
|
||||
var data = await (await fetch(url.value||(location.origin+'/gun/stats.radata'), {method: 'GET',mode: 'cors'})).json();
|
||||
$('#peers').text(data.peers.count);
|
||||
$('#time').text((data.peers.time / 1000 / 60).toFixed(0));
|
||||
$('#nodes').text(data.node.count);
|
||||
$('#hours').text((data.up.time / 60 / 60).toFixed(0));
|
||||
|
||||
$('#dinc').text(data.dam.in.count);
|
||||
$('#dind').text((data.dam.in.done / 1024 / 1024).toFixed(1));
|
||||
$('#doutc').text(data.dam.out.count);
|
||||
$('#doutd').text((data.dam.out.done / 1024 / 1024).toFixed(1));
|
||||
Stats('memory').line.append(+new Date, data.memory.heapTotal / 1024 / 1024);
|
||||
try{ Stats('dam # in').line.append(+new Date, data.dam.in.count); }catch(e){}
|
||||
try{ Stats('dam in MB').line.append(+new Date, data.dam.in.done / 1024 / 1024); }catch(e){}
|
||||
try{ Stats('dam # out').line.append(+new Date, data.dam.out.count); }catch(e){}
|
||||
try{ Stats('dam out MB').line.append(+new Date, data.dam.out.done / 1024 / 1024); }catch(e){}
|
||||
|
||||
stats.slide.push(data.memory.heapTotal / 1024 / 1024); stats.slide = stats.slide.slice(1);
|
||||
new Chartist.Line('.ct-mem', {
|
||||
// A labels array that can contain any sort of values
|
||||
labels: ['-1min', '-45s', '-30s', '-15s', '0'],
|
||||
// Our series array that contains series objects or in this case series data arrays
|
||||
series: [stats.slide]
|
||||
}, {fullWidth: true, low: 0, axisY: {
|
||||
labelInterpolationFnc: function(v) { return v+'MB' }
|
||||
}});
|
||||
console.log('data',data);
|
||||
//fetch keys in all, these may be dynamically changing
|
||||
//for each key, check if we already have created a time series, if not, create it and add it
|
||||
// to the chart corredsponding to the unit of measure
|
||||
$.each(data.all, function(key, arr){
|
||||
var chart = Stats(key);
|
||||
// get data and append to line
|
||||
// get the arrays inside the key
|
||||
//for each array append the data to the line
|
||||
for(var i in arr) {
|
||||
// append data [timestamp], [data]
|
||||
chart.line.append(arr[i][0], arr[i][1]);
|
||||
}
|
||||
})
|
||||
}
|
||||
setInterval(fetchData, 15 * 1000);
|
||||
fetchData();
|
||||
|
||||
stats.din.push(data.dam['in'].count); stats.din = stats.din.slice(1);
|
||||
stats.dout.push(data.dam.out.count); stats.dout = stats.dout.slice(1);
|
||||
new Chartist.Line('.ct-damc', {
|
||||
// A labels array that can contain any sort of values
|
||||
labels: ['-1min', '-45s', '-30s', '-15s', '0'],
|
||||
// Our series array that contains series objects or in this case series data arrays
|
||||
series: [stats.dout, stats.din]
|
||||
}, {fullWidth: true, axisY: {
|
||||
labelInterpolationFnc: function(v) { return v+'msgs' }
|
||||
}});
|
||||
|
||||
stats.dind.push(data.dam['in'].done / 1024 / 1024); stats.dind = stats.dind.slice(1);
|
||||
stats.doutd.push(data.dam.out.done / 1024 / 1024); stats.doutd = stats.doutd.slice(1);
|
||||
new Chartist.Line('.ct-damd', {
|
||||
// A labels array that can contain any sort of values
|
||||
labels: ['-1min', '-45s', '-30s', '-15s', '0'],
|
||||
// Our series array that contains series objects or in this case series data arrays
|
||||
series: [stats.doutd, stats.dind]
|
||||
}, {fullWidth: true, axisY: {
|
||||
labelInterpolationFnc: function(v) { return v+'MB' }
|
||||
}});
|
||||
|
||||
try{ $('#rerr').text(data.rad.put.err || data.rad.get.err) }catch(e){}
|
||||
|
||||
try{
|
||||
stats.rgetc.push(data.rad.get.count); stats.rgetc = stats.rgetc.slice(1);
|
||||
stats.rputc.push(data.rad.put.count); stats.rputc = stats.rputc.slice(1);
|
||||
new Chartist.Line('.ct-radc', {
|
||||
// A labels array that can contain any sort of values
|
||||
labels: ['-1min', '-45s', '-30s', '-15s', '0'],
|
||||
// Our series array that contains series objects or in this case series data arrays
|
||||
series: [stats.rputc, stats.rgetc]
|
||||
}, {fullWidth: true, axisY: {
|
||||
labelInterpolationFnc: function(v) { return v+'io' }
|
||||
}});
|
||||
}catch(e){}
|
||||
|
||||
try{
|
||||
stats.radgt = Object.values(data.rad.get.time).map(function(n){ return n/1000 });
|
||||
stats.radpt = Object.values(data.rad.put.time).map(function(n){ return n/1000 });
|
||||
new Chartist.Line('.ct-radt', {
|
||||
// A labels array that can contain any sort of values
|
||||
//labels: ['-1min', '-45s', '-30s', '-15s', '0'],
|
||||
// Our series array that contains series objects or in this case series data arrays
|
||||
series: [stats.radpt, stats.radgt]
|
||||
}, {fullWidth: true, axisY: {
|
||||
labelInterpolationFnc: function(v) { return v+'sec' }
|
||||
}});
|
||||
}catch(e){}
|
||||
|
||||
try{
|
||||
stats.daml = Object.values(data.dam['in'].long).map(function(n){ return n });
|
||||
new Chartist.Line('.ct-daml', {
|
||||
// A labels array that can contain any sort of values
|
||||
//labels: ['-1min', '-45s', '-30s', '-15s', '0'],
|
||||
// Our series array that contains series objects or in this case series data arrays
|
||||
series: [stats.daml]
|
||||
}, {fullWidth: true, axisY: {
|
||||
labelInterpolationFnc: function(v) { return v+'ms' }
|
||||
}});
|
||||
}catch(e){}
|
||||
|
||||
new Chartist.Line('.ct-cpu', {
|
||||
// A labels array that can contain any sort of values
|
||||
labels: ['-15min', '-5min', '1min'],
|
||||
// Our series array that contains series objects or in this case series data arrays
|
||||
series: [data.cpu.loadavg.reverse()]
|
||||
}, {fullWidth: true, low: 0, axisY: {
|
||||
labelInterpolationFnc: function(v) { return v+'cpu' }
|
||||
}});
|
||||
//})
|
||||
}
|
||||
stats.show();
|
||||
function Stats(key, chart){
|
||||
// if we have already created, get data to append to it.
|
||||
if(chart = Stats[key]){
|
||||
return chart;
|
||||
}
|
||||
// create a new Series for this key
|
||||
// add it into the map
|
||||
chart = Stats[key] = new SmoothieChart({responsive: true, minValue: 0, grid:{strokeStyle:'rgba(100%,100%,100%,0.2)'},labels:{fontSize:20}});
|
||||
chart.line = new TimeSeries();
|
||||
chart.addTimeSeries(chart.line,{ strokeStyle:'rgb('+Math.random()*255+', '+Math.random()*255+','+Math.random()*255+')', lineWidth:5 });
|
||||
chart.canvas = $('.model').find('.chart').clone(true).appendTo('.charts');
|
||||
chart.canvas.find('span').text(key);
|
||||
chart.streamTo(chart.canvas.find('canvas').get(0), 15 * 1000);
|
||||
// check first two characters of key to determine other charts to add this in
|
||||
// tbd later
|
||||
return chart;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
66
gun.js
66
gun.js
@ -811,20 +811,16 @@
|
||||
// Maybe... in case the in-memory key we have is a local write
|
||||
// we still need to trigger a pull/merge from peers.
|
||||
} else {
|
||||
//var S = +new Date;
|
||||
node = Gun.obj.copy(node);
|
||||
//console.log(+new Date - S, 'copy node');
|
||||
}
|
||||
node = Gun.graph.node(node);
|
||||
tmp = (at||empty).ack;
|
||||
//var S = +new Date;
|
||||
root.on('in', {
|
||||
'@': msg['#'],
|
||||
how: 'mem',
|
||||
put: node,
|
||||
$: gun
|
||||
});
|
||||
//console.log(+new Date - S, 'root got send');
|
||||
//if(0 < tmp){ return }
|
||||
root.on('get', msg);
|
||||
}
|
||||
@ -965,7 +961,7 @@
|
||||
if(obj_has(back, 'put')){
|
||||
back.on('in', back);
|
||||
}
|
||||
if(tmp){ return }
|
||||
if(tmp && u !== back.put){ return } //if(tmp){ return }
|
||||
msg.$ = back.$;
|
||||
} else
|
||||
if(obj_has(back.put, get)){ // TODO: support #LEX !
|
||||
@ -1178,7 +1174,7 @@
|
||||
if(u === tmp && u !== at.put){ return true }
|
||||
neat.put = u;
|
||||
if(neat.ack){
|
||||
neat.ack = -1; // TODO: BUG? Should this be 0?
|
||||
neat.ack = -1; // Shouldn't this be reset to 0? If we do that, SEA test `set user ref should be found` fails, odd.
|
||||
}
|
||||
neat.on('in', {
|
||||
get: key,
|
||||
@ -1317,7 +1313,6 @@
|
||||
function use(msg){
|
||||
var eve = this, as = eve.as, cat = as.at, root = cat.root, gun = msg.$, at = (gun||{})._ || {}, data = msg.put || at.put, tmp;
|
||||
if((tmp = root.now) && eve !== tmp[as.now]){ return eve.to.next(msg) }
|
||||
//console.log("USE:", cat.id, cat.soul, cat.has, cat.get, msg, root.mum);
|
||||
//if(at.async && msg.root){ return }
|
||||
//if(at.async === 1 && cat.async !== true){ return }
|
||||
//if(root.stop && root.stop[at.id]){ return } root.stop && (root.stop[at.id] = true);
|
||||
@ -1545,7 +1540,7 @@
|
||||
as = as.as;
|
||||
if(!msg.$ || !msg.$._){ return } // TODO: Handle
|
||||
if(msg.err){ // TODO: Handle
|
||||
console.log("Please report this as an issue! Put.any.err");
|
||||
Gun.log("Please report this as an issue! Put.any.err");
|
||||
return;
|
||||
}
|
||||
var at = (msg.$._), data = at.put, opt = as.opt||{}, root, tmp;
|
||||
@ -1554,7 +1549,7 @@
|
||||
if(as.ref !== as.$){
|
||||
tmp = (as.$._).get || at.get;
|
||||
if(!tmp){ // TODO: Handle
|
||||
console.log("Please report this as an issue! Put.no.get"); // TODO: BUG!??
|
||||
Gun.log("Please report this as an issue! Put.no.get"); // TODO: BUG!??
|
||||
return;
|
||||
}
|
||||
as.data = obj_put({}, tmp, as.data);
|
||||
@ -1814,7 +1809,7 @@
|
||||
var root, noop = function(){}, store, u;
|
||||
try{store = (Gun.window||noop).localStorage}catch(e){}
|
||||
if(!store){
|
||||
console.log("Warning: No localStorage exists to persist data to!");
|
||||
Gun.log("Warning: No localStorage exists to persist data to!");
|
||||
store = {setItem: function(k,v){this[k]=v}, removeItem: function(k){delete this[k]}, getItem: function(k){return this[k]}};
|
||||
}
|
||||
/*
|
||||
@ -1920,7 +1915,6 @@
|
||||
data = Gun.state.to(data, has);
|
||||
}
|
||||
//if(!data && !Gun.obj.empty(opt.peers)){ return } // if data not found, don't ack if there are peers. // Hmm, what if we have peers but we are disconnected?
|
||||
//console.log("lS get", lex, data);
|
||||
root.on('in', {'@': msg['#'], put: Gun.graph.node(data), how: 'lS', lS: msg.$});// || root.$});
|
||||
};
|
||||
Gun.debug? setTimeout(to,1) : to();
|
||||
@ -1976,15 +1970,14 @@
|
||||
if('[' === tmp){
|
||||
try{msg = JSON.parse(raw);}catch(e){opt.log('DAM JSON parse error', e)}
|
||||
if(!msg){ return }
|
||||
//console.log('hear batch length of', msg.length);
|
||||
LOG && opt.log(+new Date, msg.length, 'in hear batch');
|
||||
(function go(){
|
||||
var S = +new Date; // STATS!
|
||||
var S; LOG && (S = +new Date); // STATS!
|
||||
var m, c = 100; // hardcoded for now?
|
||||
while(c-- && (m = msg.shift())){
|
||||
mesh.hear(m, peer);
|
||||
}
|
||||
//console.log(+new Date - S, 'hear batch');
|
||||
(mesh.hear.long || (mesh.hear.long = [])).push(+new Date - S);
|
||||
LOG && opt.log(S, +new Date - S, 'batch heard');
|
||||
if(!msg.length){ return }
|
||||
puff(go, 0);
|
||||
}());
|
||||
@ -1995,7 +1988,7 @@
|
||||
}catch(e){return opt.log('DAM JSON parse error', e)}
|
||||
if(!msg){ return }
|
||||
if(!(id = msg['#'])){ id = msg['#'] = Type.text.random(9) }
|
||||
if(msg.DBG_s){ console.log(+new Date - msg.DBG_s, 'to hear', id) }
|
||||
if(msg.DBG_s){ opt.log(+new Date - msg.DBG_s, 'to hear', id) }
|
||||
if(dup.check(id)){ return }
|
||||
dup.track(id, true).it = msg; // GUN core also dedups, so `true` is needed. // Does GUN core need to dedup anymore?
|
||||
if(!(hash = msg['##']) && u !== msg.put){ hash = msg['##'] = Type.obj.hash(msg.put) }
|
||||
@ -2011,9 +2004,9 @@
|
||||
}
|
||||
return;
|
||||
}
|
||||
//var S = +new Date;
|
||||
var S; LOG && (S = +new Date);
|
||||
root.on('in', msg);
|
||||
//!msg.nts && console.log(+new Date - S, 'msg', msg['#']);
|
||||
LOG && !msg.nts && opt.log(S, +new Date - S, 'msg', msg['#']);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -2027,7 +2020,7 @@
|
||||
if(this.to){ this.to.next(msg) } // compatible with middleware adapters.
|
||||
if(!msg){ return false }
|
||||
var id, hash, tmp, raw;
|
||||
//var S = +new Date; //msg.DBG_s = msg.DBG_s || +new Date;
|
||||
var S; LOG && (S = +new Date); //msg.DBG_s = msg.DBG_s || +new Date;
|
||||
var meta = msg._||(msg._=function(){});
|
||||
if(!(id = msg['#'])){ id = msg['#'] = Type.text.random(9) }
|
||||
if(!(hash = msg['##']) && u !== msg.put){ hash = msg['##'] = Type.obj.hash(msg.put) }
|
||||
@ -2041,15 +2034,15 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
//console.log(+new Date - S, 'mesh say prep');
|
||||
LOG && opt.log(S, +new Date - S, 'say prep');
|
||||
dup.track(id).it = msg; // track for 9 seconds, default. Earth<->Mars would need more!
|
||||
if(!peer){ peer = (tmp = dup.s[msg['@']]) && (tmp = tmp.it) && (tmp = tmp._) && (tmp = tmp.via) }
|
||||
if(!peer && mesh.way){ return mesh.way(msg) }
|
||||
if(!peer || !peer.id){ message = msg;
|
||||
if(!Type.obj.is(peer || opt.peers)){ return false }
|
||||
//var S = +new Date;
|
||||
var S; LOG && (S = +new Date);
|
||||
Type.obj.map(peer || opt.peers, each); // in case peer is a peer list.
|
||||
//console.log(+new Date - S, 'mesh say loop');
|
||||
LOG && opt.log(S, +new Date - S, 'say loop');
|
||||
return;
|
||||
}
|
||||
if(!peer.wire && mesh.wire){ mesh.wire(peer) }
|
||||
@ -2073,10 +2066,10 @@
|
||||
peer.batch = peer.tail = null;
|
||||
if(!tmp){ return }
|
||||
if(!tmp.length){ return } // if(3 > tmp.length){ return } // TODO: ^
|
||||
//var S = +new Date;
|
||||
var S; LOG && (S = +new Date);
|
||||
try{tmp = (1 === tmp.length? tmp[0] : JSON.stringify(tmp));
|
||||
}catch(e){return opt.log('DAM JSON stringify error', e)}
|
||||
//console.log(+new Date - S, 'mesh flush', tmp.length);
|
||||
LOG && opt.log(S, +new Date - S, 'say stringify', tmp.length);
|
||||
if(!tmp){ return }
|
||||
send(tmp, peer);
|
||||
}
|
||||
@ -2086,14 +2079,14 @@
|
||||
// for now - find better place later.
|
||||
function send(raw, peer){ try{
|
||||
var wire = peer.wire;
|
||||
//var S = +new Date;
|
||||
var S; LOG && (S = +new Date);
|
||||
if(peer.say){
|
||||
peer.say(raw);
|
||||
} else
|
||||
if(wire.send){
|
||||
wire.send(raw);
|
||||
}
|
||||
//console.log(+new Date - S, 'wire send', raw.length);
|
||||
LOG && opt.log(S, +new Date - S, 'wire send', raw.length);
|
||||
mesh.say.d += raw.length||0; ++mesh.say.c; // STATS!
|
||||
}catch(e){
|
||||
(peer.queue = peer.queue || []).push(raw);
|
||||
@ -2129,7 +2122,8 @@
|
||||
opt.peers[peer.url || peer.id] = peer;
|
||||
} else {
|
||||
tmp = peer.id = peer.id || Type.text.random(9);
|
||||
mesh.say({dam: '?'}, opt.peers[tmp] = peer);
|
||||
mesh.say({dam: '?', pid: root.opt.pid}, opt.peers[tmp] = peer);
|
||||
delete dup.s[peer.last]; // IMPORTANT: see https://gun.eco/docs/DAM#self
|
||||
}
|
||||
peer.met = peer.met || +(new Date);
|
||||
if(!tmp.hied){ root.on(tmp.hied = 'hi', peer) }
|
||||
@ -2143,21 +2137,16 @@
|
||||
root.on('bye', peer);
|
||||
var tmp = +(new Date); tmp = (tmp - (peer.met||tmp));
|
||||
mesh.bye.time = ((mesh.bye.time || tmp) + tmp) / 2;
|
||||
LOG = console.LOG; // dirty place to cheaply update LOG settings over time.
|
||||
}
|
||||
mesh.hear['!'] = function(msg, peer){ opt.log('Error:', msg.err) }
|
||||
mesh.hear['?'] = function(msg, peer){
|
||||
if(!msg.pid){
|
||||
mesh.say({dam: '?', pid: opt.pid, '@': msg['#']}, peer);
|
||||
// @rogowski I want to re-enable this AXE logic with some fix/merge later.
|
||||
/* var tmp = peer.queue; peer.queue = [];
|
||||
Type.obj.map(tmp, function(msg){
|
||||
mesh.say(msg, peer);
|
||||
}); */
|
||||
// @rogowski 2: I think with my PID fix we can delete this and use the original.
|
||||
return;
|
||||
if(msg.pid){
|
||||
if(!peer.pid){ peer.pid = msg.pid }
|
||||
if(msg['@']){ return }
|
||||
}
|
||||
if(peer.pid){ return }
|
||||
peer.pid = msg.pid;
|
||||
mesh.say({dam: '?', pid: opt.pid, '@': msg['#']}, peer);
|
||||
delete dup.s[peer.last]; // IMPORTANT: see https://gun.eco/docs/DAM#self
|
||||
}
|
||||
|
||||
root.on('create', function(root){
|
||||
@ -2223,6 +2212,7 @@
|
||||
}());
|
||||
|
||||
var empty = {}, ok = true, u;
|
||||
var LOG = console.LOG;
|
||||
|
||||
try{ module.exports = Mesh }catch(e){}
|
||||
|
||||
|
2
gun.min.js
vendored
2
gun.min.js
vendored
File diff suppressed because one or more lines are too long
416
lib/meta.js
416
lib/meta.js
@ -1,155 +1,190 @@
|
||||
;(function(){
|
||||
var noop = function(){}, u;
|
||||
var m = window.meta = {edit:[]};
|
||||
var k = m.key = {};
|
||||
k.meta = {17:17, 91:17, 93:17, 224:17};
|
||||
k.down = function(eve){
|
||||
if(eve.repeat){ return }
|
||||
var key = (k.eve = m.eve = eve).which = eve.which || eve.fake || eve.keyCode;
|
||||
if(!eve.fake && key === k.last){ return } k.last = key;
|
||||
if(!eve.fake && $(eve.target).closest('input, textarea, [contenteditable=true]').length){
|
||||
if(k.meta[key]){ k.down.meta = key = -1 }
|
||||
if(!k.down.meta){ return }
|
||||
}
|
||||
(k.combo || (k.combo = [])).push(key);
|
||||
m.check('on', key, k.at || (k.at = m.edit));
|
||||
if(k.meta[key]){
|
||||
m.list(k.at.back || m.edit);
|
||||
if(k.at && !k.at.back){ m.flip() }
|
||||
}
|
||||
}
|
||||
k.up = function(eve){ var tmp;
|
||||
var key = (k.eve = m.eve = eve).which = eve.which || eve.fake || eve.keyCode;
|
||||
if(!eve.fake && $(eve.target).closest('input, textarea, [contenteditable=true]').length){
|
||||
var root;
|
||||
if(typeof window !== "undefined"){ root = window }
|
||||
if(typeof global !== "undefined"){ root = global }
|
||||
root = root || {};
|
||||
var console = root.console || {log: function(){}};
|
||||
function USE(arg, req){
|
||||
return req? require(arg) : arg.slice? USE[R(arg)] : function(mod, path){
|
||||
arg(mod = {exports: {}});
|
||||
USE[R(path)] = mod.exports;
|
||||
}
|
||||
function R(p){
|
||||
return p.split('/').slice(-1).toString().replace('.js','');
|
||||
}
|
||||
}
|
||||
if(typeof module !== "undefined"){ var common = module }
|
||||
|
||||
/* UNBUILD */
|
||||
;USE(function(module){
|
||||
|
||||
var noop = function(){}, u;
|
||||
$.fn.or = function(s){ return this.length ? this : $(s||'body') };
|
||||
var m = window.meta = {edit:[]};
|
||||
var k = m.key = {};
|
||||
k.meta = {17:17, 91:17, 93:17, 224:17}; // ctrl met
|
||||
|
||||
function withMeta(eve){ return eve.metaKey || eve.ctrlKey }
|
||||
|
||||
k.down = function(eve){
|
||||
if(eve.repeat){ return }
|
||||
var key = (k.eve = m.eve = eve).which = eve.which || eve.fake || eve.keyCode;
|
||||
|
||||
// ADDED
|
||||
//if(!m.flip.is() && !k.meta[key]){ return } // cancel non-open events when closed TODO make optional
|
||||
if(!k.meta[key] && withMeta(eve) && !k.at[key]) { return m.flip(false) } // cancel and close when no action and "meta key" held down (e.g. ctrl+c)
|
||||
|
||||
if(!eve.fake && key === k.last){ return }; k.last = key; // jussi: polyfilling eve.repeat?
|
||||
if(!eve.fake && $(eve.target).closest('input, textarea, [contenteditable=true]').length && !$(eve.target).closest('#meta').length){
|
||||
if(!meta.flip.is() && !withMeta(eve)){ // cancel meta/hud during text input UNLESS hud is open OR cmd key is held down.
|
||||
return;
|
||||
}
|
||||
//if(k.meta[key]){ k.down.meta = key = -1 }
|
||||
//if(!k.down.meta){ return }
|
||||
// hmmm?
|
||||
//if(!k.meta[key] && !meta.flip.is()) return // aserwed
|
||||
}
|
||||
m.check('on', key, k.at || (k.at = m.edit));
|
||||
if(k.meta[key]){
|
||||
k.down.meta = null;
|
||||
key = -1;
|
||||
} else
|
||||
if(!k.down.meta){ return }
|
||||
}
|
||||
k.last = null;
|
||||
if($(':focus').closest('#meta').length){ return }
|
||||
m.check('up', key);
|
||||
if(-1 === key || 27 === eve.which){ k.wipe() }
|
||||
}
|
||||
m.flip = function(tmp){
|
||||
var board = $('#meta .meta-menu');
|
||||
((tmp === false) || (!tmp && board.is(':visible')))?
|
||||
board.addClass('meta-none')
|
||||
: board.removeClass('meta-none');
|
||||
}
|
||||
m.flip.is = function(){
|
||||
return $('#meta .meta-menu').is(':visible');
|
||||
}
|
||||
m.flip.wait = 500;
|
||||
m.check = function(how, key, at){
|
||||
at = k.at || m.edit;
|
||||
var edit = at[key];
|
||||
if(!edit){ return }
|
||||
var tmp = k.eve || noop;
|
||||
if(tmp.preventDefault){ tmp.preventDefault() }
|
||||
if(edit[how]){
|
||||
if(tmp.fake && !edit.fake){
|
||||
m.tap.edit = edit;
|
||||
} else {
|
||||
edit[how](m.eve);
|
||||
/*if(k.at !== m.edit && 'up' === how){
|
||||
if(k.down.meta){ m.list(k.at = m.edit) }
|
||||
else { k.wipe() }
|
||||
}*/
|
||||
// m.list(k.at.back || m.edit);
|
||||
// if(k.at){ m.flip() } // && !k.at.back
|
||||
m.flip()
|
||||
}
|
||||
}
|
||||
if('up' != how){ return }
|
||||
if(at != edit){ edit.back = at }
|
||||
m.list(edit, true);
|
||||
}
|
||||
m.list = function(at, opt){
|
||||
if(!at){ return m.flip(false) }
|
||||
var l = [];
|
||||
$.each(at, function(i,k){ 'back' != i && k.combo && k.name && l.push(k) });
|
||||
if(!l.length){ return }
|
||||
k.at = at;
|
||||
l = l.sort(function(a,b){
|
||||
a = a.combo.slice(-1)[0] || 0;
|
||||
if(a.length){ a = a.toUpperCase().charCodeAt(0) }
|
||||
b = b.combo.slice(-1)[0] || 0;
|
||||
if(b.length){ b = b.toUpperCase().charCodeAt(0) }
|
||||
return (a < b)? -1 : 1;
|
||||
});
|
||||
var $ul = $('#meta .meta-menu ul')
|
||||
$ul.children('li').addClass('meta-none').hide(); setTimeout(function(){ $ul.children('.meta-none').remove() },250); // necessary fix for weird bug glitch
|
||||
$.each(l, function(i, k){
|
||||
$ul.append($('<li>').text(k.name));
|
||||
});
|
||||
if(opt){ m.flip(true) }
|
||||
$ul.append($('<li>').html('←').one('click', function(){
|
||||
m.list(k.at = at.back);
|
||||
}));
|
||||
}
|
||||
m.ask = function(help, cb){
|
||||
var $ul = $('#meta .meta-menu ul').empty();
|
||||
var $put = $('<input>').attr('id', 'meta-ask').attr('placeholder', help);
|
||||
var $form = $('<form>').append($put).on('submit', function(eve){
|
||||
eve.preventDefault();
|
||||
cb($put.val());
|
||||
$li.remove();
|
||||
k.wipe();
|
||||
});
|
||||
var $li = $('<li>').append($form);
|
||||
$ul.append($li);
|
||||
m.flip(true);
|
||||
$put.focus();
|
||||
}
|
||||
k.wipe = function(opt){
|
||||
k.down.meta = false;
|
||||
k.combo = [];
|
||||
if(!opt){ m.flip(false) }
|
||||
m.list(k.at = m.edit);
|
||||
};
|
||||
m.tap = function(){
|
||||
var on = $('.meta-on')
|
||||
.or($($(document.querySelectorAll(':hover')).get().reverse()).first())
|
||||
.or($(document.elementFromPoint(meta.tap.x, meta.tap.y)));
|
||||
return on;
|
||||
}
|
||||
$(window).on('blur', k.wipe).on('focus', k.wipe);
|
||||
$(document).on('mousedown mousemove mouseup', function(eve){
|
||||
m.tap.eve = eve;
|
||||
m.tap.x = eve.pageX||0;
|
||||
m.tap.y = eve.pageY||0;
|
||||
m.tap.on = $(eve.target);
|
||||
}).on('mousedown touchstart', function(eve){
|
||||
var tmp = m.tap.edit;
|
||||
if(!tmp || !tmp.on){ return }
|
||||
tmp.on(eve);
|
||||
m.tap.edit = null;
|
||||
});
|
||||
$(document).on('touchstart', '#meta .meta-start', function(eve){ m.tap.stun = true });
|
||||
$(document).on('click', '#meta .meta-menu li', function(eve){
|
||||
if(m.tap.stun){ return m.tap.stun = false }
|
||||
if(!(eve.fake = eve.which = (($(this).text().match(/[A-Z]/)||{})[0]||'').toUpperCase().charCodeAt(0))){ return }
|
||||
eve.tap = true;
|
||||
k.down(eve);
|
||||
k.up(eve);
|
||||
});
|
||||
$(document).on('keydown', k.down).on('keyup', k.up);
|
||||
meta.edit = function(edit){
|
||||
var tmp = edit.combow = [];
|
||||
$.each(edit.combo || (edit.combo = []), function(i,k){
|
||||
if(!k || !k.length){ if('number' == typeof k){ tmp.push(k) } return }
|
||||
tmp.push(k.toUpperCase().charCodeAt(0));
|
||||
});
|
||||
var at = meta.edit, l = edit.combo.length;
|
||||
$.each(tmp, function(i,k){ at = at[k] = (++i >= l)? edit : at[k] || {} });
|
||||
edit.combow = edit.combow.join(',');
|
||||
m.list(meta.edit);
|
||||
}
|
||||
$.fn.or = function(s){ return this.length ? this : $(s||'body') };
|
||||
;(function(){try{
|
||||
k.up = function(eve){ var tmp;
|
||||
var key = (k.eve = m.eve = eve).which = eve.which || eve.fake || eve.keyCode;
|
||||
//if(!m.flip.is() && !k.meta[key]){ return } // ADDED cancel non-open events when closed TODO make optional
|
||||
// if(!eve.fake && $(eve.target).closest('input, textarea, [contenteditable=true]').length){
|
||||
// if(k.meta[key]){
|
||||
// k.down.meta = null;
|
||||
// key = -1;
|
||||
// } else
|
||||
// if(!k.down.meta){ return }
|
||||
// }
|
||||
k.last = null;
|
||||
// if($(':focus').closest('#meta').length){ return }
|
||||
m.check('up', key);
|
||||
if(27 === eve.which){ k.wipe() } // -1 === key ||
|
||||
}
|
||||
m.flip = function(tmp){
|
||||
var board = $('#meta .meta-menu');
|
||||
((tmp === false) || (!tmp && board.is(':visible')))?
|
||||
board.addClass('meta-none')
|
||||
: board.removeClass('meta-none');
|
||||
}
|
||||
m.flip.is = function(){
|
||||
return $('#meta .meta-menu').is(':visible');
|
||||
}
|
||||
m.flip.wait = 500;
|
||||
m.check = function(how, key, at){
|
||||
at = k.at || m.edit;
|
||||
var next = at[key];
|
||||
if(!next){ return }
|
||||
var tmp = k.eve || noop;
|
||||
if(tmp.preventDefault){ tmp.preventDefault()} // prevent typing (etc) when action found
|
||||
if(next[how]){
|
||||
//if(tmp.fake && !next.fake){
|
||||
//m.tap.next = next;
|
||||
//} else {
|
||||
next[how](m.eve);
|
||||
meta.ui.blink()
|
||||
/*if(k.at !== m.next && 'up' === how){
|
||||
if(k.down.meta){ m.list(k.at = m.next) }
|
||||
else { k.wipe() }
|
||||
}*/
|
||||
//}
|
||||
}
|
||||
if('up' == how){ return }
|
||||
if(at != next){ next.back = at }
|
||||
(k.combo || (k.combo = [])).push(key);
|
||||
m.list(next, true);
|
||||
}
|
||||
m.list = function(at, opt){
|
||||
if(!at){ return m.flip(false) }
|
||||
// m.ui.depth(m.key.combo ? m.key.combo.length : 0)
|
||||
var l = [];
|
||||
$.each(at, function(i,k){ 'back' != i && k.combo && k.name && l.push(k) });
|
||||
if(!l.length){ return }
|
||||
k.at = at;
|
||||
l = l.sort(function(a,b){
|
||||
a = a.combo.slice(-1)[0] || 0;
|
||||
if(a.length){ a = a.toUpperCase().charCodeAt(0) }
|
||||
b = b.combo.slice(-1)[0] || 0;
|
||||
if(b.length){ b = b.toUpperCase().charCodeAt(0) }
|
||||
return (a < b)? -1 : 1;
|
||||
});
|
||||
var $ul = $('#meta .meta-menu ul')
|
||||
$ul.children('li').addClass('meta-none').hide(); setTimeout(function(){ $ul.children('.meta-none').remove() },250); // necessary fix for weird bug glitch
|
||||
$.each(l, function(i, k){
|
||||
$ul.append($('<li>').text(k.name).data(k));
|
||||
});
|
||||
if(opt){ m.flip(true) }
|
||||
$ul.append($('<li>').html('←').on('click', function(){
|
||||
// m.key.combo.pop()
|
||||
m.list(at.back);
|
||||
}));
|
||||
}
|
||||
m.ask = function(help, cb){
|
||||
var $ul = $('#meta .meta-menu ul').empty();
|
||||
var $put = $('<input>').attr('id', 'meta-ask').attr('placeholder', help);
|
||||
var $form = $('<form>').append($put).on('submit', function(eve){
|
||||
eve.preventDefault();
|
||||
cb($put.val());
|
||||
$li.remove();
|
||||
//k.wipe();
|
||||
m.list(k.at);
|
||||
});
|
||||
var $li = $('<li>').append($form);
|
||||
$ul.append($li);
|
||||
m.flip(true);
|
||||
$put.focus();
|
||||
}
|
||||
k.wipe = function(opt){
|
||||
// k.down.meta = false;
|
||||
k.combo = [];
|
||||
if(!opt){ m.flip(false) }
|
||||
m.list(k.at = m.edit);
|
||||
};
|
||||
m.tap = function(){
|
||||
var on = $('.meta-on')
|
||||
.or($($(document.querySelectorAll(':hover')).get().reverse()).first())
|
||||
.or($(document.elementFromPoint(meta.tap.x||0, meta.tap.y||0)));
|
||||
return on;
|
||||
}
|
||||
meta.edit = function(edit){
|
||||
var tmp = edit.combow = [];
|
||||
$.each(edit.combo || (edit.combo = []), function(i,k){
|
||||
if(!k || !k.length){ if('number' == typeof k){ tmp.push(k) } return }
|
||||
tmp.push(k.toUpperCase().charCodeAt(0));
|
||||
});
|
||||
var at = meta.edit, l = edit.combo.length;
|
||||
$.each(tmp, function(i,k){ at = at[k] = (++i >= l)? edit : at[k] || {} });
|
||||
edit.combow = edit.combow.join(',');
|
||||
m.list(k.at || meta.edit);
|
||||
}
|
||||
|
||||
|
||||
})(USE, './metaCore');
|
||||
;USE(function(module){
|
||||
/* UI */
|
||||
if(meta.css){ return }
|
||||
meta.ui = {
|
||||
blink: function(){ // hint visually that action has happened
|
||||
$('#meta').css('transition', 'none').css('background', 'none')
|
||||
setTimeout(function(){
|
||||
$('#meta')[0].style.transition = null
|
||||
$('#meta')[0].style.background = null
|
||||
})
|
||||
},
|
||||
depth: function(n){
|
||||
if (n) {
|
||||
$('#meta').css('background', 'hsl(60, 100%,'+(85-(n*10))+'%)');
|
||||
} else {
|
||||
$('#meta')[0].style.background = null
|
||||
}
|
||||
}
|
||||
}
|
||||
var $m = $('<div>').attr('id', 'meta');
|
||||
$m.append($('<span>').text('+').addClass('meta-start'));
|
||||
$m.append($('<span>').html('☰').addClass('meta-start'));
|
||||
$m.append($('<div>').addClass('meta-menu meta-none').append('<ul>'));
|
||||
$(document.body).append($m);
|
||||
css({
|
||||
@ -161,7 +196,7 @@
|
||||
background: 'white',
|
||||
'font-size': '18pt',
|
||||
'font-family': 'Tahoma, arial',
|
||||
'box-shadow': '0px 0px 1px #000044',
|
||||
//'box-shadow': '0px 0px 1px #000044',
|
||||
'border-radius': '1em',
|
||||
'text-align': 'center',
|
||||
'z-index': 999999,
|
||||
@ -202,25 +237,26 @@
|
||||
'border-radius': '1em',
|
||||
'margin-left': '0.25em',
|
||||
'margin-top': '0.25em',
|
||||
'float': 'right'
|
||||
'float': 'right',
|
||||
'cursor': 'pointer'
|
||||
},
|
||||
'#meta a': {color: 'black'},
|
||||
'#meta:hover': {opacity: 1},
|
||||
// '#meta:hover': {opacity: 1},
|
||||
'#meta .meta-menu ul:before': {
|
||||
content: "' '",
|
||||
display: 'block',
|
||||
'min-height': '15em',
|
||||
height: '50vh'
|
||||
},
|
||||
'#meta li': {
|
||||
background: 'white',
|
||||
padding: '0.5em 1em',
|
||||
'border-radius': '1em',
|
||||
'margin-left': '0.25em',
|
||||
'margin-top': '0.25em',
|
||||
'float': 'right'
|
||||
},
|
||||
'#meta:hover .meta-menu': {display: 'block'}
|
||||
// '#meta li': {
|
||||
// background: 'white',
|
||||
// padding: '0.5em 1em',
|
||||
// 'border-radius': '1em',
|
||||
// 'margin-left': '0.25em',
|
||||
// 'margin-top': '0.25em',
|
||||
// 'float': 'right'
|
||||
// },
|
||||
// '#meta:hover .meta-menu': {display: 'block'}
|
||||
});
|
||||
function css(css){
|
||||
var tmp = '';
|
||||
@ -233,10 +269,14 @@
|
||||
});
|
||||
var tag = document.createElement('style');
|
||||
tag.innerHTML = tmp;
|
||||
document.body.appendChild(tag);
|
||||
$m.append(tag)
|
||||
}
|
||||
}catch(e){}}());
|
||||
;(function(){
|
||||
//}catch(e){}
|
||||
|
||||
|
||||
})(USE, './metaUI');
|
||||
;USE(function(module){
|
||||
|
||||
// include basic text editing by default.
|
||||
var monotype = window.monotype || function(){console.log("monotype needed")};
|
||||
var m = meta;
|
||||
@ -256,7 +296,6 @@
|
||||
return ((tmp = window.getSelection) && tmp().toString()) ||
|
||||
((tmp = document.selection) && tmp.createRange().text) || '';
|
||||
}
|
||||
$(document).on('select contextmenu keyup mouseup', '[contenteditable=true]', m.text.on);
|
||||
m.text.editor = function(opt, as){ var tmp;
|
||||
if(!opt){ return }
|
||||
opt = (typeof opt == 'string')? {edit: opt} : opt.tag? opt : {tag: opt};
|
||||
@ -266,7 +305,7 @@
|
||||
r.restore();
|
||||
if(document.execCommand(cmd, null, as||null)){
|
||||
if(m.text.range){ m.text.range = monotype() }
|
||||
return;
|
||||
return meta.flip(false); // ADDED meta.flip
|
||||
}
|
||||
}
|
||||
if(!opt.tag){ return }
|
||||
@ -379,5 +418,54 @@
|
||||
on: function(eve){ meta.text.editor('fontSize', 7) },
|
||||
up: function(){}
|
||||
});
|
||||
}());
|
||||
|
||||
|
||||
})(USE, './metaText');
|
||||
;USE(function(module){
|
||||
var m = meta, k = m.key;
|
||||
$(window).on('focus', k.wipe.bind(null, false)); // .on('blur', k.wipe.bind(null, false))
|
||||
$(document).on('mousedown mousemove mouseup', function(eve){
|
||||
m.tap.eve = eve;
|
||||
m.tap.x = eve.pageX||0;
|
||||
m.tap.y = eve.pageY||0;
|
||||
m.tap.on = $(eve.target);
|
||||
})
|
||||
// Setting m.tap.edit has been commented, so should never end up here?
|
||||
//.on('mousedown touchstart', function(eve){
|
||||
// var tmp = m.tap.edit;
|
||||
// if(!tmp || !tmp.on){ return }
|
||||
// tmp.on(eve);
|
||||
// m.tap.edit = null;
|
||||
//});
|
||||
|
||||
//$(document).on('touchstart', '#meta .meta-start', function(eve){ m.tap.stun = true });
|
||||
|
||||
var [start, end] = 'ontouchstart' in window
|
||||
? ['touchstart', 'touchend']
|
||||
: ['mousedown', 'mouseup']
|
||||
|
||||
$(document).on(start, '#meta .meta-menu li', function(eve){
|
||||
var combo = $(this).data().combo;
|
||||
eve.fake = eve.which = combo && combo.slice(-1)[0].charCodeAt(0);
|
||||
eve.tap = true;
|
||||
k.down(eve);
|
||||
$(document).one(end, () => k.up(eve))
|
||||
return;
|
||||
// if(m.tap.stun){ return m.tap.stun = false }
|
||||
// if(!(eve.fake = eve.which = (($(this).text().match(/[A-Z]/)||{})[0]||'').toUpperCase().charCodeAt(0))){ return }
|
||||
// eve.tap = true;
|
||||
// k.down(eve);
|
||||
// k.up(eve);
|
||||
});
|
||||
$(document).on('keydown', k.down).on('keyup', k.up);
|
||||
|
||||
$('#meta').on('click', function(ev) {
|
||||
if (ev.target.tagName == 'LI' || ev.target.tagName == 'UL') return
|
||||
meta.flip()
|
||||
})
|
||||
|
||||
//$(document).on('select contextmenu keyup mouseup', '[contenteditable=true]', m.text.on);
|
||||
|
||||
|
||||
})(USE, './metaEvents');
|
||||
}());
|
@ -22,7 +22,7 @@ Gun.on('create', function(root){
|
||||
socket.bind({port: udp.port, exclusive: true}, function(){
|
||||
socket.setBroadcast(true);
|
||||
socket.setMulticastTTL(128);
|
||||
socket.addMembership(udp.address);
|
||||
try{ socket.addMembership(udp.address); }catch(e){}
|
||||
});
|
||||
|
||||
socket.on("listening", function(){
|
||||
|
@ -1,7 +1,8 @@
|
||||
(function(){
|
||||
|
||||
$.normalize = function(html, customOpt){
|
||||
var html, root$, wrapped, opt;
|
||||
html = html || '';
|
||||
var root$, wrapped, opt;
|
||||
opt = html.opt || (customOpt ? prepareOptTags($.extend(true, baseOpt, customOpt))
|
||||
: defaultOpt);
|
||||
if(!html.opt){
|
||||
|
@ -5,6 +5,7 @@ Gun.chain.open = function(cb, opt, at){
|
||||
opt.doc = opt.doc || {};
|
||||
opt.ids = opt.ids || {};
|
||||
opt.any = opt.any || cb;
|
||||
opt.meta = opt.meta || false;
|
||||
opt.ev = opt.ev || {off: function(){
|
||||
Gun.obj.map(opt.ev.s, function(e){
|
||||
if(e){ e.off() }
|
||||
@ -12,7 +13,9 @@ Gun.chain.open = function(cb, opt, at){
|
||||
opt.ev.s = {};
|
||||
}, s:{}}
|
||||
return this.on(function(data, key, ctx, ev){
|
||||
delete ((data = Gun.obj.copy(data))||{})._;
|
||||
if(opt.meta !== true){
|
||||
delete ((data = Gun.obj.copy(data))||{})._;
|
||||
}
|
||||
clearTimeout(opt.to);
|
||||
opt.to = setTimeout(function(){
|
||||
if(!opt.any){ return }
|
||||
|
@ -11,6 +11,10 @@
|
||||
* Author: Jachen Duschletta / 2019
|
||||
*/
|
||||
|
||||
// Get window or node Gun instance
|
||||
|
||||
var Gun = (typeof window !== "undefined")? window.Gun : require('../gun');
|
||||
|
||||
/*
|
||||
* Function promOnce
|
||||
* @param limit - due to promises resolving too fast if we do not set a timer
|
||||
|
@ -19,7 +19,7 @@
|
||||
function ename(t){ return encodeURIComponent(t).replace(/\*/g, '%2A') }
|
||||
function atomic(v){ return u !== v && (!v || 'object' != typeof v) }
|
||||
var map = Gun.obj.map;
|
||||
var LOG = false;
|
||||
var LOG = console.LOG;
|
||||
|
||||
if(!opt.store){
|
||||
return opt.log("ERROR: Radisk needs `opt.store` interface with `{get: fn, put: fn (, list: fn)}`!");
|
||||
@ -46,7 +46,7 @@
|
||||
cb = val;
|
||||
var S; LOG && (S = +new Date);
|
||||
val = r.batch(key);
|
||||
LOG && console.log(+new Date - S, 'rad mem');
|
||||
LOG && opt.log(S, +new Date - S, 'rad mem');
|
||||
if(u !== val){
|
||||
cb(u, r.range(val, o), o);
|
||||
if(atomic(val)){ return }
|
||||
@ -77,6 +77,7 @@
|
||||
r.thrash = function(){
|
||||
var thrash = r.thrash;
|
||||
if(thrash.ing){ return thrash.more = true }
|
||||
LOG = console.LOG; // dirty place to cheaply update LOG settings over time.
|
||||
thrash.more = false;
|
||||
thrash.ing = true;
|
||||
var batch = thrash.at = r.batch, i = 0;
|
||||
@ -174,9 +175,9 @@
|
||||
}
|
||||
f.write = function(){
|
||||
var tmp = ename(file);
|
||||
var start; LOG && (start = +new Date); // comment this out!
|
||||
var S; LOG && (S = +new Date);
|
||||
opt.store.put(tmp, f.text, function(err){
|
||||
LOG && console.log("wrote to disk in", (+new Date) - start, tmp); // comment this out!
|
||||
LOG && opt.log(S, +new Date - S, "wrote disk", tmp);
|
||||
if(err){ return cb(err) }
|
||||
r.list.add(tmp, cb);
|
||||
});
|
||||
@ -205,10 +206,10 @@
|
||||
|
||||
r.write.jsonify = function(f, file, rad, cb, o){
|
||||
var raw;
|
||||
var start; LOG && (start = +new Date); // comment this out!
|
||||
var S; LOG && (S = +new Date);
|
||||
try{raw = JSON.stringify(rad.$);
|
||||
}catch(e){ return cb("Record too big!") }
|
||||
LOG && console.log("stringified JSON in", +new Date - start); // comment this out!
|
||||
LOG && opt.log(S, +new Date - S, "rad stringified JSON");
|
||||
if(opt.chunk < raw.length && !o.force){
|
||||
if(Radix.map(rad, f.each, true)){ return }
|
||||
}
|
||||
@ -234,7 +235,7 @@
|
||||
if(RAD && !o.next){ // cache
|
||||
var S; LOG && (S = +new Date);
|
||||
var val = RAD(key);
|
||||
LOG && console.log(+new Date - S, 'rad cached');
|
||||
LOG && opt.log(S, +new Date - S, 'rad cached');
|
||||
//if(u !== val){
|
||||
//cb(u, val, o);
|
||||
if(atomic(val)){ cb(u, val, o); return }
|
||||
@ -247,7 +248,7 @@
|
||||
file = (u === file)? u : decodeURIComponent(file);
|
||||
tmp = o.next || key || (o.reverse? o.end || '\uffff' : o.start || '');
|
||||
if(!file || (o.reverse? file < tmp : file > tmp)){
|
||||
LOG && console.log(+new Date - S, 'rad read lex'); S = +new Date;
|
||||
LOG && opt.log(S, +new Date - S, 'rad read lex'); S = +new Date;
|
||||
if(o.next || o.reverse){ g.file = file }
|
||||
if(tmp = Q[g.file]){
|
||||
tmp.push({key: key, ack: cb, file: g.file, opt: o});
|
||||
@ -268,9 +269,9 @@
|
||||
g.info = info;
|
||||
if(disk){ RAD = g.disk = disk }
|
||||
disk = Q[g.file]; delete Q[g.file];
|
||||
LOG && console.log(+new Date - S, 'rad read it in, now ack to:', disk.length); S = +new Date;
|
||||
LOG && opt.log(S, +new Date - S, 'rad read in, ack', disk.length); S = +new Date;
|
||||
map(disk, g.ack);
|
||||
LOG && console.log(+new Date - S, 'rad read acked');
|
||||
LOG && opt.log(S, +new Date - S, 'rad read acked');
|
||||
}
|
||||
g.ack = function(as){
|
||||
if(!as.ack){ return }
|
||||
@ -315,7 +316,7 @@
|
||||
var p = function Parse(){}, info = {};
|
||||
p.disk = Radix();
|
||||
p.read = function(err, data){ var tmp;
|
||||
LOG && console.log('read disk in', +new Date - S, ename(file)); // keep this commented out in
|
||||
LOG && opt.log(S, +new Date - S, 'read disk', ename(file));
|
||||
delete Q[file];
|
||||
if((p.err = err) || (p.not = !data)){
|
||||
return map(q, p.ack);
|
||||
@ -332,12 +333,12 @@
|
||||
}
|
||||
info.parsed = data.length;
|
||||
|
||||
LOG && (S = +new Date); // keep this commented out in production!
|
||||
LOG && (S = +new Date);
|
||||
if(opt.jsonify || '{' === data[0]){ // temporary testing idea
|
||||
try{
|
||||
var json = JSON.parse(data);
|
||||
p.disk.$ = json;
|
||||
LOG && console.log('parsed JSON in', +new Date - S); // keep this commented out in production!
|
||||
LOG && opt.log(S, +new Date - S, 'rad parsed JSON');
|
||||
map(q, p.ack);
|
||||
return;
|
||||
}catch(e){ tmp = e }
|
||||
@ -346,7 +347,7 @@
|
||||
return map(q, p.ack);
|
||||
}
|
||||
}
|
||||
LOG && (S = +new Date); // keep this commented out in production!
|
||||
LOG && (S = +new Date);
|
||||
var tmp = p.split(data), pre = [], i, k, v;
|
||||
if(!tmp || 0 !== tmp[1]){
|
||||
p.err = "File '"+file+"' does not have root radix! ";
|
||||
@ -369,7 +370,7 @@
|
||||
if(u !== k && u !== v){ p.disk(pre.join(''), v) }
|
||||
tmp = p.split(tmp[2]);
|
||||
}
|
||||
LOG && console.log('parsed RAD in', +new Date - S); // keep this commented out in production!
|
||||
LOG && opt.log(S, +new Date - S, 'parsed RAD');
|
||||
//cb(err, p.disk);
|
||||
map(q, p.ack);
|
||||
};
|
||||
@ -389,7 +390,7 @@
|
||||
if(p.err || p.not){ return cb(p.err, u, info) }
|
||||
cb(u, p.disk, info);
|
||||
}
|
||||
var S; LOG && (S = +new Date); // keep this commented out in production!
|
||||
var S; LOG && (S = +new Date);
|
||||
if(raw){ return p.read(null, raw) }
|
||||
opt.store.get(ename(file), p.read);
|
||||
}
|
||||
|
@ -2,10 +2,12 @@
|
||||
var Gun = require('../gun'), u;
|
||||
Gun.serve = require('./serve');
|
||||
//process.env.GUN_ENV = process.env.GUN_ENV || 'debug';
|
||||
//console.LOG = true; // only temporarily, REVERT THIS IN FUTURE!
|
||||
Gun.on('opt', function(root){
|
||||
if(u === root.opt.super){
|
||||
root.opt.super = true;
|
||||
}
|
||||
root.opt.log = root.opt.log || Gun.log;
|
||||
this.to.next(root);
|
||||
})
|
||||
require('../nts');
|
||||
|
13
lib/stats.js
13
lib/stats.js
@ -5,6 +5,7 @@ Gun.on('opt', function(root){
|
||||
if(root.once){ return }
|
||||
if(typeof process === 'undefined'){ return }
|
||||
if(typeof require === 'undefined'){ return }
|
||||
if(false === root.opt.stats){ return }
|
||||
var noop = function(){};
|
||||
var os = require('os') || {};
|
||||
var fs = require('fs') || {};
|
||||
@ -39,6 +40,7 @@ Gun.on('opt', function(root){
|
||||
stats.peers.count = Object.keys(root.opt.peers||{}).length;
|
||||
stats.node = {};
|
||||
stats.node.count = Object.keys(root.graph||{}).length;
|
||||
stats.all = all;
|
||||
var dam = root.opt.mesh;
|
||||
if(dam){
|
||||
stats.dam = {'in': {count: dam.hear.c, done: dam.hear.d, long: dam.hear.long}, 'out': {count: dam.say.c, done: dam.say.d}};
|
||||
@ -57,3 +59,14 @@ Gun.on('opt', function(root){
|
||||
}, 1000 * 15);
|
||||
Object.keys = Object.keys || function(o){ return Gun.obj.map(o, function(v,k,t){t(k)}) }
|
||||
});
|
||||
|
||||
|
||||
var log = Gun.log, all = {}, max = 1000;
|
||||
Gun.log = function(a,b,c,d){
|
||||
if('number' == typeof a && 'number' == typeof b && 'string' == typeof c){
|
||||
var tmp = (all[c] || (all[c] = []));
|
||||
if(max < tmp.push([a,b])){ all[c] = [] } // reset
|
||||
//return;
|
||||
}
|
||||
return log.apply(Gun, arguments);
|
||||
}
|
29
lib/store.js
29
lib/store.js
@ -1,5 +1,5 @@
|
||||
var Gun = (typeof window !== "undefined")? window.Gun : require('../gun');
|
||||
|
||||
|
||||
Gun.on('create', function(root){
|
||||
if(Gun.TESTING){ root.opt.file = 'radatatest' }
|
||||
this.to.next(root);
|
||||
@ -7,6 +7,7 @@ Gun.on('create', function(root){
|
||||
if(false === opt.radisk){ return }
|
||||
var Radisk = (Gun.window && Gun.window.Radisk) || require('./radisk');
|
||||
var Radix = Radisk.Radix;
|
||||
var LOG = console.LOG;
|
||||
|
||||
opt.store = opt.store || (!Gun.window && require('./rfs')(opt));
|
||||
var rad = Radisk(opt), esc = String.fromCharCode(27);
|
||||
@ -30,12 +31,12 @@ Gun.on('create', function(root){
|
||||
val = Radisk.encode(val, null, esc)+'>'+Radisk.encode(Gun.state.is(node, key), null, esc);
|
||||
rad(soul+esc+key, val, (track? ack : u));
|
||||
});
|
||||
//console.log(+new Date - S, 'put loop');
|
||||
LOG && Gun.log(S, +new Date - S, 'put loop');
|
||||
function ack(err, ok){
|
||||
acks--;
|
||||
if(ack.err){ return }
|
||||
if(ack.err = err){
|
||||
try{opt.store.stats.put.err = err}catch(e){} // STATS!
|
||||
//Gun.log(); //try{opt.store.stats.put.err = err}catch(e){} // STATS!
|
||||
root.on('in', {'@': id, err: err});
|
||||
return;
|
||||
}
|
||||
@ -45,7 +46,7 @@ Gun.on('create', function(root){
|
||||
}catch(e){} // STATS!
|
||||
//console.log(+new Date - S, 'put'); S = +new Date;
|
||||
root.on('in', {'@': id, ok: 1});
|
||||
//console.log(+new Date - S, 'put sent');
|
||||
//console.log(S, +new Date - S, 'put sent');
|
||||
}
|
||||
});
|
||||
|
||||
@ -77,10 +78,14 @@ Gun.on('create', function(root){
|
||||
o.limit = (tmp <= (o.pack || (1000 * 100)))? tmp : 1;
|
||||
}
|
||||
if(has['-'] || (soul||{})['-']){ o.reverse = true }
|
||||
if(tmp = (root.next||empty)[soul]){
|
||||
if(tmp && tmp.rad){ return }
|
||||
if(o.atom){ tmp = (tmp.next||empty)[o.atom] }
|
||||
if(tmp && tmp.rad){ return }
|
||||
if((tmp = (root.next||empty)[soul]) && tmp.put){
|
||||
if(o.atom){
|
||||
tmp = (tmp.next||empty)[o.atom] ;
|
||||
if(tmp && tmp.rad){ return }
|
||||
} else
|
||||
if(tmp && tmp.rad){
|
||||
return;
|
||||
}
|
||||
}
|
||||
var S = (+new Date); // STATS!
|
||||
rad(key||'', function(err, data, o){
|
||||
@ -89,7 +94,7 @@ Gun.on('create', function(root){
|
||||
if(err){ opt.store.stats.get.err = err }
|
||||
}catch(e){} // STATS!
|
||||
//if(u === data && o.chunks > 1){ return } // if we already sent a chunk, ignore ending empty responses. // this causes tests to fail.
|
||||
//console.log(+new Date - S, 'got'); S = +new Date;
|
||||
LOG && Gun.log(S, +new Date - S, 'got'); S = +new Date; // MARK RETURN HERE!!!! Gun.log will always log unless off :/ switch to something like LOG && whatever?
|
||||
if(data){
|
||||
if(typeof data !== 'string'){
|
||||
if(o.atom){
|
||||
@ -100,11 +105,10 @@ Gun.on('create', function(root){
|
||||
}
|
||||
if(!graph && data){ each(data, '') }
|
||||
}
|
||||
//console.log(+new Date - S, 'got prep'); S = +new Date;
|
||||
LOG && Gun.log(S, +new Date - S, 'got prep');
|
||||
root.on('in', {'@': id, put: graph, '%': o.more? 1 : u, err: err? err : u, _: each});
|
||||
//console.log(+new Date - S, 'got sent');
|
||||
}, o);
|
||||
//console.log(+new Date - S, 'get call');
|
||||
LOG && Gun.log(S, +new Date - S, 'get call');
|
||||
function each(val, has, a,b){
|
||||
if(!val){ return }
|
||||
has = (key+has).split(esc);
|
||||
@ -118,6 +122,7 @@ Gun.on('create', function(root){
|
||||
if(o.limit && o.limit <= o.count){ return true }
|
||||
}
|
||||
each.rad = get;
|
||||
LOG = console.LOG;
|
||||
});
|
||||
opt.store.stats = {get:{time:{}, count:0}, put: {time:{}, count:0}}; // STATS!
|
||||
var statg = 0, statp = 0; // STATS!
|
||||
|
@ -1,272 +0,0 @@
|
||||
(function(){
|
||||
if(!this.Gun){ return }
|
||||
function Test(o){
|
||||
var test = this;
|
||||
if(!(test instanceof Test)){ return new Test(o) }
|
||||
test._ = {};
|
||||
test._.stack = [];
|
||||
return test;
|
||||
}
|
||||
Test.chain = Test.prototype;
|
||||
Test.chain.run = function(fn){
|
||||
var test = this;
|
||||
var e = test._.i, i = 0;
|
||||
var stack = test._.stack;
|
||||
stack.push(fn);
|
||||
//var to = setInterval(function(){ if(++i >= e){ return clearTimeout(to) }
|
||||
var start = Gun.time.is();
|
||||
while(++i <= e){
|
||||
Gun.list.map(stack, function(fn){ (fn||function(){})(i) })
|
||||
}
|
||||
console.log((Gun.time.is() - start) / 1000);
|
||||
//},0);
|
||||
return test;
|
||||
}
|
||||
Test.chain.it = function(i){
|
||||
var test = this;
|
||||
test._.i = i || 1000;
|
||||
return test;
|
||||
}
|
||||
Test.chain.gen = function(fn){
|
||||
var test = this;
|
||||
test._.stack.push(fn);
|
||||
return test;
|
||||
}
|
||||
var gun = window.gun = Gun();
|
||||
window.SPAM = function(read){ // TODO: BUG? gun-sid in transport layer not correct?
|
||||
//localStorage.clear();
|
||||
var start = Gun.time.is();
|
||||
/*var mark = {
|
||||
name: "Mark Nadal"
|
||||
};
|
||||
var amber = {
|
||||
name: "Amber Nadal",
|
||||
spouse: mark
|
||||
}
|
||||
mark.spouse = amber;
|
||||
amber.pet = {
|
||||
name: "Fluffy",
|
||||
slave: mark
|
||||
}
|
||||
Test().it(read).gen(function(i){
|
||||
Gun.ify(mark);
|
||||
}).run();return;*/
|
||||
Test().it(read).gen(function(i){
|
||||
gun.get('users').path(i).path('where').put({lat: Math.random(), lng: Math.random(),i:i});
|
||||
}).run();return;
|
||||
Test().it(read === true? 1 : read || 1000).gen(function(i){
|
||||
if(read === true){
|
||||
gun.get('users').map().path('where').on(function(node){
|
||||
console.log("node:", node);
|
||||
if(node.i === (1000)){
|
||||
console.log("total:", Gun.time.is() - start);
|
||||
start = Gun.time.is();
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
// PUT, GET, PATH, ON
|
||||
var now = Gun.time.is();
|
||||
/*var obj = {'i': i, 'v': Gun.text.random(100)};
|
||||
gun.put(obj, function(err, ok){
|
||||
//console.log("put done", i, 'in', Gun.time.is() - now);//, i % 1000);
|
||||
if(i % (1000) === 0){
|
||||
console.log("total:", Gun.time.is() - start);
|
||||
start = Gun.time.is();
|
||||
}
|
||||
});return;*/
|
||||
gun.get('users').path(i).path('where').put({
|
||||
lat: Math.random(),lng: Math.random(),i: i
|
||||
//lol: i / 2
|
||||
}, function(err, ok){
|
||||
console.log("put done", i, 'in', Gun.time.is() - now);//, i % 1000);
|
||||
if(i % (1000) === 0){
|
||||
console.log("total:", Gun.time.is() - start);
|
||||
start = Gun.time.is();
|
||||
}
|
||||
});return;
|
||||
}).run(function(){});
|
||||
}
|
||||
//window.SPAM(1000000);
|
||||
}());
|
||||
/* EXTRA GUN UTILITY FUNCTIONS I MIGHT WANT TO KEEP
|
||||
(function(){
|
||||
Gun().get('chat').path('messages').since(Gun().get('me').path('last')).map().val(function(msg){
|
||||
|
||||
});
|
||||
Gun().get('chat').path('messages').last(100).map().val(function(msg){
|
||||
});
|
||||
|
||||
var peers = [
|
||||
peer1,
|
||||
peer2
|
||||
];
|
||||
|
||||
Gun.on('put').event(function(graph, cb, opt){
|
||||
Gun.is.graph(graph, function(node, soul){
|
||||
localStorage[soul] = node;
|
||||
});
|
||||
});
|
||||
Gun.on('put').event(function(graph, cb, opt){
|
||||
Peers(opt.peers).send({
|
||||
id: MsgID,
|
||||
value: data,
|
||||
from: myPeerID
|
||||
}, cb);
|
||||
});
|
||||
|
||||
Gun.on('get').event(function(lex, cb, opt){
|
||||
Peers(opt.peers || peers).send({
|
||||
'#': MsgID,
|
||||
'$': lex,
|
||||
'~': myPeerID
|
||||
}, cb);
|
||||
});
|
||||
|
||||
Peers.server(function(req, res){
|
||||
if(Msg.IDs[req.id]){ return } // throttle
|
||||
// auth
|
||||
Peers(peers).send(req); // relay
|
||||
// auth
|
||||
if(req.rid){ return } // ignore
|
||||
if(req.put && opt.everything || graph[for soul in req.body]){ // process
|
||||
Gun.put(gun, req.body, REPLY);
|
||||
}
|
||||
});
|
||||
|
||||
// TODO: MARK / JESSE need to solve infinite circular loop on get flushing and put flushing.
|
||||
|
||||
GUN = {'#': 'soul', '.': 'field', '=': 'value', '>': 'state'}
|
||||
MSG = {'#': 'id', '$': 'body', '@': 'to'}
|
||||
|
||||
Gun.wire = function(data){
|
||||
|
||||
}
|
||||
Gun.get.wire = function(lex, cb, opt){ return Gun.text.is(lex)? Gun.get.wire.from(lex, cb, opt) : Gun.get.wire.to(lex, cb, opt) }
|
||||
Gun.get.wire.to = function(lex, cb, opt){
|
||||
var t = '';
|
||||
Gun.obj.map(lex, function(v,f){
|
||||
if(!v){ return }
|
||||
Gun.list.map(Gun.list.is(v)? v : [v], function(v){
|
||||
t += f + "'" + Gun.put.wire.ify(v) + "'";
|
||||
});
|
||||
});
|
||||
return t + '?';
|
||||
}
|
||||
Gun.get.wire.from = function(t, cb, opt){
|
||||
if(!t){ return null }
|
||||
var a = Gun.put.wire.from.parse(t), lex = {};
|
||||
Gun.list.map([Gun._.soul, Gun._.field, Gun._.value, Gun._.state], function(sym, i){
|
||||
if(!(i = a.indexOf(sym) + 1)){ return }
|
||||
lex[sym] = Gun.put.wire.type(a[i]);
|
||||
});
|
||||
return lex;
|
||||
}
|
||||
// #soul.field
|
||||
// "#soul.field=value>state"
|
||||
// #messages>>1234567890 //{soul: 'messages', state: {'>': 1234567890}}
|
||||
// #id$"msg"~who@to
|
||||
|
||||
Gun.put.wire = function(n, cb, opt){ return Gun.text.is(n)? Gun.put.wire.from(n, cb, opt) : Gun.put.wire.to(n, cb, opt) }
|
||||
Gun.put.wire.ify = function(s){ var tmp;
|
||||
if(Infinity === s || -Infinity === s){ return s }
|
||||
if(tmp = Gun.is.rel(s)){ return '#' + JSON.stringify(tmp) }
|
||||
return JSON.stringify(s)
|
||||
}
|
||||
Gun.put.wire.type = function(s){ var tmp;
|
||||
if(Gun._.soul === s.charAt(0)){ return Gun.is.rel.ify(JSON.parse(s.slice(1))) }
|
||||
if(String(Infinity) === s){ return Infinity }
|
||||
if(String(-Infinity) === s){ return -Infinity }
|
||||
return JSON.parse(s)
|
||||
}
|
||||
Gun.put.wire.to = function(n, cb, opt){ var t, b;
|
||||
if(!n || !(t = Gun.is.node.soul(n))){ return null }
|
||||
cb = cb || function(){};
|
||||
t = (b = "#'" + Gun.put.wire.ify(t) + "'");
|
||||
var val = function(v,f, nv,nf){
|
||||
var w = '', s = Gun.is.node.state(n,f), sw = '';
|
||||
if(!s){ return }
|
||||
w += ".'" + Gun.put.wire.ify(f) + "'";
|
||||
console.log("yeah value?", v, Gun.put.wire.ify(v));
|
||||
w += "='" + Gun.put.wire.ify(v) + "'";
|
||||
if(s !== Gun.is.node.state(n,nf)){
|
||||
w += ">'" + Gun.put.wire.ify(s) + "'";
|
||||
} else {
|
||||
sw = ">'" + Gun.put.wire.ify(s) + "'";
|
||||
}
|
||||
t += w;
|
||||
w = b + w + sw;
|
||||
cb(null, w);
|
||||
}
|
||||
var next = function(v,f){ // TODO: BUG! Missing adding meta data.
|
||||
if(Gun._.meta === f){ return }
|
||||
if(next.f){
|
||||
val(next.v, next.f, v,f);
|
||||
}
|
||||
next.f = f;
|
||||
next.v = v;
|
||||
}
|
||||
Gun.obj.map(n, next);
|
||||
next();
|
||||
return t;
|
||||
}
|
||||
Gun.put.wire.from = function(t, cb, opt){
|
||||
if(!t){ return null }
|
||||
var a = Gun.put.wire.from.parse(t);
|
||||
Gun.list.map(a, function(v, i){
|
||||
if(Gun._.soul === v){
|
||||
Gun.is.node.soul.ify(n, Gun.put.wire.type(a[i]));
|
||||
return;
|
||||
}
|
||||
if(Gun._.field === v){
|
||||
var val = a.indexOf(Gun._.value,i), state = a.indexOf(Gun._.state,i);
|
||||
Gun.is.node.state.ify([n], Gun.put.wire.type(a[i]), Gun.put.wire.type(a[val+1]), Gun.put.wire.type(a[state+1]));
|
||||
return;
|
||||
}
|
||||
})
|
||||
return n;
|
||||
}
|
||||
Gun.put.wire.from.parse = function(t){
|
||||
var a = [], s = -1, e = 0, end = 1, n = {};
|
||||
while((e = t.indexOf("'", s + 1)) >= 0){
|
||||
if(s === e || '\\' === t.charAt(e-1)){}else{
|
||||
a.push(t.slice(s + 1,e));
|
||||
s = e;
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
}());
|
||||
*/
|
||||
|
||||
;(function(){ // make as separate module!
|
||||
function SQL(){}
|
||||
SQL.select = function(sel){
|
||||
this._.sql.select = sel;
|
||||
return this;
|
||||
}
|
||||
SQL.from = function(from){
|
||||
this._.sql.from = from;
|
||||
//this.get(from).map();
|
||||
return this;
|
||||
}
|
||||
SQL.where = function(where){
|
||||
this._.sql.where = where;
|
||||
return this;
|
||||
}
|
||||
Gun.chain.sql = function(sql){
|
||||
var gun = this;//.chain();
|
||||
sql = gun._.sql = sql || {};
|
||||
gun.select = SQL.select;
|
||||
gun.from = SQL.from;
|
||||
gun.where = SQL.where;
|
||||
return gun;
|
||||
}
|
||||
|
||||
Gun.on('chain').event(function(gun, at){
|
||||
console.log("sql stuff?", gun._, at.node);
|
||||
var query = gun._.sql;
|
||||
if(!query){ return }
|
||||
var node = at.node;
|
||||
});
|
||||
}());
|
1242
lib/wave.js
Normal file
1242
lib/wave.js
Normal file
File diff suppressed because it is too large
Load Diff
13
package-lock.json
generated
13
package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "gun",
|
||||
"version": "0.2019.915",
|
||||
"version": "0.2019.1211",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@ -40,7 +40,8 @@
|
||||
"@types/node": {
|
||||
"version": "10.14.18",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.18.tgz",
|
||||
"integrity": "sha512-ryO3Q3++yZC/+b8j8BdKd/dn9JlzlHBPdm80656xwYUdmPkpTGTjkAdt6BByiNupGPE8w0FhBgvYy/fX9hRNGQ=="
|
||||
"integrity": "sha512-ryO3Q3++yZC/+b8j8BdKd/dn9JlzlHBPdm80656xwYUdmPkpTGTjkAdt6BByiNupGPE8w0FhBgvYy/fX9hRNGQ==",
|
||||
"optional": true
|
||||
},
|
||||
"@unimodules/core": {
|
||||
"version": "3.0.2",
|
||||
@ -120,6 +121,7 @@
|
||||
"version": "2.0.26",
|
||||
"resolved": "https://registry.npmjs.org/asn1js/-/asn1js-2.0.26.tgz",
|
||||
"integrity": "sha512-yG89F0j9B4B0MKIcFyWWxnpZPLaNTjCj4tkE3fjbAoo0qmpGw0PYYqSbX/4ebnd9Icn8ZgK4K1fvDyEtW1JYtQ==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"pvutils": "^1.0.17"
|
||||
}
|
||||
@ -1347,6 +1349,7 @@
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.0.6.tgz",
|
||||
"integrity": "sha512-0yNrOdJyLE7FZzmeEHTKanwBr5XbmDAd020cKa4ZiTYuGMBYBZmq7vHOhcOqhVllh6gghDBbaz1lnVdOqiB7cw==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"@types/node": "^10.14.17",
|
||||
"tslib": "^1.10.0"
|
||||
@ -1355,7 +1358,8 @@
|
||||
"pvutils": {
|
||||
"version": "1.0.17",
|
||||
"resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.0.17.tgz",
|
||||
"integrity": "sha512-wLHYUQxWaXVQvKnwIDWFVKDJku9XDCvyhhxoq8dc5MFdIlRenyPI9eSfEtcvgHgD7FlvCyGAlWgOzRnZD99GZQ=="
|
||||
"integrity": "sha512-wLHYUQxWaXVQvKnwIDWFVKDJku9XDCvyhhxoq8dc5MFdIlRenyPI9eSfEtcvgHgD7FlvCyGAlWgOzRnZD99GZQ==",
|
||||
"optional": true
|
||||
},
|
||||
"querystring": {
|
||||
"version": "0.2.0",
|
||||
@ -1664,7 +1668,8 @@
|
||||
"tslib": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
|
||||
"integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ=="
|
||||
"integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==",
|
||||
"optional": true
|
||||
},
|
||||
"uglify-js": {
|
||||
"version": "3.6.0",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "gun",
|
||||
"version": "0.2019.930",
|
||||
"version": "0.2019.1228",
|
||||
"description": "A realtime, decentralized, offline-first, graph data synchronization engine.",
|
||||
"main": "index.js",
|
||||
"browser": "browser.js",
|
||||
@ -16,7 +16,8 @@
|
||||
"e2e": "mocha e2e/distributed.js",
|
||||
"docker": "hooks/build",
|
||||
"minify": "uglifyjs gun.js -o gun.min.js -c -m",
|
||||
"unbuild": "node lib/unbuild.js & npm run minify"
|
||||
"unbuild": "node lib/unbuild.js & npm run minify",
|
||||
"unbuildMeta": "node lib/unbuild.js lib/meta"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
21
sea.js
21
sea.js
@ -191,8 +191,8 @@
|
||||
const isocrypto = require('isomorphic-webcrypto');
|
||||
api.ossl = api.subtle = isocrypto.subtle;
|
||||
}catch(e){
|
||||
console.log("node-webcrypto-ossl and text-encoding may not be included by default, please add it to your package.json!");
|
||||
OSSL_WEBCRYPTO_OR_TEXT_ENCODING_NOT_INSTALLED;
|
||||
console.log("text-encoding and @peculiar/webcrypto may not be included by default, please add it to your package.json!");
|
||||
TEXT_ENCODING_OR_PECULIAR_WEBCRYPTO_NOT_INSTALLED;
|
||||
}}
|
||||
|
||||
module.exports = api
|
||||
@ -978,6 +978,7 @@
|
||||
}
|
||||
// If authenticated user wants to delete his/her account, let's support it!
|
||||
User.prototype.delete = async function(alias, pass, cb){
|
||||
console.log("user.delete() IS DEPRECATED AND WILL BE MOVED TO A MODULE!!!");
|
||||
var gun = this, root = gun.back(-1), user = gun.back('user');
|
||||
try {
|
||||
user.auth(alias, pass, function(ack){
|
||||
@ -1019,6 +1020,7 @@
|
||||
return gun;
|
||||
}
|
||||
User.prototype.alive = async function(){
|
||||
console.log("user.alive() IS DEPRECATED!!!");
|
||||
const gunRoot = this.back(-1)
|
||||
try {
|
||||
// All is good. Should we do something more with actual recalled data?
|
||||
@ -1038,25 +1040,32 @@
|
||||
console.log(ctx, ev)
|
||||
})
|
||||
}
|
||||
user.get('trust').get(path).put(theirPubkey);
|
||||
|
||||
// do a lookup on this gun chain directly (that gets bob's copy of the data)
|
||||
// do a lookup on the metadata trust table for this path (that gets all the pubkeys allowed to write on this path)
|
||||
// do a lookup on each of those pubKeys ON the path (to get the collab data "layers")
|
||||
// THEN you perform Jachen's mix operation
|
||||
// and return the result of that to...
|
||||
}
|
||||
User.prototype.grant = function(to, cb){
|
||||
console.log("`.grant` API MAY BE DELETED OR CHANGED OR RENAMED, DO NOT USE!");
|
||||
var gun = this, user = gun.back(-1).user(), pair = user.pair(), path = '';
|
||||
var gun = this, user = gun.back(-1).user(), pair = user._.sea, path = '';
|
||||
gun.back(function(at){ if(at.is){ return } path += (at.get||'') });
|
||||
(async function(){
|
||||
var enc, sec = await user.get('trust').get(pair.pub).get(path).then();
|
||||
var enc, sec = await user.get('grant').get(pair.pub).get(path).then();
|
||||
sec = await SEA.decrypt(sec, pair);
|
||||
if(!sec){
|
||||
sec = SEA.random(16).toString();
|
||||
enc = await SEA.encrypt(sec, pair);
|
||||
user.get('trust').get(pair.pub).get(path).put(enc);
|
||||
user.get('grant').get(pair.pub).get(path).put(enc);
|
||||
}
|
||||
var pub = to.get('pub').then();
|
||||
var epub = to.get('epub').then();
|
||||
pub = await pub; epub = await epub;
|
||||
var dh = await SEA.secret(epub, pair);
|
||||
enc = await SEA.encrypt(sec, dh);
|
||||
user.get('trust').get(pub).get(path).put(enc, cb);
|
||||
user.get('grant').get(pub).get(path).put(enc, cb);
|
||||
}());
|
||||
return gun;
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ if(typeof Gun === 'undefined'){ return } // TODO: localStorage is Browser only.
|
||||
var root, noop = function(){}, store, u;
|
||||
try{store = (Gun.window||noop).localStorage}catch(e){}
|
||||
if(!store){
|
||||
console.log("Warning: No localStorage exists to persist data to!");
|
||||
Gun.log("Warning: No localStorage exists to persist data to!");
|
||||
store = {setItem: function(k,v){this[k]=v}, removeItem: function(k){delete this[k]}, getItem: function(k){return this[k]}};
|
||||
}
|
||||
/*
|
||||
@ -110,7 +110,6 @@ Gun.on('create', function(root){
|
||||
data = Gun.state.to(data, has);
|
||||
}
|
||||
//if(!data && !Gun.obj.empty(opt.peers)){ return } // if data not found, don't ack if there are peers. // Hmm, what if we have peers but we are disconnected?
|
||||
//console.log("lS get", lex, data);
|
||||
root.on('in', {'@': msg['#'], put: Gun.graph.node(data), how: 'lS', lS: msg.$});// || root.$});
|
||||
};
|
||||
Gun.debug? setTimeout(to,1) : to();
|
||||
|
@ -19,15 +19,14 @@ function Mesh(root){
|
||||
if('[' === tmp){
|
||||
try{msg = JSON.parse(raw);}catch(e){opt.log('DAM JSON parse error', e)}
|
||||
if(!msg){ return }
|
||||
//console.log('hear batch length of', msg.length);
|
||||
LOG && opt.log(+new Date, msg.length, 'in hear batch');
|
||||
(function go(){
|
||||
var S = +new Date; // STATS!
|
||||
var S; LOG && (S = +new Date); // STATS!
|
||||
var m, c = 100; // hardcoded for now?
|
||||
while(c-- && (m = msg.shift())){
|
||||
mesh.hear(m, peer);
|
||||
}
|
||||
//console.log(+new Date - S, 'hear batch');
|
||||
(mesh.hear.long || (mesh.hear.long = [])).push(+new Date - S);
|
||||
LOG && opt.log(S, +new Date - S, 'batch heard');
|
||||
if(!msg.length){ return }
|
||||
puff(go, 0);
|
||||
}());
|
||||
@ -38,7 +37,7 @@ function Mesh(root){
|
||||
}catch(e){return opt.log('DAM JSON parse error', e)}
|
||||
if(!msg){ return }
|
||||
if(!(id = msg['#'])){ id = msg['#'] = Type.text.random(9) }
|
||||
if(msg.DBG_s){ console.log(+new Date - msg.DBG_s, 'to hear', id) }
|
||||
if(msg.DBG_s){ opt.log(+new Date - msg.DBG_s, 'to hear', id) }
|
||||
if(dup.check(id)){ return }
|
||||
dup.track(id, true).it = msg; // GUN core also dedups, so `true` is needed. // Does GUN core need to dedup anymore?
|
||||
if(!(hash = msg['##']) && u !== msg.put){ hash = msg['##'] = Type.obj.hash(msg.put) }
|
||||
@ -54,9 +53,9 @@ function Mesh(root){
|
||||
}
|
||||
return;
|
||||
}
|
||||
//var S = +new Date;
|
||||
var S; LOG && (S = +new Date);
|
||||
root.on('in', msg);
|
||||
//!msg.nts && console.log(+new Date - S, 'msg', msg['#']);
|
||||
LOG && !msg.nts && opt.log(S, +new Date - S, 'msg', msg['#']);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -70,7 +69,7 @@ function Mesh(root){
|
||||
if(this.to){ this.to.next(msg) } // compatible with middleware adapters.
|
||||
if(!msg){ return false }
|
||||
var id, hash, tmp, raw;
|
||||
//var S = +new Date; //msg.DBG_s = msg.DBG_s || +new Date;
|
||||
var S; LOG && (S = +new Date); //msg.DBG_s = msg.DBG_s || +new Date;
|
||||
var meta = msg._||(msg._=function(){});
|
||||
if(!(id = msg['#'])){ id = msg['#'] = Type.text.random(9) }
|
||||
if(!(hash = msg['##']) && u !== msg.put){ hash = msg['##'] = Type.obj.hash(msg.put) }
|
||||
@ -84,15 +83,15 @@ function Mesh(root){
|
||||
}
|
||||
}
|
||||
}
|
||||
//console.log(+new Date - S, 'mesh say prep');
|
||||
LOG && opt.log(S, +new Date - S, 'say prep');
|
||||
dup.track(id).it = msg; // track for 9 seconds, default. Earth<->Mars would need more!
|
||||
if(!peer){ peer = (tmp = dup.s[msg['@']]) && (tmp = tmp.it) && (tmp = tmp._) && (tmp = tmp.via) }
|
||||
if(!peer && mesh.way){ return mesh.way(msg) }
|
||||
if(!peer || !peer.id){ message = msg;
|
||||
if(!Type.obj.is(peer || opt.peers)){ return false }
|
||||
//var S = +new Date;
|
||||
var S; LOG && (S = +new Date);
|
||||
Type.obj.map(peer || opt.peers, each); // in case peer is a peer list.
|
||||
//console.log(+new Date - S, 'mesh say loop');
|
||||
LOG && opt.log(S, +new Date - S, 'say loop');
|
||||
return;
|
||||
}
|
||||
if(!peer.wire && mesh.wire){ mesh.wire(peer) }
|
||||
@ -116,10 +115,10 @@ function Mesh(root){
|
||||
peer.batch = peer.tail = null;
|
||||
if(!tmp){ return }
|
||||
if(!tmp.length){ return } // if(3 > tmp.length){ return } // TODO: ^
|
||||
//var S = +new Date;
|
||||
var S; LOG && (S = +new Date);
|
||||
try{tmp = (1 === tmp.length? tmp[0] : JSON.stringify(tmp));
|
||||
}catch(e){return opt.log('DAM JSON stringify error', e)}
|
||||
//console.log(+new Date - S, 'mesh flush', tmp.length);
|
||||
LOG && opt.log(S, +new Date - S, 'say stringify', tmp.length);
|
||||
if(!tmp){ return }
|
||||
send(tmp, peer);
|
||||
}
|
||||
@ -129,14 +128,14 @@ function Mesh(root){
|
||||
// for now - find better place later.
|
||||
function send(raw, peer){ try{
|
||||
var wire = peer.wire;
|
||||
//var S = +new Date;
|
||||
var S; LOG && (S = +new Date);
|
||||
if(peer.say){
|
||||
peer.say(raw);
|
||||
} else
|
||||
if(wire.send){
|
||||
wire.send(raw);
|
||||
}
|
||||
//console.log(+new Date - S, 'wire send', raw.length);
|
||||
LOG && opt.log(S, +new Date - S, 'wire send', raw.length);
|
||||
mesh.say.d += raw.length||0; ++mesh.say.c; // STATS!
|
||||
}catch(e){
|
||||
(peer.queue = peer.queue || []).push(raw);
|
||||
@ -172,7 +171,8 @@ function Mesh(root){
|
||||
opt.peers[peer.url || peer.id] = peer;
|
||||
} else {
|
||||
tmp = peer.id = peer.id || Type.text.random(9);
|
||||
mesh.say({dam: '?'}, opt.peers[tmp] = peer);
|
||||
mesh.say({dam: '?', pid: root.opt.pid}, opt.peers[tmp] = peer);
|
||||
delete dup.s[peer.last]; // IMPORTANT: see https://gun.eco/docs/DAM#self
|
||||
}
|
||||
peer.met = peer.met || +(new Date);
|
||||
if(!tmp.hied){ root.on(tmp.hied = 'hi', peer) }
|
||||
@ -186,21 +186,16 @@ function Mesh(root){
|
||||
root.on('bye', peer);
|
||||
var tmp = +(new Date); tmp = (tmp - (peer.met||tmp));
|
||||
mesh.bye.time = ((mesh.bye.time || tmp) + tmp) / 2;
|
||||
LOG = console.LOG; // dirty place to cheaply update LOG settings over time.
|
||||
}
|
||||
mesh.hear['!'] = function(msg, peer){ opt.log('Error:', msg.err) }
|
||||
mesh.hear['?'] = function(msg, peer){
|
||||
if(!msg.pid){
|
||||
mesh.say({dam: '?', pid: opt.pid, '@': msg['#']}, peer);
|
||||
// @rogowski I want to re-enable this AXE logic with some fix/merge later.
|
||||
/* var tmp = peer.queue; peer.queue = [];
|
||||
Type.obj.map(tmp, function(msg){
|
||||
mesh.say(msg, peer);
|
||||
}); */
|
||||
// @rogowski 2: I think with my PID fix we can delete this and use the original.
|
||||
return;
|
||||
if(msg.pid){
|
||||
if(!peer.pid){ peer.pid = msg.pid }
|
||||
if(msg['@']){ return }
|
||||
}
|
||||
if(peer.pid){ return }
|
||||
peer.pid = msg.pid;
|
||||
mesh.say({dam: '?', pid: opt.pid, '@': msg['#']}, peer);
|
||||
delete dup.s[peer.last]; // IMPORTANT: see https://gun.eco/docs/DAM#self
|
||||
}
|
||||
|
||||
root.on('create', function(root){
|
||||
@ -266,6 +261,7 @@ function Mesh(root){
|
||||
}());
|
||||
|
||||
var empty = {}, ok = true, u;
|
||||
var LOG = console.LOG;
|
||||
|
||||
try{ module.exports = Mesh }catch(e){}
|
||||
|
||||
|
@ -34,7 +34,7 @@ function output(msg){
|
||||
if(obj_has(back, 'put')){
|
||||
back.on('in', back);
|
||||
}
|
||||
if(tmp){ return }
|
||||
if(tmp && u !== back.put){ return } //if(tmp){ return }
|
||||
msg.$ = back.$;
|
||||
} else
|
||||
if(obj_has(back.put, get)){ // TODO: support #LEX !
|
||||
@ -247,7 +247,7 @@ function not(at, msg){
|
||||
if(u === tmp && u !== at.put){ return true }
|
||||
neat.put = u;
|
||||
if(neat.ack){
|
||||
neat.ack = -1; // TODO: BUG? Should this be 0?
|
||||
neat.ack = -1; // Shouldn't this be reset to 0? If we do that, SEA test `set user ref should be found` fails, odd.
|
||||
}
|
||||
neat.on('in', {
|
||||
get: key,
|
||||
|
@ -89,7 +89,6 @@ function soul(gun, cb, opt, as){
|
||||
function use(msg){
|
||||
var eve = this, as = eve.as, cat = as.at, root = cat.root, gun = msg.$, at = (gun||{})._ || {}, data = msg.put || at.put, tmp;
|
||||
if((tmp = root.now) && eve !== tmp[as.now]){ return eve.to.next(msg) }
|
||||
//console.log("USE:", cat.id, cat.soul, cat.has, cat.get, msg, root.mum);
|
||||
//if(at.async && msg.root){ return }
|
||||
//if(at.async === 1 && cat.async !== true){ return }
|
||||
//if(root.stop && root.stop[at.id]){ return } root.stop && (root.stop[at.id] = true);
|
||||
|
@ -177,7 +177,7 @@ function any(soul, as, msg, eve){
|
||||
as = as.as;
|
||||
if(!msg.$ || !msg.$._){ return } // TODO: Handle
|
||||
if(msg.err){ // TODO: Handle
|
||||
console.log("Please report this as an issue! Put.any.err");
|
||||
Gun.log("Please report this as an issue! Put.any.err");
|
||||
return;
|
||||
}
|
||||
var at = (msg.$._), data = at.put, opt = as.opt||{}, root, tmp;
|
||||
@ -186,7 +186,7 @@ function any(soul, as, msg, eve){
|
||||
if(as.ref !== as.$){
|
||||
tmp = (as.$._).get || at.get;
|
||||
if(!tmp){ // TODO: Handle
|
||||
console.log("Please report this as an issue! Put.no.get"); // TODO: BUG!??
|
||||
Gun.log("Please report this as an issue! Put.no.get"); // TODO: BUG!??
|
||||
return;
|
||||
}
|
||||
as.data = obj_put({}, tmp, as.data);
|
||||
|
@ -162,20 +162,16 @@ Gun.dup = require('./dup');
|
||||
// Maybe... in case the in-memory key we have is a local write
|
||||
// we still need to trigger a pull/merge from peers.
|
||||
} else {
|
||||
//var S = +new Date;
|
||||
node = Gun.obj.copy(node);
|
||||
//console.log(+new Date - S, 'copy node');
|
||||
}
|
||||
node = Gun.graph.node(node);
|
||||
tmp = (at||empty).ack;
|
||||
//var S = +new Date;
|
||||
root.on('in', {
|
||||
'@': msg['#'],
|
||||
how: 'mem',
|
||||
put: node,
|
||||
$: gun
|
||||
});
|
||||
//console.log(+new Date - S, 'root got send');
|
||||
//if(0 < tmp){ return }
|
||||
root.on('get', msg);
|
||||
}
|
||||
|
@ -3774,6 +3774,24 @@ describe('Gun', function(){
|
||||
done();
|
||||
})
|
||||
});
|
||||
|
||||
/*describe('talk to live server tests', function(){
|
||||
this.timeout(1000 * 9);
|
||||
it.only('Second once on undefined should call', function(done){ // this test is passing when it fails by hand?
|
||||
var gun = Gun('https://gunjs.herokuapp.com/gun');
|
||||
gun.get('~@O8H2BJa4pNfecWamWN7efd888Pg1@hackernoon').once(function(data){
|
||||
console.log(1, data);
|
||||
expect(data).to.not.be.ok();
|
||||
setTimeout(function(){
|
||||
gun.get('~@O8H2BJa4pNfecWamWN7efd888Pg1@hackernoon').once(function(data){
|
||||
console.log(2, data);
|
||||
expect(data).to.not.be.ok();
|
||||
done();
|
||||
});
|
||||
}, 3000);
|
||||
});
|
||||
});
|
||||
});*/
|
||||
return;
|
||||
it('Nested listener should be called', function(done){
|
||||
|
||||
|
191
test/panic/4dht.js
Normal file
191
test/panic/4dht.js
Normal file
@ -0,0 +1,191 @@
|
||||
/*
|
||||
This is the first in a series of basic networking correctness tests.
|
||||
Each test itself might be dumb and simple, but built up together,
|
||||
they prove desired end goals for behavior at scale.
|
||||
|
||||
Alice: [Bob]
|
||||
Bob: [Carl]
|
||||
Carl: [Bob]
|
||||
Dave: [Carl]
|
||||
|
||||
Ed: [?]
|
||||
|
||||
100,000 browsers
|
||||
1 relay peer
|
||||
|
||||
50,000 browsers on Bob
|
||||
50,000 browsers on Carl
|
||||
|
||||
//var gun = Gun(['https://gunjs.herokuapp.com/gun', 'https://guntest.herokuapp.com/gun']);
|
||||
|
||||
pretend we have 3TB of data.
|
||||
300K browsers.
|
||||
|
||||
suppose we have 3 nodejs peers that are shards
|
||||
|
||||
var superpeer1 = Gun(AXE({shard: 'a~m'}));
|
||||
var superpeer2 = Gun(AXE({shard: 'n~r'}));
|
||||
var superpeer3 = Gun(AXE({shard: 's~z'}));
|
||||
|
||||
300K browsers join a popular app and they have to do this
|
||||
via the browser, so they all go to superpeer1.com
|
||||
then 2/3 of them should get sharded to superpeer2 & superpeer3
|
||||
|
||||
first all connect to:
|
||||
..s1-----s2--s3
|
||||
./\.\.
|
||||
b1.b2.b3
|
||||
|
||||
then be load balanced to:
|
||||
..s1--s2--s3
|
||||
./....|....\.
|
||||
b1....b2....b3
|
||||
*/
|
||||
|
||||
var config = {
|
||||
IP: require('ip').address(),
|
||||
port: 8765,
|
||||
servers: 3,
|
||||
browsers: 3,
|
||||
route: {
|
||||
'/': __dirname + '/index.html',
|
||||
'/gun.js': __dirname + '/../../gun.js',
|
||||
'/jquery.js': __dirname + '/../../examples/jquery.js'
|
||||
}
|
||||
}
|
||||
|
||||
var panic = require('panic-server');
|
||||
panic.server().on('request', function(req, res){
|
||||
config.route[req.url] && require('fs').createReadStream(config.route[req.url]).pipe(res);
|
||||
}).listen(config.port);
|
||||
|
||||
var clients = panic.clients;
|
||||
var manager = require('panic-manager')();
|
||||
|
||||
manager.start({
|
||||
clients: Array(config.servers).fill().map(function(u, i){
|
||||
return {
|
||||
type: 'node',
|
||||
port: config.port + (i + 1)
|
||||
}
|
||||
}),
|
||||
panic: 'http://' + config.IP + ':' + config.port
|
||||
});
|
||||
|
||||
var servers = clients.filter('Node.js');
|
||||
var s1 = servers.pluck(1);
|
||||
var s2 = servers.excluding(s1).pluck(1);
|
||||
var s3 = servers.excluding([s1,s2]).pluck(1);
|
||||
|
||||
var browsers = clients.excluding(servers);
|
||||
var b1 = browsers.pluck(1);
|
||||
var b2 = servers.excluding(b1).pluck(1);
|
||||
var b3 = servers.excluding([b1,b2]).pluck(1);
|
||||
|
||||
|
||||
describe("Put ACK", function(){
|
||||
//this.timeout(5 * 60 * 1000);
|
||||
this.timeout(10 * 60 * 1000);
|
||||
|
||||
it("Servers have joined!", function(){
|
||||
return servers.atLeast(config.servers);
|
||||
});
|
||||
|
||||
it("GUN started!", function(){
|
||||
var tests = [], i = 0;
|
||||
servers.each(function(client){
|
||||
tests.push(client.run(function(test){
|
||||
var env = test.props;
|
||||
test.async();
|
||||
try{ require('fs').unlinkSync(env.i+'data') }catch(e){}
|
||||
try{ require('gun/lib/fsrm')(env.i+'data') }catch(e){}
|
||||
var server = require('http').createServer(function(req, res){
|
||||
res.end("I am "+ env.i +"!");
|
||||
});
|
||||
var port = env.config.port + env.i;
|
||||
var Gun = require('gun');
|
||||
var peers = [], i = env.config.servers;
|
||||
while(i--){
|
||||
var tmp = (env.config.port + (i + 1));
|
||||
//if(port != tmp){ // ignore ourselves
|
||||
peers.push('http://'+ env.config.IP + ':' + tmp + '/gun');
|
||||
//}
|
||||
}
|
||||
console.log(port, " connect to ", peers);
|
||||
var gun = Gun({file: env.i+'data', peers: peers, web: server, mob: 4});
|
||||
global.gun = gun;
|
||||
server.listen(port, function(){
|
||||
test.done();
|
||||
});
|
||||
}, {i: i += 1, config: config}));
|
||||
});
|
||||
return Promise.all(tests);
|
||||
});
|
||||
|
||||
it(config.browsers +" browser(s) have joined!", function(){
|
||||
console.log("PLEASE OPEN http://"+ config.IP +":"+ config.port +" IN "+ config.browsers +" BROWSER(S)!");
|
||||
return browsers.atLeast(config.browsers);
|
||||
});
|
||||
|
||||
it("Browsers initialized gun!", function(){
|
||||
var tests = [], i = 0;
|
||||
browsers.each(function(browser, id){
|
||||
tests.push(browser.run(function(test){
|
||||
try{ localStorage.clear() }catch(e){}
|
||||
try{ indexedDB.deleteDatabase('radata') }catch(e){}
|
||||
var env = test.props;
|
||||
var gun = Gun('http://'+ env.config.IP + ':' + (env.config.port + 1) + '/gun');
|
||||
|
||||
var mesh = gun.back('opt.mesh');
|
||||
mesh.hear['mob'] = function(msg, peer){
|
||||
// TODO: NOTE, code AXE DHT to aggressively drop new peers AFTER superpeer sends this rebalance/disconnect message that contains some other superpeers.
|
||||
if(!msg.peers){ return }
|
||||
var one = msg.peers[Math.floor(Math.random()*msg.peers.length)];
|
||||
console.log("CONNECT TO THIS PEER:", one);
|
||||
gun.opt(one);
|
||||
mesh.bye(peer);
|
||||
|
||||
if(test.c){ return }
|
||||
test.c = 1;
|
||||
test.done();
|
||||
}
|
||||
|
||||
console.log("connected to who superpeer(s)?", gun._.opt.peers);
|
||||
window.gun = gun;
|
||||
window.ref = gun.get('test');
|
||||
}, {i: i += 1, config: config}));
|
||||
});
|
||||
return Promise.all(tests);
|
||||
});
|
||||
|
||||
it("Got Load Balanced to Different Peer", function(){
|
||||
var tests = [], i = 0;
|
||||
browsers.each(function(browser, id){
|
||||
tests.push(browser.run(function(test){
|
||||
|
||||
console.log("...", gun._.opt.peers);
|
||||
|
||||
}, {i: i += 1, config: config}));
|
||||
});
|
||||
return Promise.all(tests);
|
||||
});
|
||||
|
||||
it("All finished!", function(done){
|
||||
console.log("Done! Cleaning things up...");
|
||||
setTimeout(function(){
|
||||
done();
|
||||
//},1000);
|
||||
},1000 * 60);
|
||||
});
|
||||
|
||||
after("Everything shut down.", function(){
|
||||
browsers.run(function(){
|
||||
//location.reload();
|
||||
//setTimeout(function(){
|
||||
//}, 15 * 1000);
|
||||
});
|
||||
return servers.run(function(){
|
||||
process.exit();
|
||||
});
|
||||
});
|
||||
});
|
137
test/panic/bulkimport.js
Normal file
137
test/panic/bulkimport.js
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
This is the first in a series of basic networking correctness tests.
|
||||
Each test itself might be dumb and simple, but built up together,
|
||||
they prove desired end goals for behavior at scale.
|
||||
1. (this file) Is a browser write is confirmed as save by multiple peers even if by daisy chain.
|
||||
2.
|
||||
*/
|
||||
|
||||
var config = {
|
||||
IP: require('ip').address(),
|
||||
port: 8765,
|
||||
servers: 1,
|
||||
browsers: 2,
|
||||
puts: 1000,
|
||||
route: {
|
||||
'/': __dirname + '/index.html',
|
||||
'/gun.js': __dirname + '/../../gun.js',
|
||||
'/jquery.js': __dirname + '/../../examples/jquery.js'
|
||||
}
|
||||
}
|
||||
|
||||
var panic = require('panic-server');
|
||||
panic.server().on('request', function(req, res){
|
||||
config.route[req.url] && require('fs').createReadStream(config.route[req.url]).pipe(res);
|
||||
}).listen(config.port);
|
||||
|
||||
var clients = panic.clients;
|
||||
var manager = require('panic-manager')();
|
||||
|
||||
manager.start({
|
||||
clients: Array(config.servers).fill().map(function(u, i){
|
||||
return {
|
||||
type: 'node',
|
||||
port: config.port + (i + 1)
|
||||
}
|
||||
}),
|
||||
panic: 'http://' + config.IP + ':' + config.port
|
||||
});
|
||||
|
||||
var servers = clients.filter('Node.js');
|
||||
var bob = servers.pluck(1);
|
||||
var browsers = clients.excluding(servers);
|
||||
var alice = browsers.pluck(1);
|
||||
var carl = browsers.excluding(alice).pluck(1);
|
||||
|
||||
describe("Put ACK", function(){
|
||||
//this.timeout(5 * 60 * 1000);
|
||||
this.timeout(10 * 60 * 1000);
|
||||
|
||||
it("Servers have joined!", function(){
|
||||
return servers.atLeast(config.servers);
|
||||
});
|
||||
|
||||
it("GUN started!", function(){
|
||||
var tests = [], i = 0;
|
||||
servers.each(function(client){
|
||||
tests.push(client.run(function(test){
|
||||
var env = test.props;
|
||||
test.async();
|
||||
try{ require('fs').unlinkSync(env.i+'data') }catch(e){}
|
||||
try{ require('gun/lib/fsrm')(env.i+'data') }catch(e){}
|
||||
var server = require('http').createServer(function(req, res){
|
||||
res.end("I am "+ env.i +"!");
|
||||
});
|
||||
var port = env.config.port + env.i;
|
||||
var Gun = require('gun');
|
||||
var peers = [], i = env.config.servers;
|
||||
while(i--){
|
||||
var tmp = (env.config.port + (i + 1));
|
||||
if(port != tmp){ // ignore ourselves
|
||||
peers.push('http://'+ env.config.IP + ':' + tmp + '/gun');
|
||||
}
|
||||
}
|
||||
console.log(port, " connect to ", peers);
|
||||
var gun = Gun({file: env.i+'data', peers: peers, web: server});
|
||||
server.listen(port, function(){
|
||||
test.done();
|
||||
});
|
||||
}, {i: i += 1, config: config}));
|
||||
});
|
||||
return Promise.all(tests);
|
||||
});
|
||||
|
||||
it(config.browsers +" browser(s) have joined!", function(){
|
||||
console.log("PLEASE OPEN http://"+ config.IP +":"+ config.port +" IN "+ config.browsers +" BROWSER(S)!");
|
||||
return browsers.atLeast(config.browsers);
|
||||
});
|
||||
|
||||
it("Browsers initialized gun!", function(){
|
||||
var tests = [], i = 0;
|
||||
browsers.each(function(client, id){
|
||||
tests.push(client.run(function(test){
|
||||
try{ localStorage.clear() }catch(e){}
|
||||
try{ indexedDB.deleteDatabase('radata') }catch(e){}
|
||||
var env = test.props;
|
||||
var gun = Gun('http://'+ env.config.IP + ':' + (env.config.port + 1) + '/gun');
|
||||
window.ref = gun.get('test');
|
||||
}, {i: i += 1, config: config}));
|
||||
});
|
||||
return Promise.all(tests);
|
||||
});
|
||||
|
||||
it("Puts", function(){
|
||||
return alice.run(function(test){
|
||||
console.log("I AM ALICE");
|
||||
test.async();
|
||||
var i = test.props.puts, d = 0;
|
||||
while(i--){ go(i) }
|
||||
function go(i){
|
||||
ref.get(i).put({hello: 'world'}, function(ack){
|
||||
if(ack.err){ put_failed }
|
||||
if(++d !== test.props.puts){ return }
|
||||
console.log("all success", d);
|
||||
test.done();
|
||||
});
|
||||
}
|
||||
}, {puts: config.puts});
|
||||
});
|
||||
|
||||
it("All finished!", function(done){
|
||||
console.log("Done! Cleaning things up...");
|
||||
setTimeout(function(){
|
||||
done();
|
||||
},1000);
|
||||
});
|
||||
|
||||
after("Everything shut down.", function(){
|
||||
browsers.run(function(){
|
||||
//location.reload();
|
||||
//setTimeout(function(){
|
||||
//}, 15 * 1000);
|
||||
});
|
||||
return servers.run(function(){
|
||||
process.exit();
|
||||
});
|
||||
});
|
||||
});
|
192
test/panic/livestream.js
Normal file
192
test/panic/livestream.js
Normal file
@ -0,0 +1,192 @@
|
||||
/*
|
||||
This is the first in a series of basic networking correctness tests.
|
||||
Each test itself might be dumb and simple, but built up together,
|
||||
they prove desired end goals for behavior at scale.
|
||||
1. (this file) Is a browser write is confirmed as save by multiple peers even if by daisy chain.
|
||||
2.
|
||||
*/
|
||||
|
||||
var config = {
|
||||
IP: require('ip').address(),
|
||||
port: 8765,
|
||||
servers: 1,
|
||||
browsers: 2,
|
||||
route: {
|
||||
'/': __dirname + '/index.html',
|
||||
'/gun.js': __dirname + '/../../gun.js',
|
||||
'/jquery.js': __dirname + '/../../examples/jquery.js',
|
||||
'/livestream.html': __dirname + '/livestream.html',
|
||||
}
|
||||
}
|
||||
|
||||
var panic = require('panic-server');
|
||||
panic.server().on('request', function(req, res){
|
||||
config.route[req.url] && require('fs').createReadStream(config.route[req.url]).pipe(res);
|
||||
}).listen(config.port);
|
||||
|
||||
var clients = panic.clients;
|
||||
var manager = require('panic-manager')();
|
||||
|
||||
manager.start({
|
||||
clients: Array(config.servers).fill().map(function(u, i){
|
||||
return {
|
||||
type: 'node',
|
||||
port: config.port + (i + 1)
|
||||
}
|
||||
}),
|
||||
panic: 'http://' + config.IP + ':' + config.port
|
||||
});
|
||||
|
||||
var servers = clients.filter('Node.js');
|
||||
var bob = servers.pluck(1);
|
||||
var browsers = clients.excluding(servers);
|
||||
var alice = browsers.pluck(1);
|
||||
var others = browsers.excluding(alice);
|
||||
|
||||
describe("Broadcast Video", function(){
|
||||
//this.timeout(5 * 60 * 1000);
|
||||
this.timeout(10 * 60 * 1000);
|
||||
|
||||
it("Servers have joined!", function(){
|
||||
return servers.atLeast(config.servers);
|
||||
});
|
||||
|
||||
it("GUN started!", function(){
|
||||
var tests = [], i = 0;
|
||||
servers.each(function(client){
|
||||
tests.push(client.run(function(test){
|
||||
var env = test.props;
|
||||
test.async();
|
||||
try{ require('fs').unlinkSync(env.i+'data') }catch(e){}
|
||||
try{ require('gun/lib/fsrm')(env.i+'data') }catch(e){}
|
||||
var server = require('http').createServer(function(req, res){
|
||||
res.end("I am "+ env.i +"!");
|
||||
});
|
||||
var port = env.config.port + env.i;
|
||||
var Gun = require('gun');
|
||||
var peers = [], i = env.config.servers;
|
||||
while(i--){
|
||||
var tmp = (env.config.port + (i + 1));
|
||||
if(port != tmp){ // ignore ourselves
|
||||
peers.push('http://'+ env.config.IP + ':' + tmp + '/gun');
|
||||
}
|
||||
}
|
||||
console.log(port, " connect to ", peers);
|
||||
var gun = Gun({file: env.i+'data', peers: peers, web: server});
|
||||
server.listen(port, function(){
|
||||
test.done();
|
||||
});
|
||||
}, {i: i += 1, config: config}));
|
||||
});
|
||||
return Promise.all(tests);
|
||||
});
|
||||
|
||||
it(config.browsers +" browser(s) have joined!", function(){
|
||||
console.log("PLEASE OPEN http://"+ config.IP +":"+ config.port +" IN "+ config.browsers +" BROWSER(S)!");
|
||||
return browsers.atLeast(config.browsers);
|
||||
});
|
||||
|
||||
it("Browsers load QVDev's streaming!", function(){
|
||||
var tests = [], i = 0;
|
||||
browsers.each(function(client, id){
|
||||
tests.push(client.run(function(test){
|
||||
test.async();
|
||||
console.log("load?");
|
||||
function load(src, cb){
|
||||
var script = document.createElement('script');
|
||||
script.onload = cb; script.src = src;
|
||||
document.head.appendChild(script);
|
||||
}
|
||||
load('https://cdn.jsdelivr.net/gh/QVDev/GunStreamer/js/GunRecorder.js', function(){
|
||||
load('https://cdn.jsdelivr.net/gh/QVDev/GunStreamer/js/GunStreamer.js', function(){
|
||||
load('https://cdn.jsdelivr.net/gh/QVDev/GunStreamer/js/GunViewer.js', function(){
|
||||
load('https://cdn.jsdelivr.net/gh/QVDev/GunStreamer/js/mediabuffer.js', function(){
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
$('body').append('<video id="video" width="100%" autoplay></video>');
|
||||
}, {i: i += 1, config: config}));
|
||||
});
|
||||
return Promise.all(tests);
|
||||
});
|
||||
|
||||
it("Browsers initialized gun!", function(){
|
||||
var tests = [], i = 0;
|
||||
browsers.each(function(client, id){
|
||||
tests.push(client.run(function(test){
|
||||
try{ localStorage.clear() }catch(e){}
|
||||
try{ indexedDB.deleteDatabase('radata') }catch(e){}
|
||||
var env = test.props;
|
||||
var gun = Gun('http://'+ env.config.IP + ':' + (env.config.port + 1) + '/gun');
|
||||
window.gun = gun;
|
||||
}, {i: i += 1, config: config}));
|
||||
});
|
||||
return Promise.all(tests);
|
||||
});
|
||||
|
||||
it("Stream", function(){
|
||||
return alice.run(function(test){
|
||||
console.log("I AM ALICE");
|
||||
test.async();
|
||||
var stream = window.stream = new GunStreamer({
|
||||
url: "https://cdn.jsdelivr.net/gh/QVDev/GunStreamer/js/parser_worker.js",
|
||||
gun: gun,
|
||||
streamId: 'livestream',
|
||||
dbRecord: 'streams'
|
||||
});
|
||||
var record = window.record = new GunRecorder({
|
||||
mimeType: 'video/webm; codecs="opus,vp8"',
|
||||
//audioBitsPerSecond: 6000,//Audio bits per second this is the lowest quality
|
||||
//videoBitsPerSecond: 100000,//Video bits per second this is the lowest quality
|
||||
cameraOptions: {video:{width: 1280, height: 720, facingMode: "environment", frameRate: 60}, audio: false},
|
||||
video_id: "video",
|
||||
recordInterval: 1000, // how long each chunk?
|
||||
onRecordStateChange: function(state){ /* change play/pause buttons */ },
|
||||
onDataAvailable: function(data){ stream.onDataAvailable(data) } // pass recorded data to streamer
|
||||
});
|
||||
record.startCamera();
|
||||
$('#video').on('playing', function(eve){
|
||||
record.record();
|
||||
test.done();
|
||||
});
|
||||
console.log("start recording!");
|
||||
}, {acks: config.servers});
|
||||
});
|
||||
|
||||
it("View", function(){
|
||||
return others.run(function(test){
|
||||
console.log("I AM A VIEWER!");
|
||||
test.async();
|
||||
var view = new GunViewer({
|
||||
//mimeType: 'video/webm; codecs="opus,vp8"', // NEED THIS ONE FOR AUDIO+VIDEO
|
||||
mimeType: 'video/webm; codecs="vp8"',
|
||||
streamerId: "video",
|
||||
debug: true,//For debug logs
|
||||
});
|
||||
gun.get('livestream').on(function(data){
|
||||
window.data = data;
|
||||
view.onStreamerData(data);
|
||||
});
|
||||
}, {acks: config.servers});
|
||||
});
|
||||
|
||||
it("All finished!", function(done){
|
||||
console.log("Done! Cleaning things up...");
|
||||
setTimeout(function(){
|
||||
done();
|
||||
},1000);
|
||||
});
|
||||
|
||||
after("Everything shut down.", function(){
|
||||
browsers.run(function(){
|
||||
//location.reload();
|
||||
//setTimeout(function(){
|
||||
//}, 15 * 1000);
|
||||
});
|
||||
return servers.run(function(){
|
||||
process.exit();
|
||||
});
|
||||
});
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user