diff --git a/electron/mapi/app/index.ts b/electron/mapi/app/index.ts index c1fa4e97..abaa8384 100644 --- a/electron/mapi/app/index.ts +++ b/electron/mapi/app/index.ts @@ -130,17 +130,18 @@ const spawnShell = async (command: string | string[], option: { */ const availablePort = async (start: number): Promise => { for (let i = start; i < 65535; i++) { - const available = await isPortAvailable('0.0.0.0', i) - // console.log('isPortAvailable', i, available) - if (available) { + const available = await isPortAvailable(i, '0.0.0.0') + const availableLocal = await isPortAvailable(i, '127.0.0.1') + // console.log('isPortAvailable', i, available, availableLocal) + if (available && availableLocal) { return i } } throw new Error('no available port') } -const isPortAvailable = async (host: string, port: number): Promise => { +const isPortAvailable = async (port: number, host?: string): Promise => { return new Promise((resolve) => { const server = net.createServer() server.listen(port, host) @@ -164,6 +165,8 @@ const fixExecutable = async (executable: string) => { export const Apps = { shell, spawnShell, + availablePort, + isPortAvailable, } export default { diff --git a/electron/mapi/event/main.ts b/electron/mapi/event/main.ts index 03ca767f..bf095cf5 100644 --- a/electron/mapi/event/main.ts +++ b/electron/mapi/event/main.ts @@ -2,12 +2,13 @@ import {AppRuntime} from "../env"; import {ipcMain} from "electron"; import {StrUtil} from "../../lib/util"; + const init = () => { } type NameType = 'main' | string -type EventType = 'APP_READY' | 'CALL_THIRD_PARTY' | 'CALL_PAGE' +type EventType = 'APP_READY' | 'CALL_THIRD_PARTY' | 'CALL_PAGE' | 'CHANNEL' const send = (name: NameType, type: EventType, data: any = {}, id?: string): boolean => { id = id || StrUtil.randomString(32) @@ -16,6 +17,7 @@ const send = (name: NameType, type: EventType, data: any = {}, id?: string): boo if (!AppRuntime.mainWindow) { return false } + // console.log('send', payload) AppRuntime.mainWindow?.webContents.send('MAIN_PROCESS_MESSAGE', payload) } else { if (!AppRuntime.windows[name]) { @@ -76,11 +78,49 @@ ipcMain.handle('event:callPage', async (_, name: string, type: string, data: any }) }) +const sendChannel = (channel: string, data: any) => { + send('main', 'CHANNEL', {channel, data}) +} + +let onChannelIsListen = false +let channelOnCallback = {} + +const onChannel = (channel: string, callback: (data: any) => void) => { + if (!channelOnCallback[channel]) { + channelOnCallback[channel] = [] + } + channelOnCallback[channel].push(callback) + if (!onChannelIsListen) { + onChannelIsListen = true + ipcMain.handle('event:channelSend', (event, channel_, data) => { + if (channelOnCallback[channel_]) { + channelOnCallback[channel_].forEach((callback: (data: any) => void) => { + callback(data) + }) + } + }) + } +} + +const offChannel = (channel: string, callback: (data: any) => void) => { + if (channelOnCallback[channel]) { + channelOnCallback[channel] = channelOnCallback[channel].filter((item: (data: any) => void) => { + return item !== callback + }) + } + if (channelOnCallback[channel].length === 0) { + delete channelOnCallback[channel] + } +} + export default { init, send } export const Events = { - send + send, + sendChannel, + onChannel, + offChannel, } diff --git a/electron/mapi/event/render.ts b/electron/mapi/event/render.ts index 804825da..58903e21 100644 --- a/electron/mapi/event/render.ts +++ b/electron/mapi/event/render.ts @@ -5,7 +5,7 @@ const init = () => { } const send = (name: string, type: string, data: any = {}) => { - ipcRenderer.invoke('event:send', name, type, data).then() + return ipcRenderer.invoke('event:send', name, type, data).then() } const callThirdParty = async (name: string, type: string, data: any, option: any) => { @@ -16,9 +16,28 @@ const callPage = async (name: string, type: string, data: any, option: any) => { return ipcRenderer.invoke('event:callPage', name, type, data, option) } + +const channelCreate = async (callback: (data: any) => void) => { + const channel = Math.random().toString(36).substring(2) + window['__channel'] = window['__channel'] || {} + window['__channel'][channel] = callback + return channel +} + +const channelDestroy = async (channel: string) => { + delete window['__channel'][channel] +} + +const channelSend = async (channel: string, data: any) => { + return ipcRenderer.invoke('event:channelSend', channel, data) +} + export default { init, send, callThirdParty, - callPage + callPage, + channelCreate, + channelDestroy, + channelSend, } diff --git a/electron/mapi/main.ts b/electron/mapi/main.ts index a6b2d0af..3682d5fc 100644 --- a/electron/mapi/main.ts +++ b/electron/mapi/main.ts @@ -11,6 +11,8 @@ import page from "./page/main"; import user from "./user/main"; import misc from "./misc/main"; +import server from "./server/main"; + const $mapi = { app, log, @@ -23,7 +25,8 @@ const $mapi = { keys, page, user, - misc + misc, + server } export const MAPI = { diff --git a/electron/mapi/render.ts b/electron/mapi/render.ts index a61761f1..b5b554c2 100644 --- a/electron/mapi/render.ts +++ b/electron/mapi/render.ts @@ -19,6 +19,7 @@ import misc from "./misc/render"; import adb from "./adb/render"; import scrcpy from "./scrcpy/render"; import ffmpeg from "./ffmpeg/render"; +import server from "./server/render"; export const MAPI = { init(env: typeof AppEnv = null) { @@ -43,6 +44,7 @@ export const MAPI = { adb, scrcpy, ffmpeg, + server, }) db.init() event.init() diff --git a/electron/preload/index.ts b/electron/preload/index.ts index 46abacf1..f3966eac 100644 --- a/electron/preload/index.ts +++ b/electron/preload/index.ts @@ -50,6 +50,16 @@ ipcRenderer.on('MAIN_PROCESS_MESSAGE', (_event: any, payload: any) => { (resultData: any) => send(0, 'ok', resultData), (error: string) => send(-1, error) ) + } else if ('CHANNEL' === payload.type) { + // console.log('CHANNEL', payload) + const {channel, data} = payload.data + if (!window['__channel']) { + return + } + if (!window['__channel'][channel]) { + return + } + window['__channel'][channel](data) } else { console.warn('Unknown message from main process:', JSON.stringify(payload)) } diff --git a/src/declarations/mapi.d.ts b/src/declarations/mapi.d.ts index 3151798f..824dfcae 100644 --- a/src/declarations/mapi.d.ts +++ b/src/declarations/mapi.d.ts @@ -91,6 +91,10 @@ declare interface Window { send: (name: string, type: string, data: any) => void, callThirdParty: (name: string, type: string, data: any, option?: any) => Promise>, callPage: (name: string, type: string, data?: any, option?: any) => Promise>, + // channel main <-> render + channelCreate: (callback: (data: any) => void) => Promise, + channelDestroy: (channel: string) => Promise, + channelSend: (channel: string, data: any) => Promise, }, page: { open: (name: string, option?: any) => Promise, @@ -180,7 +184,11 @@ declare interface Window { ffmpeg: { version: () => Promise, run: (args: string[]) => Promise, - } + }, + server: { + // define any string to any value + [key: string]: Function, + }, } } diff --git a/src/store/modules/task.ts b/src/store/modules/task.ts index c16124c3..f039f902 100644 --- a/src/store/modules/task.ts +++ b/src/store/modules/task.ts @@ -7,7 +7,7 @@ import {mapError} from "../../lib/error"; export type TaskRecordStatus = 'queue' | 'running' | 'querying' | 'success' | 'fail' | 'delete' -export type TaskRecordRunStatus = 'retry' | 'success' +export type TaskRecordRunStatus = 'retry' | 'success' | 'querying' export type TaskRecordQueryStatus = 'running' | 'success' | 'fail' @@ -87,23 +87,27 @@ export const taskStore = defineStore("task", { record.status = 'running' record.runStart = Date.now() record.runCalling = true + this.fireChange(record, 'running') this.bizMap[record.biz] .runFunc(record.bizId, record.bizParam) .then((status: TaskRecordRunStatus) => { - if ('retry' === status) { - record.status = 'queue' - record.runStart = 0 - record.runAfter = Date.now() + 1000 - } else { - if (!!this.bizMap[record.biz].queryFunc) { + switch (status) { + case 'success': + record.status = 'success' + break + case 'querying': record.queryAfter = Date.now() + record.queryInterval record.status = 'querying' - } else { - record.status = 'success' - } + break + case 'retry': + record.status = 'queue' + record.runStart = 0 + record.runAfter = Date.now() + 1000 + break } }) .catch((e) => { + console.error('task.runFunc.error', e) record.status = 'fail' record.msg = mapError(e) }) @@ -136,6 +140,7 @@ export const taskStore = defineStore("task", { } }) .catch((e) => { + console.error('task.queryFunc.error', e) record.status = 'fail' record.msg = mapError(e) changed = true @@ -166,6 +171,7 @@ export const taskStore = defineStore("task", { record.status = 'delete' }) .catch((e) => { + console.error('task.successFunc.error', e) record.status = 'fail' record.msg = mapError(e) }) @@ -190,6 +196,8 @@ export const taskStore = defineStore("task", { .then(() => { }) .catch((e) => { + console.error('task.failFunc.error', e) + window.$mapi.log.error(`task.failFunc:${e}`) }) .finally(() => { this.fireChange(record, 'fail')