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