From a0f2c3ee107508e406a4a41cbda76ecd2d3f0d8f Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sat, 25 Sep 2021 18:17:50 +0900 Subject: Discover frames on search by count of connections When a tab switches pages quickly, a disconnect event on top frame is sometime delivered after second connect event. In addition, `tabs.onUpdated()` event is independent on port connection event. Now the background script finds alive frames by only port connection. --- src/background/Application.ts | 1 - .../repositories/ReadyFrameRepository.ts | 37 ++++++++++++---------- src/background/usecases/ReadyFrameUseCase.ts | 18 ----------- test/background/mock/MockReadyFrameRepository.ts | 4 --- .../repositories/ReadyFrameRepository.test.ts | 13 ++++++-- 5 files changed, 31 insertions(+), 42 deletions(-) delete mode 100644 src/background/usecases/ReadyFrameUseCase.ts diff --git a/src/background/Application.ts b/src/background/Application.ts index c7bcc42..b439d19 100644 --- a/src/background/Application.ts +++ b/src/background/Application.ts @@ -31,7 +31,6 @@ export default class Application { browser.tabs.onUpdated.addListener((tabId: number, info) => { if (info.status == "loading") { - this.frameRepository.clearFrameIds(tabId); this.findRepository.deleteLocalState(tabId); } }); diff --git a/src/background/repositories/ReadyFrameRepository.ts b/src/background/repositories/ReadyFrameRepository.ts index aa5d986..c993858 100644 --- a/src/background/repositories/ReadyFrameRepository.ts +++ b/src/background/repositories/ReadyFrameRepository.ts @@ -2,11 +2,9 @@ import MemoryStorage from "../infrastructures/MemoryStorage"; const REPOSITORY_KEY = "readyFrameRepository"; -type State = { [tabId: number]: number[] }; +type State = { [tabId: number]: { [frameId: number]: number } }; export default interface ReadyFrameRepository { - clearFrameIds(tabId: number): Promise; - addFrameId(tabId: number, frameId: number): Promise; removeFrameId(tabId: number, frameId: number): Promise; @@ -21,22 +19,14 @@ export class ReadyFrameRepositoryImpl implements ReadyFrameRepository { this.cache = new MemoryStorage(); } - clearFrameIds(tabId: number): Promise { - let state: State | undefined = this.cache.get(REPOSITORY_KEY); - if (typeof state === "undefined") { - state = {}; - } - delete state[tabId]; - this.cache.set(REPOSITORY_KEY, state); - return Promise.resolve(); - } - addFrameId(tabId: number, frameId: number): Promise { let state: State | undefined = this.cache.get(REPOSITORY_KEY); if (typeof state === "undefined") { state = {}; } - state[tabId] = (state[tabId] || []).concat(frameId).sort(); + const tab = state[tabId] || {}; + tab[frameId] = (tab[frameId] || 0) + 1; + state[tabId] = tab; this.cache.set(REPOSITORY_KEY, state); return Promise.resolve(); } @@ -50,7 +40,15 @@ export class ReadyFrameRepositoryImpl implements ReadyFrameRepository { if (typeof ids === "undefined") { return Promise.resolve(); } - state[tabId] = ids.filter((id) => id != frameId); + const tab = state[tabId] || {}; + tab[frameId] = (tab[frameId] || 0) - 1; + if (tab[frameId] == 0) { + delete tab[frameId]; + } + if (Object.keys(tab).length === 0) { + delete state[tabId]; + } + this.cache.set(REPOSITORY_KEY, state); return Promise.resolve(); } @@ -60,6 +58,13 @@ export class ReadyFrameRepositoryImpl implements ReadyFrameRepository { if (typeof state === "undefined") { return Promise.resolve(undefined); } - return Promise.resolve(state[tabId]); + const tab = state[tabId]; + if (typeof tab === "undefined") { + return Promise.resolve(undefined); + } + const frameIds = Object.keys(tab) + .map((v) => Number(v)) + .sort(); + return Promise.resolve(frameIds); } } diff --git a/src/background/usecases/ReadyFrameUseCase.ts b/src/background/usecases/ReadyFrameUseCase.ts deleted file mode 100644 index 81bee0c..0000000 --- a/src/background/usecases/ReadyFrameUseCase.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { inject, injectable } from "tsyringe"; -import ReadyFrameRepository from "../repositories/ReadyFrameRepository"; - -@injectable() -export default class ReadyFrameUseCase { - constructor( - @inject("ReadyFrameRepository") - private readonly frameRepository: ReadyFrameRepository - ) {} - - async addReadyFrame(tabId: number, frameId: number): Promise { - return this.frameRepository.addFrameId(tabId, frameId); - } - - async clearReadyFrame(tabId: number): Promise { - return this.frameRepository.clearFrameIds(tabId); - } -} diff --git a/test/background/mock/MockReadyFrameRepository.ts b/test/background/mock/MockReadyFrameRepository.ts index a95b2e1..4a5ec52 100644 --- a/test/background/mock/MockReadyFrameRepository.ts +++ b/test/background/mock/MockReadyFrameRepository.ts @@ -1,10 +1,6 @@ import ReadyFrameRepository from "../../../src/background/repositories/ReadyFrameRepository"; export default class MockReadyFrameRepository implements ReadyFrameRepository { - clearFrameIds(_tabId: number): Promise { - throw new Error("not implemented"); - } - addFrameId(_tabId: number, _fraemId: number): Promise { throw new Error("not implemented"); } diff --git a/test/background/repositories/ReadyFrameRepository.test.ts b/test/background/repositories/ReadyFrameRepository.test.ts index 888f3f5..71f20af 100644 --- a/test/background/repositories/ReadyFrameRepository.test.ts +++ b/test/background/repositories/ReadyFrameRepository.test.ts @@ -15,12 +15,19 @@ describe("background/repositories/ReadyFrameRepositoryImpl", () => { await sut.addFrameId(1, 12); await sut.addFrameId(1, 11); await sut.addFrameId(2, 20); + await sut.addFrameId(2, 21); + await sut.addFrameId(2, 21); expect(await sut.getFrameIds(1)).to.deep.equal([10, 11, 12]); - expect(await sut.getFrameIds(2)).to.deep.equal([20]); + expect(await sut.getFrameIds(2)).to.deep.equal([20, 21]); - await sut.clearFrameIds(1); + await sut.removeFrameId(2, 21); + expect(await sut.getFrameIds(2)).to.deep.equal([20, 21]); - expect(await sut.getFrameIds(1)).to.be.undefined; + await sut.removeFrameId(2, 21); + expect(await sut.getFrameIds(2)).to.deep.equal([20]); + + await sut.removeFrameId(2, 20); + expect(await sut.getFrameIds(2)).to.be.undefined; }); }); -- cgit v1.2.3