on.js 3.63 KB

var Gun = require('./index');
Gun.chain.on = function(tag, arg, eas, as){
	var gun = this, at = gun._, tmp, act, off;
	if(typeof tag === 'string'){
		if(!arg){ return at.on(tag) }
		act = at.on(tag, arg, eas || at, as);
		if(eas && eas.$){
			(eas.subs || (eas.subs = [])).push(act);
		}
		return gun;
	}
	var opt = arg;
	opt = (true === opt)? {change: true} : opt || {};
	opt.at = at;
	opt.ok = tag;
	//opt.last = {};
	gun.get(ok, opt); // TODO: PERF! Event listener leak!!!?
	return gun;
}

function ok(msg, ev){ var opt = this;
	var gun = msg.$, at = (gun||{})._ || {}, data = at.put || msg.put, cat = opt.at, tmp;
	if(u === data){
		return;
	}
	if(tmp = msg.$$){
		tmp = (msg.$$._);
		if(u === tmp.put){
			return;
		}
		data = tmp.put;
	}
	if(opt.change){ // TODO: BUG? Move above the undef checks?
		data = msg.put;
	}
	// DEDUPLICATE // TODO: NEEDS WORK! BAD PROTOTYPE
	//if(tmp.put === data && tmp.get === id && !Gun.node.soul(data)){ return }
	//tmp.put = data;
	//tmp.get = id;
	// DEDUPLICATE // TODO: NEEDS WORK! BAD PROTOTYPE
	//at.last = data;
	if(opt.as){
		opt.ok.call(opt.as, msg, ev);
	} else {
		opt.ok.call(gun, data, msg.get, msg, ev);
	}
}

Gun.chain.val = function(cb, opt){
	Gun.log.once("onceval", "Future Breaking API Change: .val -> .once, apologies unexpected.");
	return this.once(cb, opt);
}
Gun.chain.once = function(cb, opt){
	var gun = this, at = gun._, data = at.put;
	if(0 < at.ack && u !== data){
		(cb || noop).call(gun, data, at.get);
		return gun;
	}
	if(cb){
		(opt = opt || {}).ok = cb;
		opt.at = at;
		opt.out = {'#': Gun.text.random(9)};
		gun.get(val, {as: opt});
		opt.async = true; //opt.async = at.stun? 1 : true;
	} else {
		Gun.log.once("valonce", "Chainable val is experimental, its behavior and API may change moving forward. Please play with it and report bugs and ideas on how to improve it.");
		var chain = gun.chain();
		chain._.nix = gun.once(function(){
			chain._.on('in', gun._);
		});
		return chain;
	}
	return gun;
}

function val(msg, eve, to){
	if(!msg.$){ eve.off(); return }
	var opt = this.as, cat = opt.at, gun = msg.$, at = gun._, data = at.put || msg.put, link, tmp;
	if(tmp = msg.$$){
		link = tmp = (msg.$$._);
		if(u !== link.put){
			data = link.put;
		}
	}
	if((tmp = eve.wait) && (tmp = tmp[at.id])){ clearTimeout(tmp) }
	eve.ack = (eve.ack||0)+1;
	if(!to && u === data && eve.ack <= (opt.acks || Object.keys(at.root.opt.peers).length)){ return }
	if((!to && (u === data || at.soul || at.link || (link && !(0 < link.ack))))
	|| (u === data && (tmp = Object.keys(at.root.opt.peers).length) && (!to && (link||at).ack < tmp))){
		tmp = (eve.wait = {})[at.id] = setTimeout(function(){
			val.call({as:opt}, msg, eve, tmp || 1);
		}, opt.wait || 99);
		return;
	}
	if(link && u === link.put && (tmp = rel.is(data))){ data = Gun.node.ify({}, tmp) }
	eve.rid? eve.rid(msg) : eve.off();
	opt.ok.call(gun || opt.$, data, msg.get);
}

Gun.chain.off = function(){
	// make off more aggressive. Warning, it might backfire!
	var gun = this, at = gun._, tmp;
	var cat = at.back;
	if(!cat){ return }
	at.ack = 0; // so can resubscribe.
	if(tmp = cat.next){
		if(tmp[at.get]){
			obj_del(tmp, at.get);
		} else {

		}
	}
	if(tmp = cat.ask){
		obj_del(tmp, at.get);
	}
	if(tmp = cat.put){
		obj_del(tmp, at.get);
	}
	if(tmp = at.soul){
		obj_del(cat.root.graph, tmp);
	}
	if(tmp = at.map){
		obj_map(tmp, function(at){
			if(at.link){
				cat.root.$.get(at.link).off();
			}
		});
	}
	if(tmp = at.next){
		obj_map(tmp, function(neat){
			neat.$.off();
		});
	}
	at.on('off', {});
	return gun;
}
var obj = Gun.obj, obj_map = obj.map, obj_has = obj.has, obj_del = obj.del, obj_to = obj.to;
var rel = Gun.val.link;
var empty = {}, noop = function(){}, u;