mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-05-14 00:51:12 +03:00
219 lines
3.7 KiB
Go
219 lines
3.7 KiB
Go
package byteformats
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
Byte = 1 << (iota * 10)
|
|
KiByte
|
|
MiByte
|
|
GiByte
|
|
TiByte
|
|
PiByte
|
|
EiByte
|
|
)
|
|
|
|
const (
|
|
KByte = Byte * 1000
|
|
MByte = KByte * 1000
|
|
GByte = MByte * 1000
|
|
TByte = GByte * 1000
|
|
PByte = TByte * 1000
|
|
EByte = PByte * 1000
|
|
)
|
|
|
|
var unitValueTable = map[string]uint64{
|
|
"b": Byte,
|
|
"k": KByte,
|
|
"kb": KByte,
|
|
"ki": KiByte,
|
|
"kib": KiByte,
|
|
"m": MByte,
|
|
"mb": MByte,
|
|
"mi": MiByte,
|
|
"mib": MiByte,
|
|
"g": GByte,
|
|
"gb": GByte,
|
|
"gi": GiByte,
|
|
"gib": GiByte,
|
|
"t": TByte,
|
|
"tb": TByte,
|
|
"ti": TiByte,
|
|
"tib": TiByte,
|
|
"p": PByte,
|
|
"pb": PByte,
|
|
"pi": PiByte,
|
|
"pib": PiByte,
|
|
"e": EByte,
|
|
"eb": EByte,
|
|
"ei": EiByte,
|
|
"eib": EiByte,
|
|
}
|
|
|
|
var memoryUnitValueTable = map[string]uint64{
|
|
"b": Byte,
|
|
"k": KiByte,
|
|
"kb": KiByte,
|
|
"m": MiByte,
|
|
"mb": MiByte,
|
|
"g": GiByte,
|
|
"gb": GiByte,
|
|
"t": TiByte,
|
|
"tb": TiByte,
|
|
"p": PiByte,
|
|
"pb": PiByte,
|
|
"e": EiByte,
|
|
"eb": EiByte,
|
|
}
|
|
|
|
var networkUnitValueTable = map[string]uint64{
|
|
"Bps": Byte,
|
|
"Kbps": KByte / 8,
|
|
"KBps": KByte,
|
|
"Mbps": MByte / 8,
|
|
"MBps": MByte,
|
|
"Gbps": GByte / 8,
|
|
"GBps": GByte,
|
|
"Tbps": TByte / 8,
|
|
"TBps": TByte,
|
|
"Pbps": PByte / 8,
|
|
"PBps": PByte,
|
|
"Ebps": EByte / 8,
|
|
"EBps": EByte,
|
|
}
|
|
|
|
type rawBytes struct {
|
|
value uint64
|
|
unit string
|
|
unitValue uint64
|
|
}
|
|
|
|
func (b rawBytes) MarshalJSON() ([]byte, error) {
|
|
if b.unit == "" {
|
|
return json.Marshal(b.value)
|
|
}
|
|
return json.Marshal(strconv.FormatUint(b.value/b.unitValue, 10) + b.unit)
|
|
}
|
|
|
|
func parseUnit(b *rawBytes, unitTable map[string]uint64, caseSensitive bool, bytes []byte) error {
|
|
var intValue int64
|
|
err := json.Unmarshal(bytes, &intValue)
|
|
if err == nil {
|
|
b.value = uint64(intValue)
|
|
b.unit = ""
|
|
b.unitValue = 1
|
|
return nil
|
|
}
|
|
var stringValue string
|
|
err = json.Unmarshal(bytes, &stringValue)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if strings.TrimSpace(stringValue) == "" {
|
|
b.value = 0
|
|
b.unit = ""
|
|
b.unitValue = 1
|
|
return nil
|
|
}
|
|
unitIndex := 0
|
|
for i, c := range stringValue {
|
|
if c < '0' || c > '9' {
|
|
unitIndex = i
|
|
break
|
|
}
|
|
}
|
|
if unitIndex == 0 {
|
|
return fmt.Errorf("invalid format: %s", stringValue)
|
|
}
|
|
value, err := strconv.ParseUint(stringValue[:unitIndex], 10, 64)
|
|
if err != nil {
|
|
return fmt.Errorf("parse %s: %w", stringValue[:unitIndex], err)
|
|
}
|
|
rawUnit := stringValue[unitIndex:]
|
|
var unit string
|
|
if caseSensitive {
|
|
unit = strings.TrimSpace(rawUnit)
|
|
} else {
|
|
unit = strings.TrimSpace(strings.ToLower(rawUnit))
|
|
}
|
|
unitValue, loaded := unitTable[unit]
|
|
if !loaded {
|
|
return fmt.Errorf("unsupported unit: %s", rawUnit)
|
|
}
|
|
b.value = value * unitValue
|
|
b.unit = rawUnit
|
|
b.unitValue = unitValue
|
|
return nil
|
|
}
|
|
|
|
type Bytes struct {
|
|
rawBytes
|
|
}
|
|
|
|
func (b *Bytes) Value() uint64 {
|
|
if b == nil {
|
|
return 0
|
|
}
|
|
return b.value
|
|
}
|
|
|
|
func (b *Bytes) UnmarshalJSON(bytes []byte) error {
|
|
return parseUnit(&b.rawBytes, unitValueTable, false, bytes)
|
|
}
|
|
|
|
type MemoryBytes struct {
|
|
rawBytes
|
|
}
|
|
|
|
func (m *MemoryBytes) Value() uint64 {
|
|
if m == nil {
|
|
return 0
|
|
}
|
|
return m.value
|
|
}
|
|
|
|
func (m *MemoryBytes) UnmarshalJSON(bytes []byte) error {
|
|
return parseUnit(&m.rawBytes, memoryUnitValueTable, false, bytes)
|
|
}
|
|
|
|
type NetworkBytes struct {
|
|
rawBytes
|
|
}
|
|
|
|
func (n *NetworkBytes) Value() uint64 {
|
|
if n == nil {
|
|
return 0
|
|
}
|
|
return n.value
|
|
}
|
|
|
|
func (n *NetworkBytes) UnmarshalJSON(bytes []byte) error {
|
|
return parseUnit(&n.rawBytes, networkUnitValueTable, true, bytes)
|
|
}
|
|
|
|
type NetworkBytesCompat struct {
|
|
rawBytes
|
|
}
|
|
|
|
func (n *NetworkBytesCompat) Value() uint64 {
|
|
if n == nil {
|
|
return 0
|
|
}
|
|
return n.value
|
|
}
|
|
|
|
func (n *NetworkBytesCompat) UnmarshalJSON(bytes []byte) error {
|
|
err := parseUnit(&n.rawBytes, networkUnitValueTable, true, bytes)
|
|
if err != nil {
|
|
newErr := parseUnit(&n.rawBytes, unitValueTable, false, bytes)
|
|
if newErr == nil {
|
|
return nil
|
|
}
|
|
}
|
|
return err
|
|
}
|