Browse Source

update gundb and fix cloning

Nikolay Suslov 6 years ago
parent
commit
21a56a2043

+ 5 - 5
public/app.js

@@ -1233,15 +1233,15 @@ class App {
       'published': true
     };
 
-    let fileNamesAll = await _LCSDB.user(userPub).get('worlds').get(worldName).once().then();
+    let fileNamesAll = await _LCSDB.user(userPub).get('worlds').get(worldName).then();
     let worldFileNames = Object.keys(fileNamesAll).filter(el => (el !== '_') && (el !== 'owner') && (el !== 'parent') && (el !== 'featured') && (el !== 'published') && (el !== '_config_yaml') && (el !== '_yaml') && (el !== '_html'));
 
     for (var doc in worldFileNames) {
 
       let fn = worldFileNames[doc];
-      let res = await _LCSDB.user(userPub).get('worlds').get(worldName).get(fn).once().then();
+      let res = await _LCSDB.user(userPub).get('worlds').get(worldName).get(fn).then();
       let data = {
-        'file': res.file,
+        'file': JSON.stringify(res.file),
         'modified': created
       }
       worldObj[fn] = data;
@@ -1254,8 +1254,8 @@ class App {
     //   myNewWorld.get(obj).put(worldObj[obj]);
     // }
 
-    let myWorlds = _LCSDB.user().get('worlds');
-    myWorlds.get(worldID).put(worldObj);
+    let myWorlds = await _LCSDB.user().get('worlds').then();
+    let myWorld = _LCSDB.user().get('worlds').get(worldID).put(worldObj);
 
     _app.hideProgressBar();
     console.log('CLONED!!!');

+ 9 - 12
public/lib/gundb/gun.js

@@ -959,7 +959,6 @@
 
 		function output(msg){
 			var put, get, at = this.as, back = at.back, root = at.root, tmp;
-			if(!msg.I){ msg.I = at.$ }
 			if(!msg.$){ msg.$ = at.$ }
 			this.to.next(msg);
 			if(get = msg.get){
@@ -1215,7 +1214,6 @@
 				at.on('in', {get: at.get, put: Gun.val.link.ify(get['#']), $: at.$, '@': msg['@']});
 				return;
 			}
-			msg.$ = at.root.$;
 			Gun.on.put(msg, at.root.$);
 		}
 		var empty = {}, u;
@@ -1312,7 +1310,7 @@
 			//else if(!cat.async && msg.put !== at.put && root.stop && root.stop[at.id]){ return } root.stop && (root.stop[at.id] = true);
 
 
-			//root.stop && (root.stop.ID = root.stop.ID || Gun.text.random(2));
+			//root.stop && (root.stop.id = root.stop.id || Gun.text.random(2));
 			//if((tmp = root.stop) && (tmp = tmp[at.id] || (tmp[at.id] = {})) && tmp[cat.id]){ return } tmp && (tmp[cat.id] = true);
 			if(eve.seen && at.id && eve.seen[at.id]){ return eve.to.next(msg) }
 			//if((tmp = root.stop)){ if(tmp[at.id]){ return } tmp[at.id] = msg.root; } // temporary fix till a better solution?
@@ -1812,7 +1810,7 @@
 
 			root.on('out', function(msg){
 				if(msg.lS){ return }
-				if(msg.I && msg.put && !msg['@'] && !empty(opt.peers)){
+				if(Gun.is(msg.$) && msg.put && !msg['@'] && !empty(opt.peers)){
 					id = msg['#'];
 					Gun.graph.is(msg.put, null, map);
 					if(!to){ to = setTimeout(flush, opt.wait || 1) }
@@ -1888,7 +1886,7 @@
 					return; // 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.I});
+				root.on('in', {'@': msg['#'], put: Gun.graph.node(data), how: 'lS', lS: msg.$ || root.$});
 				};
 				Gun.debug? setTimeout(to,1) : to();
 			});
@@ -1938,8 +1936,8 @@
 				if((tmp = msg['@'])
 				&& (tmp = ctx.dup.s[tmp])
 				&& (tmp = tmp.it)
-				&& tmp.mesh){
-					mesh.say(msg, tmp.mesh.via, 1);
+				&& tmp._){
+					mesh.say(msg, (tmp._).via, 1);
 					tmp['##'] = msg['##'];
 					return;
 				}
@@ -1971,9 +1969,9 @@
 							(tmp = dup.s)[hash] = tmp[id];
 						}
 					}
-					(msg.mesh = function(){}).via = peer;
+					(msg._ = function(){}).via = peer;
 					if((tmp = msg['><'])){
-						msg.mesh.to = Type.obj.map(tmp.split(','), function(k,i,m){m(k,true)});
+						(msg._).to = Type.obj.map(tmp.split(','), function(k,i,m){m(k,true)});
 					}
 					if(msg.dam){
 						if(tmp = mesh.hear[msg.dam]){
@@ -1981,7 +1979,6 @@
 						}
 						return;
 					}
-          
 					ctx.on('in', msg);
 
 					return;
@@ -2012,7 +2009,7 @@
 					}
 					var tmp, wire = peer.wire || ((opt.wire) && opt.wire(peer)), msh, raw;// || open(peer, ctx); // TODO: Reopen!
 					if(!wire){ return }
