mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-21 03:56:23 +08:00
feat(core): new worker workspace engine (#9257)
This commit is contained in:
@@ -15,6 +15,7 @@ import {
|
||||
switchToPreviousTab,
|
||||
undoCloseTab,
|
||||
} from '../windows-manager';
|
||||
import { WorkerManager } from '../worker/pool';
|
||||
import { applicationMenuSubjects } from './subject';
|
||||
|
||||
// Unique id for menuitems
|
||||
@@ -113,6 +114,21 @@ export function createApplicationMenu() {
|
||||
showDevTools();
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Open worker devtools',
|
||||
click: () => {
|
||||
Menu.buildFromTemplate(
|
||||
Array.from(WorkerManager.instance.workers.values()).map(item => ({
|
||||
label: `${item.key}`,
|
||||
click: () => {
|
||||
item.browserWindow.webContents.openDevTools({
|
||||
mode: 'undocked',
|
||||
});
|
||||
},
|
||||
}))
|
||||
).popup();
|
||||
},
|
||||
},
|
||||
{ type: 'separator' },
|
||||
{ role: 'resetZoom' },
|
||||
{ role: 'zoomIn' },
|
||||
@@ -199,7 +215,7 @@ export function createApplicationMenu() {
|
||||
{
|
||||
label: 'Learn More',
|
||||
click: async () => {
|
||||
// oxlint-disable-next-line
|
||||
// oxlint-disable-next-line no-var-requires
|
||||
const { shell } = require('electron');
|
||||
await shell.openExternal('https://affine.pro/');
|
||||
},
|
||||
@@ -220,7 +236,7 @@ export function createApplicationMenu() {
|
||||
{
|
||||
label: 'Documentation',
|
||||
click: async () => {
|
||||
// oxlint-disable-next-line
|
||||
// oxlint-disable-next-line no-var-requires
|
||||
const { shell } = require('electron');
|
||||
await shell.openExternal(
|
||||
'https://docs.affine.pro/docs/hello-bonjour-aloha-你好'
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export const mainWindowOrigin = process.env.DEV_SERVER_URL || 'file://.';
|
||||
export const onboardingViewUrl = `${mainWindowOrigin}${mainWindowOrigin.endsWith('/') ? '' : '/'}onboarding`;
|
||||
export const shellViewUrl = `${mainWindowOrigin}${mainWindowOrigin.endsWith('/') ? '' : '/'}shell.html`;
|
||||
export const backgroundWorkerViewUrl = `${mainWindowOrigin}${mainWindowOrigin.endsWith('/') ? '' : '/'}background-worker.html`;
|
||||
export const customThemeViewUrl = `${mainWindowOrigin}${mainWindowOrigin.endsWith('/') ? '' : '/'}theme-editor`;
|
||||
|
||||
@@ -8,6 +8,7 @@ import { getLogFilePath, logger, revealLogFile } from './logger';
|
||||
import { sharedStorageHandlers } from './shared-storage';
|
||||
import { uiHandlers } from './ui/handlers';
|
||||
import { updaterHandlers } from './updater';
|
||||
import { workerHandlers } from './worker/handlers';
|
||||
|
||||
export const debugHandlers = {
|
||||
revealLogFile: async () => {
|
||||
@@ -27,6 +28,7 @@ export const allHandlers = {
|
||||
configStorage: configStorageHandlers,
|
||||
findInPage: findInPageHandlers,
|
||||
sharedStorage: sharedStorageHandlers,
|
||||
worker: workerHandlers,
|
||||
};
|
||||
|
||||
export const registerHandlers = () => {
|
||||
|
||||
@@ -25,7 +25,6 @@ import {
|
||||
|
||||
import { isMacOS } from '../../shared/utils';
|
||||
import { beforeAppQuit } from '../cleanup';
|
||||
import { isDev } from '../config';
|
||||
import { mainWindowOrigin, shellViewUrl } from '../constants';
|
||||
import { ensureHelperProcess } from '../helper-process';
|
||||
import { logger } from '../logger';
|
||||
@@ -871,9 +870,6 @@ export class WebContentViewsManager {
|
||||
});
|
||||
|
||||
view.webContents.loadURL(shellViewUrl).catch(err => logger.error(err));
|
||||
if (isDev) {
|
||||
view.webContents.openDevTools();
|
||||
}
|
||||
}
|
||||
|
||||
view.webContents.on('destroyed', () => {
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { NamespaceHandlers } from '../type';
|
||||
import { WorkerManager } from './pool';
|
||||
|
||||
export const workerHandlers = {
|
||||
connectWorker: async (e, key: string, portId: string) => {
|
||||
const { portForRenderer } = await WorkerManager.instance.connectWorker(
|
||||
key,
|
||||
portId,
|
||||
e.sender
|
||||
);
|
||||
e.sender.postMessage('worker-connect', { portId }, [portForRenderer]);
|
||||
return {
|
||||
portId: portId,
|
||||
};
|
||||
},
|
||||
disconnectWorker: async (_, key: string, portId: string) => {
|
||||
WorkerManager.instance.disconnectWorker(key, portId);
|
||||
},
|
||||
} satisfies NamespaceHandlers;
|
||||
@@ -0,0 +1,96 @@
|
||||
import { join } from 'node:path';
|
||||
|
||||
import { BrowserWindow, MessageChannelMain, type WebContents } from 'electron';
|
||||
|
||||
import { backgroundWorkerViewUrl } from '../constants';
|
||||
import { ensureHelperProcess } from '../helper-process';
|
||||
import { logger } from '../logger';
|
||||
|
||||
async function getAdditionalArguments() {
|
||||
const { getExposedMeta } = await import('../exposed');
|
||||
const mainExposedMeta = getExposedMeta();
|
||||
const helperProcessManager = await ensureHelperProcess();
|
||||
const helperExposedMeta = await helperProcessManager.rpc?.getMeta();
|
||||
return [
|
||||
`--main-exposed-meta=` + JSON.stringify(mainExposedMeta),
|
||||
`--helper-exposed-meta=` + JSON.stringify(helperExposedMeta),
|
||||
`--window-name=worker`,
|
||||
];
|
||||
}
|
||||
|
||||
export class WorkerManager {
|
||||
static readonly instance = new WorkerManager();
|
||||
|
||||
workers = new Map<
|
||||
string,
|
||||
{ browserWindow: BrowserWindow; ports: Set<string>; key: string }
|
||||
>();
|
||||
|
||||
private async getOrCreateWorker(key: string) {
|
||||
const additionalArguments = await getAdditionalArguments();
|
||||
const helperProcessManager = await ensureHelperProcess();
|
||||
const exists = this.workers.get(key);
|
||||
if (exists) {
|
||||
return exists;
|
||||
} else {
|
||||
const worker = new BrowserWindow({
|
||||
width: 1200,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
preload: join(__dirname, './preload.js'),
|
||||
additionalArguments: additionalArguments,
|
||||
},
|
||||
show: false,
|
||||
});
|
||||
let disconnectHelperProcess: (() => void) | null = null;
|
||||
worker.on('close', e => {
|
||||
e.preventDefault();
|
||||
if (worker && !worker.isDestroyed()) {
|
||||
worker.destroy();
|
||||
this.workers.delete(key);
|
||||
disconnectHelperProcess?.();
|
||||
}
|
||||
});
|
||||
worker.loadURL(backgroundWorkerViewUrl).catch(e => {
|
||||
logger.error('failed to load url', e);
|
||||
});
|
||||
worker.webContents.addListener('did-finish-load', () => {
|
||||
disconnectHelperProcess = helperProcessManager.connectRenderer(
|
||||
worker.webContents
|
||||
);
|
||||
});
|
||||
const record = { browserWindow: worker, ports: new Set<string>(), key };
|
||||
this.workers.set(key, record);
|
||||
return record;
|
||||
}
|
||||
}
|
||||
|
||||
async connectWorker(
|
||||
key: string,
|
||||
portId: string,
|
||||
bindWebContent: WebContents
|
||||
) {
|
||||
bindWebContent.addListener('destroyed', () => {
|
||||
this.disconnectWorker(key, portId);
|
||||
});
|
||||
const worker = await this.getOrCreateWorker(key);
|
||||
const { port1: portForWorker, port2: portForRenderer } =
|
||||
new MessageChannelMain();
|
||||
|
||||
worker.browserWindow.webContents.postMessage('worker-connect', { portId }, [
|
||||
portForWorker,
|
||||
]);
|
||||
return { portForRenderer, portId };
|
||||
}
|
||||
|
||||
disconnectWorker(key: string, portId: string) {
|
||||
const worker = this.workers.get(key);
|
||||
if (worker) {
|
||||
worker.ports.delete(portId);
|
||||
if (worker.ports.size === 0) {
|
||||
worker.browserWindow.destroy();
|
||||
this.workers.delete(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user