fix: lock to prevent subwiki restart main wiki

This commit is contained in:
lin onetwo 2023-06-19 23:36:56 +08:00
parent 018057f92f
commit ba513cf990
4 changed files with 19 additions and 19 deletions

View file

@ -564,7 +564,7 @@ export class View implements IViewService {
} else if (isRetry === true) {
logger.error(
`realignActiveView() ${activeId} failed view?.webContents is ${String(view?.webContents)} and isRetry is ${String(isRetry)} stack: ${
new Error('stack').stack ?? 'no stack'
new Error('stack').stack?.replace('Error:', '') ?? 'no stack'
}`,
);
} else {

View file

@ -82,16 +82,12 @@ export function setupIpcServerRoutesHandlers(view: BrowserView, workspaceID: str
async function handlerCallback(request: GlobalRequest): Promise<GlobalResponse> {
const parsedUrl = new URL(request.url);
// Iterate through methods to find matching routes
// DEBUG: console parsedUrl
console.log(`parsedUrl`, parsedUrl);
try {
for (const route of methods) {
// DEBUG: console parsedUrl.pathname
console.log(`parsedUrl.pathname`, parsedUrl.pathname, request.method === route.method, route.name, route.path.test(parsedUrl.pathname));
if (request.method === route.method && route.path.test(parsedUrl.pathname)) {
// Get the parameters in the URL path
const parameters = parsedUrl.pathname.match(route.path);
logger.debug(`setupIpcServerRoutesHandlers.handlerCallback: ${route.name}`, { parsedUrl, parameters });
logger.debug(`setupIpcServerRoutesHandlers.handlerCallback: started`, { name: route.name, parsedUrl, parameters });
// Call the handler of the route to process the request and return the result
const responseData = await route.handler(request, parameters);
if (responseData === undefined) {
@ -99,6 +95,7 @@ export function setupIpcServerRoutesHandlers(view: BrowserView, workspaceID: str
logger.warn(statusText);
return new Response(undefined, { status: 404, statusText });
}
logger.debug(`setupIpcServerRoutesHandlers.handlerCallback: success`, { name: route.name, parsedUrl, parameters, status: responseData.statusCode });
return new Response(responseData.data as string, { status: responseData.statusCode, headers: responseData.headers });
}
}

View file

@ -108,7 +108,7 @@ export class Wiki implements IWikiService {
}
const previousWorker = this.getWorker(workspaceID);
if (previousWorker !== undefined) {
logger.error(new DoubleWikiInstanceError(workspaceID));
logger.error(new DoubleWikiInstanceError(workspaceID).message, { stack: new Error('stack').stack?.replace('Error:', '') ?? 'no stack' });
await this.stopWiki(workspaceID);
}
// use Promise to handle worker callbacks
@ -188,31 +188,27 @@ export class Wiki implements IWikiService {
switch (message.actions) {
case WikiControlActions.booted: {
setTimeout(async () => {
if (message.message !== undefined) {
logger.info('WikiControlActions.booted ' + message.message, loggerMeta);
}
logger.info(`startWiki() resolved with message.type === 'control' and WikiControlActions.booted`, loggerMeta);
logger.info(`startWiki() resolved with message.type === 'control' and WikiControlActions.booted`, { ...loggerMeta, message: message.message, workspaceID });
resolve();
}, 100);
break;
}
case WikiControlActions.start: {
if (message.message !== undefined) {
logger.debug('WikiControlActions.start', { 'message.message': message.message, ...loggerMeta });
logger.debug('WikiControlActions.start', { 'message.message': message.message, ...loggerMeta, workspaceID });
}
break;
}
case WikiControlActions.listening: {
// API server started, but we are using IPC to serve content now, so do nothing here.
if (message.message !== undefined) {
logger.info('WikiControlActions.listening ' + message.message, loggerMeta);
logger.info('WikiControlActions.listening ' + message.message, { ...loggerMeta, workspaceID });
}
break;
}
case WikiControlActions.error: {
const errorMessage = message.message ?? 'get WikiControlActions.error without message';
logger.error(errorMessage, { ...loggerMeta, message });
logger.info(`startWiki() rejected with message.type === 'control' and WikiControlActions.error`, loggerMeta);
logger.error(`startWiki() rejected with message.type === 'control' and WikiControlActions.error`, { ...loggerMeta, message, errorMessage, workspaceID });
await this.workspaceService.updateMetaData(workspaceID, { isLoading: false, didFailLoadErrorMessage: errorMessage });
// fix "message":"listen EADDRINUSE: address already in use 0.0.0.0:5212"
if (errorMessage.includes('EADDRINUSE')) {
@ -268,10 +264,14 @@ export class Wiki implements IWikiService {
}
public async callWikiIpcServerRoute<NAME extends IpcServerRouteNames>(workspaceID: string, route: NAME, ...arguments_: Parameters<IpcServerRouteMethods[NAME]>) {
logger.debug(`callWikiIpcServerRoute get ${route}`, { arguments_, workspaceID });
const worker = await this.getWorkerEnsure(workspaceID);
logger.debug(`callWikiIpcServerRoute got worker`);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment, @typescript-eslint/prefer-ts-expect-error
// @ts-ignore Argument of type 'string | string[] | ITiddlerFields | undefined' is not assignable to parameter of type 'string'. Type 'undefined' is not assignable to type 'string'.ts(2345)
return await worker[route](...arguments_);
const response = await worker[route](...arguments_);
logger.debug(`callWikiIpcServerRoute returning response`, { route, code: response.statusCode });
return response;
}
public getWikiChangeObserver$(workspaceID: string): Observable<IChangedTiddlers> {
@ -314,6 +314,7 @@ export class Wiki implements IWikiService {
if (worker === undefined) {
logger.warning(`No wiki for ${id}. No running worker, means maybe tiddlywiki server in this workspace failed to start`, {
function: 'stopWiki',
stack: new Error('stack').stack?.replace('Error:', '') ?? 'no stack',
});
return;
}
@ -664,12 +665,12 @@ export class Wiki implements IWikiService {
}
public async wikiStartup(workspace: IWorkspace): Promise<void> {
const { id, isSubWiki, name, mainWikiID } = workspace;
const { id, isSubWiki, name, mainWikiID, wikiFolderLocation } = workspace;
// remove $:/StoryList, otherwise it sometimes cause $__StoryList_1.tid to be generated
// and it will leak private sub-wiki's opened tiddler title
try {
void fs.unlink(path.resolve(id, 'tiddlers', '$__StoryList')).catch(() => {});
void fs.unlink(path.resolve(wikiFolderLocation, 'tiddlers', '$__StoryList')).catch(() => {});
} catch {
// do nothing
}

View file

@ -71,13 +71,15 @@ export class WorkspaceView implements IWorkspaceViewService {
public async initializeAllWorkspaceView(): Promise<void> {
const workspacesList = await this.workspaceService.getWorkspacesAsList();
workspacesList.filter((workspace) => !workspace.isSubWiki && !workspace.hibernated).forEach((workspace) => {
this.wikiService.setWikiStartLockOn(workspace.id);
});
// sorting (-1 will make a in the front, b in the back)
const sortedList = workspacesList
.sort((a, b) => a.order - b.order) // sort by order, 1-2<0, so first will be the first
.sort((a, b) => (a.active && !b.active ? -1 : 0)) // put active wiki first
.sort((a, b) => (a.isSubWiki && !b.isSubWiki ? -1 : 0)); // put subwiki on top, they can't restart wiki, so need to sync them first, then let main wiki restart the wiki // revert this after tw can reload tid from fs
await mapSeries(sortedList, async (workspace) => {
this.wikiService.setWikiStartLockOn(workspace.id);
await this.initializeWorkspaceView(workspace);
});
this.wikiService.setAllWikiStartLockOff();