');
+ this.$body.append(this.$elm);
+ remove = function(event, modal) { modal.elm.remove(); };
+ this.showSpinner();
+ el.trigger($.modal.AJAX_SEND);
+ $.get(target).done(function(html) {
+ if (!$.modal.isActive()) return;
+ el.trigger($.modal.AJAX_SUCCESS);
+ var current = getCurrent();
+ current.$elm.empty().append(html).on($.modal.CLOSE, remove);
+ current.hideSpinner();
+ current.open();
+ el.trigger($.modal.AJAX_COMPLETE);
+ }).fail(function() {
+ el.trigger($.modal.AJAX_FAIL);
+ var current = getCurrent();
+ current.hideSpinner();
+ modals.pop(); // remove expected modal from the list
+ el.trigger($.modal.AJAX_COMPLETE);
+ });
+ }
+ } else {
+ this.$elm = el;
+ this.$body.append(this.$elm);
+ this.open();
+ }
+ };
+
+ $.modal.prototype = {
+ constructor: $.modal,
+
+ open: function() {
+ var m = this;
+ this.block();
+ if(this.options.doFade) {
+ setTimeout(function() {
+ m.show();
+ }, this.options.fadeDuration * this.options.fadeDelay);
+ } else {
+ this.show();
+ }
+ $(document).off('keydown.modal').on('keydown.modal', function(event) {
+ var current = getCurrent();
+ if (event.which == 27 && current.options.escapeClose) current.close();
+ });
+ if (this.options.clickClose)
+ this.$blocker.click(function(e) {
+ if (e.target==this)
+ $.modal.close();
+ });
+ },
+
+ close: function() {
+ modals.pop();
+ this.unblock();
+ this.hide();
+ if (!$.modal.isActive())
+ $(document).off('keydown.modal');
+ },
+
+ block: function() {
+ this.$elm.trigger($.modal.BEFORE_BLOCK, [this._ctx()]);
+ this.$body.css('overflow','hidden');
+ this.$blocker = $('
').appendTo(this.$body);
+ selectCurrent();
+ if(this.options.doFade) {
+ this.$blocker.css('opacity',0).animate({opacity: 1}, this.options.fadeDuration);
+ }
+ this.$elm.trigger($.modal.BLOCK, [this._ctx()]);
+ },
+
+ unblock: function(now) {
+ if (!now && this.options.doFade)
+ this.$blocker.fadeOut(this.options.fadeDuration, this.unblock.bind(this,true));
+ else {
+ this.$blocker.children().appendTo(this.$body);
+ this.$blocker.remove();
+ this.$blocker = null;
+ selectCurrent();
+ if (!$.modal.isActive())
+ this.$body.css('overflow','');
+ }
+ },
+
+ show: function() {
+ this.$elm.trigger($.modal.BEFORE_OPEN, [this._ctx()]);
+ if (this.options.showClose) {
+ this.closeButton = $('
' + this.options.closeText + '');
+ this.$elm.append(this.closeButton);
+ }
+ this.$elm.addClass(this.options.modalClass).appendTo(this.$blocker);
+ if(this.options.doFade) {
+ this.$elm.css('opacity',0).show().animate({opacity: 1}, this.options.fadeDuration);
+ } else {
+ this.$elm.show();
+ }
+ this.$elm.trigger($.modal.OPEN, [this._ctx()]);
+ },
+
+ hide: function() {
+ this.$elm.trigger($.modal.BEFORE_CLOSE, [this._ctx()]);
+ if (this.closeButton) this.closeButton.remove();
+ var _this = this;
+ if(this.options.doFade) {
+ this.$elm.fadeOut(this.options.fadeDuration, function () {
+ _this.$elm.trigger($.modal.AFTER_CLOSE, [_this._ctx()]);
+ });
+ } else {
+ this.$elm.hide(0, function () {
+ _this.$elm.trigger($.modal.AFTER_CLOSE, [_this._ctx()]);
+ });
+ }
+ this.$elm.trigger($.modal.CLOSE, [this._ctx()]);
+ },
+
+ showSpinner: function() {
+ if (!this.options.showSpinner) return;
+ this.spinner = this.spinner || $('
')
+ .append(this.options.spinnerHtml);
+ this.$body.append(this.spinner);
+ this.spinner.show();
+ },
+
+ hideSpinner: function() {
+ if (this.spinner) this.spinner.remove();
+ },
+
+ //Return context for custom events
+ _ctx: function() {
+ return { elm: this.$elm, $blocker: this.$blocker, options: this.options };
+ }
+ };
+
+ $.modal.close = function(event) {
+ if (!$.modal.isActive()) return;
+ if (event) event.preventDefault();
+ var current = getCurrent();
+ current.close();
+ return current.$elm;
+ };
+
+ // Returns if there currently is an active modal
+ $.modal.isActive = function () {
+ return modals.length > 0;
+ }
+
+ $.modal.defaults = {
+ closeExisting: true,
+ escapeClose: true,
+ clickClose: true,
+ closeText: 'Close',
+ closeClass: '',
+ modalClass: "modal",
+ spinnerHtml: null,
+ showSpinner: true,
+ showClose: true,
+ fadeDuration: null, // Number of milliseconds the fade animation takes.
+ fadeDelay: 1.0 // Point during the overlay's fade-in that the modal begins to fade in (.5 = 50%, 1.5 = 150%, etc.)
+ };
+
+ // Event constants
+ $.modal.BEFORE_BLOCK = 'modal:before-block';
+ $.modal.BLOCK = 'modal:block';
+ $.modal.BEFORE_OPEN = 'modal:before-open';
+ $.modal.OPEN = 'modal:open';
+ $.modal.BEFORE_CLOSE = 'modal:before-close';
+ $.modal.CLOSE = 'modal:close';
+ $.modal.AFTER_CLOSE = 'modal:after-close';
+ $.modal.AJAX_SEND = 'modal:ajax:send';
+ $.modal.AJAX_SUCCESS = 'modal:ajax:success';
+ $.modal.AJAX_FAIL = 'modal:ajax:fail';
+ $.modal.AJAX_COMPLETE = 'modal:ajax:complete';
+
+ $.fn.modal = function(options){
+ if (this.length === 1) {
+ new $.modal(this, options);
+ }
+ return this;
+ };
+
+ // Automatically bind links with rel="modal:close" to, well, close the modal.
+ $(document).on('click.modal', 'a[rel="modal:close"]', $.modal.close);
+ $(document).on('click.modal', 'a[rel="modal:open"]', function(event) {
+ event.preventDefault();
+ $(this).modal();
+ });
+})(jQuery);
diff --git a/swarm/network/kademlia/kademlia.go b/swarm/network/kademlia/kademlia.go
index 880de9b4d9..602db1445d 100644
--- a/swarm/network/kademlia/kademlia.go
+++ b/swarm/network/kademlia/kademlia.go
@@ -21,6 +21,7 @@ const (
var (
purgeInterval = 42 * time.Hour
initialRetryInterval = 42 * 100 * time.Millisecond
+ maxIdleInterval = 42 * 10 * time.Second
)
type KadParams struct {
@@ -126,12 +127,18 @@ func (self *Kademlia) On(node Node, cb func(*NodeRecord, Node) error) (err error
bucket := self.buckets[index]
// if bucket is full insertion replaces the worst node
// TODO: give priority to peers with active traffic
- if worst, pos := bucket.insert(node); worst != nil {
- glog.V(logger.Info).Infof("[KΛÐ]: replace node %v (%d) with node %v", worst, pos, node)
- return
+ replaced, err := bucket.insert(node)
+ if err != nil {
+ glog.V(logger.Debug).Infof("[KΛÐ]: node %v not needed: %v", node, err)
+ return err
// no prox adjustment needed
// do not change count
}
+ if replaced != nil {
+ glog.V(logger.Debug).Infof("[KΛÐ]: node %v replaced by %v ", replaced, node)
+ return
+ }
+ // new node added
glog.V(logger.Info).Infof("[KΛÐ]: add node %v to table", node)
self.count++
self.setProxLimit(index, false)
@@ -327,17 +334,13 @@ func (h *nodesByDistance) push(node Node, max int) {
// insert adds a peer to a bucket either by appending to existing items if
// bucket length does not exceed bucketSize, or by replacing the worst
// Node in the bucket
-func (self *bucket) insert(node Node) (dropped Node, pos int) {
+func (self *bucket) insert(node Node) (replaced Node, err error) {
self.lock.Lock()
defer self.lock.Unlock()
if len(self.nodes) >= self.size { // >= allows us to add peers beyond the bucketsize limitation
- dropped, pos = self.worstNode()
- if dropped != nil {
- self.nodes[pos] = node
- glog.V(logger.Info).Infof("[KΛÐ] dropping node %v (%d)", dropped, pos)
- dropped.Drop()
- return
- }
+ // dev p2p kicks out nodes idle for > 30 s, so here we never replace nodes if
+ // bucket is full
+ return nil, fmt.Errorf("bucket full")
}
self.nodes = append(self.nodes, node)
return
@@ -349,20 +352,6 @@ func (self *bucket) length(node Node) int {
return len(self.nodes)
}
-// worst expunges the single worst node in a row, where worst entry is the node
-// that has been inactive for the longests time
-func (self *bucket) worstNode() (node Node, pos int) {
- var oldest time.Time
- for p, n := range self.nodes {
- if (oldest == time.Time{}) || !oldest.Before(n.LastActive()) {
- oldest = n.LastActive()
- node = n
- pos = p
- }
- }
- return
-}
-
/*
Taking the proximity order relative to a fix point x classifies the points in
the space (n byte long byte sequences) into bins. Items in each are at
diff --git a/swarm/network/protocol.go b/swarm/network/protocol.go
index 67d25ed8c9..6f27f68b26 100644
--- a/swarm/network/protocol.go
+++ b/swarm/network/protocol.go
@@ -190,7 +190,7 @@ func run(requestDb *storage.LDBDatabase, depo StorageHandler, backend bind.Backe
return
}
-// may need to implement protocol drop only? don't want to kick off the peer
+// TODO: may need to implement protocol drop only? don't want to kick off the peer
// if they are useful for other protocols
func (self *bzz) Drop() {
self.peer.Disconnect(p2p.DiscSubprotocolError)