-					msh = msg.mesh || empty;
+					msh = (msg._) || empty;
 					if(peer === msh.via){ return }
 					if(!(raw = msh.raw)){ raw = mesh.raw(msg) }
 					if((tmp = msg['@'])
@@ -2063,7 +2060,7 @@
 
 				mesh.raw = function(msg){
 					if(!msg){ return '' }
-					var dup = ctx.dup, msh = msg.mesh || {}, put, hash, tmp;
+					var dup = ctx.dup, msh = (msg._) || {}, put, hash, tmp;
 					if(tmp = msh.raw){ return tmp }
 					if(typeof msg === 'string'){ return msg }
 					if(msg['@'] && (tmp = msg.put)){

+ 128 - 27
public/lib/gundb/lib/les.js

@@ -13,28 +13,93 @@
 	// Garbage Collector for Gun
 	// Originally By: Collin Conrad (@masterex1000)
 
-	//NOTE: set to false is running from file in YOUR code
-	var USELOCALGUN = true; 
+	/**
+	 *
+	 * Usage: require the file in your application
+	 * 
+	 * Gun Params: these are passed to the new gun constructor
+	 *
+	 *  - gc_enable : enables the gc, good if you are running multiple instances of gun, etc... def. true
+	 *	- gc_delay	: sets the amount of time between attempted garbage collections in milliseconds
+	 *	- gc_info_enable : Enables or Disables the info printout
+	 *	- gc_info	: sets the ~ amount of time between info messages
+	 *				  this is checked everytime the gc is ran
+	 *	- gc_info_mini : this will use a smaller, less user friendly info printout
+	 *	- gc_importance_func : This will be the function used for finding the importance of a potental collect
+	 *							takes the form of func(timestamp, ctime, memoryUsageRatio) {return val}
+	 *							Collects when returned value is 100
+	 */
 	
-	//NOTE: adds some debug messages
+	//NOTE: set to false to use require for getting gun DEFUALT: false
+	var USELOCALGUN = false; 
+		
+	
+	//NOTE: adds some debug messages DEFUALT: false
 	var DEBUG = false;
 	
+	if(!(typeof window !== "undefined") && USELOCALGUN)
+		console.log("NOTE: You currently have LES.js set to use the 'local' file version of gun, This might crash if set wrong!");
 	
 	var Gun = (typeof window !== "undefined") ? window.Gun : (USELOCALGUN ? require('../gun') : require("gun"));
-	var ev = {};
-	var empty = {};
-
+	
+	//Removes a node from the garbage collection until next write
+	Gun.chain.gcDequeue = function() {
+		//console.log(this._.root.dequeueNode);
+		if(this._.root.dequeueNode) { // check that we actually have the dequeue command on this node
+			let ctx = this;
+		
+			this.get(function (soul) {
+				ctx._.root.dequeueNode(soul);
+			}, true);
+		}
+	}
+	
+	//Puts node at the front for garbage collection, NOTE: only collects when it is hit it's time
+	Gun.chain.gcCollect = function() {
+		if(this._.root.collectNode) { // check that we actually have the dequeue command on this node
+			let ctx = this;
+			
+			this.get(function (soul) {
+				ctx._.root.collectNode(soul);
+			}, true);
+		}
+	}
+	
 	Gun.on('opt', function(root) {
+		//Setup various options
+		
+		const gc_enable = root.opt.gc_enable ? root.opt.gc_enable : true;
+		const gc_delay = root.opt.gc_delay ? root.opt.gc_delay : 1000;
+		
+		const gc_info_enable  = root.opt.gc_info_enable  ? root.opt.gc_info_enable  : true;
+		const gc_info  = root.opt.gc_info  ? root.opt.gc_info  : 5000;
+		const gc_info_mini = root.opt.gc_info_mini ? root.opt.gc_info_mini : false;
+		
+		//This is long, but it works well
+		const calcRemoveImportance = root.opt.gc_importance_func ? root.opt.gc_importance_func : function (timestamp, ctime, memoryUsageRatio) {
+			var time = (ctime - timestamp) * 0.001;
+			return time * 10 * (memoryUsageRatio * memoryUsageRatio);
+		}
+		
+		if(DEBUG) console.log(root.opt);
+		
 		this.to.next(root);
+		
 		if (root.once)
 			return;
 		if (typeof process == 'undefined')
 			return
 		var mem = process.memoryUsage;
 
+		if(!gc_enable) // exit because the gc is disabled
+			return;
+		
 		if (!mem) //exit because we are in the browser
 			return;
 
+		var ev = {}; //stores the environment
+		var empty = {}; //An empty list used to prevent crashes
+		
 		//Figure out the most amount of memory we can use. TODO: make configurable?
 		ev.max = parseFloat(root.opt.memory || process.env.WEB_MEMORY || 512) * 0.8;
 
@@ -42,20 +107,29 @@
 		var nodesArray = []; //used to easily sort everything and store info about the nodes
 		var memoryUpdate = 0; // last time we printed the current memory stats
 
+		root.dequeueNode = (soul) => {  //forward the call to our gc
+			dequeueNode(soul);
+		}
+		
+		root.collectNode = (soul) => {  //forward the call to our gc
+			collectNode(soul);
+		}
+		
 		var check = function() {
 			ev.used = mem().rss / 1024 / 1024; //Contains the amt. of used ram in MB
 			setTimeout(function() { // So we can handle requests etc. before we start collecting
 				GC(ev.used / ev.max); // Calculate the memory ratio, and execute the garbage collector
+				//GC(0.99);
 			}, 1);
 		}
 		
-		setInterval(check, 1000); // set the garbage collector to run every second, TODO: make configurable
+		setInterval(check, gc_delay); // set the garbage collector to run every second
 		
-		//Executed every time a node gets modifyed
+		//Executed every time a node gets modified
 		root.on("put", function(e) {
 			var ctime = Date.now();
-			var souls = Object.keys(e.put || empty);
-			for (var i = 0; i < souls.length; i++) {
+			var souls = Object.keys(e.put || empty); // get all of the nodes in the update
+			for (var i = 0; i < souls.length; i++) { // iterate over them and add them
 				enqueueNode(souls[i], ctime);
 			}
 		});
@@ -67,10 +141,10 @@
 					return e[0] === soul;
 				});
 				if (index == -1) {
-					console.err("Something happened and the node '" + soul + "' won't get garbage collection unless the value is updated agian");
+					console.error("Something happened and the node '" + soul + "' won't get garbage collection unless the value is updated again");
 					return;
 				} else {
-					nodesArray.splice(index, 1); // remove the existing ref.
+					nodesArray.splice(index, 1); // remove the existing ref. faster than dequeue
 					nodesArray.push([soul, ctime]); // push the new instance
 				}
 			} else {
@@ -79,18 +153,50 @@
 			}
 		}
 
+		//Removes a node from the queue
+		function dequeueNode(soul) {
+			if (nodes[soul] == true) { //The node already exists in the queue
+				var index = nodesArray.findIndex(function(e) {
+					return e[0] === soul;
+				});
+				if (index != -1) {
+					//nodesArray.splice(index, 1); // remove the existing ref.
+					nodesArray.shift();
+					nodes[soul] = false; // store that we no longer have that node in the queue
+				}
+			}
+		}
+		
+		//Moves a node to the start of the queue
+		function collectNode(soul) {
+			if (nodes[soul] == true) { //The node already exists in the queue
+				var index = nodesArray.findIndex(function(e) {
+					return e[0] === soul;
+				});
+				if (index != -1) {
+					//nodesArray.splice(index, 1); // remove the existing ref.
+					nodesArray.shift(); // WAY faster than splice
+				}
+				nodesArray.unshift([soul, nodesArray[0][1]]); // create a new node with the next nodes time stamp
+				nodes[soul] = true; // store that we no longer have that node in the queue
+			}
+		}
+		
 		//The main garbage collecting routine
 		function GC(memRatio) {
 			var curTime = Date.now(); // get the current time
 
-			if (curTime - memoryUpdate >= 5000) {
-				console.log("|GC| %s | Current Memory Ratio: %d | Current Ram Usage %sMB | Nodes in Memory %s", new Date().toLocaleString(), round(memRatio, 2), round(ev.used, 2), Object.keys(root.graph || empty).length);
-				memoryUpdate = curTime;
+			if (gc_info_enable && curTime - memoryUpdate >= gc_info) { // check if we need to print info
+				if(!gc_info_mini)
+					console.log("|GC| %s | Current Memory Ratio: %d | Current Ram Usage %sMB | Nodes in Memory %s", new Date().toLocaleString(), round(memRatio, 2), round(ev.used, 2), Object.keys(root.graph || empty).length);
+				else
+					console.log("|GC| %s, Mem Ratio %d, Ram %sMB, Nodes in mem %s, Tracked Nodes %s", new Date().toLocaleString(), round(memRatio, 2), round(ev.used, 2), Object.keys(root.graph || empty).length, nodesArray.length);
+				memoryUpdate = curTime; // reset the last update time
 			}
 
-			var freed = 0;
+			var freed = 0; // Just a nice performance counter
 
-			while (nodesArray.length > 0) {
+			while (nodesArray.length > 0) { // iterate over all of our nodes
 				var soul = nodesArray[0][0];
 				var nts = nodesArray[0][1];
 				if (DEBUG)
@@ -99,21 +205,16 @@
 				if (calcRemoveImportance(nodesArray[0][1], curTime, memRatio) >= 100) {
 					root.gun.get(nodesArray[0][0]).off(); //Remove the node
 					delete nodes[nodesArray[0][0]]; // remove the lookup value
-					nodesArray.splice(0, 1);
-					freed++;
+					//nodesArray.splice(0, 1);
+					nodesArray.shift();
+					freed++; // add one to our perf counter
 				} else
-					break;
+					break; // Break out of the loop because we don't have any more nodes to free
 			}
 			if (freed > 0)
 				console.log("|GC| Removed %s nodes in %s seconds-----------------------------------------------------------------", freed, (Date.now() - curTime) * 0.001);
 		}
-
-		//Generates a number that, after it hits a threshold, the node gets removed
-		function calcRemoveImportance(timestamp, ctime, memoryUsageRatio) {
-			var time = (ctime - timestamp) * 0.001;
-			return time * 10 * (memoryUsageRatio * memoryUsageRatio)
-		}
-
+		
 		function round(value, decimals) { //a basic rounding function
 			return Number(Math.round(value + 'e' + decimals) + 'e-' + decimals);
 		}

+ 2 - 2
public/lib/gundb/lib/rindexed.js

@@ -57,7 +57,7 @@
         };
       }
       if(!db){
-        waitDbReady(doGet, 100, function(){
+        waitDbReady(doPut, 100, function(){
           var es = 'ERROR: Timeout: RAD IndexedDB not ready.';
           console.log(es);
           cb(es, undefined);
@@ -126,4 +126,4 @@
   } else {
     module.exports = Store;
   }
-}());
+}());

+ 2 - 7
public/lib/gundb/lib/store.js

@@ -3,16 +3,11 @@ var Gun = (typeof window !== "undefined")? window.Gun : require('../gun');
 Gun.on('create', function(root){
 	this.to.next(root);
 	var opt = root.opt, u;
-	if(typeof window !== "undefined"){
-		opt.window = window;
-	}
-	//if(true !== opt.radisk && (!opt.window && !process.env.RAD_ENV && !process.env.AWS_S3_BUCKET) && false !== opt.localStorage){ return }
-	//if(true !== opt.radisk){ return }
 	if(false === opt.radisk){ return }
-	var Radisk = (opt.window && opt.window.Radisk) || require('./radisk');
+	var Radisk = (Gun.window && Gun.window.Radisk) || require('./radisk');
 	var Radix = Radisk.Radix;
 
-	opt.store = opt.store || (!opt.window && require('./rfs')(opt));
+	opt.store = opt.store || (!Gun.window && require('./rfs')(opt));
 	var rad = Radisk(opt), esc = String.fromCharCode(27);
 
 	root.on('put', function(msg){

+ 14 - 14
public/lib/gundb/lib/webrtc.js

@@ -20,7 +20,7 @@
 		opt.RTCPeerConnection = rtcpc;
 		opt.RTCSessionDescription = rtcsd;
 		opt.RTCIceCandidate = rtcic;
-		opt.webrtc = opt.webrtc || {'iceServers': [
+		opt.rtc = opt.rtc || {'iceServers': [
       {url: 'stun:stun.l.google.com:19302'},
       {url: "stun:stun.sipgate.net:3478"},
       {url: "stun:stun.stunprotocol.org"},
@@ -28,33 +28,33 @@
       {url: "stun:217.10.68.152:10000"},
       {url: 'stun:stun.services.mozilla.com'} 
     ]};
-    opt.webrtc.dataChannel = opt.webrtc.dataChannel || {ordered: false, maxRetransmits: 2};
-    opt.webrtc.sdp = opt.webrtc.sdp || {mandatory: {OfferToReceiveAudio: false, OfferToReceiveVideo: false}};
+    opt.rtc.dataChannel = opt.rtc.dataChannel || {ordered: false, maxRetransmits: 2};
+    opt.rtc.sdp = opt.rtc.sdp || {mandatory: {OfferToReceiveAudio: false, OfferToReceiveVideo: false}};
 
 		var mesh = opt.mesh = opt.mesh || Gun.Mesh(root);
 		root.on('create', function(at){
 			this.to.next(at);
-			setTimeout(function(){ root.on('out', {webrtc: {id: opt.pid}}) },1); // announce ourself
+			setTimeout(function(){ root.on('out', {rtc: {id: opt.pid}}) },1); // announce ourself
 		});
 		root.on('in', function(msg){
-			if(msg.webrtc){ open(msg) }
+			if(msg.rtc){ open(msg) }
 			this.to.next(msg);
 		});
 
 		function open(msg){
-			var rtc = msg.webrtc, peer, tmp;
+			var rtc = msg.rtc, peer, tmp;
 			if(!rtc || !rtc.id){ return }
 			if(tmp = rtc.answer){
 				if(!(peer = opt.peers[rtc.id]) || peer.remoteSet){ return }
 				return peer.setRemoteDescription(peer.remoteSet = new opt.RTCSessionDescription(tmp)); 
 			}
 			if(tmp = rtc.candidate){
-				peer = opt.peers[rtc.id] || open({webrtc: {id: rtc.id}});
+				peer = opt.peers[rtc.id] || open({rtc: {id: rtc.id}});
 				return peer.addIceCandidate(new opt.RTCIceCandidate(tmp));
 			}
 			if(opt.peers[rtc.id]){ return }
-			(peer = new opt.RTCPeerConnection(opt.webrtc)).id = rtc.id;
-			var wire = peer.wire = peer.createDataChannel('dc', opt.webrtc.dataChannel);
+			(peer = new opt.RTCPeerConnection(opt.rtc)).id = rtc.id;
+			var wire = peer.wire = peer.createDataChannel('dc', opt.rtc.dataChannel);
 			mesh.hi(peer);
 			wire.onclose = function(){
 				mesh.bye(peer);
@@ -77,7 +77,7 @@
 			};
 			peer.onicecandidate = function(e){ // source: EasyRTC!
         if(!e.candidate){ return }
-        root.on('out', {'@': msg['#'], webrtc: {candidate: e.candidate, id: opt.pid}});
+        root.on('out', {'@': msg['#'], rtc: {candidate: e.candidate, id: opt.pid}});
 			}
 			peer.ondatachannel = function(e){
 				var rc = e.channel;
@@ -89,14 +89,14 @@
 				peer.setRemoteDescription(new opt.RTCSessionDescription(tmp)); 
 				peer.createAnswer(function(answer){
 					peer.setLocalDescription(answer);
-					root.on('out', {'@': msg['#'], webrtc: {answer: answer, id: opt.pid}});
-				}, function(){}, opt.webrtc.sdp);
+					root.on('out', {'@': msg['#'], rtc: {answer: answer, id: opt.pid}});
+				}, function(){}, opt.rtc.sdp);
 				return;
 			}
 			peer.createOffer(function(offer){
 				peer.setLocalDescription(offer);
-				root.on('out', {'@': msg['#'], webrtc: {offer: offer, id: opt.pid}});
-			}, function(){}, opt.webrtc.sdp);
+				root.on('out', {'@': msg['#'], rtc: {offer: offer, id: opt.pid}});
+			}, function(){}, opt.rtc.sdp);
 			return peer;
 		}
 	});

+ 2 - 2
public/lib/gundb/nts.js

@@ -31,7 +31,7 @@
 
 		Gun.state.drift = Gun.state.drift || 0;
 		setTimeout(function ping(){
-			var NTS = {}, ack = Gun.text.random(), msg = {'#': ack, nts: true, gun: ctx.gun};
+			var NTS = {}, ack = Gun.text.random(), msg = {'#': ack, nts: true};
 			NTS.start = Gun.state();
 			ask[ack] = function(at){
 				NTS.end = Gun.state();
@@ -46,4 +46,4 @@
 		}, 1);
 	});
 	// test by opening up examples/game/nts.html on devices that aren't NTP synced.
-}());
+}());

