nginx-ui/mcp/config/config_rename.go
2025-04-29 17:41:09 +08:00

120 lines
3.4 KiB
Go

package config
import (
"context"
"encoding/json"
"os"
"path/filepath"
"strings"
"github.com/0xJacky/Nginx-UI/internal/config"
"github.com/0xJacky/Nginx-UI/internal/helper"
"github.com/0xJacky/Nginx-UI/internal/nginx"
"github.com/0xJacky/Nginx-UI/model"
"github.com/0xJacky/Nginx-UI/query"
"github.com/mark3labs/mcp-go/mcp"
)
const nginxConfigRenameToolName = "nginx_config_rename"
var nginxConfigRenameTool = mcp.NewTool(
nginxConfigRenameToolName,
mcp.WithDescription("Rename a file or directory in the Nginx configuration path"),
mcp.WithString("base_path", mcp.Description("The base path where the file or directory is located")),
mcp.WithString("orig_name", mcp.Description("The original name of the file or directory")),
mcp.WithString("new_name", mcp.Description("The new name for the file or directory")),
mcp.WithArray("sync_node_ids", mcp.Description("IDs of nodes to sync the rename operation to")),
)
func handleNginxConfigRename(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
args := request.Params.Arguments
basePath := args["base_path"].(string)
origName := args["orig_name"].(string)
newName := args["new_name"].(string)
// Convert sync_node_ids from []interface{} to []uint64
syncNodeIdsInterface, ok := args["sync_node_ids"].([]interface{})
syncNodeIds := make([]uint64, 0)
if ok {
for _, id := range syncNodeIdsInterface {
if idFloat, ok := id.(float64); ok {
syncNodeIds = append(syncNodeIds, uint64(idFloat))
}
}
}
if origName == newName {
result := map[string]interface{}{
"message": "No changes needed, names are identical",
}
jsonResult, _ := json.Marshal(result)
return mcp.NewToolResultText(string(jsonResult)), nil
}
origFullPath := nginx.GetConfPath(basePath, origName)
newFullPath := nginx.GetConfPath(basePath, newName)
if !helper.IsUnderDirectory(origFullPath, nginx.GetConfPath()) ||
!helper.IsUnderDirectory(newFullPath, nginx.GetConfPath()) {
return nil, config.ErrPathIsNotUnderTheNginxConfDir
}
stat, err := os.Stat(origFullPath)
if err != nil {
return nil, err
}
if helper.FileExists(newFullPath) {
return nil, ErrFileAlreadyExists
}
err = os.Rename(origFullPath, newFullPath)
if err != nil {
return nil, err
}
// update ChatGPT records
g := query.ChatGPTLog
q := query.Config
cfg, err := q.Where(q.Filepath.Eq(origFullPath)).FirstOrInit()
if err != nil {
return nil, err
}
if !stat.IsDir() {
_, _ = g.Where(g.Name.Eq(newFullPath)).Delete()
_, _ = g.Where(g.Name.Eq(origFullPath)).Update(g.Name, newFullPath)
// for file, the sync policy for this file is used
syncNodeIds = cfg.SyncNodeIds
} else {
// is directory, update all records under the directory
_, _ = g.Where(g.Name.Like(origFullPath+"%")).Update(g.Name, g.Name.Replace(origFullPath, newFullPath))
}
_, err = q.Where(q.Filepath.Eq(origFullPath)).Updates(&model.Config{
Filepath: newFullPath,
Name: newName,
})
if err != nil {
return nil, err
}
b := query.ConfigBackup
_, _ = b.Where(b.FilePath.Eq(origFullPath)).Updates(map[string]interface{}{
"filepath": newFullPath,
"name": newName,
})
if len(syncNodeIds) > 0 {
err = config.SyncRenameOnRemoteServer(origFullPath, newFullPath, syncNodeIds)
if err != nil {
return nil, err
}
}
result := map[string]interface{}{
"path": strings.TrimLeft(filepath.Join(basePath, newName), "/"),
}
jsonResult, _ := json.Marshal(result)
return mcp.NewToolResultText(string(jsonResult)), nil
}