Prechádzať zdrojové kódy

docs: update docs about insecure skip verify

Jacky 9 mesiacov pred
rodič
commit
6c7b644f60

+ 119 - 119
api/openai/openai.go

@@ -1,18 +1,18 @@
 package openai
 
 import (
-    "context"
-    "crypto/tls"
-    "fmt"
-    "github.com/0xJacky/Nginx-UI/api"
-    "github.com/0xJacky/Nginx-UI/internal/chatbot"
-    "github.com/0xJacky/Nginx-UI/settings"
-    "github.com/gin-gonic/gin"
-    "github.com/pkg/errors"
-    "github.com/sashabaranov/go-openai"
-    "io"
-    "net/http"
-    "net/url"
+	"context"
+	"crypto/tls"
+	"fmt"
+	"github.com/0xJacky/Nginx-UI/api"
+	"github.com/0xJacky/Nginx-UI/internal/chatbot"
+	"github.com/0xJacky/Nginx-UI/settings"
+	"github.com/gin-gonic/gin"
+	"github.com/pkg/errors"
+	"github.com/sashabaranov/go-openai"
+	"io"
+	"net/http"
+	"net/url"
 )
 
 const ChatGPTInitPrompt = `You are a assistant who can help users write and optimise the configurations of Nginx,
@@ -22,111 +22,111 @@ Later the language environment depends on the user message.
 The first reply should involve the key information of the file and ask user what can you help them.`
 
 func MakeChatCompletionRequest(c *gin.Context) {
-    var json struct {
-        Filepath string                         `json:"filepath"`
-        Messages []openai.ChatCompletionMessage `json:"messages"`
-    }
-
-    if !api.BindAndValid(c, &json) {
-        return
-    }
-
-    messages := []openai.ChatCompletionMessage{
-        {
-            Role:    openai.ChatMessageRoleSystem,
-            Content: ChatGPTInitPrompt,
-        },
-    }
-
-    messages = append(messages, json.Messages...)
-
-    if json.Filepath != "" {
-        messages = chatbot.ChatCompletionWithContext(json.Filepath, messages)
-    }
-
-    // SSE server
-    c.Writer.Header().Set("Content-Type", "text/event-stream; charset=utf-8")
-    c.Writer.Header().Set("Cache-Control", "no-cache")
-    c.Writer.Header().Set("Connection", "keep-alive")
-    c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
-
-    config := openai.DefaultConfig(settings.OpenAISettings.Token)
-
-    if settings.OpenAISettings.Proxy != "" {
-        proxyUrl, err := url.Parse(settings.OpenAISettings.Proxy)
-        if err != nil {
-            c.Stream(func(w io.Writer) bool {
-                c.SSEvent("message", gin.H{
-                    "type":    "error",
-                    "content": err.Error(),
-                })
-                return false
-            })
-            return
-        }
-        transport := &http.Transport{
-            Proxy:           http.ProxyURL(proxyUrl),
-            TLSClientConfig: &tls.Config{InsecureSkipVerify: settings.ServerSettings.InsecureSkipVerify},
-        }
-        config.HTTPClient = &http.Client{
-            Transport: transport,
-        }
-    }
-
-    if settings.OpenAISettings.BaseUrl != "" {
-        config.BaseURL = settings.OpenAISettings.BaseUrl
-    }
-
-    openaiClient := openai.NewClientWithConfig(config)
-    ctx := context.Background()
-
-    req := openai.ChatCompletionRequest{
-        Model:    settings.OpenAISettings.Model,
-        Messages: messages,
-        Stream:   true,
-    }
-    stream, err := openaiClient.CreateChatCompletionStream(ctx, req)
-    if err != nil {
-        fmt.Printf("CompletionStream error: %v\n", err)
-        c.Stream(func(w io.Writer) bool {
-            c.SSEvent("message", gin.H{
-                "type":    "error",
-                "content": err.Error(),
-            })
-            return false
-        })
-        return
-    }
-    defer stream.Close()
-    msgChan := make(chan string)
-    go func() {
-        defer close(msgChan)
-        for {
-            response, err := stream.Recv()
-            if errors.Is(err, io.EOF) {
-                fmt.Println()
-                return
-            }
-
-            if err != nil {
-                fmt.Printf("Stream error: %v\n", err)
-                return
-            }
-
-            message := fmt.Sprintf("%s", response.Choices[0].Delta.Content)
-
-            msgChan <- message
-        }
-    }()
-
-    c.Stream(func(w io.Writer) bool {
-        if m, ok := <-msgChan; ok {
-            c.SSEvent("message", gin.H{
-                "type":    "message",
-                "content": m,
-            })
-            return true
-        }
-        return false
-    })
+	var json struct {
+		Filepath string                         `json:"filepath"`
+		Messages []openai.ChatCompletionMessage `json:"messages"`
+	}
+
+	if !api.BindAndValid(c, &json) {
+		return
+	}
+
+	messages := []openai.ChatCompletionMessage{
+		{
+			Role:    openai.ChatMessageRoleSystem,
+			Content: ChatGPTInitPrompt,
+		},
+	}
+
+	messages = append(messages, json.Messages...)
+
+	if json.Filepath != "" {
+		messages = chatbot.ChatCompletionWithContext(json.Filepath, messages)
+	}
+
+	// SSE server
+	c.Writer.Header().Set("Content-Type", "text/event-stream; charset=utf-8")
+	c.Writer.Header().Set("Cache-Control", "no-cache")
+	c.Writer.Header().Set("Connection", "keep-alive")
+	c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
+
+	config := openai.DefaultConfig(settings.OpenAISettings.Token)
+
+	if settings.OpenAISettings.Proxy != "" {
+		proxyUrl, err := url.Parse(settings.OpenAISettings.Proxy)
+		if err != nil {
+			c.Stream(func(w io.Writer) bool {
+				c.SSEvent("message", gin.H{
+					"type":    "error",
+					"content": err.Error(),
+				})
+				return false
+			})
+			return
+		}
+		transport := &http.Transport{
+			Proxy:           http.ProxyURL(proxyUrl),
+			TLSClientConfig: &tls.Config{InsecureSkipVerify: settings.ServerSettings.InsecureSkipVerify},
+		}
+		config.HTTPClient = &http.Client{
+			Transport: transport,
+		}
+	}
+
+	if settings.OpenAISettings.BaseUrl != "" {
+		config.BaseURL = settings.OpenAISettings.BaseUrl
+	}
+
+	openaiClient := openai.NewClientWithConfig(config)
+	ctx := context.Background()
+
+	req := openai.ChatCompletionRequest{
+		Model:    settings.OpenAISettings.Model,
+		Messages: messages,
+		Stream:   true,
+	}
+	stream, err := openaiClient.CreateChatCompletionStream(ctx, req)
+	if err != nil {
+		fmt.Printf("CompletionStream error: %v\n", err)
+		c.Stream(func(w io.Writer) bool {
+			c.SSEvent("message", gin.H{
+				"type":    "error",
+				"content": err.Error(),
+			})
+			return false
+		})
+		return
+	}
+	defer stream.Close()
+	msgChan := make(chan string)
+	go func() {
+		defer close(msgChan)
+		for {
+			response, err := stream.Recv()
+			if errors.Is(err, io.EOF) {
+				fmt.Println()
+				return
+			}
+
+			if err != nil {
+				fmt.Printf("Stream error: %v\n", err)
+				return
+			}
+
+			message := fmt.Sprintf("%s", response.Choices[0].Delta.Content)
+
+			msgChan <- message
+		}
+	}()
+
+	c.Stream(func(w io.Writer) bool {
+		if m, ok := <-msgChan; ok {
+			c.SSEvent("message", gin.H{
+				"type":    "message",
+				"content": m,
+			})
+			return true
+		}
+		return false
+	})
 }

