Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ jobs:
- name: Run Linter
run: yarn lint

- name: Run Tests
run: yarn test

- name: Build App
env:
BRANCH: ${{ (inputs.branch != 'stable' && 'nightly') || '' }}
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG-nightly.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## 3.1.25.1000

- Fixed an issue where the database cleanup triggered when opening a new channel could delete cached emote sets older than an hour (including global emotes), causing emotes to disappear from all open tabs until the browser was restarted
- Fixed Kick Emote Menu position
- Updated 7TV API logic

Expand Down
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"lint": "yarn lint:js && yarn lint:style",
"lint:fix": "yarn lint:js:fix && yarn lint:style:fix",
"preview": "vite preview",
"test": "vitest run",
"script:compile-emoji": "tsc -p script/script.tsconfig.json --outDir dist/ && node dist/compile-emojis.js"
},
"dependencies": {
Expand Down Expand Up @@ -65,6 +66,7 @@
"eslint": "^8.47.0",
"eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-vue": "^9.17.0",
"fake-indexeddb": "^6.0.0",
"graphql": "^16.8.0",
"marked": "^10.0.0",
"nanoid": "^5.0.3",
Expand All @@ -87,9 +89,11 @@
"uuid": "^9.0.0",
"vite": "^5.0.2",
"vite-plugin-chrome-extension": "^0.0.7",
"vitest": "^1.6.0",
"vue-i18n": "9.7.1",
"vue-router": "4.2.5",
"vue-tsc": "^1.8.8",
"webextension-polyfill-ts": "^0.26.0"
}
},
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}
5 changes: 5 additions & 0 deletions src/composable/channel/useChannelContext.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { inject, onMounted, onUnmounted, provide, reactive, toRaw, watch } from "vue";
import { useStore } from "@/store/main";
import { log } from "@/common/Logger";
import { useWorker } from "../useWorker";

