🏗️ refactor data access layer and enhance service architecture
This commit is contained in:
parent
ff8b01c360
commit
9946b50d5d
@ -1,337 +1,337 @@
|
|||||||
import { app, dialog, ipcMain, shell } from "electron";
|
// import { app, dialog, ipcMain, shell } from "electron";
|
||||||
import { clearConfig, getConfig, saveConfig } from "../storage/config";
|
// import { clearConfig, getConfig, saveConfig } from "../storage/config";
|
||||||
import { clearVersion, listVersion } from "../storage/version";
|
// import { clearVersion, listVersion } from "../storage/version";
|
||||||
import { genIniConfig, genTomlConfig, stopFrpcProcess } from "./frpc";
|
// import { genIniConfig, genTomlConfig, stopFrpcProcess } from "./frpc";
|
||||||
import { clearProxy, insertProxy, listProxy } from "../storage/proxy";
|
// import { clearProxy, insertProxy, listProxy } from "../storage/proxy";
|
||||||
import path from "path";
|
// import path from "path";
|
||||||
import fs from "fs";
|
// import fs from "fs";
|
||||||
import { logDebug, logError, logInfo, LogModule, logWarn } from "../utils/log";
|
// import { logDebug, logError, logInfo, LogModule, logWarn } from "../utils/log";
|
||||||
|
//
|
||||||
const toml = require("@iarna/toml");
|
// const toml = require("@iarna/toml");
|
||||||
const { v4: uuidv4 } = require("uuid");
|
// const { v4: uuidv4 } = require("uuid");
|
||||||
|
//
|
||||||
export const initConfigApi = win => {
|
// export const initConfigApi = win => {
|
||||||
ipcMain.on("config.saveConfig", async (event, args) => {
|
// ipcMain.on("config.saveConfig", async (event, args) => {
|
||||||
logInfo(LogModule.APP, "Attempting to save configuration.");
|
// logInfo(LogModule.APP, "Attempting to save configuration.");
|
||||||
saveConfig(args, (err, numberOfUpdated, upsert) => {
|
// saveConfig(args, (err, numberOfUpdated, upsert) => {
|
||||||
if (!err) {
|
// if (!err) {
|
||||||
const start = args.systemSelfStart || false;
|
// const start = args.systemSelfStart || false;
|
||||||
logDebug(LogModule.APP, "Startup status set to: " + start);
|
// logDebug(LogModule.APP, "Startup status set to: " + start);
|
||||||
app.setLoginItemSettings({
|
// app.setLoginItemSettings({
|
||||||
openAtLogin: start, //win
|
// openAtLogin: start, //win
|
||||||
openAsHidden: start //macOs
|
// openAsHidden: start //macOs
|
||||||
});
|
// });
|
||||||
logInfo(LogModule.APP, "Configuration saved successfully.");
|
// logInfo(LogModule.APP, "Configuration saved successfully.");
|
||||||
} else {
|
// } else {
|
||||||
logError(LogModule.APP, `Error saving configuration: ${err}`);
|
// logError(LogModule.APP, `Error saving configuration: ${err}`);
|
||||||
}
|
// }
|
||||||
event.reply("Config.saveConfig.hook", {
|
// event.reply("Config.saveConfig.hook", {
|
||||||
err: err,
|
// err: err,
|
||||||
numberOfUpdated: numberOfUpdated,
|
// numberOfUpdated: numberOfUpdated,
|
||||||
upsert: upsert
|
// upsert: upsert
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
|
//
|
||||||
ipcMain.on("config.getConfig", async (event, args) => {
|
// ipcMain.on("config.getConfig", async (event, args) => {
|
||||||
logInfo(LogModule.APP, "Requesting configuration.");
|
// logInfo(LogModule.APP, "Requesting configuration.");
|
||||||
getConfig((err, doc) => {
|
// getConfig((err, doc) => {
|
||||||
if (err) {
|
// if (err) {
|
||||||
logError(LogModule.APP, `Error retrieving configuration: ${err}`);
|
// logError(LogModule.APP, `Error retrieving configuration: ${err}`);
|
||||||
}
|
// }
|
||||||
event.reply("Config.getConfig.hook", {
|
// event.reply("Config.getConfig.hook", {
|
||||||
err: err,
|
// err: err,
|
||||||
data: doc
|
// data: doc
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
|
//
|
||||||
ipcMain.on("config.versions", event => {
|
// ipcMain.on("config.versions", event => {
|
||||||
logInfo(LogModule.APP, "Requesting version information.");
|
// logInfo(LogModule.APP, "Requesting version information.");
|
||||||
listVersion((err, doc) => {
|
// listVersion((err, doc) => {
|
||||||
if (err) {
|
// if (err) {
|
||||||
logError(LogModule.APP, `Error retrieving version information: ${err}`);
|
// logError(LogModule.APP, `Error retrieving version information: ${err}`);
|
||||||
}
|
// }
|
||||||
event.reply("Config.versions.hook", {
|
// event.reply("Config.versions.hook", {
|
||||||
err: err,
|
// err: err,
|
||||||
data: doc
|
// data: doc
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
|
//
|
||||||
ipcMain.on("config.hasConfig", event => {
|
// ipcMain.on("config.hasConfig", event => {
|
||||||
logInfo(LogModule.APP, "Checking if configuration exists.");
|
// logInfo(LogModule.APP, "Checking if configuration exists.");
|
||||||
getConfig((err, doc) => {
|
// getConfig((err, doc) => {
|
||||||
if (err) {
|
// if (err) {
|
||||||
logError(LogModule.APP, `Error checking configuration: ${err}`);
|
// logError(LogModule.APP, `Error checking configuration: ${err}`);
|
||||||
}
|
// }
|
||||||
event.reply("Config.getConfig.hook", {
|
// event.reply("Config.getConfig.hook", {
|
||||||
err: err,
|
// err: err,
|
||||||
data: doc
|
// data: doc
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
|
//
|
||||||
ipcMain.on("config.exportConfig", async (event, args) => {
|
// ipcMain.on("config.exportConfig", async (event, args) => {
|
||||||
logInfo(LogModule.APP, "Attempting to export configuration.");
|
// logInfo(LogModule.APP, "Attempting to export configuration.");
|
||||||
const result = await dialog.showOpenDialog({
|
// const result = await dialog.showOpenDialog({
|
||||||
properties: ["openDirectory"]
|
// properties: ["openDirectory"]
|
||||||
});
|
// });
|
||||||
const outputDirectory = result.filePaths[0];
|
// const outputDirectory = result.filePaths[0];
|
||||||
if (!outputDirectory) {
|
// if (!outputDirectory) {
|
||||||
logWarn(LogModule.APP, "Export canceled by user.");
|
// logWarn(LogModule.APP, "Export canceled by user.");
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
logInfo(
|
// logInfo(
|
||||||
LogModule.APP,
|
// LogModule.APP,
|
||||||
`Exporting configuration to directory ${outputDirectory} with type: ${args}`
|
// `Exporting configuration to directory ${outputDirectory} with type: ${args}`
|
||||||
);
|
// );
|
||||||
getConfig((err1, config) => {
|
// getConfig((err1, config) => {
|
||||||
if (!err1 && config) {
|
// if (!err1 && config) {
|
||||||
listProxy((err2, proxys) => {
|
// listProxy((err2, proxys) => {
|
||||||
if (!err2) {
|
// if (!err2) {
|
||||||
let configContent = "";
|
// let configContent = "";
|
||||||
if (args === "ini") {
|
// if (args === "ini") {
|
||||||
configContent = genIniConfig(config, proxys);
|
// configContent = genIniConfig(config, proxys);
|
||||||
} else if (args === "toml") {
|
// } else if (args === "toml") {
|
||||||
configContent = genTomlConfig(config, proxys);
|
// configContent = genTomlConfig(config, proxys);
|
||||||
}
|
// }
|
||||||
const configPath = path.join(
|
// const configPath = path.join(
|
||||||
outputDirectory,
|
// outputDirectory,
|
||||||
`frpc-desktop.${args}`
|
// `frpc-desktop.${args}`
|
||||||
);
|
// );
|
||||||
fs.writeFile(
|
// fs.writeFile(
|
||||||
configPath, // 配置文件目录
|
// configPath, // 配置文件目录
|
||||||
configContent, // 配置文件内容
|
// configContent, // 配置文件内容
|
||||||
{ flag: "w" },
|
// { flag: "w" },
|
||||||
err => {
|
// err => {
|
||||||
if (err) {
|
// if (err) {
|
||||||
logError(
|
// logError(
|
||||||
LogModule.APP,
|
// LogModule.APP,
|
||||||
`Error writing configuration file: ${err}`
|
// `Error writing configuration file: ${err}`
|
||||||
);
|
// );
|
||||||
event.reply("config.exportConfig.hook", {
|
// event.reply("config.exportConfig.hook", {
|
||||||
data: "导出错误",
|
// data: "导出错误",
|
||||||
err: err
|
// err: err
|
||||||
});
|
// });
|
||||||
} else {
|
// } else {
|
||||||
logInfo(
|
// logInfo(
|
||||||
LogModule.APP,
|
// LogModule.APP,
|
||||||
"Configuration exported successfully."
|
// "Configuration exported successfully."
|
||||||
);
|
// );
|
||||||
event.reply("Config.exportConfig.hook", {
|
// event.reply("Config.exportConfig.hook", {
|
||||||
data: {
|
// data: {
|
||||||
configPath: configPath
|
// configPath: configPath
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
);
|
// );
|
||||||
} else {
|
// } else {
|
||||||
logError(LogModule.APP, `Error listing proxies: ${err2}`);
|
// logError(LogModule.APP, `Error listing proxies: ${err2}`);
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
} else {
|
// } else {
|
||||||
logError(LogModule.APP, `Error retrieving configuration: ${err1}`);
|
// logError(LogModule.APP, `Error retrieving configuration: ${err1}`);
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
|
//
|
||||||
const parseTomlConfig = (tomlPath: string) => {
|
// const parseTomlConfig = (tomlPath: string) => {
|
||||||
logInfo(LogModule.APP, `Parsing TOML configuration from ${tomlPath}`);
|
// logInfo(LogModule.APP, `Parsing TOML configuration from ${tomlPath}`);
|
||||||
const importConfigPath = tomlPath;
|
// const importConfigPath = tomlPath;
|
||||||
const tomlData = fs.readFileSync(importConfigPath, "utf-8");
|
// const tomlData = fs.readFileSync(importConfigPath, "utf-8");
|
||||||
logInfo(LogModule.APP, "Configuration content read successfully.");
|
// logInfo(LogModule.APP, "Configuration content read successfully.");
|
||||||
const sourceConfig = toml.parse(tomlData);
|
// const sourceConfig = toml.parse(tomlData);
|
||||||
// 解析config
|
// // 解析config
|
||||||
const targetConfig: FrpConfig = {
|
// const targetConfig: FrpConfig = {
|
||||||
currentVersion: null,
|
// currentVersion: null,
|
||||||
serverAddr: sourceConfig.serverAddr || "",
|
// serverAddr: sourceConfig.serverAddr || "",
|
||||||
serverPort: sourceConfig.serverPort || "",
|
// serverPort: sourceConfig.serverPort || "",
|
||||||
authMethod: sourceConfig?.user
|
// authMethod: sourceConfig?.user
|
||||||
? "multiuser"
|
// ? "multiuser"
|
||||||
: sourceConfig?.auth?.method || "",
|
// : sourceConfig?.auth?.method || "",
|
||||||
authToken: sourceConfig?.auth?.token || "",
|
// authToken: sourceConfig?.auth?.token || "",
|
||||||
transportHeartbeatInterval:
|
// transportHeartbeatInterval:
|
||||||
sourceConfig?.transport?.heartbeatInterval || 30,
|
// sourceConfig?.transport?.heartbeatInterval || 30,
|
||||||
transportHeartbeatTimeout:
|
// transportHeartbeatTimeout:
|
||||||
sourceConfig?.transport?.heartbeatTimeout || 90,
|
// sourceConfig?.transport?.heartbeatTimeout || 90,
|
||||||
tlsConfigEnable: sourceConfig?.transport?.tls?.enable || false,
|
// tlsConfigEnable: sourceConfig?.transport?.tls?.enable || false,
|
||||||
tlsConfigCertFile: sourceConfig?.transport?.tls?.certFile || "",
|
// tlsConfigCertFile: sourceConfig?.transport?.tls?.certFile || "",
|
||||||
tlsConfigKeyFile: sourceConfig?.transport?.tls?.keyFile || "",
|
// tlsConfigKeyFile: sourceConfig?.transport?.tls?.keyFile || "",
|
||||||
tlsConfigServerName: sourceConfig?.transport?.tls?.serverName || "",
|
// tlsConfigServerName: sourceConfig?.transport?.tls?.serverName || "",
|
||||||
tlsConfigTrustedCaFile: sourceConfig?.transport?.tls?.trustedCaFile || "",
|
// tlsConfigTrustedCaFile: sourceConfig?.transport?.tls?.trustedCaFile || "",
|
||||||
logLevel: sourceConfig?.log?.level || "info",
|
// logLevel: sourceConfig?.log?.level || "info",
|
||||||
logMaxDays: sourceConfig?.log?.maxDays || 3,
|
// logMaxDays: sourceConfig?.log?.maxDays || 3,
|
||||||
proxyConfigProxyUrl: sourceConfig?.transport?.proxyURL || "",
|
// proxyConfigProxyUrl: sourceConfig?.transport?.proxyURL || "",
|
||||||
proxyConfigEnable: Boolean(sourceConfig?.transport?.proxyURL) || false,
|
// proxyConfigEnable: Boolean(sourceConfig?.transport?.proxyURL) || false,
|
||||||
user: sourceConfig?.user || "",
|
// user: sourceConfig?.user || "",
|
||||||
metaToken: sourceConfig?.metadatas?.token || "",
|
// metaToken: sourceConfig?.metadatas?.token || "",
|
||||||
systemSelfStart: false,
|
// systemSelfStart: false,
|
||||||
systemStartupConnect: false,
|
// systemStartupConnect: false,
|
||||||
systemSilentStartup: false,
|
// systemSilentStartup: false,
|
||||||
webEnable: true,
|
// webEnable: true,
|
||||||
webPort: sourceConfig?.webServer?.port || 57400,
|
// webPort: sourceConfig?.webServer?.port || 57400,
|
||||||
transportProtocol: sourceConfig?.transport?.protocol || "tcp",
|
// transportProtocol: sourceConfig?.transport?.protocol || "tcp",
|
||||||
transportDialServerTimeout:
|
// transportDialServerTimeout:
|
||||||
sourceConfig?.transport?.dialServerTimeout || 10,
|
// sourceConfig?.transport?.dialServerTimeout || 10,
|
||||||
transportDialServerKeepalive:
|
// transportDialServerKeepalive:
|
||||||
sourceConfig?.transport?.dialServerKeepalive || 70,
|
// sourceConfig?.transport?.dialServerKeepalive || 70,
|
||||||
transportPoolCount: sourceConfig?.transport?.poolCount || 0,
|
// transportPoolCount: sourceConfig?.transport?.poolCount || 0,
|
||||||
transportTcpMux: sourceConfig?.transport?.tcpMux || true,
|
// transportTcpMux: sourceConfig?.transport?.tcpMux || true,
|
||||||
transportTcpMuxKeepaliveInterval:
|
// transportTcpMuxKeepaliveInterval:
|
||||||
sourceConfig?.transport?.tcpMuxKeepaliveInterval || 7200
|
// sourceConfig?.transport?.tcpMuxKeepaliveInterval || 7200
|
||||||
};
|
// };
|
||||||
let frpcProxys = [];
|
// let frpcProxys = [];
|
||||||
// 解析proxy
|
// // 解析proxy
|
||||||
if (sourceConfig?.proxies && sourceConfig.proxies.length > 0) {
|
// if (sourceConfig?.proxies && sourceConfig.proxies.length > 0) {
|
||||||
const frpcProxys1 = sourceConfig.proxies.map(m => {
|
// const frpcProxys1 = sourceConfig.proxies.map(m => {
|
||||||
const rm: Proxy = {
|
// const rm: Proxy = {
|
||||||
_id: uuidv4(),
|
// _id: uuidv4(),
|
||||||
name: m?.name,
|
// name: m?.name,
|
||||||
type: m?.type,
|
// type: m?.type,
|
||||||
localIp: m?.localIP || "",
|
// localIp: m?.localIP || "",
|
||||||
localPort: m?.localPort || null,
|
// localPort: m?.localPort || null,
|
||||||
remotePort: m?.remotePort || null,
|
// remotePort: m?.remotePort || null,
|
||||||
customDomains: m?.customDomains || [],
|
// customDomains: m?.customDomains || [],
|
||||||
subdomain: m.subdomain || "",
|
// subdomain: m.subdomain || "",
|
||||||
basicAuth: m.basicAuth || false,
|
// basicAuth: m.basicAuth || false,
|
||||||
httpUser: m.httpUser || "",
|
// httpUser: m.httpUser || "",
|
||||||
httpPassword: m.httpPassword || "",
|
// httpPassword: m.httpPassword || "",
|
||||||
// 以下为stcp参数
|
// // 以下为stcp参数
|
||||||
stcpModel: "visited",
|
// stcpModel: "visited",
|
||||||
serverName: "",
|
// serverName: "",
|
||||||
secretKey: m?.secretKey || "",
|
// secretKey: m?.secretKey || "",
|
||||||
bindAddr: "",
|
// bindAddr: "",
|
||||||
bindPort: null,
|
// bindPort: null,
|
||||||
status: m?.status || true,
|
// status: m?.status || true,
|
||||||
fallbackTo: m?.fallbackTo,
|
// fallbackTo: m?.fallbackTo,
|
||||||
fallbackTimeoutMs: m?.fallbackTimeoutMs || 500,
|
// fallbackTimeoutMs: m?.fallbackTimeoutMs || 500,
|
||||||
keepTunnelOpen: m?.keepTunnelOpen || false,
|
// keepTunnelOpen: m?.keepTunnelOpen || false,
|
||||||
https2http: m?.https2http || false,
|
// https2http: m?.https2http || false,
|
||||||
https2httpCaFile: m?.https2httpCaFile || "",
|
// https2httpCaFile: m?.https2httpCaFile || "",
|
||||||
https2httpKeyFile: m?.https2httpKeyFile || ""
|
// https2httpKeyFile: m?.https2httpKeyFile || ""
|
||||||
};
|
// };
|
||||||
return rm;
|
// return rm;
|
||||||
});
|
// });
|
||||||
frpcProxys = [...frpcProxys, ...frpcProxys1];
|
// frpcProxys = [...frpcProxys, ...frpcProxys1];
|
||||||
logInfo(LogModule.APP, "Parsed proxies from configuration.");
|
// logInfo(LogModule.APP, "Parsed proxies from configuration.");
|
||||||
}
|
// }
|
||||||
// 解析stcp的访问者
|
// // 解析stcp的访问者
|
||||||
if (sourceConfig?.visitors && sourceConfig.visitors.length > 0) {
|
// if (sourceConfig?.visitors && sourceConfig.visitors.length > 0) {
|
||||||
const frpcProxys2 = sourceConfig.visitors.map(m => {
|
// const frpcProxys2 = sourceConfig.visitors.map(m => {
|
||||||
const rm: Proxy = {
|
// const rm: Proxy = {
|
||||||
_id: uuidv4(),
|
// _id: uuidv4(),
|
||||||
name: m?.name,
|
// name: m?.name,
|
||||||
type: m?.type,
|
// type: m?.type,
|
||||||
localIp: "",
|
// localIp: "",
|
||||||
localPort: null,
|
// localPort: null,
|
||||||
remotePort: null,
|
// remotePort: null,
|
||||||
customDomains: [],
|
// customDomains: [],
|
||||||
subdomain: m.subdomain || "",
|
// subdomain: m.subdomain || "",
|
||||||
basicAuth: m.basicAuth || false,
|
// basicAuth: m.basicAuth || false,
|
||||||
httpUser: m.httpUser || "",
|
// httpUser: m.httpUser || "",
|
||||||
httpPassword: m.httpPassword || "",
|
// httpPassword: m.httpPassword || "",
|
||||||
// 以下为stcp参数
|
// // 以下为stcp参数
|
||||||
stcpModel: "visitors",
|
// stcpModel: "visitors",
|
||||||
serverName: m?.serverName,
|
// serverName: m?.serverName,
|
||||||
secretKey: m?.secretKey || "",
|
// secretKey: m?.secretKey || "",
|
||||||
bindAddr: m?.bindAddr,
|
// bindAddr: m?.bindAddr,
|
||||||
bindPort: m?.bindPort,
|
// bindPort: m?.bindPort,
|
||||||
status: m?.status || true,
|
// status: m?.status || true,
|
||||||
fallbackTo: m?.fallbackTo,
|
// fallbackTo: m?.fallbackTo,
|
||||||
fallbackTimeoutMs: m?.fallbackTimeoutMs || 500,
|
// fallbackTimeoutMs: m?.fallbackTimeoutMs || 500,
|
||||||
keepTunnelOpen: m?.keepTunnelOpen || false,
|
// keepTunnelOpen: m?.keepTunnelOpen || false,
|
||||||
https2http: m?.https2http || false,
|
// https2http: m?.https2http || false,
|
||||||
https2httpCaFile: m?.https2httpCaFile || "",
|
// https2httpCaFile: m?.https2httpCaFile || "",
|
||||||
https2httpKeyFile: m?.https2httpKeyFile || ""
|
// https2httpKeyFile: m?.https2httpKeyFile || ""
|
||||||
};
|
// };
|
||||||
return rm;
|
// return rm;
|
||||||
});
|
// });
|
||||||
frpcProxys = [...frpcProxys, ...frpcProxys2];
|
// frpcProxys = [...frpcProxys, ...frpcProxys2];
|
||||||
logInfo(LogModule.APP, "Parsed visitors from configuration.");
|
// logInfo(LogModule.APP, "Parsed visitors from configuration.");
|
||||||
}
|
// }
|
||||||
if (targetConfig) {
|
// if (targetConfig) {
|
||||||
clearConfig(() => {
|
// clearConfig(() => {
|
||||||
logInfo(LogModule.APP, "Clearing existing configuration.");
|
// logInfo(LogModule.APP, "Clearing existing configuration.");
|
||||||
saveConfig(targetConfig);
|
// saveConfig(targetConfig);
|
||||||
logInfo(LogModule.APP, "New configuration saved.");
|
// logInfo(LogModule.APP, "New configuration saved.");
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
if (frpcProxys && frpcProxys.length > 0) {
|
// if (frpcProxys && frpcProxys.length > 0) {
|
||||||
clearProxy(() => {
|
// clearProxy(() => {
|
||||||
frpcProxys.forEach(f => {
|
// frpcProxys.forEach(f => {
|
||||||
insertProxy(f, err => {
|
// insertProxy(f, err => {
|
||||||
if (err) {
|
// if (err) {
|
||||||
logError(LogModule.APP, `Error inserting proxy: ${err}`);
|
// logError(LogModule.APP, `Error inserting proxy: ${err}`);
|
||||||
} else {
|
// } else {
|
||||||
logInfo(LogModule.APP, `Inserted proxy: ${JSON.stringify(f)}`);
|
// logInfo(LogModule.APP, `Inserted proxy: ${JSON.stringify(f)}`);
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
|
//
|
||||||
ipcMain.on("config.importConfig", async (event, args) => {
|
// ipcMain.on("config.importConfig", async (event, args) => {
|
||||||
logInfo(LogModule.APP, "Attempting to import configuration.");
|
// logInfo(LogModule.APP, "Attempting to import configuration.");
|
||||||
const result = await dialog.showOpenDialog(win, {
|
// const result = await dialog.showOpenDialog(win, {
|
||||||
properties: ["openFile"],
|
// properties: ["openFile"],
|
||||||
filters: [
|
// filters: [
|
||||||
{ name: "FrpcConfig Files", extensions: ["toml", "ini"] } // 允许选择的文件类型
|
// { name: "FrpcConfig Files", extensions: ["toml", "ini"] } // 允许选择的文件类型
|
||||||
]
|
// ]
|
||||||
});
|
// });
|
||||||
if (result.canceled) {
|
// if (result.canceled) {
|
||||||
logWarn(LogModule.APP, "Import canceled by user.");
|
// logWarn(LogModule.APP, "Import canceled by user.");
|
||||||
return;
|
// return;
|
||||||
} else {
|
// } else {
|
||||||
const filePath = result.filePaths[0];
|
// const filePath = result.filePaths[0];
|
||||||
const fileExtension = path.extname(filePath); // 获取文件后缀名
|
// const fileExtension = path.extname(filePath); // 获取文件后缀名
|
||||||
logWarn(
|
// logWarn(
|
||||||
LogModule.APP,
|
// LogModule.APP,
|
||||||
`Importing file ${filePath} with extension ${fileExtension}`
|
// `Importing file ${filePath} with extension ${fileExtension}`
|
||||||
);
|
// );
|
||||||
if (fileExtension === ".toml") {
|
// if (fileExtension === ".toml") {
|
||||||
parseTomlConfig(filePath);
|
// parseTomlConfig(filePath);
|
||||||
event.reply("Config.importConfig.hook", {
|
// event.reply("Config.importConfig.hook", {
|
||||||
success: true
|
// success: true
|
||||||
});
|
// });
|
||||||
} else {
|
// } else {
|
||||||
logError(
|
// logError(
|
||||||
LogModule.APP,
|
// LogModule.APP,
|
||||||
`Import failed, unsupported file format: ${fileExtension}`
|
// `Import failed, unsupported file format: ${fileExtension}`
|
||||||
);
|
// );
|
||||||
event.reply("Config.importConfig.hook", {
|
// event.reply("Config.importConfig.hook", {
|
||||||
success: false,
|
// success: false,
|
||||||
data: `导入失败,暂不支持 ${fileExtension} 格式文件`
|
// data: `导入失败,暂不支持 ${fileExtension} 格式文件`
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
|
//
|
||||||
ipcMain.on("config.clearAll", async (event, args) => {
|
// ipcMain.on("config.clearAll", async (event, args) => {
|
||||||
logInfo(LogModule.APP, "Clearing all configurations.");
|
// logInfo(LogModule.APP, "Clearing all configurations.");
|
||||||
stopFrpcProcess(() => {
|
// stopFrpcProcess(() => {
|
||||||
clearConfig();
|
// clearConfig();
|
||||||
clearProxy();
|
// clearProxy();
|
||||||
clearVersion();
|
// clearVersion();
|
||||||
event.reply("Config.clearAll.hook", {});
|
// event.reply("Config.clearAll.hook", {});
|
||||||
logInfo(LogModule.APP, "All configurations cleared.");
|
// logInfo(LogModule.APP, "All configurations cleared.");
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
|
//
|
||||||
ipcMain.on("config.openDataFolder", async (event, args) => {
|
// ipcMain.on("config.openDataFolder", async (event, args) => {
|
||||||
const userDataPath = app.getPath("userData");
|
// const userDataPath = app.getPath("userData");
|
||||||
logInfo(LogModule.APP, "Attempting to open data folder.");
|
// logInfo(LogModule.APP, "Attempting to open data folder.");
|
||||||
shell.openPath(userDataPath).then(errorMessage => {
|
// shell.openPath(userDataPath).then(errorMessage => {
|
||||||
if (errorMessage) {
|
// if (errorMessage) {
|
||||||
logError(LogModule.APP, `Failed to open data folder: ${errorMessage}`);
|
// logError(LogModule.APP, `Failed to open data folder: ${errorMessage}`);
|
||||||
event.reply("Config.openDataFolder.hook", false);
|
// event.reply("Config.openDataFolder.hook", false);
|
||||||
} else {
|
// } else {
|
||||||
logInfo(LogModule.APP, "Data folder opened successfully.");
|
// logInfo(LogModule.APP, "Data folder opened successfully.");
|
||||||
event.reply("Config.openDataFolder.hook", true);
|
// event.reply("Config.openDataFolder.hook", true);
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
};
|
// };
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
import {dialog, ipcMain} from "electron";
|
// import {dialog, ipcMain} from "electron";
|
||||||
import { logInfo, logError, LogModule } from "../utils/log";
|
// import { logInfo, logError, LogModule } from "../utils/log";
|
||||||
|
//
|
||||||
export const initFileApi = () => {
|
// export const initFileApi = () => {
|
||||||
ipcMain.handle("file.selectFile", async (event, args) => {
|
// ipcMain.handle("file.selectFile", async (event, args) => {
|
||||||
logInfo(LogModule.APP, `Attempting to open file dialog with filters: ${JSON.stringify(args)}`);
|
// logInfo(LogModule.APP, `Attempting to open file dialog with filters: ${JSON.stringify(args)}`);
|
||||||
try {
|
// try {
|
||||||
const result = dialog.showOpenDialogSync({
|
// const result = dialog.showOpenDialogSync({
|
||||||
properties: ['openFile'],
|
// properties: ['openFile'],
|
||||||
filters: [
|
// filters: [
|
||||||
{ name: 'Text Files', extensions: args },
|
// { name: 'Text Files', extensions: args },
|
||||||
]
|
// ]
|
||||||
});
|
// });
|
||||||
logInfo(LogModule.APP, `File dialog result: ${JSON.stringify(result)}`);
|
// logInfo(LogModule.APP, `File dialog result: ${JSON.stringify(result)}`);
|
||||||
return result;
|
// return result;
|
||||||
} catch (error) {
|
// } catch (error) {
|
||||||
logError(LogModule.APP, `Error opening file dialog: ${error.message}`);
|
// logError(LogModule.APP, `Error opening file dialog: ${error.message}`);
|
||||||
return null;
|
// return null;
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
1444
electron/api/frpc.ts
1444
electron/api/frpc.ts
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,81 +1,81 @@
|
|||||||
import {app, dialog, autoUpdater, BrowserWindow} from "electron";
|
// import {app, dialog, autoUpdater, BrowserWindow} from "electron";
|
||||||
|
//
|
||||||
const log = require('electron-log');
|
// const log = require('electron-log');
|
||||||
|
//
|
||||||
|
//
|
||||||
export const initUpdaterApi = (win: BrowserWindow) => {
|
// export const initUpdaterApi = (win: BrowserWindow) => {
|
||||||
//更新测试打开
|
// //更新测试打开
|
||||||
Object.defineProperty(app, 'isPackaged', {
|
// Object.defineProperty(app, 'isPackaged', {
|
||||||
get() {
|
// get() {
|
||||||
return true;
|
// return true;
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
const server = 'https://hazel-git-master-uiluck.vercel.app'
|
// const server = 'https://hazel-git-master-uiluck.vercel.app'
|
||||||
let packageName = null
|
// let packageName = null
|
||||||
const platform = process.platform;
|
// const platform = process.platform;
|
||||||
const arch = process.arch;
|
// const arch = process.arch;
|
||||||
switch (platform) {
|
// switch (platform) {
|
||||||
case "darwin":
|
// case "darwin":
|
||||||
if (arch == "arm64") {
|
// if (arch == "arm64") {
|
||||||
packageName = "darwin_arm64";
|
// packageName = "darwin_arm64";
|
||||||
} else {
|
// } else {
|
||||||
packageName = "darwin";
|
// packageName = "darwin";
|
||||||
}
|
// }
|
||||||
break;
|
// break;
|
||||||
case "win32":
|
// case "win32":
|
||||||
packageName = "exe";
|
// packageName = "exe";
|
||||||
break;
|
// break;
|
||||||
case "linux":
|
// case "linux":
|
||||||
packageName = "AppImage";
|
// packageName = "AppImage";
|
||||||
if (arch == "arm64") {
|
// if (arch == "arm64") {
|
||||||
packageName = "AppImage_arm64";
|
// packageName = "AppImage_arm64";
|
||||||
} else {
|
// } else {
|
||||||
packageName = "AppImage";
|
// packageName = "AppImage";
|
||||||
}
|
// }
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
const url = `${server}/update/${packageName}/${app.getVersion()}`
|
// const url = `${server}/update/${packageName}/${app.getVersion()}`
|
||||||
log.info(`开启自动更新 ${url}`);
|
// log.info(`开启自动更新 ${url}`);
|
||||||
autoUpdater.setFeedURL({url: url})
|
// autoUpdater.setFeedURL({url: url})
|
||||||
|
//
|
||||||
autoUpdater.on('checking-for-update', () => {
|
// autoUpdater.on('checking-for-update', () => {
|
||||||
log.info("正在检查更新")
|
// log.info("正在检查更新")
|
||||||
})
|
// })
|
||||||
|
//
|
||||||
autoUpdater.on('update-available', (event, info) => {
|
// autoUpdater.on('update-available', (event, info) => {
|
||||||
log.info(`发现新版本`)
|
// log.info(`发现新版本`)
|
||||||
})
|
// })
|
||||||
|
//
|
||||||
autoUpdater.on('update-not-available', () => {
|
// autoUpdater.on('update-not-available', () => {
|
||||||
log.info('没有可用的更新')
|
// log.info('没有可用的更新')
|
||||||
|
//
|
||||||
})
|
// })
|
||||||
|
//
|
||||||
autoUpdater.on('error', (err) => {
|
// autoUpdater.on('error', (err) => {
|
||||||
log.error(`更新错误:${err.message}`)
|
// log.error(`更新错误:${err.message}`)
|
||||||
|
//
|
||||||
})
|
// })
|
||||||
|
//
|
||||||
autoUpdater.on('update-downloaded', () => {
|
// autoUpdater.on('update-downloaded', () => {
|
||||||
dialog.showMessageBox({
|
// dialog.showMessageBox({
|
||||||
type: 'info',
|
// type: 'info',
|
||||||
title: '应用更新',
|
// title: '应用更新',
|
||||||
message: '发现新版本,是否更新?',
|
// message: '发现新版本,是否更新?',
|
||||||
buttons: ['是', '否']
|
// buttons: ['是', '否']
|
||||||
}).then((buttonIndex) => {
|
// }).then((buttonIndex) => {
|
||||||
if (buttonIndex.response == 0) { //选择是,则退出程序,安装新版本
|
// if (buttonIndex.response == 0) { //选择是,则退出程序,安装新版本
|
||||||
autoUpdater.quitAndInstall()
|
// autoUpdater.quitAndInstall()
|
||||||
app.quit()
|
// app.quit()
|
||||||
}
|
// }
|
||||||
})
|
// })
|
||||||
})
|
// })
|
||||||
|
//
|
||||||
// setInterval(() => {
|
// // setInterval(() => {
|
||||||
// log.initialize("定时检查更新")
|
// // log.initialize("定时检查更新")
|
||||||
// // autoUpdater.checkForUpdates();
|
// // // autoUpdater.checkForUpdates();
|
||||||
// }, 60000)
|
// // }, 60000)
|
||||||
autoUpdater.checkForUpdates();
|
// autoUpdater.checkForUpdates();
|
||||||
log.info("手动检查更新一次")
|
// log.info("手动检查更新一次")
|
||||||
|
//
|
||||||
|
//
|
||||||
}
|
// }
|
||||||
|
@ -5,6 +5,7 @@ import PathUtils from "../utils/PathUtils";
|
|||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import FrpcProcessService from "../service/FrpcProcessService";
|
import FrpcProcessService from "../service/FrpcProcessService";
|
||||||
import SystemService from "../service/SystemService";
|
import SystemService from "../service/SystemService";
|
||||||
|
import moment from "moment";
|
||||||
|
|
||||||
class ConfigController extends BaseController {
|
class ConfigController extends BaseController {
|
||||||
private readonly _serverService: ServerService;
|
private readonly _serverService: ServerService;
|
||||||
@ -70,8 +71,11 @@ class ConfigController extends BaseController {
|
|||||||
|
|
||||||
exportConfig(req: ControllerParam) {
|
exportConfig(req: ControllerParam) {
|
||||||
this._systemService.openDirectory().then(folder => {
|
this._systemService.openDirectory().then(folder => {
|
||||||
this._serverService.genTomlConfig(folder.filePaths[0]).then(() => {
|
const path = `${folder.filePaths[0]}/frpc-${moment(new Date()).format(
|
||||||
req.event.reply(req.channel, success());
|
"YYYYMMDDhhmmss"
|
||||||
|
)}.toml`;
|
||||||
|
this._serverService.genTomlConfig(path).then(() => {
|
||||||
|
req.event.reply(req.channel, success(path));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import BaseController from "./BaseController";
|
import BaseController from "./BaseController";
|
||||||
import ProxyService from "../service/ProxyService";
|
import ProxyService from "../service/ProxyService";
|
||||||
import { success } from "../utils/response";
|
import { success } from "../utils/response";
|
||||||
import ProxyDao from "../dao/ProxyDao";
|
import ProxyRepository from "../repository/ProxyRepository";
|
||||||
|
|
||||||
class ProxyController extends BaseController {
|
class ProxyController extends BaseController {
|
||||||
private readonly _proxyService: ProxyService;
|
private readonly _proxyService: ProxyService;
|
||||||
private readonly _proxyDao: ProxyDao;
|
private readonly _proxyDao: ProxyRepository;
|
||||||
|
|
||||||
constructor(proxyService: ProxyService, proxyDao: ProxyDao) {
|
constructor(proxyService: ProxyService, proxyDao: ProxyRepository) {
|
||||||
super();
|
super();
|
||||||
this._proxyService = proxyService;
|
this._proxyService = proxyService;
|
||||||
this._proxyDao = proxyDao;
|
this._proxyDao = proxyDao;
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import BaseController from "./BaseController";
|
import BaseController from "./BaseController";
|
||||||
import VersionService from "../service/VersionService";
|
import VersionService from "../service/VersionService";
|
||||||
import { fail, success } from "../utils/response";
|
import { fail, success } from "../utils/response";
|
||||||
import VersionDao from "../dao/VersionDao";
|
import VersionRepository from "../repository/VersionRepository";
|
||||||
|
|
||||||
class VersionController extends BaseController {
|
class VersionController extends BaseController {
|
||||||
private readonly _versionService: VersionService;
|
private readonly _versionService: VersionService;
|
||||||
private readonly _versionDao: VersionDao;
|
private readonly _versionDao: VersionRepository;
|
||||||
|
|
||||||
constructor(versionService: VersionService, versionDao: VersionDao) {
|
constructor(versionService: VersionService, versionDao: VersionRepository) {
|
||||||
super();
|
super();
|
||||||
this._versionService = versionService;
|
this._versionService = versionService;
|
||||||
this._versionDao = versionDao;
|
this._versionDao = versionDao;
|
||||||
|
@ -1,13 +1,23 @@
|
|||||||
/**
|
import Logger from "./Logger";
|
||||||
* todo DI
|
|
||||||
*/
|
|
||||||
class BeanFactory {
|
class BeanFactory {
|
||||||
private static _beans: Map<string, any> = new Map<string, any>();
|
private static _beans: Map<string, any> = new Map<string, any>();
|
||||||
|
|
||||||
private static registerBean(name: string, instance: any): void {
|
static registerBean(clazz: Function, beanName?: string): void {
|
||||||
if (!this._beans.has(name)) {
|
if (!beanName) {
|
||||||
this._beans.set(name, instance);
|
beanName = this.getBeanName(clazz.name);
|
||||||
}
|
}
|
||||||
|
if (this.hasBean(beanName)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const instance = new (clazz as any)();
|
||||||
|
|
||||||
|
this._beans.set(beanName, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static setBean<T>(name: string, bean: T): void {
|
||||||
|
this._beans.set(name, bean);
|
||||||
|
Logger.info(`register bean ${name} ${bean}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static getBean<T>(name: string): T {
|
public static getBean<T>(name: string): T {
|
||||||
@ -21,6 +31,14 @@ class BeanFactory {
|
|||||||
public static clear(): void {
|
public static clear(): void {
|
||||||
this._beans.clear();
|
this._beans.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static getBeanName(className: string) {
|
||||||
|
return className.charAt(0).toLowerCase() + className.slice(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export default BeanFactory;
|
export default BeanFactory;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
|
import { app } from "electron";
|
||||||
|
|
||||||
class GlobalConstant {
|
class GlobalConstant {
|
||||||
public static APP_NAME = "Frpc Desktop";
|
|
||||||
public static ZIP_EXT = ".zip";
|
public static ZIP_EXT = ".zip";
|
||||||
public static GZ_EXT = ".gz";
|
public static GZ_EXT = ".gz";
|
||||||
public static TAR_GZ_EXT = ".tar.gz";
|
public static TAR_GZ_EXT = ".tar.gz";
|
||||||
|
@ -1,20 +1,3 @@
|
|||||||
import ConfigController from "../controller/ConfigController";
|
|
||||||
import ServerDao from "../dao/ServerDao";
|
|
||||||
import ServerService from "../service/ServerService";
|
|
||||||
import LogService from "../service/LogService";
|
|
||||||
import VersionService from "../service/VersionService";
|
|
||||||
import { BrowserWindow, ipcMain } from "electron";
|
|
||||||
import LogController from "../controller/LogController";
|
|
||||||
import VersionController from "../controller/VersionController";
|
|
||||||
import VersionDao from "../dao/VersionDao";
|
|
||||||
import GitHubService from "../service/GitHubService";
|
|
||||||
import FrpcProcessService from "../service/FrpcProcessService";
|
|
||||||
import LaunchController from "../controller/LaunchController";
|
|
||||||
import ProxyDao from "../dao/ProxyDao";
|
|
||||||
import ProxyService from "../service/ProxyService";
|
|
||||||
import ProxyController from "../controller/ProxyController";
|
|
||||||
import SystemService from "../service/SystemService";
|
|
||||||
import SystemController from "../controller/SystemController";
|
|
||||||
|
|
||||||
export const ipcRouters: IpcRouters = {
|
export const ipcRouters: IpcRouters = {
|
||||||
SERVER: {
|
SERVER: {
|
||||||
@ -133,119 +116,3 @@ export const listeners: Listeners = {
|
|||||||
channel: "frpcProcess:watchFrpcLog"
|
channel: "frpcProcess:watchFrpcLog"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class IpcRouterConfigurate {
|
|
||||||
ipcRouters: Array<IpcRouter>;
|
|
||||||
private readonly _beans: Map<string, any> = new Map<string, any>();
|
|
||||||
private readonly _win: BrowserWindow;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* initBeans
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
private initializeBeans() {
|
|
||||||
const serverDao = new ServerDao();
|
|
||||||
const versionDao = new VersionDao();
|
|
||||||
const proxyDao = new ProxyDao();
|
|
||||||
const systemService = new SystemService();
|
|
||||||
const serverService = new ServerService(serverDao, proxyDao);
|
|
||||||
const gitHubService = new GitHubService();
|
|
||||||
const versionService = new VersionService(
|
|
||||||
versionDao,
|
|
||||||
systemService,
|
|
||||||
gitHubService
|
|
||||||
);
|
|
||||||
const logService = new LogService(systemService);
|
|
||||||
const frpcProcessService = new FrpcProcessService(
|
|
||||||
serverService,
|
|
||||||
versionDao
|
|
||||||
);
|
|
||||||
const proxyService = new ProxyService(proxyDao);
|
|
||||||
const configController = new ConfigController(
|
|
||||||
serverService,
|
|
||||||
systemService,
|
|
||||||
frpcProcessService
|
|
||||||
);
|
|
||||||
const versionController = new VersionController(versionService, versionDao);
|
|
||||||
const logController = new LogController(logService);
|
|
||||||
const launchController = new LaunchController(frpcProcessService);
|
|
||||||
const proxyController = new ProxyController(proxyService, proxyDao);
|
|
||||||
const systemController = new SystemController(systemService);
|
|
||||||
|
|
||||||
this._beans.set("serverDao", serverDao);
|
|
||||||
this._beans.set("versionDao", versionDao);
|
|
||||||
this._beans.set("proxyDao", proxyDao);
|
|
||||||
this._beans.set("systemService", systemService);
|
|
||||||
this._beans.set("serverService", serverService);
|
|
||||||
this._beans.set("versionService", versionService);
|
|
||||||
this._beans.set("logService", logService);
|
|
||||||
this._beans.set("proxyService", proxyService);
|
|
||||||
this._beans.set("frpcProcessService", frpcProcessService);
|
|
||||||
this._beans.set("configController", configController);
|
|
||||||
this._beans.set("versionController", versionController);
|
|
||||||
this._beans.set("logController", logController);
|
|
||||||
this._beans.set("launchController", launchController);
|
|
||||||
this._beans.set("proxyController", proxyController);
|
|
||||||
this._beans.set("systemController", systemController);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* initJob
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
private initializeListeners() {
|
|
||||||
Object.keys(listeners).forEach(listenerKey => {
|
|
||||||
console.log(listenerKey, "listenerKey", listeners[listenerKey]);
|
|
||||||
const { listenerMethod, channel } = listeners[listenerKey];
|
|
||||||
const [beanName, method] = listenerMethod.split(".");
|
|
||||||
const bean = this._beans.get(beanName);
|
|
||||||
const listenerParam: ListenerParam = {
|
|
||||||
win: this._win,
|
|
||||||
channel: channel,
|
|
||||||
args: []
|
|
||||||
};
|
|
||||||
bean[method].call(bean, listenerParam);
|
|
||||||
});
|
|
||||||
console.log("initialize listeners success");
|
|
||||||
// this._beans.get("logService").watchFrpcLog(this._win);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* initRouters
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
private initializeRouters() {
|
|
||||||
Object.keys(ipcRouters).forEach(routerKey => {
|
|
||||||
const routerGroup = ipcRouters[routerKey];
|
|
||||||
|
|
||||||
Object.keys(routerGroup).forEach(method => {
|
|
||||||
const router = routerGroup[method];
|
|
||||||
ipcMain.on(router.path, (event, args) => {
|
|
||||||
const req: ControllerParam = {
|
|
||||||
win: this._win,
|
|
||||||
channel: `${router.path}:hook`,
|
|
||||||
event: event,
|
|
||||||
args: args
|
|
||||||
};
|
|
||||||
const [beanName, method] = router.controller.split(".");
|
|
||||||
const bean = this._beans.get(beanName);
|
|
||||||
bean[method].call(bean, req);
|
|
||||||
// bean[method].call(bean, req);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* constructor
|
|
||||||
* @param win mainWindows
|
|
||||||
*/
|
|
||||||
constructor(win: BrowserWindow) {
|
|
||||||
this._win = win;
|
|
||||||
this.initializeBeans();
|
|
||||||
this.initializeListeners();
|
|
||||||
this.initializeRouters();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default IpcRouterConfigurate;
|
|
||||||
|
18
electron/core/Logger.ts
Normal file
18
electron/core/Logger.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import log from "electron-log";
|
||||||
|
|
||||||
|
class Logger {
|
||||||
|
static {
|
||||||
|
log.transports.file.level = "debug";
|
||||||
|
log.transports.console.level = "debug";
|
||||||
|
}
|
||||||
|
|
||||||
|
static info(msg: string) {}
|
||||||
|
|
||||||
|
static debug(msg: string) {}
|
||||||
|
|
||||||
|
static warn(msg: string) {}
|
||||||
|
|
||||||
|
static error(msg: string) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Logger;
|
25
electron/core/annotation/Component.ts
Normal file
25
electron/core/annotation/Component.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// // Class decorator
|
||||||
|
// import "reflect-metadata";
|
||||||
|
// import BeanFactory from "../BeanFactory";
|
||||||
|
//
|
||||||
|
// const Component =
|
||||||
|
// (): ClassDecorator =>
|
||||||
|
// target => {
|
||||||
|
// // BeanFactory.registerBean(
|
||||||
|
// // beanName || BeanFactory.getBeanName(target.name),
|
||||||
|
// // target
|
||||||
|
// // );
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// export default Component;
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// // export default function Component(beanName?: string): ClassDecorator {
|
||||||
|
// // return function (target) {
|
||||||
|
// // const paramtypes = Reflect.getMetadata('design:paramtypes', target);
|
||||||
|
// // console.log(paramtypes);
|
||||||
|
// // };
|
||||||
|
// // }
|
5
electron/core/annotation/Resource.ts
Normal file
5
electron/core/annotation/Resource.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
// export default function Resource(beanName?: string): PropertyDecorator {
|
||||||
|
// return function (target: Object, propertyKey: string | symbol) {
|
||||||
|
// console.log(target, propertyKey);
|
||||||
|
// };
|
||||||
|
// }
|
@ -10,14 +10,25 @@ import {
|
|||||||
} from "electron";
|
} from "electron";
|
||||||
import { release } from "node:os";
|
import { release } from "node:os";
|
||||||
import node_path, { join } from "node:path";
|
import node_path, { join } from "node:path";
|
||||||
import { initGitHubApi } from "../api/github";
|
import BeanFactory from "../core/BeanFactory";
|
||||||
import { initConfigApi } from "../api/config";
|
import ServerRepository from "../repository/ServerRepository";
|
||||||
import { startFrpWorkerProcess, stopFrpcProcess } from "../api/frpc";
|
import VersionRepository from "../repository/VersionRepository";
|
||||||
import { initFileApi } from "../api/file";
|
import ProxyRepository from "../repository/ProxyRepository";
|
||||||
import { getConfig } from "../storage/config";
|
import SystemService from "../service/SystemService";
|
||||||
import { initLog, logError, logInfo, LogModule } from "../utils/log";
|
import ServerService from "../service/ServerService";
|
||||||
import { maskSensitiveData } from "../utils/desensitize";
|
import GitHubService from "../service/GitHubService";
|
||||||
import IpcRouterConfigurate from "../core/IpcRouter";
|
import VersionService from "../service/VersionService";
|
||||||
|
import LogService from "../service/LogService";
|
||||||
|
import FrpcProcessService from "../service/FrpcProcessService";
|
||||||
|
import ProxyService from "../service/ProxyService";
|
||||||
|
import ConfigController from "../controller/ConfigController";
|
||||||
|
import VersionController from "../controller/VersionController";
|
||||||
|
import LogController from "../controller/LogController";
|
||||||
|
import LaunchController from "../controller/LaunchController";
|
||||||
|
import ProxyController from "../controller/ProxyController";
|
||||||
|
import SystemController from "../controller/SystemController";
|
||||||
|
import { ipcRouters, listeners } from "../core/IpcRouter";
|
||||||
|
import Logger from "../core/Logger";
|
||||||
|
|
||||||
process.env.DIST_ELECTRON = join(__dirname, "..");
|
process.env.DIST_ELECTRON = join(__dirname, "..");
|
||||||
process.env.DIST = join(process.env.DIST_ELECTRON, "../dist");
|
process.env.DIST = join(process.env.DIST_ELECTRON, "../dist");
|
||||||
@ -25,260 +36,351 @@ process.env.VITE_PUBLIC = process.env.VITE_DEV_SERVER_URL
|
|||||||
? join(process.env.DIST_ELECTRON, "../public")
|
? join(process.env.DIST_ELECTRON, "../public")
|
||||||
: process.env.DIST;
|
: process.env.DIST;
|
||||||
|
|
||||||
let win: BrowserWindow | null = null;
|
|
||||||
let tray = null;
|
|
||||||
const preload = join(__dirname, "../preload/index.js");
|
const preload = join(__dirname, "../preload/index.js");
|
||||||
const url = process.env.VITE_DEV_SERVER_URL;
|
const url = process.env.VITE_DEV_SERVER_URL;
|
||||||
const indexHtml = join(process.env.DIST, "index.html");
|
const indexHtml = join(process.env.DIST, "index.html");
|
||||||
let isQuiting;
|
|
||||||
|
|
||||||
// Disable GPU Acceleration for Windows 7
|
|
||||||
if (release().startsWith("6.1")) app.disableHardwareAcceleration();
|
|
||||||
|
|
||||||
// Set application name for Windows 10+ notifications
|
class FrpcDesktopApp {
|
||||||
if (process.platform === "win32") app.setAppUserModelId(app.getName());
|
private _win: BrowserWindow | null = null;
|
||||||
|
private readonly _silentStart = false;
|
||||||
|
private _quitting = false;
|
||||||
|
|
||||||
if (!app.requestSingleInstanceLock()) {
|
constructor() {
|
||||||
app.quit();
|
this.initializeBeans();
|
||||||
process.exit(0);
|
this.initializeListeners();
|
||||||
}
|
this.initializeRouters();
|
||||||
|
this.initializeElectronApp();
|
||||||
async function createWindow(config: FrpConfig) {
|
|
||||||
let show = true;
|
|
||||||
if (config) {
|
|
||||||
show = !config.systemSilentStartup;
|
|
||||||
}
|
|
||||||
win = new BrowserWindow({
|
|
||||||
title: "Frpc Desktop",
|
|
||||||
icon: join(process.env.VITE_PUBLIC, "logo/only/16x16.png"),
|
|
||||||
width: 800,
|
|
||||||
height: 600,
|
|
||||||
minWidth: 800,
|
|
||||||
minHeight: 600,
|
|
||||||
maxWidth: 1280,
|
|
||||||
maxHeight: 960,
|
|
||||||
webPreferences: {
|
|
||||||
preload,
|
|
||||||
// Warning: Enable nodeIntegration and disable contextIsolation is not secure in production
|
|
||||||
// Consider using contextBridge.exposeInMainWorld
|
|
||||||
// Read more on https://www.electronjs.org/docs/latest/tutorial/context-isolation
|
|
||||||
nodeIntegration: true,
|
|
||||||
contextIsolation: false
|
|
||||||
},
|
|
||||||
show: show
|
|
||||||
});
|
|
||||||
if (process.env.VITE_DEV_SERVER_URL) {
|
|
||||||
// electron-vite-vue#298
|
|
||||||
win.loadURL(url);
|
|
||||||
// Open devTool if the app is not packaged
|
|
||||||
win.webContents.openDevTools();
|
|
||||||
} else {
|
|
||||||
win.loadFile(indexHtml);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test actively push message to the Electron-Renderer
|
initializeWindow() {
|
||||||
win.webContents.on("did-finish-load", () => {
|
if (this._win) {
|
||||||
win?.webContents.send("main-process-message", new Date().toLocaleString());
|
|
||||||
});
|
|
||||||
|
|
||||||
// Make all links open with the browser, not with the application
|
|
||||||
win.webContents.setWindowOpenHandler(({ url }) => {
|
|
||||||
if (url.startsWith("https:")) shell.openExternal(url);
|
|
||||||
return { action: "deny" };
|
|
||||||
});
|
|
||||||
|
|
||||||
// 隐藏菜单栏
|
|
||||||
const { Menu } = require("electron");
|
|
||||||
Menu.setApplicationMenu(null);
|
|
||||||
// hide menu for Mac
|
|
||||||
// if (process.platform !== "darwin") {
|
|
||||||
// app.dock.hide();
|
|
||||||
// }
|
|
||||||
|
|
||||||
win.on("minimize", function (event) {
|
|
||||||
event.preventDefault();
|
|
||||||
win.hide();
|
|
||||||
});
|
|
||||||
|
|
||||||
win.on("close", function (event) {
|
|
||||||
if (!isQuiting) {
|
|
||||||
event.preventDefault();
|
|
||||||
win.hide();
|
|
||||||
if (process.platform === "darwin") {
|
|
||||||
app.dock.hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const createTray = (config: FrpConfig) => {
|
|
||||||
let menu: Array<MenuItemConstructorOptions | MenuItem> = [
|
|
||||||
{
|
|
||||||
label: "显示主窗口",
|
|
||||||
click: function () {
|
|
||||||
win.show();
|
|
||||||
if (process.platform === "darwin") {
|
|
||||||
app.dock.show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "退出",
|
|
||||||
click: () => {
|
|
||||||
isQuiting = true;
|
|
||||||
stopFrpcProcess(() => {
|
|
||||||
app.quit();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
];
|
|
||||||
tray = new Tray(
|
|
||||||
node_path.join(process.env.VITE_PUBLIC, "logo/only/16x16.png")
|
|
||||||
);
|
|
||||||
tray.setToolTip("Frpc Desktop");
|
|
||||||
const contextMenu = Menu.buildFromTemplate(menu);
|
|
||||||
tray.setContextMenu(contextMenu);
|
|
||||||
|
|
||||||
// 托盘双击打开
|
|
||||||
tray.on("double-click", () => {
|
|
||||||
win.show();
|
|
||||||
});
|
|
||||||
|
|
||||||
logInfo(LogModule.APP, `Tray created successfully.`);
|
|
||||||
};
|
|
||||||
app.whenReady().then(() => {
|
|
||||||
initLog();
|
|
||||||
logInfo(
|
|
||||||
LogModule.APP,
|
|
||||||
`Application started. Current system architecture: ${
|
|
||||||
process.arch
|
|
||||||
}, platform: ${process.platform}, version: ${app.getVersion()}.`
|
|
||||||
);
|
|
||||||
|
|
||||||
getConfig((err, config) => {
|
|
||||||
if (err) {
|
|
||||||
logError(LogModule.APP, `Failed to get config: ${err.message}`);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this._win = new BrowserWindow({
|
||||||
|
title: app.getName(),
|
||||||
|
icon: join(process.env.VITE_PUBLIC, "logo/only/16x16.png"),
|
||||||
|
width: 800,
|
||||||
|
height: 600,
|
||||||
|
minWidth: 800,
|
||||||
|
minHeight: 600,
|
||||||
|
maxWidth: 1280,
|
||||||
|
maxHeight: 960,
|
||||||
|
webPreferences: {
|
||||||
|
preload,
|
||||||
|
// Warning: Enable nodeIntegration and disable contextIsolation is not secure in production
|
||||||
|
// Consider using contextBridge.exposeInMainWorld
|
||||||
|
// Read more on https://www.electronjs.org/docs/latest/tutorial/context-isolation
|
||||||
|
nodeIntegration: true,
|
||||||
|
contextIsolation: false
|
||||||
|
},
|
||||||
|
show: true
|
||||||
|
});
|
||||||
|
BeanFactory.setBean("win", this._win);
|
||||||
|
if (process.env.VITE_DEV_SERVER_URL) {
|
||||||
|
// electron-vite-vue#298
|
||||||
|
this._win.loadURL(url).then(() => {});
|
||||||
|
// Open devTool if the app is not packaged
|
||||||
|
this._win.webContents.openDevTools();
|
||||||
|
} else {
|
||||||
|
this._win.loadFile(indexHtml).then(() => {});
|
||||||
|
}
|
||||||
|
|
||||||
createWindow(config)
|
this._win.webContents.on("did-finish-load", () => {
|
||||||
.then(r => {
|
this._win?.webContents.send(
|
||||||
logInfo(LogModule.APP, `Window created successfully.`);
|
"main-process-message",
|
||||||
createTray(config);
|
new Date().toLocaleString()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
this._win.webContents.setWindowOpenHandler(({ url }) => {
|
||||||
|
if (url.startsWith("https:")) shell.openExternal(url);
|
||||||
|
return { action: "deny" };
|
||||||
|
});
|
||||||
|
const { Menu } = require("electron");
|
||||||
|
Menu.setApplicationMenu(null);
|
||||||
|
|
||||||
if (config) {
|
const that = this;
|
||||||
logInfo(
|
this._win.on("minimize", function (event) {
|
||||||
LogModule.APP,
|
event.preventDefault();
|
||||||
`Config retrieved: ${JSON.stringify(
|
that._win.hide();
|
||||||
maskSensitiveData(config, [
|
});
|
||||||
"serverAddr",
|
|
||||||
"serverPort",
|
|
||||||
"authToken",
|
|
||||||
"user",
|
|
||||||
"metaToken"
|
|
||||||
])
|
|
||||||
)}`
|
|
||||||
);
|
|
||||||
|
|
||||||
if (config.systemStartupConnect) {
|
this._win.on("close", function (event) {
|
||||||
startFrpWorkerProcess(config);
|
if (!that._quitting) {
|
||||||
|
event.preventDefault();
|
||||||
|
that._win.hide();
|
||||||
|
if (process.platform === "darwin") {
|
||||||
|
app.dock.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeTray() {
|
||||||
|
const that = this;
|
||||||
|
let menu: Array<MenuItemConstructorOptions | MenuItem> = [
|
||||||
|
{
|
||||||
|
label: "显示主窗口",
|
||||||
|
click: function () {
|
||||||
|
that._win.show();
|
||||||
|
if (process.platform === "darwin") {
|
||||||
|
app.dock.show().then(() => {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const ipcRouterConfig = new IpcRouterConfigurate(win);
|
},
|
||||||
// Initialize APIs
|
{
|
||||||
try {
|
label: "退出",
|
||||||
initGitHubApi(win);
|
click: () => {
|
||||||
logInfo(LogModule.APP, `GitHub API initialized.`);
|
that._quitting = true;
|
||||||
|
// todo stop frpc process
|
||||||
initConfigApi(win);
|
app.quit();
|
||||||
logInfo(LogModule.APP, `Config API initialized.`);
|
|
||||||
|
|
||||||
initFileApi();
|
|
||||||
logInfo(LogModule.APP, `File API initialized.`);
|
|
||||||
|
|
||||||
|
|
||||||
// initUpdaterApi(win);
|
|
||||||
logInfo(LogModule.APP, `Updater API initialization skipped.`);
|
|
||||||
} catch (error) {
|
|
||||||
logError(
|
|
||||||
LogModule.APP,
|
|
||||||
`Error during API initialization: ${error.message}`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
logError(LogModule.APP, `Error creating window: ${error.message}`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.on("window-all-closed", () => {
|
|
||||||
logInfo(LogModule.APP, `All windows closed.`);
|
|
||||||
win = null;
|
|
||||||
if (process.platform !== "darwin") {
|
|
||||||
stopFrpcProcess(() => {
|
|
||||||
logInfo(LogModule.APP, `FRPC process stopped. Quitting application.`);
|
|
||||||
app.quit();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.on("second-instance", () => {
|
|
||||||
logInfo(LogModule.APP, `Second instance detected.`);
|
|
||||||
if (win) {
|
|
||||||
// Focus on the main window if the user tried to open another
|
|
||||||
if (win.isMinimized()) win.restore();
|
|
||||||
win.focus();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.on("activate", () => {
|
|
||||||
logInfo(LogModule.APP, `Application activated.`);
|
|
||||||
const allWindows = BrowserWindow.getAllWindows();
|
|
||||||
if (allWindows.length) {
|
|
||||||
allWindows[0].focus();
|
|
||||||
} else {
|
|
||||||
getConfig((err, config) => {
|
|
||||||
if (err) {
|
|
||||||
logError(
|
|
||||||
LogModule.APP,
|
|
||||||
`Failed to get config on activate: ${err.message}`
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
createWindow(config).then(r => {
|
];
|
||||||
logInfo(LogModule.APP, `Window created on activate.`);
|
const tray = new Tray(
|
||||||
});
|
node_path.join(process.env.VITE_PUBLIC, "logo/only/16x16.png")
|
||||||
|
);
|
||||||
|
tray.setToolTip(app.getName());
|
||||||
|
const contextMenu = Menu.buildFromTemplate(menu);
|
||||||
|
tray.setContextMenu(contextMenu);
|
||||||
|
|
||||||
|
// 托盘双击打开
|
||||||
|
tray.on("double-click", () => {
|
||||||
|
this._win.show();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
app.on("before-quit", () => {
|
initializeElectronApp() {
|
||||||
logInfo(LogModule.APP, `Application is about to quit.`);
|
// Disable GPU Acceleration for Windows 7
|
||||||
stopFrpcProcess(() => {
|
if (release().startsWith("6.1")) app.disableHardwareAcceleration();
|
||||||
isQuiting = true;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.handle("open-win", (_, arg) => {
|
// Set application name for Windows 10+ notifications
|
||||||
logInfo(LogModule.APP, `Opening new window with argument: ${arg}`);
|
if (process.platform === "win32") app.setAppUserModelId(app.getName());
|
||||||
const childWindow = new BrowserWindow({
|
|
||||||
webPreferences: {
|
if (!app.requestSingleInstanceLock()) {
|
||||||
preload,
|
app.quit();
|
||||||
nodeIntegration: true,
|
process.exit(0);
|
||||||
contextIsolation: false
|
|
||||||
}
|
}
|
||||||
});
|
app.whenReady().then(() => {
|
||||||
|
this.initializeWindow();
|
||||||
|
this.initializeTray();
|
||||||
|
// initLog();
|
||||||
|
// logInfo(
|
||||||
|
// LogModule.APP,
|
||||||
|
// `Application started. Current system architecture: ${
|
||||||
|
// process.arch
|
||||||
|
// }, platform: ${process.platform}, version: ${app.getVersion()}.`
|
||||||
|
// );
|
||||||
|
|
||||||
if (process.env.VITE_DEV_SERVER_URL) {
|
// getConfig((err, config) => {
|
||||||
childWindow.loadURL(`${url}#${arg}`);
|
// if (err) {
|
||||||
logInfo(LogModule.APP, `Child window loaded URL: ${url}#${arg}`);
|
// logError(LogModule.APP, `Failed to get config: ${err.message}`);
|
||||||
} else {
|
// return;
|
||||||
childWindow.loadFile(indexHtml, { hash: arg });
|
// }
|
||||||
logInfo(
|
|
||||||
LogModule.APP,
|
// createWindow(config)
|
||||||
`Child window loaded file: ${indexHtml} with hash: ${arg}`
|
// .then(r => {
|
||||||
|
// logInfo(LogModule.APP, `Window created successfully.`);
|
||||||
|
// createTray(config);
|
||||||
|
//
|
||||||
|
// // if (config) {
|
||||||
|
// // logInfo(
|
||||||
|
// // LogModule.APP,
|
||||||
|
// // `Config retrieved: ${JSON.stringify(
|
||||||
|
// // maskSensitiveData(config, [
|
||||||
|
// // "serverAddr",
|
||||||
|
// // "serverPort",
|
||||||
|
// // "authToken",
|
||||||
|
// // "user",
|
||||||
|
// // "metaToken"
|
||||||
|
// // ])
|
||||||
|
// // )}`
|
||||||
|
// // );
|
||||||
|
// //
|
||||||
|
// // if (config.systemStartupConnect) {
|
||||||
|
// // startFrpWorkerProcess(config);
|
||||||
|
// // }
|
||||||
|
// // }
|
||||||
|
// // const ipcRouterConfig = new IpcRouterConfigurate(win);
|
||||||
|
// // Initialize APIs
|
||||||
|
// // try {
|
||||||
|
// // initGitHubApi(win);
|
||||||
|
// // logInfo(LogModule.APP, `GitHub API initialized.`);
|
||||||
|
// //
|
||||||
|
// // initConfigApi(win);
|
||||||
|
// // logInfo(LogModule.APP, `Config API initialized.`);
|
||||||
|
// //
|
||||||
|
// // initFileApi();
|
||||||
|
// // logInfo(LogModule.APP, `File API initialized.`);
|
||||||
|
// //
|
||||||
|
// // // initUpdaterApi(win);
|
||||||
|
// // logInfo(LogModule.APP, `Updater API initialization skipped.`);
|
||||||
|
// // } catch (error) {
|
||||||
|
// // logError(
|
||||||
|
// // LogModule.APP,
|
||||||
|
// // `Error during API initialization: ${error.message}`
|
||||||
|
// // );
|
||||||
|
// // }
|
||||||
|
// })
|
||||||
|
// .catch(error => {
|
||||||
|
// logError(LogModule.APP, `Error creating window: ${error.message}`);
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
});
|
||||||
|
|
||||||
|
app.on("window-all-closed", () => {
|
||||||
|
// logInfo(LogModule.APP, `All windows closed.`);
|
||||||
|
this._win = null;
|
||||||
|
if (process.platform !== "darwin") {
|
||||||
|
// todo stop frpc process
|
||||||
|
// stopFrpcProcess(() => {
|
||||||
|
// logInfo(LogModule.APP, `FRPC process stopped. Quitting application.`);
|
||||||
|
app.quit();
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.on("second-instance", () => {
|
||||||
|
if (this._win) {
|
||||||
|
if (this._win.isMinimized()) this._win.restore();
|
||||||
|
this._win.focus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.on("activate", () => {
|
||||||
|
// logInfo(LogModule.APP, `Application activated.`);
|
||||||
|
const allWindows = BrowserWindow.getAllWindows();
|
||||||
|
if (allWindows.length) {
|
||||||
|
allWindows[0].focus();
|
||||||
|
} else {
|
||||||
|
this.initializeWindow();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.on("before-quit", () => {
|
||||||
|
// todo stop frpc process
|
||||||
|
this._quitting = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeBeans() {
|
||||||
|
BeanFactory.setBean("serverRepository", new ServerRepository());
|
||||||
|
BeanFactory.setBean("versionRepository", new VersionRepository());
|
||||||
|
BeanFactory.setBean("proxyRepository", new ProxyRepository());
|
||||||
|
BeanFactory.setBean("systemService", new SystemService());
|
||||||
|
BeanFactory.setBean(
|
||||||
|
"serverService",
|
||||||
|
new ServerService(
|
||||||
|
BeanFactory.getBean("serverRepository"),
|
||||||
|
BeanFactory.getBean("proxyRepository")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
BeanFactory.setBean("gitHubService", new GitHubService());
|
||||||
|
BeanFactory.setBean(
|
||||||
|
"versionService",
|
||||||
|
new VersionService(
|
||||||
|
BeanFactory.getBean("versionRepository"),
|
||||||
|
BeanFactory.getBean("systemService"),
|
||||||
|
BeanFactory.getBean("gitHubService")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
BeanFactory.setBean(
|
||||||
|
"logService",
|
||||||
|
new LogService(BeanFactory.getBean("systemService"))
|
||||||
|
);
|
||||||
|
BeanFactory.setBean(
|
||||||
|
"frpcProcessService",
|
||||||
|
new FrpcProcessService(
|
||||||
|
BeanFactory.getBean("serverService"),
|
||||||
|
BeanFactory.getBean("versionRepository")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
BeanFactory.setBean(
|
||||||
|
"proxyService",
|
||||||
|
new ProxyService(BeanFactory.getBean("proxyRepository"))
|
||||||
|
);
|
||||||
|
BeanFactory.setBean(
|
||||||
|
"configController",
|
||||||
|
new ConfigController(
|
||||||
|
BeanFactory.getBean("serverService"),
|
||||||
|
BeanFactory.getBean("systemService"),
|
||||||
|
BeanFactory.getBean("frpcProcessService")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
BeanFactory.setBean(
|
||||||
|
"versionController",
|
||||||
|
new VersionController(
|
||||||
|
BeanFactory.getBean("versionService"),
|
||||||
|
BeanFactory.getBean("versionRepository")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
BeanFactory.setBean(
|
||||||
|
"logController",
|
||||||
|
new LogController(BeanFactory.getBean("logService"))
|
||||||
|
);
|
||||||
|
BeanFactory.setBean(
|
||||||
|
"launchController",
|
||||||
|
new LaunchController(BeanFactory.getBean("frpcProcessService"))
|
||||||
|
);
|
||||||
|
BeanFactory.setBean(
|
||||||
|
"proxyController",
|
||||||
|
new ProxyController(
|
||||||
|
BeanFactory.getBean("proxyService"),
|
||||||
|
BeanFactory.getBean("proxyRepository")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
BeanFactory.setBean(
|
||||||
|
"systemController",
|
||||||
|
new SystemController(BeanFactory.getBean("systemService"))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
/**
|
||||||
|
* initJob
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
private initializeListeners() {
|
||||||
|
Object.keys(listeners).forEach(listenerKey => {
|
||||||
|
console.log(listenerKey, "listenerKey", listeners[listenerKey]);
|
||||||
|
const { listenerMethod, channel } = listeners[listenerKey];
|
||||||
|
const [beanName, method] = listenerMethod.split(".");
|
||||||
|
const bean = BeanFactory.getBean(beanName);
|
||||||
|
const listenerParam: ListenerParam = {
|
||||||
|
// win: BeanFactory.getBean("win"),
|
||||||
|
channel: channel,
|
||||||
|
args: []
|
||||||
|
};
|
||||||
|
bean[method].call(bean, listenerParam);
|
||||||
|
});
|
||||||
|
Logger.info("initialize listeners success");
|
||||||
|
// this._beans.get("logService").watchFrpcLog(this._win);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* initRouters
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
private initializeRouters() {
|
||||||
|
Object.keys(ipcRouters).forEach(routerKey => {
|
||||||
|
const routerGroup = ipcRouters[routerKey];
|
||||||
|
|
||||||
|
Object.keys(routerGroup).forEach(method => {
|
||||||
|
const router = routerGroup[method];
|
||||||
|
ipcMain.on(router.path, (event, args) => {
|
||||||
|
const req: ControllerParam = {
|
||||||
|
// win: BeanFactory.getBean("win"),
|
||||||
|
channel: `${router.path}:hook`,
|
||||||
|
event: event,
|
||||||
|
args: args
|
||||||
|
};
|
||||||
|
const [beanName, method] = router.controller.split(".");
|
||||||
|
const bean = BeanFactory.getBean(beanName);
|
||||||
|
bean[method].call(bean, req);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new FrpcDesktopApp();
|
@ -20,7 +20,7 @@ import IdUtils from "../utils/IdUtils";
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
class BaseDao<T> {
|
class BaseRepository<T> {
|
||||||
protected readonly db: Datastore;
|
protected readonly db: Datastore;
|
||||||
|
|
||||||
constructor(dbName: string) {
|
constructor(dbName: string) {
|
||||||
@ -135,4 +135,4 @@ class BaseDao<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default BaseDao;
|
export default BaseRepository;
|
@ -1,6 +1,8 @@
|
|||||||
import BaseDao from "./BaseDao";
|
import BaseRepository from "./BaseRepository";
|
||||||
|
import Component from "../core/annotation/Component";
|
||||||
|
|
||||||
class ProxyDao extends BaseDao<FrpcProxy> {
|
// @Component()
|
||||||
|
class ProxyRepository extends BaseRepository<FrpcProxy> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super("proxy");
|
super("proxy");
|
||||||
}
|
}
|
||||||
@ -23,4 +25,4 @@ class ProxyDao extends BaseDao<FrpcProxy> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ProxyDao;
|
export default ProxyRepository;
|
@ -1,6 +1,8 @@
|
|||||||
import BaseDao from "./BaseDao";
|
import BaseRepository from "./BaseRepository";
|
||||||
|
import Component from "../core/annotation/Component";
|
||||||
|
|
||||||
class ServerDao extends BaseDao<OpenSourceFrpcDesktopServer> {
|
// @Component()
|
||||||
|
class ServerRepository extends BaseRepository<OpenSourceFrpcDesktopServer> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super("server");
|
super("server");
|
||||||
}
|
}
|
||||||
@ -18,4 +20,4 @@ class ServerDao extends BaseDao<OpenSourceFrpcDesktopServer> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ServerDao
|
export default ServerRepository
|
@ -1,6 +1,8 @@
|
|||||||
import BaseDao from "./BaseDao";
|
import BaseRepository from "./BaseRepository";
|
||||||
|
import Component from "../core/annotation/Component";
|
||||||
|
|
||||||
class VersionDao extends BaseDao<FrpcVersion> {
|
// @Component()
|
||||||
|
class VersionRepository extends BaseRepository<FrpcVersion> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super("version");
|
super("version");
|
||||||
}
|
}
|
||||||
@ -18,7 +20,7 @@ class VersionDao extends BaseDao<FrpcVersion> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
exists(githubReleaseId: number): Promise<boolean> {
|
exists(githubReleaseId: number): Promise<boolean> {
|
||||||
return new Promise(( resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.db.count({ githubReleaseId: githubReleaseId }, (err, count) => {
|
this.db.count({ githubReleaseId: githubReleaseId }, (err, count) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
reject(err);
|
reject(err);
|
||||||
@ -30,4 +32,4 @@ class VersionDao extends BaseDao<FrpcVersion> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default VersionDao;
|
export default VersionRepository;
|
@ -1,14 +1,14 @@
|
|||||||
import BaseDao from "../dao/BaseDao";
|
import BaseRepository from "../repository/BaseRepository";
|
||||||
|
|
||||||
|
|
||||||
interface BaseServiceInterface<T> {
|
interface BaseServiceInterface<T> {
|
||||||
// dao: BaseDao<T>;
|
// dao: BaseRepository<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
class BaseService<T> implements BaseServiceInterface<T> {
|
class BaseService<T> implements BaseServiceInterface<T> {
|
||||||
// dao: BaseDao<T>;
|
// dao: BaseRepository<T>;
|
||||||
//
|
//
|
||||||
// constructor(dao: BaseDao<T>) {
|
// constructor(dao: BaseRepository<T>) {
|
||||||
// this.dao = dao;
|
// this.dao = dao;
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
import ServerService from "./ServerService";
|
import ServerService from "./ServerService";
|
||||||
import VersionDao from "../dao/VersionDao";
|
import VersionRepository from "../repository/VersionRepository";
|
||||||
import PathUtils from "../utils/PathUtils";
|
import PathUtils from "../utils/PathUtils";
|
||||||
import GlobalConstant from "../core/GlobalConstant";
|
import GlobalConstant from "../core/GlobalConstant";
|
||||||
import { Notification } from "electron";
|
import { app, BrowserWindow, Notification } from "electron";
|
||||||
import { success } from "../utils/response";
|
import { success } from "../utils/response";
|
||||||
import treeKill from "tree-kill";
|
import treeKill from "tree-kill";
|
||||||
|
import BeanFactory from "../core/BeanFactory";
|
||||||
|
|
||||||
class FrpcProcessService {
|
class FrpcProcessService {
|
||||||
private readonly _serverService: ServerService;
|
private readonly _serverService: ServerService;
|
||||||
private readonly _versionDao: VersionDao;
|
private readonly _versionDao: VersionRepository;
|
||||||
private _frpcProcess: any;
|
private _frpcProcess: any;
|
||||||
private _frpcProcessListener: any;
|
private _frpcProcessListener: any;
|
||||||
|
|
||||||
constructor(serverService: ServerService, versionDao: VersionDao) {
|
constructor(serverService: ServerService, versionDao: VersionRepository) {
|
||||||
this._serverService = serverService;
|
this._serverService = serverService;
|
||||||
this._versionDao = versionDao;
|
this._versionDao = versionDao;
|
||||||
}
|
}
|
||||||
@ -81,7 +82,7 @@ class FrpcProcessService {
|
|||||||
console.log("running", running);
|
console.log("running", running);
|
||||||
if (!running) {
|
if (!running) {
|
||||||
new Notification({
|
new Notification({
|
||||||
title: GlobalConstant.APP_NAME,
|
title: app.getName(),
|
||||||
body: "Connection lost, please check the logs for details."
|
body: "Connection lost, please check the logs for details."
|
||||||
}).show();
|
}).show();
|
||||||
// logError(
|
// logError(
|
||||||
@ -90,7 +91,8 @@ class FrpcProcessService {
|
|||||||
// );
|
// );
|
||||||
// clearInterval(this._frpcProcessListener);
|
// clearInterval(this._frpcProcessListener);
|
||||||
}
|
}
|
||||||
listenerParam.win.webContents.send(
|
const win: BrowserWindow = BeanFactory.getBean("win");
|
||||||
|
win.webContents.send(
|
||||||
listenerParam.channel,
|
listenerParam.channel,
|
||||||
success(running)
|
success(running)
|
||||||
);
|
);
|
||||||
|
@ -2,6 +2,8 @@ import fs from "fs";
|
|||||||
import { success } from "../utils/response";
|
import { success } from "../utils/response";
|
||||||
import PathUtils from "../utils/PathUtils";
|
import PathUtils from "../utils/PathUtils";
|
||||||
import SystemService from "./SystemService";
|
import SystemService from "./SystemService";
|
||||||
|
import BeanFactory from "../core/BeanFactory";
|
||||||
|
import { BrowserWindow } from "electron";
|
||||||
|
|
||||||
class LogService {
|
class LogService {
|
||||||
private readonly _systemService: SystemService;
|
private readonly _systemService: SystemService;
|
||||||
@ -11,8 +13,11 @@ class LogService {
|
|||||||
this._systemService = systemService;
|
this._systemService = systemService;
|
||||||
}
|
}
|
||||||
|
|
||||||
getFrpLogContent(): Promise<string> {
|
async getFrpLogContent() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
if (!fs.existsSync(this._logPath)) {
|
||||||
|
resolve("");
|
||||||
|
}
|
||||||
fs.readFile(this._logPath, "utf-8", (error, data) => {
|
fs.readFile(this._logPath, "utf-8", (error, data) => {
|
||||||
if (!error) {
|
if (!error) {
|
||||||
resolve(data);
|
resolve(data);
|
||||||
@ -28,11 +33,12 @@ class LogService {
|
|||||||
setTimeout(() => this.watchFrpcLog(listenerParam), 1000);
|
setTimeout(() => this.watchFrpcLog(listenerParam), 1000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log('watchFrpcLog succcess');
|
console.log("watchFrpcLog succcess");
|
||||||
fs.watch(this._logPath, (eventType, filename) => {
|
fs.watch(this._logPath, (eventType, filename) => {
|
||||||
if (eventType === "change") {
|
if (eventType === "change") {
|
||||||
console.log("change", eventType, listenerParam.channel);
|
console.log("change", eventType, listenerParam.channel);
|
||||||
listenerParam.win.webContents.send(
|
const win: BrowserWindow = BeanFactory.getBean("win");
|
||||||
|
win.webContents.send(
|
||||||
listenerParam.channel,
|
listenerParam.channel,
|
||||||
success(true)
|
success(true)
|
||||||
);
|
);
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
import ProxyDao from "../dao/ProxyDao";
|
import ProxyRepository from "../repository/ProxyRepository";
|
||||||
|
import Component from "../core/annotation/Component";
|
||||||
|
|
||||||
const { exec, spawn } = require("child_process");
|
const { exec, spawn } = require("child_process");
|
||||||
|
|
||||||
class ProxyService {
|
class ProxyService {
|
||||||
private readonly _proxyDao: ProxyDao;
|
|
||||||
|
|
||||||
constructor(proxyDao: ProxyDao) {
|
private readonly _proxyDao: ProxyRepository;
|
||||||
|
|
||||||
|
constructor(public proxyDao: ProxyRepository) {
|
||||||
this._proxyDao = proxyDao;
|
this._proxyDao = proxyDao;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
import BaseService from "./BaseService";
|
import BaseService from "./BaseService";
|
||||||
import ServerDao from "../dao/ServerDao";
|
import ServerRepository from "../repository/ServerRepository";
|
||||||
import TOML from "smol-toml";
|
import TOML from "smol-toml";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import PathUtils from "../utils/PathUtils";
|
import PathUtils from "../utils/PathUtils";
|
||||||
import ProxyDao from "../dao/ProxyDao";
|
import ProxyRepository from "../repository/ProxyRepository";
|
||||||
|
|
||||||
class ServerService extends BaseService<OpenSourceFrpcDesktopServer> {
|
class ServerService extends BaseService<OpenSourceFrpcDesktopServer> {
|
||||||
private readonly _serverDao: ServerDao;
|
private readonly _serverDao: ServerRepository;
|
||||||
private readonly _proxyDao: ProxyDao;
|
private readonly _proxyDao: ProxyRepository;
|
||||||
private readonly _serverId: string = "1";
|
private readonly _serverId: string = "1";
|
||||||
|
|
||||||
constructor(serverDao: ServerDao, proxyDao: ProxyDao) {
|
constructor(serverDao: ServerRepository, proxyDao: ProxyRepository) {
|
||||||
super();
|
super();
|
||||||
this._serverDao = serverDao;
|
this._serverDao = serverDao;
|
||||||
this._proxyDao = proxyDao;
|
this._proxyDao = proxyDao;
|
||||||
|
@ -4,6 +4,7 @@ import path from "path";
|
|||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import zlib from "zlib";
|
import zlib from "zlib";
|
||||||
import admZip from "adm-zip";
|
import admZip from "adm-zip";
|
||||||
|
import Component from "../core/annotation/Component";
|
||||||
|
|
||||||
const tar = require("tar");
|
const tar = require("tar");
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import VersionDao from "../dao/VersionDao";
|
import VersionRepository from "../repository/VersionRepository";
|
||||||
import BaseService from "./BaseService";
|
import BaseService from "./BaseService";
|
||||||
import GitHubService from "./GitHubService";
|
import GitHubService from "./GitHubService";
|
||||||
import frpReleasesJson from "../json/frp-releases.json";
|
import frpReleasesJson from "../json/frp-releases.json";
|
||||||
@ -14,14 +14,14 @@ import frpChecksums from "../json/frp_all_sha256_checksums.json";
|
|||||||
import SystemService from "./SystemService";
|
import SystemService from "./SystemService";
|
||||||
|
|
||||||
class VersionService extends BaseService<FrpcVersion> {
|
class VersionService extends BaseService<FrpcVersion> {
|
||||||
private readonly _versionDao: VersionDao;
|
private readonly _versionDao: VersionRepository;
|
||||||
private readonly _systemService: SystemService;
|
private readonly _systemService: SystemService;
|
||||||
private readonly _gitHubService: GitHubService;
|
private readonly _gitHubService: GitHubService;
|
||||||
private readonly _currFrpArch: Array<string>;
|
private readonly _currFrpArch: Array<string>;
|
||||||
private _versions: Array<FrpcVersion> = [];
|
private _versions: Array<FrpcVersion> = [];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
versionDao: VersionDao,
|
versionDao: VersionRepository,
|
||||||
systemService: SystemService,
|
systemService: SystemService,
|
||||||
gitHubService: GitHubService
|
gitHubService: GitHubService
|
||||||
) {
|
) {
|
||||||
|
10
package.json
10
package.json
@ -64,9 +64,9 @@
|
|||||||
"sass": "^1.66.1",
|
"sass": "^1.66.1",
|
||||||
"tailwindcss": "^3.3.3",
|
"tailwindcss": "^3.3.3",
|
||||||
"tree-kill": "^1.2.2",
|
"tree-kill": "^1.2.2",
|
||||||
"typescript": "^5.1.6",
|
"typescript": "5.7.3",
|
||||||
"vite": "^4.4.9",
|
"vite": "^5.4.11",
|
||||||
"vite-plugin-electron": "^0.15.3",
|
"vite-plugin-electron": "^0.28.6",
|
||||||
"vite-plugin-electron-renderer": "^0.14.5",
|
"vite-plugin-electron-renderer": "^0.14.5",
|
||||||
"vue": "^3.3.4",
|
"vue": "^3.3.4",
|
||||||
"vue-router": "^4.2.4",
|
"vue-router": "^4.2.4",
|
||||||
@ -82,10 +82,10 @@
|
|||||||
"intro.js": "^8.0.0-beta.1",
|
"intro.js": "^8.0.0-beta.1",
|
||||||
"isbinaryfile": "4.0.10",
|
"isbinaryfile": "4.0.10",
|
||||||
"js-base64": "^3.7.7",
|
"js-base64": "^3.7.7",
|
||||||
|
"smol-toml": "^1.3.1",
|
||||||
"snowflakify": "^1.0.5",
|
"snowflakify": "^1.0.5",
|
||||||
"tar": "^6.2.0",
|
"tar": "^6.2.0",
|
||||||
"unused-filename": "^4.0.1",
|
"unused-filename": "^4.0.1",
|
||||||
"uuid": "^10.0.0",
|
"uuid": "^10.0.0"
|
||||||
"smol-toml": "^1.3.1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -362,21 +362,22 @@ onMounted(() => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
on(ipcRouters.SERVER.exportConfig, () => {
|
on(ipcRouters.SERVER.exportConfig, (data) => {
|
||||||
// 礼花
|
ElMessageBox.alert(`配置路径:${data}`, `🎉 导出成功`);
|
||||||
confetti({
|
// // 礼花
|
||||||
zIndex: 12002,
|
// confetti({
|
||||||
particleCount: 200,
|
// zIndex: 12002,
|
||||||
spread: 70,
|
// particleCount: 200,
|
||||||
origin: { y: 0.6 }
|
// spread: 70,
|
||||||
});
|
// origin: { y: 0.6 }
|
||||||
ElMessageBox.alert("🎉 恭喜你,导入成功 请重启软件", `提示`, {
|
// });
|
||||||
closeOnClickModal: false,
|
// ElMessageBox.alert("🎉 恭喜你,导入成功 请重启软件", `提示`, {
|
||||||
showClose: false,
|
// closeOnClickModal: false,
|
||||||
confirmButtonText: "立即重启"
|
// showClose: false,
|
||||||
}).then(() => {
|
// confirmButtonText: "立即重启"
|
||||||
send(ipcRouters.SYSTEM.relaunchApp);
|
// }).then(() => {
|
||||||
});
|
// send(ipcRouters.SYSTEM.relaunchApp);
|
||||||
|
// });
|
||||||
});
|
});
|
||||||
// ElMessageBox.alert(data, `提示`);
|
// ElMessageBox.alert(data, `提示`);
|
||||||
on(ipcRouters.SYSTEM.openAppData, () => {
|
on(ipcRouters.SYSTEM.openAppData, () => {
|
||||||
@ -514,7 +515,6 @@ onUnmounted(() => {
|
|||||||
removeRouterListeners(ipcRouters.SERVER.resetAllConfig);
|
removeRouterListeners(ipcRouters.SERVER.resetAllConfig);
|
||||||
removeRouterListeners(ipcRouters.VERSION.getDownloadedVersions);
|
removeRouterListeners(ipcRouters.VERSION.getDownloadedVersions);
|
||||||
removeRouterListeners(ipcRouters.SERVER.exportConfig);
|
removeRouterListeners(ipcRouters.SERVER.exportConfig);
|
||||||
// ipcRenderer.removeAllListeners("Config.clearAll.hook");
|
|
||||||
removeRouterListeners(ipcRouters.SYSTEM.openAppData);
|
removeRouterListeners(ipcRouters.SYSTEM.openAppData);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"types": [
|
"types": [
|
||||||
// "node",
|
// "node",
|
||||||
"vite/client",
|
"vite/client",
|
||||||
"element-plus/global"
|
"element-plus/global"
|
||||||
],
|
],
|
||||||
|
4
types/core.d.ts
vendored
4
types/core.d.ts
vendored
@ -5,14 +5,14 @@ interface ApiResponse<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface ControllerParam {
|
interface ControllerParam {
|
||||||
win: BrowserWindow;
|
// win: BrowserWindow;
|
||||||
channel: string;
|
channel: string;
|
||||||
event: Electron.IpcMainEvent;
|
event: Electron.IpcMainEvent;
|
||||||
args: any;
|
args: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ListenerParam {
|
interface ListenerParam {
|
||||||
win: BrowserWindow;
|
// win: BrowserWindow;
|
||||||
channel: string;
|
channel: string;
|
||||||
args: any[];
|
args: any[];
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user