+ 7 - 0
docs/guide/config-server.md

@@ -145,3 +145,10 @@ Nginx UI will not create a system initial acme user, this means you can't apply
 - Type: `string`
 
 Use this option to customize the name of local server to be displayed in the environment indicator.
+
+## InsecureSkipVerify
+
+- Version:`>= v2.0.0-beta.30`
+- Type: `bool`
+
+This option is used to skip the verification of the certificate of servers when Nginx UI sends requests to them.

+ 19 - 18
docs/guide/env.md

@@ -3,24 +3,25 @@ Applicable for version v2.0.0-beta.23 and above.
 
 ## Server
 
-| Configuration Setting         | Environment Variable                  |
-| ----------------------------- | ------------------------------------- |
-| HttpPort                      | NGINX_UI_SERVER_HTTP_PORT             |
-| RunMode                       | NGINX_UI_SERVER_RUN_MODE              |
-| JwtSecret                     | NGINX_UI_SERVER_JWT_SECRET            |
-| HTTPChallengePort             | NGINX_UI_SERVER_HTTP_CHALLENGE_PORT   |
-| StartCmd                      | NGINX_UI_SERVER_START_CMD             |
-| Database                      | NGINX_UI_SERVER_DATABASE              |
-| CADir                         | NGINX_UI_SERVER_CA_DIR                |
-| GithubProxy                   | NGINX_UI_SERVER_GITHUB_PROXY          |
-| NodeSecret                    | NGINX_UI_SERVER_NODE_SECRET           |
-| Demo                          | NGINX_UI_SERVER_DEMO                  |
-| PageSize                      | NGINX_UI_SERVER_PAGE_SIZE             |
-| HttpHost                      | NGINX_UI_SERVER_HTTP_HOST             |
-| CertRenewalInterval           | NGINX_UI_SERVER_CERT_RENEWAL_INTERVAL |
-| RecursiveNameservers          | NGINX_UI_SERVER_RECURSIVE_NAMESERVERS |
-| SkipInstallation              | NGINX_UI_SERVER_SKIP_INSTALLATION     |
-| Name                          | NGINX_UI_SERVER_NAME                  |
+| Configuration Setting | Environment Variable                  |
+|-----------------------|---------------------------------------|
+| HttpPort              | NGINX_UI_SERVER_HTTP_PORT             |
+| RunMode               | NGINX_UI_SERVER_RUN_MODE              |
+| JwtSecret             | NGINX_UI_SERVER_JWT_SECRET            |
+| HTTPChallengePort     | NGINX_UI_SERVER_HTTP_CHALLENGE_PORT   |
+| StartCmd              | NGINX_UI_SERVER_START_CMD             |
+| Database              | NGINX_UI_SERVER_DATABASE              |
+| CADir                 | NGINX_UI_SERVER_CA_DIR                |
+| GithubProxy           | NGINX_UI_SERVER_GITHUB_PROXY          |
+| NodeSecret            | NGINX_UI_SERVER_NODE_SECRET           |
+| Demo                  | NGINX_UI_SERVER_DEMO                  |
+| PageSize              | NGINX_UI_SERVER_PAGE_SIZE             |
+| HttpHost              | NGINX_UI_SERVER_HTTP_HOST             |
+| CertRenewalInterval   | NGINX_UI_SERVER_CERT_RENEWAL_INTERVAL |
+| RecursiveNameservers  | NGINX_UI_SERVER_RECURSIVE_NAMESERVERS |
+| SkipInstallation      | NGINX_UI_SERVER_SKIP_INSTALLATION     |
+| Name                  | NGINX_UI_SERVER_NAME                  |
+| InsecureSkipVerify    | NGINX_UI_SERVER_INSECURE_SKIP_VERIFY  |
 
 ## Nginx
 

