diff --git a/config/config.go b/config/config.go index e1c2e84..13ec9c8 100644 --- a/config/config.go +++ b/config/config.go @@ -57,17 +57,29 @@ func LoadConfig(configPath string, getInitSystem func() string) error { return fmt.Errorf("failed to parse config file: %w", err) } - if fileConfig.ListenAddr != "" { - global.CurrentConfig.ListenAddr = fileConfig.ListenAddr + global.CurrentConfig.ListenAddr = fileConfig.ListenAddr + global.CurrentConfig.ListenPort = fileConfig.ListenPort + global.CurrentConfig.FrpcPath = fileConfig.FrpcPath + global.CurrentConfig.InstancePath = fileConfig.InstancePath + global.CurrentConfig.Debug = fileConfig.Debug + global.CurrentConfig.Watchdog.Enabled = fileConfig.Watchdog.Enabled + global.CurrentConfig.Watchdog.Port = fileConfig.Watchdog.Port + global.CurrentConfig.Notification.Enabled = fileConfig.Notification.Enabled + global.CurrentConfig.Notification.Method = fileConfig.Notification.Method + global.CurrentConfig.Webhook.Method = fileConfig.Webhook.Method + global.CurrentConfig.Webhook.URL = fileConfig.Webhook.URL + global.CurrentConfig.Webhook.Headers = fileConfig.Webhook.Headers + global.CurrentConfig.Webhook.Body = fileConfig.Webhook.Body + + if fileConfig.ListenAddr == "" { + global.CurrentConfig.ListenAddr = "0.0.0.0" } - if fileConfig.ListenPort != "" { - global.CurrentConfig.ListenPort = fileConfig.ListenPort + if fileConfig.ListenPort == "" { + global.CurrentConfig.ListenPort = "7000" } - if fileConfig.FrpcPath != "" { - global.CurrentConfig.FrpcPath = fileConfig.FrpcPath - } else { + if fileConfig.FrpcPath == "" { if getInitSystem() == "windows" { global.CurrentConfig.FrpcPath = "frp_client/frpc.exe" } else { @@ -75,22 +87,14 @@ func LoadConfig(configPath string, getInitSystem func() string) error { } } - if fileConfig.InstancePath != "" { - global.CurrentConfig.InstancePath = fileConfig.InstancePath - } else { + if fileConfig.InstancePath == "" { global.CurrentConfig.InstancePath = "./configs" } - global.CurrentConfig.Debug = fileConfig.Debug - - if fileConfig.Watchdog.Port != 0 { - global.CurrentConfig.Watchdog.Port = fileConfig.Watchdog.Port - } else { + if fileConfig.Watchdog.Port == 0 { global.CurrentConfig.Watchdog.Port = 12380 } - global.CurrentConfig.Watchdog.Enabled = fileConfig.Watchdog.Enabled - if err := os.MkdirAll(global.CurrentConfig.InstancePath, 0755); err != nil { return fmt.Errorf("failed to create config directory: %w", err) } diff --git a/global/global.go b/global/global.go index 39e3c5f..b89b840 100644 --- a/global/global.go +++ b/global/global.go @@ -51,53 +51,49 @@ type Config struct { Debug bool `json:"debug"` Watchdog struct { Enabled bool `json:"enabled"` - Port int `json:"port"` + Port int `json:"port"` } `json:"watchdog"` Notification struct { - Enabled bool `json:"enabled"` + Enabled bool `json:"enabled"` Method string `json:"method"` } `json:"notification"` Webhook struct { - Method string `json:"method"` - URL string `json:"url"` - Headers map[string]string `json:"headers"` - Body map[string]string `json:"body"` + Method string `json:"method"` + URL string `json:"url"` + Headers string `json:"headers"` + Body string `json:"body"` } `json:"webhook"` } var CurrentConfig = Config{ - ListenAddr: "0.0.0.0", - ListenPort: "7000", - FrpcPath: "", + ListenAddr: "0.0.0.0", + ListenPort: "7000", + FrpcPath: "", InstancePath: "", Debug: false, - Watchdog: struct { + Watchdog: struct { Enabled bool `json:"enabled"` - Port int `json:"port"` + Port int `json:"port"` }{ Enabled: false, - Port: 0, + Port: 0, }, Notification: struct { - Enabled bool `json:"enabled"` + Enabled bool `json:"enabled"` Method string `json:"method"` }{ Enabled: false, Method: "webhook", }, Webhook: struct { - Method string `json:"method"` - URL string `json:"url"` - Headers map[string]string `json:"headers"` - Body map[string]string `json:"body"` + Method string `json:"method"` + URL string `json:"url"` + Headers string `json:"headers"` + Body string `json:"body"` }{ Method: "", URL: "", - Headers: map[string]string{ - "Content-Type": "", - }, - Body: map[string]string{ - "text": "", - }, + Headers: "Content-Type: application/json", + Body: "", }, } diff --git a/watchdog/command.go b/watchdog/command.go index d8e96a5..b61c854 100644 --- a/watchdog/command.go +++ b/watchdog/command.go @@ -3,6 +3,7 @@ package watchdog import ( "fmt" "super-frpc/postLog" + "super-frpc/utils" ) func AddInstance(serviceName string) bool { @@ -70,4 +71,17 @@ func Close() bool { } return false +} + +func parseCommand(cmd string) (result string, err error) { + cmdType := utils.GetCmdType(cmd) + if cmdType == "Exception" { + // Watchdog msg: [Exception] ... ... ... + exceptionType := utils.GetCmdParams(cmd, "exceptionType") + serviceName := utils.GetCmdParams(cmd, "serviceName") + errorMsg := utils.GetCmdParams(cmd, "errorMsg") + postLog.Error(fmt.Sprintf("[Watchdog] Exception[%s]: %s, %s", serviceName, exceptionType, errorMsg)) + exceptionHandle(exceptionType, serviceName, errorMsg) + } + return "", nil } \ No newline at end of file diff --git a/watchdog/processor.go b/watchdog/processor.go index 19744df..c9c1326 100644 --- a/watchdog/processor.go +++ b/watchdog/processor.go @@ -1,18 +1,26 @@ package watchdog import ( + "encoding/json" "fmt" "strings" "super-frpc/global" + "super-frpc/postLog" "super-frpc/webhook" ) func exceptionHandle(exceptionType string, serviceName string, errorMsg string) { if global.CurrentConfig.Notification.Enabled { - body := make(map[string]string) - if global.CurrentConfig.Notification.Method == "Webhook" { - for k, v := range global.CurrentConfig.Webhook.Body { + if global.CurrentConfig.Notification.Method == "webhook" { + var bodyMap map[string]string + err := json.Unmarshal([]byte(global.CurrentConfig.Webhook.Body), &bodyMap) + if err != nil { + postLog.Error(fmt.Sprintf("[exceptionHandler] Failed to parse webhook body: %v", err)) + return + } + + for k, v := range bodyMap { replaced := v for strings.Contains(replaced, "{{ exceptionType }}") || strings.Contains(replaced, "{{ serviceName }}") || @@ -21,17 +29,33 @@ func exceptionHandle(exceptionType string, serviceName string, errorMsg string) replaced = strings.ReplaceAll(replaced, "{{ serviceName }}", serviceName) replaced = strings.ReplaceAll(replaced, "{{ exceptionMsg }}", errorMsg) } - body[k] = replaced + bodyMap[k] = replaced } - bodyJSON := "" - for k, v := range body { - bodyJSON = fmt.Sprintf(`{"%s": "%s"}`, k, v) - break + bodyJSON, err := json.Marshal(bodyMap) + if err != nil { + postLog.Error(fmt.Sprintf("[exceptionHandler] Failed to marshal webhook body: %v", err)) + return } - webhook.SendHook(global.CurrentConfig.Webhook.URL, global.CurrentConfig.Webhook.Method, global.CurrentConfig.Webhook.Headers, bodyJSON) + // Parse headers as map[string]string format + headersMap := make(map[string]string) + headerPairs := strings.Split(global.CurrentConfig.Webhook.Headers, ";") + for _, pair := range headerPairs { + pair = strings.TrimSpace(pair) + if pair == "" { + continue + } + parts := strings.SplitN(pair, ":", 2) + if len(parts) == 2 { + headersMap[strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1]) + } + } + + webhook.SendHook(global.CurrentConfig.Webhook.URL, global.CurrentConfig.Webhook.Method, headersMap, string(bodyJSON)) } + } else { + postLog.Warning("[exceptionHandler] exception occoured, but notification is not enabled!") } - + } diff --git a/watchdog/tcpClient.go b/watchdog/tcpClient.go index 49fee22..7387e85 100644 --- a/watchdog/tcpClient.go +++ b/watchdog/tcpClient.go @@ -5,8 +5,6 @@ import ( "fmt" "net" "strings" - "super-frpc/postLog" - "super-frpc/utils" "sync" "time" ) @@ -117,15 +115,8 @@ func recvMsg() { } // Here add logic to handle the message if !isResponseMessage(line) { - postLog.Debug(fmt.Sprintf("[Watchdog] TCP Socket received message: %s", line)) - cmdType := utils.GetCmdType(line) - if cmdType == "Exception" { - exceptionType := utils.GetCmdParams(line, "exceptionType") - serviceName := utils.GetCmdParams(line, "serviceName") - errorMsg := utils.GetCmdParams(line, "errorMsg") - postLog.Error(fmt.Sprintf("[Watchdog] Exception[%s]: %s, %s", serviceName, exceptionType, errorMsg)) - exceptionHandle(exceptionType, serviceName, errorMsg) - } + // postLog.Debug(fmt.Sprintf("[Watchdog] TCP Socket received message: %s", line)) + parseCommand(line) } } } diff --git a/webhook/webhook.go b/webhook/webhook.go index 4309cb1..32ab658 100644 --- a/webhook/webhook.go +++ b/webhook/webhook.go @@ -14,6 +14,7 @@ import ( // If the status code is not 200, it logs the error and returns the status code and response message. // If the status code is 200, it returns an empty error message, status code, and response message. func SendHook(url string, method string, headers map[string]string, body string) (err string, code int, msg string) { + postLog.Debug(fmt.Sprintf("[SendHook] SendHook { %s, %s, %s, %s }", url, method, headers, body)) req, reqErr := http.NewRequest(method, url, strings.NewReader(body)) if reqErr != nil { return reqErr.Error(), 500, "" @@ -34,6 +35,8 @@ func SendHook(url string, method string, headers map[string]string, body string) if resp.StatusCode != http.StatusOK { postLog.Debug(fmt.Sprintf("[SendHook] SendHook { %s, %s, %s, %s } failed, status code: %d, response: [%s]: %s", url, method, headers, body, resp.StatusCode, resp.Status, respMsg)) return fmt.Sprintf("unexpected status code: %d, response: [%s]: %s", resp.StatusCode, resp.Status, respMsg), resp.StatusCode, respMsg + } else { + postLog.Debug(fmt.Sprintf("[SendHook] SendHook { %s, %s, %s, %s } success, status code: %d, response: [%s]: %s", url, method, headers, body, resp.StatusCode, resp.Status, respMsg)) } return "", 200, "" }