Skip to content

Commit

Permalink
* Increase reliability of Electron and renderer communication by invo…
Browse files Browse the repository at this point in the history
…ke instead of once.
  • Loading branch information
MrMYHuang committed Jun 18, 2022
1 parent b3b3611 commit 5d5676c
Show file tree
Hide file tree
Showing 12 changed files with 96 additions and 20 deletions.
3 changes: 3 additions & 0 deletions VERSIONS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
# <a id='history'>版本歷史</a>
* PWA 10.0.0, Electron app 21.0.0:
* [變更] 使檔案系統離線 DB 載入更可靠。

* PWA 9.2.0:
* [新增] 重置設定支援重建 IndexedDB。
* [變更] 經文資料、字型資料使用獨立 IndexedDB stores。
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"productName": "電子佛典",
"homepage": "/",
"pwaVersion": "9.2.0",
"version": "20.0.1",
"version": "21.0.0",
"license": "MIT",
"keywords": [
"CBETA",
Expand Down
7 changes: 5 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -188,9 +188,12 @@ class _AppOrig extends React.Component<AppOrigProps, State> {
case 'cbetaOfflineDbMode':
let dbMode = CbetaDbMode.Online;
if (data.isOn) {
if (semver.gte(data.backendVersion, '20.0.0')) {
if (semver.gte(data.backendVersion, '21.0.0')) {
dbMode = CbetaDbMode.OfflineFileSystemV3;
CbetaOfflineDb.init(dbMode);
} else if (semver.gte(data.backendVersion, '20.0.0')) {
dbMode = CbetaDbMode.OfflineFileSystemV2;
CbetaOfflineDb.init(CbetaDbMode.OfflineFileSystemV2);
CbetaOfflineDb.init(dbMode);
} else {
dbMode = CbetaDbMode.OfflineFileSystem;
}
Expand Down
65 changes: 55 additions & 10 deletions src/CbetaOfflineDb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ async function wait(ms: number = 1000) {
});
}

const electronBackendApi: any = (window as any).electronBackendApi;
const electronBackendApi: {
send: (channel: string, data: any) => {},
receive: (channel: string, func: Function) => {},
receiveOnce: (channel: string, func: Function) => {},
invoke: (channel: string, data: any) => Promise<any>,
} = (window as any).electronBackendApi;

const cbetaBookcaseDir = 'Bookcase';
const bookcaseInfosKey = 'bookcaseInfos';
Expand Down Expand Up @@ -131,17 +136,34 @@ export async function init(mode: CbetaDbMode) {
}, 100);
});