+ 7 - 0
docs/zh_CN/guide/config-server.md

@@ -132,3 +132,10 @@ Nginx UI 将不会创建系统初始的 acme 用户,这意味着您无法在
 - 类型:`string`
 
 使用此选项自定义本地服务器的名称,以在环境指示器中显示。
+
+## InsecureSkipVerify
+
+- 版本:`>= v2.0.0-beta.30`
+- 类型: `bool`
+
+此选项用于配置 Nginx UI 服务器在与其他服务器建立 TLS 连接时是否跳过证书验证。

+ 19 - 18
docs/zh_CN/guide/env.md

@@ -3,24 +3,25 @@
 
 ## Server
 
-| Configuration Setting         | Environment Variable                  |
-| ----------------------------- | ------------------------------------- |
-| HttpPort                      | NGINX_UI_SERVER_HTTP_PORT             |
-| RunMode                       | NGINX_UI_SERVER_RUN_MODE              |
-| JwtSecret                     | NGINX_UI_SERVER_JWT_SECRET            |
-| HTTPChallengePort             | NGINX_UI_SERVER_HTTP_CHALLENGE_PORT   |
-| StartCmd                      | NGINX_UI_SERVER_START_CMD             |
-| Database                      | NGINX_UI_SERVER_DATABASE              |
-| CADir                         | NGINX_UI_SERVER_CA_DIR                |
-| GithubProxy                   | NGINX_UI_SERVER_GITHUB_PROXY          |
-| NodeSecret                    | NGINX_UI_SERVER_NODE_SECRET           |
-| Demo                          | NGINX_UI_SERVER_DEMO                  |
-| PageSize                      | NGINX_UI_SERVER_PAGE_SIZE             |
-| HttpHost                      | NGINX_UI_SERVER_HTTP_HOST             |
-| CertRenewalInterval           | NGINX_UI_SERVER_CERT_RENEWAL_INTERVAL |
-| RecursiveNameservers          | NGINX_UI_SERVER_RECURSIVE_NAMESERVERS |
-| SkipInstallation              | NGINX_UI_SERVER_SKIP_INSTALLATION     |
-| Name                          | NGINX_UI_SERVER_NAME                  |
+| Configuration Setting   | Environment Variable                  |
+|-------------------------| ------------------------------------- |
+| HttpPort                | NGINX_UI_SERVER_HTTP_PORT             |
+| RunMode                 | NGINX_UI_SERVER_RUN_MODE              |
+| JwtSecret               | NGINX_UI_SERVER_JWT_SECRET            |
+| HTTPChallengePort       | NGINX_UI_SERVER_HTTP_CHALLENGE_PORT   |
+| StartCmd                | NGINX_UI_SERVER_START_CMD             |
+| Database                | NGINX_UI_SERVER_DATABASE              |
+| CADir                   | NGINX_UI_SERVER_CA_DIR                |
+| GithubProxy             | NGINX_UI_SERVER_GITHUB_PROXY          |
+| NodeSecret              | NGINX_UI_SERVER_NODE_SECRET           |
+| Demo                    | NGINX_UI_SERVER_DEMO                  |
+| PageSize                | NGINX_UI_SERVER_PAGE_SIZE             |
+| HttpHost                | NGINX_UI_SERVER_HTTP_HOST             |
+| CertRenewalInterval     | NGINX_UI_SERVER_CERT_RENEWAL_INTERVAL |
+| RecursiveNameservers    | NGINX_UI_SERVER_RECURSIVE_NAMESERVERS |
+| SkipInstallation        | NGINX_UI_SERVER_SKIP_INSTALLATION     |
+| Name                    | NGINX_UI_SERVER_NAME                  |
+| InsecureSkipVerify      | NGINX_UI_SERVER_INSECURE_SKIP_VERIFY  |
 
 ## Nginx
 

