feat: Electron 中打开页面增加 Scheme 模式

This commit is contained in:
purocean
2021-06-10 18:53:43 +08:00
parent 6bec9abfe2
commit 6e53bb2a04
3 changed files with 118 additions and 21 deletions
+48 -20
View File
@@ -1,4 +1,4 @@
import { app, BrowserWindow, Menu, Tray, powerMonitor } from 'electron'
import { protocol, app, BrowserWindow, Menu, Tray, powerMonitor } from 'electron'
import * as path from 'path'
import * as os from 'os'
import { dialog } from 'electron'
@@ -8,18 +8,28 @@ import { USER_DIR } from './server/constant'
import * as updater from './updater'
import { getAccelerator, registerShortcut } from './shortcut'
import { mainMenus, inputMenu, selectionMenu } from './menus';
import { SCHEME, transformProtocolRequest } from './protocol';
import { bus } from './bus'
const opn = require('opn')
const isMacos = os.platform() === 'darwin'
let isDev = false
let urlMode: 'scheme' | 'dev' | 'prod' = 'scheme'
const showTray = !(yargs.argv['disable-tray'])
const backendPort = Number(yargs.argv.port) || 3044
const devFrontendPort = 8066
const getUrl = () => {
Menu.setApplicationMenu(mainMenus)
// 主窗口
let win: BrowserWindow | null = null
// 系统托盘
let tray = null
const getUrl = (mode?: typeof urlMode) => {
mode = mode ?? urlMode
const args = Object.entries(yargs.argv).filter(x => [
'readonly',
'show-status-bar',
@@ -29,15 +39,15 @@ const getUrl = () => {
const query = (new URLSearchParams(args as any)).toString()
return `http://localhost:${isDev ? devFrontendPort : backendPort}` + (query ? `?${query}` : '')
const proto = mode === 'scheme' ? SCHEME : 'http'
const port = mode === 'dev' ? devFrontendPort : backendPort
console.log(mode, `${proto}://localhost:${port}` + (query ? `?${query}` : ''))
return `${proto}://localhost:${port}` + (query ? `?${query}` : '')
}
Menu.setApplicationMenu(mainMenus)
// 主窗口
let win: BrowserWindow | null = null
// 系统托盘
let tray = null
const openInBrowser = () => opn(getUrl('prod'))
const hide = () => {
if (win) {
@@ -177,7 +187,18 @@ if (!gotTheLock) {
app.on('ready', () => {
// 打开后端服务器
try {
server(backendPort)
const handler = server(backendPort)
protocol.registerStreamProtocol('yank-note', async (request, callback) => {
// 自定义 protocol 协议转换为 koa 请求
const { req, res, out } = await transformProtocolRequest(request)
await handler(req, res)
callback({
headers: res.getHeaders() as any,
statusCode: res.statusCode,
data: out,
})
})
} catch (error) {
app.exit(-1)
}
@@ -194,7 +215,7 @@ if (!gotTheLock) {
// 注册快捷键
registerShortcut({
'show-main-window': () => showWindow(),
'open-in-browser': () => opn(getUrl())
'open-in-browser': () => openInBrowser()
})
powerMonitor.on('shutdown', quit)
@@ -213,9 +234,7 @@ if (!gotTheLock) {
type: 'normal',
label: '浏览器中打开',
accelerator: getAccelerator('open-in-browser'),
click: () => {
opn(getUrl())
}
click: openInBrowser
},
{
type: 'normal',
@@ -245,19 +264,28 @@ if (!gotTheLock) {
submenu: [
{
type: 'radio',
checked: !isDev,
label: `正式端口(${backendPort})`,
checked: urlMode === 'scheme',
label: `正式端口(Schema)`,
click: () => {
isDev = false
urlMode = 'scheme'
reload()
}
},
{
type: 'radio',
checked: isDev,
checked: urlMode === 'prod',
label: `正式端口(${backendPort})`,
click: () => {
urlMode = 'prod'
reload()
}
},
{
type: 'radio',
checked: urlMode === 'dev',
label: `开发端口(${devFrontendPort})`,
click: () => {
isDev = true
urlMode = 'dev'
reload()
}
},
+66
View File
@@ -0,0 +1,66 @@
import { protocol, session, ProtocolRequest, UploadData } from 'electron'
import { IncomingMessage, ServerResponse } from 'http'
import { Readable } from 'stream'
import { Transform } from 'stream'
export const SCHEME = 'yank-note'
protocol.registerSchemesAsPrivileged([{
scheme: SCHEME,
privileges: {
supportFetchAPI: true,
standard: true,
secure: true,
allowServiceWorkers: true,
bypassCSP: true,
corsEnabled: true,
}
}])
async function transformBody(data?: UploadData[]): Promise<Buffer | null> {
if (!data) {
return null
}
let body = Buffer.from([])
for (const payload of data) {
if (payload.bytes) {
body = Buffer.concat([body, payload.bytes])
} else if (payload.blobUUID) {
const file = await session.defaultSession.getBlobData(payload.blobUUID)
body = Buffer.concat([body, file])
}
}
return body
}
export async function transformProtocolRequest (request: ProtocolRequest) {
const req = new IncomingMessage(null)
req.method = request.method
req.url = request.url.replace('yank-note', 'http')
Object.keys(request.headers).forEach(key => {
req.headers[key.toLowerCase()] = request.headers[key]
})
const body = await transformBody(request.uploadData)
if (body) {
req.headers['content-length'] = body.length.toString()
req._read = Readable.from(body)._read
}
const out = new Transform({
transform(chunk, encoding, cb) {
this.push(chunk, encoding)
cb()
},
})
const res = new ServerResponse(req)
res.write = out.write.bind(out)
res.end = out.end.bind(out)
return { req, res, out }
}
+4 -1
View File
@@ -302,7 +302,8 @@ const server = (port = 3000) => {
await sendFile(path.resolve(STATIC_DIR, urlPath), true);
})
const server = require('http').createServer(app.callback())
const callback = app.callback()
const server = require('http').createServer(callback)
const io = require('socket.io')(server, {path: '/ws'})
io.on('connection', (socket: any) => {
@@ -329,6 +330,8 @@ const server = (port = 3000) => {
server.listen(port, 'localhost')
console.log(`访问地址:http://localhost:${port}`)
return callback
}
if (require.main === module) {