mirror of
https://github.com/amark/gun.git
synced 2025-06-06 06:06:50 +00:00
working realtime live push yay
This commit is contained in:
parent
5150118332
commit
9e71c88198
@ -8,13 +8,11 @@ var gun = Gun({
|
||||
s3: (process.env.NODE_ENV === 'production')? null : require('../../test/shotgun') // replace this with your own keys!
|
||||
});
|
||||
|
||||
app.use(express.static(__dirname))
|
||||
.use(bodyParser.json())
|
||||
.use(gun.server);
|
||||
app.use(gun.server)
|
||||
.use(express.static(__dirname))
|
||||
app.listen(port);
|
||||
|
||||
console.log('Express started on port ' + port + ' with /gun');
|
||||
|
||||
gun.load('blob/data').blank(function(){
|
||||
gun.set({ hello: "world", from: "Mark Nadal" }).key('blob/data');
|
||||
gun.load('blob/data').blank(function(){ // in case there is no data on this key
|
||||
gun.set({ hello: "world", from: "Mark Nadal" }).key('blob/data'); // save some sample data
|
||||
});
|
64
examples/admin/duel.html
Normal file
64
examples/admin/duel.html
Normal file
@ -0,0 +1,64 @@
|
||||
<!DOCTYPE html>
|
||||
<html ng-app="admin">
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<script src="https://ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js"></script>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
|
||||
<script src="../../gun.js"></script>
|
||||
</head>
|
||||
<body ng-controller="editor">
|
||||
<style>
|
||||
html, body {
|
||||
font-family: Verdana, Geneva, sans-serif;
|
||||
}
|
||||
a {
|
||||
color: skyblue;
|
||||
text-decoration: none;
|
||||
cursor: poiner;
|
||||
}
|
||||
ul, li {
|
||||
list-style-type: none;
|
||||
}
|
||||
ul:hover, li:hover {
|
||||
list-style-type: inherit;
|
||||
}
|
||||
input {
|
||||
border: none;
|
||||
border-bottom: dashed 1px gainsboro;
|
||||
}
|
||||
.none {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
<form id="p1" class="assign-player" onsubmit="return false;">
|
||||
Player 1: <input type="text" name="p1" placeholder="nickname">
|
||||
<input type="submit" value="Join!">
|
||||
</form>
|
||||
<form id="p2" class="assign-player" onsubmit="return false;">
|
||||
Player 2: <input type="text" name="p2" placeholder="nickname">
|
||||
<input type="submit" value="Join!">
|
||||
</form>
|
||||
<script>
|
||||
(function(){
|
||||
var gun = Gun(['http://localhost:8888/' + 'gun'])
|
||||
.load('game/duel', function(game){
|
||||
console.log(game);
|
||||
$(document).on('submit', '.assign-player', function(e){
|
||||
e.preventDefault();
|
||||
console.log("Choosing player!");
|
||||
var nick = $(this).find('input').val();
|
||||
if(!nick){ return }
|
||||
gun.path(this.id).get(function(val){
|
||||
console.log(val, nick, 'oh?');
|
||||
if(val){ return }
|
||||
gun.path('p1').set(nick);
|
||||
});
|
||||
})
|
||||
Gun.on(game._[Gun.sym.id]).event(function(node){
|
||||
console.log("change!", node);
|
||||
});
|
||||
});
|
||||
}());
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -2,6 +2,9 @@
|
||||
<html ng-app="admin">
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<script src="https://ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js"></script>
|
||||
<!--
|
||||
-->
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.js"></script>
|
||||
<script src="../../gun.js"></script>
|
||||
</head>
|
||||
@ -13,6 +16,7 @@
|
||||
a {
|
||||
color: skyblue;
|
||||
text-decoration: none;
|
||||
cursor: poiner;
|
||||
}
|
||||
ul, li {
|
||||
list-style-type: none;
|
||||
@ -30,6 +34,13 @@
|
||||
</style>
|
||||
<h3>Admin Data Editor</h3>
|
||||
This is a live view of your JSON data, you can edit it in realtime or add new key/values.
|
||||
<!--
|
||||
<form method="post" action="http://localhost:8888/gun">
|
||||
First name: <input type="text" name="firstname"><br>
|
||||
Last name: <input type="text" name="lastname">
|
||||
<input type="submit" value="Submit">
|
||||
</form>
|
||||
-->
|
||||
<ul name="list">
|
||||
<li ng-repeat="(key, val) in data">
|
||||
<div ng-if="key != '_'">
|
||||
@ -41,17 +52,26 @@
|
||||
<form ng-submit="add()">
|
||||
<label>
|
||||
<input ng-model="field" placeholder="key" ng-submit="add()">
|
||||
<a href="#" ng-click="add()">add</a>
|
||||
<a ng-click="add()">add</a>
|
||||
<input type="submit" class="none"/>
|
||||
</label>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
<div id="debug">SUP</div>
|
||||
<script>
|
||||
gun = Gun([location.origin + '/gun']);
|
||||
angular.module('admin', [
|
||||
|
||||
]).controller('editor', function($scope){
|
||||
function debug(s){
|
||||
document.getElementById('debug').innerHTML = s;
|
||||
}
|
||||
//var gun = Gun([location + 'gun']);
|
||||
var gun = Gun(['http://localhost:8888/' + 'gun']);
|
||||
/*
|
||||
(function(){
|
||||
debug('meow ');// + tab.com.toString());
|
||||
tab.com.jsonp();
|
||||
})();
|
||||
*/
|
||||
angular.module('admin', []).controller('editor', function($scope){
|
||||
$scope.data = {};
|
||||
$scope.$data = gun.load('blob/data', function(data){
|
||||
$scope.data = data;
|
||||
@ -64,19 +84,13 @@
|
||||
});
|
||||
});
|
||||
$scope.add = function(a,b,c){
|
||||
$scope.$data.path($scope.field).set(
|
||||
$scope.data[$scope.field] = 'value'
|
||||
);
|
||||
$scope.$data.path($scope.field).set( $scope.data[$scope.field] = 'value' );
|
||||
$scope.field = '';
|
||||
};
|
||||
window.$data = $scope.$data;
|
||||
}).directive('gun', function(){
|
||||
return function(scope, elem){
|
||||
elem.on('keyup', function(){
|
||||
scope.$data.path(scope.key).set(
|
||||
scope.data[scope.key] = elem.text()
|
||||
);
|
||||
// scope.$apply();
|
||||
scope.$data.path(scope.key).set( scope.data[scope.key] = elem.text() );
|
||||
});
|
||||
};
|
||||
});
|
||||
|
359
gun.js
359
gun.js
@ -39,13 +39,17 @@
|
||||
Gun.obj.map(from._, function(val, field){
|
||||
gun._[field] = val;
|
||||
});
|
||||
Gun.chain.chain.events(gun);
|
||||
return gun;
|
||||
}
|
||||
Gun.chain.chain.events = function(gun){
|
||||
gun._.events = Gun.on.split(); // we want events per chain
|
||||
gun._.events.trace = gun._.events.trace || 0;
|
||||
gun._.events.at = gun._.events.at || 0;
|
||||
return gun;
|
||||
}
|
||||
Gun.chain.load = function(key, cb, opt){
|
||||
var gun = this.chain();
|
||||
var gun = this; // this.chain();
|
||||
Gun.chain.chain.events(gun);
|
||||
cb = cb || function(){};
|
||||
if(cb.node = gun.__.keys[key]){ // set this to the current node, too!
|
||||
Gun.log("from gun"); // remember to do all the same stack stuff here also!
|
||||
@ -64,6 +68,7 @@
|
||||
context = Gun.chain.set.now.union.call(gun, context.nodes); // data safely transformed
|
||||
if(context.err){ return (gun._.dud||cb.fn)(context.err) }
|
||||
gun._.node = gun.__.keys[key] = gun.__.nodes[data._[own.sym.id]];
|
||||
//console.log("compare", gun._, gun.__);
|
||||
cb(Gun.obj.copy(gun._.node));
|
||||
gun._.events.on(gun._.events.at += 1).emit(gun._.node);
|
||||
gun._.events.at = 0; // ???? reset it back once everything is done? the returns above don't allow for this.
|
||||
@ -110,23 +115,30 @@
|
||||
Gun.log("PATH failed to resolve");
|
||||
gun._.events.on(gun._.events.at += 1).emit();
|
||||
} else { // we are done, and this should be the value we wanted.
|
||||
Gun.log("PATH resolved", val);
|
||||
Gun.log("PATH resolved", node, val);
|
||||
gun._.events.on(gun._.events.at += 1).emit(val);
|
||||
}
|
||||
}
|
||||
});
|
||||
if(this._.loaded){ // this was the previous chain, gun is the new one
|
||||
console.log("Send off!", gun._.events.at + 1);
|
||||
Gun.log("Send off!", gun._.events.at + 1, path);
|
||||
gun._.events.on(gun._.events.at += 1).emit(this._.node);
|
||||
}
|
||||
return gun;
|
||||
}
|
||||
Gun.chain.get = function(cb){
|
||||
var gun = this;
|
||||
Gun.log("GET stack trace", gun._.events.trace + 1);
|
||||
gun._.events.on(gun._.events.trace += 1).event(function(node){
|
||||
console.log("shabam", node);
|
||||
if(gun._.field){
|
||||
return cb((node||{})[gun._.field]);
|
||||
}
|
||||
cb(Gun.obj.copy(node));
|
||||
});
|
||||
if(gun._.loaded){
|
||||
Gun.log("GET stack trace", gun._.events.trace, gun._.events.at, gun);
|
||||
gun._.events.on(gun._.events.at += 1).emit(this._.node);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
/*
|
||||
@ -250,6 +262,12 @@
|
||||
Gun.list.index = 1; // change this to 0 if you want non-logical, non-mathematical, non-matrix, non-convenient array notation
|
||||
Gun.obj = {};
|
||||
Gun.obj.is = function(o){ return (o instanceof Object && !Gun.list.is(o) && !Gun.fns.is(o))? true : false }
|
||||
Gun.obj.del = function(o, k){
|
||||
if(!o){ return }
|
||||
o[k] = null;
|
||||
delete o[k];
|
||||
return true;
|
||||
}
|
||||
Gun.obj.ify = function(o){
|
||||
if(Gun.obj.is(o)){ return o }
|
||||
try{o = JSON.parse(o);
|
||||
@ -319,7 +337,7 @@
|
||||
if(!hear.as){ return }
|
||||
map(hear);
|
||||
hear.as.apply(hear, args);
|
||||
}))){ delete this._.events[on] }
|
||||
}))){ Gun.obj.del(this._.events,on) }
|
||||
}
|
||||
On.echo.event = function(as, i){
|
||||
var on = this._.on, e;
|
||||
@ -409,7 +427,7 @@
|
||||
var serverState = Gun.time.is();
|
||||
// add more checks?
|
||||
var state = HAM(serverState, deltaStates[field], states[field], deltaValue, current[field]);
|
||||
// console.log("HAM:", field, deltaValue, deltaStates[field], current[field], 'the', state, (deltaStates[field] - serverState));
|
||||
// Gun.log("HAM:", field, deltaValue, deltaStates[field], current[field], 'the', state, (deltaStates[field] - serverState));
|
||||
if(state.err){
|
||||
Gun.log(".!HYPOTHETICAL AMNESIA MACHINE ERR!.", state.err);
|
||||
return;
|
||||
@ -595,8 +613,9 @@
|
||||
return false;
|
||||
}
|
||||
}());
|
||||
Gun.log = function(s, l){
|
||||
console.log.apply(console, arguments);
|
||||
Gun.log = function(a, b, c, d, e, f){ //s, l){
|
||||
//console.log(a, b, c, d, e, f);
|
||||
//console.log.apply(console, arguments);
|
||||
}
|
||||
own.sym = Gun.sym = {
|
||||
id: '#'
|
||||
@ -617,12 +636,13 @@
|
||||
tab.server = tab.server || function(req, res, next){
|
||||
|
||||
}
|
||||
//window.tab = tab; //window.XMLHttpRequest = null; // for debugging purposes
|
||||
tab.load = tab.load || function(key, cb, opt){
|
||||
cb = cb || function(){};
|
||||
opt = opt || {};
|
||||
Gun.obj.map(gun.__.opt.peers, function(peer, url){
|
||||
tab.ajax(url + '/' + key, null, function(reply){
|
||||
Gun.log('via', url, key, reply);
|
||||
tab.ajax(url + '/' + key, null, function(err, reply){
|
||||
console.log('via', url, key, reply);
|
||||
if(!reply){ return } // handle reconnect?
|
||||
if(reply.body && reply.body.err){
|
||||
cb(reply.body.err);
|
||||
@ -631,43 +651,64 @@
|
||||
}
|
||||
|
||||
(function(){
|
||||
tab.subscribe.sub = (reply.headers || {})['Gun-Sub'];
|
||||
tab.subscribe.sub = (reply.headers || {})['gun-sub'];
|
||||
//console.log("We are sub", tab.subscribe.sub);
|
||||
var data = reply.body;
|
||||
if(!data || !data._){ return }
|
||||
tab.subscribe(data._[Gun.sym.id]);
|
||||
}());
|
||||
}, {head: {'Gun-Sub': 1}});
|
||||
}, {headers: {'Gun-Sub': tab.subscribe.sub || ''}, header: {'Gun-Sub': 1}});
|
||||
});
|
||||
}
|
||||
tab.set = tab.set || function(nodes, cb){
|
||||
cb = cb || function(){};
|
||||
// TODO: batch and throttle later.
|
||||
console.log('ajax set', nodes);
|
||||
Gun.obj.map(gun.__.opt.peers, function(peer, url){
|
||||
tab.ajax(url, nodes, function(reply){
|
||||
console.log("set confirmed?", reply);
|
||||
});
|
||||
tab.ajax(url, nodes, function respond(err, reply, id){
|
||||
if(reply && reply.body){
|
||||
if(reply.body.defer){
|
||||
tab.set.defer[reply.body.defer] = respond;
|
||||
}
|
||||
if(reply.body.refed || reply.body.reply){
|
||||
//console.log("-------post-reply-all--------->", reply, err);
|
||||
respond(null, {headers: reply.headers, body: reply});
|
||||
Gun.obj.map(reply.body.refed, function(r, id){
|
||||
var cb;
|
||||
if(cb = tab.set.defer[id]){
|
||||
cb(null, {headers: reply.headers, body: r}, id);
|
||||
}
|
||||
});
|
||||
// TODO: should be able to do some type of "checksum" that every request cleared, and if not, figure out what is wrong/wait for finish.
|
||||
return;
|
||||
}
|
||||
tab.sent(reply.body);
|
||||
}
|
||||
Gun.obj.del(tab.set.defer, id);
|
||||
}, {headers: {'Gun-Sub': tab.subscribe.sub || ''}});
|
||||
});
|
||||
}
|
||||
tab.subscribe = function(id){
|
||||
tab.set.defer = {};
|
||||
tab.sent = function(){
|
||||
// remove set from unsure queue.
|
||||
}
|
||||
tab.subscribe = function(id){ // TODO: BUG!!! ERROR! Unexpected end of input!!!! Fix!
|
||||
tab.subscribe.to = tab.subscribe.to || {};
|
||||
if(id){
|
||||
tab.subscribe.to[id] = 1;
|
||||
}
|
||||
var opt = {
|
||||
//head: {'Gun-Sub': 1},
|
||||
header: {'Gun-Sub': 1},
|
||||
headers: {
|
||||
'Gun-Transport': 'XHR-SLP',
|
||||
'Gun-Sub': tab.subscribe.sub || ''
|
||||
}
|
||||
}, query = tab.subscribe.sub? '' : tab.subscribe.query(tab.subscribe.to);
|
||||
console.log("SUB", tab.subscribe.sub);
|
||||
Gun.obj.map(gun.__.opt.peers, function(peer, url){
|
||||
tab.ajax(url + query, null, function(reply){
|
||||
tab.ajax(url + query, null, function(err, reply){
|
||||
//console.log("poll", err, reply);
|
||||
tab.subscribe.poll();
|
||||
if(!reply){ return } // do anything?
|
||||
if(reply.headers){
|
||||
tab.subscribe.sub = reply.headers['Gun-Sub'] || tab.subscribe.sub;
|
||||
tab.subscribe.sub = reply.headers['gun-sub'] || tab.subscribe.sub;
|
||||
}
|
||||
var data = reply.body
|
||||
, union = function(node){ // maybe we shouldn't have this type of logic, below, in a hook?
|
||||
@ -682,7 +723,6 @@
|
||||
});
|
||||
}
|
||||
if(!data){ return } // do anything?
|
||||
if(data.err){ return } // do anything?
|
||||
if(data._){
|
||||
union(data);
|
||||
} else {
|
||||
@ -695,7 +735,7 @@
|
||||
}
|
||||
tab.subscribe.poll = function(){
|
||||
clearTimeout(tab.subscribe.poll.id);
|
||||
tab.subscribe.poll.id = setTimeout(tab.subscribe, 1); // 1000 * 10); // should enable some server-side control of this.
|
||||
tab.subscribe.poll.id = setTimeout(tab.subscribe, 1); //1000 * 10); // should enable some server-side control of this.
|
||||
}
|
||||
tab.subscribe.query = function(params){
|
||||
var s = '?'
|
||||
@ -705,129 +745,153 @@
|
||||
});
|
||||
return s;
|
||||
}
|
||||
tab.ajax =
|
||||
window.ajax =
|
||||
function(url, data, cb, opt){
|
||||
/*
|
||||
via Sockjs@1.0.0
|
||||
Parts of the code are derived from various open source projects.
|
||||
For code derived from Socket.IO by Guillermo Rauch see https://github.com/LearnBoost/socket.io/tree/0.6.17#readme.
|
||||
Snippets derived from JSON-js by Douglas Crockford are public domain.
|
||||
Snippets derived from jQuery-JSONP by Julian Aubourg, generic MIT license.
|
||||
All other code is released on MIT license, see LICENSE.
|
||||
*/
|
||||
var u;
|
||||
opt = opt || {};
|
||||
opt.head = opt.head || {};
|
||||
opt.reshead = {};
|
||||
opt.headers = opt.headers || {};
|
||||
if(data === u || data === null){
|
||||
data = u;
|
||||
} else {
|
||||
try{data = JSON.stringify(data);
|
||||
opt.headers["Content-Type"] = "application/json;charset=utf-8";
|
||||
}catch(e){}
|
||||
}
|
||||
opt.method = opt.method || (data? 'POST' : 'GET');
|
||||
// unload?
|
||||
opt.close = function(){
|
||||
opt.done(true);
|
||||
}
|
||||
opt.done = opt.done || function(abort){
|
||||
if(!opt.xhr){ return }
|
||||
// unload?
|
||||
try{opt.xhr.onreadystatechange = function(){};
|
||||
opt.xhr.ontimeout = opt.xhr.onerror =
|
||||
opt.xhr.onprogress = opt.xhr.onload = null;
|
||||
}catch(e){}
|
||||
if(abort){
|
||||
try{opt.xhr.abort();
|
||||
tab.ajax = (function(){
|
||||
function ajax(url, data, cb, opt){
|
||||
var u;
|
||||
opt = opt || {};
|
||||
opt.header = opt.header || {};
|
||||
opt.header["Content-Type"] = 1;
|
||||
opt.headers = opt.headers || {};
|
||||
if(data === u || data === null){
|
||||
data = u;
|
||||
} else {
|
||||
try{data = JSON.stringify(data);
|
||||
opt.headers["Content-Type"] = "application/json";
|
||||
}catch(e){}
|
||||
}
|
||||
opt.xhr = null;
|
||||
}
|
||||
opt.data = opt.data || function(d, head){
|
||||
var reply = {};
|
||||
reply.headers = head;
|
||||
try{reply.body = JSON.parse(d) || d;
|
||||
}catch(e){
|
||||
reply.body = d;
|
||||
opt.method = opt.method || (data? 'POST' : 'GET');
|
||||
var xhr = ajax.xhr() || ajax.jsonp() // TODO: BUG: JSONP push is working, but not post
|
||||
, clean = function(){
|
||||
if(!xhr){ return }
|
||||
xhr.onreadystatechange = xhr.onerror = null;
|
||||
try{xhr.abort();
|
||||
}catch(e){}
|
||||
xhr = null;
|
||||
}
|
||||
if(cb){ cb(reply) }
|
||||
}
|
||||
opt.chunk = function(status, text, force){
|
||||
if(status !== 200){ return }
|
||||
opt.each(opt.head, function(val, i){
|
||||
opt.reshead[i] = opt.xhr.getResponseHeader(i);
|
||||
});
|
||||
var d, b, p = 1;
|
||||
while(p || force){
|
||||
if(u !== d){
|
||||
opt.data(d, opt.reshead);
|
||||
force = false;
|
||||
xhr.onerror = function(){
|
||||
if(cb){
|
||||
cb({err: err || 'Unknown error.', status: xhr.status });
|
||||
}
|
||||
b = text.slice(opt.i = opt.i || 0);
|
||||
p = b.indexOf('\n') + 1;
|
||||
d = p? b.slice(0, p - 1) : b;
|
||||
opt.i += p;
|
||||
}
|
||||
}
|
||||
opt.finish = function(status, text) {
|
||||
opt.chunk(status, text, true);
|
||||
opt.close(status === 200 ? 'network' : 'permanent');
|
||||
}
|
||||
opt.error = function(){
|
||||
opt.finish(0, '');
|
||||
opt.done();
|
||||
}
|
||||
opt.xhr = opt.xhr || (function(xhr){
|
||||
try{xhr = new(window.XDomainRequest || window.XMLHttpRequest || window.ActiveXObject)('Microsoft.XMLHTTP');
|
||||
}catch(e){}
|
||||
if(window.ActiveXObject || window.XDomainRequest){
|
||||
url += ((url.indexOf('?') === -1) ? '?' : '&') + 't='+(+new Date());
|
||||
}
|
||||
if(xhr && window.XDomainRequest){
|
||||
xhr.ontimeout = xhr.onerror = opt.error;
|
||||
xhr.onprogress = function(){
|
||||
opt.chunk(200, (xhr || {}).responseText);
|
||||
clean(xhr.status === 200 ? 'network' : 'permanent');
|
||||
};
|
||||
xhr.onreadystatechange = function(){
|
||||
if(!xhr){ return }
|
||||
var reply, status;
|
||||
try{reply = xhr.responseText;
|
||||
status = xhr.status;
|
||||
}catch(e){}
|
||||
if(status === 1223){ status = 204 }
|
||||
if(xhr.readyState === 3){
|
||||
if(reply && 0 < reply.length){
|
||||
opt.ondata(status, reply);
|
||||
}
|
||||
} else
|
||||
if(xhr.readyState === 4){
|
||||
opt.ondata(status, reply, true);
|
||||
clean(status === 200? 'network' : 'permanent');
|
||||
}
|
||||
xhr.onload = function(){
|
||||
opt.finish(200, (xhr || {}).responseText);
|
||||
opt.done();
|
||||
};
|
||||
opt.ondata = opt.ondata || function(status, chunk, end){
|
||||
if(status !== 200){ return }
|
||||
try{ajax.each(opt.header, function(val, i){
|
||||
(xhr.responseHeader = xhr.responseHeader||{})[i.toLowerCase()] = xhr.getResponseHeader(i);
|
||||
});
|
||||
}catch(e){}
|
||||
var data, buf, pos = 1;
|
||||
while(pos || end){ // in order to end
|
||||
if(u !== data){ // we need at least one loop
|
||||
opt.onload({
|
||||
headers: xhr.responseHeader || {}
|
||||
,body: data
|
||||
});
|
||||
end = false; // now both pos and end will be false
|
||||
}
|
||||
if(ajax.string(chunk)){
|
||||
buf = chunk.slice(xhr.index = xhr.index || 0);
|
||||
pos = buf.indexOf('\n') + 1;
|
||||
data = pos? buf.slice(0, pos - 1) : buf;
|
||||
xhr.index += pos;
|
||||
} else {
|
||||
data = chunk;
|
||||
pos = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
opt.onload = opt.onload || function(reply){
|
||||
if(!reply){ return }
|
||||
if( reply.headers
|
||||
&& ("application/json" === reply.headers["content-type"])
|
||||
&& (ajax.string(reply.body))
|
||||
){
|
||||
reply.body = (reply.body === String(u))? u : JSON.parse(reply.body);
|
||||
}
|
||||
if(cb){
|
||||
cb(null, reply);
|
||||
}
|
||||
}
|
||||
if(opt.cookies || opt.credentials || opt.withCredentials){
|
||||
xhr.withCredentials = true;
|
||||
}
|
||||
opt.headers["X-Requested-With"] = xhr.transport || "XMLHttpRequest";
|
||||
try{xhr.open(opt.method, url, true);
|
||||
}catch(e){ return xhr.onerror("Open failed.") }
|
||||
if(opt.headers){
|
||||
try{ajax.each(opt.headers, function(val, i){
|
||||
xhr.setRequestHeader(i, val);
|
||||
});
|
||||
}catch(e){ return xhr.onerror("Invalid headers.") }
|
||||
}
|
||||
try{xhr.send(data);
|
||||
}catch(e){ return xhr.onerror("Failed to send request.") }
|
||||
}
|
||||
ajax.xhr = function(xhr){
|
||||
return (window.XMLHttpRequest && "withCredentials" in (xhr = new XMLHttpRequest()))? xhr : null;
|
||||
}
|
||||
ajax.jsonp = function(xhr){
|
||||
xhr = {};
|
||||
xhr.transport = "jsonp";
|
||||
xhr.open = function(method, url){
|
||||
xhr.url = url;
|
||||
}
|
||||
xhr.send = function(){
|
||||
xhr.url += ((xhr.url.indexOf('?') + 1)? '&' : '?') + 'jsonp=' + xhr.js.id;
|
||||
ajax.each(xhr.headers, function(val, i){
|
||||
xhr.url += '&' + encodeURIComponent(i) + "=" + encodeURIComponent(val);
|
||||
});
|
||||
xhr.js.src = xhr.url = xhr.url.replace(/%20/g, "+");
|
||||
document.getElementsByTagName('head')[0].appendChild(xhr.js);
|
||||
}
|
||||
xhr.setRequestHeader = function(i, val){
|
||||
(xhr.headers = xhr.headers||{})[i] = val;
|
||||
}
|
||||
xhr.getResponseHeader = function(i){ return (xhr.responseHeaders||{})[i] }
|
||||
xhr.js = document.createElement('script');
|
||||
window[xhr.js.id = 'P'+Math.floor((Math.random()*65535)+1)] = function(reply){
|
||||
xhr.status = 200;
|
||||
if(reply.chunks && reply.chunks.length){
|
||||
xhr.readyState = 3
|
||||
while(0 < reply.chunks.length){
|
||||
xhr.responseText = reply.chunks.shift();
|
||||
xhr.onreadystatechange();
|
||||
}
|
||||
}
|
||||
xhr.responseHeaders = reply.headers || {};
|
||||
xhr.readyState = 4;
|
||||
xhr.responseText = reply.body;
|
||||
xhr.onreadystatechange();
|
||||
xhr.id = xhr.js.id;
|
||||
xhr.js.parentNode.removeChild(xhr.js);
|
||||
window[xhr.id] = null;
|
||||
try{delete window[xhr.id];
|
||||
}catch(e){}
|
||||
|
||||
}
|
||||
xhr.abort = function(){} // clean up?
|
||||
xhr.js.async = true;
|
||||
return xhr;
|
||||
}());
|
||||
if(!opt.xhr){
|
||||
opt.error();
|
||||
return;
|
||||
}
|
||||
if(opt.cookies || opt.credentials || opt.withCredentials){
|
||||
opt.xhr.withCredentials = true;
|
||||
}
|
||||
opt.xhr.onreadystatechange = function(){
|
||||
if(!opt.xhr){ return }
|
||||
var reply, status;
|
||||
try{reply = opt.xhr.responseText;
|
||||
status = opt.xhr.status;
|
||||
}catch(e){}
|
||||
if(status === 1223){ status = 204 }
|
||||
if(opt.xhr.readyState === 3){
|
||||
if(reply && 0 < reply.length){
|
||||
opt.chunk(status, reply);
|
||||
}
|
||||
} else
|
||||
if(opt.xhr.readyState === 4){
|
||||
opt.finish(status, reply);
|
||||
opt.done(false);
|
||||
}
|
||||
}
|
||||
try{opt.xhr.open(opt.method, url, true);
|
||||
} catch(e) {
|
||||
opt.error();
|
||||
return;
|
||||
}
|
||||
opt.each = function(obj, cb){
|
||||
ajax.string = function(s){ return (typeof s == 'string') }
|
||||
ajax.each = function(obj, cb){
|
||||
if(!obj || !cb){ return }
|
||||
for(var i in obj){
|
||||
if(obj.hasOwnProperty(i)){
|
||||
@ -835,21 +899,8 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
if(opt.headers){
|
||||
try{opt.each(opt.headers, function(val, i){
|
||||
opt.xhr.setRequestHeader(i, val);
|
||||
});
|
||||
} catch(e) {
|
||||
opt.error();
|
||||
return;
|
||||
}
|
||||
}
|
||||
try{opt.xhr.send(data);
|
||||
}catch(e){
|
||||
opt.error();
|
||||
}
|
||||
return opt;
|
||||
}
|
||||
return ajax;
|
||||
}());
|
||||
gun.__.opt.hooks.load = gun.__.opt.hooks.load || tab.load;
|
||||
gun.__.opt.hooks.set = gun.__.opt.hooks.set || tab.set;
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
{ "name": "gun"
|
||||
, "version": "0.0.4"
|
||||
, "version": "0.0.5"
|
||||
, "author": "Mark Nadal"
|
||||
, "description": "Graph engine."
|
||||
, "engines": {
|
||||
@ -8,6 +8,7 @@
|
||||
, "dependencies": {
|
||||
"mime": "~>1.2.11",
|
||||
"aws-sdk": "~>2.0.0",
|
||||
"formidable": "~>1.0.15",
|
||||
"request": "~>2.39.0"
|
||||
}
|
||||
, "devDependencies": {
|
||||
|
308
shots.js
308
shots.js
@ -1,10 +1,11 @@
|
||||
;(function(){
|
||||
var Gun = require(__dirname+'/gun')
|
||||
, S3 = require(__dirname+'/gate/s3') // redis has been removed, can be replaced with a disk system
|
||||
, formidable = require('formidable')
|
||||
, url = require('url')
|
||||
, meta = {};
|
||||
Gun.on('opt').event(function(gun, opt){
|
||||
gun.server = gun.server || function(req, res, next){ // this whole function needs refactoring and modularization
|
||||
gun.server = gun.server || function(req, res, next){ // this whole function needs refactoring and modularization
|
||||
next = next || function(){};
|
||||
if(!req || !res){ return next() }
|
||||
if(!req.url){ return next() }
|
||||
@ -18,12 +19,14 @@
|
||||
res.end(gun.server.js = gun.server.js || require('fs').readFileSync(__dirname + '/gun.js')); // gun server is caching the gun library for the client
|
||||
return;
|
||||
}
|
||||
msg.url.key = msg.url.key.replace(/^\//i,'') || ''; // strip the base
|
||||
msg.url.key = msg.url.key.replace(/^\//i,'') || ''; // strip the base slash
|
||||
msg.method = (req.method||'').toLowerCase();
|
||||
msg.headers = req.headers;
|
||||
msg.body = req.body; // TODO: include body-parser here?
|
||||
if('get' === msg.method){ // get is used as subscribe
|
||||
gun.__.opt.hooks.sub(msg, function(reply){
|
||||
var body
|
||||
, form = new formidable.IncomingForm()
|
||||
, post = function(err, body){
|
||||
msg.body = body;
|
||||
gun.__.opt.hooks.transport(msg, function(reply){
|
||||
if(!res){ return }
|
||||
if(!reply){ return res.end() }
|
||||
if(reply.headers){
|
||||
@ -41,46 +44,21 @@
|
||||
res.end(Gun.text.ify(reply.body));
|
||||
}
|
||||
});
|
||||
return;
|
||||
} else
|
||||
if('post' === msg.method || 'patch' === msg.method){ // post is used as patch, sad that patch has such poor support
|
||||
if(!msg.body){
|
||||
console.log("Warn: No body on POST?");
|
||||
}
|
||||
// raw test for now, no auth:
|
||||
// should probably load all the nodes first?
|
||||
var context = Gun.chain.set.now.union.call(gun, msg.body); // data safely transformed
|
||||
if(context.err){
|
||||
return meta.JSON(res, context.err); // need to use the now standardized errors
|
||||
}
|
||||
/*
|
||||
WARNING! TODO: BUG! Do not send OK confirmation if amnesiaQuaratine is activated! Not until after it has actually been processed!!!
|
||||
*/
|
||||
if(Gun.fns.is(gun.__.opt.hooks.set)){
|
||||
gun.__.opt.hooks.set(context.nodes, function(err, data){ // now iterate through those nodes to S3 and get a callback once all are saved
|
||||
if(err){
|
||||
return meta.JSON(res, {err: err}); // server should handle the error for the client first! Not force client to re-attempt.
|
||||
}
|
||||
meta.JSON(res, {ok: 1}); // need to standardize OKs, OK:1 not good.
|
||||
});
|
||||
} else {
|
||||
context.err = "Warning! You have no persistence layer to save to!";
|
||||
Gun.log(context.err);
|
||||
}
|
||||
|
||||
var diff = msg.body
|
||||
msg.body = null;
|
||||
Gun.obj.map(context.nodes, function(node, id){
|
||||
var req = Gun.obj.copy(msg);
|
||||
msg.body = node;
|
||||
gun.server.push.on(id).emit(msg);
|
||||
});
|
||||
msg.body = diff;
|
||||
}
|
||||
form.on('field',function(k,v){
|
||||
(body = body || {})[k] = v;
|
||||
}).on('file',function(k,v){
|
||||
return; // files not supported in gun yet
|
||||
}).on('error',function(e){
|
||||
if(form.done){ return }
|
||||
post(e);
|
||||
}).on('end', function(){
|
||||
if(form.done){ return }
|
||||
post(null, body);
|
||||
});
|
||||
form.parse(req);
|
||||
}
|
||||
gun.server.regex = /^\/gun/i;
|
||||
gun.server.clients = {};
|
||||
gun.server.push = Gun.on.split();
|
||||
opt.s3 = opt.s3 || {};
|
||||
var s3 = gun.__.opt.s3 = gun.__.opt.s3 || S3(opt && opt.s3);
|
||||
s3.prefix = s3.prefix || opt.s3.prefix || '';
|
||||
@ -180,85 +158,222 @@
|
||||
}, {Metadata: {'#': id}});
|
||||
}
|
||||
|
||||
gun.server.sub = (function(){
|
||||
function sub(req, cb){
|
||||
gun.server.transport = (function(){
|
||||
function tran(req, cb){
|
||||
//console.log("\n\n\n", req);
|
||||
req.sub = req.headers['gun-sub'];
|
||||
req.transport = req.headers['gun-transport'];
|
||||
if(req.transport === 'XHR-SLP'){ return sub.SLP(req, cb) }
|
||||
if(!req.url.key){ return sub.keyless(req, cb) }
|
||||
req.sub = req.headers['gun-sub']; // grab the sub
|
||||
req.tab = tran.sub.s[req.sub] || {}; // check to see if there already is a tab associated with it, or create one
|
||||
req.tab.sub = req.sub = req.sub || Gun.text.random(); // Generate a session id if we don't already have one
|
||||
req.tran = tran.xhr(req, cb) || tran.jsonp(req, cb); // polyfill transport layer
|
||||
// raw test for now, no auth:
|
||||
req.tab = sub.s[req.sub] || {};
|
||||
cb.header = {'Content-Type': sub.json};
|
||||
cb.header['Gun-Sub'] = req.tab.sub =
|
||||
req.sub = req.tab.sub || req.sub || Gun.text.random();
|
||||
if(!req.tran){ return cb({headers: {"Content-Type": tran.json}, body: {err: "No transport layer!"}}) }
|
||||
if('post' === req.method || 'patch' === req.method){ return tran.post(req, req.tran) } // TODO: Handle JSONP emulated POST via GET
|
||||
if('get' !== req.method){ return req.tran({body: {err: "Invalid method"}}) }
|
||||
if(!req.url.key){ return tran.sub(req, req.tran) } // get acts as sub, too.
|
||||
return tran.load(req, req.tran); // else load the state for the tab!
|
||||
}
|
||||
tran.load = function(req, cb){
|
||||
var reply = {};
|
||||
reply.headers = {'Content-Type': tran.json};
|
||||
reply.headers['Gun-Sub'] = req.tab.sub = req.sub;
|
||||
gun.load(req.url.key, function(node){
|
||||
sub.scribe(req.tab, node._[Gun.sym.id]);
|
||||
console.log("Loading for", req.tab);
|
||||
tran.sub.scribe(req.tab, node._[Gun.sym.id]);
|
||||
cb({
|
||||
headers: cb.header
|
||||
,body: Gun.text.ify(node)
|
||||
headers: reply.headers
|
||||
,body: node
|
||||
});
|
||||
}).blank(function(){
|
||||
cb({
|
||||
headers: cb.header
|
||||
,body: Gun.text.ify(null)
|
||||
headers: reply.headers
|
||||
,body: null
|
||||
});
|
||||
}).dud(function(err){
|
||||
cb({
|
||||
headers: cb.header
|
||||
,body: Gun.text.ify({err: err || "Unknown error."})
|
||||
headers: reply.headers
|
||||
,body: {err: err || "Unknown error."}
|
||||
});
|
||||
});
|
||||
}
|
||||
sub.s = {};
|
||||
sub.scribe = function(tab, id){
|
||||
sub.s[tab.sub] = tab;
|
||||
tran.post = function(req, cb){ // post is used as patch, sad that patch has such poor support
|
||||
if(!req.body){ return cb({body: {err: "No body"}}) }
|
||||
// raw test for now, no auth:
|
||||
// should probably load all the nodes first? YES.
|
||||
var context = Gun.chain.set.now.union.call(gun, req.body); // data safely transformed
|
||||
//console.log("body?", req.body, context.err);
|
||||
if(context.err){ return cb({body: {err: context.err}}) }
|
||||
// WARNING! TODO: BUG! Do not send OK confirmation if amnesiaQuaratine is activated! Not until after it has actually been processed!!!
|
||||
if(Gun.fns.is(gun.__.opt.hooks.set)){
|
||||
gun.__.opt.hooks.set(context.nodes, function(err, data){ // now iterate through those nodes to S3 and get a callback once all are saved
|
||||
var body = {};
|
||||
if(err){
|
||||
body.err = err ;
|
||||
}
|
||||
if(!req.sub){
|
||||
if(!err){
|
||||
body = defer.map({}, context.nodes, 1);
|
||||
}
|
||||
return cb({body: body});
|
||||
}
|
||||
var now = tran.post.s[req.sub]; // begin our stupid Chrome fix, we should abstract this out into defer (where it belogns) to keep things clean.
|
||||
if(!now){ return } // utoh we've lost our reply to the tab!
|
||||
now.body = now.body || {}; // make sure we have a body for our multi-response in a single response.
|
||||
if(req.wait){ // did this request get deferred?
|
||||
(now.body.refed = now.body.refed || {})[req.wait] = err? {err: err} : defer.map({}, context.nodes, 1); // then reply to it "here".
|
||||
} else {
|
||||
now.body.reply = err? {err: err} : defer.map({}, context.nodes, 1); // else this is the original POST that had to be upgraded.
|
||||
}
|
||||
if(0 < (now.count = ((now.count || 0) - 1))){ // Don't reply till all deferred POSTs have successfully heard back from S3. (Sarcasm: Like counting guarantees that)
|
||||
return; // TODO: BUG!!! Memory leak, we have no guarantee we'll ever get a reply! So time it out, maybe some multiple of the S3 throttle.
|
||||
}
|
||||
if(Gun.fns.is(now)){
|
||||
now({body: now.body}); // FINALLY reply for ALL the POSTs for that session that accumulated.
|
||||
} else {
|
||||
// console.log("Error! We deleted our response!");
|
||||
}
|
||||
Gun.obj.del(tran.post.s, req.sub); // clean up our memory.
|
||||
// need to rewrite that if Stream is enabled that both Stream + State save are guaranteed before replying.
|
||||
});
|
||||
// stuff past this point is just stupid implementation optimizations.
|
||||
function defer(nodes, req){ // because Chrome can only handle 4 requests at a time, sad face.
|
||||
if(!req.sub){
|
||||
return;
|
||||
}
|
||||
var next = tran.post.s[req.sub];
|
||||
if(!next){ return tran.post.s[req.sub] = cb } // was there a previous POST? If not, we become the previous POST.
|
||||
next.count = (next.count || 1) + 1; // start counting how many we accumulate
|
||||
//console.log("Counting up", next.count);
|
||||
next.body = next.body || {}; // this becomes the polyfill for all the posts
|
||||
next.body.refed = next.body.refed || {}; // where we refeed the responses for the deferred POSTs.
|
||||
req.wait = Gun.text.random(); // generate an random id for this deferred POST.
|
||||
next.body.refed[req.wait] = false; // establish that we are incomplete.
|
||||
cb({body: {defer: req.wait}}); // end this POST immediately so Chrome only ever uses a couple connections.
|
||||
cb = null; // null it out so we don't accidentally reply to it once we hear back from S3.
|
||||
}
|
||||
defer.map = function(now, nodes, val){ // shortcut for maping which nodes were saved successfully
|
||||
if(!now){ return }
|
||||
Gun.obj.map(nodes, function(node, id, map){
|
||||
now[id] = val;
|
||||
});
|
||||
return now;
|
||||
}
|
||||
defer(context.nodes, req); // actually do the weird stuff to make Chrome not be slow
|
||||
} else {
|
||||
context.err = "Warning! You have no persistence layer to save to!";
|
||||
Gun.log(context.err);
|
||||
cb({body: {err: "Server has no persistence layer!"}});
|
||||
}
|
||||
Gun.obj.map(context.nodes, function(node, id){ // live push the stream out in realtime to every tab subscribed
|
||||
var msg = {};
|
||||
msg.headers = req.headers; // polyfill the delta as its own message.
|
||||
msg.body = node;
|
||||
//console.log("emit delta", id);
|
||||
tran.push.on(id).emit(msg);
|
||||
});
|
||||
}
|
||||
tran.post.s = {};
|
||||
tran.sub = function(req, cb){
|
||||
//console.log("<-- ", req.sub, req.tran ," -->");
|
||||
req.tab = tran.sub.s[req.sub];
|
||||
if(!req.tab){
|
||||
cb({
|
||||
headers: {'Gun-Sub': ''}
|
||||
,body: {err: "Please re-initialize sub."}
|
||||
});
|
||||
return;
|
||||
}
|
||||
//console.log("\n\n\n THE CURRENT STATUS IS");console.log(req.tab);
|
||||
if(req.tab.queue && req.tab.queue.length){
|
||||
console.log("_____ NOW PUSHING YOUR DATA ______", req.sub);
|
||||
cb({ headers: {'Gun-Sub': req.sub} });
|
||||
while(1 < req.tab.queue.length){
|
||||
cb({ chunk: req.tab.queue.shift() });
|
||||
}
|
||||
cb({ body: req.tab.queue.shift() });
|
||||
} else {
|
||||
req.tab.reply = cb;
|
||||
console.log("_____ STANDING BY, WAITING FOR DATA ______", req.sub);
|
||||
}
|
||||
}
|
||||
tran.sub.s = {};
|
||||
tran.sub.scribe = function(tab, id){ // TODO: BUG!!! Memory leaks, remember to destroy sessions via timeout.
|
||||
tran.sub.s[tab.sub] = tab;
|
||||
tab.subs = tab.subs || {};
|
||||
tab.subs[id] = tab.subs[id] || gun.server.push.on(id).event(function(req){
|
||||
tab.subs[id] = tab.subs[id] || tran.push.on(id).event(function(req){
|
||||
if(!req){ return }
|
||||
if(!tab){ return this.off() } // resolve any dangling callbacks
|
||||
req.sub = req.sub || req.headers['gun-sub'];
|
||||
if(req.sub === tab.sub){ return } // do not send back to the tab that sent it
|
||||
if(Gun.fns.is(tab.reply)){
|
||||
console.log('FROM:', req.sub, "TO:", tab);
|
||||
if(tab.reply){
|
||||
tab.reply({
|
||||
headers: {'Content-Type': sub.json, 'Gun-Sub': tab.sub}
|
||||
,body: Gun.text.ify(req.body)
|
||||
})
|
||||
headers: {'Gun-Sub': tab.sub}
|
||||
,body: req.body
|
||||
});
|
||||
tab.reply = null;
|
||||
return;
|
||||
}
|
||||
(tab.queue = tab.queue || []).push(req.body);
|
||||
});
|
||||
}
|
||||
sub.SLP = function(req, cb){ // Streaming Long Polling
|
||||
//console.log("<-- ", req.sub, req.transport ," -->");
|
||||
req.tab = sub.s[req.sub];
|
||||
if(!req.tab){
|
||||
cb({
|
||||
headers: {'Content-Type': sub.json, 'Gun-Sub': ''}
|
||||
,body: Gun.text.ify({err: "Please re-initialize sub."})
|
||||
});
|
||||
return;
|
||||
}
|
||||
req.tab.sub = req.tab.sub || req.sub;
|
||||
if(req.tab.queue && req.tab.queue.length){
|
||||
cb({ headers: {'Content-Type': sub.json, 'Gun-Sub': req.sub} });
|
||||
while(1 < req.tab.queue.length){
|
||||
cb({ chunk: Gun.text.ify(req.tab.queue.shift() + '\n') });
|
||||
tran.xhr = function(req, cb){ // Streaming Long Polling
|
||||
return req.tran || (req.headers['x-requested-with'] === 'XMLHttpRequest'? transport : null);
|
||||
function transport(res){
|
||||
if(!res){ return }
|
||||
var reply = {headers: {}};
|
||||
if(res.headers){
|
||||
Gun.obj.map(res.headers, function(val, field){
|
||||
reply.headers[field] = val;
|
||||
});
|
||||
}
|
||||
reply.headers["Content-Type"] = tran.json;
|
||||
if(res.chunk){
|
||||
cb({
|
||||
headers: reply.headers
|
||||
,body: Gun.text.ify(res.body) + '\n'
|
||||
})
|
||||
}
|
||||
if(res.body){
|
||||
cb({
|
||||
headers: reply.headers
|
||||
,body: Gun.text.ify(res.body)
|
||||
})
|
||||
}
|
||||
cb({ body: Gun.text.ify(req.tab.queue.shift()) });
|
||||
} else {
|
||||
req.tab.reply = cb;
|
||||
}
|
||||
}
|
||||
sub.keyless = function(req, cb){
|
||||
cb({
|
||||
headers: {'Content-Type': sub.json}
|
||||
,body: {gun: true}
|
||||
});
|
||||
tran.jsonp = function(req, cb){
|
||||
var reply = {headers: {}};
|
||||
if(req.tran || req.headers['x-requested-with']){ return }
|
||||
if((req.url.query||{}).jsonp){
|
||||
cb.jsonp = req.url.query.jsonp;
|
||||
Gun.obj.del(req.url.query, 'jsonp');
|
||||
req.headers['x-requested-with'] = 'jsonp'; // polyfill
|
||||
req.sub = req.headers['gun-sub'] = req.headers['gun-sub'] || req.url.query['Gun-Sub'] || req.url.query['gun-sub'];
|
||||
Gun.obj.del(req.url.query, 'Gun-Sub');
|
||||
Gun.obj.del(req.url.query, 'gun-sub');
|
||||
return transport;
|
||||
}
|
||||
function transport(res){
|
||||
if(!res){ return }
|
||||
if(res.headers){
|
||||
Gun.obj.map(res.headers, function(val, field){
|
||||
reply.headers[field] = val;
|
||||
});
|
||||
}
|
||||
if(res.chunk && (!reply.body || Gun.list.is(reply.chunks))){
|
||||
(reply.chunks = reply.chunks || []).push(res.chunk);
|
||||
}
|
||||
if(res.body){
|
||||
reply.body = res.body;
|
||||
reply.body = ';'+ cb.jsonp + '(' + Gun.text.ify(reply) + ');';
|
||||
cb(reply);
|
||||
console.log("replied with jsonp!!!!!!");
|
||||
}
|
||||
}
|
||||
}
|
||||
sub.json = 'application/json';
|
||||
return sub;
|
||||
tran.json = 'application/json';
|
||||
tran.push = Gun.on.split();
|
||||
return tran;
|
||||
}());
|
||||
|
||||
opt.hooks = opt.hooks || {};
|
||||
@ -266,7 +381,7 @@
|
||||
load: opt.hooks.load || s3.load
|
||||
,set: opt.hooks.set || s3.set
|
||||
,key: opt.hooks.key || s3.key
|
||||
,sub: opt.hooks.sub || gun.server.sub
|
||||
,transport: opt.hooks.transport || gun.server.transport
|
||||
}}, true);
|
||||
});
|
||||
meta.json = 'application/json';
|
||||
@ -275,7 +390,7 @@
|
||||
res.setHeader('Content-Type', meta.json);
|
||||
}
|
||||
if(!data && multi){
|
||||
res.write(Gun.text.ify(multi||'')+'\n');
|
||||
res.write(Gun.text.ify(multi||'') + '\n');
|
||||
return;
|
||||
}
|
||||
return res.end(Gun.text.ify(data||''));
|
||||
@ -284,9 +399,10 @@
|
||||
if(!res || res.CORSHeader || res._headerSent){ return }
|
||||
res.setHeader("Access-Control-Allow-Origin", "*");
|
||||
res.setHeader("Access-Control-Allow-Methods", ["POST", "GET", "PUT", "DELETE", "OPTIONS"]);
|
||||
res.setHeader("Access-Control-Allow-Credentials", true);
|
||||
res.setHeader("Access-Control-Allow-Credentials", false);
|
||||
res.setHeader("Access-Control-Max-Age", 1000 * 60 * 60 * 24);
|
||||
res.setHeader("Access-Control-Allow-Headers", ["X-Requested-With", "X-HTTP-Method-Override", "Content-Type", "Accept"]);
|
||||
res.setHeader("Access-Control-Allow-Headers", ["X-Requested-With", "X-HTTP-Method-Override", "Content-Type", "Accept", "Gun-Sub"]);
|
||||
res.setHeader("Access-Control-Expose-Headers", ["Content-Type", "Gun-Sub"]);
|
||||
res.CORSHeader = true;
|
||||
if(req && req.method === 'OPTIONS'){
|
||||
res.end();
|
||||
|
Loading…
x
Reference in New Issue
Block a user