+ 7 - 0
docs/zh_TW/guide/config-server.md

@@ -133,3 +133,10 @@ Nginx UI 將不會創建系統初始的 acme 使用者,這意味著您無法
 - 類型:`string`
 
 使用此選項自定義本地伺服器的名稱,以在環境指示器中顯示。
+
+## InsecureSkipVerify
+
+- 版本:`>= v2.0.0-beta.30`
+- 類型: `bool`
+
+此選項用於配置 Nginx UI 伺服器在與其他伺服器建立 TLS 連接時是否跳過證書驗證。

+ 19 - 18
docs/zh_TW/guide/env.md

@@ -3,24 +3,25 @@
 
 ## Server
 
-| Configuration Setting         | Environment Variable                  |
-| ----------------------------- | ------------------------------------- |
-| HttpPort                      | NGINX_UI_SERVER_HTTP_PORT             |
-| RunMode                       | NGINX_UI_SERVER_RUN_MODE              |
-| JwtSecret                     | NGINX_UI_SERVER_JWT_SECRET            |
-| HTTPChallengePort             | NGINX_UI_SERVER_HTTP_CHALLENGE_PORT   |
-| StartCmd                      | NGINX_UI_SERVER_START_CMD             |
-| Database                      | NGINX_UI_SERVER_DATABASE              |
-| CADir                         | NGINX_UI_SERVER_CA_DIR                |
-| GithubProxy                   | NGINX_UI_SERVER_GITHUB_PROXY          |
-| NodeSecret                    | NGINX_UI_SERVER_NODE_SECRET           |
-| Demo                          | NGINX_UI_SERVER_DEMO                  |
-| PageSize                      | NGINX_UI_SERVER_PAGE_SIZE             |
-| HttpHost                      | NGINX_UI_SERVER_HTTP_HOST             |
-| CertRenewalInterval           | NGINX_UI_SERVER_CERT_RENEWAL_INTERVAL |
-| RecursiveNameservers          | NGINX_UI_SERVER_RECURSIVE_NAMESERVERS |
-| SkipInstallation              | NGINX_UI_SERVER_SKIP_INSTALLATION     |
-| Name                          | NGINX_UI_SERVER_NAME                  |
+| Configuration Setting  | Environment Variable                  |
+|------------------------| ------------------------------------- |
+| HttpPort               | NGINX_UI_SERVER_HTTP_PORT             |
+| RunMode                | NGINX_UI_SERVER_RUN_MODE              |
+| JwtSecret              | NGINX_UI_SERVER_JWT_SECRET            |
+| HTTPChallengePort      | NGINX_UI_SERVER_HTTP_CHALLENGE_PORT   |
+| StartCmd               | NGINX_UI_SERVER_START_CMD             |
+| Database               | NGINX_UI_SERVER_DATABASE              |
+| CADir                  | NGINX_UI_SERVER_CA_DIR                |
+| GithubProxy            | NGINX_UI_SERVER_GITHUB_PROXY          |
+| NodeSecret             | NGINX_UI_SERVER_NODE_SECRET           |
+| Demo                   | NGINX_UI_SERVER_DEMO                  |
+| PageSize               | NGINX_UI_SERVER_PAGE_SIZE             |
+| HttpHost               | NGINX_UI_SERVER_HTTP_HOST             |
+| CertRenewalInterval    | NGINX_UI_SERVER_CERT_RENEWAL_INTERVAL |
+| RecursiveNameservers   | NGINX_UI_SERVER_RECURSIVE_NAMESERVERS |
+| SkipInstallation       | NGINX_UI_SERVER_SKIP_INSTALLATION     |
+| Name                   | NGINX_UI_SERVER_NAME                  |
+| InsecureSkipVerify     | NGINX_UI_SERVER_INSECURE_SKIP_VERIFY  |
 
 ## Nginx
 

+ 82 - 82
internal/analytic/node.go

