mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-06-28 00:24:19 +00:00
Use efficient APIs and simplify loops
Minor refactors across the codebase to improve readability and use more efficient APIs: replace fmt.Sprintf+base64 encoding with fmt.Appendf when building Shadowsocks userInfo; compute elapsed using max(now-prev.at, window) to simplify logic; use strings.SplitSeq for splitting in two places; simplify test and goroutine loops to range-based iterations and use errgroup's Go helper; and align/clean up struct field formatting and test map literals. Mostly stylistic/efficiency changes with no intended behavior changes.
This commit is contained in:
@@ -320,33 +320,33 @@ func TestBuildProxy_VLESSNoneEncryptionOmittedForClash(t *testing.T) {
|
||||
|
||||
func TestBuildXhttpClashOpts_FullFieldMapping(t *testing.T) {
|
||||
xhttp := map[string]any{
|
||||
"path": "/api/v1",
|
||||
"mode": "stream-up",
|
||||
"host": "example.com",
|
||||
"xPaddingBytes": "100-1000",
|
||||
"xPaddingObfsMode": true,
|
||||
"xPaddingKey": "mykey",
|
||||
"xPaddingHeader": "X-Trace-ID",
|
||||
"xPaddingPlacement": "queryInHeader",
|
||||
"xPaddingMethod": "tokenish",
|
||||
"uplinkHTTPMethod": "POST",
|
||||
"sessionPlacement": "query",
|
||||
"sessionKey": "sess",
|
||||
"seqPlacement": "header",
|
||||
"seqKey": "seq",
|
||||
"uplinkDataPlacement": "body",
|
||||
"uplinkDataKey": "udata",
|
||||
"uplinkChunkSize": "64-256",
|
||||
"noGRPCHeader": true,
|
||||
"scMaxEachPostBytes": "500000",
|
||||
"path": "/api/v1",
|
||||
"mode": "stream-up",
|
||||
"host": "example.com",
|
||||
"xPaddingBytes": "100-1000",
|
||||
"xPaddingObfsMode": true,
|
||||
"xPaddingKey": "mykey",
|
||||
"xPaddingHeader": "X-Trace-ID",
|
||||
"xPaddingPlacement": "queryInHeader",
|
||||
"xPaddingMethod": "tokenish",
|
||||
"uplinkHTTPMethod": "POST",
|
||||
"sessionPlacement": "query",
|
||||
"sessionKey": "sess",
|
||||
"seqPlacement": "header",
|
||||
"seqKey": "seq",
|
||||
"uplinkDataPlacement": "body",
|
||||
"uplinkDataKey": "udata",
|
||||
"uplinkChunkSize": "64-256",
|
||||
"noGRPCHeader": true,
|
||||
"scMaxEachPostBytes": "500000",
|
||||
"scMinPostsIntervalMs": "50",
|
||||
"xmux": map[string]any{
|
||||
"maxConcurrency": "16-32",
|
||||
"maxConnections": "4",
|
||||
"cMaxReuseTimes": "8",
|
||||
"hMaxRequestTimes": "600-900",
|
||||
"hMaxReusableSecs": "1800-3000",
|
||||
"hKeepAlivePeriod": float64(60),
|
||||
"hMaxRequestTimes": "600-900",
|
||||
"hMaxReusableSecs": "1800-3000",
|
||||
"hKeepAlivePeriod": float64(60),
|
||||
},
|
||||
"headers": map[string]any{
|
||||
"User-Agent": "chrome",
|
||||
@@ -473,8 +473,8 @@ func TestBuildXhttpClashOpts_FullFieldMapping(t *testing.T) {
|
||||
|
||||
func TestBuildXhttpClashOpts_DPIDefaultsFiltered(t *testing.T) {
|
||||
xhttp := map[string]any{
|
||||
"path": "/",
|
||||
"mode": "stream-up",
|
||||
"path": "/",
|
||||
"mode": "stream-up",
|
||||
"scMaxEachPostBytes": "1000000",
|
||||
"scMinPostsIntervalMs": "30",
|
||||
}
|
||||
@@ -494,9 +494,9 @@ func TestBuildXhttpClashOpts_PaddingObfsGate(t *testing.T) {
|
||||
// Sub-test 1: obfs mode false — gated fields should not appear
|
||||
t.Run("ObfsModeFalse", func(t *testing.T) {
|
||||
xhttp := map[string]any{
|
||||
"path": "/",
|
||||
"path": "/",
|
||||
"xPaddingObfsMode": false,
|
||||
"xPaddingKey": "should-not-appear",
|
||||
"xPaddingKey": "should-not-appear",
|
||||
}
|
||||
opts := buildXhttpClashOpts(xhttp)
|
||||
if opts == nil {
|
||||
@@ -553,9 +553,9 @@ func TestBuildXhttpClashOpts_XmuxMapsToReuseSettings(t *testing.T) {
|
||||
"maxConcurrency": "16-32",
|
||||
"maxConnections": "4",
|
||||
"cMaxReuseTimes": "8",
|
||||
"hMaxRequestTimes": "600-900",
|
||||
"hMaxReusableSecs": "1800-3000",
|
||||
"hKeepAlivePeriod": float64(60),
|
||||
"hMaxRequestTimes": "600-900",
|
||||
"hMaxReusableSecs": "1800-3000",
|
||||
"hKeepAlivePeriod": float64(60),
|
||||
},
|
||||
}
|
||||
opts := buildXhttpClashOpts(xhttp)
|
||||
|
||||
@@ -747,7 +747,7 @@ func (s *SubService) genShadowsocksLink(inbound *model.Inbound, email string) st
|
||||
url.QueryEscape(inboundPassword),
|
||||
url.QueryEscape(clients[clientIndex].Password))
|
||||
} else {
|
||||
userInfo = base64.RawURLEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", method, clients[clientIndex].Password)))
|
||||
userInfo = base64.RawURLEncoding.EncodeToString(fmt.Appendf(nil, "%s:%s", method, clients[clientIndex].Password))
|
||||
}
|
||||
|
||||
externalProxies, _ := stream["externalProxy"].([]any)
|
||||
|
||||
@@ -39,29 +39,29 @@ type AllSetting struct {
|
||||
Datepicker string `json:"datepicker" form:"datepicker"` // Date picker format
|
||||
|
||||
// Telegram bot settings
|
||||
TgBotEnable bool `json:"tgBotEnable" form:"tgBotEnable"` // Enable Telegram bot notifications
|
||||
TgBotToken string `json:"tgBotToken" form:"tgBotToken"` // Telegram bot token
|
||||
TgBotProxy string `json:"tgBotProxy" form:"tgBotProxy"` // Proxy URL for Telegram bot
|
||||
TgBotAPIServer string `json:"tgBotAPIServer" form:"tgBotAPIServer"` // Custom API server for Telegram bot
|
||||
TgBotChatId string `json:"tgBotChatId" form:"tgBotChatId"` // Telegram chat ID for notifications
|
||||
TgRunTime string `json:"tgRunTime" form:"tgRunTime"` // Cron schedule for Telegram notifications
|
||||
TgBotBackup bool `json:"tgBotBackup" form:"tgBotBackup"` // Enable database backup via Telegram
|
||||
TgCpu int `json:"tgCpu" form:"tgCpu" validate:"gte=0,lte=100"` // CPU usage threshold for alerts (percent)
|
||||
TgBotEnable bool `json:"tgBotEnable" form:"tgBotEnable"` // Enable Telegram bot notifications
|
||||
TgBotToken string `json:"tgBotToken" form:"tgBotToken"` // Telegram bot token
|
||||
TgBotProxy string `json:"tgBotProxy" form:"tgBotProxy"` // Proxy URL for Telegram bot
|
||||
TgBotAPIServer string `json:"tgBotAPIServer" form:"tgBotAPIServer"` // Custom API server for Telegram bot
|
||||
TgBotChatId string `json:"tgBotChatId" form:"tgBotChatId"` // Telegram chat ID for notifications
|
||||
TgRunTime string `json:"tgRunTime" form:"tgRunTime"` // Cron schedule for Telegram notifications
|
||||
TgBotBackup bool `json:"tgBotBackup" form:"tgBotBackup"` // Enable database backup via Telegram
|
||||
TgCpu int `json:"tgCpu" form:"tgCpu" validate:"gte=0,lte=100"` // CPU usage threshold for alerts (percent)
|
||||
TgMemory int `json:"tgMemory" form:"tgMemory" validate:"gte=0,lte=100"` // Memory usage threshold for alerts (percent)
|
||||
TgLang string `json:"tgLang" form:"tgLang"` // Telegram bot language
|
||||
TgEnabledEvents string `json:"tgEnabledEvents" form:"tgEnabledEvents"` // Comma-separated event types to send via Telegram
|
||||
TgLang string `json:"tgLang" form:"tgLang"` // Telegram bot language
|
||||
TgEnabledEvents string `json:"tgEnabledEvents" form:"tgEnabledEvents"` // Comma-separated event types to send via Telegram
|
||||
|
||||
// Email (SMTP) notification settings
|
||||
SmtpEnable bool `json:"smtpEnable" form:"smtpEnable"` // Enable email notifications
|
||||
SmtpHost string `json:"smtpHost" form:"smtpHost"` // SMTP server host
|
||||
SmtpPort int `json:"smtpPort" form:"smtpPort" validate:"gte=1,lte=65535"` // SMTP server port
|
||||
SmtpUsername string `json:"smtpUsername" form:"smtpUsername"` // SMTP username
|
||||
SmtpPassword string `json:"smtpPassword" form:"smtpPassword"` // SMTP password
|
||||
SmtpTo string `json:"smtpTo" form:"smtpTo"` // Comma-separated recipient emails
|
||||
SmtpEncryptionType string `json:"smtpEncryptionType" form:"smtpEncryptionType"` // SMTP encryption: none, starttls, tls
|
||||
SmtpEnabledEvents string `json:"smtpEnabledEvents" form:"smtpEnabledEvents"` // Comma-separated event types to send via email
|
||||
SmtpCpu int `json:"smtpCpu" form:"smtpCpu" validate:"gte=0,lte=100"` // CPU threshold for email notifications
|
||||
SmtpMemory int `json:"smtpMemory" form:"smtpMemory" validate:"gte=0,lte=100"` // Memory threshold for email notifications
|
||||
SmtpEnable bool `json:"smtpEnable" form:"smtpEnable"` // Enable email notifications
|
||||
SmtpHost string `json:"smtpHost" form:"smtpHost"` // SMTP server host
|
||||
SmtpPort int `json:"smtpPort" form:"smtpPort" validate:"gte=1,lte=65535"` // SMTP server port
|
||||
SmtpUsername string `json:"smtpUsername" form:"smtpUsername"` // SMTP username
|
||||
SmtpPassword string `json:"smtpPassword" form:"smtpPassword"` // SMTP password
|
||||
SmtpTo string `json:"smtpTo" form:"smtpTo"` // Comma-separated recipient emails
|
||||
SmtpEncryptionType string `json:"smtpEncryptionType" form:"smtpEncryptionType"` // SMTP encryption: none, starttls, tls
|
||||
SmtpEnabledEvents string `json:"smtpEnabledEvents" form:"smtpEnabledEvents"` // Comma-separated event types to send via email
|
||||
SmtpCpu int `json:"smtpCpu" form:"smtpCpu" validate:"gte=0,lte=100"` // CPU threshold for email notifications
|
||||
SmtpMemory int `json:"smtpMemory" form:"smtpMemory" validate:"gte=0,lte=100"` // Memory threshold for email notifications
|
||||
|
||||
// Security settings
|
||||
TimeLocation string `json:"timeLocation" form:"timeLocation"` // Time zone location
|
||||
|
||||
@@ -246,10 +246,7 @@ func (j *NodeTrafficSyncJob) nodeInboundSpeed() []*xray.Traffic {
|
||||
if dDown < 0 {
|
||||
dDown = 0
|
||||
}
|
||||
elapsed := now - prev.at
|
||||
if elapsed < nodeInboundSpeedWindowMs {
|
||||
elapsed = nodeInboundSpeedWindowMs
|
||||
}
|
||||
elapsed := max(now-prev.at, nodeInboundSpeedWindowMs)
|
||||
up := dUp * nodeInboundSpeedWindowMs / elapsed
|
||||
down := dDown * nodeInboundSpeedWindowMs / elapsed
|
||||
if up > 0 || down > 0 {
|
||||
|
||||
@@ -936,7 +936,7 @@ func (s *ServerService) fetchXrayDigestSHA256(client *http.Client, dgstURL strin
|
||||
// parseXrayDigestSHA256 extracts the lowercase SHA2-256 hex from an XTLS .dgst
|
||||
// file, whose lines are "ALGO= <hex>" (the relevant one being "SHA2-256= ...").
|
||||
func parseXrayDigestSHA256(dgst []byte) (string, error) {
|
||||
for _, line := range strings.Split(string(dgst), "\n") {
|
||||
for line := range strings.SplitSeq(string(dgst), "\n") {
|
||||
rest, ok := strings.CutPrefix(strings.TrimSpace(line), "SHA2-256=")
|
||||
if !ok {
|
||||
continue
|
||||
|
||||
+1
-1
@@ -429,7 +429,7 @@ func (s *Server) memoryAlarmWanted() bool {
|
||||
if threshold <= 0 {
|
||||
return false
|
||||
}
|
||||
for _, e := range strings.Split(events, ",") {
|
||||
for e := range strings.SplitSeq(events, ",") {
|
||||
if strings.TrimSpace(e) == string(eventbus.EventMemoryHigh) {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -16,18 +16,18 @@ func TestLogWriterLastLineConcurrent(t *testing.T) {
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(writers + readers)
|
||||
|
||||
for i := 0; i < writers; i++ {
|
||||
for range writers {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for j := 0; j < iterations; j++ {
|
||||
for range iterations {
|
||||
_, _ = lw.Write([]byte("2024/01/01 00:00:00.000000 [Info] connection accepted"))
|
||||
}
|
||||
}()
|
||||
}
|
||||
for i := 0; i < readers; i++ {
|
||||
for range readers {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for j := 0; j < iterations; j++ {
|
||||
for range iterations {
|
||||
_ = lw.LastLine()
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -19,9 +19,7 @@ func TestProcessLifecycleFieldsRaceSafe(t *testing.T) {
|
||||
stop := make(chan struct{})
|
||||
|
||||
// Writer: churn cmd/done/exitErr like Start + waitForCommand.
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
wg.Go(func() {
|
||||
for {
|
||||
select {
|
||||
case <-stop:
|
||||
@@ -34,13 +32,11 @@ func TestProcessLifecycleFieldsRaceSafe(t *testing.T) {
|
||||
p.mu.Unlock()
|
||||
p.setExitErr(errors.New("boom"))
|
||||
}
|
||||
}()
|
||||
})
|
||||
|
||||
// Readers: the concurrent status getters.
|
||||
for i := 0; i < 4; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for range 4 {
|
||||
wg.Go(func() {
|
||||
for {
|
||||
select {
|
||||
case <-stop:
|
||||
@@ -51,7 +47,7 @@ func TestProcessLifecycleFieldsRaceSafe(t *testing.T) {
|
||||
_ = p.GetErr()
|
||||
_ = p.GetResult()
|
||||
}
|
||||
}()
|
||||
})
|
||||
}
|
||||
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
|
||||
Reference in New Issue
Block a user