Files

194 lines
3.7 KiB
Go

package utils
import (
"crypto/rand"
"encoding/hex"
"fmt"
"net"
"strconv"
"strings"
"time"
)
// GenerateID 生成唯一 ID
func GenerateID() string {
b := make([]byte, 16)
rand.Read(b)
return hex.EncodeToString(b)
}
// GenerateNodeID 生成节点 ID
func GenerateNodeID(prefix string) string {
return fmt.Sprintf("%s_%s_%d", prefix, GenerateID()[:8], time.Now().Unix())
}
// FormatBytes 格式化字节数
func FormatBytes(bytes int64) string {
const unit = 1024
if bytes < unit {
return fmt.Sprintf("%d B", bytes)
}
div, exp := int64(unit), 0
for n := bytes / unit; n >= unit; n /= unit {
div *= unit
exp++
}
return fmt.Sprintf("%.1f %ciB", float64(bytes)/float64(div), "KMGTPE"[exp])
}
// ParseBytes 解析字节字符串
func ParseBytes(s string) (int64, error) {
s = strings.TrimSpace(s)
s = strings.ToUpper(s)
multiplier := int64(1)
if strings.HasSuffix(s, "KB") {
multiplier = 1024
s = strings.TrimSuffix(s, "KB")
} else if strings.HasSuffix(s, "MB") {
multiplier = 1024 * 1024
s = strings.TrimSuffix(s, "MB")
} else if strings.HasSuffix(s, "GB") {
multiplier = 1024 * 1024 * 1024
s = strings.TrimSuffix(s, "GB")
} else if strings.HasSuffix(s, "TB") {
multiplier = 1024 * 1024 * 1024 * 1024
s = strings.TrimSuffix(s, "TB")
}
value, err := strconv.ParseInt(strings.TrimSpace(s), 10, 64)
if err != nil {
return 0, err
}
return value * multiplier, nil
}
// FormatDuration 格式化持续时间
func FormatDuration(d time.Duration) string {
if d < time.Second {
return fmt.Sprintf("%dms", d.Milliseconds())
}
if d < time.Minute {
return fmt.Sprintf("%.1fs", d.Seconds())
}
if d < time.Hour {
return fmt.Sprintf("%.1fm", d.Minutes())
}
return fmt.Sprintf("%.1fh", d.Hours())
}
// IsPrivateIP 检查是否为私有 IP
func IsPrivateIP(ip string) bool {
ipAddr := net.ParseIP(ip)
if ipAddr == nil {
return false
}
privateBlocks := []string{
"10.0.0.0/8",
"172.16.0.0/12",
"192.168.0.0/16",
"127.0.0.0/8",
}
for _, block := range privateBlocks {
_, cidr, _ := net.ParseCIDR(block)
if cidr.Contains(ipAddr) {
return true
}
}
return false
}
// IsValidPort 检查端口是否有效
func IsValidPort(port int) bool {
return port > 0 && port <= 65535
}
// ParseHostPort 解析主机:端口
func ParseHostPort(addr string) (host string, port int, err error) {
parts := strings.Split(addr, ":")
if len(parts) != 2 {
return "", 0, fmt.Errorf("invalid address format")
}
host = parts[0]
port, err = strconv.Atoi(parts[1])
if err != nil {
return "", 0, fmt.Errorf("invalid port: %v", err)
}
if !IsValidPort(port) {
return "", 0, fmt.Errorf("port out of range")
}
return host, port, nil
}
// Contains 检查字符串切片是否包含某元素
func Contains(slice []string, item string) bool {
for _, s := range slice {
if s == item {
return true
}
}
return false
}
// Unique 去重
func Unique(slice []string) []string {
keys := make(map[string]bool)
result := []string{}
for _, item := range slice {
if !keys[item] {
keys[item] = true
result = append(result, item)
}
}
return result
}
// Retry 重试函数
func Retry(fn func() error, maxAttempts int, delay time.Duration) error {
var lastErr error
for i := 0; i < maxAttempts; i++ {
if err := fn(); err != nil {
lastErr = err
if i < maxAttempts-1 {
time.Sleep(delay)
}
continue
}
return nil
}
return fmt.Errorf("after %d attempts, last error: %v", maxAttempts, lastErr)
}
// Min 返回最小值
func Min(a, b int) int {
if a < b {
return a
}
return b
}
// Max 返回最大值
func Max(a, b int) int {
if a > b {
return a
}
return b
}
// Clamp 将值限制在范围内
func Clamp(value, min, max int) int {
if value < min {
return min
}
if value > max {
return max
}
return value
}