+ 32 - 45
public/lib/gundb/sea.js

@@ -1108,11 +1108,11 @@
 
     // signature handles data output, it is a proxy to the security function.
     function signature(msg){
-      if(msg.user){
+      if((msg._||noop).user){
         return this.to.next(msg);
       }
       var ctx = this.as;
-      msg.user = ctx.user;
+      (msg._||(msg._=function(){})).user = ctx.user;
       security.call(this, msg);
     }
 
@@ -1153,9 +1153,9 @@
             each.pubs(val, key, node, soul); return;
           }
           if('~' === soul.slice(0,1) && 2 === (tmp = soul.slice(1)).split('.').length){ // special case, account data for a public key.
-            each.pub(val, key, node, soul, tmp, msg.user); return;
+            each.pub(val, key, node, soul, tmp, (msg._||noop).user); return;
           }
-          each.any(val, key, node, soul, msg.user); return;
+          each.any(val, key, node, soul, (msg._||noop).user); return;
           return each.end({err: "No other data allowed!"});
         };
         each.alias = function(val, key, node, soul){ // Example: {_:#~@, ~@alice: {#~@alice}}
@@ -1174,7 +1174,7 @@
             return each.end({err: "Account must match!"});
           }
           check['user'+soul+key] = 1;
-          if(msg.I && user && user.is && pub === user.is.pub){
+          if(Gun.is(msg.$) && user && user.is && pub === user.is.pub){
             SEA.sign(SEA.opt.prep(tmp = SEA.opt.parse(val), key, node, soul), (user._).sea, function(data){ var rel;
               if(u === data){ return each.end({err: SEA.err || 'Pub signature fail.'}) }
               if(rel = Gun.val.link.is(val)){
@@ -1199,20 +1199,12 @@
           });
         };
         each.any = function(val, key, node, soul, user){ var tmp, pub;
-          if(!user || !user.is){
-            if(tmp = SEA.opt.pub(soul)){
-              check['any'+soul+key] = 1;
-              SEA.verify(SEA.opt.pack(val,key,node,soul), pub = tmp, function(data){ var rel;
-                data = SEA.opt.unpack(data, key, node);
-                if(u === data){ return each.end({err: "Mismatched owner on '" + key + "'."}) } // thanks @rogowski !
-                if((rel = Gun.val.link.is(data)) && pub === SEA.opt.pub(rel)){
-                  (at.sea.own[rel] = at.sea.own[rel] || {})[pub] = true;
-                }
-                check['any'+soul+key] = 0;
-                each.end({ok: 1});
-              });
+          if(!(pub = SEA.opt.pub(soul))){
+            if(at.opt.secure){
+              each.end({err: "Soul is missing public key at '" + key + "'."});
               return;
             }
+            // TODO: Ask community if should auto-sign non user-graph data.
             check['any'+soul+key] = 1;
             at.on('secure', function(msg){ this.off();
               check['any'+soul+key] = 0;
@@ -1222,38 +1214,33 @@
             //each.end({err: "Data cannot be modified."});
             return;
           }
-          if(!(tmp = SEA.opt.pub(soul))){
-            if(at.opt.secure){
-              each.end({err: "Soul is missing public key at '" + key + "'."});
+          if(Gun.is(msg.$) && user && user.is && pub === user.is.pub){
+            /*var other = Gun.obj.map(at.sea.own[soul], function(v, p){
+              if((user.is||{}).pub !== p){ return p }
+            });
+            if(other){
+              each.any(val, key, node, soul);
               return;
-            }
-            // TODO: Ask community if should auto-sign non user-graph data.
-            check['any'+soul+key] = 0;
-            each.end({ok: 1});
-            return;
-          }
-          if(!msg.I){ // only sign data put out from this instance.
-            each.any(val, key, node, soul);
-            return;
-          }
-          if((pub = tmp) !== (user.is||noop).pub){
-            each.any(val, key, node, soul);
+            }*/
+            check['any'+soul+key] = 1;
+            SEA.sign(SEA.opt.prep(tmp = SEA.opt.parse(val), key, node, soul), (user._).sea, function(data){
+              if(u === data){ return each.end({err: 'My signature fail.'}) }
+              node[key] = JSON.stringify({':': SEA.opt.unpack(data.m), '~': data.s});
+              check['any'+soul+key] = 0;
+              each.end({ok: 1});
+            }, {check: SEA.opt.pack(tmp, key, node, soul), raw: 1});
             return;
           }
-          /*var other = Gun.obj.map(at.sea.own[soul], function(v, p){
-            if((user.is||{}).pub !== p){ return p }
-          });
-          if(other){
-            each.any(val, key, node, soul);
-            return;
-          }*/
           check['any'+soul+key] = 1;
-          SEA.sign(SEA.opt.prep(tmp = SEA.opt.parse(val), key, node, soul), (user._).sea, function(data){
-            if(u === data){ return each.end({err: 'My signature fail.'}) }
-            node[key] = JSON.stringify({':': SEA.opt.unpack(data.m), '~': data.s});
+          SEA.verify(SEA.opt.pack(val,key,node,soul), pub, function(data){ var rel;
+            data = SEA.opt.unpack(data, key, node);
+            if(u === data){ return each.end({err: "Mismatched owner on '" + key + "'."}) } // thanks @rogowski !
+            if((rel = Gun.val.link.is(data)) && pub === SEA.opt.pub(rel)){
+              (at.sea.own[rel] = at.sea.own[rel] || {})[pub] = true;
+            }
             check['any'+soul+key] = 0;
             each.end({ok: 1});
-          }, {check: SEA.opt.pack(tmp, key, node, soul), raw: 1});
+          });
         }
         each.end = function(ctx){ // TODO: Can't you just switch this to each.end = cb?
           if(each.err){ return }
@@ -1265,7 +1252,7 @@
           if(Gun.obj.map(check, function(no){
             if(no){ return true }
           })){ return }
-          msg.user = at.user; // already been through firewall, does not need to again on out.
+          (msg._||{}).user = at.user || security; // already been through firewall, does not need to again on out.
           to.next(msg);
         };
         Gun.obj.map(msg.put, each.node);
@@ -1306,7 +1293,7 @@
       }
     }
     SEA.opt.shuffle_attack = 1546329600000; // Jan 1, 2019
-    var noop = {}, u;
+    var noop = function(){}, u;
     var fl = Math.floor; // TODO: Still need to fix inconsistent state issue.
     var rel_is = Gun.val.rel.is;
     // TODO: Potential bug? If pub/priv key starts with `-`? IDK how possible.