@@ -1,44 +1,44 @@
 package analytic
 
 import (
-    "crypto/tls"
-    "encoding/json"
-    "github.com/0xJacky/Nginx-UI/internal/logger"
-    "github.com/0xJacky/Nginx-UI/internal/upgrader"
-    "github.com/0xJacky/Nginx-UI/model"
-    "github.com/0xJacky/Nginx-UI/settings"
-    "github.com/shirou/gopsutil/v3/load"
-    "github.com/shirou/gopsutil/v3/net"
-    "io"
-    "net/http"
-    "net/url"
-    "sync"
-    "time"
+	"crypto/tls"
+	"encoding/json"
+	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/0xJacky/Nginx-UI/internal/upgrader"
+	"github.com/0xJacky/Nginx-UI/model"
+	"github.com/0xJacky/Nginx-UI/settings"
+	"github.com/shirou/gopsutil/v3/load"
+	"github.com/shirou/gopsutil/v3/net"
+	"io"
+	"net/http"
+	"net/url"
+	"sync"
+	"time"
 )
 
 type NodeInfo struct {
-    NodeRuntimeInfo upgrader.RuntimeInfo `json:"node_runtime_info"`
-    Version         string               `json:"version"`
-    CPUNum          int                  `json:"cpu_num"`
-    MemoryTotal     string               `json:"memory_total"`
-    DiskTotal       string               `json:"disk_total"`
+	NodeRuntimeInfo upgrader.RuntimeInfo `json:"node_runtime_info"`
+	Version         string               `json:"version"`
+	CPUNum          int                  `json:"cpu_num"`
+	MemoryTotal     string               `json:"memory_total"`
+	DiskTotal       string               `json:"disk_total"`
 }
 
 type NodeStat struct {
-    AvgLoad       *load.AvgStat      `json:"avg_load"`
-    CPUPercent    float64            `json:"cpu_percent"`
-    MemoryPercent float64            `json:"memory_percent"`
-    DiskPercent   float64            `json:"disk_percent"`
-    Network       net.IOCountersStat `json:"network"`
-    Status        bool               `json:"status"`
-    ResponseAt    time.Time          `json:"response_at"`
+	AvgLoad       *load.AvgStat      `json:"avg_load"`
+	CPUPercent    float64            `json:"cpu_percent"`
+	MemoryPercent float64            `json:"memory_percent"`
+	DiskPercent   float64            `json:"disk_percent"`
+	Network       net.IOCountersStat `json:"network"`
+	Status        bool               `json:"status"`
+	ResponseAt    time.Time          `json:"response_at"`
 }
 
 type Node struct {
-    EnvironmentID int `json:"environment_id,omitempty"`
-    *model.Environment
-    NodeStat
-    NodeInfo
+	EnvironmentID int `json:"environment_id,omitempty"`
+	*model.Environment
+	NodeStat
+	NodeInfo
 }
 
 var mutex sync.Mutex
@@ -48,74 +48,74 @@ type TNodeMap map[int]*Node
 var NodeMap TNodeMap
 
 func init() {
-    NodeMap = make(TNodeMap)
+	NodeMap = make(TNodeMap)
 }
 
 func GetNode(env *model.Environment) (n *Node) {
-    if env == nil {
-        // this should never happen
-        logger.Error("env is nil")
-        return
-    }
-    if !env.Enabled {
-        return &Node{
-            Environment: env,
-        }
-    }
-    n, ok := NodeMap[env.ID]
-    if !ok {
-        n = &Node{}
-    }
-    n.Environment = env
-    return n
+	if env == nil {
+		// this should never happen
+		logger.Error("env is nil")
+		return
+	}
+	if !env.Enabled {
+		return &Node{
+			Environment: env,
+		}
+	}
+	n, ok := NodeMap[env.ID]
+	if !ok {
+		n = &Node{}
+	}
+	n.Environment = env
+	return n
 }
 
 func InitNode(env *model.Environment) (n *Node) {
-    n = &Node{
-        Environment: env,
-    }
+	n = &Node{
+		Environment: env,
+	}
 
-    u, err := url.JoinPath(env.URL, "/api/node")
+	u, err := url.JoinPath(env.URL, "/api/node")
 
-    if err != nil {
-        logger.Error(err)
-        return
-    }
+	if err != nil {
+		logger.Error(err)
+		return
+	}
 
-    client := http.Client{
-        Transport: &http.Transport{
-            TLSClientConfig: &tls.Config{InsecureSkipVerify: settings.ServerSettings.InsecureSkipVerify},
-        },
-    }
+	client := http.Client{
+		Transport: &http.Transport{
+			TLSClientConfig: &tls.Config{InsecureSkipVerify: settings.ServerSettings.InsecureSkipVerify},
+		},
+	}
 
-    req, err := http.NewRequest("GET", u, nil)
-    if err != nil {
-        logger.Error(err)
-        return
-    }
+	req, err := http.NewRequest("GET", u, nil)
+	if err != nil {
+		logger.Error(err)
+		return
+	}
 
-    req.Header.Set("X-Node-Secret", env.Token)
+	req.Header.Set("X-Node-Secret", env.Token)
 
-    resp, err := client.Do(req)
+	resp, err := client.Do(req)
 
-    if err != nil {
-        logger.Error(err)
-        return
-    }
+	if err != nil {
+		logger.Error(err)
+		return
+	}
 
-    defer resp.Body.Close()
-    bytes, _ := io.ReadAll(resp.Body)
+	defer resp.Body.Close()
+	bytes, _ := io.ReadAll(resp.Body)
 
-    if resp.StatusCode != http.StatusOK {
-        logger.Error(string(bytes))
-        return
-    }
+	if resp.StatusCode != http.StatusOK {
+		logger.Error(string(bytes))
+		return
+	}
 
-    err = json.Unmarshal(bytes, &n.NodeInfo)
-    if err != nil {
-        logger.Error(err)
-        return
-    }
+	err = json.Unmarshal(bytes, &n.NodeInfo)
+	if err != nil {
+		logger.Error(err)
+		return
+	}
 
-    return
+	return
 }

+ 230 - 230
internal/config/sync.go

