mirror of
https://github.com/langhuihui/monibuca.git
synced 2025-10-06 09:22:44 +08:00
220 lines
6.8 KiB
Go
220 lines
6.8 KiB
Go
package plugin_debug
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net"
|
|
"net/http"
|
|
"net/url"
|
|
"time"
|
|
|
|
"google.golang.org/protobuf/types/known/timestamppb"
|
|
"gopkg.in/yaml.v3"
|
|
"m7s.live/v5/pb"
|
|
"m7s.live/v5/pkg/util"
|
|
)
|
|
|
|
type EnvCheckResult struct {
|
|
Message string `json:"message"`
|
|
Type string `json:"type"` // info, success, error, complete
|
|
}
|
|
|
|
// 自定义系统信息响应结构体,用于 JSON 解析
|
|
type SysInfoResponseJSON struct {
|
|
Code int32 `json:"code"`
|
|
Message string `json:"message"`
|
|
Data struct {
|
|
StartTime string `json:"startTime"`
|
|
LocalIP string `json:"localIP"`
|
|
PublicIP string `json:"publicIP"`
|
|
Version string `json:"version"`
|
|
GoVersion string `json:"goVersion"`
|
|
OS string `json:"os"`
|
|
Arch string `json:"arch"`
|
|
CPUs int32 `json:"cpus"`
|
|
Plugins []struct {
|
|
Name string `json:"name"`
|
|
PushAddr []string `json:"pushAddr"`
|
|
PlayAddr []string `json:"playAddr"`
|
|
Description map[string]string `json:"description"`
|
|
} `json:"plugins"`
|
|
} `json:"data"`
|
|
}
|
|
|
|
// 插件配置响应结构体
|
|
type PluginConfigResponse struct {
|
|
Code int32 `json:"code"`
|
|
Message string `json:"message"`
|
|
Data struct {
|
|
File string `json:"file"`
|
|
Modified string `json:"modified"`
|
|
Merged string `json:"merged"`
|
|
} `json:"data"`
|
|
}
|
|
|
|
// TCP 配置结构体
|
|
type TCPConfig struct {
|
|
ListenAddr string `yaml:"listenaddr"`
|
|
ListenAddrTLS string `yaml:"listenaddrtls"`
|
|
}
|
|
|
|
// 插件配置结构体
|
|
type PluginConfig struct {
|
|
TCP TCPConfig `yaml:"tcp"`
|
|
}
|
|
|
|
func (p *DebugPlugin) EnvCheck(w http.ResponseWriter, r *http.Request) {
|
|
// Get target URL from query parameter
|
|
targetURL := r.URL.Query().Get("target")
|
|
if targetURL == "" {
|
|
r.URL.Path = "/static/envcheck.html"
|
|
staticFSHandler.ServeHTTP(w, r)
|
|
return
|
|
}
|
|
|
|
// Create SSE connection
|
|
util.NewSSE(w, r.Context(), func(sse *util.SSE) {
|
|
// Function to send SSE messages
|
|
sendMessage := func(message string, msgType string) {
|
|
result := EnvCheckResult{
|
|
Message: message,
|
|
Type: msgType,
|
|
}
|
|
sse.WriteJSON(result)
|
|
}
|
|
|
|
// Parse target URL
|
|
_, err := url.Parse(targetURL)
|
|
if err != nil {
|
|
sendMessage(fmt.Sprintf("Invalid URL: %v", err), "error")
|
|
return
|
|
}
|
|
|
|
// Check if we can connect to the target server
|
|
sendMessage(fmt.Sprintf("Checking connection to %s...", targetURL), "info")
|
|
|
|
// Get system info from target server
|
|
resp, err := http.Get(fmt.Sprintf("%s/api/sysinfo", targetURL))
|
|
if err != nil {
|
|
sendMessage(fmt.Sprintf("Failed to connect to target server: %v", err), "error")
|
|
return
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
sendMessage(fmt.Sprintf("Target server returned status code: %d", resp.StatusCode), "error")
|
|
return
|
|
}
|
|
|
|
// Read and parse system info
|
|
body, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
sendMessage(fmt.Sprintf("Failed to read response: %v", err), "error")
|
|
return
|
|
}
|
|
|
|
var sysInfoJSON SysInfoResponseJSON
|
|
if err := json.Unmarshal(body, &sysInfoJSON); err != nil {
|
|
sendMessage(fmt.Sprintf("Failed to parse system info: %v", err), "error")
|
|
return
|
|
}
|
|
|
|
// Convert JSON response to protobuf response
|
|
sysInfo := &pb.SysInfoResponse{
|
|
Code: sysInfoJSON.Code,
|
|
Message: sysInfoJSON.Message,
|
|
Data: &pb.SysInfoData{
|
|
LocalIP: sysInfoJSON.Data.LocalIP,
|
|
PublicIP: sysInfoJSON.Data.PublicIP,
|
|
Version: sysInfoJSON.Data.Version,
|
|
GoVersion: sysInfoJSON.Data.GoVersion,
|
|
Os: sysInfoJSON.Data.OS,
|
|
Arch: sysInfoJSON.Data.Arch,
|
|
Cpus: sysInfoJSON.Data.CPUs,
|
|
},
|
|
}
|
|
|
|
// Parse start time
|
|
if startTime, err := time.Parse(time.RFC3339, sysInfoJSON.Data.StartTime); err == nil {
|
|
sysInfo.Data.StartTime = timestamppb.New(startTime)
|
|
}
|
|
|
|
// Convert plugins
|
|
for _, pluginJSON := range sysInfoJSON.Data.Plugins {
|
|
plugin := &pb.PluginInfo{
|
|
Name: pluginJSON.Name,
|
|
PushAddr: pluginJSON.PushAddr,
|
|
PlayAddr: pluginJSON.PlayAddr,
|
|
Description: pluginJSON.Description,
|
|
}
|
|
sysInfo.Data.Plugins = append(sysInfo.Data.Plugins, plugin)
|
|
}
|
|
|
|
// Check each plugin's configuration
|
|
for _, plugin := range sysInfo.Data.Plugins {
|
|
// Get plugin configuration
|
|
configResp, err := http.Get(fmt.Sprintf("%s/api/config/get/%s", targetURL, plugin.Name))
|
|
if err != nil {
|
|
sendMessage(fmt.Sprintf("Failed to get configuration for plugin %s: %v", plugin.Name, err), "error")
|
|
continue
|
|
}
|
|
defer configResp.Body.Close()
|
|
|
|
if configResp.StatusCode != http.StatusOK {
|
|
sendMessage(fmt.Sprintf("Failed to get configuration for plugin %s: status code %d", plugin.Name, configResp.StatusCode), "error")
|
|
continue
|
|
}
|
|
|
|
var configRespJSON PluginConfigResponse
|
|
if err := json.NewDecoder(configResp.Body).Decode(&configRespJSON); err != nil {
|
|
sendMessage(fmt.Sprintf("Failed to parse configuration for plugin %s: %v", plugin.Name, err), "error")
|
|
continue
|
|
}
|
|
|
|
// Parse YAML configuration
|
|
var config PluginConfig
|
|
if err := yaml.Unmarshal([]byte(configRespJSON.Data.Merged), &config); err != nil {
|
|
sendMessage(fmt.Sprintf("Failed to parse YAML configuration for plugin %s: %v", plugin.Name, err), "error")
|
|
continue
|
|
}
|
|
// Check TCP configuration
|
|
if config.TCP.ListenAddr != "" {
|
|
host, port, err := net.SplitHostPort(config.TCP.ListenAddr)
|
|
if err != nil {
|
|
sendMessage(fmt.Sprintf("Invalid listenaddr format for plugin %s: %v", plugin.Name, err), "error")
|
|
} else {
|
|
sendMessage(fmt.Sprintf("Checking TCP listenaddr %s for plugin %s...", config.TCP.ListenAddr, plugin.Name), "info")
|
|
// Try to establish TCP connection
|
|
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%s", host, port), 5*time.Second)
|
|
if err != nil {
|
|
sendMessage(fmt.Sprintf("TCP listenaddr %s for plugin %s is not accessible: %v", config.TCP.ListenAddr, plugin.Name, err), "error")
|
|
} else {
|
|
conn.Close()
|
|
sendMessage(fmt.Sprintf("TCP listenaddr %s for plugin %s is accessible", config.TCP.ListenAddr, plugin.Name), "success")
|
|
}
|
|
}
|
|
}
|
|
|
|
if config.TCP.ListenAddrTLS != "" {
|
|
host, port, err := net.SplitHostPort(config.TCP.ListenAddrTLS)
|
|
if err != nil {
|
|
sendMessage(fmt.Sprintf("Invalid listenaddrtls format for plugin %s: %v", plugin.Name, err), "error")
|
|
} else {
|
|
sendMessage(fmt.Sprintf("Checking TCP TLS listenaddr %s for plugin %s...", config.TCP.ListenAddrTLS, plugin.Name), "info")
|
|
// Try to establish TCP connection
|
|
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%s", host, port), 5*time.Second)
|
|
if err != nil {
|
|
sendMessage(fmt.Sprintf("TCP TLS listenaddr %s for plugin %s is not accessible: %v", config.TCP.ListenAddrTLS, plugin.Name, err), "error")
|
|
} else {
|
|
conn.Close()
|
|
sendMessage(fmt.Sprintf("TCP TLS listenaddr %s for plugin %s is accessible", config.TCP.ListenAddrTLS, plugin.Name), "success")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
sendMessage("Environment check completed", "complete")
|
|
})
|
|
}
|