1515package utils
1616
1717import (
18+ "crypto/rand"
1819 "crypto/sha1"
20+ "encoding/binary"
1921 "fmt"
2022 "os"
23+ "sync"
24+ "time"
2125
2226 "github.com/jxskiss/base62"
2327 "github.com/lithammer/shortuuid/v4"
2428
2529 "github.com/livekit/protocol/livekit"
30+ "github.com/livekit/protocol/logger"
2631)
2732
2833const GuidSize = 12
@@ -45,8 +50,10 @@ const (
4550 AgentJobPrefix = "AJ_"
4651)
4752
53+ var defaultGuidGenerator = newGuidGenerator (4096 , GuidSize + 10 )
54+
4855func NewGuid (prefix string ) string {
49- return prefix + shortuuid . New ()[: GuidSize ]
56+ return defaultGuidGenerator . NewGuid ( prefix )
5057}
5158
5259// HashedID creates a hashed ID from a unique string
@@ -66,17 +73,91 @@ func LocalNodeID() (string, error) {
6673 return fmt .Sprintf ("%s%s" , NodePrefix , HashedID (hostname )[:8 ]), nil
6774}
6875
69- var b62Index = newB62Index ()
70- var b62Chars = []byte (shortuuid .DefaultAlphabet )
76+ var b57Index = newB57Index ()
77+ var b57Chars = []byte (shortuuid .DefaultAlphabet )
7178
72- func newB62Index () [256 ]byte {
79+ func newB57Index () [256 ]byte {
7380 var index [256 ]byte
74- for i := 0 ; i < len (b62Chars ); i ++ {
75- index [b62Chars [i ]] = byte (i )
81+ for i := 0 ; i < len (b57Chars ); i ++ {
82+ index [b57Chars [i ]] = byte (i )
7683 }
7784 return index
7885}
7986
87+ type guidGenerator struct {
88+ pool sync.Pool
89+ mu sync.Mutex
90+ buf []byte
91+ pos int
92+ }
93+
94+ func newGuidGenerator (bufSize , scratchSize int ) * guidGenerator {
95+ return & guidGenerator {
96+ pool : sync.Pool {
97+ New : func () any {
98+ b := make ([]byte , scratchSize )
99+ return & b
100+ },
101+ },
102+ buf : make ([]byte , bufSize ),
103+ pos : bufSize ,
104+ }
105+ }
106+
107+ func (g * guidGenerator ) refillBuf () {
108+ for {
109+ _ , err := rand .Read (g .buf )
110+ if err == nil {
111+ return
112+ }
113+
114+ logger .Errorw ("unable to refill guid buffer" , err )
115+ time .Sleep (time .Millisecond )
116+ }
117+ }
118+
119+ func (g * guidGenerator ) uint32 () uint32 {
120+ if g .pos == len (g .buf ) {
121+ g .refillBuf ()
122+ g .pos = 0
123+ }
124+
125+ n := binary .BigEndian .Uint32 (g .buf [g .pos :])
126+ g .pos += 4
127+
128+ return n
129+ }
130+
131+ func (g * guidGenerator ) readIDChars (b []byte ) {
132+ g .mu .Lock ()
133+ defer g .mu .Unlock ()
134+
135+ var n int
136+ for {
137+ r := g .uint32 ()
138+ for i := 0 ; i < 5 ; i ++ {
139+ if int (r & 0x3f ) < len (b57Chars ) {
140+ b [n ] = b57Chars [r & 0x3f ]
141+ n ++
142+ if n == len (b ) {
143+ return
144+ }
145+ }
146+ r >>= 6
147+ }
148+ }
149+ }
150+
151+ func (g * guidGenerator ) NewGuid (prefix string ) string {
152+ b := g .pool .Get ().(* []byte )
153+ defer g .pool .Put (b )
154+
155+ * b = append ((* b )[:0 ], make ([]byte , len (prefix )+ GuidSize )... )
156+ copy (* b , prefix )
157+ g .readIDChars ((* b )[len (prefix ):])
158+ return string (* b )
159+ }
160+
80161func guidPrefix [T livekit.Guid ]() string {
81162 var id T
82163 switch any (id ).(type ) {
@@ -97,9 +178,9 @@ func MarshalGuid[T livekit.Guid](id T) livekit.GuidBlock {
97178 for i := 0 ; i < 3 ; i ++ {
98179 j := i * 3
99180 k := i * 4
100- b [j ] = b62Index [idb [k ]]<< 2 | b62Index [idb [k + 1 ]]>> 4
101- b [j + 1 ] = b62Index [idb [k + 1 ]]<< 4 | b62Index [idb [k + 2 ]]>> 2
102- b [j + 2 ] = b62Index [idb [k + 2 ]]<< 6 | b62Index [idb [k + 3 ]]
181+ b [j ] = b57Index [idb [k ]]<< 2 | b57Index [idb [k + 1 ]]>> 4
182+ b [j + 1 ] = b57Index [idb [k + 1 ]]<< 4 | b57Index [idb [k + 2 ]]>> 2
183+ b [j + 2 ] = b57Index [idb [k + 2 ]]<< 6 | b57Index [idb [k + 3 ]]
103184 }
104185 return b
105186}
@@ -112,10 +193,10 @@ func UnmarshalGuid[T livekit.Guid](b livekit.GuidBlock) T {
112193 for i := 0 ; i < 3 ; i ++ {
113194 j := i * 3
114195 k := i * 4
115- idb [k ] = b62Chars [b [j ]>> 2 ]
116- idb [k + 1 ] = b62Chars [(b [j ]& 3 )<< 4 | b [j + 1 ]>> 4 ]
117- idb [k + 2 ] = b62Chars [(b [j + 1 ]& 15 )<< 2 | b [j + 2 ]>> 6 ]
118- idb [k + 3 ] = b62Chars [b [j + 2 ]& 63 ]
196+ idb [k ] = b57Chars [b [j ]>> 2 ]
197+ idb [k + 1 ] = b57Chars [(b [j ]& 3 )<< 4 | b [j + 1 ]>> 4 ]
198+ idb [k + 2 ] = b57Chars [(b [j + 1 ]& 15 )<< 2 | b [j + 2 ]>> 6 ]
199+ idb [k + 3 ] = b57Chars [b [j + 2 ]& 63 ]
119200 }
120201 return T (id )
121202}
0 commit comments