export const CHANNEL_CTX = Symbol("seventv-channel-context");
Expand Down Expand Up @@ -49,6 +50,8 @@ export class ChannelContext implements CurrentChannel {
this.displayName = channel.displayName;
this.active = channel.active;

log.info("Channel set", `id=${channel.id}`, `username=${channel.username}`, `old=${oldID}`);

m.set(channel.id, this);
m.delete(oldID);

Expand All @@ -57,6 +60,8 @@ export class ChannelContext implements CurrentChannel {
}

leave(): void {
log.info("Channel left", `id=${this.id}`, `username=${this.username}`);

this.active = false;

sendMessage("STATE", {
Expand Down
14 changes: 11 additions & 3 deletions src/composable/useWorker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ type WorkerAddrMap = Record<string, string>;
async function init(originURL: string): Promise<SharedWorker> {
let sw: SharedWorker;

log.info("Worker init starting", `origin=${originURL}`, `url=${location.href}`);

// Check for existing url
// If it exists, we'll connect to it
const appVersion = import.meta.env.VITE_APP_VERSION;
Expand Down Expand Up @@ -68,6 +70,8 @@ async function init(originURL: string): Promise<SharedWorker> {
return new Promise<SharedWorker>((resolve, reject) => {
if (!workerURL) return reject("No address to worker");

log.info("Worker connected", `addr=${workerURL}`);

// Spawn or connect to worker
sw = worker = new SharedWorker(workerURL, {
name: "seventv-extension",
Expand Down Expand Up @@ -127,6 +131,7 @@ function useHandlers(mp: MessagePort) {

switch (type) {
case "INIT": {
log.info("Worker ready (INIT received)");
events.emit("ready", {});
break;
}
Expand Down Expand Up @@ -231,11 +236,14 @@ class WorkletTarget extends EventTarget {
**/
async listenUntil<T extends WorkletEventName>(name: T, cb: (ev: WorkletEvent<T>) => boolean) {
await new Promise<void>((resolve) => {
this.addEventListener(name, (ev) => {
const handler = (ev: WorkletEvent<T>) => {
if (!cb(ev)) return;
this.removeEventListener(name, cb);

this.removeEventListener(name, handler);
resolve();
});
};

this.addEventListener(name, handler);
});
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/content/content.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { APP_BROADCAST_CHANNEL } from "@/common/Constant";
import { log } from "@/common/Logger";
import { insertEmojiVectors } from "./emoji";

const SEVENTV_EXTENSION_EVENT = "seventv:extension-presence";
Expand All @@ -16,6 +17,7 @@ function markLegacyRunning(): void {

// Inject extension into site
const inject = () => {
log.info("Content script injecting site script", `url=${location.href}`, `origin=${location.origin}`);
// Script
const script = document.createElement("script");
script.src = import.meta.env.DEV ? import.meta.env.BASE_URL + "src/site/site.ts" : chrome.runtime.getURL("site.js");
Expand Down
18 changes: 13 additions & 5 deletions src/db/idb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ export class Dexie7 extends Dexie {

this.open()
.then(() => {
this._ready = true;
resolve(true);
})
.catch(onError);
Expand Down Expand Up @@ -112,12 +113,19 @@ export class Dexie7 extends Dexie {
.and((c) => !exemptChannels?.includes(c.id))
.toArray();

// Expire emote sets
const activeSetIDs = new Set<string>(
(await this.channels.where("id").anyOf(exemptChannels).toArray()).flatMap((c) => c.set_ids ?? []),
);

const expiredSetIDs = channels.map((c) => c.set_ids).reduce((a, b) => a.concat(b), []);

this.emoteSets
.where("id")
.anyOf(channels.map((c) => c.set_ids).reduce((a, b) => a.concat(b), []))
.or("timestamp")
.below(now - oneHour)
.filter((es) => {
if (es.scope === "GLOBAL") return false;
if (activeSetIDs.has(es.id)) return false;

return (es.timestamp ?? 0) < now - oneHour || expiredSetIDs.includes(es.id);
})
.delete();

// Clean up entitlements
Expand Down
28 changes: 17 additions & 11 deletions src/worker/worker.driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ export class WorkerDriver extends EventTarget {
db: Dexie7;
log: Logger;

startupID = Date.now().toString(36) + Math.random().toString(36).slice(2, 8);

ports = new Map<symbol, WorkerPort>();
portSeq = 0;

Expand Down Expand Up @@ -81,16 +83,20 @@ export class WorkerDriver extends EventTarget {
this.ports.set(p.id, p);

// Do DB cleanup for unused data
setTimeout(
() => {
const exemptions = Array.from(this.ports.values())
.filter((p) => p.channels.size)
.flatMap((p) => p.channelIds);

db.expireDocuments(exemptions);
},
getRandomInt(2500, 15000),
);
const expirationDelay = getRandomInt(2500, 15000);
setTimeout(() => {
const exemptions = Array.from(this.ports.values())
.filter((p) => p.channels.size)
.flatMap((p) => p.channelIds);

this.log.debug(
"Expiring documents",
`portSeq=${p.seq}`,
`delay=${expirationDelay}ms`,
`exemptions=${exemptions.join(",") || "none"}`,
);
db.expireDocuments(exemptions);
}, expirationDelay);

// Fetch config anew
this.http
Expand All @@ -106,7 +112,7 @@ export class WorkerDriver extends EventTarget {

w.caches.open("SEVENTV#CACHE").then((c) => (this.cache = c));

this.log.info("Worker has spawned. Logs will be piped to the UI thread");
this.log.info("Worker has spawned", `startup=${this.startupID}`, "Logs will be piped to the UI thread");
}

addEventListener<T extends WorkerEventName>(
Expand Down
19 changes: 19 additions & 0 deletions src/worker/worker.events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,15 @@ export class EventAPI {
channels: new Set([channelID]),
});

log.debug(
"<EventAPI>",
"Subscribe",
`type=${type}`,
`channel=${channelID}`,
`portSeq=${port.seq}`,
`condition=${JSON.stringify(condition)}`,
);

if (this.socket === null) {
this.connect(this.transport);
}
Expand Down Expand Up @@ -327,6 +336,8 @@ export class EventAPI {
reconnect(): number {
const jitter = Math.min((this.backoff += getRandomInt(1000, 5000)), 120000);

log.debug("<EventAPI>", "Reconnect scheduled", `in=${jitter}ms`, `resume=${this.shouldResume}`);

setTimeout(() => {
if (this.socket || !this.transport) return;

Expand All @@ -338,6 +349,14 @@ export class EventAPI {
disconnect(shouldReconnect = true, timer = 0, reason = ""): void {
this.disconnectReason = reason;

log.debug(
"<EventAPI>",
"Disconnect scheduled",
`in=${timer}ms`,
`reason=${reason || "manual"}`,
`reconnect=${shouldReconnect}`,
);

const f = () => {
if (!this.socket) return;

Expand Down
5 changes: 5 additions & 0 deletions src/worker/worker.http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,11 @@ export class WorkerHttp {
),
),
).then(() => {
this.driver.log.debug(
`<Net/Http> channel data fetched for #${channel.username}`,
`id=${channel.id}`,
`portSeq=${port.seq}`,
);
port?.postMessage("CHANNEL_SETS_FETCHED", {
channel,
});
Expand Down
6 changes: 3 additions & 3 deletions src/worker/worker.port.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,15 @@ export class WorkerPort {
if (channel && channel.active && !this.channels.has(channel.id)) {
this.channels.set(channel.id, channel);

this.driver.log.debugWithObjects(["Channel added"], [channel]);
this.driver.log.debugWithObjects(["Channel added", `portSeq=${this.seq}`], [channel]);
this.driver.emit("join_channel", channel, this);
} else if (channel && channel.active && refetch) {
this.driver.log.debugWithObjects(["Channel refetched"], [channel]);
this.driver.log.debugWithObjects(["Channel refetched", `portSeq=${this.seq}`], [channel]);
this.driver.emit("join_channel", channel, this);
} else if (channel && !channel.active && this.channels.has(channel.id)) {
this.channels.delete(channel.id);

this.driver.log.debugWithObjects(["Channel removed"], [channel]);
this.driver.log.debugWithObjects(["Channel removed", `portSeq=${this.seq}`], [channel]);
this.driver.emit("part_channel", channel, this);
}

Expand Down
Loading
Loading