Skip to content

Instantly share code, notes, and snippets.

@formula1
Last active August 29, 2015 14:19
Show Gist options
  • Save formula1/b56d74bc448ff6fd353d to your computer and use it in GitHub Desktop.
Save formula1/b56d74bc448ff6fd353d to your computer and use it in GitHub Desktop.
One to Many, Recursive
/*
Cone
*/
var SortedBacklog = require("./SortedBacklog");
function Cone(originator,child_limit,stay_alive){
this.stay_alive = (typeof stayalive === "undefined")?true:stay_alive;
this.child_limit = child_limit||7;
this.originator = originator;
this.backlog = new SortedBacklog();
}
Cone.prototype.enter = function(item){
var parent = this.backlog.getAtIndex(0);
if(parent.children.length === this.child_limit -1){
this.backlog.remove(parent);
}
item.parent = parent;
item.children = [];
parent.children.push(item);
this.backlog.push(item);
this.emit("enter",item);
};
Cone.prototype.exit = function(item,next){
if(item.children.length > 0){
this.replace(item);
}else{
this.parentCanGetMore(item);
}
};
Cone.prototype.replace = function(oldItem){
//Need an easy to use method of finding the last item and removing it
var newestItem = this.backlog.getAtIndex(-1);
this.backlog.remove(newestItem);
newestItem.children = oldItem.children;
newestItem.parent = oldItem.parent;
//need an easy to use method of replacing the backlog
this.backlog.set(oldItem,newestItem);
this.emit("replace",oldItem,newestItem);
};
Cone.prototype.parentCanGetMore = function(item){
var parent = item.parent;
parent.children.splice(parent.children.indexOf(item),1);
this.backlog.remove(item);
this.backlog.insert(parent);
this.emit("exit",item);
};
Cone.prototype.stdListeners = function(){
var self = this;
this.on("replace",function(oldItem,newItem){
self.removeAllRelatonships(newItem, function(err){
if(err) throw err;
async.each(newItem.children,function(child,next){
self.addRelationship(newItem,child,next);
},function(err){
if(err) throw err;
});
});
});
this.on("exit",function(item){
//its likely that if the user disconnected from us,
//they likely disconnected from The other party.
//just in case though, we most likely want to remove the relationship
//Since it may cause the parent to have more children than they should
self.removeRelationship(item.parent,item);
});
this.on("enter",function(item){
self.addRelationship(item.parent,item,function(err){
if(err) throw err;
item.get("watcher_limit",function(err,limit){
if(err) throw err;
item.limit = limit;
});
});
});
};
Cone.prototype.removeAllRelationships = function(item,next){
throw new Error("removeRelationships is an abstract that should be overridden");
item.send("remove_parent");
var t, l;
l = function(){
clearTimeout(t);
next();
};
t = setTimeout(function(){
item.removeListener("parent_removed",l);
next(new Error("timed out"));
},10*1000);
item.on("parent_removed",l);
};
Cone.prototype.removeRelationship = function(parent,child,next){
throw new Error("removeRelationships is an abstract that should be overridden");
parent.send("remove_child",child._id);
var t, l;
l = function(id){
if(id !== child._id) return;
clearTimeout(t);
next();
};
t = setTimeout(function(){
item.removeListener("child_removed",l);
next(new Error("timed out"));
},10*1000);
item.on("parent_removed",l);
};
Cone.prototype.addRelationship = function(parent,child,next){
throw new Error("addRelationship is an abstract that should be overridden");
return child.getOffer()
.then(function(offer){
return parent.getAccept(offer);
}).then(function(accept){
return child.finalize(accept);
});
};
function SortedBacklog(){
this.obj = {};
var isDirty = false;
var cachedKeys = [];
this.resetKeys = function(){
isDirty = true;
};
Object.defineProperty(this,keys,{
get:function(){
if(isDirty){
cachedKeys = Object.keys(this.obj);
cachedKeys.sort(function(a,b){
return parseInt(a.time) - parseInt(b.time);
});
}
return cachedKeys;
},set:function(y){
var first = cachedKeys[0];
if(y < first){
cachedKeys.unshift(y);
return;
}
var last = cachedKeys[cachedKeys.length-1];
if(y > last){
cachedKeys.push(y);
return;
}
self.resetKeys();
}
});
}
SortedBacklog.prototype.getAtIndex = function(index){
if(index == -1){
index = this.keys.length -1;
}
return this.obj[keys[index]];
};
SortedBacklog.prototype.push = function(item){
item.time = Date.now();
this.obj[item.time] = item;
this.keys = item.time;
};
SortedBacklog.prototype.insert = function(item){
if(!("time" in item)) throw new Error("cannot insert an item without a time");
if(item.time in this.obj){
if(this.obj[item.time] != item) throw new Error("inserting a duplicant key");
return console.warn("inserting the same item twice");
}
this.obj[item.time] = item;
this.keys = item.time;
};
SortedBacklog.prototype.set = function(oldItem,newItem){
newItem.time = oldItem.time;
this.obj[oldItem.time] = newItem;
};
SortedBacklog.prototype.remove = function(item){
delete this.obj[keys[0]];
this.resetKeys();
return ret;
};
module.exports = SortedBacklog;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment