Files
telemt-api/internal/server/radar.go
T
Denozordec d021e4b1d7
Publish telemt-api gateway Docker image / test (push) Successful in 23s
Publish telemt-api gateway Docker image / build-and-push (push) Successful in 2m9s
Add Radar DC Telegram functionality and configuration
- Introduced new `RadarConfig` structure in `config.go` to manage radar settings, including `statuses_url`, `http_timeout_ms`, and `ping_from`.
- Implemented validation for radar configuration in `config_test.go` to ensure correct URL schemes and timeout limits.
- Added new API routes for radar statuses and ping functionality in the gateway, enhancing the service's capabilities.
- Updated documentation in `GATEWAY_RUN.md` to include details about the new radar features and their usage.
- Enhanced the user interface to include navigation and display options for the Radar DC section in the sidebar and page titles.
- Added client-side API functions for fetching radar statuses and ping responses, improving integration with the frontend.
2026-04-12 12:53:20 +07:00

125 lines
3.2 KiB
Go

package server
import (
"encoding/json"
"io"
"net"
"net/http"
"strconv"
"strings"
"time"
)
const defaultRadarStatusesURL = "https://radar.telemt.top/api/v1/endpoints/statuses"
// telegramDC443 — IPv4 DC Telegram для MTProto (как в ping_proxy.php исходной панели).
var telegramDC443 = map[int]string{
1: "149.154.175.50",
2: "149.154.167.51",
3: "149.154.175.100",
4: "149.154.167.91",
5: "149.154.171.5",
}
func (g *Gateway) serveRadar(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/api/radar/statuses":
if r.Method != http.MethodGet {
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
return
}
g.serveRadarStatuses(w, r)
case "/api/radar/ping-dc":
if r.Method != http.MethodGet {
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
return
}
g.serveRadarPingDC(w, r)
default:
http.NotFound(w, r)
}
}
// serveRadarStatuses проксирует JSON radar.telemt.top (аналог radar_proxy.php).
func (g *Gateway) serveRadarStatuses(w http.ResponseWriter, r *http.Request) {
req, err := http.NewRequestWithContext(r.Context(), http.MethodGet, g.radarStatusesURL, nil)
if err != nil {
writeRadarFailed(w)
return
}
resp, err := g.radarHTTPClient.Do(req)
if err != nil {
writeRadarFailed(w)
return
}
defer resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
writeRadarFailed(w)
return
}
ct := resp.Header.Get("Content-Type")
if ct == "" {
ct = "application/json"
}
w.Header().Set("Content-Type", ct)
w.WriteHeader(http.StatusOK)
_, _ = io.Copy(w, resp.Body)
}
func writeRadarFailed(w http.ResponseWriter) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(http.StatusInternalServerError)
_ = json.NewEncoder(w).Encode(map[string]string{"error": "failed"})
}
// serveRadarPingDC — TCP :443 до каждого DC с таймаутом 2 с (аналог ping_proxy.php).
func (g *Gateway) serveRadarPingDC(w http.ResponseWriter, r *http.Request) {
from := strings.TrimSpace(g.radarPingFrom)
if from == "" {
from = hostOnly(r.Host)
if from == "" {
from = "telemt-gateway"
}
}
results := make(map[string]map[string]any, len(telegramDC443))
for i := 1; i <= 5; i++ {
ip := telegramDC443[i]
addr := net.JoinHostPort(ip, "443")
t0 := time.Now()
conn, err := net.DialTimeout("tcp", addr, 2*time.Second)
ms := int(time.Since(t0).Milliseconds())
key := strconv.Itoa(i)
if err != nil {
results[key] = map[string]any{"ok": false, "ms": nil}
continue
}
_ = conn.Close()
results[key] = map[string]any{"ok": true, "ms": ms}
}
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(http.StatusOK)
_ = json.NewEncoder(w).Encode(map[string]any{
"ok": true,
"results": results,
"from": from,
})
}
func hostOnly(hostPort string) string {
hostPort = strings.TrimSpace(hostPort)
if hostPort == "" {
return ""
}
// IPv6 в квадратных скобках: [::1]:8080
if strings.HasPrefix(hostPort, "[") {
if i := strings.IndexByte(hostPort, ']'); i > 0 {
return hostPort[1:i]
}
}
h, _, err := net.SplitHostPort(hostPort)
if err != nil {
return hostPort
}
return h
}