drop uuid and use modified nanoid

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
This commit is contained in:
Василий Толстов 2021-08-20 22:40:48 +03:00
parent 4509323cae
commit a45b672c98
21 changed files with 310 additions and 49 deletions

View File

@ -55,7 +55,7 @@ type Auth interface {
type Account struct { type Account struct {
// Metadata any other associated metadata // Metadata any other associated metadata
Metadata metadata.Metadata `json:"metadata"` Metadata metadata.Metadata `json:"metadata"`
// ID of the account e.g. email or uuid // ID of the account e.g. email or id
ID string `json:"id"` ID string `json:"id"`
// Type of the account, e.g. service // Type of the account, e.g. service
Type string `json:"type"` Type string `json:"type"`

View File

@ -1,7 +1,7 @@
package auth package auth
import ( import (
"github.com/google/uuid" "github.com/unistack-org/micro/v3/util/id"
) )
type noopAuth struct { type noopAuth struct {
@ -61,11 +61,11 @@ func (n *noopAuth) Verify(acc *Account, res *Resource, opts ...VerifyOption) err
// Inspect a token // Inspect a token
func (n *noopAuth) Inspect(token string) (*Account, error) { func (n *noopAuth) Inspect(token string) (*Account, error) {
uid, err := uuid.NewRandom() id, err := id.New()
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &Account{ID: uid.String(), Issuer: n.Options().Issuer}, nil return &Account{ID: id, Issuer: n.Options().Issuer}, nil
} }
// Token generation using an account id and secret // Token generation using an account id and secret

View File

@ -4,10 +4,10 @@ import (
"context" "context"
"sync" "sync"
"github.com/google/uuid"
"github.com/unistack-org/micro/v3/logger" "github.com/unistack-org/micro/v3/logger"
"github.com/unistack-org/micro/v3/metadata" "github.com/unistack-org/micro/v3/metadata"
maddr "github.com/unistack-org/micro/v3/util/addr" maddr "github.com/unistack-org/micro/v3/util/addr"
"github.com/unistack-org/micro/v3/util/id"
mnet "github.com/unistack-org/micro/v3/util/net" mnet "github.com/unistack-org/micro/v3/util/net"
"github.com/unistack-org/micro/v3/util/rand" "github.com/unistack-org/micro/v3/util/rand"
) )
@ -224,7 +224,7 @@ func (m *memoryBroker) BatchSubscribe(ctx context.Context, topic string, handler
} }
m.RUnlock() m.RUnlock()
id, err := uuid.NewRandom() sid, err := id.New()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -233,7 +233,7 @@ func (m *memoryBroker) BatchSubscribe(ctx context.Context, topic string, handler
sub := &memorySubscriber{ sub := &memorySubscriber{
exit: make(chan bool, 1), exit: make(chan bool, 1),
id: id.String(), id: sid,
topic: topic, topic: topic,
batchhandler: handler, batchhandler: handler,
opts: options, opts: options,
@ -269,7 +269,7 @@ func (m *memoryBroker) Subscribe(ctx context.Context, topic string, handler Hand
} }
m.RUnlock() m.RUnlock()
id, err := uuid.NewRandom() sid, err := id.New()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -278,7 +278,7 @@ func (m *memoryBroker) Subscribe(ctx context.Context, topic string, handler Hand
sub := &memorySubscriber{ sub := &memorySubscriber{
exit: make(chan bool, 1), exit: make(chan bool, 1),
id: id.String(), id: sid,
topic: topic, topic: topic,
handler: handler, handler: handler,
opts: options, opts: options,

View File

@ -37,7 +37,7 @@ var (
// Error type // Error type
type Error struct { type Error struct {
// Id holds error id or service, usually someting like my_service or uuid // Id holds error id or service, usually someting like my_service or id
Id string Id string
// Detail holds some useful details about error // Detail holds some useful details about error
Detail string Detail string

View File

@ -6,13 +6,13 @@ import (
"path/filepath" "path/filepath"
"sync" "sync"
"github.com/google/uuid"
"github.com/silas/dag" "github.com/silas/dag"
"github.com/unistack-org/micro/v3/client" "github.com/unistack-org/micro/v3/client"
"github.com/unistack-org/micro/v3/codec" "github.com/unistack-org/micro/v3/codec"
"github.com/unistack-org/micro/v3/logger" "github.com/unistack-org/micro/v3/logger"
"github.com/unistack-org/micro/v3/metadata" "github.com/unistack-org/micro/v3/metadata"
"github.com/unistack-org/micro/v3/store" "github.com/unistack-org/micro/v3/store"
"github.com/unistack-org/micro/v3/util/id"
) )
type microFlow struct { type microFlow struct {
@ -149,18 +149,18 @@ func (w *microWorkflow) getSteps(start string, reverse bool) ([][]Step, error) {
return steps, nil return steps, nil
} }
func (w *microWorkflow) Abort(ctx context.Context, eid string) error { func (w *microWorkflow) Abort(ctx context.Context, id string) error {
workflowStore := store.NewNamespaceStore(w.opts.Store, filepath.Join("workflows", eid)) workflowStore := store.NewNamespaceStore(w.opts.Store, filepath.Join("workflows", id))
return workflowStore.Write(ctx, "status", &codec.Frame{Data: []byte(StatusAborted.String())}) return workflowStore.Write(ctx, "status", &codec.Frame{Data: []byte(StatusAborted.String())})
} }
func (w *microWorkflow) Suspend(ctx context.Context, eid string) error { func (w *microWorkflow) Suspend(ctx context.Context, id string) error {
workflowStore := store.NewNamespaceStore(w.opts.Store, filepath.Join("workflows", eid)) workflowStore := store.NewNamespaceStore(w.opts.Store, filepath.Join("workflows", id))
return workflowStore.Write(ctx, "status", &codec.Frame{Data: []byte(StatusSuspend.String())}) return workflowStore.Write(ctx, "status", &codec.Frame{Data: []byte(StatusSuspend.String())})
} }
func (w *microWorkflow) Resume(ctx context.Context, eid string) error { func (w *microWorkflow) Resume(ctx context.Context, id string) error {
workflowStore := store.NewNamespaceStore(w.opts.Store, filepath.Join("workflows", eid)) workflowStore := store.NewNamespaceStore(w.opts.Store, filepath.Join("workflows", id))
return workflowStore.Write(ctx, "status", &codec.Frame{Data: []byte(StatusRunning.String())}) return workflowStore.Write(ctx, "status", &codec.Frame{Data: []byte(StatusRunning.String())})
} }
@ -176,14 +176,13 @@ func (w *microWorkflow) Execute(ctx context.Context, req *Message, opts ...Execu
} }
w.Unlock() w.Unlock()
uid, err := uuid.NewRandom() id, err := id.New()
if err != nil { if err != nil {
return "", err return "", err
} }
eid := uid.String()
stepStore := store.NewNamespaceStore(w.opts.Store, filepath.Join("steps", eid)) stepStore := store.NewNamespaceStore(w.opts.Store, filepath.Join("steps", id))
workflowStore := store.NewNamespaceStore(w.opts.Store, filepath.Join("workflows", eid)) workflowStore := store.NewNamespaceStore(w.opts.Store, filepath.Join("workflows", id))
options := NewExecuteOptions(opts...) options := NewExecuteOptions(opts...)
@ -215,13 +214,13 @@ func (w *microWorkflow) Execute(ctx context.Context, req *Message, opts ...Execu
if werr := workflowStore.Write(w.opts.Context, "status", &codec.Frame{Data: []byte(StatusRunning.String())}); werr != nil { if werr := workflowStore.Write(w.opts.Context, "status", &codec.Frame{Data: []byte(StatusRunning.String())}); werr != nil {
w.opts.Logger.Errorf(w.opts.Context, "store error: %v", werr) w.opts.Logger.Errorf(w.opts.Context, "store error: %v", werr)
return eid, werr return id, werr
} }
for idx := range steps { for idx := range steps {
for nidx := range steps[idx] { for nidx := range steps[idx] {
cstep := steps[idx][nidx] cstep := steps[idx][nidx]
if werr := stepStore.Write(ctx, filepath.Join(cstep.ID(), "status"), &codec.Frame{Data: []byte(StatusPending.String())}); werr != nil { if werr := stepStore.Write(ctx, filepath.Join(cstep.ID(), "status"), &codec.Frame{Data: []byte(StatusPending.String())}); werr != nil {
return eid, werr return id, werr
} }
} }
} }
@ -317,7 +316,7 @@ func (w *microWorkflow) Execute(ctx context.Context, req *Message, opts ...Execu
}() }()
if options.Async { if options.Async {
return eid, nil return id, nil
} }
logger.Tracef(ctx, "wait for finish or error") logger.Tracef(ctx, "wait for finish or error")

View File

@ -116,11 +116,11 @@ type Workflow interface {
// Steps returns steps slice where parallel steps returned on the same level // Steps returns steps slice where parallel steps returned on the same level
Steps() ([][]Step, error) Steps() ([][]Step, error)
// Suspend suspends execution // Suspend suspends execution
Suspend(ctx context.Context, eid string) error Suspend(ctx context.Context, id string) error
// Resume resumes execution // Resume resumes execution
Resume(ctx context.Context, eid string) error Resume(ctx context.Context, id string) error
// Abort abort execution // Abort abort execution
Abort(ctx context.Context, eid string) error Abort(ctx context.Context, id string) error
} }
// Flow the base interface to interact with workflows // Flow the base interface to interact with workflows

2
go.mod
View File

@ -5,10 +5,10 @@ go 1.16
require ( require (
github.com/ef-ds/deque v1.0.4 github.com/ef-ds/deque v1.0.4
github.com/golang-jwt/jwt/v4 v4.0.0 github.com/golang-jwt/jwt/v4 v4.0.0
github.com/google/uuid v1.3.0
github.com/imdario/mergo v0.3.12 github.com/imdario/mergo v0.3.12
github.com/patrickmn/go-cache v2.1.0+incompatible github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/silas/dag v0.0.0-20210121180416-41cf55125c34 github.com/silas/dag v0.0.0-20210121180416-41cf55125c34
github.com/stretchr/testify v1.7.0
github.com/unistack-org/micro-proto v0.0.5 github.com/unistack-org/micro-proto v0.0.5
golang.org/x/net v0.0.0-20210510120150-4163338589ed golang.org/x/net v0.0.0-20210510120150-4163338589ed
) )

12
go.sum
View File

@ -1,3 +1,5 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/ef-ds/deque v1.0.4 h1:iFAZNmveMT9WERAkqLJ+oaABF9AcVQ5AjXem/hroniI= github.com/ef-ds/deque v1.0.4 h1:iFAZNmveMT9WERAkqLJ+oaABF9AcVQ5AjXem/hroniI=
github.com/ef-ds/deque v1.0.4/go.mod h1:gXDnTC3yqvBcHbq2lcExjtAcVrOnJCbMcZXmuj8Z4tg= github.com/ef-ds/deque v1.0.4/go.mod h1:gXDnTC3yqvBcHbq2lcExjtAcVrOnJCbMcZXmuj8Z4tg=
github.com/golang-jwt/jwt/v4 v4.0.0 h1:RAqyYixv1p7uEnocuy8P1nru5wprCh/MH2BIlW5z5/o= github.com/golang-jwt/jwt/v4 v4.0.0 h1:RAqyYixv1p7uEnocuy8P1nru5wprCh/MH2BIlW5z5/o=
@ -5,14 +7,17 @@ github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzw
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/silas/dag v0.0.0-20210121180416-41cf55125c34 h1:vBfVmA5mZhsQa2jr1FOL9nfA37N/jnbBmi5XUfviVTI= github.com/silas/dag v0.0.0-20210121180416-41cf55125c34 h1:vBfVmA5mZhsQa2jr1FOL9nfA37N/jnbBmi5XUfviVTI=
github.com/silas/dag v0.0.0-20210121180416-41cf55125c34/go.mod h1:7RTUFBdIRC9nZ7/3RyRNH1bdqIShrDejd1YbLwgPS+I= github.com/silas/dag v0.0.0-20210121180416-41cf55125c34/go.mod h1:7RTUFBdIRC9nZ7/3RyRNH1bdqIShrDejd1YbLwgPS+I=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/unistack-org/micro-proto v0.0.5 h1:DIC97Hufa2nGjuvTsfToD9laEOKddWMRTzeCfBwJ1j8= github.com/unistack-org/micro-proto v0.0.5 h1:DIC97Hufa2nGjuvTsfToD9laEOKddWMRTzeCfBwJ1j8=
github.com/unistack-org/micro-proto v0.0.5/go.mod h1:EuI7UlfGXmT1hy6WacULib9LbNgRnDYQvTCFoLgKM2I= github.com/unistack-org/micro-proto v0.0.5/go.mod h1:EuI7UlfGXmT1hy6WacULib9LbNgRnDYQvTCFoLgKM2I=
golang.org/x/net v0.0.0-20210510120150-4163338589ed h1:p9UgmWI9wKpfYmgaV/IZKGdXc5qEK45tDwwwDyjS26I= golang.org/x/net v0.0.0-20210510120150-4163338589ed h1:p9UgmWI9wKpfYmgaV/IZKGdXc5qEK45tDwwwDyjS26I=
@ -27,6 +32,9 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -1,13 +1,13 @@
package network package network
import ( import (
"github.com/google/uuid"
"github.com/unistack-org/micro/v3/logger" "github.com/unistack-org/micro/v3/logger"
"github.com/unistack-org/micro/v3/meter" "github.com/unistack-org/micro/v3/meter"
"github.com/unistack-org/micro/v3/network/tunnel" "github.com/unistack-org/micro/v3/network/tunnel"
"github.com/unistack-org/micro/v3/proxy" "github.com/unistack-org/micro/v3/proxy"
"github.com/unistack-org/micro/v3/router" "github.com/unistack-org/micro/v3/router"
"github.com/unistack-org/micro/v3/tracer" "github.com/unistack-org/micro/v3/tracer"
"github.com/unistack-org/micro/v3/util/id"
) )
// Option func // Option func
@ -119,7 +119,7 @@ func Tracer(t tracer.Tracer) Option {
// NewOptions returns network default options // NewOptions returns network default options
func NewOptions(opts ...Option) Options { func NewOptions(opts ...Option) Options {
options := Options{ options := Options{
Id: uuid.New().String(), Id: id.Must(),
Name: "go.micro", Name: "go.micro",
Address: ":0", Address: ":0",
Logger: logger.DefaultLogger, Logger: logger.DefaultLogger,

View File

@ -3,11 +3,11 @@ package tunnel
import ( import (
"time" "time"
"github.com/google/uuid"
"github.com/unistack-org/micro/v3/logger" "github.com/unistack-org/micro/v3/logger"
"github.com/unistack-org/micro/v3/meter" "github.com/unistack-org/micro/v3/meter"
"github.com/unistack-org/micro/v3/network/transport" "github.com/unistack-org/micro/v3/network/transport"
"github.com/unistack-org/micro/v3/tracer" "github.com/unistack-org/micro/v3/tracer"
"github.com/unistack-org/micro/v3/util/id"
) )
var ( var (
@ -164,7 +164,7 @@ func DialWait(b bool) DialOption {
// NewOptions returns router default options with filled values // NewOptions returns router default options with filled values
func NewOptions(opts ...Option) Options { func NewOptions(opts ...Option) Options {
options := Options{ options := Options{
ID: uuid.New().String(), ID: id.Must(),
Address: DefaultAddress, Address: DefaultAddress,
Token: DefaultToken, Token: DefaultToken,
Logger: logger.DefaultLogger, Logger: logger.DefaultLogger,

View File

@ -6,8 +6,8 @@ import (
"sync" "sync"
"time" "time"
"github.com/google/uuid"
"github.com/unistack-org/micro/v3/logger" "github.com/unistack-org/micro/v3/logger"
"github.com/unistack-org/micro/v3/util/id"
) )
var ( var (
@ -378,13 +378,16 @@ func (m *memory) ListServices(ctx context.Context, opts ...ListOption) ([]*Servi
} }
func (m *memory) Watch(ctx context.Context, opts ...WatchOption) (Watcher, error) { func (m *memory) Watch(ctx context.Context, opts ...WatchOption) (Watcher, error) {
id, err := id.New()
if err != nil {
return nil, err
}
wo := NewWatchOptions(opts...) wo := NewWatchOptions(opts...)
// construct the watcher // construct the watcher
w := &watcher{ w := &watcher{
exit: make(chan bool), exit: make(chan bool),
res: make(chan *Result), res: make(chan *Result),
id: uuid.New().String(), id: id,
wo: wo, wo: wo,
} }

View File

@ -3,9 +3,9 @@ package router
import ( import (
"context" "context"
"github.com/google/uuid"
"github.com/unistack-org/micro/v3/logger" "github.com/unistack-org/micro/v3/logger"
"github.com/unistack-org/micro/v3/register" "github.com/unistack-org/micro/v3/register"
"github.com/unistack-org/micro/v3/util/id"
) )
// Options are router options // Options are router options
@ -80,7 +80,7 @@ func Name(n string) Option {
// NewOptions returns router default options // NewOptions returns router default options
func NewOptions(opts ...Option) Options { func NewOptions(opts ...Option) Options {
options := Options{ options := Options{
Id: uuid.New().String(), Id: id.Must(),
Network: DefaultNetwork, Network: DefaultNetwork,
Register: register.DefaultRegister, Register: register.DefaultRegister,
Logger: logger.DefaultLogger, Logger: logger.DefaultLogger,

View File

@ -5,10 +5,10 @@ import (
"context" "context"
"time" "time"
"github.com/google/uuid"
"github.com/unistack-org/micro/v3/codec" "github.com/unistack-org/micro/v3/codec"
"github.com/unistack-org/micro/v3/metadata" "github.com/unistack-org/micro/v3/metadata"
"github.com/unistack-org/micro/v3/register" "github.com/unistack-org/micro/v3/register"
"github.com/unistack-org/micro/v3/util/id"
) )
// DefaultServer default server // DefaultServer default server
@ -22,7 +22,7 @@ var (
// DefaultVersion will be used if no version passed // DefaultVersion will be used if no version passed
DefaultVersion = "latest" DefaultVersion = "latest"
// DefaultID will be used if no id passed // DefaultID will be used if no id passed
DefaultID = uuid.New().String() DefaultID = id.Must()
// DefaultRegisterCheck holds func that run before register server // DefaultRegisterCheck holds func that run before register server
DefaultRegisterCheck = func(context.Context) error { return nil } DefaultRegisterCheck = func(context.Context) error { return nil }
// DefaultRegisterInterval holds interval for register // DefaultRegisterInterval holds interval for register

View File

@ -4,9 +4,9 @@ import (
"context" "context"
"time" "time"
"github.com/google/uuid"
"github.com/unistack-org/micro/v3/auth" "github.com/unistack-org/micro/v3/auth"
"github.com/unistack-org/micro/v3/logger" "github.com/unistack-org/micro/v3/logger"
"github.com/unistack-org/micro/v3/util/id"
) )
// Verify the auth credentials and refresh the auth token periodically // Verify the auth credentials and refresh the auth token periodically
@ -22,7 +22,11 @@ func Verify(a auth.Auth) error {
auth.WithScopes("service"), auth.WithScopes("service"),
} }
acc, err := a.Generate(uuid.New().String(), opts...) id, err := id.New()
if err != nil {
return err
}
acc, err := a.Generate(id, opts...)
if err != nil { if err != nil {
return err return err
} }

22
util/id/LICENSE Normal file
View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2018-2021 Matous Dzivjak <matousdzivjak@gmail.com>
Copyright (c) 2021 Unistack LLC <v.tolstov@unistack.org>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

108
util/id/id.go Normal file
View File

@ -0,0 +1,108 @@
package id
import (
"crypto/rand"
"errors"
"math"
)
// DefaultAlphabet is the alphabet used for ID characters by default
var DefaultAlphabet = []rune("6789BCDFGHJKLMNPQRTWbcdfghjkmnpqrtwz")
// DefaultSize is the size used for ID by default
var DefaultSize = 16
// getMask generates bit mask used to obtain bits from the random bytes that are used to get index of random character
// from the alphabet. Example: if the alphabet has 6 = (110)_2 characters it is sufficient to use mask 7 = (111)_2
func getMask(alphabetSize int) int {
for i := 1; i <= 8; i++ {
mask := (2 << uint(i)) - 1
if mask >= alphabetSize-1 {
return mask
}
}
return 0
}
// New returns new id or error
func New(opts ...Option) (string, error) {
options := NewOptions(opts...)
if len(options.Alphabet) == 0 || len(options.Alphabet) > 255 {
return "", errors.New("alphabet must not be empty and contain no more than 255 chars")
}
if options.Size <= 0 {
return "", errors.New("size must be positive integer")
}
chars := options.Alphabet
mask := getMask(len(chars))
// estimate how many random bytes we will need for the ID, we might actually need more but this is tradeoff
// between average case and worst case
ceilArg := 1.6 * float64(mask*options.Size) / float64(len(options.Alphabet))
step := int(math.Ceil(ceilArg))
id := make([]rune, options.Size)
bytes := make([]byte, step)
for j := 0; ; {
_, err := rand.Read(bytes)
if err != nil {
return "", err
}
for i := 0; i < step; i++ {
currByte := bytes[i] & byte(mask)
if currByte < byte(len(chars)) {
id[j] = chars[currByte]
j++
if j == options.Size {
return string(id[:options.Size]), nil
}
}
}
}
}
// Must is the same as New but panics on error
func Must(opts ...Option) string {
id, err := New(opts...)
if err != nil {
panic(err)
}
return id
}
// Options contains id deneration options
type Options struct {
Alphabet []rune
Size int
}
// Option func signature
type Option func(*Options)
// Alphabet specifies alphabet to use
func Alphabet(alphabet string) Option {
return func(o *Options) {
o.Alphabet = []rune(alphabet)
}
}
// Size specifies id size
func Size(size int) Option {
return func(o *Options) {
o.Size = size
}
}
// NewOptions returns new Options struct filled by opts
func NewOptions(opts ...Option) Options {
options := Options{
Alphabet: DefaultAlphabet,
Size: DefaultSize,
}
for _, o := range opts {
o(&options)
}
return options
}

View File

@ -0,0 +1,41 @@
package id
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestHasNoCollisions(t *testing.T) {
tries := 100_000
used := make(map[string]bool, tries)
for i := 0; i < tries; i++ {
id := Must()
require.False(t, used[id], "shouldn't return colliding IDs")
used[id] = true
}
}
func TestFlatDistribution(t *testing.T) {
tries := 100_000
alphabet := "abcdefghij"
size := 10
chars := make(map[rune]int)
for i := 0; i < tries; i++ {
id := Must(Alphabet(alphabet), Size(size))
for _, r := range id {
chars[r]++
}
}
for _, count := range chars {
require.InEpsilon(t, size*tries/len(alphabet), count, .01, "should have flat distribution")
}
}
// Benchmark id generator
func BenchmarkNanoid(b *testing.B) {
for n := 0; n < b.N; n++ {
_, _ = New()
}
}

68
util/id/id_test.go Normal file
View File

@ -0,0 +1,68 @@
package id_test
import (
"strings"
"testing"
"unicode/utf8"
"github.com/stretchr/testify/assert"
id "github.com/unistack-org/micro/v3/util/id"
)
func TestGenerate(t *testing.T) {
t.Run("short alphabet", func(t *testing.T) {
alphabet := ""
_, err := id.New(id.Alphabet(alphabet), id.Size(32))
assert.Error(t, err, "should return error if the alphabet is too small")
})
t.Run("long alphabet", func(t *testing.T) {
alphabet := strings.Repeat("a", 256)
_, err := id.New(id.Alphabet(alphabet), id.Size(32))
assert.Error(t, err, "should return error if the alphabet is too long")
})
t.Run("negative ID length", func(t *testing.T) {
_, err := id.New(id.Alphabet("abcdef"), id.Size(-1))
assert.Error(t, err, "should return error if the requested ID length is invalid")
})
t.Run("happy path", func(t *testing.T) {
alphabet := "abcdef"
id, err := id.New(id.Alphabet(alphabet), id.Size(6))
assert.NoError(t, err, "shouldn't return error")
assert.Len(t, id, 6, "should return ID of requested length")
for _, r := range id {
assert.True(t, strings.ContainsRune(alphabet, r), "should use given alphabet")
}
})
t.Run("works with unicode", func(t *testing.T) {
alphabet := "🚀💩🦄🤖"
id, err := id.New(id.Alphabet(alphabet), id.Size(6))
assert.NoError(t, err, "shouldn't return error")
assert.Equal(t, utf8.RuneCountInString(id), 6, "should return ID of requested length")
for _, r := range id {
assert.True(t, strings.ContainsRune(alphabet, r), "should use given alphabet")
}
})
}
func TestNew(t *testing.T) {
t.Run("negative ID length", func(t *testing.T) {
_, err := id.New(id.Size(-1))
assert.Error(t, err, "should return error if the requested ID length is invalid")
})
t.Run("happy path", func(t *testing.T) {
nid, err := id.New()
assert.NoError(t, err, "shouldn't return error")
assert.Len(t, nid, id.DefaultSize, "should return ID of default length")
})
t.Run("custom length", func(t *testing.T) {
id, err := id.New(id.Size(6))
assert.NoError(t, err, "shouldn't return error")
assert.Len(t, id, 6, "should return ID of requested length")
})
}

View File

@ -5,8 +5,8 @@ import (
"sync" "sync"
"time" "time"
"github.com/google/uuid"
"github.com/unistack-org/micro/v3/network/transport" "github.com/unistack-org/micro/v3/network/transport"
"github.com/unistack-org/micro/v3/util/id"
) )
type pool struct { type pool struct {
@ -87,9 +87,13 @@ func (p *pool) Get(ctx context.Context, addr string, opts ...transport.DialOptio
if err != nil { if err != nil {
return nil, err return nil, err
} }
id, err := id.New()
if err != nil {
return nil, err
}
return &poolConn{ return &poolConn{
Client: c, Client: c,
id: uuid.New().String(), id: id,
created: time.Now(), created: time.Now(),
}, nil }, nil
} }

View File

@ -5,7 +5,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/google/uuid" "github.com/unistack-org/micro/v3/util/id"
) )
// Buffer is ring buffer // Buffer is ring buffer
@ -112,7 +112,7 @@ func (b *Buffer) Stream() (<-chan *Entry, chan bool) {
defer b.Unlock() defer b.Unlock()
entries := make(chan *Entry, 128) entries := make(chan *Entry, 128)
id := uuid.New().String() id := id.Must()
stop := make(chan bool) stop := make(chan bool)
b.streams[id] = &Stream{ b.streams[id] = &Stream{

View File

@ -6,9 +6,9 @@ import (
"fmt" "fmt"
"time" "time"
"github.com/google/uuid"
"github.com/unistack-org/micro/v3/auth" "github.com/unistack-org/micro/v3/auth"
"github.com/unistack-org/micro/v3/store" "github.com/unistack-org/micro/v3/store"
"github.com/unistack-org/micro/v3/util/id"
"github.com/unistack-org/micro/v3/util/token" "github.com/unistack-org/micro/v3/util/token"
) )
@ -44,7 +44,11 @@ func (b *Basic) Generate(acc *auth.Account, opts ...token.GenerateOption) (*toke
} }
// write to the store // write to the store
key := uuid.New().String() key, err := id.New()
if err !=nil {
return nil, err
}
err = b.store.Write(context.Background(), fmt.Sprintf("%v%v", StorePrefix, key), bytes, store.WriteTTL(options.Expiry)) err = b.store.Write(context.Background(), fmt.Sprintf("%v%v", StorePrefix, key), bytes, store.WriteTTL(options.Expiry))
if err != nil { if err != nil {
return nil, err return nil, err