This commit is contained in:
2025-10-05 08:55:59 +08:00
parent c1df1f6465
commit ff1bf594a0
3 changed files with 65 additions and 9 deletions

View File

@@ -180,12 +180,15 @@ type (
) )
type ( type (
A2SQueryReq { A2SQueryReqServer {
ServerIP string `json:"serverIP"` // Server IP address ServerIP string `json:"serverIP"` // Server IP address
ServerPort int `json:"serverPort"` // Server port ServerPort int `json:"serverPort"` // Server port
Timeout int `json:"timeout,example=3000,default=3000"` // Timeout in milliseconds (default: 3000ms) Timeout int `json:"timeout,example=3000,default=3000"` // Timeout in milliseconds (default: 3000ms)
} }
A2SQueryResp { A2SQueryReq {
Servers []A2SQueryReqServer `json:"servers"` // List of servers to query
}
A2SQueryRespServer {
ServerName string `json:"serverName"` // Server name ServerName string `json:"serverName"` // Server name
MapName string `json:"mapName"` // Current map name MapName string `json:"mapName"` // Current map name
GameDirectory string `json:"gameDirectory"` // Game directory GameDirectory string `json:"gameDirectory"` // Game directory
@@ -200,6 +203,9 @@ type (
VAC int `json:"vac"` // VAC status (0 for unsecured, 1 for secured) VAC int `json:"vac"` // VAC status (0 for unsecured, 1 for secured)
Version string `json:"version"` // Server version Version string `json:"version"` // Server version
} }
A2SQueryResp {
Results []A2SQueryRespServer `json:"results"` // List of query results for each server
}
) )
@server ( @server (

View File

@@ -3,6 +3,7 @@ package logic
import ( import (
"context" "context"
"fmt" "fmt"
"sync"
"time" "time"
"src/internal/svc" "src/internal/svc"
@@ -28,6 +29,45 @@ func NewA2sQueryLogic(ctx context.Context, svcCtx *svc.ServiceContext) *A2sQuery
} }
func (l *A2sQueryLogic) A2sQuery(req *types.A2SQueryReq) (resp *types.A2SQueryResp, err error) { func (l *A2sQueryLogic) A2sQuery(req *types.A2SQueryReq) (resp *types.A2SQueryResp, err error) {
if len(req.Servers) == 0 {
return &types.A2SQueryResp{Results: []types.A2SQueryRespServer{}}, nil
}
// Channel to collect results
results := make(chan types.A2SQueryRespServer, len(req.Servers))
var wg sync.WaitGroup
// Query each server concurrently
for _, server := range req.Servers {
wg.Add(1)
go func(srv types.A2SQueryReqServer) {
defer wg.Done()
result := l.querySingleServer(srv)
results <- result
}(server)
}
// Close channel when all goroutines are done
go func() {
wg.Wait()
close(results)
}()
// Collect all results
resp = &types.A2SQueryResp{
Results: make([]types.A2SQueryRespServer, 0, len(req.Servers)),
}
for result := range results {
resp.Results = append(resp.Results, result)
}
return resp, nil
}
// querySingleServer performs A2S query for a single server
func (l *A2sQueryLogic) querySingleServer(req types.A2SQueryReqServer) types.A2SQueryRespServer {
// Set default timeout if not provided // Set default timeout if not provided
timeout := time.Duration(req.Timeout) * time.Millisecond timeout := time.Duration(req.Timeout) * time.Millisecond
if req.Timeout <= 0 { if req.Timeout <= 0 {
@@ -37,16 +77,20 @@ func (l *A2sQueryLogic) A2sQuery(req *types.A2SQueryReq) (resp *types.A2SQueryRe
// Create A2S client with timeout option // Create A2S client with timeout option
client, err := a2s.NewClient(fmt.Sprintf("%s:%d", req.ServerIP, req.ServerPort), a2s.TimeoutOption(timeout)) client, err := a2s.NewClient(fmt.Sprintf("%s:%d", req.ServerIP, req.ServerPort), a2s.TimeoutOption(timeout))
if err != nil { if err != nil {
l.Logger.Errorf("Failed to create A2S client: %v", err) l.Logger.Errorf("Failed to create A2S client for %s:%d: %v", req.ServerIP, req.ServerPort, err)
return nil, err return types.A2SQueryRespServer{
ServerName: fmt.Sprintf("Error: %v", err),
}
} }
defer client.Close() defer client.Close()
// Query server info // Query server info
info, err := client.QueryInfo() info, err := client.QueryInfo()
if err != nil { if err != nil {
l.Logger.Errorf("Failed to query server info: %v", err) l.Logger.Errorf("Failed to query server info for %s:%d: %v", req.ServerIP, req.ServerPort, err)
return nil, err return types.A2SQueryRespServer{
ServerName: fmt.Sprintf("Error: %v", err),
}
} }
// Convert boolean values to int // Convert boolean values to int
@@ -60,7 +104,7 @@ func (l *A2sQueryLogic) A2sQuery(req *types.A2SQueryReq) (resp *types.A2SQueryRe
} }
// Map response to our types // Map response to our types
resp = &types.A2SQueryResp{ return types.A2SQueryRespServer{
ServerName: info.Name, ServerName: info.Name,
MapName: info.Map, MapName: info.Map,
GameDirectory: info.Folder, GameDirectory: info.Folder,
@@ -75,6 +119,4 @@ func (l *A2sQueryLogic) A2sQuery(req *types.A2SQueryReq) (resp *types.A2SQueryRe
VAC: vac, VAC: vac,
Version: info.Version, Version: info.Version,
} }
return resp, nil
} }

View File

@@ -4,12 +4,20 @@
package types package types
type A2SQueryReq struct { type A2SQueryReq struct {
Servers []A2SQueryReqServer `json:"servers"` // List of servers to query
}
type A2SQueryReqServer struct {
ServerIP string `json:"serverIP"` // Server IP address ServerIP string `json:"serverIP"` // Server IP address
ServerPort int `json:"serverPort"` // Server port ServerPort int `json:"serverPort"` // Server port
Timeout int `json:"timeout,example=3000,default=3000"` // Timeout in milliseconds (default: 3000ms) Timeout int `json:"timeout,example=3000,default=3000"` // Timeout in milliseconds (default: 3000ms)
} }
type A2SQueryResp struct { type A2SQueryResp struct {
Results []A2SQueryRespServer `json:"results"` // List of query results for each server
}
type A2SQueryRespServer struct {
ServerName string `json:"serverName"` // Server name ServerName string `json:"serverName"` // Server name
MapName string `json:"mapName"` // Current map name MapName string `json:"mapName"` // Current map name
GameDirectory string `json:"gameDirectory"` // Game directory GameDirectory string `json:"gameDirectory"` // Game directory