refactor: relation worker use MessageHelper
This commit is contained in:
parent
ba4ffb03db
commit
59ab1413ad
|
|
@ -6,7 +6,8 @@ import hooks from "./hooks";
|
|||
import api from "./api";
|
||||
import { createZToolkit } from "./utils/ztoolkit";
|
||||
import { MessageHelper } from "zotero-plugin-toolkit/dist/helpers/message";
|
||||
import type { handlers } from "./extras/parsingWorker";
|
||||
import type { handlers as parsingHandlers } from "./extras/parsingWorker";
|
||||
import type { handlers as relationHandlers } from "./extras/relationWorker";
|
||||
|
||||
class Addon {
|
||||
public data: {
|
||||
|
|
@ -71,9 +72,10 @@ class Addon {
|
|||
};
|
||||
relation: {
|
||||
worker?: Worker;
|
||||
server?: MessageHelper<typeof relationHandlers>;
|
||||
};
|
||||
parsing: {
|
||||
server?: MessageHelper<typeof handlers>;
|
||||
server?: MessageHelper<typeof parsingHandlers>;
|
||||
};
|
||||
imageCache: Record<number, string>;
|
||||
hint: {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
import Dexie from "dexie";
|
||||
import { MessageHelper } from "zotero-plugin-toolkit";
|
||||
|
||||
export { handlers };
|
||||
|
||||
const db = new Dexie("BN_Two_Way_Relation") as Dexie & {
|
||||
link: Dexie.Table<LinkModel>;
|
||||
|
|
@ -10,12 +13,31 @@ db.version(2).stores({
|
|||
annotation: "++id, fromLibID, fromKey, toLibID, toKey, url",
|
||||
});
|
||||
|
||||
console.log("Using Dexie v" + Dexie.semVer, db);
|
||||
log("Using Dexie v" + Dexie.semVer, db);
|
||||
|
||||
postMessage({
|
||||
type: "ready",
|
||||
const funcs = {
|
||||
addLink,
|
||||
bulkAddLink,
|
||||
rebuildLinkForNote,
|
||||
getOutboundLinks,
|
||||
getInboundLinks,
|
||||
linkAnnotationToTarget,
|
||||
getLinkTargetByAnnotation,
|
||||
getAnnotationByLinkTarget,
|
||||
};
|
||||
|
||||
const handlers = MessageHelper.wrapHandlers(funcs);
|
||||
|
||||
const messageServer = new MessageHelper({
|
||||
canBeDestroyed: true,
|
||||
dev: true,
|
||||
name: "parsingWorker",
|
||||
target: self,
|
||||
handlers,
|
||||
});
|
||||
|
||||
messageServer.start();
|
||||
|
||||
async function addLink(model: LinkModel) {
|
||||
await db.link.add(model);
|
||||
}
|
||||
|
|
@ -29,12 +51,12 @@ async function rebuildLinkForNote(
|
|||
fromKey: string,
|
||||
links: LinkModel[],
|
||||
) {
|
||||
console.log("rebuildLinkForNote", fromLibID, fromKey, links);
|
||||
log("rebuildLinkForNote", fromLibID, fromKey, links);
|
||||
|
||||
const collection = db.link.where({ fromLibID, fromKey });
|
||||
const oldOutboundLinks = await collection.toArray();
|
||||
await collection.delete().then((deleteCount) => {
|
||||
console.log("Deleted " + deleteCount + " objects");
|
||||
log("Deleted " + deleteCount + " objects");
|
||||
return bulkAddLink(links);
|
||||
});
|
||||
return {
|
||||
|
|
@ -43,17 +65,17 @@ async function rebuildLinkForNote(
|
|||
}
|
||||
|
||||
async function getOutboundLinks(fromLibID: number, fromKey: string) {
|
||||
console.log("getOutboundLinks", fromLibID, fromKey);
|
||||
log("getOutboundLinks", fromLibID, fromKey);
|
||||
return db.link.where({ fromLibID, fromKey }).toArray();
|
||||
}
|
||||
|
||||
async function getInboundLinks(toLibID: number, toKey: string) {
|
||||
console.log("getInboundLinks", toLibID, toKey);
|
||||
log("getInboundLinks", toLibID, toKey);
|
||||
return db.link.where({ toLibID, toKey }).toArray();
|
||||
}
|
||||
|
||||
async function linkAnnotationToTarget(model: AnnotationModel) {
|
||||
console.log("linkAnnotationToTarget", model);
|
||||
log("linkAnnotationToTarget", model);
|
||||
const collection = db.annotation.where({
|
||||
fromLibID: model.fromLibID,
|
||||
fromKey: model.fromKey,
|
||||
|
|
@ -64,15 +86,19 @@ async function linkAnnotationToTarget(model: AnnotationModel) {
|
|||
}
|
||||
|
||||
async function getLinkTargetByAnnotation(fromLibID: number, fromKey: string) {
|
||||
console.log("getLinkTargetByAnnotation", fromLibID, fromKey);
|
||||
log("getLinkTargetByAnnotation", fromLibID, fromKey);
|
||||
return db.annotation.get({ fromLibID, fromKey });
|
||||
}
|
||||
|
||||
async function getAnnotationByLinkTarget(toLibID: number, toKey: string) {
|
||||
console.log("getAnnotationByLinkTarget", toLibID, toKey);
|
||||
log("getAnnotationByLinkTarget", toLibID, toKey);
|
||||
return db.annotation.get({ toLibID, toKey });
|
||||
}
|
||||
|
||||
function log(...args: any[]) {
|
||||
if (__env__ === "development") console.log("[relationWorker]", ...args);
|
||||
}
|
||||
|
||||
interface LinkModel {
|
||||
fromLibID: number;
|
||||
fromKey: string;
|
||||
|
|
@ -91,73 +117,3 @@ interface AnnotationModel {
|
|||
toKey: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
// Handle messages from the main thread and send responses back for await
|
||||
onmessage = async (event) => {
|
||||
const { type, jobID, data } = event.data;
|
||||
console.log("Worker received message", type, jobID, data);
|
||||
switch (type) {
|
||||
case "addLink":
|
||||
postMessage({
|
||||
type,
|
||||
jobID,
|
||||
result: await addLink(data),
|
||||
});
|
||||
break;
|
||||
case "bulkAddLink":
|
||||
postMessage({
|
||||
type,
|
||||
jobID,
|
||||
result: await bulkAddLink(data),
|
||||
});
|
||||
break;
|
||||
case "rebuildLinkForNote":
|
||||
postMessage({
|
||||
type,
|
||||
jobID,
|
||||
result: await rebuildLinkForNote(
|
||||
data.fromLibID,
|
||||
data.fromKey,
|
||||
data.links,
|
||||
),
|
||||
});
|
||||
break;
|
||||
case "getOutboundLinks":
|
||||
postMessage({
|
||||
type,
|
||||
jobID,
|
||||
result: await getOutboundLinks(data.fromLibID, data.fromKey),
|
||||
});
|
||||
break;
|
||||
case "getInboundLinks":
|
||||
postMessage({
|
||||
type,
|
||||
jobID,
|
||||
result: await getInboundLinks(data.toLibID, data.toKey),
|
||||
});
|
||||
break;
|
||||
case "linkAnnotationToTarget":
|
||||
postMessage({
|
||||
type,
|
||||
jobID,
|
||||
result: await linkAnnotationToTarget(data),
|
||||
});
|
||||
break;
|
||||
case "getLinkTargetByAnnotation":
|
||||
postMessage({
|
||||
type,
|
||||
jobID,
|
||||
result: await getLinkTargetByAnnotation(data.fromLibID, data.fromKey),
|
||||
});
|
||||
break;
|
||||
case "getAnnotationByLinkTarget":
|
||||
postMessage({
|
||||
type,
|
||||
jobID,
|
||||
result: await getAnnotationByLinkTarget(data.toLibID, data.toKey),
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ import { patchViewItems } from "./modules/viewItems";
|
|||
import { getFocusedWindow } from "./utils/window";
|
||||
import { registerNoteRelation } from "./modules/workspace/relation";
|
||||
import { getPref, setPref } from "./utils/prefs";
|
||||
import { closeRelationWorker } from "./utils/relation";
|
||||
import { closeRelationServer } from "./utils/relation";
|
||||
import { registerNoteLinkSection } from "./modules/workspace/link";
|
||||
import { showUserGuide } from "./modules/userGuide";
|
||||
import { refreshTemplatesInNote } from "./modules/template/refresh";
|
||||
|
|
@ -109,7 +109,7 @@ async function onMainWindowUnload(win: Window): Promise<void> {
|
|||
}
|
||||
|
||||
function onShutdown(): void {
|
||||
closeRelationWorker();
|
||||
closeRelationServer();
|
||||
closeParsingServer();
|
||||
ztoolkit.unregisterAll();
|
||||
// Remove addon object
|
||||
|
|
|
|||
|
|
@ -1,73 +1,47 @@
|
|||
import { MessageHelper } from "zotero-plugin-toolkit";
|
||||
import { config } from "../../package.json";
|
||||
import { getNoteLinkParams } from "./link";
|
||||
import type { handlers } from "../extras/relationWorker";
|
||||
|
||||
function closeRelationServer() {
|
||||
if (addon.data.relation.server) {
|
||||
addon.data.relation.server.destroy();
|
||||
addon.data.relation.server = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
async function getRelationServer() {
|
||||
if (!addon.data.relation.server) {
|
||||
const worker = new Worker(
|
||||
`chrome://${config.addonRef}/content/scripts/relationWorker.js`,
|
||||
{ name: "relationWorker" },
|
||||
);
|
||||
const server = new MessageHelper<typeof handlers>({
|
||||
canBeDestroyed: false,
|
||||
dev: true,
|
||||
name: "relationWorkerMain",
|
||||
target: worker,
|
||||
handlers: {},
|
||||
});
|
||||
server.start();
|
||||
await server.exec("_ping");
|
||||
addon.data.relation.server = server;
|
||||
}
|
||||
|
||||
return addon.data.relation.server!;
|
||||
}
|
||||
|
||||
export { getRelationServer, closeRelationServer };
|
||||
|
||||
export {
|
||||
updateNoteLinkRelation,
|
||||
getNoteLinkInboundRelation,
|
||||
getNoteLinkOutboundRelation,
|
||||
closeRelationWorker,
|
||||
linkAnnotationToTarget,
|
||||
getLinkTargetByAnnotation,
|
||||
getAnnotationByLinkTarget,
|
||||
};
|
||||
|
||||
function closeRelationWorker() {
|
||||
if (addon.data.relation.worker) {
|
||||
addon.data.relation.worker.terminate();
|
||||
addon.data.relation.worker = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
async function getRelationWorker() {
|
||||
if (addon.data.relation.worker) {
|
||||
return addon.data.relation.worker;
|
||||
}
|
||||
const deferred = Zotero.Promise.defer();
|
||||
const worker = new Worker(
|
||||
`chrome://${config.addonRef}/content/scripts/relationWorker.js`,
|
||||
);
|
||||
addon.data.relation.worker = worker;
|
||||
worker.addEventListener(
|
||||
"message",
|
||||
(e) => {
|
||||
if (e.data === "ready") {
|
||||
ztoolkit.log("Relation worker is ready.");
|
||||
deferred.resolve();
|
||||
}
|
||||
},
|
||||
{ once: true },
|
||||
);
|
||||
await deferred.promise;
|
||||
return worker;
|
||||
}
|
||||
|
||||
async function executeRelationWorker(data: {
|
||||
type: string;
|
||||
data: any;
|
||||
}): Promise<any> {
|
||||
const worker = await getRelationWorker();
|
||||
const deferred = Zotero.Promise.defer();
|
||||
const jobID = Zotero.Utilities.randomString(8);
|
||||
let retData;
|
||||
ztoolkit.log("executeRelationWorker", data, jobID);
|
||||
const callback = (e: MessageEvent) => {
|
||||
if (e.data.jobID === jobID) {
|
||||
retData = e.data;
|
||||
worker.removeEventListener("message", callback);
|
||||
deferred.resolve();
|
||||
}
|
||||
};
|
||||
worker.addEventListener("message", callback);
|
||||
worker.postMessage({ ...data, jobID });
|
||||
await Promise.race([deferred.promise, Zotero.Promise.delay(5000)]);
|
||||
if (!retData) {
|
||||
worker.removeEventListener("message", callback);
|
||||
throw new Error(`Worker timeout: ${data.type}, ${jobID}`);
|
||||
}
|
||||
ztoolkit.log("executeRelationWorker return", retData);
|
||||
return (retData as { result: any }).result;
|
||||
}
|
||||
|
||||
async function updateNoteLinkRelation(noteID: number) {
|
||||
const note = Zotero.Items.get(noteID);
|
||||
const affectedNoteIDs = new Set([noteID]);
|
||||
|
|
@ -99,10 +73,10 @@ async function updateNoteLinkRelation(noteID: number) {
|
|||
}
|
||||
}
|
||||
}
|
||||
const result = await executeRelationWorker({
|
||||
type: "rebuildLinkForNote",
|
||||
data: { fromLibID, fromKey, links: linkToData },
|
||||
});
|
||||
const result = await (
|
||||
await getRelationServer()
|
||||
).exec("rebuildLinkForNote", [fromLibID, fromKey, linkToData]);
|
||||
|
||||
for (const link of result.oldOutboundLinks as LinkModel[]) {
|
||||
const item = Zotero.Items.getByLibraryAndKey(link.toLibID, link.toKey);
|
||||
if (!item) {
|
||||
|
|
@ -120,28 +94,21 @@ async function updateNoteLinkRelation(noteID: number) {
|
|||
);
|
||||
}
|
||||
|
||||
async function getNoteLinkOutboundRelation(
|
||||
noteID: number,
|
||||
): Promise<LinkModel[]> {
|
||||
async function getNoteLinkOutboundRelation(noteID: number) {
|
||||
const note = Zotero.Items.get(noteID);
|
||||
const fromLibID = note.libraryID;
|
||||
const fromKey = note.key;
|
||||
return executeRelationWorker({
|
||||
type: "getOutboundLinks",
|
||||
data: { fromLibID, fromKey },
|
||||
});
|
||||
return (await getRelationServer()).exec("getOutboundLinks", [
|
||||
fromLibID,
|
||||
fromKey,
|
||||
]);
|
||||
}
|
||||
|
||||
async function getNoteLinkInboundRelation(
|
||||
noteID: number,
|
||||
): Promise<LinkModel[]> {
|
||||
async function getNoteLinkInboundRelation(noteID: number) {
|
||||
const note = Zotero.Items.get(noteID);
|
||||
const toLibID = note.libraryID;
|
||||
const toKey = note.key;
|
||||
return executeRelationWorker({
|
||||
type: "getInboundLinks",
|
||||
data: { toLibID, toKey },
|
||||
});
|
||||
return (await getRelationServer()).exec("getInboundLinks", [toLibID, toKey]);
|
||||
}
|
||||
|
||||
function decodeHTMLEntities(text: string) {
|
||||
|
|
@ -162,31 +129,22 @@ interface LinkModel {
|
|||
url: string;
|
||||
}
|
||||
|
||||
async function linkAnnotationToTarget(model: AnnotationModel): Promise<void> {
|
||||
return executeRelationWorker({
|
||||
type: "linkAnnotationToTarget",
|
||||
data: model,
|
||||
});
|
||||
async function linkAnnotationToTarget(model: AnnotationModel) {
|
||||
return (await getRelationServer()).exec("linkAnnotationToTarget", [model]);
|
||||
}
|
||||
|
||||
async function getLinkTargetByAnnotation(
|
||||
fromLibID: number,
|
||||
fromKey: string,
|
||||
): Promise<AnnotationModel> {
|
||||
return executeRelationWorker({
|
||||
type: "getLinkTargetByAnnotation",
|
||||
data: { fromLibID, fromKey },
|
||||
});
|
||||
async function getLinkTargetByAnnotation(fromLibID: number, fromKey: string) {
|
||||
return (await getRelationServer()).exec("getLinkTargetByAnnotation", [
|
||||
fromLibID,
|
||||
fromKey,
|
||||
]);
|
||||
}
|
||||
|
||||
async function getAnnotationByLinkTarget(
|
||||
toLibID: number,
|
||||
toKey: string,
|
||||
): Promise<AnnotationModel> {
|
||||
return executeRelationWorker({
|
||||
type: "getAnnotationByLinkTarget",
|
||||
data: { toLibID, toKey },
|
||||
});
|
||||
async function getAnnotationByLinkTarget(toLibID: number, toKey: string) {
|
||||
return (await getRelationServer()).exec("getAnnotationByLinkTarget", [
|
||||
toLibID,
|
||||
toKey,
|
||||
]);
|
||||
}
|
||||
|
||||
interface AnnotationModel {
|
||||
|
|
|
|||
|
|
@ -40,6 +40,9 @@ export default defineConfig({
|
|||
},
|
||||
{
|
||||
entryPoints: ["src/extras/*.*"],
|
||||
define: {
|
||||
__env__: `"${process.env.NODE_ENV}"`,
|
||||
},
|
||||
outdir: "build/addon/chrome/content/scripts",
|
||||
bundle: true,
|
||||
target: ["firefox115"],
|
||||
|
|
|
|||
Loading…
Reference in New Issue