add update button
This commit is contained in:
@@ -15,7 +15,7 @@ export const apiKeyAuth =
|
||||
`http://127.0.0.1:${config.PORT || 3456}`,
|
||||
`http://localhost:${config.PORT || 3456}`,
|
||||
];
|
||||
if (req.headers.origin && allowedOrigins.includes(req.headers.origin)) {
|
||||
if (req.headers.origin && !allowedOrigins.includes(req.headers.origin)) {
|
||||
reply.status(403).send("CORS not allowed for this origin");
|
||||
return;
|
||||
} else {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import Server from "@musistudio/llms";
|
||||
import { readConfigFile, writeConfigFile, backupConfigFile } from "./utils";
|
||||
import { checkForUpdates, performUpdate } from "./utils";
|
||||
import { join } from "path";
|
||||
import fastifyStatic from "@fastify/static";
|
||||
|
||||
@@ -39,13 +40,6 @@ export const createServer = (config: any): Server => {
|
||||
|
||||
// Add endpoint to restart the service with access control
|
||||
server.app.post("/api/restart", async (req, reply) => {
|
||||
// Only allow full access users to restart service
|
||||
const accessLevel = (req as any).accessLevel || "restricted";
|
||||
if (accessLevel !== "full") {
|
||||
reply.status(403).send("Full access required to restart service");
|
||||
return;
|
||||
}
|
||||
|
||||
reply.send({ success: true, message: "Service restart initiated" });
|
||||
|
||||
// Restart the service after a short delay to allow response to be sent
|
||||
@@ -69,6 +63,44 @@ export const createServer = (config: any): Server => {
|
||||
server.app.get("/ui", async (_, reply) => {
|
||||
return reply.redirect("/ui/");
|
||||
});
|
||||
|
||||
// 版本检查端点
|
||||
server.app.get("/api/update/check", async (req, reply) => {
|
||||
try {
|
||||
// 获取当前版本
|
||||
const currentVersion = require("../package.json").version;
|
||||
const { hasUpdate, latestVersion, changelog } = await checkForUpdates(currentVersion);
|
||||
|
||||
return {
|
||||
hasUpdate,
|
||||
latestVersion: hasUpdate ? latestVersion : undefined,
|
||||
changelog: hasUpdate ? changelog : undefined
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Failed to check for updates:", error);
|
||||
reply.status(500).send({ error: "Failed to check for updates" });
|
||||
}
|
||||
});
|
||||
|
||||
// 执行更新端点
|
||||
server.app.post("/api/update/perform", async (req, reply) => {
|
||||
try {
|
||||
// 只允许完全访问权限的用户执行更新
|
||||
const accessLevel = (req as any).accessLevel || "restricted";
|
||||
if (accessLevel !== "full") {
|
||||
reply.status(403).send("Full access required to perform updates");
|
||||
return;
|
||||
}
|
||||
|
||||
// 执行更新逻辑
|
||||
const result = await performUpdate();
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error("Failed to perform update:", error);
|
||||
reply.status(500).send({ error: "Failed to perform update" });
|
||||
}
|
||||
});
|
||||
|
||||
return server;
|
||||
};
|
||||
|
||||
@@ -162,3 +162,6 @@ export const initConfig = async () => {
|
||||
|
||||
// 导出日志清理函数
|
||||
export { cleanupLogFiles };
|
||||
|
||||
// 导出更新功能
|
||||
export { checkForUpdates, performUpdate } from "./update";
|
||||
|
||||
80
src/utils/update.ts
Normal file
80
src/utils/update.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { exec } from "child_process";
|
||||
import { promisify } from "util";
|
||||
import { join } from "path";
|
||||
import { readFileSync } from "fs";
|
||||
|
||||
const execPromise = promisify(exec);
|
||||
|
||||
/**
|
||||
* 检查是否有新版本可用
|
||||
* @param currentVersion 当前版本
|
||||
* @returns 包含更新信息的对象
|
||||
*/
|
||||
export async function checkForUpdates(currentVersion: string) {
|
||||
try {
|
||||
// 从npm registry获取最新版本信息
|
||||
const { stdout } = await execPromise("npm view @musistudio/claude-code-router version");
|
||||
const latestVersion = stdout.trim();
|
||||
|
||||
// 比较版本
|
||||
const hasUpdate = compareVersions(latestVersion, currentVersion) > 0;
|
||||
|
||||
// 如果有更新,获取更新日志
|
||||
let changelog = "";
|
||||
|
||||
return { hasUpdate, latestVersion, changelog };
|
||||
} catch (error) {
|
||||
console.error("Error checking for updates:", error);
|
||||
// 如果检查失败,假设没有更新
|
||||
return { hasUpdate: false, latestVersion: currentVersion, changelog: "" };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行更新操作
|
||||
* @returns 更新结果
|
||||
*/
|
||||
export async function performUpdate() {
|
||||
try {
|
||||
// 执行npm update命令
|
||||
const { stdout, stderr } = await execPromise("npm update -g @musistudio/claude-code-router");
|
||||
|
||||
if (stderr) {
|
||||
console.error("Update stderr:", stderr);
|
||||
}
|
||||
|
||||
console.log("Update stdout:", stdout);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Update completed successfully. Please restart the application to apply changes."
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Error performing update:", error);
|
||||
return {
|
||||
success: false,
|
||||
message: `Failed to perform update: ${error instanceof Error ? error.message : 'Unknown error'}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较两个版本号
|
||||
* @param v1 版本号1
|
||||
* @param v2 版本号2
|
||||
* @returns 1 if v1 > v2, -1 if v1 < v2, 0 if equal
|
||||
*/
|
||||
function compareVersions(v1: string, v2: string): number {
|
||||
const parts1 = v1.split(".").map(Number);
|
||||
const parts2 = v2.split(".").map(Number);
|
||||
|
||||
for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
|
||||
const num1 = i < parts1.length ? parts1[i] : 0;
|
||||
const num2 = i < parts2.length ? parts2[i] : 0;
|
||||
|
||||
if (num1 > num2) return 1;
|
||||
if (num1 < num2) return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user