修复token过期重复调用接口
This commit is contained in:
@@ -138,7 +138,9 @@ func (c *Client) runWebSocket(ctx context.Context) {
|
||||
defer c.wg.Done()
|
||||
|
||||
maxConsecutiveFailures := 5
|
||||
maxAuthFailures := 10
|
||||
consecutiveFailures := 0
|
||||
authFailures := 0
|
||||
|
||||
for {
|
||||
select {
|
||||
@@ -156,8 +158,31 @@ func (c *Client) runWebSocket(ctx context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// Check if this is an authentication error
|
||||
if authErr, ok := err.(*AuthError); ok {
|
||||
authFailures++
|
||||
if authErr.IsTokenInvalid() {
|
||||
log.Printf("[Agent] Authentication failed (invalid token): %v", err)
|
||||
if authFailures >= maxAuthFailures {
|
||||
log.Printf("[Agent] Too many auth failures (%d), entering sleep mode (30 min backoff)", authFailures)
|
||||
c.waitWithTrafficReport(ctx, 30*time.Minute)
|
||||
authFailures = 0
|
||||
continue
|
||||
}
|
||||
}
|
||||
// Use longer backoff for auth errors
|
||||
backoff := time.Duration(authFailures) * 30 * time.Second
|
||||
if backoff > 10*time.Minute {
|
||||
backoff = 10 * time.Minute
|
||||
}
|
||||
log.Printf("[Agent] Auth error, reconnecting in %v...", backoff)
|
||||
c.waitWithTrafficReport(ctx, backoff)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Printf("[Agent] WebSocket error: %v", err)
|
||||
consecutiveFailures++
|
||||
authFailures = 0 // Reset auth failures on non-auth errors
|
||||
|
||||
if consecutiveFailures >= maxConsecutiveFailures {
|
||||
log.Printf("[Agent] Too many WebSocket failures (%d), switching to auto mode for fallback...", consecutiveFailures)
|
||||
@@ -167,6 +192,7 @@ func (c *Client) runWebSocket(ctx context.Context) {
|
||||
}
|
||||
} else {
|
||||
consecutiveFailures = 0
|
||||
authFailures = 0
|
||||
}
|
||||
|
||||
backoff := c.calculateBackoff()
|
||||
@@ -862,16 +888,23 @@ func (c *Client) getSystemNetworkStats() (rxBytes, txBytes int64) {
|
||||
// AuthError represents an authentication error
|
||||
type AuthError struct {
|
||||
Message string
|
||||
Code string // "token_expired", "token_invalid", "server_error"
|
||||
}
|
||||
|
||||
func (e *AuthError) Error() string {
|
||||
return "authentication failed: " + e.Message
|
||||
}
|
||||
|
||||
// IsTokenInvalid returns true if the error indicates an invalid token
|
||||
func (e *AuthError) IsTokenInvalid() bool {
|
||||
return e.Code == "token_invalid" || e.Message == "Invalid token"
|
||||
}
|
||||
|
||||
// WebSocket message types
|
||||
const (
|
||||
WSMsgTypeCertRequest = "cert_request"
|
||||
WSMsgTypeCertUpdate = "cert_update"
|
||||
WSMsgTypeTokenUpdate = "token_update"
|
||||
)
|
||||
|
||||
// WSCertRequestPayload represents a certificate request from master
|
||||
@@ -898,6 +931,12 @@ type WSCertUpdatePayload struct {
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// WSTokenUpdatePayload represents a token update from master
|
||||
type WSTokenUpdatePayload struct {
|
||||
ServerToken string `json:"server_token"`
|
||||
ExpiresAt time.Time `json:"expires_at"`
|
||||
}
|
||||
|
||||
// handleMessage processes incoming messages from master
|
||||
func (c *Client) handleMessage(conn *websocket.Conn, message []byte) {
|
||||
var msg struct {
|
||||
@@ -918,6 +957,13 @@ func (c *Client) handleMessage(conn *websocket.Conn, message []byte) {
|
||||
return
|
||||
}
|
||||
go c.handleCertRequest(conn, payload)
|
||||
case WSMsgTypeTokenUpdate:
|
||||
var payload WSTokenUpdatePayload
|
||||
if err := json.Unmarshal(msg.Payload, &payload); err != nil {
|
||||
log.Printf("[Agent] Failed to parse token_update payload: %v", err)
|
||||
return
|
||||
}
|
||||
c.handleTokenUpdate(payload)
|
||||
default:
|
||||
// Ignore unknown message types
|
||||
}
|
||||
@@ -988,3 +1034,13 @@ func (c *Client) requestCertificate(req WSCertRequestPayload) WSCertUpdatePayloa
|
||||
log.Printf("[Agent] Certificate obtained for %s, expires: %s", req.Domain, certResult.ExpiryDate)
|
||||
return result
|
||||
}
|
||||
|
||||
// handleTokenUpdate processes a token update from master
|
||||
func (c *Client) handleTokenUpdate(payload WSTokenUpdatePayload) {
|
||||
log.Printf("[Agent] Received token update from master, new token expires at %s", payload.ExpiresAt.Format(time.RFC3339))
|
||||
|
||||
// Update the token in memory
|
||||
c.config.Token = payload.ServerToken
|
||||
|
||||
log.Printf("[Agent] Token updated successfully in memory")
|
||||
}
|
||||
|
||||
@@ -1406,7 +1406,10 @@ func (h *ManageHandler) getInboundTagsFromGRPC() []string {
|
||||
|
||||
tags := make([]string, 0, len(resp.Inbounds))
|
||||
for _, ib := range resp.Inbounds {
|
||||
tags = append(tags, ib.Tag)
|
||||
// 过滤掉 tag="api" 和空 tag(Xray 内部入站)
|
||||
if ib.Tag != "" && ib.Tag != "api" {
|
||||
tags = append(tags, ib.Tag)
|
||||
}
|
||||
}
|
||||
return tags
|
||||
}
|
||||
@@ -1427,10 +1430,28 @@ func (h *ManageHandler) mergeInbounds(configInbounds []map[string]interface{}, r
|
||||
result := make([]map[string]interface{}, 0, len(configInbounds)+len(runtimeTags))
|
||||
for _, ib := range configInbounds {
|
||||
tag, _ := ib["tag"].(string)
|
||||
// 跳过 tag="api" 的入站(Xray 内部 API 入站)
|
||||
if tag == "api" {
|
||||
continue
|
||||
}
|
||||
ibCopy := make(map[string]interface{})
|
||||
for k, v := range ib {
|
||||
ibCopy[k] = v
|
||||
}
|
||||
// 如果 tag 为空,根据协议和端口生成名称
|
||||
if tag == "" {
|
||||
protocol, _ := ib["protocol"].(string)
|
||||
port := 0
|
||||
if p, ok := ib["port"].(float64); ok {
|
||||
port = int(p)
|
||||
} else if p, ok := ib["port"].(int); ok {
|
||||
port = p
|
||||
}
|
||||
if protocol != "" && port > 0 {
|
||||
ibCopy["tag"] = fmt.Sprintf("%s-%d", protocol, port)
|
||||
ibCopy["_generated_tag"] = true
|
||||
}
|
||||
}
|
||||
if runtimeTagSet[tag] {
|
||||
ibCopy["_runtime_status"] = "running"
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user