diff --git a/index.js b/index.js index 647be5395..e49c2fcc9 100644 --- a/index.js +++ b/index.js @@ -223,6 +223,7 @@ class Hypercore extends EventEmitter { const onseq = opts.onseq === undefined ? this.onseq : opts.onseq const timeout = opts.timeout === undefined ? this.timeout : opts.timeout const weak = opts.weak === undefined ? this.weak : opts.weak + const active = opts.active === undefined ? this._active : opts.active const Clz = opts.class || Hypercore const s = new Clz(null, this.key, { ...opts, @@ -232,6 +233,7 @@ class Hypercore extends EventEmitter { timeout, writable, weak, + active, parent: this }) @@ -415,6 +417,8 @@ class Hypercore extends EventEmitter { await this.core.setManifest(createManifest(opts.manifest)) } + if (this.state !== this.core.state) this._active = false + this.core.replicator.updateActivity(this._active ? 1 : 0) this.opened = true diff --git a/lib/replicator.js b/lib/replicator.js index 4c2517f11..77f8838ee 100644 --- a/lib/replicator.js +++ b/lib/replicator.js @@ -1541,7 +1541,7 @@ module.exports = class Replicator { clearTimeout(this._downloadingTimer) if (this.destroyed) return - if (downloading || this._notDownloadingLinger === 0) { + if (downloading || this._notDownloadingLinger === 0 || !this.peers.length) { this.setDownloadingNow(downloading) return } @@ -2461,6 +2461,8 @@ module.exports = class Replicator { } _makePeer (protomux) { + if (!this.downloading) return false + const replicator = this if (protomux.opened({ protocol: 'hypercore/alpha', id: this.core.discoveryKey })) return onnochannel() diff --git a/test/replicate.js b/test/replicate.js index 298bc0f23..b7bcd6bee 100644 --- a/test/replicate.js +++ b/test/replicate.js @@ -132,6 +132,112 @@ test('basic downloading is set immediately after ready', async function (t) { }) }) +test('basic session on inactive core is inactive', async function (t) { + t.plan(5) + + const createA = await createStored(t) + const a = await createA() + + a.on('ready', function () { + t.ok(a.core.replicator.downloading) + }) + + const createB = await createStored(t) + const b = await createB({ active: false }) + + b.on('ready', function () { + t.absent(b.core.replicator.downloading) + + const c = b.session() + t.teardown(() => c.close()) + + c.on('ready', function () { + t.absent(b.core.replicator.downloading) + t.absent(c.core.replicator.downloading) + + const d = c.session({ active: true }) + t.teardown(() => d.close()) + + d.on('ready', function () { + t.ok(d.core.replicator.downloading) + }) + }) + }) + + t.teardown(async () => { + await a.close() + await b.close() + }) +}) + +test('basic named session is always inactive', async function (t) { + t.plan(4) + + const createA = await createStored(t) + const a = await createA() + + a.on('ready', function () { + t.ok(a.core.replicator.downloading) + }) + + const createB = await createStored(t) + const b = await createB({ + notDownloadingLinger: 0 // replicator activity updates immediately + }) + + b.on('ready', function () { + t.ok(b.core.replicator.downloading) + + const c = b.session({ name: 'named' }) + t.teardown(() => c.close()) + + c.on('ready', async function () { + b.setActive(false) + + t.absent(b.core.replicator.downloading) + t.absent(c.core.replicator.downloading) + }) + }) + + t.teardown(async () => { + await a.close() + await b.close() + }) +}) + +test('basic toggle active with existing connection', async function (t) { + t.plan(4) + + const a = await create(t) + await a.ready() + + const b = await create(t, a.key, { active: false }) + + await b.ready() + + t.absent(b.core.replicator.downloading) + + replicate(a, b, t) + + await a.append('a1') + + setTimeout(() => { + t.is(b.length, 0) + + b.setActive(true) + t.ok(b.core.replicator.downloading) + + b.on('append', () => { + t.is(b.length, 1) + }) + }, 1000) + + t.teardown(async () => { + await a.close() + await b.close() + }) +}) + test('basic replication from fork', async function (t) { const a = await create(t)