const catalogsString = (await readBookcaseFromFileSystem(`CBETA/catalog.txt`));
const catalogsString = (await readBookcaseFromFileSystemV2(`CBETA/catalog.txt`));
await wait();
const spinesString = (await readBookcaseFromFileSystem(`CBETA/spine.txt`));
const spinesString = (await readBookcaseFromFileSystemV2(`CBETA/spine.txt`));
await wait();
const gaijisString = (await readResourceFromFileSystem(`cbeta_gaiji/cbeta_gaiji.json`));
const gaijisString = (await readResourceFromFileSystemV2(`cbeta_gaiji/cbeta_gaiji.json`));
await wait();
const stylesheetString = (await readResourceFromFileSystem(`buildElectron/nav_fix.xsl`));
const stylesheetString = (await readResourceFromFileSystemV2(`buildElectron/nav_fix.xsl`));
await wait();
const documentString = (await readBookcaseFromFileSystem(`CBETA/bulei_nav.xhtml`));
const documentString = (await readBookcaseFromFileSystemV2(`CBETA/bulei_nav.xhtml`));
await wait();
const teiStylesheetString = await readResourceFromFileSystem(`buildElectron/tei.xsl`);
const teiStylesheetString = await readResourceFromFileSystemV2(`buildElectron/tei.xsl`);
await initFromFiles(catalogsString, spinesString, gaijisString, stylesheetString, documentString, teiStylesheetString);
} else if (mode === CbetaDbMode.OfflineFileSystemV3) {
await new Promise<void>(ok => {
const timer = setInterval(() => {
if (isOfflineFileSystemV2Ready) {
clearInterval(timer);
ok();
}
}, 100);
});

const catalogsString = (await readBookcaseFromFileSystemV3(`CBETA/catalog.txt`));
const spinesString = (await readBookcaseFromFileSystemV3(`CBETA/spine.txt`));
const gaijisString = (await readResourceFromFileSystemV3(`cbeta_gaiji/cbeta_gaiji.json`));
const stylesheetString = (await readResourceFromFileSystemV3(`buildElectron/nav_fix.xsl`));
const documentString = (await readBookcaseFromFileSystemV3(`CBETA/bulei_nav.xhtml`));
const teiStylesheetString = await readResourceFromFileSystemV3(`buildElectron/tei.xsl`);
await initFromFiles(catalogsString, spinesString, gaijisString, stylesheetString, documentString, teiStylesheetString);
}
}
Expand Down Expand Up @@ -318,7 +340,10 @@ export async function fetchJuan(work: string, juan: string, mode: CbetaDbMode) {
documentString = await getFileAsStringFromIndexedDB(`/${cbetaBookcaseDir}/${xmlPath}`);
figurePath = `https://${Constants.indexedDBHost}/${cbetaBookcaseDir}/CBETA/figures`;
} else if (mode === CbetaDbMode.OfflineFileSystemV2) {
documentString = await readBookcaseFromFileSystem(xmlPath);
documentString = await readBookcaseFromFileSystemV2(xmlPath);
figurePath = `${Globals.localFileProtocolName}://${cbetaBookcaseDir}/CBETA/figures`;
} else if (mode === CbetaDbMode.OfflineFileSystemV3) {
documentString = await readBookcaseFromFileSystemV3(xmlPath);
figurePath = `${Globals.localFileProtocolName}://${cbetaBookcaseDir}/CBETA/figures`;
}

Expand Down Expand Up @@ -382,7 +407,7 @@ async function elementTPostprocessing(doc: Document, node: Node, parent: Node |
}
}

