package api import ( "bufio" "bytes" "fmt" "io" "net" "net/http" "os/exec" "runtime" "strconv" "strings" "time" "github.com/labstack/echo/v4" "golang.org/x/text/encoding/simplifiedchinese" "golang.org/x/text/transform" ) type ToolsApi struct{} func (api ToolsApi) TcpingEndpoint(c echo.Context) error { host := c.QueryParam("host") port := c.QueryParam("port") attemptsStr := c.QueryParam("attempts") attempts := 4 if attemptsStr != "" { attempts, _ = strconv.Atoi(attemptsStr) } c.Response().Header().Set("Content-Type", "text/event-stream") c.Response().Header().Set("Cache-Control", "no-cache") c.Response().Header().Set("Connection", "keep-alive") flusher, ok := c.Response().Writer.(http.Flusher) if !ok { return echo.NewHTTPError(500, "Streaming unsupported") } for i := 0; i < attempts; i++ { start := time.Now() conn, err := net.DialTimeout("tcp", host+":"+port, 5*time.Second) elapsed := time.Since(start) var result string if err != nil { result = fmt.Sprintf("TCP ping %s:%s - Failed: %v", host, port, err) } else { conn.Close() result = fmt.Sprintf("TCP ping %s:%s - Connected, time=%v", host, port, elapsed.Round(time.Millisecond)) } fmt.Fprintf(c.Response(), "data: %s\n\n", result) flusher.Flush() if i < attempts-1 { time.Sleep(1 * time.Second) } } fmt.Fprintf(c.Response(), "event: done\ndata: completed\n\n") flusher.Flush() return nil } func (api ToolsApi) PingEndpoint(c echo.Context) error { host := c.QueryParam("host") attemptsStr := c.QueryParam("attempts") attempts := 4 if attemptsStr != "" { attempts, _ = strconv.Atoi(attemptsStr) } c.Response().Header().Set("Content-Type", "text/event-stream") c.Response().Header().Set("Cache-Control", "no-cache") c.Response().Header().Set("Connection", "keep-alive") flusher, ok := c.Response().Writer.(http.Flusher) if !ok { return echo.NewHTTPError(500, "Streaming unsupported") } var cmd *exec.Cmd if runtime.GOOS == "windows" { cmd = exec.Command("ping", "-n", strconv.Itoa(attempts), host) } else { cmd = exec.Command("ping", "-c", strconv.Itoa(attempts), host) } stdout, err := cmd.StdoutPipe() if err != nil { fmt.Fprintf(c.Response(), "data: Error: %v\n\n", err) flusher.Flush() return nil } if err := cmd.Start(); err != nil { fmt.Fprintf(c.Response(), "data: Error: %v\n\n", err) flusher.Flush() return nil } var reader io.Reader = stdout if runtime.GOOS == "windows" { reader = transform.NewReader(stdout, simplifiedchinese.GBK.NewDecoder()) } scanner := bufio.NewScanner(reader) for scanner.Scan() { line := scanner.Text() if strings.TrimSpace(line) != "" { fmt.Fprintf(c.Response(), "data: %s\n\n", line) flusher.Flush() } } _ = cmd.Wait() fmt.Fprintf(c.Response(), "event: done\ndata: completed\n\n") flusher.Flush() return nil } func (api ToolsApi) TelnetEndpoint(c echo.Context) error { host := c.QueryParam("host") port := c.QueryParam("port") c.Response().Header().Set("Content-Type", "text/event-stream") c.Response().Header().Set("Cache-Control", "no-cache") c.Response().Header().Set("Connection", "keep-alive") flusher, ok := c.Response().Writer.(http.Flusher) if !ok { return echo.NewHTTPError(500, "Streaming unsupported") } start := time.Now() conn, err := net.DialTimeout("tcp", host+":"+port, 10*time.Second) elapsed := time.Since(start) var result bytes.Buffer if err != nil { result.WriteString(fmt.Sprintf("Telnet %s:%s - Connection failed: %v", host, port, err)) } else { conn.Close() result.WriteString(fmt.Sprintf("Telnet %s:%s - Connected successfully in %v", host, port, elapsed.Round(time.Millisecond))) } fmt.Fprintf(c.Response(), "data: %s\n\n", result.String()) flusher.Flush() fmt.Fprintf(c.Response(), "event: done\ndata: completed\n\n") flusher.Flush() return nil }