Compare commits

..

No commits in common. "v3" and "v3.11.12" have entirely different histories.
v3 ... v3.11.12

101 changed files with 630 additions and 1272 deletions

View File

@ -1,51 +0,0 @@
name: coverage
on:
push:
branches: [ main, v3, v4 ]
pull_request:
branches: [ main, v3, v4 ]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: checkout code
uses: actions/checkout@v4
with:
filter: 'blob:none'
- name: setup go
uses: actions/setup-go@v5
with:
cache-dependency-path: "**/*.sum"
go-version: 'stable'
- name: test coverage
run: |
go test -v -cover ./... -coverprofile coverage.out -coverpkg ./...
go tool cover -func coverage.out -o coverage.out
- name: coverage badge
uses: tj-actions/coverage-badge-go@v1
with:
green: 80
filename: coverage.out
- uses: stefanzweifel/git-auto-commit-action@v4
id: auto-commit-action
with:
commit_message: Apply Code Coverage Badge
skip_fetch: true
skip_checkout: true
file_pattern: ./README.md
- name: Push Changes
if: steps.auto-commit-action.outputs.changes_detected == 'true'
uses: ad-m/github-push-action@master
with:
github_token: ${{ github.token }}
branch: ${{ github.ref }}

View File

@ -12,18 +12,15 @@ jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: checkout code
uses: actions/checkout@v4
with:
filter: 'blob:none'
- name: setup go
- name: setup-go
uses: actions/setup-go@v5
with:
cache-dependency-path: "**/*.sum"
go-version: 'stable'
- name: setup deps
run: go get -v ./...
- name: run lint
go-version: 'stable'
- name: checkout
uses: actions/checkout@v3
- name: deps
run: go get -v -d ./...
- name: lint
uses: https://github.com/golangci/golangci-lint-action@v6
with:
version: 'latest'

View File

@ -17,18 +17,15 @@ jobs:
test:
runs-on: ubuntu-latest
steps:
- name: checkout code
uses: actions/checkout@v4
with:
filter: 'blob:none'
- name: setup go
- name: setup-go
uses: actions/setup-go@v5
with:
cache-dependency-path: "**/*.sum"
go-version: 'stable'
- name: setup deps
run: go get -v ./...
- name: run test
- name: checkout
uses: actions/checkout@v3
- name: deps
run: go get -v -d ./...
- name: test
env:
INTEGRATION_TESTS: yes
run: go test -mod readonly -v ./...

View File

@ -1,53 +0,0 @@
name: test
on:
pull_request:
types: [opened, reopened, synchronize]
branches:
- master
- v3
- v4
push:
branches:
- master
- v3
- v4
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: checkout code
uses: actions/checkout@v4
with:
filter: 'blob:none'
- name: checkout tests
uses: actions/checkout@v4
with:
ref: master
filter: 'blob:none'
repository: unistack-org/micro-tests
path: micro-tests
- name: setup go
uses: actions/setup-go@v5
with:
cache-dependency-path: "**/*.sum"
go-version: 'stable'
- name: setup go work
env:
GOWORK: /workspace/${{ github.repository_owner }}/go.work
run: |
go work init
go work use .
go work use micro-tests
- name: setup deps
env:
GOWORK: /workspace/${{ github.repository_owner }}/go.work
run: go get -v ./...
- name: run tests
env:
INTEGRATION_TESTS: yes
GOWORK: /workspace/${{ github.repository_owner }}/go.work
run: |
cd micro-tests
go test -mod readonly -v ./... || true

View File

