diff --git a/desktop/package.json b/desktop/package.json index 6f6dd260..a8ee749a 100644 --- a/desktop/package.json +++ b/desktop/package.json @@ -110,6 +110,7 @@ }, "dependencies": { "electron-debug": "^3.2.0", + "electron-is": "^3.0.0", "electron-log": "^4.4.7", "electron-serve": "^1.1.0", "electron-updater": "^5.0.1", diff --git a/desktop/release/app/package.json b/desktop/release/app/package.json index dd8898f2..5e5b4b92 100644 --- a/desktop/release/app/package.json +++ b/desktop/release/app/package.json @@ -1,5 +1,5 @@ { - "name": "tailchat-meeting", + "name": "tailchat-desktop", "version": "0.0.1", "description": "A foundation for scalable desktop apps", "license": "MIT", diff --git a/desktop/src/main/lib/serve.ts b/desktop/src/main/lib/serve.ts new file mode 100644 index 00000000..8360a537 --- /dev/null +++ b/desktop/src/main/lib/serve.ts @@ -0,0 +1,150 @@ +/** + * Fork from: https://github.com/sindresorhus/electron-serve + * + * Has some problem + */ + +import fs from 'fs'; +import path from 'path'; +import { promisify } from 'util'; +import electron, { + BrowserWindow, + ProtocolRequest, + ProtocolResponse, +} from 'electron'; +import log from 'electron-log'; +import is from 'electron-is'; + +interface Options { + /** + The directory to serve, relative to the app root directory. + */ + directory: string; + + /** + Custom scheme. For example, `foo` results in your `directory` being available at `foo://-`. + @default 'app' + */ + scheme?: string; + + /** + Whether [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) should be enabled. + Useful for testing purposes. + @default true + */ + isCorsEnabled?: boolean; + + /** + The partition the protocol should be installed to, if you're not using Electron's default partition. + @default electron.session.defaultSession + */ + partition?: string; +} + +const stat = promisify(fs.stat); + +// See https://cs.chromium.org/chromium/src/net/base/net_error_list.h +const FILE_NOT_FOUND = -6; + +async function getPath(_path: string): Promise { + try { + const result = await stat(_path); + + if (result.isFile()) { + return _path; + } + + if (result.isDirectory()) { + return getPath(path.join(_path, 'index.html')); + } + } catch (_) {} +} + +export default (options: Options) => { + const scheme = options.scheme ?? 'app'; + const isCorsEnabled = options.isCorsEnabled ?? true; + + if (!options.directory) { + throw new Error('The `directory` option is required'); + } + + const directory = path.resolve(electron.app.getAppPath(), options.directory); + + const handler = async ( + request: ProtocolRequest, + callback: (response: ProtocolResponse) => void + ) => { + log.info('Request custom scheme url:', request.url); + + const pathname = new URL(request.url).pathname; + + if (is.dev()) { + callback({ + headers: request.headers, + method: request.method, + referrer: request.referrer, + url: `http://localhost:1212/${request.url.replace('app://-/', '')}`, + }); + return; + } + + const indexPath = path.join(directory, 'index.html'); + const filePath = path.join(directory, decodeURIComponent(pathname)); + const resolvedPath = await getPath(filePath); + const fileExtension = path.extname(filePath); + + log.info('Request custom scheme path', { + indexPath, + filePath, + resolvedPath, + fileExtension, + }); + + if ( + resolvedPath || + !fileExtension || + fileExtension === '.html' || + fileExtension === '.asar' + ) { + callback({ + path: resolvedPath || indexPath, + }); + } else { + callback({ error: FILE_NOT_FOUND }); + } + }; + + log.info('register scheme:', scheme); + try { + electron.protocol.registerSchemesAsPrivileged([ + { + scheme, + privileges: { + standard: true, + secure: true, + allowServiceWorkers: true, + supportFetchAPI: true, + corsEnabled: isCorsEnabled, + }, + }, + ]); + } catch (e) { + log.error('register scheme error:', e); + } + + electron.app.on('ready', () => { + const session = options.partition + ? electron.session.fromPartition(options.partition) + : electron.session.defaultSession; + + if (is.dev()) { + session.protocol.registerHttpProtocol(scheme, handler); + } else { + session.protocol.registerFileProtocol(scheme, handler); + } + }); + + return async (window: BrowserWindow) => { + await window.loadURL(`${scheme}://-`); + }; +}; diff --git a/desktop/src/main/main.ts b/desktop/src/main/main.ts index b6248e86..3a895b0b 100644 --- a/desktop/src/main/main.ts +++ b/desktop/src/main/main.ts @@ -15,9 +15,16 @@ import log from 'electron-log'; import MenuBuilder from './menu'; import { resolveHtmlPath } from './util'; import windowStateKeeper from 'electron-window-state'; +import is from 'electron-is'; log.info('Start...'); +if (is.dev()) { + console.log('==========================='); + console.log('Log file:', log.transports.file.getFile().path); + console.log('==========================='); +} + export default class AppUpdater { constructor() { log.transports.file.level = 'info'; diff --git a/desktop/src/main/util.ts b/desktop/src/main/util.ts index 4d86f7ef..4929e751 100644 --- a/desktop/src/main/util.ts +++ b/desktop/src/main/util.ts @@ -1,4 +1,3 @@ -/* eslint import/prefer-default-export: off, import/no-mutable-exports: off */ import { URL } from 'url'; import path from 'path'; diff --git a/desktop/yarn.lock b/desktop/yarn.lock index 007172a7..71607707 100644 --- a/desktop/yarn.lock +++ b/desktop/yarn.lock @@ -4478,11 +4478,24 @@ electron-is-accelerator@^0.1.0: resolved "https://registry.npmmirror.com/electron-is-accelerator/-/electron-is-accelerator-0.1.2.tgz#509e510c26a56b55e17f863a4b04e111846ab27b" integrity sha512-fLGSAjXZtdn1sbtZxx52+krefmtNuVwnJCV2gNiVt735/ARUboMl8jnNC9fZEqQdlAv2ZrETfmBUsoQci5evJA== +electron-is-dev@^0.3.0: + version "0.3.0" + resolved "https://registry.npmmirror.com/electron-is-dev/-/electron-is-dev-0.3.0.tgz#14e6fda5c68e9e4ecbeff9ccf037cbd7c05c5afe" + integrity sha512-jLttuuq8QK67n3mXmIe9pkrO7IH3LGIk12xJkhTmc852U2sCJaRAOpRGPSh+1Xnzck5v9escd9YXzuze9nGejg== + electron-is-dev@^1.1.0: version "1.2.0" resolved "https://registry.npmmirror.com/electron-is-dev/-/electron-is-dev-1.2.0.tgz#2e5cea0a1b3ccf1c86f577cee77363ef55deb05e" integrity sha512-R1oD5gMBPS7PVU8gJwH6CtT0e6VSoD0+SzSnYpNm+dBkcijgA+K7VAMHDfnRq/lkKPZArpzplTW6jfiMYosdzw== +electron-is@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/electron-is/-/electron-is-3.0.0.tgz#bd4c27651fbe03f243f3607c2a098be884f9ed50" + integrity sha512-aQv1y3WrDZ+mtO8acbhiiip/8fa0Et7cvZyvlqJm2H7fih4hiJWEFRyYxzLgDG2kmiLdF8l3y5tbek5JFOPQkQ== + dependencies: + electron-is-dev "^0.3.0" + semver "^5.5.0" + electron-localshortcut@^3.1.0: version "3.2.1" resolved "https://registry.npmmirror.com/electron-localshortcut/-/electron-localshortcut-3.2.1.tgz#cfc83a3eff5e28faf98ddcc87f80a2ce4f623cd3" @@ -9456,7 +9469,7 @@ semver@7.x, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^ dependencies: lru-cache "^6.0.0" -semver@^5.6.0, semver@^5.7.1: +semver@^5.5.0, semver@^5.6.0, semver@^5.7.1: version "5.7.1" resolved "https://registry.npmmirror.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==