mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-08-01 19:44:15 +03:00
Add xhttp transport
This commit is contained in:
104
transport/v2rayxhttp/mux.go
Normal file
104
transport/v2rayxhttp/mux.go
Normal file
@@ -0,0 +1,104 @@
|
||||
package xhttp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"math"
|
||||
"math/big"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-box/option"
|
||||
)
|
||||
|
||||
type XmuxConn interface {
|
||||
IsClosed() bool
|
||||
}
|
||||
|
||||
type XmuxClient struct {
|
||||
XmuxConn XmuxConn
|
||||
OpenUsage atomic.Int32
|
||||
leftUsage int32
|
||||
LeftRequests atomic.Int32
|
||||
UnreusableAt time.Time
|
||||
}
|
||||
|
||||
type XmuxManager struct {
|
||||
options option.V2RayXHTTPXmuxOptions
|
||||
concurrency int32
|
||||
connections int32
|
||||
newConnFunc func() XmuxConn
|
||||
xmuxClients []*XmuxClient
|
||||
mtx sync.Mutex
|
||||
}
|
||||
|
||||
func NewXmuxManager(options option.V2RayXHTTPXmuxOptions, newConnFunc func() XmuxConn) *XmuxManager {
|
||||
return &XmuxManager{
|
||||
options: options,
|
||||
concurrency: options.GetNormalizedMaxConcurrency().Rand(),
|
||||
connections: options.GetNormalizedMaxConnections().Rand(),
|
||||
newConnFunc: newConnFunc,
|
||||
xmuxClients: make([]*XmuxClient, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *XmuxManager) newXmuxClient() *XmuxClient {
|
||||
xmuxClient := &XmuxClient{
|
||||
XmuxConn: m.newConnFunc(),
|
||||
leftUsage: -1,
|
||||
}
|
||||
if x := m.options.GetNormalizedCMaxReuseTimes().Rand(); x > 0 {
|
||||
xmuxClient.leftUsage = x - 1
|
||||
}
|
||||
xmuxClient.LeftRequests.Store(math.MaxInt32)
|
||||
if x := m.options.GetNormalizedHMaxRequestTimes().Rand(); x > 0 {
|
||||
xmuxClient.LeftRequests.Store(x)
|
||||
}
|
||||
if x := m.options.GetNormalizedHMaxReusableSecs().Rand(); x > 0 {
|
||||
xmuxClient.UnreusableAt = time.Now().Add(time.Duration(x) * time.Second)
|
||||
}
|
||||
m.xmuxClients = append(m.xmuxClients, xmuxClient)
|
||||
return xmuxClient
|
||||
}
|
||||
|
||||
func (m *XmuxManager) GetXmuxClient(ctx context.Context) *XmuxClient {
|
||||
m.mtx.Lock()
|
||||
defer m.mtx.Unlock()
|
||||
for i := 0; i < len(m.xmuxClients); {
|
||||
xmuxClient := m.xmuxClients[i]
|
||||
if xmuxClient.XmuxConn.IsClosed() ||
|
||||
xmuxClient.leftUsage == 0 ||
|
||||
xmuxClient.LeftRequests.Load() <= 0 ||
|
||||
(xmuxClient.UnreusableAt != time.Time{} && time.Now().After(xmuxClient.UnreusableAt)) {
|
||||
m.xmuxClients = append(m.xmuxClients[:i], m.xmuxClients[i+1:]...)
|
||||
} else {
|
||||
i++
|
||||
}
|
||||
}
|
||||
if len(m.xmuxClients) == 0 {
|
||||
return m.newXmuxClient()
|
||||
}
|
||||
if m.connections > 0 && len(m.xmuxClients) < int(m.connections) {
|
||||
return m.newXmuxClient()
|
||||
}
|
||||
xmuxClients := make([]*XmuxClient, 0)
|
||||
if m.concurrency > 0 {
|
||||
for _, xmuxClient := range m.xmuxClients {
|
||||
if xmuxClient.OpenUsage.Load() < m.concurrency {
|
||||
xmuxClients = append(xmuxClients, xmuxClient)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
xmuxClients = m.xmuxClients
|
||||
}
|
||||
if len(xmuxClients) == 0 {
|
||||
return m.newXmuxClient()
|
||||
}
|
||||
i, _ := rand.Int(rand.Reader, big.NewInt(int64(len(xmuxClients))))
|
||||
xmuxClient := xmuxClients[i.Int64()]
|
||||
if xmuxClient.leftUsage > 0 {
|
||||
xmuxClient.leftUsage -= 1
|
||||
}
|
||||
return xmuxClient
|
||||
}
|
||||
Reference in New Issue
Block a user