@@ -1,258 +1,258 @@
 package config
 
 import (
-    "bytes"
-    "crypto/tls"
-    "encoding/json"
-    "fmt"
-    "github.com/0xJacky/Nginx-UI/internal/helper"
-    "github.com/0xJacky/Nginx-UI/internal/logger"
-    "github.com/0xJacky/Nginx-UI/internal/nginx"
-    "github.com/0xJacky/Nginx-UI/internal/notification"
-    "github.com/0xJacky/Nginx-UI/model"
-    "github.com/0xJacky/Nginx-UI/query"
-    "github.com/0xJacky/Nginx-UI/settings"
-    "github.com/gin-gonic/gin"
-    "io"
-    "net/http"
-    "os"
-    "path/filepath"
-    "strings"
+	"bytes"
+	"crypto/tls"
+	"encoding/json"
+	"fmt"
+	"github.com/0xJacky/Nginx-UI/internal/helper"
+	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/0xJacky/Nginx-UI/internal/nginx"
+	"github.com/0xJacky/Nginx-UI/internal/notification"
+	"github.com/0xJacky/Nginx-UI/model"
+	"github.com/0xJacky/Nginx-UI/query"
+	"github.com/0xJacky/Nginx-UI/settings"
+	"github.com/gin-gonic/gin"
+	"io"
+	"net/http"
+	"os"
+	"path/filepath"
+	"strings"
 )
 
 type SyncConfigPayload struct {
-    Name        string `json:"name"`
-    Filepath    string `json:"filepath"`
-    NewFilepath string `json:"new_filepath"`
-    Content     string `json:"content"`
-    Overwrite   bool   `json:"overwrite"`
+	Name        string `json:"name"`
+	Filepath    string `json:"filepath"`
+	NewFilepath string `json:"new_filepath"`
+	Content     string `json:"content"`
+	Overwrite   bool   `json:"overwrite"`
 }
 
 func SyncToRemoteServer(c *model.Config, newFilepath string) (err error) {
-    if c.Filepath == "" || len(c.SyncNodeIds) == 0 {
-        return
-    }
-
-    nginxConfPath := nginx.GetConfPath()
-    if !helper.IsUnderDirectory(c.Filepath, nginxConfPath) {
-        return fmt.Errorf("config: %s is not under the nginx conf path: %s",
-            c.Filepath, nginxConfPath)
-    }
-
-    if newFilepath != "" && !helper.IsUnderDirectory(newFilepath, nginxConfPath) {
-        return fmt.Errorf("config: %s is not under the nginx conf path: %s",
-            c.Filepath, nginxConfPath)
-    }
-
-    currentPath := c.Filepath
-    if newFilepath != "" {
-        currentPath = newFilepath
-    }
-    configBytes, err := os.ReadFile(currentPath)
-    if err != nil {
-        return
-    }
-
-    payload := &SyncConfigPayload{
-        Name:        c.Name,
-        Filepath:    c.Filepath,
-        NewFilepath: newFilepath,
-        Content:     string(configBytes),
-        Overwrite:   c.SyncOverwrite,
-    }
-    payloadBytes, err := json.Marshal(payload)
-    if err != nil {
-        return
-    }
-
-    q := query.Environment
-    envs, _ := q.Where(q.ID.In(c.SyncNodeIds...)).Find()
-    for _, env := range envs {
-        go func() {
-            err := payload.deploy(env, c, payloadBytes)
-            if err != nil {
-                logger.Error(err)
-            }
-        }()
-    }
-
-    return
+	if c.Filepath == "" || len(c.SyncNodeIds) == 0 {
+		return
+	}
+
+	nginxConfPath := nginx.GetConfPath()
+	if !helper.IsUnderDirectory(c.Filepath, nginxConfPath) {
+		return fmt.Errorf("config: %s is not under the nginx conf path: %s",
+			c.Filepath, nginxConfPath)
+	}
+
+	if newFilepath != "" && !helper.IsUnderDirectory(newFilepath, nginxConfPath) {
+		return fmt.Errorf("config: %s is not under the nginx conf path: %s",
+			c.Filepath, nginxConfPath)
+	}
+
+	currentPath := c.Filepath
+	if newFilepath != "" {
+		currentPath = newFilepath
+	}
+	configBytes, err := os.ReadFile(currentPath)
+	if err != nil {
+		return
+	}
+
+	payload := &SyncConfigPayload{
+		Name:        c.Name,
+		Filepath:    c.Filepath,
+		NewFilepath: newFilepath,
+		Content:     string(configBytes),
+		Overwrite:   c.SyncOverwrite,
+	}
+	payloadBytes, err := json.Marshal(payload)
+	if err != nil {
+		return
+	}
+
+	q := query.Environment
+	envs, _ := q.Where(q.ID.In(c.SyncNodeIds...)).Find()
+	for _, env := range envs {
+		go func() {
+			err := payload.deploy(env, c, payloadBytes)
+			if err != nil {
+				logger.Error(err)
+			}
+		}()
+	}
+
+	return
 }
 
 func SyncRenameOnRemoteServer(origPath, newPath string, syncNodeIds []int) (err error) {
-    if origPath == "" || newPath == "" || len(syncNodeIds) == 0 {
-        return
-    }
-
-    nginxConfPath := nginx.GetConfPath()
-    if !helper.IsUnderDirectory(origPath, nginxConfPath) {
-        return fmt.Errorf("config: %s is not under the nginx conf path: %s",
-            origPath, nginxConfPath)
-    }
-
-    if !helper.IsUnderDirectory(newPath, nginxConfPath) {
-        return fmt.Errorf("config: %s is not under the nginx conf path: %s",
-            newPath, nginxConfPath)
-    }
-
-    payload := &RenameConfigPayload{
-        Filepath:    origPath,
-        NewFilepath: newPath,
-    }
-
-    q := query.Environment
-    envs, _ := q.Where(q.ID.In(syncNodeIds...)).Find()
-    for _, env := range envs {
-        go func() {
-            err := payload.rename(env)
-            if err != nil {
-                logger.Error(err)
-            }
-        }()
-    }
-
-    return
+	if origPath == "" || newPath == "" || len(syncNodeIds) == 0 {
+		return
+	}
+
+	nginxConfPath := nginx.GetConfPath()
+	if !helper.IsUnderDirectory(origPath, nginxConfPath) {
+		return fmt.Errorf("config: %s is not under the nginx conf path: %s",
+			origPath, nginxConfPath)
+	}
+
+	if !helper.IsUnderDirectory(newPath, nginxConfPath) {
+		return fmt.Errorf("config: %s is not under the nginx conf path: %s",
+			newPath, nginxConfPath)
+	}
+
+	payload := &RenameConfigPayload{
+		Filepath:    origPath,
+		NewFilepath: newPath,
+	}
+
+	q := query.Environment
+	envs, _ := q.Where(q.ID.In(syncNodeIds...)).Find()
+	for _, env := range envs {
+		go func() {
+			err := payload.rename(env)
+			if err != nil {
+				logger.Error(err)
+			}
+		}()
+	}
+
+	return
 }
 
 type SyncNotificationPayload struct {
-    StatusCode int    `json:"status_code"`
-    ConfigName string `json:"config_name"`
-    EnvName    string `json:"env_name"`
-    RespBody   string `json:"resp_body"`
+	StatusCode int    `json:"status_code"`
+	ConfigName string `json:"config_name"`
+	EnvName    string `json:"env_name"`
+	RespBody   string `json:"resp_body"`
 }
 
 func (p *SyncConfigPayload) deploy(env *model.Environment, c *model.Config, payloadBytes []byte) (err error) {
-    client := http.Client{
-        Transport: &http.Transport{
-            TLSClientConfig: &tls.Config{InsecureSkipVerify: settings.ServerSettings.InsecureSkipVerify},
-        },
-    }
-    url, err := env.GetUrl("/api/config")
-    if err != nil {
-        return
-    }
-    req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(payloadBytes))
-    if err != nil {
-        return
-    }
-    req.Header.Set("X-Node-Secret", env.Token)
-    resp, err := client.Do(req)
-    if err != nil {
-        return
-    }
-    defer resp.Body.Close()
-
-    respBody, err := io.ReadAll(resp.Body)
-    if err != nil {
-        return
-    }
-
-    notificationPayload := &SyncNotificationPayload{
-        StatusCode: resp.StatusCode,
-        ConfigName: c.Name,
-        EnvName:    env.Name,
-        RespBody:   string(respBody),
-    }
-
-    notificationPayloadBytes, err := json.Marshal(notificationPayload)
-    if err != nil {
-        return
-    }
-
-    if resp.StatusCode != http.StatusOK {
-        notification.Error("Sync Config Error", string(notificationPayloadBytes))
-        return
-    }
-
-    notification.Success("Sync Config Success", string(notificationPayloadBytes))
-
-    // handle rename
-    if p.NewFilepath == "" || p.Filepath == p.NewFilepath {
-        return
-    }
-
-    payload := &RenameConfigPayload{
-        Filepath:    p.Filepath,
-        NewFilepath: p.NewFilepath,
-    }
-
-    err = payload.rename(env)
-
-    return
+	client := http.Client{
+		Transport: &http.Transport{
+			TLSClientConfig: &tls.Config{InsecureSkipVerify: settings.ServerSettings.InsecureSkipVerify},
+		},
+	}
+	url, err := env.GetUrl("/api/config")
+	if err != nil {
+		return
+	}
+	req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(payloadBytes))
+	if err != nil {
+		return
+	}
+	req.Header.Set("X-Node-Secret", env.Token)
+	resp, err := client.Do(req)
+	if err != nil {
+		return
+	}
+	defer resp.Body.Close()
+
+	respBody, err := io.ReadAll(resp.Body)
+	if err != nil {
+		return
+	}
+
+	notificationPayload := &SyncNotificationPayload{
+		StatusCode: resp.StatusCode,
+		ConfigName: c.Name,
+		EnvName:    env.Name,
+		RespBody:   string(respBody),
+	}
+
+	notificationPayloadBytes, err := json.Marshal(notificationPayload)
+	if err != nil {
+		return
+	}
+
+	if resp.StatusCode != http.StatusOK {
+		notification.Error("Sync Config Error", string(notificationPayloadBytes))
+		return
+	}
+
+	notification.Success("Sync Config Success", string(notificationPayloadBytes))
+
+	// handle rename
+	if p.NewFilepath == "" || p.Filepath == p.NewFilepath {
+		return
+	}
+
+	payload := &RenameConfigPayload{
+		Filepath:    p.Filepath,
+		NewFilepath: p.NewFilepath,
+	}
+
+	err = payload.rename(env)
+
+	return
 }
 
 type RenameConfigPayload struct {
-    Filepath    string `json:"filepath"`
-    NewFilepath string `json:"new_filepath"`
+	Filepath    string `json:"filepath"`
+	NewFilepath string `json:"new_filepath"`
 }
 
 type SyncRenameNotificationPayload struct {
-    StatusCode int    `json:"status_code"`
-    OrigPath   string `json:"orig_path"`
-    NewPath    string `json:"new_path"`
-    EnvName    string `json:"env_name"`
-    RespBody   string `json:"resp_body"`
+	StatusCode int    `json:"status_code"`
+	OrigPath   string `json:"orig_path"`
+	NewPath    string `json:"new_path"`
+	EnvName    string `json:"env_name"`
+	RespBody   string `json:"resp_body"`
 }
 
 func (p *RenameConfigPayload) rename(env *model.Environment) (err error) {
-    // handle rename
-    if p.NewFilepath == "" || p.Filepath == p.NewFilepath {
-        return
-    }
-
-    client := http.Client{
-        Transport: &http.Transport{
-            TLSClientConfig: &tls.Config{InsecureSkipVerify: settings.ServerSettings.InsecureSkipVerify},
-        },
-    }
-
-    payloadBytes, err := json.Marshal(gin.H{
-        "base_path": strings.ReplaceAll(filepath.Dir(p.Filepath), nginx.GetConfPath(), ""),
-        "orig_name": filepath.Base(p.Filepath),
-        "new_name":  filepath.Base(p.NewFilepath),
-    })
-    if err != nil {
-        return
-    }
-    url, err := env.GetUrl("/api/config_rename")
-    if err != nil {
-        return
-    }
-    req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(payloadBytes))
-    if err != nil {
-        return
-    }
-    req.Header.Set("X-Node-Secret", env.Token)
-    resp, err := client.Do(req)
-    if err != nil {
-        return
-    }
-    defer resp.Body.Close()
-
-    respBody, err := io.ReadAll(resp.Body)
-    if err != nil {
-        return
-    }
-
-    notificationPayload := &SyncRenameNotificationPayload{
-        StatusCode: resp.StatusCode,
-        OrigPath:   p.Filepath,
-        NewPath:    p.NewFilepath,
-        EnvName:    env.Name,
-        RespBody:   string(respBody),
-    }
-
-    notificationPayloadBytes, err := json.Marshal(notificationPayload)
-    if err != nil {
-        return
-    }
-
-    if resp.StatusCode != http.StatusOK {
-        notification.Error("Rename Remote Config Error", string(notificationPayloadBytes))
-        return
-    }
-
-    notification.Success("Rename Remote Config Success", string(notificationPayloadBytes))
-
-    return
+	// handle rename
+	if p.NewFilepath == "" || p.Filepath == p.NewFilepath {
+		return
+	}
+
+	client := http.Client{
+		Transport: &http.Transport{
+			TLSClientConfig: &tls.Config{InsecureSkipVerify: settings.ServerSettings.InsecureSkipVerify},
+		},
+	}
+
+	payloadBytes, err := json.Marshal(gin.H{
+		"base_path": strings.ReplaceAll(filepath.Dir(p.Filepath), nginx.GetConfPath(), ""),
+		"orig_name": filepath.Base(p.Filepath),
+		"new_name":  filepath.Base(p.NewFilepath),
+	})
+	if err != nil {
+		return
+	}
+	url, err := env.GetUrl("/api/config_rename")
+	if err != nil {
+		return
+	}
+	req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(payloadBytes))
+	if err != nil {
+		return
+	}
+	req.Header.Set("X-Node-Secret", env.Token)
+	resp, err := client.Do(req)
+	if err != nil {
+		return
+	}
+	defer resp.Body.Close()
+
+	respBody, err := io.ReadAll(resp.Body)
+	if err != nil {
+		return
+	}
+
+	notificationPayload := &SyncRenameNotificationPayload{
+		StatusCode: resp.StatusCode,
+		OrigPath:   p.Filepath,
+		NewPath:    p.NewFilepath,
+		EnvName:    env.Name,
+		RespBody:   string(respBody),
+	}
+
+	notificationPayloadBytes, err := json.Marshal(notificationPayload)
+	if err != nil {
+		return
+	}
+
+	if resp.StatusCode != http.StatusOK {
+		notification.Error("Rename Remote Config Error", string(notificationPayloadBytes))
+		return
+	}
+
+	notification.Success("Rename Remote Config Success", string(notificationPayloadBytes))
+
+	return
 }