🚧 v2
This commit is contained in:
parent
3ef92a8af9
commit
8d56faeb80
@ -1,28 +1,20 @@
|
||||
import electron, {
|
||||
app,
|
||||
dialog,
|
||||
BrowserWindow,
|
||||
ipcMain,
|
||||
net,
|
||||
shell
|
||||
} from "electron";
|
||||
import { app, BrowserWindow, dialog, ipcMain, net } from "electron";
|
||||
import {
|
||||
deleteVersionById,
|
||||
getVersionById,
|
||||
insertVersion,
|
||||
listVersion
|
||||
} from "../storage/version";
|
||||
import frpReleasesJson from "../json/frp-releases.json";
|
||||
import frpChecksums from "../json/frp_all_sha256_checksums.json";
|
||||
import { logDebug, logError, logInfo, LogModule, logWarn } from "../utils/log";
|
||||
// import { calculateFileChecksum, formatBytes } from "../utils/FileUtils";
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const zlib = require("zlib");
|
||||
const { download } = require("electron-dl");
|
||||
const AdmZip = require("adm-zip");
|
||||
import frpReleasesJson from "../json/frp-releases.json";
|
||||
import frpChecksums from "../json/frp_all_sha256_checksums.json";
|
||||
import { logInfo, logError, LogModule, logDebug, logWarn } from "../utils/log";
|
||||
import { calculateFileChecksum, formatBytes } from "../utils/file";
|
||||
import { el } from "element-plus/es/locale";
|
||||
|
||||
const versionRelation = {
|
||||
win32_x64: ["window", "amd64"],
|
||||
@ -311,7 +303,7 @@ export const initGitHubApi = win => {
|
||||
});
|
||||
});
|
||||
|
||||
request.on("error", error => {
|
||||
request.on("error", jerror => {
|
||||
logError(
|
||||
LogModule.GITHUB,
|
||||
"Error occurred while requesting GitHub releases: " + error
|
||||
|
@ -8,13 +8,11 @@ class LogController extends BaseController {
|
||||
constructor(logService: LogService) {
|
||||
super();
|
||||
this._logService = logService;
|
||||
console.log("logService2", this._logService);
|
||||
}
|
||||
|
||||
getFrpLogContent(req: ControllerRequest) {
|
||||
console.log("logService3", this._logService);
|
||||
getFrpLogContent(req: ControllerParam) {
|
||||
this._logService.getFrpLogContent().then(data => {
|
||||
req.event.reply(req.reply, success(data));
|
||||
req.event.reply(req.channel, success(data));
|
||||
});
|
||||
}
|
||||
|
||||
@ -25,7 +23,7 @@ class LogController extends BaseController {
|
||||
// });
|
||||
// }
|
||||
|
||||
openFrpcLogFile(req: ControllerRequest) {
|
||||
openFrpcLogFile(req: ControllerParam) {
|
||||
this._logService.openFrpcLogFile().then(data => {
|
||||
if (data) {
|
||||
success(null);
|
||||
|
@ -1,17 +1,25 @@
|
||||
import BaseController from "./BaseController";
|
||||
import ServerService from "../service/ServerService";
|
||||
import IpcMainEvent = Electron.IpcMainEvent;
|
||||
import { success } from "../utils/response";
|
||||
|
||||
class ServerController extends BaseController {
|
||||
serverService: ServerService;
|
||||
private readonly _serverService: ServerService;
|
||||
|
||||
constructor(serverService: ServerService) {
|
||||
super();
|
||||
this.serverService = serverService;
|
||||
this._serverService = serverService;
|
||||
}
|
||||
|
||||
saveConfig(event: IpcMainEvent, ...args: any[]) {
|
||||
console.log("test", args);
|
||||
saveConfig(req: ControllerParam) {
|
||||
console.log("save", req.args);
|
||||
}
|
||||
|
||||
getServerConfig(req: ControllerParam) {
|
||||
console.log("get", req.args);
|
||||
this._serverService.getServerConfig().then(data => {
|
||||
req.event.reply(req.channel, success(data));
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
27
electron/controller/VersionController.ts
Normal file
27
electron/controller/VersionController.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import BaseController from "./BaseController";
|
||||
import VersionService from "../service/VersionService";
|
||||
import { success } from "../utils/response";
|
||||
|
||||
class VersionController extends BaseController {
|
||||
private readonly _versionService: VersionService;
|
||||
|
||||
constructor(versionService: VersionService) {
|
||||
super();
|
||||
this._versionService = versionService;
|
||||
}
|
||||
|
||||
getVersions(req: ControllerParam) {
|
||||
this._versionService
|
||||
.getFrpVersionsByGitHub()
|
||||
.then(data => {
|
||||
req.event.reply(req.channel, success(data));
|
||||
})
|
||||
.catch(() => {
|
||||
this._versionService.getFrpVersionByLocalJson().then(localData => {
|
||||
req.event.reply(req.channel, success(localData));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default VersionController;
|
24
electron/core/GlobalConstant.ts
Normal file
24
electron/core/GlobalConstant.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import path from "path";
|
||||
import { app } from "electron";
|
||||
import SecureUtils from "../utils/SecureUtils";
|
||||
|
||||
class GlobalConstant {
|
||||
public static FRPC_STORAGE_FOLDER = "";
|
||||
|
||||
public static ZIP_EXT = ".zip";
|
||||
public static GZ_EXT = ".gz";
|
||||
public static TAR_GZ_EXT = ".tar.gz";
|
||||
// public static APP_DATA_PATH = app.getPath("userData");
|
||||
|
||||
// public static DOWNLOAD_STORAGE_PATH = path.join(
|
||||
// GlobalConstant.APP_DATA_PATH,
|
||||
// SecureUtils.calculateMD5("download")
|
||||
// );
|
||||
//
|
||||
// public static VERSION_STORAGE_PATH = path.join(
|
||||
// GlobalConstant.APP_DATA_PATH,
|
||||
// SecureUtils.calculateMD5("frpc")
|
||||
// );
|
||||
}
|
||||
|
||||
export default GlobalConstant;
|
@ -2,73 +2,142 @@ import ServerController from "../controller/ServerController";
|
||||
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 FileService from "../service/FileService";
|
||||
import VersionDao from "../dao/VersionDao";
|
||||
import GitHubService from "../service/GitHubService";
|
||||
|
||||
type IpcRouter = {
|
||||
path: string;
|
||||
reply: string;
|
||||
controller: any;
|
||||
instance: any;
|
||||
export const ipcRouters: IpcRouters = {
|
||||
SERVER: {
|
||||
saveConfig: {
|
||||
path: "server/saveConfig",
|
||||
controller: "serverController.saveConfig"
|
||||
},
|
||||
getServerConfig: {
|
||||
path: "server/getServerConfig",
|
||||
controller: "serverController.getServerConfig"
|
||||
}
|
||||
},
|
||||
LOG: {
|
||||
getFrpLogContent: {
|
||||
path: "log/getFrpLogContent",
|
||||
controller: "logController.getFrpLogContent"
|
||||
},
|
||||
openFrpcLogFile: {
|
||||
path: "log/openFrpcLogFile",
|
||||
controller: "logController.openFrpcLogFile"
|
||||
}
|
||||
},
|
||||
VERSION: {
|
||||
getVersions: {
|
||||
path: "version/getVersions",
|
||||
controller: "versionController.getVersions"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const listeners: Listeners = {
|
||||
watchFrpcLog: {
|
||||
listenerMethod: "logService.watchFrpcLog",
|
||||
channel: "log:watchFrpcLog"
|
||||
}
|
||||
};
|
||||
|
||||
class IpcRouterConfigurate {
|
||||
ipcRouters: Array<IpcRouter>;
|
||||
private readonly _beans: Map<string, any> = new Map<string, any>();
|
||||
private readonly _win: BrowserWindow;
|
||||
|
||||
constructor(win: BrowserWindow) {
|
||||
this._win = win;
|
||||
/**
|
||||
* initBeans
|
||||
* @private
|
||||
*/
|
||||
private initializeBeans() {
|
||||
const serverDao = new ServerDao();
|
||||
const versionDao = new VersionDao();
|
||||
const fileService = new FileService();
|
||||
const serverService = new ServerService(serverDao);
|
||||
const gitHubService = new GitHubService();
|
||||
const versionService = new VersionService(
|
||||
versionDao,
|
||||
fileService,
|
||||
gitHubService
|
||||
);
|
||||
const logService = new LogService(fileService);
|
||||
const serverController = new ServerController(serverService);
|
||||
const versionController = new VersionController(versionService);
|
||||
const logController = new LogController(logService);
|
||||
|
||||
logService.watchFrpcLog(win);
|
||||
|
||||
this.ipcRouters = [
|
||||
{
|
||||
path: "server/test",
|
||||
reply: "server/test.hook",
|
||||
controller: serverController.saveConfig,
|
||||
instance: serverController
|
||||
},
|
||||
{
|
||||
path: "log/getFrpLogContent",
|
||||
reply: "log/getFrpLogContent.hook",
|
||||
controller: logController.getFrpLogContent,
|
||||
instance: logController
|
||||
},
|
||||
// {
|
||||
// path: "log/watchFrpcLogContent",
|
||||
// reply: "log/watchFrpcLogContent.hook",
|
||||
// controller: logController.watchFrpcLogContent,
|
||||
// instance: logController
|
||||
// },
|
||||
{
|
||||
path: "log/openFrpcLogFile",
|
||||
reply: "log/openFrpcLogFile.hook",
|
||||
controller: logController.openFrpcLogFile,
|
||||
instance: logController
|
||||
}
|
||||
];
|
||||
this._beans.set("serverDao", serverDao);
|
||||
this._beans.set("versionDao", versionDao);
|
||||
this._beans.set("fileService", fileService);
|
||||
this._beans.set("serverService", serverService);
|
||||
this._beans.set("versionService", versionService);
|
||||
this._beans.set("logService", logService);
|
||||
this._beans.set("serverController", serverController);
|
||||
this._beans.set("versionController", versionController);
|
||||
this._beans.set("logController", logController);
|
||||
}
|
||||
|
||||
init() {
|
||||
this.ipcRouters.forEach(router => {
|
||||
ipcMain.on(router.path, (event, args) => {
|
||||
const req: ControllerRequest = {
|
||||
win: this._win,
|
||||
reply: router.reply,
|
||||
event: event,
|
||||
args: args
|
||||
};
|
||||
router.controller.call(router.instance, req);
|
||||
/**
|
||||
* 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);
|
||||
});
|
||||
});
|
||||
});
|
||||
console.log("ipcRouter init success.");
|
||||
}
|
||||
|
||||
/**
|
||||
* constructor
|
||||
* @param win mainWindows
|
||||
*/
|
||||
constructor(win: BrowserWindow) {
|
||||
this._win = win;
|
||||
this.initializeBeans();
|
||||
this.initializeListeners();
|
||||
this.initializeRouters();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,24 +1,34 @@
|
||||
import Datastore from "nedb";
|
||||
import path from "path";
|
||||
import { app } from "electron";
|
||||
import Snowflakify from "snowflakify";
|
||||
import GlobalConstant from "../core/GlobalConstant";
|
||||
import PathUtils from "../utils/PathUtils";
|
||||
|
||||
interface BaseDaoInterface<T> {
|
||||
db: Datastore;
|
||||
// interface BaseDaoInterface<T> {
|
||||
// db: Datastore;
|
||||
//
|
||||
// insert(t: T): Promise<T>;
|
||||
//
|
||||
// //
|
||||
// updateById(id: string, t: T): Promise<T>;
|
||||
//
|
||||
// //
|
||||
// // deleteById(id: string): void;
|
||||
// //
|
||||
// // findAll(): T[];
|
||||
//
|
||||
// findById(id: string): Promise<T>;
|
||||
// }
|
||||
|
||||
insert(t: T): Promise<T>;
|
||||
|
||||
updateById(t: T): T;
|
||||
|
||||
deleteById(id: string): void;
|
||||
|
||||
findAll(): T[];
|
||||
}
|
||||
|
||||
class BaseDao<T> implements BaseDaoInterface<T> {
|
||||
db: Datastore;
|
||||
class BaseDao<T> {
|
||||
protected readonly db: Datastore;
|
||||
|
||||
constructor(dbName: string) {
|
||||
const dbFilename = path.join(app.getPath("userData"), `${dbName}-v2.db`);
|
||||
const dbFilename = path.join(
|
||||
PathUtils.getAppData(),
|
||||
`${dbName}-v2.db`
|
||||
);
|
||||
this.db = new Datastore({
|
||||
autoload: true,
|
||||
filename: dbFilename
|
||||
@ -26,22 +36,72 @@ class BaseDao<T> implements BaseDaoInterface<T> {
|
||||
// todo log
|
||||
}
|
||||
|
||||
async insert(t: T): Promise<T> {
|
||||
protected genId(): string {
|
||||
return IdUtils.genUUID();
|
||||
}
|
||||
|
||||
// async insert(t: T): Promise<T> {
|
||||
// return new Promise<T>((resolve, reject) => {
|
||||
// resolve(t);
|
||||
// });
|
||||
// }
|
||||
//
|
||||
insert(t: T): Promise<T> {
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
resolve(t);
|
||||
t["_id"] = this.genId();
|
||||
this.db.insert(t, (err, document) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
resolve(document);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
updateById(t: T): T {
|
||||
return null;
|
||||
updateById(id: string, t: T): Promise<T> {
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
this.db.update(
|
||||
{ _id: id },
|
||||
t,
|
||||
{ upsert: true },
|
||||
(err, numberOfUpdated, upsert) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
t["_id"] = id;
|
||||
resolve(t);
|
||||
// this.findById(id)
|
||||
// .then(data => {
|
||||
// resolve(t);
|
||||
// })
|
||||
// .catch(err2 => {
|
||||
// reject(err2);
|
||||
// });
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
deleteById(id: string): void {
|
||||
return null;
|
||||
}
|
||||
//
|
||||
// deleteById(id: string): void {
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// findAll(): T[] {
|
||||
// return null;
|
||||
// }
|
||||
|
||||
findAll(): T[] {
|
||||
return null;
|
||||
findById(id: string): Promise<T> {
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
this.db.findOne({ _id: id }, (err, document) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(document);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,19 @@ import BaseDao from "./BaseDao";
|
||||
|
||||
class ServerDao extends BaseDao<FrpcDesktopServer> {
|
||||
constructor() {
|
||||
super("config");
|
||||
super("server");
|
||||
}
|
||||
|
||||
exists(id: string): Promise<boolean> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.db.count({ _id: id }, (err, count) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(count > 0);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
33
electron/dao/VersionDao.ts
Normal file
33
electron/dao/VersionDao.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import BaseDao from "./BaseDao";
|
||||
|
||||
class VersionDao extends BaseDao<FrpcVersion> {
|
||||
constructor() {
|
||||
super("version");
|
||||
}
|
||||
|
||||
findByGithubReleaseId(githubReleaseId: number): Promise<FrpcVersion> {
|
||||
return new Promise<FrpcVersion>((resolve, reject) => {
|
||||
this.db.findOne({ githubReleaseId: githubReleaseId }, (err, document) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(document);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
exists(githubReleaseId: number): Promise<boolean> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.db.count({ githubReleaseId: githubReleaseId }, (err, count) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(count > 0);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default VersionDao;
|
@ -193,7 +193,6 @@ app.whenReady().then(() => {
|
||||
}
|
||||
}
|
||||
const ipcRouterConfig = new IpcRouterConfigurate(win);
|
||||
ipcRouterConfig.init();
|
||||
// Initialize APIs
|
||||
try {
|
||||
initGitHubApi(win);
|
||||
|
@ -1,15 +1,16 @@
|
||||
import BaseDao from "../dao/BaseDao";
|
||||
|
||||
|
||||
interface BaseServiceInterface<T> {
|
||||
dao: BaseDao<T>;
|
||||
// dao: BaseDao<T>;
|
||||
}
|
||||
|
||||
class BaseService<T> implements BaseServiceInterface<T> {
|
||||
dao: BaseDao<T>;
|
||||
|
||||
constructor(dao: BaseDao<T>) {
|
||||
this.dao = dao;
|
||||
}
|
||||
// dao: BaseDao<T>;
|
||||
//
|
||||
// constructor(dao: BaseDao<T>) {
|
||||
// this.dao = dao;
|
||||
// }
|
||||
}
|
||||
|
||||
export default BaseService;
|
||||
|
@ -1,9 +1,16 @@
|
||||
import { shell } from "electron";
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
import zlib from "zlib";
|
||||
import admZip from "adm-zip";
|
||||
import GlobalConstant from "../core/GlobalConstant";
|
||||
import { logError, logInfo, LogModule } from "../utils/log";
|
||||
// import tar from "tar";
|
||||
|
||||
class FileService {
|
||||
constructor() {}
|
||||
|
||||
openFile(filePath: string) {
|
||||
openLocalFile(filePath: string) {
|
||||
return new Promise<boolean>((resolve, reject) => {
|
||||
shell
|
||||
.openPath(filePath)
|
||||
@ -19,6 +26,62 @@ class FileService {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
decompressZipFile(zipFilePath: string, targetPath: string) {
|
||||
if (!zipFilePath.endsWith(GlobalConstant.ZIP_EXT)) {
|
||||
throw new Error("The file is not a .zip file");
|
||||
}
|
||||
if (!fs.existsSync(zipFilePath)) {
|
||||
throw new Error("The file does not exist");
|
||||
}
|
||||
// const zipBasename = path.basename(zipFilePath, GlobalConstant.ZIP_EXT);
|
||||
const targetFolder = path.join(targetPath, targetPath);
|
||||
if (!fs.existsSync) {
|
||||
// not exists. do mkdir
|
||||
fs.mkdirSync(targetFolder, {
|
||||
recursive: true
|
||||
});
|
||||
}
|
||||
// starting unzip.
|
||||
const zip = new admZip(zipFilePath);
|
||||
zip.extractAllTo(targetPath, true); // true: cover exists file.
|
||||
// todo 2025-02-21 return targetPath.
|
||||
// const frpcPath = path.join("frp", path.basename(zipFilePath, zipExt));
|
||||
}
|
||||
|
||||
decompressTarGzFile(tarGzPath: string, targetPath: string) {
|
||||
// const targetFolder = path.join(targetPath, targetPath);
|
||||
const unzip = zlib.createGunzip();
|
||||
const readStream = fs.createReadStream(tarGzPath);
|
||||
// if (!fs.existsSync(unzip)) {
|
||||
// fs.mkdirSync(targetPath, { recursive: true, mode: 0o777 });
|
||||
// }
|
||||
readStream
|
||||
.pipe(unzip)
|
||||
.on("error", err => {
|
||||
logError(LogModule.APP, `Error during gunzip: ${err.message}`);
|
||||
})
|
||||
// .pipe(
|
||||
// tar
|
||||
// .extract({
|
||||
// cwd: targetPath,
|
||||
// filter: filePath => path.basename(filePath) === "frpc"
|
||||
// })
|
||||
// .on("error", err => {
|
||||
// logError(
|
||||
// LogModule.APP,
|
||||
// `Error extracting tar file: ${err.message}`
|
||||
// );
|
||||
// })
|
||||
// )
|
||||
.on("finish", () => {
|
||||
const frpcPath = path.join("frp", path.basename(tarGzPath, ".tar.gz"));
|
||||
logInfo(
|
||||
LogModule.APP,
|
||||
`Extraction completed. Extracted directory: ${frpcPath}`
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default FileService;
|
||||
|
64
electron/service/GitHubService.ts
Normal file
64
electron/service/GitHubService.ts
Normal file
@ -0,0 +1,64 @@
|
||||
class GitHubService {
|
||||
constructor() {}
|
||||
|
||||
getGithubRepoAllReleases(githubRepo: string): Promise<Array<GithubRelease>> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const { net } = require("electron");
|
||||
|
||||
const request = net.request({
|
||||
method: "get",
|
||||
url: `https://api.github.com/repos/${githubRepo}/releases?page=1&per_page=1000`
|
||||
});
|
||||
|
||||
request.on("response", response => {
|
||||
// logInfo(
|
||||
// LogModule.GITHUB,
|
||||
// `Received response with status code: ${response.statusCode}`
|
||||
// );
|
||||
let responseData: Buffer = Buffer.alloc(0);
|
||||
|
||||
response.on("data", (data: Buffer) => {
|
||||
responseData = Buffer.concat([responseData, data]);
|
||||
});
|
||||
|
||||
response.on("end", () => {
|
||||
if (response.statusCode === 200) {
|
||||
this.parseGitHubVersion(responseData.toString())
|
||||
.then(data => {
|
||||
resolve(data);
|
||||
})
|
||||
.catch(err => reject(err));
|
||||
// logInfo(
|
||||
// LogModule.GITHUB,
|
||||
// "Successfully retrieved GitHub release data."
|
||||
// );
|
||||
} else {
|
||||
// logWarn(
|
||||
// LogModule.GITHUB,
|
||||
// "Failed to retrieve data, using local JSON instead. Status code: " +
|
||||
// response.statusCode
|
||||
// );
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
request.on("error", error => {
|
||||
reject(error);
|
||||
});
|
||||
|
||||
request.end();
|
||||
});
|
||||
}
|
||||
|
||||
parseGitHubVersion(
|
||||
githubReleaseJsonStr: string
|
||||
): Promise<Array<GithubRelease>> {
|
||||
return new Promise<Array<GithubRelease>>(resolve => {
|
||||
const githubReleases: Array<GithubRelease> =
|
||||
JSON.parse(githubReleaseJsonStr);
|
||||
resolve(githubReleases);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default GitHubService;
|
@ -1,6 +1,6 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { app, BrowserWindow } from "electron";
|
||||
import { app } from "electron";
|
||||
import FileService from "./FileService";
|
||||
import { success } from "../utils/response";
|
||||
|
||||
@ -27,13 +27,14 @@ class LogService {
|
||||
});
|
||||
}
|
||||
|
||||
watchFrpcLog(win: BrowserWindow) {
|
||||
watchFrpcLog(listenerParam: ListenerParam) {
|
||||
fs.watch(this._logPath, (eventType, filename) => {
|
||||
if (eventType === "change") {
|
||||
win.webContents.send(
|
||||
"log/watchFrpcLogContent.hook",
|
||||
console.log("change", eventType, listenerParam.channel);
|
||||
listenerParam.win.webContents.send(
|
||||
listenerParam.channel,
|
||||
success(true)
|
||||
)
|
||||
);
|
||||
} else {
|
||||
}
|
||||
});
|
||||
@ -45,7 +46,7 @@ class LogService {
|
||||
openFrpcLogFile(): Promise<boolean> {
|
||||
return new Promise<boolean>((resolve, reject) => {
|
||||
this._fileService
|
||||
.openFile(this._logPath)
|
||||
.openLocalFile(this._logPath)
|
||||
.then(result => {
|
||||
resolve(result);
|
||||
})
|
||||
|
@ -2,11 +2,44 @@ import BaseService from "./BaseService";
|
||||
import ServerDao from "../dao/ServerDao";
|
||||
|
||||
class ServerService extends BaseService<FrpcDesktopServer> {
|
||||
private readonly _serverDao: ServerDao;
|
||||
constructor(serverDao: ServerDao) {
|
||||
super(serverDao);
|
||||
super();
|
||||
this._serverDao = serverDao;
|
||||
}
|
||||
|
||||
saveServerConfig(frpcServer: FrpcDesktopServer) {}
|
||||
saveServerConfig(frpcServer: FrpcDesktopServer): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this._serverDao
|
||||
.updateById("1", frpcServer)
|
||||
.then(() => {
|
||||
resolve();
|
||||
})
|
||||
.catch(err => reject(err));
|
||||
});
|
||||
}
|
||||
|
||||
getServerConfig(): Promise<FrpcDesktopServer> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this._serverDao
|
||||
.findById("1")
|
||||
.then((frpcServer: FrpcDesktopServer) => {
|
||||
resolve(frpcServer);
|
||||
})
|
||||
.catch(err => reject(err));
|
||||
});
|
||||
}
|
||||
|
||||
hasServerConfig(): Promise<boolean> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this._serverDao
|
||||
.exists("1")
|
||||
.then(r => {
|
||||
resolve(r);
|
||||
})
|
||||
.catch(err => reject(err));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default ServerService;
|
||||
|
191
electron/service/VersionService.ts
Normal file
191
electron/service/VersionService.ts
Normal file
@ -0,0 +1,191 @@
|
||||
import VersionDao from "../dao/VersionDao";
|
||||
import BaseService from "./BaseService";
|
||||
import GitHubService from "./GitHubService";
|
||||
import FileService from "./FileService";
|
||||
import frpReleasesJson from "../json/frp-releases.json";
|
||||
import { download } from "electron-dl";
|
||||
import { BrowserWindow } from "electron";
|
||||
import GlobalConstant from "../core/GlobalConstant";
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
import FileUtils from "../utils/FileUtils";
|
||||
import SecureUtils from "../utils/SecureUtils";
|
||||
import PathUtils from "../utils/PathUtils";
|
||||
|
||||
/**
|
||||
* arch mapping
|
||||
*/
|
||||
const versionMapping = {
|
||||
win32_x64: ["window", "amd64"],
|
||||
win32_arm64: ["window", "arm64"],
|
||||
win32_ia32: ["window", "386"],
|
||||
darwin_arm64: ["darwin", "arm64"],
|
||||
darwin_x64: ["darwin", "amd64"],
|
||||
darwin_amd64: ["darwin", "amd64"],
|
||||
linux_x64: ["linux", "amd64"],
|
||||
linux_arm64: ["linux", "arm64"]
|
||||
};
|
||||
|
||||
class VersionService extends BaseService<FrpcVersion> {
|
||||
private readonly _versionDao: VersionDao;
|
||||
private readonly _fileService: FileService;
|
||||
private readonly _gitHubService: GitHubService;
|
||||
private readonly _currFrpArch: Array<string>;
|
||||
private versions: Array<FrpcVersion> = [];
|
||||
|
||||
constructor(
|
||||
versionDao: VersionDao,
|
||||
fileService: FileService,
|
||||
gitHubService: GitHubService
|
||||
) {
|
||||
super();
|
||||
this._versionDao = versionDao;
|
||||
this._gitHubService = gitHubService;
|
||||
this._fileService = fileService;
|
||||
const nodeVersion = `${process.platform}_${process.arch}`;
|
||||
this._currFrpArch = versionMapping[nodeVersion];
|
||||
}
|
||||
|
||||
downloadFrpVersion(githubReleaseId: number, onProgress: Function) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const version = this.versions.find(
|
||||
f => f.githubReleaseId === githubReleaseId
|
||||
);
|
||||
if (!version) {
|
||||
reject(new Error("version not found"));
|
||||
}
|
||||
const url = version.browserDownloadUrl;
|
||||
const downloadedFilePath = path.join(
|
||||
PathUtils.getDownloadStoragePath(),
|
||||
`${version.assetName}`
|
||||
);
|
||||
|
||||
const versionFilePath = path.join(
|
||||
PathUtils.getVersionStoragePath(),
|
||||
SecureUtils.calculateMD5(version.name)
|
||||
);
|
||||
|
||||
// const targetPath = path.resolve();
|
||||
download(BrowserWindow.getFocusedWindow(), url, {
|
||||
filename: `${version.assetName}`,
|
||||
directory: PathUtils.getDownloadStoragePath(),
|
||||
onProgress: progress => {
|
||||
onProgress(progress);
|
||||
},
|
||||
onCompleted: () => {
|
||||
if (fs.existsSync(versionFilePath)) {
|
||||
fs.rmSync(versionFilePath, { recursive: true, force: true });
|
||||
}
|
||||
const ext = path.extname(version.assetName);
|
||||
if (ext === GlobalConstant.ZIP_EXT) {
|
||||
this._fileService.decompressZipFile(
|
||||
downloadedFilePath,
|
||||
versionFilePath
|
||||
);
|
||||
} else if (
|
||||
ext === GlobalConstant.GZ_EXT &&
|
||||
version.assetName.includes(GlobalConstant.TAR_GZ_EXT)
|
||||
) {
|
||||
this._fileService.decompressTarGzFile(
|
||||
downloadedFilePath,
|
||||
versionFilePath
|
||||
);
|
||||
}
|
||||
version.localPath = versionFilePath;
|
||||
this._versionDao.insert(version).then(data => {
|
||||
resolve(data);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
deleteFrpVersion() {}
|
||||
|
||||
getFrpVersionsByGitHub(): Promise<Array<FrpcVersion>> {
|
||||
return new Promise<Array<FrpcVersion>>((resolve, reject) => {
|
||||
this._gitHubService
|
||||
.getGithubRepoAllReleases("fatedier/frp")
|
||||
.then((releases: Array<GithubRelease>) => {
|
||||
const versions: Array<FrpcVersion> =
|
||||
this.githubRelease2FrpcVersion(releases);
|
||||
this.versions = versions;
|
||||
resolve(versions);
|
||||
})
|
||||
.catch(err => reject(err));
|
||||
});
|
||||
}
|
||||
|
||||
getFrpVersionByLocalJson(): Promise<Array<FrpcVersion>> {
|
||||
return new Promise<Array<FrpcVersion>>(resolve => {
|
||||
const versions = this.githubRelease2FrpcVersion(frpReleasesJson);
|
||||
resolve(versions);
|
||||
});
|
||||
}
|
||||
|
||||
getFrpVersion() {}
|
||||
|
||||
private findCurrentArchitectureAsset(assets: Array<GithubAsset>) {
|
||||
return assets.find((af: GithubAsset) => {
|
||||
return this._currFrpArch.every(item => af.name.includes(item));
|
||||
});
|
||||
}
|
||||
|
||||
private githubRelease2FrpcVersion(
|
||||
releases: Array<GithubRelease>
|
||||
): Array<FrpcVersion> {
|
||||
return releases
|
||||
.filter(release => {
|
||||
return this.findCurrentArchitectureAsset(release.assets);
|
||||
})
|
||||
.map(m => {
|
||||
const asset = this.findCurrentArchitectureAsset(m.assets);
|
||||
// m.assets.forEach((ma: GithubAsset) => {
|
||||
// // if (asset) {
|
||||
// // const absPath = path.join(
|
||||
// // frpPath,
|
||||
// // asset.name.replace(/(\.tar\.gz|\.zip)$/, "")
|
||||
// // );
|
||||
// // m.absPath = absPath;
|
||||
// // m.download_completed = fs.existsSync(absPath);
|
||||
// m.download_count = download_count;
|
||||
// m.size = formatBytes(ma.size);
|
||||
// // }
|
||||
// });
|
||||
// const asset = getAdaptiveAsset(m.id);
|
||||
const download_count = m.assets.reduce(
|
||||
(sum, item) => sum + item.download_count,
|
||||
0
|
||||
);
|
||||
|
||||
const v: FrpcVersion = {
|
||||
githubReleaseId: m.id,
|
||||
githubAssetId: asset.id,
|
||||
githubCreatedAt: asset.created_at,
|
||||
name: m.name,
|
||||
assetName: asset.name,
|
||||
versionDownloadCount: download_count,
|
||||
assetDownloadCount: asset.download_count,
|
||||
browserDownloadUrl: asset.browser_download_url,
|
||||
downloaded: false,
|
||||
localPath: "",
|
||||
size: FileUtils.formatBytes(asset.size)
|
||||
};
|
||||
|
||||
return v;
|
||||
});
|
||||
}
|
||||
|
||||
// private async frpcVersionExists(githubReleaseId: number): boolean {
|
||||
// const version = await this._versionDao.findByGithubReleaseId(
|
||||
// githubReleaseId
|
||||
// );
|
||||
//
|
||||
// if (version) {
|
||||
// return fs.existsSync(version.localPath);
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
}
|
||||
|
||||
export default VersionService;
|
23
electron/utils/FileUtils.ts
Normal file
23
electron/utils/FileUtils.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { createHash } from "crypto";
|
||||
import fs from "fs";
|
||||
|
||||
class FileUtils {
|
||||
public static formatBytes(bytes: number, decimals: number = 2): string {
|
||||
if (bytes === 0) return "0 Bytes";
|
||||
const k = 1024; // 1 KB = 1024 Bytes
|
||||
const dm = decimals < 0 ? 0 : decimals; // Ensure decimal places are not less than 0
|
||||
const sizes = ["Bytes", "KB", "MB", "GB", "TB"];
|
||||
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k)); // Calculate unit index
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i]; // Return formatted string
|
||||
}
|
||||
|
||||
public static calculateFileChecksum(filePath: string) {
|
||||
const fileBuffer = fs.readFileSync(filePath);
|
||||
const hash = createHash("sha256");
|
||||
hash.update(fileBuffer);
|
||||
return hash.digest("hex");
|
||||
}
|
||||
}
|
||||
|
||||
export default FileUtils;
|
39
electron/utils/IdUtils.ts
Normal file
39
electron/utils/IdUtils.ts
Normal file
@ -0,0 +1,39 @@
|
||||
class IdUtils {
|
||||
public static genUUID() {
|
||||
if (typeof crypto === "object") {
|
||||
if (typeof crypto.randomUUID === "function") {
|
||||
return crypto.randomUUID();
|
||||
}
|
||||
if (
|
||||
typeof crypto.getRandomValues === "function" &&
|
||||
typeof Uint8Array === "function"
|
||||
) {
|
||||
const callback = c => {
|
||||
const num = Number(c);
|
||||
return (
|
||||
num ^
|
||||
(crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (num / 4)))
|
||||
).toString(16);
|
||||
};
|
||||
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, callback);
|
||||
}
|
||||
}
|
||||
let timestamp = new Date().getTime();
|
||||
let perforNow =
|
||||
(typeof performance !== "undefined" &&
|
||||
performance.now &&
|
||||
performance.now() * 1000) ||
|
||||
0;
|
||||
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, c => {
|
||||
let random = Math.random() * 16;
|
||||
if (timestamp > 0) {
|
||||
random = (timestamp + random) % 16 | 0;
|
||||
timestamp = Math.floor(timestamp / 16);
|
||||
} else {
|
||||
random = (perforNow + random) % 16 | 0;
|
||||
perforNow = Math.floor(perforNow / 16);
|
||||
}
|
||||
return (c === "x" ? random : (random & 0x3) | 0x8).toString(16);
|
||||
});
|
||||
}
|
||||
}
|
26
electron/utils/PathUtils.ts
Normal file
26
electron/utils/PathUtils.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import SecureUtils from "./SecureUtils";
|
||||
|
||||
import { app } from "electron";
|
||||
import path from "path";
|
||||
|
||||
class PathUtils {
|
||||
public static getDownloadStoragePath() {
|
||||
return path.join(
|
||||
PathUtils.getAppData(),
|
||||
SecureUtils.calculateMD5("download")
|
||||
);
|
||||
}
|
||||
|
||||
public static getVersionStoragePath() {
|
||||
return path.join(
|
||||
PathUtils.getAppData(),
|
||||
SecureUtils.calculateMD5("frpc")
|
||||
);
|
||||
}
|
||||
|
||||
public static getAppData() {
|
||||
return app.getPath("userData");
|
||||
}
|
||||
}
|
||||
|
||||
export default PathUtils;
|
11
electron/utils/SecureUtils.ts
Normal file
11
electron/utils/SecureUtils.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { createHash } from "crypto";
|
||||
|
||||
class SecureUtils {
|
||||
public static calculateMD5(str: string): string {
|
||||
const hash = createHash("md5");
|
||||
hash.update(str);
|
||||
return hash.digest("hex");
|
||||
}
|
||||
}
|
||||
|
||||
export default SecureUtils;
|
@ -1,19 +0,0 @@
|
||||
import { createHash } from "crypto";
|
||||
|
||||
export const formatBytes = (bytes: number, decimals: number = 2): string => {
|
||||
if (bytes === 0) return "0 Bytes";
|
||||
const k = 1024; // 1 KB = 1024 Bytes
|
||||
const dm = decimals < 0 ? 0 : decimals; // Ensure decimal places are not less than 0
|
||||
const sizes = ["Bytes", "KB", "MB", "GB", "TB"];
|
||||
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k)); // Calculate unit index
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i]; // Return formatted string
|
||||
};
|
||||
|
||||
export const calculateFileChecksum = (filePath: string): string => {
|
||||
const fs = require("fs");
|
||||
const fileBuffer = fs.readFileSync(filePath);
|
||||
const hash = createHash("sha256");
|
||||
hash.update(fileBuffer);
|
||||
return hash.digest("hex");
|
||||
};
|
@ -82,6 +82,7 @@
|
||||
"intro.js": "^8.0.0-beta.1",
|
||||
"isbinaryfile": "4.0.10",
|
||||
"js-base64": "^3.7.7",
|
||||
"snowflakify": "^1.0.5",
|
||||
"tar": "^6.2.0",
|
||||
"unused-filename": "^4.0.1",
|
||||
"uuid": "^10.0.0"
|
||||
|
42
src/utils/ipcUtils.ts
Normal file
42
src/utils/ipcUtils.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import { ipcRenderer } from "electron";
|
||||
|
||||
export const send = (router: IpcRouter) => {
|
||||
console.log(router, "send.router");
|
||||
ipcRenderer.send(router.path);
|
||||
};
|
||||
|
||||
export const on = (router: IpcRouter, listerHandler: (data: any) => void) => {
|
||||
ipcRenderer.on(`${router.path}:hook`, (event, args: ApiResponse<any>) => {
|
||||
const { success, data, message } = args;
|
||||
if (success) {
|
||||
listerHandler(data);
|
||||
} else {
|
||||
// reject(new Error(message));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const onListener = (
|
||||
listener: Listener,
|
||||
listerHandler: (data: any) => void
|
||||
) => {
|
||||
// return new Promise((resolve, reject) => {
|
||||
ipcRenderer.on(`${listener.channel}`, (event, args: ApiResponse<any>) => {
|
||||
const { success, data, message } = args;
|
||||
if (success) {
|
||||
listerHandler(data);
|
||||
}
|
||||
});
|
||||
// });
|
||||
};
|
||||
|
||||
export const removeRouterListeners = (router: IpcRouter) => {
|
||||
ipcRenderer.removeAllListeners(`${router.path}:hook`);
|
||||
};
|
||||
|
||||
export const removeRouterListeners2 = (listen: Listener) => {
|
||||
ipcRenderer.removeAllListeners(`${listen.channel}`);
|
||||
}
|
||||
// export const removeAllListeners = (listen: Listener) => {
|
||||
// ipcRenderer.removeAllListeners(`${listen.channel}:hook`);
|
||||
// };
|
File diff suppressed because it is too large
Load Diff
@ -6,6 +6,8 @@ import Breadcrumb from "@/layout/compoenets/Breadcrumb.vue";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { useDebounceFn } from "@vueuse/core";
|
||||
import IconifyIconOffline from "@/components/IconifyIcon/src/iconifyIconOffline";
|
||||
import { on, send } from "@/utils/ipcUtils";
|
||||
import ipcRouter, { ipcRouters } from "../../../electron/core/IpcRouter";
|
||||
|
||||
defineComponent({
|
||||
name: "Download"
|
||||
@ -122,8 +124,18 @@ const handleMirrorChange = () => {
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
handleLoadVersions();
|
||||
handleInitDownloadHook();
|
||||
|
||||
send(ipcRouters.VERSION.getVersions);
|
||||
|
||||
on(ipcRouters.VERSION.getVersions, (data) => {
|
||||
console.log('versionData', data);
|
||||
// versions.value = args.map(m => {
|
||||
// m.published_at = moment(m.published_at).format("YYYY-MM-DD");
|
||||
// return m as FrpVersion;
|
||||
// }) as Array<FrpVersion>;
|
||||
});
|
||||
// handleLoadVersions();
|
||||
// handleInitDownloadHook();
|
||||
// ipcRenderer.invoke("process").then((r: any) => {
|
||||
// console.log(r, "rrr");
|
||||
// });
|
||||
|
@ -1,10 +1,18 @@
|
||||
<script lang="ts" setup>
|
||||
import { defineComponent, onMounted, onUnmounted, ref } from "vue";
|
||||
import Breadcrumb from "@/layout/compoenets/Breadcrumb.vue";
|
||||
import { ipcRenderer } from "electron";
|
||||
import IconifyIconOffline from "@/components/IconifyIcon/src/iconifyIconOffline";
|
||||
import { useDebounceFn } from "@vueuse/core";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { ipcRouters, listeners } from "../../../electron/core/IpcRouter";
|
||||
import {
|
||||
on,
|
||||
onListener,
|
||||
removeAllListeners,
|
||||
removeRouterListeners,
|
||||
removeRouterListeners2,
|
||||
send
|
||||
} from "@/utils/ipcUtils";
|
||||
|
||||
defineComponent({
|
||||
name: "Logger"
|
||||
@ -36,12 +44,9 @@ const logLoading = ref(true);
|
||||
// const isWatch = ref(false);
|
||||
|
||||
onMounted(() => {
|
||||
ipcRenderer.send("log/getFrpLogContent");
|
||||
ipcRenderer.on("log/getFrpLogContent.hook", (event, args) => {
|
||||
const { success, data } = args;
|
||||
if (success) {
|
||||
loggerContent.value = formatLogContent(data);
|
||||
}
|
||||
send(ipcRouters.LOG.getFrpLogContent);
|
||||
on(ipcRouters.LOG.getFrpLogContent, data => {
|
||||
loggerContent.value = formatLogContent(data as string);
|
||||
logLoading.value = false;
|
||||
if (refreshStatus.value) {
|
||||
// 刷新逻辑
|
||||
@ -49,47 +54,23 @@ onMounted(() => {
|
||||
type: "success",
|
||||
message: "刷新成功"
|
||||
});
|
||||
} else {
|
||||
// if (!isWatch.value) {
|
||||
// // ipcRenderer.send("log/watchFrpcLogContent");
|
||||
// isWatch.value = true;
|
||||
// }
|
||||
refreshStatus.value = false;
|
||||
}
|
||||
});
|
||||
ipcRenderer.on("log/watchFrpcLogContent.hook", (event, args) => {
|
||||
console.log(event,'eevent');
|
||||
console.log("watchFrpcLogContent", args);
|
||||
const { success, data } = args;
|
||||
if (success && data) {
|
||||
ipcRenderer.send("log/getFrpLogContent");
|
||||
}
|
||||
// if (args) {
|
||||
// loggerContent.value = formatLogContent(args);
|
||||
// }
|
||||
on(ipcRouters.LOG.openFrpcLogFile, () => {
|
||||
ElMessage({
|
||||
type: "success",
|
||||
message: "打开日志成功"
|
||||
});
|
||||
});
|
||||
// ipcRenderer.on("log/watchFrpcLogContent.hook", (event, args) => {
|
||||
// console.log("watchFrpcLogContent", args);
|
||||
// const { success, data } = args;
|
||||
// if (success && data) {
|
||||
// ipcRenderer.send("log/getFrpLogContent");
|
||||
// }
|
||||
// // if (args) {
|
||||
// // loggerContent.value = formatLogContent(args);
|
||||
// // }
|
||||
// });
|
||||
ipcRenderer.on("log/openFrpcLogFile.hook", (event, args) => {
|
||||
const { success } = args;
|
||||
if (success) {
|
||||
ElMessage({
|
||||
type: "success",
|
||||
message: "打开日志成功"
|
||||
});
|
||||
}
|
||||
onListener(listeners.watchFrpcLog, data => {
|
||||
console.log("onListener Data", data);
|
||||
send(ipcRouters.LOG.getFrpLogContent);
|
||||
});
|
||||
});
|
||||
|
||||
const openLocalLog = useDebounceFn(() => {
|
||||
ipcRenderer.send("log/openFrpcLogFile");
|
||||
send(ipcRouters.LOG.openFrpcLogFile);
|
||||
}, 1000);
|
||||
|
||||
const refreshLog = useDebounceFn(() => {
|
||||
@ -100,12 +81,12 @@ const refreshLog = useDebounceFn(() => {
|
||||
// });
|
||||
refreshStatus.value = true;
|
||||
logLoading.value = true;
|
||||
ipcRenderer.send("log/getFrpLogContent");
|
||||
send(ipcRouters.LOG.getFrpLogContent);
|
||||
}, 300);
|
||||
|
||||
onUnmounted(() => {
|
||||
ipcRenderer.removeAllListeners("log/getFrpLogContent.hook");
|
||||
ipcRenderer.removeAllListeners("log/openFrpcLogFile.hook");
|
||||
removeRouterListeners(ipcRouters.LOG.getFrpLogContent);
|
||||
removeRouterListeners2(listeners.watchFrpcLog);
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
|
35
types/core.d.ts
vendored
35
types/core.d.ts
vendored
@ -4,9 +4,40 @@ interface ApiResponse<T> {
|
||||
message: string;
|
||||
}
|
||||
|
||||
interface ControllerRequest {
|
||||
interface ControllerParam {
|
||||
win: BrowserWindow;
|
||||
reply: string;
|
||||
channel: string;
|
||||
event: Electron.IpcMainEvent;
|
||||
args: any[];
|
||||
}
|
||||
|
||||
interface ListenerParam {
|
||||
win: BrowserWindow;
|
||||
channel: string;
|
||||
args: any[];
|
||||
}
|
||||
|
||||
type IpcRouter = {
|
||||
path: string;
|
||||
controller: string;
|
||||
}
|
||||
|
||||
type Listener = {
|
||||
channel: string;
|
||||
listenerMethod: any;
|
||||
};
|
||||
|
||||
enum IpcRouterKeys {
|
||||
SERVER = "SERVER",
|
||||
LOG = "LOG",
|
||||
VERSION = "VERSION",
|
||||
}
|
||||
|
||||
type IpcRouters = Record<
|
||||
IpcRouterKeys,
|
||||
{
|
||||
[method: string]: IpcRouter;
|
||||
}
|
||||
>;
|
||||
|
||||
type Listeners = Record<string, Listener>;
|
||||
|
19
types/frp.d.ts
vendored
19
types/frp.d.ts
vendored
@ -18,10 +18,27 @@ type WebServerConfig = {
|
||||
pprofEnable: boolean;
|
||||
};
|
||||
|
||||
type TransportTlsConfig = {
|
||||
enable: boolean;
|
||||
certFile: string;
|
||||
keyFile: string;
|
||||
trustedCaFile: string;
|
||||
serverName: string;
|
||||
disableCustomTLSFirstByte: boolean;
|
||||
};
|
||||
|
||||
type TransportConfig = {
|
||||
dialServerTimeout: number;
|
||||
dialServerKeepalive: number;
|
||||
poolCount: number;
|
||||
tcpMux: boolean;
|
||||
tcpMuxKeepaliveInterval: number;
|
||||
protocol: string;
|
||||
connectServerLocalIP: string;
|
||||
proxyURL: string;
|
||||
tls: TransportTlsConfig;
|
||||
heartbeatInterval: number;
|
||||
heartbeatTimeout: number;
|
||||
};
|
||||
|
||||
interface FrpcCommonConfig {
|
||||
@ -34,7 +51,7 @@ interface FrpcCommonConfig {
|
||||
webServer: WebServerConfig;
|
||||
transport: TransportConfig;
|
||||
udpPacketSize: number;
|
||||
// metadatas: MetadataConfig;
|
||||
metadatas: Record<string, any>;
|
||||
}
|
||||
|
||||
interface FrpcProxyConfig {
|
||||
|
28
types/frpc-desktop.d.ts
vendored
28
types/frpc-desktop.d.ts
vendored
@ -1,3 +1,29 @@
|
||||
type FrpcDesktopProxy = FrpcProxyConfig & {};
|
||||
|
||||
type FrpcDesktopServer = FrpcCommonConfig & {};
|
||||
interface FrpcSystemConfiguration {
|
||||
launchAtStartup: boolean;
|
||||
silentStartup: boolean;
|
||||
autoConnectOnStartup: boolean;
|
||||
}
|
||||
|
||||
type FrpcDesktopServer = FrpcCommonConfig & {
|
||||
frpcVersion: number;
|
||||
};
|
||||
|
||||
type FrpcVersion = {
|
||||
githubReleaseId: number;
|
||||
githubAssetId: number;
|
||||
githubCreatedAt: string;
|
||||
name: string;
|
||||
assetName: string;
|
||||
versionDownloadCount: number;
|
||||
assetDownloadCount: number;
|
||||
browserDownloadUrl: string;
|
||||
downloaded: boolean;
|
||||
localPath: string;
|
||||
size: string;
|
||||
};
|
||||
|
||||
type OpenSourceFrpcDesktopServer = FrpcDesktopServer & {
|
||||
system: FrpcSystemConfiguration;
|
||||
};
|
18
types/github.d.ts
vendored
Normal file
18
types/github.d.ts
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
interface GithubAsset {
|
||||
id: number;
|
||||
name: string;
|
||||
content_type: string;
|
||||
download_count: number;
|
||||
size: number;
|
||||
browser_download_url: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
interface GithubRelease {
|
||||
id: number;
|
||||
name: string;
|
||||
created_at: string;
|
||||
published_at: string;
|
||||
assets: GithubAsset[]
|
||||
}
|
Loading…
Reference in New Issue
Block a user