Files
backend/internal/pkg/utils/snowflake.go
lan 9a1851f023
Some checks failed
Build Backend / build (push) Successful in 1m56s
Build Backend / build-docker (push) Has been cancelled
refactor: cleanup unused code and simplify internal packages
This commit performs a significant cleanup of the codebase by removing unused functions, methods, and entire files across various internal modules. This reduces technical debt and simplifies the project structure.

Key changes include:
- **cache**: Removed unused cache key generators and metrics snapshots.
- **dto**: Removed redundant converter functions and segment creation helpers.
- **middleware**: Deleted the unused `logger.go` middleware and simplified `ratelimit.go` and `casbin.go`.
- **model**: Removed unused ID helpers, database closing functions, and batch decryption logic.
- **pkg**: Cleaned up unused utility functions in `circuitbreaker`, `crypto`, `cursor`, `hook`, and `utils`.
- **service**: Deleted `account_cleanup_service.go` and removed unused helper functions in `log_cleanup_service.go` and `sensitive_service.go`.
- **repository**: Removed unused private loading methods in `comment_repo.go`.
2026-05-14 02:24:30 +08:00

197 lines
4.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package utils
import (
"errors"
"os"
"sync"
"time"
)
// 雪花算法常量定义
const (
// 64位ID结构1位符号位 + 41位时间戳 + 10位机器ID + 12位序列号
// 机器ID占用的位数
nodeIDBits uint64 = 10
// 序列号占用的位数
sequenceBits uint64 = 12
// 机器ID的最大值 (0-1023)
maxNodeID int64 = -1 ^ (-1 << nodeIDBits)
// 序列号的最大值 (0-4095)
maxSequence int64 = -1 ^ (-1 << sequenceBits)
// 机器ID左移位数
nodeIDShift uint64 = sequenceBits
// 时间戳左移位数
timestampShift uint64 = sequenceBits + nodeIDBits
// 自定义纪元时间2024-01-01 00:00:00 UTC
// 使用自定义纪元可以延长ID有效期约24年从2024年开始
customEpoch int64 = 1704067200000 // 2024-01-01 00:00:00 UTC 的毫秒时间戳
)
// 错误定义
var (
// ErrInvalidNodeID 机器ID无效
ErrInvalidNodeID = errors.New("node ID must be between 0 and 1023")
// ErrClockBackwards 时钟回拨
ErrClockBackwards = errors.New("clock moved backwards, refusing to generate ID")
)
// IDInfo 解析后的ID信息
type IDInfo struct {
Timestamp int64 // 生成ID时的时间戳毫秒
NodeID int64 // 机器ID
Sequence int64 // 序列号
}
// Snowflake 雪花算法ID生成器
type Snowflake struct {
mu sync.Mutex // 互斥锁,保证线程安全
nodeID int64 // 机器ID (0-1023)
sequence int64 // 当前序列号 (0-4095)
lastTimestamp int64 // 上次生成ID的时间戳
}
// 全局雪花算法实例
var (
globalSnowflake *Snowflake
globalSnowflakeOnce sync.Once
globalSnowflakeErr error
)
// GetSnowflake 获取全局雪花算法实例
// 如果未初始化,会自动使用默认配置初始化
func GetSnowflake() *Snowflake {
globalSnowflakeOnce.Do(func() {
if globalSnowflake == nil {
globalSnowflake, globalSnowflakeErr = NewSnowflake(-1)
}
})
return globalSnowflake
}
// NewSnowflake 创建雪花算法ID生成器实例
// nodeID: 机器ID范围0-1023可以通过环境变量 NODE_ID 配置
// 如果nodeID为-1则尝试从环境变量 NODE_ID 读取
func NewSnowflake(nodeID int64) (*Snowflake, error) {
// 如果传入-1尝试从环境变量读取
if nodeID == -1 {
nodeIDStr := os.Getenv("NODE_ID")
if nodeIDStr != "" {
// 解析环境变量
parsedID, err := parseInt(nodeIDStr)
if err != nil {
return nil, ErrInvalidNodeID
}
nodeID = parsedID
} else {
// 默认使用0
nodeID = 0
}
}
// 验证机器ID范围
if nodeID < 0 || nodeID > maxNodeID {
return nil, ErrInvalidNodeID
}
return &Snowflake{
nodeID: nodeID,
sequence: 0,
lastTimestamp: 0,
}, nil
}
// parseInt 辅助函数:解析整数
func parseInt(s string) (int64, error) {
var result int64
var negative bool
if len(s) == 0 {
return 0, errors.New("empty string")
}
i := 0
if s[0] == '-' {
negative = true
i = 1
}
for ; i < len(s); i++ {
if s[i] < '0' || s[i] > '9' {
return 0, errors.New("invalid character")
}
result = result*10 + int64(s[i]-'0')
}
if negative {
result = -result
}
return result, nil
}
// GenerateID 生成唯一的雪花算法ID
// 返回值生成的ID以及可能的错误如时钟回拨
// 线程安全:使用互斥锁保证并发安全
func (s *Snowflake) GenerateID() (int64, error) {
s.mu.Lock()
defer s.mu.Unlock()
// 获取当前时间戳(毫秒)
now := currentTimestamp()
// 处理时钟回拨
if now < s.lastTimestamp {
return 0, ErrClockBackwards
}
// 同一毫秒内
if now == s.lastTimestamp {
// 序列号递增
s.sequence = (s.sequence + 1) & maxSequence
// 序列号溢出,等待下一毫秒
if s.sequence == 0 {
now = s.waitNextMillis(now)
}
} else {
// 不同毫秒序列号重置为0
s.sequence = 0
}
// 更新上次生成时间
s.lastTimestamp = now
// 组装ID
// ID结构时间戳部分 | 机器ID部分 | 序列号部分
id := ((now - customEpoch) << timestampShift) |
(s.nodeID << nodeIDShift) |
s.sequence
return id, nil
}
// waitNextMillis 等待到下一毫秒
// 参数:当前时间戳
// 返回值:下一毫秒的时间戳
func (s *Snowflake) waitNextMillis(timestamp int64) int64 {
now := currentTimestamp()
for now <= timestamp {
now = currentTimestamp()
}
return now
}
// currentTimestamp 获取当前时间戳(毫秒)
func currentTimestamp() int64 {
return time.Now().UnixNano() / 1e6
}