@ -1,5 +1,4 @@
# Micro
[![License](https://img.shields.io/:license-apache-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![Doc](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white&style=flat-square)](https://pkg.go.dev/github.com/unistack-org/micro/v3?tab=overview) [![Status](https://git.unistack.org/unistack-org/micro/actions/workflows/job_tests.yml/badge.svg?branch=v3)](https://git.unistack.org/unistack-org/micro/actions?query=workflow%3Abuild+branch%3Av3+event%3Apush) [![Lint](https://goreportcard.com/badge/go.unistack.org/micro/v3)](https://goreportcard.com/report/go.unistack.org/micro/v3)![Coverage](https://img.shields.io/badge/Coverage-44.9%25-yellow)
# Micro [![License](https://img.shields.io/:license-apache-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![Doc](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white&style=flat-square)](https://pkg.go.dev/github.com/unistack-org/micro/v3?tab=overview) [![Status](https://github.com/unistack-org/micro/workflows/build/badge.svg?branch=master)](https://github.com/unistack-org/micro/actions?query=workflow%3Abuild+branch%3Amaster+event%3Apush) [![Lint](https://goreportcard.com/badge/go.unistack.org/micro/v3)](https://goreportcard.com/report/go.unistack.org/micro/v3) [![Coverage](https://codecov.io/gh/unistack-org/micro/branch/v3/graph/badge.svg?token=OZPO2LP7VS)](https://codecov.io/gh/unistack-org/micro)
Micro is a standard library for microservices.

View File

@ -15,15 +15,6 @@ func FromContext(ctx context.Context) (Broker, bool) {
return c, ok
}
// MustContext returns broker from passed context
func MustContext(ctx context.Context) Broker {
b, ok := FromContext(ctx)
if !ok {
panic("missing broker")
}
return b
}
// NewContext savess broker in context
func NewContext(ctx context.Context, s Broker) context.Context {
if ctx == nil {

View File

@ -109,7 +109,7 @@ func (m *memoryBroker) Init(opts ...broker.Option) error {
m.funcSubscribe = m.fnSubscribe
m.funcBatchSubscribe = m.fnBatchSubscribe
m.opts.Hooks.EachPrev(func(hook options.Hook) {
m.opts.Hooks.EachNext(func(hook options.Hook) {
switch h := hook.(type) {
case broker.HookPublish:
m.funcPublish = h(m.funcPublish)

View File

@ -74,7 +74,7 @@ func TestMemoryBroker(t *testing.T) {
topic := "test"
count := 10
fn := func(_ broker.Event) error {
fn := func(p broker.Event) error {
return nil
}

View File

@ -59,7 +59,7 @@ func (b *NoopBroker) Init(opts ...Option) error {
b.funcSubscribe = b.fnSubscribe
b.funcBatchSubscribe = b.fnBatchSubscribe
b.opts.Hooks.EachPrev(func(hook options.Hook) {
b.opts.Hooks.EachNext(func(hook options.Hook) {
switch h := hook.(type) {
case HookPublish:
b.funcPublish = h(b.funcPublish)

View File

@ -16,9 +16,6 @@ import (
// Options struct
type Options struct {
// Name holds the broker name
Name string
// Tracer used for tracing
Tracer tracer.Tracer
// Register can be used for clustering
@ -31,25 +28,23 @@ type Options struct {
Meter meter.Meter
// Context holds external options
Context context.Context
// Wait waits for a collection of goroutines to finish
Wait *sync.WaitGroup
// TLSConfig holds tls.TLSConfig options
TLSConfig *tls.Config
// ErrorHandler used when broker can't unmarshal incoming message
ErrorHandler Handler
// BatchErrorHandler used when broker can't unmashal incoming messages
BatchErrorHandler BatchHandler
// Name holds the broker name
Name string
// Addrs holds the broker address
Addrs []string
// Wait waits for a collection of goroutines to finish
Wait *sync.WaitGroup
// GracefulTimeout contains time to wait to finish in flight requests
GracefulTimeout time.Duration
// Hooks can be run before broker Publish/BatchPublish and
// Subscribe/BatchSubscribe methods
Hooks options.Hooks
// GracefulTimeout contains time to wait to finish in flight requests
GracefulTimeout time.Duration
}
// NewOptions create new Options

View File

@ -17,13 +17,13 @@ func BackoffExp(_ context.Context, _ Request, attempts int) (time.Duration, erro
}
// BackoffInterval specifies randomization interval for backoff func
func BackoffInterval(minTime time.Duration, maxTime time.Duration) BackoffFunc {
func BackoffInterval(min time.Duration, max time.Duration) BackoffFunc {
return func(_ context.Context, _ Request, attempts int) (time.Duration, error) {
td := time.Duration(math.Pow(float64(attempts), math.E)) * time.Millisecond * 100
if td < minTime {
return minTime, nil
} else if td > maxTime {
return maxTime, nil
if td < min {
return min, nil
} else if td > max {
return max, nil
}
return td, nil
}

View File

@ -34,23 +34,23 @@ func TestBackoffExp(t *testing.T) {
}
func TestBackoffInterval(t *testing.T) {
minTime := 100 * time.Millisecond
maxTime := 300 * time.Millisecond
min := 100 * time.Millisecond
max := 300 * time.Millisecond
r := &testRequest{
service: "test",
method: "test",
}
fn := BackoffInterval(minTime, maxTime)
fn := BackoffInterval(min, max)
for i := 0; i < 5; i++ {
d, err := fn(context.TODO(), r, i)
if err != nil {
t.Fatal(err)
}
if d < minTime || d > maxTime {
t.Fatalf("Expected %v < %v < %v", minTime, d, maxTime)
if d < min || d > max {
t.Fatalf("Expected %v < %v < %v", min, d, max)
}
}
}

View File

@ -15,15 +15,6 @@ func FromContext(ctx context.Context) (Client, bool) {
return c, ok
}
// MustContext get client from context
func MustContext(ctx context.Context) Client {
c, ok := FromContext(ctx)
if !ok {
panic("missing client")
}
return c
}
// NewContext put client in context
func NewContext(ctx context.Context, c Client) context.Context {
if ctx == nil {

View File

@ -194,7 +194,7 @@ func (n *noopClient) Init(opts ...Option) error {
n.funcPublish = n.fnPublish
n.funcBatchPublish = n.fnBatchPublish
n.opts.Hooks.EachPrev(func(hook options.Hook) {
n.opts.Hooks.EachNext(func(hook options.Hook) {
switch h := hook.(type) {
case HookCall:
n.funcCall = h(n.funcCall)
@ -222,7 +222,7 @@ func (n *noopClient) Call(ctx context.Context, req Request, rsp interface{}, opt
ts := time.Now()
n.opts.Meter.Counter(semconv.ClientRequestInflight, "endpoint", req.Endpoint()).Inc()
var sp tracer.Span
ctx, sp = n.opts.Tracer.Start(ctx, "rpc-client",
ctx, sp = n.opts.Tracer.Start(ctx, req.Endpoint()+" rpc-client",
tracer.WithSpanKind(tracer.SpanKindClient),
tracer.WithSpanLabels("endpoint", req.Endpoint()),
)
@ -298,7 +298,7 @@ func (n *noopClient) fnCall(ctx context.Context, req Request, rsp interface{}, o
// call backoff first. Someone may want an initial start delay
t, err := callOpts.Backoff(ctx, req, i)
if err != nil {
return errors.InternalServerError("go.micro.client", "%s", err)
return errors.InternalServerError("go.micro.client", "%s", err.Error())
}
// only sleep if greater than 0
@ -312,7 +312,7 @@ func (n *noopClient) fnCall(ctx context.Context, req Request, rsp interface{}, o
// TODO apply any filtering here
routes, err = n.opts.Lookup(ctx, req, callOpts)
if err != nil {
return errors.InternalServerError("go.micro.client", "%s", err)
return errors.InternalServerError("go.micro.client", "%s", err.Error())
}
// balance the list of nodes
@ -372,7 +372,7 @@ func (n *noopClient) fnCall(ctx context.Context, req Request, rsp interface{}, o
return gerr
}
func (n *noopClient) NewRequest(service, endpoint string, _ interface{}, _ ...RequestOption) Request {
func (n *noopClient) NewRequest(service, endpoint string, req interface{}, opts ...RequestOption) Request {
return &noopRequest{service: service, endpoint: endpoint}
}
@ -385,7 +385,7 @@ func (n *noopClient) Stream(ctx context.Context, req Request, opts ...CallOption
ts := time.Now()
n.opts.Meter.Counter(semconv.ClientRequestInflight, "endpoint", req.Endpoint()).Inc()
var sp tracer.Span
ctx, sp = n.opts.Tracer.Start(ctx, "rpc-client",
ctx, sp = n.opts.Tracer.Start(ctx, req.Endpoint()+" rpc-client",
tracer.WithSpanKind(tracer.SpanKindClient),
tracer.WithSpanLabels("endpoint", req.Endpoint()),
)
@ -466,7 +466,7 @@ func (n *noopClient) fnStream(ctx context.Context, req Request, opts ...CallOpti
// call backoff first. Someone may want an initial start delay
t, cerr := callOpts.Backoff(ctx, req, i)
if cerr != nil {
return nil, errors.InternalServerError("go.micro.client", "%s", cerr)
return nil, errors.InternalServerError("go.micro.client", "%s", cerr.Error())
}
// only sleep if greater than 0
@ -480,7 +480,7 @@ func (n *noopClient) fnStream(ctx context.Context, req Request, opts ...CallOpti
// TODO apply any filtering here
routes, err = n.opts.Lookup(ctx, req, callOpts)
if err != nil {
return nil, errors.InternalServerError("go.micro.client", "%s", err)
return nil, errors.InternalServerError("go.micro.client", "%s", err.Error())
}
// balance the list of nodes
@ -546,7 +546,7 @@ func (n *noopClient) fnStream(ctx context.Context, req Request, opts ...CallOpti
return nil, grr
}
func (n *noopClient) stream(ctx context.Context, _ string, _ Request, _ CallOptions) (Stream, error) {
func (n *noopClient) stream(ctx context.Context, addr string, req Request, opts CallOptions) (Stream, error) {
return &noopStream{ctx: ctx}, nil
}
@ -609,13 +609,13 @@ func (n *noopClient) publish(ctx context.Context, ps []Message, opts ...PublishO
// use codec for payload
cf, err := n.newCodec(p.ContentType())
if err != nil {
return errors.InternalServerError("go.micro.client", "%s", err)
return errors.InternalServerError("go.micro.client", "%s", err.Error())
}
// set the body
b, err := cf.Marshal(p.Payload())
if err != nil {
return errors.InternalServerError("go.micro.client", "%s", err)
return errors.InternalServerError("go.micro.client", "%s", err.Error())
}
body = b
}

View File

@ -21,16 +21,6 @@ import (
// Options holds client options
type Options struct {
// Codecs map
Codecs map[string]codec.Codec
// Proxy is used for proxy requests
Proxy string
// ContentType is used to select codec
ContentType string
// Name is the client name
Name string
// Selector used to select needed address
Selector selector.Selector
// Logger used to log messages
@ -45,28 +35,31 @@ type Options struct {
Context context.Context
// Router used to get route
Router router.Router
// TLSConfig specifies tls.Config for secure connection
TLSConfig *tls.Config
// Codecs map
Codecs map[string]codec.Codec
// Lookup func used to get destination addr
Lookup LookupFunc
// ContextDialer used to connect
ContextDialer func(context.Context, string) (net.Conn, error)
// Proxy is used for proxy requests
Proxy string
// ContentType is used to select codec
ContentType string
// Name is the client name
Name string
// Wrappers contains wrappers
Wrappers []Wrapper
// Hooks can be run before broker Publish/BatchPublish and
// Subscribe/BatchSubscribe methods
Hooks options.Hooks
// CallOptions contains default CallOptions
CallOptions CallOptions
// PoolSize connection pool size
PoolSize int
// PoolTTL connection pool ttl
PoolTTL time.Duration
// ContextDialer used to connect
ContextDialer func(context.Context, string) (net.Conn, error)
// Hooks can be run before broker Publish/BatchPublish and
// Subscribe/BatchSubscribe methods
Hooks options.Hooks
}
// NewCallOptions creates new call options struct
@ -80,16 +73,6 @@ func NewCallOptions(opts ...CallOption) CallOptions {
// CallOptions holds client call options
type CallOptions struct {
// RequestMetadata holds additional metadata for call
RequestMetadata metadata.Metadata
// Network name
Network string
// Content-Type
ContentType string
// AuthToken string
AuthToken string
// Selector selects addr
Selector selector.Selector
// Context used for deadline
@ -97,30 +80,33 @@ type CallOptions struct {
// Router used for route
Router router.Router
// Retry func used for retries
// ResponseMetadata holds additional metadata from call
ResponseMetadata *metadata.Metadata
Retry RetryFunc
// Backoff func used for backoff when retry
Backoff BackoffFunc
// ContextDialer used to connect
ContextDialer func(context.Context, string) (net.Conn, error)
// Network name
Network string
// Content-Type
ContentType string
// AuthToken string
AuthToken string
// Address specifies static addr list
Address []string
// SelectOptions selector options
SelectOptions []selector.SelectOption
// StreamTimeout stream timeout
StreamTimeout time.Duration
// RequestTimeout request timeout
RequestTimeout time.Duration
// RequestMetadata holds additional metadata for call
RequestMetadata metadata.Metadata
// ResponseMetadata holds additional metadata from call
ResponseMetadata *metadata.Metadata
// DialTimeout dial timeout
DialTimeout time.Duration
// Retries specifies retries num
Retries int
// ContextDialer used to connect
ContextDialer func(context.Context, string) (net.Conn, error)
}
// ContextDialer pass ContextDialer to client

View File

@ -15,15 +15,6 @@ func FromContext(ctx context.Context) (Codec, bool) {
return c, ok
}
// MustContext returns codec from context
func MustContext(ctx context.Context) Codec {
c, ok := FromContext(ctx)
if !ok {
panic("missing codec")
}
return c
}
// NewContext put codec in context
func NewContext(ctx context.Context, c Codec) context.Context {
if ctx == nil {

View File

@ -13,7 +13,7 @@ type Validator interface {
}
// DefaultConfig default config
var DefaultConfig = NewConfig()
var DefaultConfig Config = NewConfig()
// DefaultWatcherMinInterval default min interval for poll changes
var DefaultWatcherMinInterval = 5 * time.Second

View File

@ -15,15 +15,6 @@ func FromContext(ctx context.Context) (Config, bool) {
return c, ok
}
// MustContext returns store from context
func MustContext(ctx context.Context) Config {
c, ok := FromContext(ctx)
if !ok {
panic("missing config")
}
return c
}
// NewContext put store in context
func NewContext(ctx context.Context, c Config) context.Context {
if ctx == nil {

View File

@ -37,7 +37,7 @@ func (c *defaultConfig) Init(opts ...Option) error {
c.funcLoad = c.fnLoad
c.funcSave = c.fnSave
c.opts.Hooks.EachPrev(func(hook options.Hook) {
c.opts.Hooks.EachNext(func(hook options.Hook) {
switch h := hook.(type) {
case HookLoad:
c.funcLoad = h(c.funcLoad)

View File

@ -3,26 +3,24 @@ package config_test
import (
"context"
"fmt"
"reflect"
"testing"
"time"
"go.unistack.org/micro/v3/config"
mid "go.unistack.org/micro/v3/util/id"
mtime "go.unistack.org/micro/v3/util/time"
)
type cfg struct {
MapValue map[string]bool `default:"key1=true,key2=false"`
StructValue *cfgStructValue
StringValue string `default:"string_value"`
IgnoreValue string `json:"-"`
UUIDValue string `default:"micro:generate uuid"`
IDValue string `default:"micro:generate id"`
DurationValue time.Duration `default:"10s"`
MDurationValue mtime.Duration `default:"10s"`
IntValue int `default:"99"`
StringValue string `default:"string_value"`
IgnoreValue string `json:"-"`
StructValue *cfgStructValue
IntValue int `default:"99"`
DurationValue time.Duration `default:"10s"`
MDurationValue mtime.Duration `default:"10s"`
MapValue map[string]bool `default:"key1=true,key2=false"`
UUIDValue string `default:"micro:generate uuid"`
IDValue string `default:"micro:generate id"`
}
type cfgStructValue struct {
@ -114,6 +112,8 @@ func TestDefault(t *testing.T) {
if conf.IDValue == "" {
t.Fatalf("id value empty")
} else if len(conf.IDValue) != mid.DefaultSize {
t.Fatalf("id value invalid: %s", conf.IDValue)
}
_ = conf
// t.Logf("%#+v\n", conf)
@ -134,13 +134,3 @@ func TestValidate(t *testing.T) {
t.Fatal(err)
}
}
func Test_SizeOf(t *testing.T) {
st := cfg{}
tVal := reflect.TypeOf(st)
for i := 0; i < tVal.NumField(); i++ {
field := tVal.Field(i)
fmt.Printf("Field: %s, Offset: %d, Size: %d\n", field.Name, field.Offset, field.Type.Size())
}
}

View File

@ -41,16 +41,14 @@ type Options struct {
BeforeInit []func(context.Context, Config) error
// AfterInit contains slice of funcs that runs after Init
AfterInit []func(context.Context, Config) error
// AllowFail flag to allow fail in config source
AllowFail bool
// SkipLoad runs only if condition returns true
SkipLoad func(context.Context, Config) bool
// SkipSave runs only if condition returns true
SkipSave func(context.Context, Config) bool
// Hooks can be run before/after config Save/Load
Hooks options.Hooks
// AllowFail flag to allow fail in config source
AllowFail bool
}
// Option function signature
@ -280,10 +278,10 @@ func WatchCoalesce(b bool) WatchOption {
}
// WatchInterval specifies min and max time.Duration for pulling changes
func WatchInterval(minTime, maxTime time.Duration) WatchOption {
func WatchInterval(min, max time.Duration) WatchOption {
return func(o *WatchOptions) {
o.MinInterval = minTime
o.MaxInterval = maxTime
o.MinInterval = min
o.MaxInterval = max
}
}

View File

@ -3,6 +3,7 @@ package errors
import (
"encoding/json"
"errors"
er "errors"
"fmt"
"net/http"
"testing"
@ -42,7 +43,7 @@ func TestFromError(t *testing.T) {
if merr.ID != "go.micro.test" || merr.Code != 404 {
t.Fatalf("invalid conversation %v != %v", err, merr)
}
err = errors.New(err.Error())
err = er.New(err.Error())
merr = FromError(err)
if merr.ID != "go.micro.test" || merr.Code != 404 {
t.Fatalf("invalid conversation %v != %v", err, merr)
@ -57,7 +58,7 @@ func TestEqual(t *testing.T) {
t.Fatal("errors must be equal")
}
err3 := errors.New("my test err")
err3 := er.New("my test err")
if Equal(err1, err3) {
t.Fatal("errors must be not equal")
}

View File

@ -15,15 +15,6 @@ func FromContext(ctx context.Context) (Flow, bool) {
return c, ok
}
// MustContext returns Flow from context
func MustContext(ctx context.Context) Flow {
f, ok := FromContext(ctx)
if !ok {
panic("missing flow")
}
return f
}
// NewContext stores Flow to context
func NewContext(ctx context.Context, f Flow) context.Context {
if ctx == nil {

View File

@ -32,7 +32,7 @@ type fsm struct {
// NewFSM creates a new finite state machine having the specified initial state
// with specified options
func NewFSM(opts ...Option) FSM {
func NewFSM(opts ...Option) *fsm {
return &fsm{
statesMap: map[string]StateFunc{},
opts: NewOptions(opts...),

45
go.mod
View File

@ -1,43 +1,32 @@
module go.unistack.org/micro/v3
go 1.23.4
go 1.22
require (
dario.cat/mergo v1.0.1
dario.cat/mergo v1.0.0
github.com/DATA-DOG/go-sqlmock v1.5.0
github.com/KimMachineGun/automemlimit v0.6.1
github.com/ash3in/uuidv8 v1.0.1
github.com/google/uuid v1.6.0
github.com/matoous/go-nanoid v1.5.1
github.com/google/uuid v1.3.0
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/silas/dag v0.0.0-20220518035006-a7e85ada93c5
go.uber.org/automaxprocs v1.6.0
go.unistack.org/micro-proto/v3 v3.4.1
golang.org/x/sync v0.10.0
google.golang.org/grpc v1.68.1
google.golang.org/protobuf v1.35.2
gopkg.in/yaml.v3 v3.0.1
golang.org/x/sync v0.3.0
google.golang.org/grpc v1.57.0
google.golang.org/protobuf v1.33.0
)
require (
github.com/cilium/ebpf v0.16.0 // indirect
github.com/containerd/cgroups/v3 v3.0.4 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/moby/sys/userns v0.1.0 // indirect
github.com/opencontainers/runtime-spec v1.2.0 // indirect
github.com/cilium/ebpf v0.9.1 // indirect
github.com/containerd/cgroups/v3 v3.0.1 // indirect
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
github.com/docker/go-units v0.4.0 // indirect
github.com/godbus/dbus/v5 v5.0.4 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/opencontainers/runtime-spec v1.0.2 // indirect
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/stretchr/testify v1.10.0 // indirect
go.uber.org/goleak v1.3.0 // indirect
golang.org/x/exp v0.0.0-20241210194714-1829a127f884 // indirect
golang.org/x/net v0.32.0 // indirect
golang.org/x/sys v0.28.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
golang.org/x/net v0.14.0 // indirect
golang.org/x/sys v0.11.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230526203410-71b5a4ffd15e // indirect
)

132
go.sum
View File

@ -1,102 +1,78 @@
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/KimMachineGun/automemlimit v0.6.1 h1:ILa9j1onAAMadBsyyUJv5cack8Y1WT26yLj/V+ulKp8=
github.com/KimMachineGun/automemlimit v0.6.1/go.mod h1:T7xYht7B8r6AG/AqFcUdc7fzd2bIdBKmepfP2S1svPY=
github.com/ash3in/uuidv8 v1.0.1 h1:dIq1XRkWT8lGA7N5s7WRTB4V3k49WTBLvILz7aCLp80=
github.com/ash3in/uuidv8 v1.0.1/go.mod h1:EoyUgCtxNBnrnpc9efw5rVN1cQ+LFGCoJiFuD6maOMw=
github.com/cilium/ebpf v0.16.0 h1:+BiEnHL6Z7lXnlGUsXQPPAE7+kenAd4ES8MQ5min0Ok=
github.com/cilium/ebpf v0.16.0/go.mod h1:L7u2Blt2jMM/vLAVgjxluxtBKlz3/GWjB0dMOEngfwE=
github.com/containerd/cgroups/v3 v3.0.4 h1:2fs7l3P0Qxb1nKWuJNFiwhp2CqiKzho71DQkDrHJIo4=
github.com/containerd/cgroups/v3 v3.0.4/go.mod h1:SA5DLYnXO8pTGYiAHXz94qvLQTKfVM5GEVisn4jpins=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/cilium/ebpf v0.9.1 h1:64sn2K3UKw8NbP/blsixRpF3nXuyhz/VjRlRzvlBRu4=
github.com/cilium/ebpf v0.9.1/go.mod h1:+OhNOIXx/Fnu1IE8bJz2dzOA+VSfyTfdNUVdlQnxUFY=
github.com/containerd/cgroups/v3 v3.0.1 h1:4hfGvu8rfGIwVIDd+nLzn/B9ZXx4BcCjzt5ToenJRaE=
github.com/containerd/cgroups/v3 v3.0.1/go.mod h1:/vtwk1VXrtoa5AaZLkypuOJgA/6DyPMZHJPGQNtlHnw=
github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI=
github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow=
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss=
github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og=
github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
github.com/jsimonetti/rtnetlink/v2 v2.0.1 h1:xda7qaHDSVOsADNouv7ukSuicKZO7GgVUCXxpaIEIlM=
github.com/jsimonetti/rtnetlink/v2 v2.0.1/go.mod h1:7MoNYNbb3UaDHtF8udiJo/RH6VsTKP1pqKLUTVCvToE=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
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/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/matoous/go-nanoid v1.5.1 h1:aCjdvTyO9LLnTIi0fgdXhOPPvOHjpXN6Ik9DaNjIct4=
github.com/matoous/go-nanoid v1.5.1/go.mod h1:zyD2a71IubI24efhpvkJz+ZwfwagzgSO6UNiFsZKN7U=
github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk=
github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0=
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
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/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
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/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/silas/dag v0.0.0-20220518035006-a7e85ada93c5 h1:G/FZtUu7a6NTWl3KUHMV9jkLAh/Rvtf03NWMHaEDl+E=
github.com/silas/dag v0.0.0-20220518035006-a7e85ada93c5/go.mod h1:7RTUFBdIRC9nZ7/3RyRNH1bdqIShrDejd1YbLwgPS+I=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.unistack.org/micro-proto/v3 v3.4.1 h1:UTjLSRz2YZuaHk9iSlVqqsA50JQNAEK2ZFboGqtEa9Q=
go.unistack.org/micro-proto/v3 v3.4.1/go.mod h1:okx/cnOhzuCX0ggl/vToatbCupi0O44diiiLLsZ93Zo=
golang.org/x/exp v0.0.0-20241210194714-1829a127f884 h1:Y/Mj/94zIQQGHVSv1tTtQBDaQaJe62U9bkDZKKyhPCU=
golang.org/x/exp v0.0.0-20241210194714-1829a127f884/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI=
golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 h1:8ZmaLZE4XWrtU3MyClkYqqtl6Oegr3235h7jxsDyqCY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
google.golang.org/grpc v1.68.1 h1:oI5oTa11+ng8r8XMMN7jAOmWfPZWbYpCFaMUTACxkM0=
google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe00waw=
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230526203410-71b5a4ffd15e h1:NumxXLPfHSndr3wBBdeKiVHjGVFzi9RX2HwwQke94iY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw=
google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -4,6 +4,17 @@ import "context"
type loggerKey struct{}
// MustContext returns logger from passed context or DefaultLogger if empty
func MustContext(ctx context.Context) Logger {
if ctx == nil {
return DefaultLogger
}
if l, ok := ctx.Value(loggerKey{}).(Logger); ok && l != nil {
return l
}
return DefaultLogger
}
// FromContext returns logger from passed context
func FromContext(ctx context.Context) (Logger, bool) {
if ctx == nil {
@ -13,15 +24,6 @@ func FromContext(ctx context.Context) (Logger, bool) {
return l, ok
}
// MustContext returns logger from passed context or DefaultLogger if empty
func MustContext(ctx context.Context) Logger {
l, ok := FromContext(ctx)
if !ok {
panic("missing logger")
}
return l
}
// NewContext stores logger into passed context
func NewContext(ctx context.Context, l Logger) context.Context {
if ctx == nil {

View File

@ -11,7 +11,7 @@ var DefaultContextAttrFuncs []ContextAttrFunc
var (
// DefaultLogger variable
DefaultLogger = NewLogger()
DefaultLogger Logger = NewLogger()
// DefaultLevel used by logger
DefaultLevel = InfoLevel
)

View File

@ -5,7 +5,6 @@ import (
"io"
"log/slog"
"os"
"slices"
"time"
"go.unistack.org/micro/v3/meter"
@ -16,6 +15,18 @@ type Option func(*Options)
// Options holds logger options
type Options struct {
// Out holds the output writer
Out io.Writer
// Context holds exernal options
Context context.Context
// Name holds the logger name
Name string
// Fields holds additional metadata
Fields []interface{}
// callerSkipCount number of frmaes to skip
CallerSkipCount int
// ContextAttrFuncs contains funcs that executed before log func on context
ContextAttrFuncs []ContextAttrFunc
// TimeKey is the key used for the time of the log call
TimeKey string
// LevelKey is the key used for the level of the log call
@ -28,30 +39,16 @@ type Options struct {
SourceKey string
// StacktraceKey is the key used for the stacktrace
StacktraceKey string
// Name holds the logger name
Name string
// Out holds the output writer
Out io.Writer
// Context holds exernal options
Context context.Context
// Meter used to count logs for specific level
Meter meter.Meter
// TimeFunc used to obtain current time
TimeFunc func() time.Time
// Fields holds additional metadata
Fields []interface{}
// ContextAttrFuncs contains funcs that executed before log func on context
ContextAttrFuncs []ContextAttrFunc
// callerSkipCount number of frmaes to skip
CallerSkipCount int
// The logging level the logger should log
Level Level
// AddSource enabled writing source file and position in log
AddSource bool
// AddStacktrace controls writing of stacktaces on error
AddStacktrace bool
// DedupKeys deduplicate keys in log output
DedupKeys bool
// AddSource enabled writing source file and position in log
AddSource bool
// The logging level the logger should log
Level Level
// TimeFunc used to obtain current time
TimeFunc func() time.Time
// Meter used to count logs for specific level
Meter meter.Meter
}
// NewOptions creates new options struct
@ -83,32 +80,10 @@ func WithContextAttrFuncs(fncs ...ContextAttrFunc) Option {
}
}
// WithDedupKeys dont log duplicate keys
func WithDedupKeys(b bool) Option {
return func(o *Options) {
o.DedupKeys = b
}
}
// WithAddFields add fields for the logger
func WithAddFields(fields ...interface{}) Option {
return func(o *Options) {
if o.DedupKeys {
for i := 0; i < len(o.Fields); i += 2 {
for j := 0; j < len(fields); j += 2 {
iv, iok := o.Fields[i].(string)
jv, jok := fields[j].(string)
if iok && jok && iv == jv {
fields = slices.Delete(fields, j, j+2)
}
}
}
if len(fields) > 0 {
o.Fields = append(o.Fields, fields...)
}
} else {
o.Fields = append(o.Fields, fields...)
}
o.Fields = append(o.Fields, fields...)
}
}
@ -178,8 +153,8 @@ func WithTimeFunc(fn func() time.Time) Option {
func WithZapKeys() Option {
return func(o *Options) {
o.TimeKey = "@timestamp"
o.LevelKey = slog.LevelKey
o.MessageKey = slog.MessageKey
o.LevelKey = "level"
o.MessageKey = "msg"
o.SourceKey = "caller"
o.StacktraceKey = "stacktrace"
o.ErrorKey = "error"
@ -188,8 +163,8 @@ func WithZapKeys() Option {
func WithZerologKeys() Option {
return func(o *Options) {
o.TimeKey = slog.TimeKey
o.LevelKey = slog.LevelKey
o.TimeKey = "time"
o.LevelKey = "level"
o.MessageKey = "message"
o.SourceKey = "caller"
o.StacktraceKey = "stacktrace"
@ -211,8 +186,8 @@ func WithSlogKeys() Option {
func WithMicroKeys() Option {
return func(o *Options) {
o.TimeKey = "timestamp"
o.LevelKey = slog.LevelKey
o.MessageKey = slog.MessageKey
o.LevelKey = "level"
o.MessageKey = "msg"
o.SourceKey = "caller"
o.StacktraceKey = "stacktrace"
o.ErrorKey = "error"

View File

@ -2,7 +2,6 @@ package slog
import (
"context"
"io"
"log/slog"
"os"
"reflect"
@ -11,7 +10,6 @@ import (
"strconv"
"sync"
"sync/atomic"
"time"
"go.unistack.org/micro/v3/logger"
"go.unistack.org/micro/v3/semconv"
@ -144,7 +142,6 @@ func (s *slogLogger) Fields(fields ...interface{}) logger.Logger {
s.mu.RUnlock()
l := &slogLogger{opts: options}
logger.WithAddFields(fields...)(&l.opts)
if len(options.ContextAttrFuncs) == 0 {
options.ContextAttrFuncs = logger.DefaultContextAttrFuncs
@ -226,10 +223,6 @@ func (s *slogLogger) Error(ctx context.Context, msg string, attrs ...interface{}
func (s *slogLogger) Fatal(ctx context.Context, msg string, attrs ...interface{}) {
s.printLog(ctx, logger.FatalLevel, msg, attrs...)
if closer, ok := s.opts.Out.(io.Closer); ok {
closer.Close()
}
time.Sleep(1 * time.Second)
os.Exit(1)
}
@ -276,7 +269,7 @@ func (s *slogLogger) printLog(ctx context.Context, lvl logger.Level, msg string,
}
}
if (s.opts.AddStacktrace || lvl == logger.FatalLevel) || (s.opts.AddStacktrace && lvl == logger.ErrorLevel) {
if s.opts.AddStacktrace && lvl == logger.ErrorLevel {
stackInfo := make([]byte, 1024*1024)
if stackSize := runtime.Stack(stackInfo, false); stackSize > 0 {
traceLines := reTrace.Split(string(stackInfo[:stackSize]), -1)
@ -347,7 +340,7 @@ func (s *slogLogger) argsAttrs(args []interface{}) ([]slog.Attr, error) {
case string:
if idx+1 < len(args) {
attrs = append(attrs, slog.Any(arg, args[idx+1]))
idx++
idx += 1
} else {
attrs = append(attrs, slog.String(badKey, arg))
}

View File

@ -11,80 +11,11 @@ import (
"testing"
"github.com/google/uuid"
"go.unistack.org/micro/v3/logger"
"go.unistack.org/micro/v3/metadata"
"go.unistack.org/micro/v3/logger"
)
func TestStacktrace(t *testing.T) {
ctx := context.TODO()
buf := bytes.NewBuffer(nil)
l := NewLogger(logger.WithLevel(logger.ErrorLevel), logger.WithOutput(buf),
WithHandlerFunc(slog.NewTextHandler),
logger.WithAddStacktrace(true),
)
if err := l.Init(logger.WithFields("key1", "val1")); err != nil {
t.Fatal(err)
}
l.Error(ctx, "msg1", errors.New("err"))
if !bytes.Contains(buf.Bytes(), []byte(`slog_test.go:29`)) {
t.Fatalf("logger error not works, buf contains: %s", buf.Bytes())
}
}
func TestWithFields(t *testing.T) {
ctx := context.TODO()
buf := bytes.NewBuffer(nil)
l := NewLogger(logger.WithLevel(logger.InfoLevel), logger.WithOutput(buf),
WithHandlerFunc(slog.NewTextHandler),
logger.WithDedupKeys(true),
)
if err := l.Init(logger.WithFields("key1", "val1")); err != nil {
t.Fatal(err)
}
l.Info(ctx, "msg1")
l = l.Fields("key1", "val2")
l.Info(ctx, "msg2")
if !bytes.Contains(buf.Bytes(), []byte(`msg=msg2 key1=val1`)) {
t.Fatalf("logger error not works, buf contains: %s", buf.Bytes())
}
}
func TestWithDedupKeysWithAddFields(t *testing.T) {
ctx := context.TODO()
buf := bytes.NewBuffer(nil)
l := NewLogger(logger.WithLevel(logger.InfoLevel), logger.WithOutput(buf),
WithHandlerFunc(slog.NewTextHandler),
logger.WithDedupKeys(true),
)
if err := l.Init(logger.WithFields("key1", "val1")); err != nil {
t.Fatal(err)
}
l.Info(ctx, "msg1")
if err := l.Init(logger.WithAddFields("key2", "val2")); err != nil {
t.Fatal(err)
}
l.Info(ctx, "msg2")
if err := l.Init(logger.WithAddFields("key2", "val3", "key1", "val4")); err != nil {
t.Fatal(err)
}
l.Info(ctx, "msg3")
if !bytes.Contains(buf.Bytes(), []byte(`msg=msg3 key1=val1 key2=val2`)) {
t.Fatalf("logger error not works, buf contains: %s", buf.Bytes())
}
}
func TestWithHandlerFunc(t *testing.T) {
ctx := context.TODO()
buf := bytes.NewBuffer(nil)
@ -202,7 +133,7 @@ func TestErrorf(t *testing.T) {
buf := bytes.NewBuffer(nil)
l := NewLogger(logger.WithLevel(logger.ErrorLevel), logger.WithOutput(buf), logger.WithAddStacktrace(true))
if err := l.Init(logger.WithContextAttrFuncs(func(_ context.Context) []interface{} {
if err := l.Init(logger.WithContextAttrFuncs(func(ctx context.Context) []interface{} {
return nil
})); err != nil {
t.Fatal(err)

View File

@ -52,15 +52,13 @@ type protoMessage interface {
}
type Wrapper struct {
pointers map[uintptr]int
takeMap map[int]bool
val interface{}
s fmt.State
opts *Options
val interface{}
s fmt.State
pointers map[uintptr]int
opts *Options
depth int
ignoreNextType bool
takeMap map[int]bool
protoWrapperType bool
sqlWrapperType bool
}

View File

@ -24,17 +24,6 @@ func FromIncomingContext(ctx context.Context) (Metadata, bool) {
return md.md, ok
}
// MustIncomingContext returns metadata from incoming ctx
// returned metadata shoud not be modified or race condition happens.
// If metadata not exists panics.
func MustIncomingContext(ctx context.Context) Metadata {
md, ok := FromIncomingContext(ctx)
if !ok {
panic("missing metadata")
}
return md
}
// FromOutgoingContext returns metadata from outgoing ctx
// returned metadata shoud not be modified or race condition happens
func FromOutgoingContext(ctx context.Context) (Metadata, bool) {
@ -48,17 +37,6 @@ func FromOutgoingContext(ctx context.Context) (Metadata, bool) {
return md.md, ok
}
// MustOutgoingContext returns metadata from outgoing ctx
// returned metadata shoud not be modified or race condition happens.
// If metadata not exists panics.
func MustOutgoingContext(ctx context.Context) Metadata {
md, ok := FromOutgoingContext(ctx)
if !ok {
panic("missing metadata")
}
return md
}
// FromContext returns metadata from the given context
// returned metadata shoud not be modified or race condition happens
func FromContext(ctx context.Context) (Metadata, bool) {
@ -72,16 +50,6 @@ func FromContext(ctx context.Context) (Metadata, bool) {
return md.md, ok
}
// MustContext returns metadata from the given context
// returned metadata shoud not be modified or race condition happens
func MustContext(ctx context.Context) Metadata {
md, ok := FromContext(ctx)
if !ok {
panic("missing metadata")
}
return md
}
// NewContext creates a new context with the given metadata
func NewContext(ctx context.Context, md Metadata) context.Context {
if ctx == nil {
@ -143,7 +111,7 @@ func AppendOutgoingContext(ctx context.Context, kv ...string) context.Context {
for k, v := range md {
omd.Set(k, v)
}
return ctx
return NewOutgoingContext(ctx, omd)
}
// AppendIncomingContext apends new md to context
@ -159,21 +127,5 @@ func AppendIncomingContext(ctx context.Context, kv ...string) context.Context {
for k, v := range md {
omd.Set(k, v)
}
return ctx
}
// AppendContext apends new md to context
func AppendContext(ctx context.Context, kv ...string) context.Context {
md, ok := Pairs(kv...)
if !ok {
return ctx
}
omd, ok := FromContext(ctx)
if !ok {
return NewContext(ctx, md)
}
for k, v := range md {
omd.Set(k, v)
}
return ctx
return NewIncomingContext(ctx, omd)
}

View File

@ -4,7 +4,6 @@ package metadata
import (
"net/textproto"
"sort"
"strings"
)
var (
@ -67,14 +66,6 @@ func (md Metadata) Iterator() *Iterator {
return iter
}
func (md Metadata) MustGet(key string) string {
val, ok := md.Get(key)
if !ok {
panic("missing metadata key")
}
return val
}
// Get returns value from metadata by key
func (md Metadata) Get(key string) (string, bool) {
// fast path
@ -82,9 +73,6 @@ func (md Metadata) Get(key string) (string, bool) {
if !ok {
// slow path
val, ok = md[textproto.CanonicalMIMEHeaderKey(key)]
if !ok {
val, ok = md[strings.ToLower(key)]
}
}
return val, ok
}
@ -106,23 +94,14 @@ func (md Metadata) Del(keys ...string) {
delete(md, key)
// slow path
delete(md, textproto.CanonicalMIMEHeaderKey(key))
// very slow path
delete(md, strings.ToLower(key))
}
}
// Copy makes a copy of the metadata
func (md Metadata) CopyTo(dst Metadata) {
for k, v := range md {
dst[k] = v
}
}
// Copy makes a copy of the metadata
func Copy(md Metadata, exclude ...string) Metadata {
nmd := New(len(md))
for k, v := range md {
nmd[k] = v
for key, val := range md {
nmd.Set(key, val)
}
nmd.Del(exclude...)
return nmd
@ -146,7 +125,7 @@ func Merge(omd Metadata, mmd Metadata, overwrite bool) Metadata {
case ok && !overwrite:
continue
case val != "":
nmd[key] = val
nmd.Set(key, val)
case ok && val == "":
nmd.Del(key)
}
@ -160,8 +139,6 @@ func Pairs(kv ...string) (Metadata, bool) {
return nil, false
}
md := New(len(kv) / 2)
for idx := 0; idx < len(kv); idx += 2 {
md[kv[idx]] = kv[idx+1]
}
md.Set(kv...)
return md, true
}

View File

@ -5,15 +5,6 @@ import (
"testing"
)
func TestLowercase(t *testing.T) {
md := New(1)
md["x-request-id"] = "12345"
v, ok := md.Get("X-Request-Id")
if !ok || v == "" {
t.Fatalf("metadata invalid %#+v", md)
}
}
func TestMultipleUsage(t *testing.T) {
ctx := context.TODO()
md := New(0)
@ -32,8 +23,8 @@ func TestMultipleUsage(t *testing.T) {
m.Del("key1_3")
return ctx
}(ctx)
_ = imd
_ = omd
t.Logf("imd %#+v", imd)
t.Logf("omd %#+v", omd)
}
func TestMetadataSetMultiple(t *testing.T) {
@ -88,14 +79,15 @@ func TestPassing(t *testing.T) {
ctx = NewIncomingContext(ctx, md1)
testCtx(ctx)
_, ok := FromOutgoingContext(ctx)
md, ok := FromOutgoingContext(ctx)
if ok {
t.Fatalf("create outgoing context")
}
_ = md
ctx = NewOutgoingContext(ctx, New(1))
testCtx(ctx)
md, ok := FromOutgoingContext(ctx)
md, ok = FromOutgoingContext(ctx)
if !ok {
t.Fatalf("missing metadata from outgoing context")
}
@ -118,7 +110,7 @@ func TestMerge(t *testing.T) {
}
}
func TestIterator(_ *testing.T) {
func TestIterator(t *testing.T) {
md := Metadata{
"1Last": "last",
"2First": "first",

View File

@ -15,15 +15,6 @@ func FromContext(ctx context.Context) (Meter, bool) {
return c, ok
}
// MustContext get meter from context
func MustContext(ctx context.Context) Meter {
m, ok := FromContext(ctx)
if !ok {
panic("missing meter")
}
return m
}
// NewContext put meter in context
func NewContext(ctx context.Context, c Meter) context.Context {
if ctx == nil {

View File

@ -11,7 +11,7 @@ import (
var (
// DefaultMeter is the default meter
DefaultMeter = NewMeter()
DefaultMeter Meter = NewMeter()
// DefaultAddress data will be made available on this host:port
DefaultAddress = ":9090"
// DefaultPath the meter endpoint where the Meter data will be made available

View File

@ -37,32 +37,32 @@ func (r *noopMeter) Init(opts ...Option) error {
}
// Counter implements the Meter interface
func (r *noopMeter) Counter(_ string, labels ...string) Counter {
func (r *noopMeter) Counter(name string, labels ...string) Counter {
return &noopCounter{labels: labels}
}
// FloatCounter implements the Meter interface
func (r *noopMeter) FloatCounter(_ string, labels ...string) FloatCounter {
func (r *noopMeter) FloatCounter(name string, labels ...string) FloatCounter {
return &noopFloatCounter{labels: labels}
}
// Gauge implements the Meter interface
func (r *noopMeter) Gauge(_ string, _ func() float64, labels ...string) Gauge {
func (r *noopMeter) Gauge(name string, f func() float64, labels ...string) Gauge {
return &noopGauge{labels: labels}
}
// Summary implements the Meter interface
func (r *noopMeter) Summary(_ string, labels ...string) Summary {
func (r *noopMeter) Summary(name string, labels ...string) Summary {
return &noopSummary{labels: labels}
}
// SummaryExt implements the Meter interface
func (r *noopMeter) SummaryExt(_ string, _ time.Duration, _ []float64, labels ...string) Summary {
func (r *noopMeter) SummaryExt(name string, window time.Duration, quantiles []float64, labels ...string) Summary {
return &noopSummary{labels: labels}
}
// Histogram implements the Meter interface
func (r *noopMeter) Histogram(_ string, labels ...string) Histogram {
func (r *noopMeter) Histogram(name string, labels ...string) Histogram {
return &noopHistogram{labels: labels}
}
@ -77,7 +77,7 @@ func (r *noopMeter) Set(opts ...Option) Meter {
return m
}
func (r *noopMeter) Write(_ io.Writer, _ ...Option) error {
func (r *noopMeter) Write(w io.Writer, opts ...Option) error {
return nil
}

View File

@ -18,27 +18,26 @@ func TestAs(t *testing.T) {
testCases := []struct {
b any
target any
match bool
want any
match bool
}{
{
b: broTarget,
target: &b,
match: true,
want: broTarget,
broTarget,
&b,
true,
broTarget,
},
{
b: nil,
target: &b,
match: false,
want: nil,
nil,
&b,
false,
nil,
},
{
b: fsmTarget,
target: &b,
match: false,
want: nil,
fsmTarget,
&b,
false,
nil,
},
}
for i, tc := range testCases {
@ -73,7 +72,7 @@ func (p *bro) Ready() bool { return true }
func (p *bro) Health() bool { return true }
func (p *bro) Init(_ ...broker.Option) error { return nil }
func (p *bro) Init(opts ...broker.Option) error { return nil }
// Options returns broker options
func (p *bro) Options() broker.Options { return broker.Options{} }
@ -82,28 +81,28 @@ func (p *bro) Options() broker.Options { return broker.Options{} }
func (p *bro) Address() string { return "" }
// Connect connects to broker
func (p *bro) Connect(_ context.Context) error { return nil }
func (p *bro) Connect(ctx context.Context) error { return nil }
// Disconnect disconnect from broker
func (p *bro) Disconnect(_ context.Context) error { return nil }
func (p *bro) Disconnect(ctx context.Context) error { return nil }
// Publish message, msg can be single broker.Message or []broker.Message
func (p *bro) Publish(_ context.Context, _ string, _ *broker.Message, _ ...broker.PublishOption) error {
func (p *bro) Publish(ctx context.Context, topic string, msg *broker.Message, opts ...broker.PublishOption) error {
return nil
}
// BatchPublish messages to broker with multiple topics
func (p *bro) BatchPublish(_ context.Context, _ []*broker.Message, _ ...broker.PublishOption) error {
func (p *bro) BatchPublish(ctx context.Context, msgs []*broker.Message, opts ...broker.PublishOption) error {
return nil
}
// BatchSubscribe subscribes to topic messages via handler
func (p *bro) BatchSubscribe(_ context.Context, _ string, _ broker.BatchHandler, _ ...broker.SubscribeOption) (broker.Subscriber, error) {
func (p *bro) BatchSubscribe(ctx context.Context, topic string, h broker.BatchHandler, opts ...broker.SubscribeOption) (broker.Subscriber, error) {
return nil, nil
}
// Subscribe subscribes to topic message via handler
func (p *bro) Subscribe(_ context.Context, _ string, _ broker.Handler, _ ...broker.SubscribeOption) (broker.Subscriber, error) {
func (p *bro) Subscribe(ctx context.Context, topic string, handler broker.Handler, opts ...broker.SubscribeOption) (broker.Subscriber, error) {
return nil, nil
}
@ -114,9 +113,9 @@ type fsmT struct {
name string
}
func (f *fsmT) Start(_ context.Context, _ interface{}, _ ...Option) (interface{}, error) {
func (f *fsmT) Start(ctx context.Context, a interface{}, o ...Option) (interface{}, error) {
return nil, nil
}
func (f *fsmT) Current() string { return f.name }
func (f *fsmT) Reset() {}
func (f *fsmT) State(_ string, _ fsm.StateFunc) {}
func (f *fsmT) Current() string { return f.name }
func (f *fsmT) Reset() {}
func (f *fsmT) State(s string, sf fsm.StateFunc) {}

View File

@ -8,20 +8,19 @@ import (
// CertificateOptions holds options for x509.CreateCertificate
type CertificateOptions struct {
Organization []string
OrganizationalUnit []string
CommonName string
OCSPServer []string
IssuingCertificateURL []string
SerialNumber *big.Int
NotAfter time.Time
NotBefore time.Time
CommonName string
Organization []string
OrganizationalUnit []string
OCSPServer []string
IssuingCertificateURL []string
SignatureAlgorithm x509.SignatureAlgorithm
PublicKeyAlgorithm x509.PublicKeyAlgorithm
ExtKeyUsage []x509.ExtKeyUsage
SignatureAlgorithm x509.SignatureAlgorithm
PublicKeyAlgorithm x509.PublicKeyAlgorithm
KeyUsage x509.KeyUsage
IsCA bool
KeyUsage x509.KeyUsage
IsCA bool
}
// CertificateOrganizationalUnit set OrganizationalUnit in certificate subject

View File

@ -119,7 +119,7 @@ func Tracer(t tracer.Tracer) Option {
// NewOptions returns network default options
func NewOptions(opts ...Option) Options {
options := Options{
ID: id.MustNew(),
ID: id.Must(),
Name: "go.micro",
Address: ":0",
Logger: logger.DefaultLogger,

View File

@ -10,7 +10,7 @@ import (
var (
// DefaultTransport is the global default transport
DefaultTransport = NewTransport()
DefaultTransport Transport = NewTransport()
// DefaultDialTimeout the default dial timeout
DefaultDialTimeout = time.Second * 5
)

View File

@ -84,7 +84,7 @@ func (t *tunBroker) Disconnect(ctx context.Context) error {
return t.tunnel.Close(ctx)
}
func (t *tunBroker) BatchPublish(ctx context.Context, msgs []*broker.Message, _ ...broker.PublishOption) error {
func (t *tunBroker) BatchPublish(ctx context.Context, msgs []*broker.Message, opts ...broker.PublishOption) error {
// TODO: this is probably inefficient, we might want to just maintain an open connection
// it may be easier to add broadcast to the tunnel
topicMap := make(map[string]tunnel.Session)
@ -114,7 +114,7 @@ func (t *tunBroker) BatchPublish(ctx context.Context, msgs []*broker.Message, _
return nil
}
func (t *tunBroker) Publish(ctx context.Context, topic string, m *broker.Message, _ ...broker.PublishOption) error {
func (t *tunBroker) Publish(ctx context.Context, topic string, m *broker.Message, opts ...broker.PublishOption) error {
// TODO: this is probably inefficient, we might want to just maintain an open connection
// it may be easier to add broadcast to the tunnel
c, err := t.tunnel.Dial(ctx, topic, tunnel.DialMode(tunnel.Multicast))

View File

@ -164,7 +164,7 @@ func DialWait(b bool) DialOption {
// NewOptions returns router default options with filled values
func NewOptions(opts ...Option) Options {
options := Options{
ID: id.MustNew(),
ID: id.Must(),
Address: DefaultAddress,
Token: DefaultToken,
Logger: logger.DefaultLogger,

View File

@ -15,6 +15,6 @@ func (p *noopProfiler) String() string {
}
// NewProfiler returns new noop profiler
func NewProfiler(_ ...Option) Profiler {
func NewProfiler(opts ...Option) Profiler {
return &noopProfiler{}
}

View File

@ -12,7 +12,7 @@ type Profiler interface {
}
// DefaultProfiler holds the default profiler
var DefaultProfiler = NewProfiler()
var DefaultProfiler Profiler = NewProfiler()
// Options holds the options for profiler
type Options struct {

View File

@ -15,15 +15,6 @@ func FromContext(ctx context.Context) (Register, bool) {
return c, ok
}
// MustContext get register from context
func MustContext(ctx context.Context) Register {
r, ok := FromContext(ctx)
if !ok {
panic("missing register")
}
return r
}
// NewContext put register in context
func NewContext(ctx context.Context, c Register) context.Context {
if ctx == nil {

View File

@ -31,10 +31,10 @@ type record struct {
}
type memory struct {
sync.RWMutex
records map[string]services
watchers map[string]*watcher
opts register.Options
sync.RWMutex
}
// services is a KV map with service name as the key and a map of records as the value
@ -100,11 +100,11 @@ func (m *memory) sendEvent(r *register.Result) {
}
}
func (m *memory) Connect(_ context.Context) error {
func (m *memory) Connect(ctx context.Context) error {
return nil
}
func (m *memory) Disconnect(_ context.Context) error {
func (m *memory) Disconnect(ctx context.Context) error {
return nil
}
@ -124,7 +124,7 @@ func (m *memory) Options() register.Options {
return m.opts
}
func (m *memory) Register(_ context.Context, s *register.Service, opts ...register.RegisterOption) error {
func (m *memory) Register(ctx context.Context, s *register.Service, opts ...register.RegisterOption) error {
m.Lock()
defer m.Unlock()

View File

@ -208,9 +208,9 @@ func TestMemoryRegistryTTLConcurrent(t *testing.T) {
}
}
// if len(os.Getenv("IN_TRAVIS_CI")) == 0 {
//if len(os.Getenv("IN_TRAVIS_CI")) == 0 {
// t.Logf("test will wait %v, then check TTL timeouts", waitTime)
// }
//}
errChan := make(chan error, concurrency)
syncChan := make(chan struct{})
@ -290,12 +290,8 @@ func TestWatcher(t *testing.T) {
ctx := context.TODO()
m := NewRegister()
if err := m.Init(); err != nil {
t.Fatal(err)
}
if err := m.Connect(ctx); err != nil {
t.Fatal(err)
}
_ = m.Init()
_ = m.Connect(ctx)
wc, err := m.Watch(ctx)
if err != nil {
t.Fatalf("cant watch: %v", err)

View File

@ -18,7 +18,7 @@ var DefaultDomain = "micro"
var (
// DefaultRegister is the global default register
DefaultRegister = NewRegister()
DefaultRegister Register = NewRegister()
// ErrNotFound returned when LookupService is called and no services found
ErrNotFound = errors.New("service not found")
// ErrWatcherStopped returned when when watcher is stopped

View File

@ -9,6 +9,6 @@ import (
type Resolver struct{}
// Resolve returns the list of nodes
func (r *Resolver) Resolve(_ string) ([]*resolver.Record, error) {
func (r *Resolver) Resolve(name string) ([]*resolver.Record, error) {
return []*resolver.Record{}, nil
}

View File

@ -15,15 +15,6 @@ func FromContext(ctx context.Context) (Router, bool) {
return c, ok
}
// MustContext get router from context
func MustContext(ctx context.Context) Router {
r, ok := FromContext(ctx)
if !ok {
panic("missing router")
}
return r
}
// NewContext put router in context
func NewContext(ctx context.Context, c Router) context.Context {
if ctx == nil {

View File

@ -80,7 +80,7 @@ func Name(n string) Option {
// NewOptions returns router default options
func NewOptions(opts ...Option) Options {
options := Options{
ID: id.MustNew(),
ID: id.Must(),
Network: DefaultNetwork,
Register: register.DefaultRegister,
Logger: logger.DefaultLogger,

View File

@ -7,7 +7,7 @@ import (
var (
// DefaultRouter is the global default router
DefaultRouter = NewRouter()
DefaultRouter Router = NewRouter()
// DefaultNetwork is default micro network
DefaultNetwork = "micro"
// ErrRouteNotFound is returned when no route was found in the routing table

View File

@ -25,7 +25,7 @@ func (r *random) Select(routes []string, opts ...selector.SelectOption) (selecto
}, nil
}
func (r *random) Record(_ string, _ error) error {
func (r *random) Record(addr string, err error) error {
return nil
}

View File

@ -6,14 +6,14 @@ import (
)
// NewSelector returns an initialised round robin selector
func NewSelector(_ ...selector.Option) selector.Selector {
func NewSelector(opts ...selector.Option) selector.Selector {
return new(roundrobin)
}
type roundrobin struct{}
// Select return routes based on algo
func (r *roundrobin) Select(routes []string, _ ...selector.SelectOption) (selector.Next, error) {
func (r *roundrobin) Select(routes []string, opts ...selector.SelectOption) (selector.Next, error) {
if len(routes) == 0 {
return nil, selector.ErrNoneAvailable
}
@ -28,7 +28,7 @@ func (r *roundrobin) Select(routes []string, _ ...selector.SelectOption) (select
}, nil
}
func (r *roundrobin) Record(_ string, _ error) error { return nil }
func (r *roundrobin) Record(addr string, err error) error { return nil }
func (r *roundrobin) Reset() error { return nil }

View File

@ -1,14 +0,0 @@
package semconv
var (
// CacheRequestDurationSeconds specifies meter metric name
CacheRequestDurationSeconds = "micro_cache_request_duration_seconds"
// CacheRequestLatencyMicroseconds specifies meter metric name
CacheRequestLatencyMicroseconds = "micro_cache_request_latency_microseconds"
// CacheRequestTotal specifies meter metric name
CacheRequestTotal = "micro_cache_request_total"
// CacheRequestInflight specifies meter metric name
CacheRequestInflight = "micro_cache_request_inflight"
// CacheItemsTotal specifies total cache items
CacheItemsTotal = "micro_cache_items_total"
)

View File

@ -1,18 +0,0 @@
package semconv
var (
// HeaderTopic is the header name that contains topic name
HeaderTopic = "Micro-Topic"
// HeaderContentType specifies content type of message
HeaderContentType = "Content-Type"
// HeaderEndpoint specifies endpoint in service
HeaderEndpoint = "Micro-Endpoint"
// HeaderService specifies service
HeaderService = "Micro-Service"
// HeaderTimeout specifies timeout of operation
HeaderTimeout = "Micro-Timeout"
// HeaderAuthorization specifies Authorization header
HeaderAuthorization = "Authorization"
// HeaderXRequestID specifies request id
HeaderXRequestID = "X-Request-Id"
)

View File

@ -3,7 +3,7 @@ package semconv
var (
// StoreRequestDurationSeconds specifies meter metric name
StoreRequestDurationSeconds = "micro_store_request_duration_seconds"
// StoreRequestLatencyMicroseconds specifies meter metric name
// ClientRequestLatencyMicroseconds specifies meter metric name
StoreRequestLatencyMicroseconds = "micro_store_request_latency_microseconds"
// StoreRequestTotal specifies meter metric name
StoreRequestTotal = "micro_store_request_total"

View File

@ -15,15 +15,6 @@ func FromContext(ctx context.Context) (Server, bool) {
return c, ok
}
// MustContext returns Server from context
func MustContext(ctx context.Context) Server {
s, ok := FromContext(ctx)
if !ok {
panic("missing server")
}
return s
}
// NewContext stores Server to context
func NewContext(ctx context.Context, s Server) context.Context {
if ctx == nil {

View File

@ -723,7 +723,7 @@ func (n *noopServer) createSubHandler(sb *subscriber, opts Options) broker.Handl
return nil
}
opts.Hooks.EachPrev(func(hook options.Hook) {
opts.Hooks.EachNext(func(hook options.Hook) {
if h, ok := hook.(HookSubHandler); ok {
fn = h(fn)
}
@ -775,16 +775,13 @@ func (s *subscriber) Options() SubscriberOptions {
}
type subscriber struct {
topic string
typ reflect.Type
subscriber interface{}
endpoints []*register.Endpoint
handlers []*handler
rcvr reflect.Value
opts SubscriberOptions
topic string
endpoints []*register.Endpoint
handlers []*handler
opts SubscriberOptions
rcvr reflect.Value
}
type handler struct {

View File

@ -9,7 +9,6 @@ import (
"go.unistack.org/micro/v3/client"
"go.unistack.org/micro/v3/codec"
"go.unistack.org/micro/v3/logger"
"go.unistack.org/micro/v3/options"
"go.unistack.org/micro/v3/server"
)
@ -39,9 +38,7 @@ func TestNoopSub(t *testing.T) {
t.Fatal(err)
}
if err := logger.DefaultLogger.Init(logger.WithLevel(logger.ErrorLevel)); err != nil {
t.Fatal(err)
}
_ = logger.DefaultLogger.Init(logger.WithLevel(logger.ErrorLevel))
s := server.NewServer(
server.Broker(b),
server.Codec("application/octet-stream", codec.NewCodec()),
@ -85,40 +82,3 @@ func TestNoopSub(t *testing.T) {
}
}()
}
func TestHooks_Wrap(t *testing.T) {
n := 5
fn1 := func(next server.FuncSubHandler) server.FuncSubHandler {
return func(ctx context.Context, msg server.Message) (err error) {
n *= 2
return next(ctx, msg)
}
}
fn2 := func(next server.FuncSubHandler) server.FuncSubHandler {
return func(ctx context.Context, msg server.Message) (err error) {
n -= 10
return next(ctx, msg)
}
}
hs := &options.Hooks{}
hs.Append(server.HookSubHandler(fn1), server.HookSubHandler(fn2))
var fn = func(ctx context.Context, msg server.Message) error {
return nil
}
hs.EachPrev(func(hook options.Hook) {
if h, ok := hook.(server.HookSubHandler); ok {
fn = h(fn)
}
})
if err := fn(nil, nil); err != nil {
t.Fatal(err)
}
if n != 0 {
t.Fatalf("uncorrected hooks call")
}
}

View File

@ -24,24 +24,6 @@ type Option func(*Options)
// Options server struct
type Options struct {
// Codecs map to handle content-type
Codecs map[string]codec.Codec
// Metadata holds the server metadata
Metadata metadata.Metadata
// ID holds the id of the server
ID string
// Namespace for te server
Namespace string
// Name holds the server name
Name string
// Address holds the server address
Address string
// Advertise holds the advertise address
Advertise string
// Version holds the server version
Version string
// Context holds the external options and can be used for server shutdown
Context context.Context
// Broker holds the server broker
@ -54,33 +36,51 @@ type Options struct {
Logger logger.Logger
// Meter holds the meter
Meter meter.Meter
/*
// Router for requests
Router Router
*/
// Listener may be passed if already created
Listener net.Listener
// TLSConfig specifies tls.Config for secure serving
TLSConfig *tls.Config
// Wait group
Wait *msync.WaitGroup
// TLSConfig specifies tls.Config for secure serving
TLSConfig *tls.Config
// Metadata holds the server metadata
Metadata metadata.Metadata
// RegisterCheck run before register server
RegisterCheck func(context.Context) error
// Hooks may contains hook actions that performs before/after server handler
// or server subscriber handler
Hooks options.Hooks
// Codecs map to handle content-type
Codecs map[string]codec.Codec
// ID holds the id of the server
ID string
// Namespace for te server
Namespace string
// Name holds the server name
Name string
// Address holds the server address
Address string
// Advertise holds the advertise address
Advertise string
// Version holds the server version
Version string
// RegisterAttempts holds the number of register attempts before error
RegisterAttempts int
// RegisterInterval holds he interval for re-register
RegisterInterval time.Duration
// RegisterTTL specifies TTL for register record
RegisterTTL time.Duration
// GracefulTimeout timeout for graceful stop server
GracefulTimeout time.Duration
// MaxConn limits number of connections
MaxConn int
// DeregisterAttempts holds the number of deregister attempts before error
DeregisterAttempts int
// RegisterAttempts holds the number of register attempts before error
RegisterAttempts int
// Hooks may contains hook actions that performs before/after server handler
// or server subscriber handler
Hooks options.Hooks
// GracefulTimeout timeout for graceful stop server
GracefulTimeout time.Duration
}
// NewOptions returns new options struct with default or passed values
@ -100,7 +100,7 @@ func NewOptions(opts ...Option) Options {
Address: DefaultAddress,
Name: DefaultName,
Version: DefaultVersion,
ID: id.MustNew(),
ID: id.Must(),
Namespace: DefaultNamespace,
GracefulTimeout: DefaultGracefulTimeout,
}
@ -318,14 +318,14 @@ type SubscriberOptions struct {
Context context.Context
// Queue holds the subscription queue
Queue string
// BatchWait flag specifies max wait time for batch filling
BatchWait time.Duration
// BatchSize flag specifies max size of batch
BatchSize int
// AutoAck flag for auto ack messages after processing
AutoAck bool
// BodyOnly flag specifies that message without headers
BodyOnly bool
// BatchSize flag specifies max size of batch
BatchSize int
// BatchWait flag specifies max wait time for batch filling
BatchWait time.Duration
}
// NewSubscriberOptions create new SubscriberOptions

View File

@ -12,7 +12,7 @@ import (
// DefaultServer default server
var (
DefaultServer = NewServer()
DefaultServer Server = NewServer()
)
var (

View File

@ -34,10 +34,7 @@ func init() {
),
)
net.DefaultResolver = utildns.NewNetResolver(
utildns.Timeout(1*time.Second),
utildns.MinCacheTTL(5*time.Second),
)
net.DefaultResolver = utildns.NewNetResolver(utildns.Timeout(1 * time.Second))
}
// Service is an interface that wraps the lower level components.

View File

@ -121,10 +121,8 @@ func TestNewService(t *testing.T) {
}
tests := []struct {
name string
want Service
args args
want Service
}{
{
name: "NewService",
@ -148,10 +146,9 @@ func Test_service_Name(t *testing.T) {
opts Options
}
tests := []struct {
name string
want string
name string
fields fields
want string
}{
{
name: "Test_service_Name",
@ -248,12 +245,10 @@ func Test_service_Broker(t *testing.T) {
names []string
}
tests := []struct {
name string
want broker.Broker
name string
fields fields
args args
want broker.Broker
}{
{
name: "service.Broker",
@ -306,12 +301,10 @@ func Test_service_Tracer(t *testing.T) {
names []string
}
tests := []struct {
name string
want tracer.Tracer
name string
fields fields
args args
want tracer.Tracer
}{
{
name: "service.Tracer",
@ -345,11 +338,10 @@ func Test_service_Config(t *testing.T) {
names []string
}
tests := []struct {
name string
want config.Config
name string
fields fields
args args
want config.Config
}{
{
name: "service.Config",
@ -383,12 +375,10 @@ func Test_service_Client(t *testing.T) {
names []string
}
tests := []struct {
name string
want client.Client
name string
fields fields
args args
want client.Client
}{
{
name: "service.Client",
@ -422,12 +412,10 @@ func Test_service_Server(t *testing.T) {
names []string
}
tests := []struct {
name string
want server.Server
name string
fields fields
args args
want server.Server
}{
{
name: "service.Server",
@ -461,12 +449,10 @@ func Test_service_Store(t *testing.T) {
names []string
}
tests := []struct {
name string
want store.Store
name string
fields fields
args args
want store.Store
}{
{
name: "service.Store",
@ -500,12 +486,10 @@ func Test_service_Register(t *testing.T) {
names []string
}
tests := []struct {
name string
want register.Register
name string
fields fields
args args
want register.Register
}{
{
name: "service.Register",
@ -539,12 +523,10 @@ func Test_service_Logger(t *testing.T) {
names []string
}
tests := []struct {
name string
want logger.Logger
name string
fields fields
args args
want logger.Logger
}{
{
name: "service.Logger",
@ -578,12 +560,10 @@ func Test_service_Router(t *testing.T) {
names []string
}
tests := []struct {
name string
want router.Router
name string
fields fields
args args
want router.Router
}{
{
name: "service.Router",
@ -617,12 +597,10 @@ func Test_service_Meter(t *testing.T) {
names []string
}
tests := []struct {
name string
want meter.Meter
name string
fields fields
args args
want meter.Meter
}{
{
name: "service.Meter",
@ -653,8 +631,8 @@ func Test_service_String(t *testing.T) {
}
tests := []struct {
name string
want string
fields fields
want string
}{
{
name: "service.String",

View File

@ -15,15 +15,6 @@ func FromContext(ctx context.Context) (Store, bool) {
return c, ok
}
// MustContext get store from context
func MustContext(ctx context.Context) Store {
s, ok := FromContext(ctx)
if !ok {
panic("missing store")
}
return s
}
// NewContext put store in context
func NewContext(ctx context.Context, c Store) context.Context {
if ctx == nil {

View File

@ -96,15 +96,15 @@ func (m *memoryStore) list(prefix string, limit, offset uint) []string {
if limit != 0 || offset != 0 {
sort.Slice(allKeys, func(i, j int) bool { return allKeys[i] < allKeys[j] })
sort.Slice(allKeys, func(i, j int) bool { return allKeys[i] < allKeys[j] })
end := uint(len(allKeys))
end := len(allKeys)
if limit > 0 {
calcLimit := offset + limit
calcLimit := int(offset + limit)
if calcLimit < end {
end = calcLimit
}
}
if offset >= end {
if int(offset) >= end {
return nil
}
return allKeys[offset:end]
@ -123,7 +123,7 @@ func (m *memoryStore) Init(opts ...store.Option) error {
m.funcList = m.fnList
m.funcDelete = m.fnDelete
m.opts.Hooks.EachPrev(func(hook options.Hook) {
m.opts.Hooks.EachNext(func(hook options.Hook) {
switch h := hook.(type) {
case store.HookRead:
m.funcRead = h(m.funcRead)

View File

@ -12,18 +12,15 @@ import (
var _ Store = (*noopStore)(nil)
type noopStore struct {
watchers map[string]Watcher
funcRead FuncRead
funcWrite FuncWrite
funcExists FuncExists
funcList FuncList
funcDelete FuncDelete
mu sync.Mutex
watchers map[string]Watcher
funcRead FuncRead
funcWrite FuncWrite
funcExists FuncExists
funcList FuncList
funcDelete FuncDelete
opts Options
isConnected atomic.Int32
mu sync.Mutex
}
func (n *noopStore) Live() bool {
@ -38,7 +35,7 @@ func (n *noopStore) Health() bool {
return true
}
func NewStore(opts ...Option) Store {
func NewStore(opts ...Option) *noopStore {
options := NewOptions(opts...)
return &noopStore{opts: options}
}
@ -54,7 +51,7 @@ func (n *noopStore) Init(opts ...Option) error {
n.funcList = n.fnList
n.funcDelete = n.fnDelete
n.opts.Hooks.EachPrev(func(hook options.Hook) {
n.opts.Hooks.EachNext(func(hook options.Hook) {
switch h := hook.(type) {
case HookRead:
n.funcRead = h(n.funcRead)
@ -97,7 +94,7 @@ func (n *noopStore) Read(ctx context.Context, key string, val interface{}, opts
return n.funcRead(ctx, key, val, opts...)
}
func (n *noopStore) fnRead(ctx context.Context, _ string, _ interface{}, _ ...ReadOption) error {
func (n *noopStore) fnRead(ctx context.Context, key string, val interface{}, opts ...ReadOption) error {
select {
case <-ctx.Done():
return ctx.Err()
@ -115,7 +112,7 @@ func (n *noopStore) Delete(ctx context.Context, key string, opts ...DeleteOption
return n.funcDelete(ctx, key, opts...)
}
func (n *noopStore) fnDelete(ctx context.Context, _ string, _ ...DeleteOption) error {
func (n *noopStore) fnDelete(ctx context.Context, key string, opts ...DeleteOption) error {
select {
case <-ctx.Done():
return ctx.Err()
@ -133,7 +130,7 @@ func (n *noopStore) Exists(ctx context.Context, key string, opts ...ExistsOption
return n.funcExists(ctx, key, opts...)
}
func (n *noopStore) fnExists(ctx context.Context, _ string, _ ...ExistsOption) error {
func (n *noopStore) fnExists(ctx context.Context, key string, opts ...ExistsOption) error {
select {
case <-ctx.Done():
return ctx.Err()
@ -151,7 +148,7 @@ func (n *noopStore) Write(ctx context.Context, key string, val interface{}, opts
return n.funcWrite(ctx, key, val, opts...)
}
func (n *noopStore) fnWrite(ctx context.Context, _ string, _ interface{}, _ ...WriteOption) error {
func (n *noopStore) fnWrite(ctx context.Context, key string, val interface{}, opts ...WriteOption) error {
select {
case <-ctx.Done():
return ctx.Err()
@ -203,13 +200,13 @@ func (n *noopStore) connect(ctx context.Context) error {
}
type watcher struct {
opts WatchOptions
ch chan Event
exit chan bool
id string
ch chan Event
opts WatchOptions
}
func (n *noopStore) Watch(_ context.Context, opts ...WatchOption) (Watcher, error) {
func (m *noopStore) Watch(ctx context.Context, opts ...WatchOption) (Watcher, error) {
id, err := id.New()
if err != nil {
return nil, err
@ -226,9 +223,9 @@ func (n *noopStore) Watch(_ context.Context, opts ...WatchOption) (Watcher, erro
opts: wo,
}
n.mu.Lock()
n.watchers[w.id] = w
n.mu.Unlock()
m.mu.Lock()
m.watchers[w.id] = w
m.mu.Unlock()
return w, nil
}

View File

@ -15,13 +15,6 @@ import (
// Options contains configuration for the Store
type Options struct {
// Name specifies store name
Name string
// Namespace of the records
Namespace string
// Separator used as key parts separator
Separator string
// Meter used for metrics
Meter meter.Meter
// Tracer used for tracing
@ -32,17 +25,22 @@ type Options struct {
Codec codec.Codec
// Logger used for logging
Logger logger.Logger
// TLSConfig holds tls.TLSConfig options
TLSConfig *tls.Config
// Name specifies store name
Name string
// Namespace of the records
Namespace string
// Separator used as key parts separator
Separator string
// Addrs contains store address
Addrs []string
// Hooks can be run before/after store Read/List/Write/Exists/Delete
Hooks options.Hooks
// Wrappers store wrapper that called before actual functions
// Wrappers []Wrapper
// Timeout specifies timeout duration for all operations
Timeout time.Duration
// Hooks can be run before/after store Read/List/Write/Exists/Delete
Hooks options.Hooks
// LazyConnect creates a connection when using store
LazyConnect bool
}

View File

@ -16,7 +16,7 @@ var (
// ErrInvalidKey is returned when a key has empty or have invalid format
ErrInvalidKey = errors.New("invalid key")
// DefaultStore is the global default store
DefaultStore = NewStore()
DefaultStore Store = NewStore()
// DefaultSeparator is the gloabal default key parts separator
DefaultSeparator = "/"
)

View File

@ -6,10 +6,9 @@ import (
)
type memorySync struct {
mtx gosync.RWMutex
locks map[string]*memoryLock
options Options
mtx gosync.RWMutex
}
type memoryLock struct {

View File

@ -18,15 +18,6 @@ func FromContext(ctx context.Context) (Tracer, bool) {
return nil, false
}
// MustContext returns a tracer from context
func MustContext(ctx context.Context) Tracer {
t, ok := FromContext(ctx)
if !ok {
panic("missing tracer")
}
return t
}
// NewContext saves the tracer in the context
func NewContext(ctx context.Context, tracer Tracer) context.Context {
if ctx == nil {
@ -37,15 +28,6 @@ func NewContext(ctx context.Context, tracer Tracer) context.Context {
type spanKey struct{}
// SpanFromContext returns a span from context
func SpanMustContext(ctx context.Context) Span {
sp, ok := SpanFromContext(ctx)
if !ok {
panic("missing span")
}
return sp
}
// SpanFromContext returns a span from context
func SpanFromContext(ctx context.Context) (Span, bool) {
if ctx == nil {

View File

@ -25,7 +25,6 @@ func (t *Tracer) Start(ctx context.Context, name string, opts ...tracer.SpanOpti
name: name,
ctx: ctx,
tracer: t,
labels: options.Labels,
kind: options.Kind,
startTime: time.Now(),
}
@ -38,14 +37,6 @@ func (t *Tracer) Start(ctx context.Context, name string, opts ...tracer.SpanOpti
return tracer.NewSpanContext(ctx, span), span
}
type memoryStringer struct {
s string
}
func (s memoryStringer) String() string {
return s.s
}
func (t *Tracer) Flush(_ context.Context) error {
return nil
}
@ -61,6 +52,14 @@ func (t *Tracer) Name() string {
return t.opts.Name
}
type noopStringer struct {
s string
}
func (s noopStringer) String() string {
return s.s
}
type Span struct {
ctx context.Context
tracer tracer.Tracer
@ -68,8 +67,8 @@ type Span struct {
statusMsg string
startTime time.Time
finishTime time.Time
traceID memoryStringer
spanID memoryStringer
traceID noopStringer
spanID noopStringer
events []*Event
labels []interface{}
logs []interface{}

View File

@ -2,7 +2,6 @@ package tracer
import (
"context"
"time"
"go.unistack.org/micro/v3/util/id"
)
@ -21,18 +20,18 @@ func (t *noopTracer) Spans() []Span {
func (t *noopTracer) Start(ctx context.Context, name string, opts ...SpanOption) (context.Context, Span) {
options := NewSpanOptions(opts...)
span := &noopSpan{
name: name,
ctx: ctx,
tracer: t,
startTime: time.Now(),
labels: options.Labels,
kind: options.Kind,
name: name,
ctx: ctx,
tracer: t,
labels: options.Labels,
kind: options.Kind,
}
span.spanID.s, _ = id.New()
span.traceID.s, _ = id.New()
if span.ctx == nil {
span.ctx = context.Background()
}
t.spans = append(t.spans, span)
return NewSpanContext(ctx, span), span
}
@ -59,18 +58,23 @@ func (t *noopTracer) Name() string {
return t.opts.Name
}
type noopEvent struct {
name string
labels []interface{}
}
type noopSpan struct {
ctx context.Context
tracer Tracer
name string
statusMsg string
startTime time.Time
finishTime time.Time
traceID noopStringer
spanID noopStringer
labels []interface{}
kind SpanKind
status SpanStatus
ctx context.Context
tracer Tracer
name string
statusMsg string
traceID noopStringer
spanID noopStringer
events []*noopEvent
labels []interface{}
logs []interface{}
kind SpanKind
status SpanStatus
}
func (s *noopSpan) TraceID() string {
@ -82,7 +86,6 @@ func (s *noopSpan) SpanID() string {
}
func (s *noopSpan) Finish(_ ...SpanOption) {
s.finishTime = time.Now()
}
func (s *noopSpan) Context() context.Context {
@ -94,6 +97,8 @@ func (s *noopSpan) Tracer() Tracer {
}
func (s *noopSpan) AddEvent(name string, opts ...EventOption) {
options := NewEventOptions(opts...)
s.events = append(s.events, &noopEvent{name: name, labels: options.Labels})
}
func (s *noopSpan) SetName(name string) {
@ -101,6 +106,7 @@ func (s *noopSpan) SetName(name string) {
}
func (s *noopSpan) AddLogs(kv ...interface{}) {
s.logs = append(s.logs, kv...)
}
func (s *noopSpan) AddLabels(kv ...interface{}) {

View File

@ -6,9 +6,6 @@ import (
"net"
"sync"
"time"
"go.unistack.org/micro/v3/meter"
"go.unistack.org/micro/v3/semconv"
)
// DialFunc is a [net.Resolver.Dial] function.
@ -22,11 +19,6 @@ func NewNetResolver(opts ...Option) *net.Resolver {
o(&options)
}
if options.Meter == nil {
options.Meter = meter.DefaultMeter
opts = append(opts, Meter(options.Meter))
}
return &net.Resolver{
PreferGo: true,
StrictErrors: options.Resolver.StrictErrors,
@ -43,7 +35,7 @@ func NewNetDialer(parent DialFunc, opts ...Option) DialFunc {
if cache.opts.MaxCacheEntries == 0 {
cache.opts.MaxCacheEntries = DefaultMaxCacheEntries
}
return func(_ context.Context, network, address string) (net.Conn, error) {
return func(ctx context.Context, network, address string) (net.Conn, error) {
conn := &dnsConn{}
conn.roundTrip = cachingRoundTrip(&cache, network, address)
return conn, nil
@ -64,7 +56,6 @@ type Options struct {
PreferIPV4 bool
PreferIPV6 bool
Timeout time.Duration
Meter meter.Meter
}
// MaxCacheEntries sets the maximum number of entries to cache.
@ -96,13 +87,6 @@ func NegativeCache(b bool) Option {
}
}
// Meter sets meter.Meter
func Meter(m meter.Meter) Option {
return func(o *Options) {
o.Meter = m
}
}
// Timeout sets upstream *net.Resolver timeout
func Timeout(td time.Duration) Option {
return func(o *Options) {
@ -132,12 +116,12 @@ func PreferIPV6(b bool) Option {
}
type cache struct {
entries map[string]cacheEntry
sync.RWMutex
dial DialFunc
entries map[string]cacheEntry
opts Options
sync.RWMutex
}
type cacheEntry struct {
@ -172,6 +156,7 @@ func (c *cache) put(req string, res string) {
}
c.Lock()
defer c.Unlock()
if c.entries == nil {
c.entries = make(map[string]cacheEntry)
}
@ -180,8 +165,6 @@ func (c *cache) put(req string, res string) {
var tested, evicted int
for k, e := range c.entries {
if time.Until(e.deadline) <= 0 {
c.opts.Meter.Counter(semconv.CacheItemsTotal, "type", "dns").Dec()
c.opts.Meter.Counter(semconv.CacheRequestTotal, "type", "dns", "method", "evict").Inc()
// delete expired entry
delete(c.entries, k)
evicted++
@ -192,8 +175,6 @@ func (c *cache) put(req string, res string) {
continue
}
if evicted == 0 && c.opts.MaxCacheEntries > 0 && len(c.entries) >= c.opts.MaxCacheEntries {
c.opts.Meter.Counter(semconv.CacheItemsTotal, "type", "dns").Dec()
c.opts.Meter.Counter(semconv.CacheRequestTotal, "type", "dns", "method", "evict").Inc()
// delete at least one entry
delete(c.entries, k)
}
@ -205,9 +186,6 @@ func (c *cache) put(req string, res string) {
deadline: time.Now().Add(ttl),
value: res[2:],
}
c.opts.Meter.Counter(semconv.CacheItemsTotal, "type", "dns").Inc()
c.Unlock()
}
func (c *cache) get(req string) (res string) {
@ -232,7 +210,6 @@ func (c *cache) get(req string) (res string) {
// prepend correct ID
return req[:2] + entry.value
}
return ""
}
@ -306,7 +283,7 @@ func getNameLen(msg string) int {
for i < len(msg) {
if msg[i] == 0 {
// end of name
i++
i += 1
break
}
if msg[i] >= 0xc0 {
@ -333,18 +310,10 @@ func getUint32(s string) int {
func cachingRoundTrip(cache *cache, network, address string) roundTripper {
return func(ctx context.Context, req string) (res string, err error) {
cache.opts.Meter.Counter(semconv.CacheRequestInflight, "type", "dns").Inc()
defer cache.opts.Meter.Counter(semconv.CacheRequestInflight, "type", "dns").Dec()
// check cache
if res = cache.get(req); res != "" {
if res := cache.get(req); res != "" {
return res, nil
}
cache.opts.Meter.Counter(semconv.CacheRequestTotal, "type", "dns", "method", "get", "status", "miss").Inc()
ts := time.Now()
defer func() {
cache.opts.Meter.Summary(semconv.CacheRequestLatencyMicroseconds, "type", "dns", "method", "get").UpdateDuration(ts)
cache.opts.Meter.Histogram(semconv.CacheRequestDurationSeconds, "type", "dns", "method", "get").UpdateDuration(ts)
}()
switch {
case cache.opts.PreferIPV4 && cache.opts.PreferIPV6:
@ -371,7 +340,6 @@ func cachingRoundTrip(cache *cache, network, address string) roundTripper {
var d net.Dialer
conn, err = d.DialContext(ctx, network, address)
}
if err != nil {
return "", err
}

View File

@ -8,13 +8,9 @@ import (
func TestCache(t *testing.T) {
net.DefaultResolver = NewNetResolver(PreferIPV4(true))
_, err := net.LookupHost("unistack.org")
if err != nil {
t.Fatal(err)
}
_, err = net.LookupHost("unistack.org")
addrs, err := net.LookupHost("unistack.org")
if err != nil {
t.Fatal(err)
}
t.Logf("addrs %v", addrs)
}

View File

@ -11,16 +11,15 @@ import (
)
type dnsConn struct {
ctx context.Context
cancel context.CancelFunc
roundTrip roundTripper
deadline time.Time
sync.Mutex
ibuf bytes.Buffer
obuf bytes.Buffer
sync.Mutex
ctx context.Context
cancel context.CancelFunc
deadline time.Time
roundTrip roundTripper
}
type roundTripper func(ctx context.Context, req string) (res string, err error)
@ -79,12 +78,12 @@ func (c *dnsConn) SetDeadline(t time.Time) error {
func (c *dnsConn) SetReadDeadline(t time.Time) error {
c.Lock()
defer c.Unlock()
c.deadline = t
c.Unlock()
return nil
}
func (c *dnsConn) SetWriteDeadline(_ time.Time) error {
func (c *dnsConn) SetWriteDeadline(t time.Time) error {
// writes do not timeout
return nil
}
@ -162,22 +161,23 @@ func readMessage(c net.Conn) (string, error) {
return "", err
}
return string(b[:n]), nil
}
var sz [2]byte
_, err := io.ReadFull(c, sz[:])
if err != nil {
return "", err
}
} else {
var sz [2]byte
_, err := io.ReadFull(c, sz[:])
if err != nil {
return "", err
}
size := int64(sz[0])<<8 | int64(sz[1])
size := int64(sz[0])<<8 | int64(sz[1])
var str strings.Builder
_, err = io.CopyN(&str, c, size)
if err == io.EOF {
return "", io.ErrUnexpectedEOF
var str strings.Builder
_, err = io.CopyN(&str, c, size)
if err == io.EOF {
return "", io.ErrUnexpectedEOF
}
if err != nil {
return "", err
}
return str.String(), nil
}
if err != nil {
return "", err
}
return str.String(), nil
}

View File

@ -71,7 +71,7 @@ func (h *serverHandler) HandleRPC(ctx context.Context, rs stats.RPCStats) {
}
// TagConn can attach some information to the given context.
func (h *serverHandler) TagConn(ctx context.Context, _ *stats.ConnTagInfo) context.Context {
func (h *serverHandler) TagConn(ctx context.Context, info *stats.ConnTagInfo) context.Context {
if span, ok := tracer.SpanFromContext(ctx); ok {
attrs := peerAttr(peerFromCtx(ctx))
span.AddLabels(attrs...)
@ -80,7 +80,7 @@ func (h *serverHandler) TagConn(ctx context.Context, _ *stats.ConnTagInfo) conte
}
// HandleConn processes the Conn stats.
func (h *serverHandler) HandleConn(_ context.Context, _ stats.ConnStats) {
func (h *serverHandler) HandleConn(ctx context.Context, info stats.ConnStats) {
}
type clientHandler struct {

View File

@ -665,12 +665,12 @@ func patParamKeys(pattern string) ([]string, error) {
// longestPrefix finds the length of the shared prefix
// of two strings
func longestPrefix(k1, k2 string) int {
maxLen := len(k1)
if l := len(k2); l < maxLen {
maxLen = l
max := len(k1)
if l := len(k2); l < max {
max = l
}
var i int
for i = 0; i < maxLen; i++ {
for i = 0; i < max; i++ {
if k1[i] != k2[i] {
break
}

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.

View File

@ -1,154 +1,112 @@
package id
import (
"context"
"crypto/rand"
"encoding/binary"
"errors"
"fmt"
"time"
"math"
uuidv8 "github.com/ash3in/uuidv8"
nanoid "github.com/matoous/go-nanoid"
"go.unistack.org/micro/v3/logger"
)
var generatedNode [6]byte
// DefaultAlphabet is the alphabet used for ID characters by default
var DefaultAlphabet = []rune("6789BCDFGHJKLMNPQRTWbcdfghjkmnpqrtwz")
func init() {
if _, err := rand.Read(generatedNode[:]); err != nil {
panic(err)
}
}
type Type int
const (
TypeUnspecified Type = iota
TypeNanoid
TypeUUIDv8
)
// DefaultNanoidAlphabet is the alphabet used for ID characters by default
var DefaultNanoidAlphabet = "6789BCDFGHJKLMNPQRTWbcdfghjkmnpqrtwz"
// DefaultNanoidSize is the size used for ID by default
// DefaultSize is the size used for ID by default
// To get uuid like collision specify 21
var DefaultNanoidSize = 16
var DefaultSize = 16
type Generator struct {
opts Options
}
func (g *Generator) MustNew() string {
id, err := g.New()
if err != nil {
panic(err)
// 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 id
}
func (g *Generator) New() (string, error) {
switch g.opts.Type {
case TypeNanoid:
if len(g.opts.NanoidAlphabet) == 0 || len(g.opts.NanoidAlphabet) > 255 {
return "", errors.New("invalid option, NanoidAlphabet must not be empty and contain no more than 255 chars")
}
if g.opts.NanoidSize <= 0 {
return "", errors.New("invalid option, NanoidSize must be positive integer")
}
return nanoid.Generate(g.opts.NanoidAlphabet, g.opts.NanoidSize)
case TypeUUIDv8:
timestamp := uint64(time.Now().UnixNano())
clockSeq := make([]byte, 2)
if _, err := rand.Read(clockSeq); err != nil {
return "", fmt.Errorf("failed to generate random clock sequence: %w", err)
}
clockSeqValue := binary.BigEndian.Uint16(clockSeq) & 0x0FFF // Mask to 12 bits
return uuidv8.NewWithParams(timestamp, clockSeqValue, g.opts.UUIDNode[:], uuidv8.TimestampBits48)
}
return "", errors.New("invalid option, Type unspecified")
return 0
}
// New returns new id or error
func New(opts ...Option) (string, error) {
options := NewOptions(opts...)
switch options.Type {
case TypeNanoid:
if len(options.NanoidAlphabet) == 0 || len(options.NanoidAlphabet) > 255 {
return "", errors.New("invalid option, NanoidAlphabet must not be empty and contain no more than 255 chars")
}
if options.NanoidSize <= 0 {
return "", errors.New("invalid option, NanoidSize must be positive integer")
}
return nanoid.Generate(options.NanoidAlphabet, options.NanoidSize)
case TypeUUIDv8:
timestamp := uint64(time.Now().UnixNano())
clockSeq := make([]byte, 2)
if _, err := rand.Read(clockSeq); err != nil {
return "", fmt.Errorf("failed to generate random clock sequence: %w", err)
}
clockSeqValue := binary.BigEndian.Uint16(clockSeq) & 0x0FFF // Mask to 12 bits
return uuidv8.NewWithParams(timestamp, clockSeqValue, options.UUIDNode[:], uuidv8.TimestampBits48)
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")
}
return "", errors.New("invalid option, Type unspecified")
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 fatals on error
func MustNew(opts ...Option) string {
func Must(opts ...Option) string {
id, err := New(opts...)
if err != nil {
panic(err)
logger.DefaultLogger.Fatal(context.TODO(), "Must call is failed", err)
}
return id
}
// Options contains id deneration options
type Options struct {
Type Type
NanoidAlphabet string
NanoidSize int
UUIDNode [6]byte
Alphabet []rune
Size int
}
// Option func signature
type Option func(*Options)
// WithNanoidAlphabet specifies alphabet to use
func WithNanoidAlphabet(alphabet string) Option {
// Alphabet specifies alphabet to use
func Alphabet(alphabet string) Option {
return func(o *Options) {
o.NanoidAlphabet = alphabet
o.Alphabet = []rune(alphabet)
}
}
// WithNanoidSize specifies generated id size
func WithNanoidSize(size int) Option {
// Size specifies id size
func Size(size int) Option {
return func(o *Options) {
o.NanoidSize = size
}
}
// WithUUIDNode specifies node component for UUIDv8
func WithUUIDNode(node [6]byte) Option {
return func(o *Options) {
o.UUIDNode = node
o.Size = size
}
}
// NewOptions returns new Options struct filled by opts
func NewOptions(opts ...Option) Options {
options := Options{
Type: TypeUUIDv8,
NanoidAlphabet: DefaultNanoidAlphabet,
NanoidSize: DefaultNanoidSize,
UUIDNode: generatedNode,
Alphabet: DefaultAlphabet,
Size: DefaultSize,
}
for _, o := range opts {
o(&options)
}
return options
}

View File

@ -1,11 +0,0 @@
package id
import "testing"
func TestUUIDv8(t *testing.T) {
id, err := New()
if err != nil {
t.Fatal(err)
}
t.Logf("xxx %s\n", id)
}

View File

@ -14,7 +14,7 @@ func Random(d time.Duration) time.Duration {
return time.Duration(v)
}
func RandomInterval(minTime, maxTime time.Duration) time.Duration {
func RandomInterval(min, max time.Duration) time.Duration {
var rng rand.Rand
return time.Duration(rng.Int63n(maxTime.Nanoseconds()-minTime.Nanoseconds())+minTime.Nanoseconds()) * time.Nanosecond
return time.Duration(rng.Int63n(max.Nanoseconds()-min.Nanoseconds())+min.Nanoseconds()) * time.Nanosecond
}

View File

@ -23,12 +23,12 @@ type Ticker struct {
// NewTickerContext returns a pointer to an initialized instance of the Ticker.
// It works like NewTicker except that it has ability to close via context.
// Also it works fine with context.WithTimeout to handle max time to run ticker.
func NewTickerContext(ctx context.Context, minTime, maxTime time.Duration) *Ticker {
func NewTickerContext(ctx context.Context, min, max time.Duration) *Ticker {
ticker := &Ticker{
C: make(chan time.Time),
done: make(chan chan struct{}),
min: minTime.Nanoseconds(),
max: maxTime.Nanoseconds(),
min: min.Nanoseconds(),
max: max.Nanoseconds(),
ctx: ctx,
}
go ticker.run()
@ -38,12 +38,12 @@ func NewTickerContext(ctx context.Context, minTime, maxTime time.Duration) *Tick
// NewTicker returns a pointer to an initialized instance of the Ticker.
// Min and max are durations of the shortest and longest allowed
// ticks. Ticker will run in a goroutine until explicitly stopped.
func NewTicker(minTime, maxTime time.Duration) *Ticker {
func NewTicker(min, max time.Duration) *Ticker {
ticker := &Ticker{
C: make(chan time.Time),
done: make(chan chan struct{}),
min: minTime.Nanoseconds(),
max: maxTime.Nanoseconds(),
min: min.Nanoseconds(),
max: max.Nanoseconds(),
ctx: context.Background(),
}
go ticker.run()

View File

@ -31,26 +31,26 @@ loop:
func TestTicker(t *testing.T) {
t.Parallel()
minTime := time.Duration(10)
maxTime := time.Duration(20)
min := time.Duration(10)
max := time.Duration(20)
// tick can take a little longer since we're not adjusting it to account for
// processing.
precision := time.Duration(4)
rt := NewTicker(minTime*time.Millisecond, maxTime*time.Millisecond)
rt := NewTicker(min*time.Millisecond, max*time.Millisecond)
for i := 0; i < 5; i++ {
t0 := time.Now()
t1 := <-rt.C
td := t1.Sub(t0)
if td < minTime*time.Millisecond {
if td < min*time.Millisecond {
t.Fatalf("tick was shorter than expected: %s", td)
} else if td > (maxTime+precision)*time.Millisecond {
} else if td > (max+precision)*time.Millisecond {
t.Fatalf("tick was longer than expected: %s", td)
}
}
rt.Stop()
time.Sleep((maxTime + precision) * time.Millisecond)
time.Sleep((max + precision) * time.Millisecond)
select {
case v, ok := <-rt.C:
if ok || !v.IsZero() {

View File

@ -48,19 +48,19 @@ func Listen(addr string, fn func(string) (net.Listener, error)) (net.Listener, e
// we have a port range
// extract min port
minPort, err := strconv.Atoi(prange[0])
min, err := strconv.Atoi(prange[0])
if err != nil {
return nil, errors.New("unable to extract port range")
}
// extract max port
maxPort, err := strconv.Atoi(prange[1])
max, err := strconv.Atoi(prange[1])
if err != nil {
return nil, errors.New("unable to extract port range")
}
// range the ports
for port := minPort; port <= maxPort; port++ {
for port := min; port <= max; port++ {
// try bind to host:port
ln, err := fn(HostPort(host, port))
if err == nil {
@ -68,7 +68,7 @@ func Listen(addr string, fn func(string) (net.Listener, error)) (net.Listener, e
}
// hit max port
if port == maxPort {
if port == max {
return nil, err
}
}

View File

@ -155,7 +155,7 @@ func indexFunction(v reflect.Value) func(i int) reflect.Value {
return v.MapIndex(keys[i])
}
}
return func(_ int) reflect.Value { return reflect.Value{} }
return func(i int) reflect.Value { return reflect.Value{} }
}
func mergeValue(values []reflect.Value) reflect.Value {

View File

@ -130,16 +130,16 @@ func TestMergeString(t *testing.T) {
func TestMergeNested(t *testing.T) {
type CallReqNested struct {
Nested *CallReqNested `json:"nested2"`
StringArgs []string `json:"string_args"`
Uint64Args []uint64 `json:"uint64_args"`
Nested *CallReqNested `json:"nested2"`
}
type CallReq struct {
Nested *CallReqNested `json:"nested"`
Name string `json:"name"`
Req string `json:"req"`
Arg2 int `json:"arg2"`
Nested *CallReqNested `json:"nested"`
}
dst := &CallReq{

View File

@ -109,11 +109,12 @@ func Merge(olist []*register.Service, nlist []*register.Service) []*register.Ser
seen = true
srv = append(srv, sp)
break
} else {
sp := &register.Service{}
// make copy
*sp = *o
srv = append(srv, sp)
}
sp := &register.Service{}
// make copy
*sp = *o
srv = append(srv, sp)
}
if !seen {
srv = append(srv, Copy([]*register.Service{n})...)
@ -152,14 +153,14 @@ func Remove(old, del []*register.Service) []*register.Service {
// WaitService using register wait for service to appear with min/max interval for check and optional timeout.
// Timeout can be 0 to wait infinitive.
func WaitService(ctx context.Context, reg register.Register, name string, minTime time.Duration, maxTime time.Duration, timeout time.Duration, opts ...register.LookupOption) error {
func WaitService(ctx context.Context, reg register.Register, name string, min time.Duration, max time.Duration, timeout time.Duration, opts ...register.LookupOption) error {
if timeout > 0 {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, timeout)
defer cancel()
}
ticker := jitter.NewTickerContext(ctx, minTime, maxTime)
ticker := jitter.NewTickerContext(ctx, min, max)
defer ticker.Stop()
for {

View File

@ -10,11 +10,10 @@ import (
// Buffer is ring buffer
type Buffer struct {
sync.RWMutex
streams map[string]*Stream
vals []*Entry
size int
sync.RWMutex
}
// Entry is ring buffer data entry
@ -113,7 +112,7 @@ func (b *Buffer) Stream() (<-chan *Entry, chan bool) {
defer b.Unlock()
entries := make(chan *Entry, 128)
id := id.MustNew()
id := id.Must()
stop := make(chan bool)
b.streams[id] = &Stream{

View File

@ -6,8 +6,8 @@ import (
// Pool holds the socket pool
type Pool struct {
pool map[string]*Socket
sync.RWMutex
pool map[string]*Socket
}
// Get socket from pool

View File

@ -1,6 +1,7 @@
package sort
import (
"fmt"
"sort"
)
@ -8,7 +9,7 @@ import (
type byKey []interface{}
func (k byKey) Len() int { return len(k) / 2 }
func (k byKey) Less(i, j int) bool { return k[i*2].(string) < k[j*2].(string) }
func (k byKey) Less(i, j int) bool { return fmt.Sprintf("%s", k[i*2]) < fmt.Sprintf("%s", k[j*2]) }
func (k byKey) Swap(i, j int) {
k[i*2], k[j*2] = k[j*2], k[i*2]
k[i*2+1], k[j*2+1] = k[j*2+1], k[i*2+1]

View File

@ -20,11 +20,10 @@ type Stream interface {
}
type stream struct {
sync.RWMutex
Stream
err error
request *request
sync.RWMutex
}
type request struct {

View File

@ -10,18 +10,11 @@ import (
type DigitalOceanMetadata struct {
Metadata struct {
V1 struct {
Features map[string]interface{} `json:"features"`
Hostname string `json:"hostname"`
VendorData string `json:"vendor_data"`
Region string `json:"region"`
DropletID int64 `json:"droplet_id"`
Hostname string `json:"hostname"`
VendorData string `json:"vendor_data"`
PublicKeys []string `json:"public_keys"`
DNS struct {
Nameservers []string `json:"nameservers"`
} `json:"dns"`
Region string `json:"region"`
Interfaces struct {
Private []struct {
IPv4 struct {
@ -38,23 +31,24 @@ type DigitalOceanMetadata struct {
Netmask string `json:"netmask"`
Gateway string `json:"gateway"`
} `json:"ipv4"`
Mac string `json:"mac"`
Type string `json:"type"`
IPv6 struct {
Address string `json:"ip_address"`
Gateway string `json:"gateway"`
CIDR int `json:"cidr"`
Gateway string `json:"gateway"`
} `json:"ipv6"`
Mac string `json:"mac"`
Type string `json:"type"`
} `json:"public"`
} `json:"interfaces"`
DropletID int64 `json:"droplet_id"`
FloatingIP struct {
IPv4 struct {
Active bool `json:"active"`
} `json:"ipv4"`
} `json:"floating_ip"`
DNS struct {
Nameservers []string `json:"nameservers"`
} `json:"dns"`
Features map[string]interface{} `json:"features"`
} `json:"v1"`
} `json:"metadata"`
}

View File

@ -2,29 +2,29 @@ package structfs
type EC2Metadata struct {
Latest struct {
Userdata string `json:"user-data"`
Metadata struct {
AMIManifestPath string `json:"ami-manifest-path"`
InstanceType string `json:"instance-type"`
LocalHostname string `json:"local-hostname"`
LocalIPv4 string `json:"local-ipv4"`
Placement string `json:"placement"`
AvailabilityZone string `json:"availability-zone"`
ProductCodes string `json:"product-codes"`
PublicHostname string `json:"public-hostname"`
PublicIPv4 string `json:"public-ipv4"`
PublicKeys []struct {
Key []string `json:"-"`
} `json:"public-keys"`
AncestorAMIIDs []int `json:"ancestor-ami-ids"`
BlockDeviceMapping []string `json:"block-device-mapping"`
SecurityGroups []string `json:"security-groups"`
RamdiskID int `json:"ramdisk-id"`
ReservationID int `json:"reservation-id"`
AMIID int `json:"ami-id"`
AMILaunchIndex int `json:"ami-launch-index"`
KernelID int `json:"kernel-id"`
AMIManifestPath string `json:"ami-manifest-path"`
AncestorAMIIDs []int `json:"ancestor-ami-ids"`
BlockDeviceMapping []string `json:"block-device-mapping"`
InstanceID int `json:"instance-id"`
InstanceType string `json:"instance-type"`
LocalHostname string `json:"local-hostname"`
LocalIPv4 string `json:"local-ipv4"`
KernelID int `json:"kernel-id"`
Placement string `json:"placement"`
AvailabilityZone string `json:"availability-zone"`
ProductCodes string `json:"product-codes"`
PublicHostname string `json:"public-hostname"`
PublicIPv4 string `json:"public-ipv4"`
PublicKeys []struct {
Key []string `json:"-"`
} `json:"public-keys"`
RamdiskID int `json:"ramdisk-id"`
ReservationID int `json:"reservation-id"`
SecurityGroups []string `json:"security-groups"`
} `json:"meta-data"`
Userdata string `json:"user-data"`
} `json:"latest"`
}

View File

@ -35,22 +35,22 @@ func (fs *fs) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
type fs struct {
modtime time.Time
iface interface{}
tag string
modtime time.Time
}
type file struct {
modtime time.Time
name string
data []byte
offset int64
data []byte
modtime time.Time
}
type fileInfo struct {
modtime time.Time
name string
size int64
modtime time.Time
}
func (fi *fileInfo) Sys() interface{} {
@ -105,7 +105,7 @@ func (f *file) Read(b []byte) (int, error) {
return n, err
}
func (f *file) Readdir(_ int) ([]os.FileInfo, error) {
func (f *file) Readdir(count int) ([]os.FileInfo, error) {
return nil, nil
}

View File

@ -93,7 +93,7 @@ func TestAll(t *testing.T) {
in string
out string
}{
{"http://127.0.0.1:8080/metadata/v1/", "features\nhostname\nvendor_data\nregion\npublic_keys\ndns\ninterfaces\ndroplet_id\nfloating_ip"},
{"http://127.0.0.1:8080/metadata/v1/", "droplet_id\nhostname\nvendor_data\npublic_keys\nregion\ninterfaces\nfloating_ip\ndns\nfeatures"},
{"http://127.0.0.1:8080/metadata/v1/droplet_id", "2756294"},
{"http://127.0.0.1:8080/metadata/v1/dns/", "nameservers"},
{"http://127.0.0.1:8080/metadata/v1/dns/nameservers", "2001:4860:4860::8844\n2001:4860:4860::8888\n8.8.8.8"},

View File

@ -78,8 +78,8 @@ var (
for _, se := range st.Details() {
switch ne := se.(type) {
case proto.Message:
var buf []byte
if buf, err = testCodec.Marshal(ne); err != nil {
buf, err := testCodec.Marshal(ne)
if err != nil {
return fmt.Errorf("failed to marshal err: %w", err)
}
if err = testCodec.Unmarshal(buf, &testMap); err != nil {
@ -438,10 +438,10 @@ func Run(ctx context.Context, c client.Client, m sqlmock.Sqlmock, dir string, ex
}
type Case struct {
dbfiles []string
reqfile string
rspfile string
errfile string
dbfiles []string
}
func GetCases(dir string, exts []string) ([]Case, error) {

View File

@ -1,5 +1,6 @@
package text
func DetectEncoding(text string) map[string]int {
charsets := map[string]int{
"UTF-8": 0,
@ -18,7 +19,7 @@ func DetectEncoding(text string) map[string]int {
utfupper := 5
lowercase := 3
uppercase := 1
lastSimb := 0
last_simb := 0
for a := 0; a < len(text); a++ {
char := int(text[a])
@ -29,10 +30,10 @@ func DetectEncoding(text string) map[string]int {
}
// UTF-8
if (lastSimb == 208) && ((char > 143 && char < 176) || char == 129) {
if (last_simb == 208) && ((char > 143 && char < 176) || char == 129) {
charsets["UTF-8"] += (utfupper * 2)
}
if ((lastSimb == 208) && ((char > 175 && char < 192) || char == 145)) || (lastSimb == 209 && char > 127 && char < 144) {
if ((last_simb == 208) && ((char > 175 && char < 192) || char == 145)) || (last_simb == 209 && char > 127 && char < 144) {
charsets["UTF-8"] += (utflower * 2)
}
@ -76,7 +77,7 @@ func DetectEncoding(text string) map[string]int {
charsets["MAC"] += uppercase
}
lastSimb = char
last_simb = char
}
return charsets

Some files were not shown because too many files have changed in this diff Show More