diff --git a/common/humanize/bytes.go b/common/humanize/bytes.go deleted file mode 100644 index 6ee4d268..00000000 --- a/common/humanize/bytes.go +++ /dev/null @@ -1,158 +0,0 @@ -package humanize - -import ( - "fmt" - "math" - "strconv" - "strings" - "unicode" -) - -// IEC Sizes. -// kibis of bits -const ( - Byte = 1 << (iota * 10) - KiByte - MiByte - GiByte - TiByte - PiByte - EiByte -) - -// SI Sizes. -const ( - IByte = 1 - KByte = IByte * 1000 - MByte = KByte * 1000 - GByte = MByte * 1000 - TByte = GByte * 1000 - PByte = TByte * 1000 - EByte = PByte * 1000 -) - -var defaultSizeTable = map[string]uint64{ - "b": Byte, - "kib": KiByte, - "kb": KByte, - "mib": MiByte, - "mb": MByte, - "gib": GiByte, - "gb": GByte, - "tib": TiByte, - "tb": TByte, - "pib": PiByte, - "pb": PByte, - "eib": EiByte, - "eb": EByte, - // Without suffix - "": Byte, - "ki": KiByte, - "k": KByte, - "mi": MiByte, - "m": MByte, - "gi": GiByte, - "g": GByte, - "ti": TiByte, - "t": TByte, - "pi": PiByte, - "p": PByte, - "ei": EiByte, - "e": EByte, -} - -var memorysSizeTable = map[string]uint64{ - "b": Byte, - "kb": KiByte, - "mb": MiByte, - "gb": GiByte, - "tb": TiByte, - "pb": PiByte, - "eb": EiByte, - "": Byte, - "k": KiByte, - "m": MiByte, - "g": GiByte, - "t": TiByte, - "p": PiByte, - "e": EiByte, -} - -var ( - defaultSizes = []string{"B", "kB", "MB", "GB", "TB", "PB", "EB"} - iSizes = []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"} -) - -func Bytes(s uint64) string { - return humanateBytes(s, 1000, defaultSizes) -} - -func MemoryBytes(s uint64) string { - return humanateBytes(s, 1024, defaultSizes) -} - -func IBytes(s uint64) string { - return humanateBytes(s, 1024, iSizes) -} - -func logn(n, b float64) float64 { - return math.Log(n) / math.Log(b) -} - -func humanateBytes(s uint64, base float64, sizes []string) string { - if s < 10 { - return fmt.Sprintf("%d B", s) - } - e := math.Floor(logn(float64(s), base)) - suffix := sizes[int(e)] - val := math.Floor(float64(s)/math.Pow(base, e)*10+0.5) / 10 - f := "%.0f %s" - if val < 10 { - f = "%.1f %s" - } - - return fmt.Sprintf(f, val, suffix) -} - -func ParseBytes(s string) (uint64, error) { - return parseBytes0(s, defaultSizeTable) -} - -func ParseMemoryBytes(s string) (uint64, error) { - return parseBytes0(s, memorysSizeTable) -} - -func parseBytes0(s string, sizeTable map[string]uint64) (uint64, error) { - lastDigit := 0 - hasComma := false - for _, r := range s { - if !(unicode.IsDigit(r) || r == '.' || r == ',') { - break - } - if r == ',' { - hasComma = true - } - lastDigit++ - } - - num := s[:lastDigit] - if hasComma { - num = strings.Replace(num, ",", "", -1) - } - - f, err := strconv.ParseFloat(num, 64) - if err != nil { - return 0, err - } - - extra := strings.ToLower(strings.TrimSpace(s[lastDigit:])) - if m, ok := sizeTable[extra]; ok { - f *= float64(m) - if f >= math.MaxUint64 { - return 0, fmt.Errorf("too large: %v", s) - } - return uint64(f), nil - } - - return 0, fmt.Errorf("unhandled size name: %v", extra) -} diff --git a/debug.go b/debug.go index 2fa962d6..1726c10e 100644 --- a/debug.go +++ b/debug.go @@ -24,9 +24,9 @@ func applyDebugOptions(options option.DebugOptions) { if options.TraceBack != "" { debug.SetTraceback(options.TraceBack) } - if options.MemoryLimit != 0 { - debug.SetMemoryLimit(int64(float64(options.MemoryLimit) / 1.5)) - conntrack.MemoryLimit = uint64(options.MemoryLimit) + if options.MemoryLimit.Value() != 0 { + debug.SetMemoryLimit(int64(float64(options.MemoryLimit.Value()) / 1.5)) + conntrack.MemoryLimit = options.MemoryLimit.Value() } if options.OOMKiller != nil { conntrack.KillerEnabled = *options.OOMKiller diff --git a/debug_http.go b/debug_http.go index 32159778..e51a0731 100644 --- a/debug_http.go +++ b/debug_http.go @@ -7,9 +7,9 @@ import ( "runtime/debug" "strings" - "github.com/sagernet/sing-box/common/humanize" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" + "github.com/sagernet/sing/common/byteformats" E "github.com/sagernet/sing/common/exceptions" "github.com/sagernet/sing/common/json" "github.com/sagernet/sing/common/json/badjson" @@ -38,9 +38,9 @@ func applyDebugListenOption(options option.DebugOptions) { runtime.ReadMemStats(&memStats) var memObject badjson.JSONObject - memObject.Put("heap", humanize.MemoryBytes(memStats.HeapInuse)) - memObject.Put("stack", humanize.MemoryBytes(memStats.StackInuse)) - memObject.Put("idle", humanize.MemoryBytes(memStats.HeapIdle-memStats.HeapReleased)) + memObject.Put("heap", byteformats.FormatMemoryBytes(memStats.HeapInuse)) + memObject.Put("stack", byteformats.FormatMemoryBytes(memStats.StackInuse)) + memObject.Put("idle", byteformats.FormatMemoryBytes(memStats.HeapIdle-memStats.HeapReleased)) memObject.Put("goroutines", runtime.NumGoroutine()) memObject.Put("rss", rusageMaxRSS()) diff --git a/experimental/libbox/setup.go b/experimental/libbox/setup.go index 184d5250..ad898fee 100644 --- a/experimental/libbox/setup.go +++ b/experimental/libbox/setup.go @@ -7,10 +7,10 @@ import ( "strconv" "time" - "github.com/sagernet/sing-box/common/humanize" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/experimental/locale" "github.com/sagernet/sing-box/log" + "github.com/sagernet/sing/common/byteformats" ) var ( @@ -75,11 +75,11 @@ func Version() string { } func FormatBytes(length int64) string { - return humanize.Bytes(uint64(length)) + return byteformats.FormatBytes(uint64(length)) } func FormatMemoryBytes(length int64) string { - return humanize.MemoryBytes(uint64(length)) + return byteformats.FormatMemoryBytes(uint64(length)) } func FormatDuration(duration int64) string { diff --git a/go.mod b/go.mod index 69c3f6e7..2d99bb61 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/sagernet/gvisor v0.0.0-20241123041152-536d05261cff github.com/sagernet/quic-go v0.49.0-beta.1 github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 - github.com/sagernet/sing v0.6.7 + github.com/sagernet/sing v0.6.8-0.20250429070844-b63643251ed5 github.com/sagernet/sing-dns v0.4.2 github.com/sagernet/sing-mux v0.3.1 github.com/sagernet/sing-quic v0.4.1-0.20250423030647-0eb05f373a76 diff --git a/go.sum b/go.sum index 37caa69e..11987904 100644 --- a/go.sum +++ b/go.sum @@ -119,8 +119,8 @@ github.com/sagernet/quic-go v0.49.0-beta.1/go.mod h1:uesWD1Ihrldq1M3XtjuEvIUqi8W github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc= github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU= github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= -github.com/sagernet/sing v0.6.7 h1:NIWBLZ9AUWDXAQBKGleKwsitbQrI9M0nqoheXhUKnrI= -github.com/sagernet/sing v0.6.7/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= +github.com/sagernet/sing v0.6.8-0.20250429070844-b63643251ed5 h1:j5r2x3Lazb1giycHFxICc201LSyDn3ZH+ywa+8duNxo= +github.com/sagernet/sing v0.6.8-0.20250429070844-b63643251ed5/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/sagernet/sing-dns v0.4.2 h1:cWe2XPUBFLep2j9kJV4Epg3bctGhMvrrl/sWi9Wszfg= github.com/sagernet/sing-dns v0.4.2/go.mod h1:dweQs54ng2YGzoJfz+F9dGuDNdP5pJ3PLeggnK5VWc8= github.com/sagernet/sing-mux v0.3.1 h1:kvCc8HyGAskDHDQ0yQvoTi/7J4cZPB/VJMsAM3MmdQI= diff --git a/option/debug.go b/option/debug.go index 0b0b825a..3dfef7b0 100644 --- a/option/debug.go +++ b/option/debug.go @@ -1,43 +1,14 @@ package option -import ( - "github.com/sagernet/sing-box/common/humanize" - "github.com/sagernet/sing/common/json" -) +import "github.com/sagernet/sing/common/byteformats" type DebugOptions struct { - Listen string `json:"listen,omitempty"` - GCPercent *int `json:"gc_percent,omitempty"` - MaxStack *int `json:"max_stack,omitempty"` - MaxThreads *int `json:"max_threads,omitempty"` - PanicOnFault *bool `json:"panic_on_fault,omitempty"` - TraceBack string `json:"trace_back,omitempty"` - MemoryLimit MemoryBytes `json:"memory_limit,omitempty"` - OOMKiller *bool `json:"oom_killer,omitempty"` -} - -type MemoryBytes uint64 - -func (l MemoryBytes) MarshalJSON() ([]byte, error) { - return json.Marshal(humanize.MemoryBytes(uint64(l))) -} - -func (l *MemoryBytes) UnmarshalJSON(bytes []byte) error { - var valueInteger int64 - err := json.Unmarshal(bytes, &valueInteger) - if err == nil { - *l = MemoryBytes(valueInteger) - return nil - } - var valueString string - err = json.Unmarshal(bytes, &valueString) - if err != nil { - return err - } - parsedValue, err := humanize.ParseMemoryBytes(valueString) - if err != nil { - return err - } - *l = MemoryBytes(parsedValue) - return nil + Listen string `json:"listen,omitempty"` + GCPercent *int `json:"gc_percent,omitempty"` + MaxStack *int `json:"max_stack,omitempty"` + MaxThreads *int `json:"max_threads,omitempty"` + PanicOnFault *bool `json:"panic_on_fault,omitempty"` + TraceBack string `json:"trace_back,omitempty"` + MemoryLimit *byteformats.MemoryBytes `json:"memory_limit,omitempty"` + OOMKiller *bool `json:"oom_killer,omitempty"` } diff --git a/option/hysteria.go b/option/hysteria.go index beb3685e..6332be11 100644 --- a/option/hysteria.go +++ b/option/hysteria.go @@ -1,17 +1,19 @@ package option +import "github.com/sagernet/sing/common/byteformats" + type HysteriaInboundOptions struct { ListenOptions - Up string `json:"up,omitempty"` - UpMbps int `json:"up_mbps,omitempty"` - Down string `json:"down,omitempty"` - DownMbps int `json:"down_mbps,omitempty"` - Obfs string `json:"obfs,omitempty"` - Users []HysteriaUser `json:"users,omitempty"` - ReceiveWindowConn uint64 `json:"recv_window_conn,omitempty"` - ReceiveWindowClient uint64 `json:"recv_window_client,omitempty"` - MaxConnClient int `json:"max_conn_client,omitempty"` - DisableMTUDiscovery bool `json:"disable_mtu_discovery,omitempty"` + Up *byteformats.NetworkBytesCompat `json:"up,omitempty"` + UpMbps int `json:"up_mbps,omitempty"` + Down *byteformats.NetworkBytesCompat `json:"down,omitempty"` + DownMbps int `json:"down_mbps,omitempty"` + Obfs string `json:"obfs,omitempty"` + Users []HysteriaUser `json:"users,omitempty"` + ReceiveWindowConn uint64 `json:"recv_window_conn,omitempty"` + ReceiveWindowClient uint64 `json:"recv_window_client,omitempty"` + MaxConnClient int `json:"max_conn_client,omitempty"` + DisableMTUDiscovery bool `json:"disable_mtu_discovery,omitempty"` InboundTLSOptionsContainer } @@ -24,16 +26,16 @@ type HysteriaUser struct { type HysteriaOutboundOptions struct { DialerOptions ServerOptions - Up string `json:"up,omitempty"` - UpMbps int `json:"up_mbps,omitempty"` - Down string `json:"down,omitempty"` - DownMbps int `json:"down_mbps,omitempty"` - Obfs string `json:"obfs,omitempty"` - Auth []byte `json:"auth,omitempty"` - AuthString string `json:"auth_str,omitempty"` - ReceiveWindowConn uint64 `json:"recv_window_conn,omitempty"` - ReceiveWindow uint64 `json:"recv_window,omitempty"` - DisableMTUDiscovery bool `json:"disable_mtu_discovery,omitempty"` - Network NetworkList `json:"network,omitempty"` + Up *byteformats.NetworkBytesCompat `json:"up,omitempty"` + UpMbps int `json:"up_mbps,omitempty"` + Down *byteformats.NetworkBytesCompat `json:"down,omitempty"` + DownMbps int `json:"down_mbps,omitempty"` + Obfs string `json:"obfs,omitempty"` + Auth []byte `json:"auth,omitempty"` + AuthString string `json:"auth_str,omitempty"` + ReceiveWindowConn uint64 `json:"recv_window_conn,omitempty"` + ReceiveWindow uint64 `json:"recv_window,omitempty"` + DisableMTUDiscovery bool `json:"disable_mtu_discovery,omitempty"` + Network NetworkList `json:"network,omitempty"` OutboundTLSOptionsContainer } diff --git a/protocol/hysteria/inbound.go b/protocol/hysteria/inbound.go index 872e4dd7..5afc440d 100644 --- a/protocol/hysteria/inbound.go +++ b/protocol/hysteria/inbound.go @@ -7,7 +7,6 @@ import ( "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter/inbound" - "github.com/sagernet/sing-box/common/humanize" "github.com/sagernet/sing-box/common/listener" "github.com/sagernet/sing-box/common/tls" C "github.com/sagernet/sing-box/constant" @@ -16,7 +15,6 @@ import ( "github.com/sagernet/sing-quic/hysteria" "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/auth" - E "github.com/sagernet/sing/common/exceptions" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" ) @@ -56,19 +54,13 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo tlsConfig: tlsConfig, } var sendBps, receiveBps uint64 - if len(options.Up) > 0 { - sendBps, err = humanize.ParseBytes(options.Up) - if err != nil { - return nil, E.Cause(err, "invalid up speed format: ", options.Up) - } + if options.Up.Value() > 0 { + sendBps = options.Up.Value() } else { sendBps = uint64(options.UpMbps) * hysteria.MbpsToBps } - if len(options.Down) > 0 { - receiveBps, err = humanize.ParseBytes(options.Down) - if err != nil { - return nil, E.Cause(err, "invalid down speed format: ", options.Down) - } + if options.Down.Value() > 0 { + receiveBps = options.Down.Value() } else { receiveBps = uint64(options.DownMbps) * hysteria.MbpsToBps } diff --git a/protocol/hysteria/outbound.go b/protocol/hysteria/outbound.go index e1d8716c..e59b17a1 100644 --- a/protocol/hysteria/outbound.go +++ b/protocol/hysteria/outbound.go @@ -8,7 +8,6 @@ import ( "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter/outbound" "github.com/sagernet/sing-box/common/dialer" - "github.com/sagernet/sing-box/common/humanize" "github.com/sagernet/sing-box/common/tls" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" @@ -59,19 +58,13 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL password = string(options.Auth) } var sendBps, receiveBps uint64 - if len(options.Up) > 0 { - sendBps, err = humanize.ParseBytes(options.Up) - if err != nil { - return nil, E.Cause(err, "invalid up speed format: ", options.Up) - } + if options.Up.Value() > 0 { + sendBps = options.Up.Value() } else { sendBps = uint64(options.UpMbps) * hysteria.MbpsToBps } - if len(options.Down) > 0 { - receiveBps, err = humanize.ParseBytes(options.Down) - if err != nil { - return nil, E.Cause(err, "invalid down speed format: ", options.Down) - } + if options.Down.Value() > 0 { + receiveBps = options.Down.Value() } else { receiveBps = uint64(options.DownMbps) * hysteria.MbpsToBps }