|
@@ -24,7 +24,7 @@ if (!app.requestSingleInstanceLock()) { app.quit() }
|
|
|
else {
|
|
else {
|
|
|
let window, tray, manager, runnerManager, quitting = false, closing = false, timer
|
|
let window, tray, manager, runnerManager, quitting = false, closing = false, timer
|
|
|
let updateWindow, updater, environmentHost, hostManager, loginWindow
|
|
let updateWindow, updater, environmentHost, hostManager, loginWindow
|
|
|
- let remoteMode = false, remoteURL = '', serverModeActive = false
|
|
|
|
|
|
|
+ let remoteMode = false, remoteURL = '', serverModeActive = false, switchingMode = false
|
|
|
const serviceURL = () => remoteMode ? remoteURL : manager?.state.url
|
|
const serviceURL = () => remoteMode ? remoteURL : manager?.state.url
|
|
|
const serviceOrigins = () => {
|
|
const serviceOrigins = () => {
|
|
|
try { return remoteMode && remoteURL ? [new URL(remoteURL).origin] : manager?.state.url ? [new URL(manager.state.url).origin] : [] }
|
|
try { return remoteMode && remoteURL ? [new URL(remoteURL).origin] : manager?.state.url ? [new URL(manager.state.url).origin] : [] }
|
|
@@ -283,6 +283,26 @@ else {
|
|
|
})
|
|
})
|
|
|
async function hostAction(action){try{await action()}catch(error){await dialog.showMessageBox(window,{type:'error',message:'桌面主机操作未完成',detail:error.message})}}
|
|
async function hostAction(action){try{await action()}catch(error){await dialog.showMessageBox(window,{type:'error',message:'桌面主机操作未完成',detail:error.message})}}
|
|
|
const appDialog = options => window && !window.isDestroyed() ? dialog.showMessageBox(window, options) : dialog.showMessageBox(options)
|
|
const appDialog = options => window && !window.isDestroyed() ? dialog.showMessageBox(window, options) : dialog.showMessageBox(options)
|
|
|
|
|
+ function requireModePage(event){
|
|
|
|
|
+ let trusted=false
|
|
|
|
|
+ try{trusted=event.sender===window?.webContents&&event.senderFrame===window.webContents.mainFrame
|
|
|
|
|
+ &&serviceOrigins().includes(new URL(event.senderFrame.url).origin)}catch{}
|
|
|
|
|
+ if(!trusted||closing||quitting)throw new Error('不允许此页面切换桌面运行模式')
|
|
|
|
|
+ }
|
|
|
|
|
+ ipcMain.handle('desktop:mode-state',event=>{
|
|
|
|
|
+ requireModePage(event)
|
|
|
|
|
+ return {mode:remoteMode?'client':'server',serverURL:serviceURL()||'',switching:switchingMode}
|
|
|
|
|
+ })
|
|
|
|
|
+ ipcMain.handle('desktop:mode-switch',async(event,mode)=>{
|
|
|
|
|
+ requireModePage(event)
|
|
|
|
|
+ if(mode!=='client'&&mode!=='server')throw new Error('运行模式无效')
|
|
|
|
|
+ return switchMode(mode==='client'?'remote':'local',false)
|
|
|
|
|
+ })
|
|
|
|
|
+ ipcMain.handle('desktop:remote-login',event=>{
|
|
|
|
|
+ requireModePage(event)
|
|
|
|
|
+ if(switchingMode)throw new Error('正在切换运行模式,请稍候')
|
|
|
|
|
+ openRemoteLogin()
|
|
|
|
|
+ })
|
|
|
async function importDesktopHost(){
|
|
async function importDesktopHost(){
|
|
|
const selection=window&&!window.isDestroyed()
|
|
const selection=window&&!window.isDestroyed()
|
|
|
?await dialog.showOpenDialog(window,{title:'导入桌面主机配置',properties:['openFile'],filters:[{name:'桌面主机配置',extensions:['json']}]})
|
|
?await dialog.showOpenDialog(window,{title:'导入桌面主机配置',properties:['openFile'],filters:[{name:'桌面主机配置',extensions:['json']}]})
|
|
@@ -330,29 +350,36 @@ else {
|
|
|
function syncModeMenu(){
|
|
function syncModeMenu(){
|
|
|
const menu=Menu.getApplicationMenu()
|
|
const menu=Menu.getApplicationMenu()
|
|
|
const useRemote=menu?.getMenuItemById('desktop-host-use-remote'),useLocal=menu?.getMenuItemById('desktop-host-use-local'),ask=menu?.getMenuItemById('desktop-host-ask')
|
|
const useRemote=menu?.getMenuItemById('desktop-host-use-remote'),useLocal=menu?.getMenuItemById('desktop-host-use-local'),ask=menu?.getMenuItemById('desktop-host-ask')
|
|
|
- if(useRemote)useRemote.enabled=!remoteMode
|
|
|
|
|
- if(useLocal)useLocal.enabled=!serverModeActive
|
|
|
|
|
|
|
+ if(useRemote)useRemote.enabled=!switchingMode&&!remoteMode
|
|
|
|
|
+ if(useLocal)useLocal.enabled=!switchingMode&&!serverModeActive
|
|
|
|
|
+ const status=menu?.getMenuItemById('desktop-mode-status')
|
|
|
|
|
+ if(status)status.label=switchingMode?'正在切换运行模式…':remoteMode?'当前:客户端模式':serverModeActive?'当前:服务器模式':'请选择运行模式'
|
|
|
if(ask)ask.checked=preferences.value.startupChoice==='ask'
|
|
if(ask)ask.checked=preferences.value.startupChoice==='ask'
|
|
|
}
|
|
}
|
|
|
- async function switchMode(mode){
|
|
|
|
|
- if(closing||quitting)return
|
|
|
|
|
|
|
+ async function switchMode(mode,notify=true){
|
|
|
|
|
+ if(closing||quitting)return {ok:false,error:'App 正在退出'}
|
|
|
|
|
+ if(switchingMode)return {ok:false,error:'正在切换运行模式,请稍候'}
|
|
|
|
|
+ if(mode==='remote'&&remoteMode||mode==='local'&&serverModeActive)return {ok:true}
|
|
|
|
|
+ switchingMode=true;syncModeMenu()
|
|
|
try{
|
|
try{
|
|
|
if(mode==='remote'){
|
|
if(mode==='remote'){
|
|
|
if(await enterRemoteMode()){
|
|
if(await enterRemoteMode()){
|
|
|
if(window&&!window.isDestroyed())void window.loadURL(remoteURL)
|
|
if(window&&!window.isDestroyed())void window.loadURL(remoteURL)
|
|
|
- await appDialog({type:'info',message:'已登录远程服务器',detail:`窗口已切换到 ${remoteURL},本 App 已断开本机服务;这台 Mac 的桌面可在远程服务器的电脑面板中授权使用。`})
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ }else return {ok:true,pendingLogin:true}
|
|
|
}else{
|
|
}else{
|
|
|
|
|
+ loginWindow?.close()
|
|
|
serverModeActive=true;remoteMode=false;remoteURL=''
|
|
serverModeActive=true;remoteMode=false;remoteURL=''
|
|
|
await hostManager?.stop().catch(error=>log(error.message))
|
|
await hostManager?.stop().catch(error=>log(error.message))
|
|
|
await preferences.setStartupChoice('local').catch(error=>log(error.message))
|
|
await preferences.setStartupChoice('local').catch(error=>log(error.message))
|
|
|
if(window&&!window.isDestroyed())void window.loadFile(join(desktopRoot,'boot.html'))
|
|
if(window&&!window.isDestroyed())void window.loadFile(join(desktopRoot,'boot.html'))
|
|
|
await manager?.start().catch(error=>log(error.message))
|
|
await manager?.start().catch(error=>log(error.message))
|
|
|
if(!closing)environmentHost?.start()
|
|
if(!closing)environmentHost?.start()
|
|
|
- await appDialog({type:'info',message:'已切换为服务器',detail:'本机夭夭服务正在启动,就绪后窗口会自动打开。'})
|
|
|
|
|
}
|
|
}
|
|
|
- syncModeMenu()
|
|
|
|
|
- }catch(error){await appDialog({type:'error',message:'切换使用方式未完成',detail:error.message})}
|
|
|
|
|
|
|
+ return {ok:true}
|
|
|
|
|
+ }catch(error){
|
|
|
|
|
+ if(notify)await appDialog({type:'error',message:'切换使用方式未完成',detail:error.message})
|
|
|
|
|
+ return {ok:false,error:error.message}
|
|
|
|
|
+ }finally{switchingMode=false;syncModeMenu()}
|
|
|
}
|
|
}
|
|
|
ipcMain.handle('desktop-remote-login:submit',async(_event,value)=>{
|
|
ipcMain.handle('desktop-remote-login:submit',async(_event,value)=>{
|
|
|
if(closing||quitting)return {ok:false,error:'App 正在退出'}
|
|
if(closing||quitting)return {ok:false,error:'App 正在退出'}
|
|
@@ -380,7 +407,7 @@ else {
|
|
|
})
|
|
})
|
|
|
ipcMain.handle('desktop-remote-login:use-local',async()=>{
|
|
ipcMain.handle('desktop-remote-login:use-local',async()=>{
|
|
|
loginWindow?.close()
|
|
loginWindow?.close()
|
|
|
- if(!remoteMode){
|
|
|
|
|
|
|
+ if(!serverModeActive){
|
|
|
if(!window||window.isDestroyed())createWindow()
|
|
if(!window||window.isDestroyed())createWindow()
|
|
|
await switchMode('local')
|
|
await switchMode('local')
|
|
|
}
|
|
}
|
|
@@ -428,14 +455,16 @@ else {
|
|
|
{id:'runner-import',label:'导入节点配置…',click:importRunner},
|
|
{id:'runner-import',label:'导入节点配置…',click:importRunner},
|
|
|
{id:'runner-reconnect',label:'重新连接',click:()=>runnerAction(()=>runnerManager.start())},
|
|
{id:'runner-reconnect',label:'重新连接',click:()=>runnerAction(()=>runnerManager.start())},
|
|
|
{id:'runner-forget',label:'断开并忘记配置',click:()=>runnerAction(()=>runnerManager.forget())}]},
|
|
{id:'runner-forget',label:'断开并忘记配置',click:()=>runnerAction(()=>runnerManager.forget())}]},
|
|
|
|
|
+ {label:'运行模式',submenu:[{id:'desktop-mode-status',label:'请选择运行模式',enabled:false},{type:'separator'},
|
|
|
|
|
+ {id:'desktop-host-use-remote',label:'客户端模式(连接服务器)',enabled:!remoteMode,click:()=>void switchMode('remote')},
|
|
|
|
|
+ {id:'desktop-host-use-local',label:'服务器模式(本机运行)',enabled:!serverModeActive,click:()=>void switchMode('local')},
|
|
|
|
|
+ {label:'更换服务器…',click:openRemoteLogin},{type:'separator'},
|
|
|
|
|
+ {id:'desktop-host-ask',label:'启动时询问运行模式',type:'checkbox',checked:preferences.value.startupChoice==='ask',
|
|
|
|
|
+ click:item=>{void preferences.setStartupChoice(item.checked?'ask':remoteMode?'remote':'local').catch(async error=>{item.checked=preferences.value.startupChoice==='ask';await appDialog({type:'error',message:'无法保存启动偏好',detail:error.message})})}}]},
|
|
|
{label:'桌面主机',submenu:[{id:'desktop-host-status',label:'未配置桌面主机',enabled:false},{type:'separator'},
|
|
{label:'桌面主机',submenu:[{id:'desktop-host-status',label:'未配置桌面主机',enabled:false},{type:'separator'},
|
|
|
- {id:'desktop-host-use-remote',label:'登录远程服务器…',enabled:!remoteMode,click:()=>void switchMode('remote')},
|
|
|
|
|
- {id:'desktop-host-use-local',label:'作为服务器运行',enabled:!serverModeActive,click:()=>void switchMode('local')},{type:'separator'},
|
|
|
|
|
{id:'desktop-host-import',label:'导入主机配置…',click:importDesktopHost},
|
|
{id:'desktop-host-import',label:'导入主机配置…',click:importDesktopHost},
|
|
|
{id:'desktop-host-reconnect',label:'重新连接',click:()=>hostAction(()=>hostManager.start())},
|
|
{id:'desktop-host-reconnect',label:'重新连接',click:()=>hostAction(()=>hostManager.start())},
|
|
|
- {id:'desktop-host-forget',label:'断开并忘记配置',click:()=>hostAction(()=>hostManager.forget())},{type:'separator'},
|
|
|
|
|
- {id:'desktop-host-ask',label:'启动时询问使用方式',type:'checkbox',checked:preferences.value.startupChoice==='ask',
|
|
|
|
|
- click:item=>{void preferences.setStartupChoice(item.checked?'ask':'local').catch(async error=>{item.checked=preferences.value.startupChoice==='ask';await appDialog({type:'error',message:'无法保存启动偏好',detail:error.message})})}}]},
|
|
|
|
|
|
|
+ {id:'desktop-host-forget',label:'断开并忘记配置',click:()=>hostAction(()=>hostManager.forget())}]},
|
|
|
{ role: 'editMenu', label: '编辑' }, { role: 'viewMenu', label: '显示' }, { role: 'windowMenu', label: '窗口' },
|
|
{ role: 'editMenu', label: '编辑' }, { role: 'viewMenu', label: '显示' }, { role: 'windowMenu', label: '窗口' },
|
|
|
]))
|
|
]))
|
|
|
const icon = nativeImage.createFromPath(join(desktopRoot, 'icon.png')).resize({ width: 20, height: 20 })
|
|
const icon = nativeImage.createFromPath(join(desktopRoot, 'icon.png')).resize({ width: 20, height: 20 })
|