add: base module
This commit is contained in:
3
src/main/app.ts
Normal file
3
src/main/app.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { useContextKey } from '@kevisual/use-config/context';
|
||||
|
||||
export { log, getLogPath } from './logger.ts';
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ipcMain } from 'electron';
|
||||
import { getAppList, getCacheAssistantConfig, setConfig } from '@/modules/config';
|
||||
import { installApp, uninstallApp } from '../proxy/install';
|
||||
import { relunch } from '../window/relunch';
|
||||
import { getAppList, getCacheAssistantConfig, setConfig } from '@/modules/config/index.ts';
|
||||
import { installApp, uninstallApp } from '../proxy/install.ts';
|
||||
import { relunch } from '../window/relunch.ts';
|
||||
|
||||
export const handle = () => {
|
||||
ipcMain.handle('get-app-list', (event, data) => {
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
import { app, BrowserWindow, ipcMain, session } from 'electron';
|
||||
import { app, BrowserWindow } from 'electron';
|
||||
import * as path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { LocalElectronAppUrl } from '../modules/config';
|
||||
import { createSession } from './session';
|
||||
import { handle } from './handle';
|
||||
import { loadMenu } from './menu';
|
||||
import { checkShowPage } from './window/page';
|
||||
import { createIntroducePage } from './window/page/introduce';
|
||||
import { createSession } from './session/index.ts';
|
||||
import { handle } from './handle/index.ts';
|
||||
import { loadMenu } from './menu/index.ts';
|
||||
import { getLogPath, log } from './app.ts';
|
||||
import { checkShowPage } from './window/page/index.ts';
|
||||
import { closeProcess, createProcess } from './process/index.ts';
|
||||
import { getElectronResourcePath } from './system/env.ts';
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
let mainWindow: BrowserWindow | null;
|
||||
|
||||
async function createWindow() {
|
||||
const resourcePath = getElectronResourcePath();
|
||||
log.info('resourcePath', resourcePath);
|
||||
log.info('createWindow');
|
||||
log.info('path', getLogPath());
|
||||
const _session = createSession();
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
@@ -20,6 +25,7 @@ async function createWindow() {
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, 'preload.js'), // 如果有 preload 脚本
|
||||
session: _session,
|
||||
webSecurity: false,
|
||||
},
|
||||
});
|
||||
loadMenu();
|
||||
@@ -30,12 +36,16 @@ async function createWindow() {
|
||||
});
|
||||
}
|
||||
|
||||
app.on('ready', createWindow);
|
||||
app.on('ready', async () => {
|
||||
await createProcess();
|
||||
createWindow();
|
||||
});
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit();
|
||||
}
|
||||
closeProcess();
|
||||
});
|
||||
|
||||
app.on('activate', () => {
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { createEnterPage } from '../window/page/enter';
|
||||
import { createEnterPage } from '../window/page/enter.ts';
|
||||
import { BrowserWindow, Menu, app } from 'electron';
|
||||
|
||||
import path from 'path';
|
||||
import { getLogPath, log } from '../logger';
|
||||
import { createAppPackagesPage } from '../window/page/app-packages';
|
||||
import { relunch } from '../window/relunch';
|
||||
import { getLogPath, log } from '../logger.ts';
|
||||
import { createAppPackagesPage } from '../window/page/app-packages.ts';
|
||||
import { relunch } from '../window/relunch.ts';
|
||||
import { checkShowPage } from '../window/page/index.ts';
|
||||
export const loadMenu = () => {
|
||||
const template = [
|
||||
{
|
||||
@@ -32,11 +33,40 @@ export const loadMenu = () => {
|
||||
// },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '打开应用',
|
||||
submenu: [
|
||||
{
|
||||
label: '首页',
|
||||
click: () => {
|
||||
// 获取当前window
|
||||
const mainWindow = BrowserWindow.getFocusedWindow();
|
||||
if (mainWindow) {
|
||||
checkShowPage(mainWindow);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '打开配置',
|
||||
click: async () => {
|
||||
createEnterPage();
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '打开应用市场',
|
||||
click: async () => {
|
||||
createAppPackagesPage();
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '编辑',
|
||||
submenu: [
|
||||
{ label: '复制', accelerator: 'CmdOrCtrl+C', selector: 'copy:' },
|
||||
{ label: '粘贴', accelerator: 'CmdOrCtrl+V', selector: 'paste:' },
|
||||
{ label: '撤销', accelerator: 'CmdOrCtrl+Z', selector: 'undo:' },
|
||||
{ label: '全选', accelerator: 'CmdOrCtrl+A', selector: 'selectAll:' },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -72,13 +102,6 @@ export const loadMenu = () => {
|
||||
label: '帮助',
|
||||
role: 'help',
|
||||
submenu: [
|
||||
{
|
||||
label: '文档',
|
||||
click: async () => {
|
||||
const { shell } = require('electron');
|
||||
// shell.openExternal('http://adstudio.nisar.ai/docs/');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '打开日志',
|
||||
click: async () => {
|
||||
@@ -87,18 +110,6 @@ export const loadMenu = () => {
|
||||
shell.openExternal('file://' + path.join(getLogPath()));
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '打开配置',
|
||||
click: async () => {
|
||||
createEnterPage();
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '打开应用市场',
|
||||
click: async () => {
|
||||
createAppPackagesPage();
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
82
src/main/process/index.ts
Normal file
82
src/main/process/index.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
// import { AssistantProcess } from '@kevisual/assistant-module/assistant-process';
|
||||
|
||||
import path from 'path';
|
||||
import { fork } from 'child_process';
|
||||
import { log } from '../app.ts';
|
||||
import { isMac, isDev, getElectronResourcePath } from '../system/env.ts';
|
||||
import { setProcessPid, getProcessPid, removeProcessPid } from '../../modules/config/process-pid.ts';
|
||||
|
||||
export const getAssistantCenterPath = () => {
|
||||
const resourcePath = getElectronResourcePath();
|
||||
if (isDev) {
|
||||
return path.join(resourcePath, '../dist');
|
||||
}
|
||||
if (isMac()) {
|
||||
return path.join(resourcePath, 'dist');
|
||||
}
|
||||
return path.join(resourcePath, 'dist');
|
||||
};
|
||||
// export const assistantCenterPath = path.join(__dirname, '../dist');
|
||||
export const assistantCenterPath = getAssistantCenterPath();
|
||||
export const assistantProcessPath = path.join(assistantCenterPath, 'dist/app.mjs');
|
||||
// export const assistantProcess = new AssistantProcess(assistantPath);
|
||||
export const processConfig = {
|
||||
assistantCenterPath,
|
||||
assistantProcessPath,
|
||||
port: 51015,
|
||||
process: null,
|
||||
};
|
||||
export const getOrigin = () => {
|
||||
return `https://localhost:${processConfig.port}`;
|
||||
};
|
||||
export const createProcess = async () => {
|
||||
log.info('createProcess', assistantProcessPath, 'cwd', assistantCenterPath);
|
||||
const pid = getProcessPid();
|
||||
if (pid) {
|
||||
removeProcessPid();
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
// const signal = new AbortSignal();
|
||||
try {
|
||||
const assistantProcess = fork(assistantProcessPath, {
|
||||
cwd: assistantCenterPath,
|
||||
// signal,
|
||||
stdio: 'inherit',
|
||||
env: {
|
||||
...process.env,
|
||||
// KEVISUAL_URL: 'https://kevisual.xiongxiao.me',
|
||||
KEVISUAL_URL: 'https://kevisual.silkyai.cn',
|
||||
NODE_ENV_PARENT: 'fork',
|
||||
},
|
||||
});
|
||||
assistantProcess.on('message', (message) => {
|
||||
log.log('assistantProcess message', typeof message, message);
|
||||
// if (message.toString().includes(checkString)) {
|
||||
// resolve(assistantProcess);
|
||||
// }
|
||||
if (typeof message === 'object') {
|
||||
const msg = message as { type: string; data?: { port?: number } };
|
||||
if (msg.type === 'fork') {
|
||||
resolve({ process: assistantProcess, port: msg.data?.port || processConfig.port });
|
||||
}
|
||||
}
|
||||
});
|
||||
assistantProcess.on('error', (error) => {
|
||||
log.error(error);
|
||||
});
|
||||
processConfig.process = assistantProcess;
|
||||
setProcessPid(assistantProcess.pid);
|
||||
return assistantProcess;
|
||||
} catch (error) {
|
||||
log.error(error);
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const closeProcess = () => {
|
||||
log.info('closeProcess');
|
||||
removeProcessPid();
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { appDir, kevisualUrl, addAppConfig, getAppConfig, setAppConfig, getCacheAssistantConfig, setConfig } from '../../modules/config';
|
||||
import { appDir, kevisualUrl, addAppConfig, getAppConfig, setAppConfig, getCacheAssistantConfig, setConfig } from '../../modules/config/index.ts';
|
||||
|
||||
export const demoData = {
|
||||
id: '471ee96f-d7d8-4da1-b84f-4a34f4732f16',
|
||||
|
||||
@@ -1,57 +1,19 @@
|
||||
import { app, BrowserWindow, ipcMain, session } from 'electron';
|
||||
import { getCacheAssistantConfig, appDir, LocalElectronAppUrl } from '../../modules/config';
|
||||
import { net } from 'electron';
|
||||
import path from 'path';
|
||||
import * as url from 'url';
|
||||
import { checkFileExists } from '../../modules/file';
|
||||
import { apiProxyList } from '../proxy/api-proxy';
|
||||
import { session } from 'electron';
|
||||
|
||||
let _session: Electron.Session;
|
||||
|
||||
export const createSession = () => {
|
||||
if (_session) {
|
||||
return _session;
|
||||
}
|
||||
// 创建一个持久化的会话
|
||||
_session = session.fromPartition('persist:app');
|
||||
|
||||
_session.protocol.handle('https', async (req) => {
|
||||
const requrl = req.url;
|
||||
const newReqUrl = new URL(requrl);
|
||||
const localOrigin = new URL(LocalElectronAppUrl).origin;
|
||||
if (newReqUrl.origin !== localOrigin) {
|
||||
// 不拦截
|
||||
return net.fetch(req.url, { bypassCustomProtocolHandlers: true });
|
||||
}
|
||||
const apiProxy = apiProxyList.find((_proxy: any) => newReqUrl.pathname.startsWith(_proxy.path));
|
||||
if (apiProxy) {
|
||||
const pageApi = getCacheAssistantConfig().pageApi || '';
|
||||
if (!pageApi) {
|
||||
return new Response(`App Page Api Not Set, please set it first`);
|
||||
}
|
||||
const newPageUrl = new URL(req.url, pageApi);
|
||||
return net.fetch(newPageUrl.toString(), { bypassCustomProtocolHandlers: true });
|
||||
}
|
||||
const [user, key] = newReqUrl.pathname.split('/').slice(1);
|
||||
const proxyList = getCacheAssistantConfig().proxy || [];
|
||||
const proxy = proxyList.find((_proxy: any) => newReqUrl.pathname.startsWith(_proxy.path));
|
||||
if (proxy) {
|
||||
try {
|
||||
const relativePath = path.join(appDir, newReqUrl.pathname);
|
||||
const indexHtml = path.join(appDir, user, key, 'index.html');
|
||||
console.log('relativePath', relativePath);
|
||||
if (checkFileExists(relativePath, true)) {
|
||||
const res = await net.fetch(url.pathToFileURL(relativePath).toString());
|
||||
return res;
|
||||
} else {
|
||||
const res = await net.fetch(url.pathToFileURL(indexHtml).toString());
|
||||
return res;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
return new Response('App is Running Error, please reinstall it or refresh the page');
|
||||
}
|
||||
return new Response(`App Not Install, please install it first,user/app: [${user}/${key}]`);
|
||||
// Ignore certificate errors (for development only)
|
||||
_session.webRequest.onBeforeSendHeaders((details, callback) => {
|
||||
details.requestHeaders['User-Agent'] = 'silky-assistant';
|
||||
callback({ cancel: false, requestHeaders: details.requestHeaders });
|
||||
});
|
||||
_session.setCertificateVerifyProc((request, callback) => {
|
||||
callback(0); // 0 means trust the certificate
|
||||
});
|
||||
return _session;
|
||||
};
|
||||
|
||||
21
src/main/system/env.ts
Normal file
21
src/main/system/env.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { app } from 'electron';
|
||||
|
||||
export const isDev = () => {
|
||||
return process.env.NODE_ENV === 'development';
|
||||
};
|
||||
|
||||
export const isMac = () => {
|
||||
return process.platform === 'darwin';
|
||||
};
|
||||
|
||||
export const isWin = () => {
|
||||
return process.platform === 'win32';
|
||||
};
|
||||
|
||||
export const isLinux = () => {
|
||||
return process.platform === 'linux';
|
||||
};
|
||||
|
||||
export const getElectronResourcePath = () => {
|
||||
return app.getAppPath();
|
||||
};
|
||||
@@ -1,19 +1,10 @@
|
||||
import { BrowserWindow } from 'electron';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
import { getOrigin } from '@/main/process/index.ts';
|
||||
import { createWinodw } from './create-window.ts';
|
||||
|
||||
export const createAppPackagesPage = (window?: BrowserWindow) => {
|
||||
const mainWindow =
|
||||
window ||
|
||||
new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, 'preload.js'), // 如果有 preload 脚本
|
||||
},
|
||||
});
|
||||
mainWindow.loadFile(path.join(__dirname, '../renderer/packages/index.html')); // Vite 构建后的文件
|
||||
const mainWindow = createWinodw(window);
|
||||
const url = new URL('/root/assistant-base-app/?link=packages', getOrigin());
|
||||
mainWindow.loadURL(url.toString());
|
||||
return mainWindow;
|
||||
};
|
||||
|
||||
22
src/main/window/page/create-window.ts
Normal file
22
src/main/window/page/create-window.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { BrowserWindow } from 'electron';
|
||||
import { fileURLToPath } from 'url';
|
||||
import path from 'path';
|
||||
import { createSession } from '../../session/index.ts';
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
export const createWinodw = (window: BrowserWindow, opts?: any) => {
|
||||
if (window) return window;
|
||||
const _session = createSession();
|
||||
return new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
...opts,
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, 'preload.js'), // 如果有 preload 脚本
|
||||
session: _session,
|
||||
webSecurity: false,
|
||||
...opts?.webPreferences,
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -1,19 +1,10 @@
|
||||
import { BrowserWindow } from 'electron';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
import { getOrigin } from '@/main/process/index.ts';
|
||||
import { createWinodw } from './create-window.ts';
|
||||
|
||||
export const createEnterPage = (window?: BrowserWindow) => {
|
||||
const mainWindow =
|
||||
window ||
|
||||
new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, 'preload.js'), // 如果有 preload 脚本
|
||||
},
|
||||
});
|
||||
mainWindow.loadFile(path.join(__dirname, '../renderer/enter/index.html')); // Vite 构建后的文件
|
||||
const mainWindow = createWinodw(window);
|
||||
const url = new URL('/root/assistant-base-app/?link=enter', getOrigin());
|
||||
mainWindow.loadURL(url.toString());
|
||||
return mainWindow;
|
||||
};
|
||||
|
||||
@@ -1,18 +1,36 @@
|
||||
import { getCacheAssistantConfig, LocalElectronAppUrl } from '@/modules/config';
|
||||
import { createEnterPage } from './enter';
|
||||
import { createAppPackagesPage } from './app-packages';
|
||||
import { getCacheAssistantConfig } from '@/modules/config/index.ts';
|
||||
import { createEnterPage } from './enter.ts';
|
||||
import { createAppPackagesPage } from './app-packages.ts';
|
||||
import { BrowserWindow } from 'electron';
|
||||
import { getOrigin } from '@/main/process/index.ts';
|
||||
import { createWinodw } from './create-window.ts';
|
||||
|
||||
export const checkShowPage = async (window?: BrowserWindow) => {
|
||||
const assistantConfig = getCacheAssistantConfig();
|
||||
const { pageApi, proxy } = assistantConfig;
|
||||
const { pageApi, proxy, loadURL } = assistantConfig;
|
||||
if (!pageApi) {
|
||||
createEnterPage(window);
|
||||
return;
|
||||
return createEnterPage(window);
|
||||
}
|
||||
if (!proxy || proxy.length === 0) {
|
||||
createAppPackagesPage(window);
|
||||
return;
|
||||
return createAppPackagesPage(window);
|
||||
}
|
||||
return window?.loadURL(LocalElectronAppUrl);
|
||||
window = createWinodw(window);
|
||||
let defaultURL = getOrigin() + '/web/note/';
|
||||
if (loadURL) {
|
||||
const url = new URL(loadURL, getOrigin());
|
||||
const urls = url.pathname.split('/');
|
||||
const [_, user, app] = urls;
|
||||
let _loadURL = url.toString();
|
||||
if (!user && !app) {
|
||||
_loadURL = defaultURL;
|
||||
}
|
||||
if (app && urls.length === 3) {
|
||||
_loadURL = url.toString() + '/';
|
||||
}
|
||||
console.log('url loadURL', _loadURL);
|
||||
window?.loadURL(_loadURL);
|
||||
return window;
|
||||
}
|
||||
window?.loadURL(defaultURL);
|
||||
return window;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user