| | |
| | | |
| | | import ( |
| | | "apsClient/pkg/logx" |
| | | "errors" |
| | | "fmt" |
| | | "github.com/bwmarrin/snowflake" |
| | | "hash/fnv" |
| | | "net" |
| | | "strconv" |
| | | "sync" |
| | | "time" |
| | | ) |
| | | |
| | | var Node *snowflake.Node |
| | | var idGenerater *IdWorker |
| | | |
| | | func Init(nodeId int64) error { |
| | | // Create a new Node with a Node number of 0~1023 |
| | | var err error |
| | | Node, err = snowflake.NewNode(nodeId) |
| | | if err != nil { |
| | | logx.Errorf("snowflake NewNode error:%v", err) |
| | | return err |
| | | } |
| | | return nil |
| | | } |
| | | |
| | | func InitWithIP() { |
| | | func init() { |
| | | // 使用 LookupIP 获取主机的 IP 地址列表 |
| | | // 获取本机所有网络接口 |
| | | interfaces, err := net.Interfaces() |
| | |
| | | logx.Errorf("snowflake can not generate, init error, ip to number error :%v", err) |
| | | panic(fmt.Sprintf("snowflake can not generate, init error, ip to number error :%v", err)) |
| | | } |
| | | err = Init(ipNumber) |
| | | idGenerater, err = NewIdWorker(ipNumber) |
| | | if err != nil { |
| | | logx.Errorf("snowflake can not generate, init error :%v", err) |
| | | panic(fmt.Sprintf("snowflake can not generate, init error :%v", err)) |
| | | } |
| | | } |
| | | |
| | | func StringToNumber(input string) (int64, error) { |
| | | hash := fnv.New32a() |
| | | _, err := hash.Write([]byte(input)) |
| | | if err != nil { |
| | | return 0, err |
| | | } |
| | | return int64(hash.Sum32() % 1024), nil // 取余数确保结果在 1 到 1023 之间 |
| | | } |
| | | |
| | | func ipToNumber(ip string) (int64, error) { |
| | |
| | | return int64(hash.Sum32() % 1024), nil // 取余数确保结果在 1 到 1023 之间 |
| | | } |
| | | |
| | | func GenerateID() int64 { |
| | | if Node == nil { |
| | | InitWithIP() |
| | | const ( |
| | | CEpoch = 1474802888000 |
| | | CWorkerIdBits = 10 // Num of WorkerId Bits |
| | | CSenquenceBits = 12 // Num of Sequence Bits |
| | | |
| | | CWorkerIdShift = 12 |
| | | CTimeStampShift = 22 |
| | | |
| | | CSequenceMask = 0xfff // equal as getSequenceMask() |
| | | CMaxWorker = 0x3ff // equal as getMaxWorkerId() |
| | | ) |
| | | |
| | | type IdWorker struct { |
| | | workerId int64 |
| | | lastTimeStamp int64 |
| | | sequence int64 |
| | | maxWorkerId int64 |
| | | lock *sync.Mutex |
| | | } |
| | | |
| | | func NewIdWorker(workerId int64) (iw *IdWorker, err error) { |
| | | iw = new(IdWorker) |
| | | |
| | | iw.maxWorkerId = getMaxWorkerId() |
| | | |
| | | if workerId > iw.maxWorkerId || workerId < 0 { |
| | | return nil, errors.New("worker not fit") |
| | | } |
| | | return int64(Node.Generate()) |
| | | iw.workerId = workerId |
| | | iw.lastTimeStamp = -1 |
| | | iw.sequence = 0 |
| | | iw.lock = new(sync.Mutex) |
| | | return iw, nil |
| | | } |
| | | |
| | | func getMaxWorkerId() int64 { |
| | | return -1 ^ -1<<CWorkerIdBits |
| | | } |
| | | |
| | | func getSequenceMask() int64 { |
| | | return -1 ^ -1<<CSenquenceBits |
| | | } |
| | | |
| | | // return in ms |
| | | func (iw *IdWorker) timeGen() int64 { |
| | | return time.Now().UnixNano() / 1000 / 1000 |
| | | } |
| | | |
| | | func (iw *IdWorker) timeReGen(last int64) int64 { |
| | | ts := time.Now().UnixNano() / 1000 / 1000 |
| | | for { |
| | | if ts <= last { |
| | | ts = iw.timeGen() |
| | | } else { |
| | | break |
| | | } |
| | | } |
| | | return ts |
| | | } |
| | | |
| | | func (iw *IdWorker) NextId() (ts int64, err error) { |
| | | iw.lock.Lock() |
| | | defer iw.lock.Unlock() |
| | | ts = iw.timeGen() |
| | | if ts == iw.lastTimeStamp { |
| | | iw.sequence = (iw.sequence + 1) & CSequenceMask |
| | | if iw.sequence == 0 { |
| | | ts = iw.timeReGen(ts) |
| | | } |
| | | } else { |
| | | iw.sequence = 0 |
| | | } |
| | | |
| | | if ts < iw.lastTimeStamp { |
| | | err = errors.New("Clock moved backwards, Refuse gen id") |
| | | return 0, err |
| | | } |
| | | iw.lastTimeStamp = ts |
| | | ts = (ts-CEpoch)<<CTimeStampShift | iw.workerId<<CWorkerIdShift | iw.sequence |
| | | return ts, nil |
| | | } |
| | | |
| | | func ParseId(id int64) (t time.Time, ts int64, workerId int64, seq int64) { |
| | | seq = id & CSequenceMask |
| | | workerId = (id >> CWorkerIdShift) & CMaxWorker |
| | | ts = (id >> CTimeStampShift) + CEpoch |
| | | t = time.Unix(ts/1000, (ts%1000)*1000000) |
| | | return |
| | | } |
| | | |
| | | func GenerateID() int64 { |
| | | start: |
| | | id, err := idGenerater.NextId() |
| | | if err != nil { |
| | | goto start |
| | | } |
| | | return id |
| | | } |
| | | |
| | | func GenerateIdStr() string { |
| | | start: |
| | | id, err := idGenerater.NextId() |
| | | if err != nil { |
| | | goto start |
| | | } |
| | | return strconv.FormatInt(id, 10) |
| | | } |