async function readResourceFromFileSystem(path: string) {
async function readResourceFromFileSystemV2(path: string) {
electronBackendApi?.send('toMain', { event: 'readResource', path: path });
return new Promise<any>((ok, fail) => {
electronBackendApi?.receiveOnce('fromMain', (data: any) => {
Expand All @@ -399,7 +424,7 @@ async function readResourceFromFileSystem(path: string) {
});
}

async function readBookcaseFromFileSystem(path: string) {
async function readBookcaseFromFileSystemV2(path: string) {
electronBackendApi?.send('toMain', { event: 'readBookcase', path: path });
return new Promise<any>((ok, fail) => {
electronBackendApi?.receiveOnce('fromMain', (data: any) => {
Expand All @@ -416,6 +441,26 @@ async function readBookcaseFromFileSystem(path: string) {
});
}

async function readResourceFromFileSystemV3(path: string) {
return electronBackendApi?.invoke('toMainV3', { event: 'readResource', path: path }).then((data: any) => {
if (data.error) {
return Promise.reject(data.error);
} else {
return Promise.resolve(data.data);
}
});
}

async function readBookcaseFromFileSystemV3(path: string) {
return electronBackendApi?.invoke('toMainV3', { event: 'readBookcase', path: path }).then((data: any) => {
if (data.error) {
return Promise.reject(data.error);
} else {
return Promise.resolve(data.data);
}
});
}

const CbetaOfflineDb = {
filesFilter,
init,
Expand Down
1 change: 1 addition & 0 deletions src/components/CatalogTouch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ class _CatalogTouch extends React.Component<PageProps, State> {
switch (this.props.settings.cbetaOfflineDbMode) {
case CbetaDbMode.OfflineIndexedDb:
case CbetaDbMode.OfflineFileSystemV2:
case CbetaDbMode.OfflineFileSystemV3:
obj = await CbetaOfflineDb.fetchCatalogs(path || 'CBETA', this.props.settings.cbetaOfflineDbMode);
break;
case CbetaDbMode.OfflineFileSystem:
Expand Down
1 change: 1 addition & 0 deletions src/components/WorkTouch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ class _WorkTouchPage extends React.Component<PageProps, State> {
switch (this.props.settings.cbetaOfflineDbMode) {
case CbetaDbMode.OfflineIndexedDb:
case CbetaDbMode.OfflineFileSystemV2:
case CbetaDbMode.OfflineFileSystemV3:
data = await CbetaOfflineDb.fetchWork(path, this.props.settings.cbetaOfflineDbMode);
break;
case CbetaDbMode.OfflineFileSystem:
Expand Down
1 change: 1 addition & 0 deletions src/fetchJuan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export default async function fetchJuan(work: string, juan: string, htmlFile: st
switch (cbetaOfflineDbMode) {
case CbetaDbMode.OfflineIndexedDb:
case CbetaDbMode.OfflineFileSystemV2:
case CbetaDbMode.OfflineFileSystemV3:
data = await fetchJuanFromIndexedDB(work, juan, cbetaOfflineDbMode);
break;
case CbetaDbMode.OfflineFileSystem:
Expand Down
1 change: 1 addition & 0 deletions src/models/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export enum CbetaDbMode {
OfflineFileSystem,
OfflineIndexedDb,
OfflineFileSystemV2,
OfflineFileSystemV3,
}

export enum UiMode {
Expand Down
1 change: 1 addition & 0 deletions src/pages/CatalogDesktopPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ class _CatalogDesktopPage extends React.Component<PageProps, State> {
switch (this.props.settings.cbetaOfflineDbMode) {
case CbetaDbMode.OfflineIndexedDb:
case CbetaDbMode.OfflineFileSystemV2:
case CbetaDbMode.OfflineFileSystemV3:
obj = await CbetaOfflineDb.fetchAllCatalogs(this.props.settings.cbetaOfflineDbMode);
break;
case CbetaDbMode.OfflineFileSystem:
Expand Down
20 changes: 19 additions & 1 deletion srcElectron/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,11 +239,29 @@ async function createWindow() {
} catch (error) {
mainWindow?.webContents.send('fromMain', Object.assign({ event: args.event }, { error: error }));
}

break;
}
});

ipcMain.handle('toMainV3', async (ev, args) => {
switch (args.event) {
case 'readResource':
try {
const str = fs.readFileSync(`${isDevMode() ? '.' : resourcesPath}/${args.path}`).toString();
return { event: args.event, data: str };
} catch (error) {
return { event: args.event, error: error };
}
case 'readBookcase':
try {
const str = fs.readFileSync(`${settings.cbetaBookcaseDir}/${args.path}`).toString();
return { event: args.event, data: str };
} catch (error) {
return { event: args.event, error: error };
}
}
});

const clearListeners = () => {
mainWindow?.webContents.removeAllListeners('did-finish-load');
mainWindow?.webContents.removeAllListeners('did-fail-load');
Expand Down
8 changes: 8 additions & 0 deletions srcElectron/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ contextBridge.exposeInMainWorld(
ipcRenderer.once(channel, (event: any, ...args: any[]) => func(...args));
}
},
invoke: (channel: string, data: any) => {
let validChannels = ["toMainV3"];
if (validChannels.includes(channel)) {
// Deliberately strip event as it includes `sender`
return ipcRenderer.invoke(channel, data);
}
return Promise.reject('Invalid invoke channel.');
},
removeAllListeners: (channel: string) => {
ipcRenderer.removeAllListeners(channel);
}
Expand Down
6 changes: 0 additions & 6 deletions srcElectron/renderer.js

This file was deleted.

0 comments on commit 5d5676c

Please sign in to comment.