mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-10-25 07:15:01 +03:00
f105132866
A client per runtime operation made a bulk delete pay a TCP and HTTP/2 handshake for every client. The local runtime now keeps one gRPC client per API port and replaces it when a core restart moves the port; the traffic poll keeps its own client, since StatsLastValues is unlocked. A pooled channel keeps grpc-go's reconnect backoff after the core restarts, so a call that fails with Unavailable drops the client and dials again, as a client per call did.
53 lines
1.2 KiB
Go
53 lines
1.2 KiB
Go
package runtime
|
|
|
|
import (
|
|
"sync"
|
|
|
|
"github.com/mhsanaei/3x-ui/v3/internal/xray"
|
|
)
|
|
|
|
// One pooled gRPC client serves local runtime operations; never use it for traffic stats, whose
|
|
// unlocked StatsLastValues a second reader would corrupt, so the traffic poll keeps its own client.
|
|
var (
|
|
localAPIMu sync.Mutex
|
|
localAPIPort int
|
|
localAPIClient *xray.XrayAPI
|
|
)
|
|
|
|
// localAPIForPort returns the pooled client for the API port, replacing (and closing) it when a core
|
|
// restart moved the port; callers must not close it.
|
|
func localAPIForPort(port int) (*xray.XrayAPI, error) {
|
|
localAPIMu.Lock()
|
|
defer localAPIMu.Unlock()
|
|
|
|
if localAPIClient != nil {
|
|
if localAPIPort == port {
|
|
return localAPIClient, nil
|
|
}
|
|
localAPIClient.Close()
|
|
localAPIClient = nil
|
|
}
|
|
|
|
api := &xray.XrayAPI{}
|
|
if err := api.Init(port); err != nil {
|
|
return nil, err
|
|
}
|
|
localAPIClient = api
|
|
localAPIPort = port
|
|
return api, nil
|
|
}
|
|
|
|
// evictLocalAPIClient closes the pooled client so the next call dials a fresh connection, unless
|
|
// another call already replaced the one that failed.
|
|
func evictLocalAPIClient(api *xray.XrayAPI) {
|
|
localAPIMu.Lock()
|
|
defer localAPIMu.Unlock()
|
|
|
|
if localAPIClient != api {
|
|
return
|
|
}
|
|
localAPIClient.Close()
|
|
localAPIClient = nil
|
|
localAPIPort = 0
|
|
}
|