Repository navigation
Expand file tree
/
Copy pathguid.go
More file actions
133 lines (125 loc) · 4.18 KB
/
Copy pathguid.go
File metadata and controls
133 lines (125 loc) · 4.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Copyright 2020 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
// Package guid provides simple and high performance unique id generation functionality.
//
// PLEASE VERY NOTE:
// This package only provides unique number generation for simple, convenient and most common
// usage purpose, but does not provide strict global unique number generation. Please refer
// to UUID algorithm for global unique number generation if necessary.
package guid
import (
"github.com/gogf/gf/container/gtype"
"github.com/gogf/gf/encoding/ghash"
"github.com/gogf/gf/net/gipv4"
"github.com/gogf/gf/util/gconv"
"github.com/gogf/gf/util/grand"
"os"
"strconv"
"time"
)
var (
sequence gtype.Uint32 // Sequence for unique purpose of current process.
sequenceMax = uint32(46655) // Sequence max("zzz").
randomStrBase = "0123456789abcdefghijklmnopqrstuvwxyz" // Random chars string(36 bytes).
macAddrStr = "0000000" // MAC addresses hash result in 7 bytes.
processIdStr = "0000" // Process id in 4 bytes.
)
// init initializes several fixed local variable.
func init() {
// MAC addresses hash result in 7 bytes.
macs, _ := gipv4.GetMacArray()
if len(macs) > 0 {
var macAddrBytes []byte
for _, mac := range macs {
macAddrBytes = append(macAddrBytes, []byte(mac)...)
}
b := []byte{'0', '0', '0', '0', '0', '0', '0'}
s := strconv.FormatUint(uint64(ghash.DJBHash(macAddrBytes)), 36)
copy(b, s)
macAddrStr = string(b)
}
// Process id in 4 bytes.
{
b := []byte{'0', '0', '0', '0'}
s := strconv.FormatInt(int64(os.Getpid()), 36)
copy(b, s)
processIdStr = string(b)
}
}
// S creates and returns a global unique string in 32 bytes that meets most common
// usages without strict UUID algorithm. It returns an unique string using default
// unique algorithm if no <data> is given.
//
// The specified <data> can be no more than 2 count. No matter how long each of the
// <data> size is, each of them will be hashed into 7 bytes as part of the result.
// If given <data> count is less than 2, the leftover size of the result bytes will
// be token by random string.
//
// The returned string is composed with:
// 1. Default: MAC(7) + PID(4) + TimestampNano(12) + Sequence(3) + RandomString(6)
// 2. CustomData: Data(7/14) + TimestampNano(12) + Sequence(3) + RandomString(3/10)
//
// Note that:
// 1. The returned length is fixed to 32 bytes for performance purpose.
// 2. The custom parameter <data> composed should have unique attribute in your
// business situation.
func S(data ...[]byte) string {
var (
b = make([]byte, 32)
nanoStr = strconv.FormatInt(time.Now().UnixNano(), 36)
)
if len(data) == 0 {
copy(b, macAddrStr)
copy(b[7:], processIdStr)
copy(b[11:], nanoStr)
copy(b[23:], getSequence())
copy(b[26:], getRandomStr(6))
} else if len(data) <= 2 {
n := 0
for i, v := range data {
// Ignore empty data item bytes.
if len(v) > 0 {
copy(b[i*7:], getDataHashStr(v))
n += 7
}
}
copy(b[n:], nanoStr)
copy(b[n+12:], getSequence())
copy(b[n+12+3:], getRandomStr(32-n-12-3))
} else {
panic("data count too long, no more than 2")
}
return gconv.UnsafeBytesToStr(b)
}
// getSequence increases and returns the sequence string in 3 bytes.
// The sequence is less than "zzz"(46655).
func getSequence() []byte {
b := []byte{'0', '0', '0'}
s := strconv.FormatUint(uint64(sequence.Add(1)%sequenceMax), 36)
copy(b, s)
return b
}
// getRandomStr randomly picks and returns <n> count of chars from randomStrBase.
func getRandomStr(n int) []byte {
if n <= 0 {
return []byte{}
}
var (
b = make([]byte, n)
numberBytes = grand.B(n)
)
for i := range b {
b[i] = randomStrBase[numberBytes[i]%36]
}
return b
}
// getDataHashStr creates and returns hash bytes in 7 bytes with given data bytes.
func getDataHashStr(data []byte) []byte {
b := []byte{'0', '0', '0', '0', '0', '0', '0'}
s := strconv.FormatUint(uint64(ghash.DJBHash(data)), 36)
copy(b, s)
return b
}