Compare commits
39 Commits
Author | SHA1 | Date | |
---|---|---|---|
ef664607b4 | |||
62e482a14b | |||
a390ebf80f | |||
9a44960be7 | |||
c846c59b9b | |||
|
902bf6326b | ||
|
bddf3bf502 | ||
|
284131da98 | ||
927c7ea3c2 | |||
0e51a79bb6 | |||
1de9911b73 | |||
b4092c6619 | |||
024868bfd7 | |||
a0bbfd6d02 | |||
2cb6843773 | |||
87e1480077 | |||
bcd7f6a551 | |||
925b3af46b | |||
ef4efa6a6b | |||
125646d89b | |||
7af7649448 | |||
827d467077 | |||
ac8a3a12c4 | |||
286785491c | |||
263ea8910d | |||
202a942eef | |||
c7bafecce3 | |||
c67fe6f330 | |||
8c3f0d2c64 | |||
8494178b0d | |||
8a2c4c511e | |||
dcca28944e | |||
92e6fd036e | |||
eab1a1dd40 | |||
188d9611c9 | |||
74a52eed9d | |||
770e8425bd | |||
4783c6d9a3 | |||
2b2bcf4586 |
19
.github/renovate.json
vendored
Normal file
19
.github/renovate.json
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"extends": [
|
||||||
|
"config:base"
|
||||||
|
],
|
||||||
|
"packageRules": [
|
||||||
|
{
|
||||||
|
"matchUpdateTypes": ["minor", "patch", "pin", "digest"],
|
||||||
|
"automerge": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"groupName": "all deps",
|
||||||
|
"separateMajorMinor": true,
|
||||||
|
"groupSlug": "all",
|
||||||
|
"packagePatterns": [
|
||||||
|
"*"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -9,7 +9,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: setup
|
- name: setup
|
||||||
uses: actions/setup-go@v1
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: 1.15
|
go-version: 1.15
|
||||||
- name: cache
|
- name: cache
|
||||||
@@ -49,7 +49,7 @@ jobs:
|
|||||||
- name: checkout
|
- name: checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: lint
|
- name: lint
|
||||||
uses: golangci/golangci-lint-action@v1
|
uses: golangci/golangci-lint-action@v2
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
|
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
|
||||||
|
4
.github/workflows/pr.yml
vendored
4
.github/workflows/pr.yml
vendored
@@ -9,7 +9,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: setup
|
- name: setup
|
||||||
uses: actions/setup-go@v1
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: 1.15
|
go-version: 1.15
|
||||||
- name: cache
|
- name: cache
|
||||||
@@ -49,7 +49,7 @@ jobs:
|
|||||||
- name: checkout
|
- name: checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: lint
|
- name: lint
|
||||||
uses: golangci/golangci-lint-action@v1
|
uses: golangci/golangci-lint-action@v2
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
|
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
|
||||||
|
@@ -6,7 +6,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/unistack-org/micro/v3/metadata"
|
"github.com/unistack-org/micro/v3/metadata"
|
||||||
"github.com/unistack-org/micro/v3/registry"
|
"github.com/unistack-org/micro/v3/register"
|
||||||
"github.com/unistack-org/micro/v3/server"
|
"github.com/unistack-org/micro/v3/server"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ type Service struct {
|
|||||||
// The endpoint for this service
|
// The endpoint for this service
|
||||||
Endpoint *Endpoint
|
Endpoint *Endpoint
|
||||||
// Versions of this service
|
// Versions of this service
|
||||||
Services []*registry.Service
|
Services []*register.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
func strip(s string) string {
|
func strip(s string) string {
|
||||||
@@ -98,6 +98,7 @@ func Encode(e *Endpoint) map[string]string {
|
|||||||
set("method", strings.Join(e.Method, ","))
|
set("method", strings.Join(e.Method, ","))
|
||||||
set("path", strings.Join(e.Path, ","))
|
set("path", strings.Join(e.Path, ","))
|
||||||
set("host", strings.Join(e.Host, ","))
|
set("host", strings.Join(e.Host, ","))
|
||||||
|
set("body", e.Body)
|
||||||
|
|
||||||
return ep
|
return ep
|
||||||
}
|
}
|
||||||
@@ -118,6 +119,7 @@ func Decode(e metadata.Metadata) *Endpoint {
|
|||||||
ephost, _ := e.Get("host")
|
ephost, _ := e.Get("host")
|
||||||
ep.Host = []string{ephost}
|
ep.Host = []string{ephost}
|
||||||
ep.Handler, _ = e.Get("handler")
|
ep.Handler, _ = e.Get("handler")
|
||||||
|
ep.Body, _ = e.Get("body")
|
||||||
|
|
||||||
return ep
|
return ep
|
||||||
}
|
}
|
||||||
|
@@ -11,7 +11,7 @@ import (
|
|||||||
|
|
||||||
"github.com/unistack-org/micro/v3/api"
|
"github.com/unistack-org/micro/v3/api"
|
||||||
"github.com/unistack-org/micro/v3/api/handler"
|
"github.com/unistack-org/micro/v3/api/handler"
|
||||||
"github.com/unistack-org/micro/v3/registry"
|
"github.com/unistack-org/micro/v3/register"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -70,7 +70,7 @@ func (h *httpHandler) getService(r *http.Request) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get the nodes for this service
|
// get the nodes for this service
|
||||||
nodes := make([]*registry.Node, 0, len(service.Services))
|
nodes := make([]*register.Node, 0, len(service.Services))
|
||||||
for _, srv := range service.Services {
|
for _, srv := range service.Services {
|
||||||
nodes = append(nodes, srv.Nodes...)
|
nodes = append(nodes, srv.Nodes...)
|
||||||
}
|
}
|
||||||
|
@@ -12,13 +12,13 @@ import (
|
|||||||
"github.com/unistack-org/micro/v3/api/resolver"
|
"github.com/unistack-org/micro/v3/api/resolver"
|
||||||
"github.com/unistack-org/micro/v3/api/resolver/vpath"
|
"github.com/unistack-org/micro/v3/api/resolver/vpath"
|
||||||
"github.com/unistack-org/micro/v3/api/router"
|
"github.com/unistack-org/micro/v3/api/router"
|
||||||
regRouter "github.com/unistack-org/micro/v3/api/router/registry"
|
regRouter "github.com/unistack-org/micro/v3/api/router/register"
|
||||||
"github.com/unistack-org/micro/v3/registry"
|
"github.com/unistack-org/micro/v3/register"
|
||||||
"github.com/unistack-org/micro/v3/registry/memory"
|
"github.com/unistack-org/micro/v3/register/memory"
|
||||||
)
|
)
|
||||||
|
|
||||||
func testHttp(t *testing.T, path, service, ns string) {
|
func testHttp(t *testing.T, path, service, ns string) {
|
||||||
r := memory.NewRegistry()
|
r := memory.NewRegister()
|
||||||
|
|
||||||
l, err := net.Listen("tcp", "127.0.0.1:0")
|
l, err := net.Listen("tcp", "127.0.0.1:0")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -26,9 +26,9 @@ func testHttp(t *testing.T, path, service, ns string) {
|
|||||||
}
|
}
|
||||||
defer l.Close()
|
defer l.Close()
|
||||||
|
|
||||||
s := ®istry.Service{
|
s := ®ister.Service{
|
||||||
Name: service,
|
Name: service,
|
||||||
Nodes: []*registry.Node{
|
Nodes: []*register.Node{
|
||||||
{
|
{
|
||||||
Id: service + "-1",
|
Id: service + "-1",
|
||||||
Address: l.Addr().String(),
|
Address: l.Addr().String(),
|
||||||
@@ -58,7 +58,7 @@ func testHttp(t *testing.T, path, service, ns string) {
|
|||||||
// initialise the handler
|
// initialise the handler
|
||||||
rt := regRouter.NewRouter(
|
rt := regRouter.NewRouter(
|
||||||
router.WithHandler("http"),
|
router.WithHandler("http"),
|
||||||
router.WithRegistry(r),
|
router.WithRegister(r),
|
||||||
router.WithResolver(vpath.NewResolver(
|
router.WithResolver(vpath.NewResolver(
|
||||||
resolver.WithServicePrefix(ns),
|
resolver.WithServicePrefix(ns),
|
||||||
)),
|
)),
|
||||||
|
@@ -14,7 +14,7 @@ import (
|
|||||||
|
|
||||||
"github.com/unistack-org/micro/v3/api"
|
"github.com/unistack-org/micro/v3/api"
|
||||||
"github.com/unistack-org/micro/v3/api/handler"
|
"github.com/unistack-org/micro/v3/api/handler"
|
||||||
"github.com/unistack-org/micro/v3/registry"
|
"github.com/unistack-org/micro/v3/register"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -72,7 +72,7 @@ func (wh *webHandler) getService(r *http.Request) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get the nodes
|
// get the nodes
|
||||||
nodes := make([]*registry.Node, 0, len(service.Services))
|
nodes := make([]*register.Node, 0, len(service.Services))
|
||||||
for _, srv := range service.Services {
|
for _, srv := range service.Services {
|
||||||
nodes = append(nodes, srv.Nodes...)
|
nodes = append(nodes, srv.Nodes...)
|
||||||
}
|
}
|
||||||
|
@@ -3,7 +3,7 @@ package resolver
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/unistack-org/micro/v3/registry"
|
"github.com/unistack-org/micro/v3/register"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Options struct
|
// Options struct
|
||||||
@@ -58,7 +58,7 @@ func Domain(n string) ResolveOption {
|
|||||||
|
|
||||||
// NewResolveOptions returns new initialised resolve options
|
// NewResolveOptions returns new initialised resolve options
|
||||||
func NewResolveOptions(opts ...ResolveOption) ResolveOptions {
|
func NewResolveOptions(opts ...ResolveOption) ResolveOptions {
|
||||||
options := ResolveOptions{Domain: registry.DefaultDomain}
|
options := ResolveOptions{Domain: register.DefaultDomain}
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
o(&options)
|
o(&options)
|
||||||
}
|
}
|
||||||
|
@@ -5,13 +5,15 @@ import (
|
|||||||
|
|
||||||
"github.com/unistack-org/micro/v3/api/resolver"
|
"github.com/unistack-org/micro/v3/api/resolver"
|
||||||
"github.com/unistack-org/micro/v3/api/resolver/vpath"
|
"github.com/unistack-org/micro/v3/api/resolver/vpath"
|
||||||
"github.com/unistack-org/micro/v3/registry"
|
"github.com/unistack-org/micro/v3/logger"
|
||||||
|
"github.com/unistack-org/micro/v3/register"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Options struct {
|
type Options struct {
|
||||||
Handler string
|
Handler string
|
||||||
Registry registry.Registry
|
Register register.Register
|
||||||
Resolver resolver.Resolver
|
Resolver resolver.Resolver
|
||||||
|
Logger logger.Logger
|
||||||
Context context.Context
|
Context context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,10 +52,10 @@ func WithHandler(h string) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithRegistry sets the registry
|
// WithRegister sets the register
|
||||||
func WithRegistry(r registry.Registry) Option {
|
func WithRegister(r register.Register) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
o.Registry = r
|
o.Register = r
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,29 +0,0 @@
|
|||||||
// Package acme abstracts away various ACME libraries
|
|
||||||
package acme
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/tls"
|
|
||||||
"errors"
|
|
||||||
"net"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// ErrProviderNotImplemented can be returned when attempting to
|
|
||||||
// instantiate an unimplemented provider
|
|
||||||
ErrProviderNotImplemented = errors.New("Provider not implemented")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Provider is a ACME provider interface
|
|
||||||
type Provider interface {
|
|
||||||
Init(...Option) error
|
|
||||||
// Listen returns a new listener
|
|
||||||
Listen(...string) (net.Listener, error)
|
|
||||||
// TLSConfig returns a tls config
|
|
||||||
TLSConfig(...string) (*tls.Config, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// The Let's Encrypt ACME endpoints
|
|
||||||
const (
|
|
||||||
LetsEncryptStagingCA = "https://acme-staging-v02.api.letsencrypt.org/directory"
|
|
||||||
LetsEncryptProductionCA = "https://acme-v02.api.letsencrypt.org/directory"
|
|
||||||
)
|
|
@@ -1,53 +0,0 @@
|
|||||||
// Package autocert is the ACME provider from golang.org/x/crypto/acme/autocert
|
|
||||||
// This provider does not take any config.
|
|
||||||
package autocert
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/tls"
|
|
||||||
"net"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/unistack-org/micro/v3/api/server"
|
|
||||||
"github.com/unistack-org/micro/v3/api/server/acme"
|
|
||||||
"github.com/unistack-org/micro/v3/logger"
|
|
||||||
"golang.org/x/crypto/acme/autocert"
|
|
||||||
)
|
|
||||||
|
|
||||||
// autoCertACME is the ACME provider from golang.org/x/crypto/acme/autocert
|
|
||||||
type autocertProvider struct {
|
|
||||||
opts server.Options
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *autocertProvider) Init(opts ...acme.Option) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Listen implements acme.Provider
|
|
||||||
func (a *autocertProvider) Listen(hosts ...string) (net.Listener, error) {
|
|
||||||
return autocert.NewListener(hosts...), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TLSConfig returns a new tls config
|
|
||||||
func (a *autocertProvider) TLSConfig(hosts ...string) (*tls.Config, error) {
|
|
||||||
// create a new manager
|
|
||||||
m := &autocert.Manager{
|
|
||||||
Prompt: autocert.AcceptTOS,
|
|
||||||
}
|
|
||||||
if len(hosts) > 0 {
|
|
||||||
m.HostPolicy = autocert.HostWhitelist(hosts...)
|
|
||||||
}
|
|
||||||
dir := cacheDir()
|
|
||||||
if err := os.MkdirAll(dir, 0700); err != nil {
|
|
||||||
if logger.V(logger.InfoLevel) {
|
|
||||||
logger.Info(a.opts.Context, "warning: autocert not using a cache: %v", err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
m.Cache = autocert.DirCache(dir)
|
|
||||||
}
|
|
||||||
return m.TLSConfig(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// New returns an autocert acme.Provider
|
|
||||||
func NewProvider() acme.Provider {
|
|
||||||
return &autocertProvider{}
|
|
||||||
}
|
|
@@ -1,16 +0,0 @@
|
|||||||
package autocert
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestAutocert(t *testing.T) {
|
|
||||||
l := NewProvider()
|
|
||||||
if _, ok := l.(*autocertProvider); !ok {
|
|
||||||
t.Error("NewProvider() didn't return an autocertProvider")
|
|
||||||
}
|
|
||||||
// TODO: Travis CI doesn't let us bind :443
|
|
||||||
// if _, err := l.NewListener(); err != nil {
|
|
||||||
// t.Error(err.Error())
|
|
||||||
// }
|
|
||||||
}
|
|
@@ -1,37 +0,0 @@
|
|||||||
package autocert
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
func homeDir() string {
|
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
return os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
|
|
||||||
}
|
|
||||||
if h := os.Getenv("HOME"); h != "" {
|
|
||||||
return h
|
|
||||||
}
|
|
||||||
return "/"
|
|
||||||
}
|
|
||||||
|
|
||||||
func cacheDir() string {
|
|
||||||
const base = "golang-autocert"
|
|
||||||
switch runtime.GOOS {
|
|
||||||
case "darwin":
|
|
||||||
return filepath.Join(homeDir(), "Library", "Caches", base)
|
|
||||||
case "windows":
|
|
||||||
for _, ev := range []string{"APPDATA", "CSIDL_APPDATA", "TEMP", "TMP"} {
|
|
||||||
if v := os.Getenv(ev); v != "" {
|
|
||||||
return filepath.Join(v, base)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Worst case:
|
|
||||||
return filepath.Join(homeDir(), base)
|
|
||||||
}
|
|
||||||
if xdg := os.Getenv("XDG_CACHE_HOME"); xdg != "" {
|
|
||||||
return filepath.Join(xdg, base)
|
|
||||||
}
|
|
||||||
return filepath.Join(homeDir(), ".cache", base)
|
|
||||||
}
|
|
@@ -1,71 +0,0 @@
|
|||||||
// Package certmagic is the ACME provider from github.com/caddyserver/certmagic
|
|
||||||
package certmagic
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/tls"
|
|
||||||
"fmt"
|
|
||||||
"math/rand"
|
|
||||||
"net"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/caddyserver/certmagic"
|
|
||||||
"github.com/unistack-org/micro/v3/api/server/acme"
|
|
||||||
)
|
|
||||||
|
|
||||||
type certmagicProvider struct {
|
|
||||||
opts acme.Options
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: set self-contained options
|
|
||||||
func (c *certmagicProvider) setup() {
|
|
||||||
certmagic.DefaultACME.CA = c.opts.CA
|
|
||||||
if c.opts.ChallengeProvider != nil {
|
|
||||||
// Enabling DNS Challenge disables the other challenges
|
|
||||||
certmagic.DefaultACME.DNSProvider = c.opts.ChallengeProvider
|
|
||||||
}
|
|
||||||
if c.opts.OnDemand {
|
|
||||||
certmagic.Default.OnDemand = new(certmagic.OnDemandConfig)
|
|
||||||
}
|
|
||||||
if c.opts.Cache != nil {
|
|
||||||
// already validated by new()
|
|
||||||
certmagic.Default.Storage = c.opts.Cache.(certmagic.Storage)
|
|
||||||
}
|
|
||||||
// If multiple instances of the provider are running, inject some
|
|
||||||
// randomness so they don't collide
|
|
||||||
// RenewalWindowRatio [0.33 - 0.50)
|
|
||||||
rand.Seed(time.Now().UnixNano())
|
|
||||||
randomRatio := float64(rand.Intn(17)+33) * 0.01
|
|
||||||
certmagic.Default.RenewalWindowRatio = randomRatio
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *certmagicProvider) Listen(hosts ...string) (net.Listener, error) {
|
|
||||||
c.setup()
|
|
||||||
return certmagic.Listen(hosts)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *certmagicProvider) TLSConfig(hosts ...string) (*tls.Config, error) {
|
|
||||||
c.setup()
|
|
||||||
return certmagic.TLS(hosts)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *certmagicProvider) Init(opts ...acme.Option) error {
|
|
||||||
if p.opts.Cache != nil {
|
|
||||||
if _, ok := p.opts.Cache.(certmagic.Storage); !ok {
|
|
||||||
return fmt.Errorf("ACME: cache provided doesn't implement certmagic's Storage interface")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewProvider returns a certmagic provider
|
|
||||||
func NewProvider(options ...acme.Option) acme.Provider {
|
|
||||||
opts := acme.DefaultOptions()
|
|
||||||
|
|
||||||
for _, o := range options {
|
|
||||||
o(&opts)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &certmagicProvider{
|
|
||||||
opts: opts,
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,138 +0,0 @@
|
|||||||
package certmagic
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/gob"
|
|
||||||
"errors"
|
|
||||||
"path"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/caddyserver/certmagic"
|
|
||||||
"github.com/unistack-org/micro/v3/store"
|
|
||||||
"github.com/unistack-org/micro/v3/sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
// File represents a "File" that will be stored in store.Store - the contents and last modified time
|
|
||||||
type File struct {
|
|
||||||
// last modified time
|
|
||||||
LastModified time.Time
|
|
||||||
// Contents
|
|
||||||
Contents []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// storage is an implementation of certmagic.Storage using micro's sync.Map and store.Store interfaces.
|
|
||||||
// As certmagic storage expects a filesystem (with stat() abilities) we have to implement
|
|
||||||
// the bare minimum of metadata.
|
|
||||||
type storage struct {
|
|
||||||
lock sync.Sync
|
|
||||||
store store.Store
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *storage) Lock(key string) error {
|
|
||||||
return s.lock.Lock(key, sync.LockTTL(10*time.Minute))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *storage) Unlock(key string) error {
|
|
||||||
return s.lock.Unlock(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *storage) Store(key string, value []byte) error {
|
|
||||||
f := File{
|
|
||||||
LastModified: time.Now(),
|
|
||||||
Contents: value,
|
|
||||||
}
|
|
||||||
buf := &bytes.Buffer{}
|
|
||||||
e := gob.NewEncoder(buf)
|
|
||||||
if err := e.Encode(f); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return s.store.Write(s.store.Options().Context, key, buf.Bytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *storage) Load(key string) ([]byte, error) {
|
|
||||||
if !s.Exists(key) {
|
|
||||||
return nil, certmagic.ErrNotExist(errors.New(key + " doesn't exist"))
|
|
||||||
}
|
|
||||||
var val []byte
|
|
||||||
err := s.store.Read(s.store.Options().Context, key, val)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
b := bytes.NewBuffer(val)
|
|
||||||
d := gob.NewDecoder(b)
|
|
||||||
var f File
|
|
||||||
err = d.Decode(&f)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return f.Contents, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *storage) Delete(key string) error {
|
|
||||||
return s.store.Delete(s.store.Options().Context, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *storage) Exists(key string) bool {
|
|
||||||
if err := s.store.Read(s.store.Options().Context, key, nil); err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *storage) List(prefix string, recursive bool) ([]string, error) {
|
|
||||||
keys, err := s.store.List(s.store.Options().Context)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
//nolint:prealloc
|
|
||||||
var results []string
|
|
||||||
for _, k := range keys {
|
|
||||||
if strings.HasPrefix(k, prefix) {
|
|
||||||
results = append(results, k)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if recursive {
|
|
||||||
return results, nil
|
|
||||||
}
|
|
||||||
keysMap := make(map[string]bool)
|
|
||||||
for _, key := range results {
|
|
||||||
dir := strings.Split(strings.TrimPrefix(key, prefix+"/"), "/")
|
|
||||||
keysMap[dir[0]] = true
|
|
||||||
}
|
|
||||||
results = make([]string, 0)
|
|
||||||
for k := range keysMap {
|
|
||||||
results = append(results, path.Join(prefix, k))
|
|
||||||
}
|
|
||||||
return results, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *storage) Stat(key string) (certmagic.KeyInfo, error) {
|
|
||||||
var val []byte
|
|
||||||
err := s.store.Read(s.store.Options().Context, key, val)
|
|
||||||
if err != nil {
|
|
||||||
return certmagic.KeyInfo{}, err
|
|
||||||
}
|
|
||||||
b := bytes.NewBuffer(val)
|
|
||||||
d := gob.NewDecoder(b)
|
|
||||||
var f File
|
|
||||||
err = d.Decode(&f)
|
|
||||||
if err != nil {
|
|
||||||
return certmagic.KeyInfo{}, err
|
|
||||||
}
|
|
||||||
return certmagic.KeyInfo{
|
|
||||||
Key: key,
|
|
||||||
Modified: f.LastModified,
|
|
||||||
Size: int64(len(f.Contents)),
|
|
||||||
IsTerminal: false,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewStorage returns a certmagic.Storage backed by a micro/lock and micro/store
|
|
||||||
func NewStorage(lock sync.Sync, store store.Store) certmagic.Storage {
|
|
||||||
return &storage{
|
|
||||||
lock: lock,
|
|
||||||
store: store,
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,73 +0,0 @@
|
|||||||
package acme
|
|
||||||
|
|
||||||
import "github.com/go-acme/lego/v3/challenge"
|
|
||||||
|
|
||||||
// Option (or Options) are passed to New() to configure providers
|
|
||||||
type Option func(o *Options)
|
|
||||||
|
|
||||||
// Options represents various options you can present to ACME providers
|
|
||||||
type Options struct {
|
|
||||||
// AcceptTLS must be set to true to indicate that you have read your
|
|
||||||
// provider's terms of service.
|
|
||||||
AcceptToS bool
|
|
||||||
// CA is the CA to use
|
|
||||||
CA string
|
|
||||||
// ChallengeProvider is a go-acme/lego challenge provider. Set this if you
|
|
||||||
// want to use DNS Challenges. Otherwise, tls-alpn-01 will be used
|
|
||||||
ChallengeProvider challenge.Provider
|
|
||||||
// Issue certificates for domains on demand. Otherwise, certs will be
|
|
||||||
// retrieved / issued on start-up.
|
|
||||||
OnDemand bool
|
|
||||||
// Cache is a storage interface. Most ACME libraries have an cache, but
|
|
||||||
// there's no defined interface, so if you consume this option
|
|
||||||
// sanity check it before using.
|
|
||||||
Cache interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AcceptToS indicates whether you accept your CA's terms of service
|
|
||||||
func AcceptToS(b bool) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.AcceptToS = b
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CA sets the CA of an acme.Options
|
|
||||||
func CA(CA string) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.CA = CA
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChallengeProvider sets the Challenge provider of an acme.Options
|
|
||||||
// if set, it enables the DNS challenge, otherwise tls-alpn-01 will be used.
|
|
||||||
func ChallengeProvider(p challenge.Provider) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.ChallengeProvider = p
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// OnDemand enables on-demand certificate issuance. Not recommended for use
|
|
||||||
// with the DNS challenge, as the first connection may be very slow.
|
|
||||||
func OnDemand(b bool) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.OnDemand = b
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cache provides a cache / storage interface to the underlying ACME library
|
|
||||||
// as there is no standard, this needs to be validated by the underlying
|
|
||||||
// implementation
|
|
||||||
func Cache(c interface{}) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.Cache = c
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultOptions uses the Let's Encrypt Production CA, with DNS Challenge disabled.
|
|
||||||
func DefaultOptions() Options {
|
|
||||||
return Options{
|
|
||||||
AcceptToS: true,
|
|
||||||
CA: LetsEncryptProductionCA,
|
|
||||||
OnDemand: true,
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,44 +0,0 @@
|
|||||||
package cors
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CombinedCORSHandler wraps a server and provides CORS headers
|
|
||||||
func CombinedCORSHandler(h http.Handler) http.Handler {
|
|
||||||
return corsHandler{h}
|
|
||||||
}
|
|
||||||
|
|
||||||
type corsHandler struct {
|
|
||||||
handler http.Handler
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c corsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
||||||
SetHeaders(w, r)
|
|
||||||
|
|
||||||
if r.Method == "OPTIONS" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.handler.ServeHTTP(w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetHeaders sets the CORS headers
|
|
||||||
func SetHeaders(w http.ResponseWriter, r *http.Request) {
|
|
||||||
set := func(w http.ResponseWriter, k, v string) {
|
|
||||||
if v := w.Header().Get(k); len(v) > 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w.Header().Set(k, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
if origin := r.Header.Get("Origin"); len(origin) > 0 {
|
|
||||||
set(w, "Access-Control-Allow-Origin", origin)
|
|
||||||
} else {
|
|
||||||
set(w, "Access-Control-Allow-Origin", "*")
|
|
||||||
}
|
|
||||||
|
|
||||||
set(w, "Access-Control-Allow-Credentials", "true")
|
|
||||||
set(w, "Access-Control-Allow-Methods", "POST, PATCH, GET, OPTIONS, PUT, DELETE")
|
|
||||||
set(w, "Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
|
|
||||||
}
|
|
@@ -1,110 +0,0 @@
|
|||||||
// Package http provides a http server with features; acme, cors, etc
|
|
||||||
package http
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/tls"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/unistack-org/micro/v3/api/server"
|
|
||||||
"github.com/unistack-org/micro/v3/logger"
|
|
||||||
)
|
|
||||||
|
|
||||||
type httpServer struct {
|
|
||||||
mux *http.ServeMux
|
|
||||||
opts server.Options
|
|
||||||
|
|
||||||
sync.RWMutex
|
|
||||||
address string
|
|
||||||
exit chan chan error
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewServer(address string, opts ...server.Option) server.Server {
|
|
||||||
return &httpServer{
|
|
||||||
opts: server.NewOptions(opts...),
|
|
||||||
mux: http.NewServeMux(),
|
|
||||||
address: address,
|
|
||||||
exit: make(chan chan error),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *httpServer) Address() string {
|
|
||||||
s.RLock()
|
|
||||||
defer s.RUnlock()
|
|
||||||
return s.address
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *httpServer) Init(opts ...server.Option) error {
|
|
||||||
for _, o := range opts {
|
|
||||||
o(&s.opts)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *httpServer) Handle(path string, handler http.Handler) {
|
|
||||||
// TODO: move this stuff out to one place with ServeHTTP
|
|
||||||
|
|
||||||
// apply the wrappers, e.g. auth
|
|
||||||
for _, wrapper := range s.opts.Wrappers {
|
|
||||||
handler = wrapper(handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
s.mux.Handle(path, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *httpServer) Start() error {
|
|
||||||
var l net.Listener
|
|
||||||
var err error
|
|
||||||
|
|
||||||
s.RLock()
|
|
||||||
config := s.opts
|
|
||||||
s.RUnlock()
|
|
||||||
if s.opts.EnableACME && s.opts.ACMEProvider != nil {
|
|
||||||
// should we check the address to make sure its using :443?
|
|
||||||
l, err = s.opts.ACMEProvider.Listen(s.opts.ACMEHosts...)
|
|
||||||
} else if s.opts.EnableTLS && s.opts.TLSConfig != nil {
|
|
||||||
l, err = tls.Listen("tcp", s.address, s.opts.TLSConfig)
|
|
||||||
} else {
|
|
||||||
// otherwise plain listen
|
|
||||||
l, err = net.Listen("tcp", s.address)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.Logger.V(logger.InfoLevel) {
|
|
||||||
config.Logger.Infof(s.opts.Context, "HTTP API Listening on %s", l.Addr().String())
|
|
||||||
}
|
|
||||||
|
|
||||||
s.Lock()
|
|
||||||
s.address = l.Addr().String()
|
|
||||||
s.Unlock()
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
if err := http.Serve(l, s.mux); err != nil {
|
|
||||||
// temporary fix
|
|
||||||
if config.Logger.V(logger.ErrorLevel) {
|
|
||||||
config.Logger.Errorf(s.opts.Context, "serve err: %v", err)
|
|
||||||
}
|
|
||||||
s.Stop()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
ch := <-s.exit
|
|
||||||
ch <- l.Close()
|
|
||||||
}()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *httpServer) Stop() error {
|
|
||||||
ch := make(chan error)
|
|
||||||
s.exit <- ch
|
|
||||||
return <-ch
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *httpServer) String() string {
|
|
||||||
return "http"
|
|
||||||
}
|
|
@@ -1,41 +0,0 @@
|
|||||||
package http
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestHTTPServer(t *testing.T) {
|
|
||||||
testResponse := "hello world"
|
|
||||||
|
|
||||||
s := NewServer("localhost:0")
|
|
||||||
|
|
||||||
s.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprint(w, testResponse)
|
|
||||||
}))
|
|
||||||
|
|
||||||
if err := s.Start(); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
rsp, err := http.Get(fmt.Sprintf("http://%s/", s.Address()))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer rsp.Body.Close()
|
|
||||||
|
|
||||||
b, err := ioutil.ReadAll(rsp.Body)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if string(b) != testResponse {
|
|
||||||
t.Fatalf("Unexpected response, got %s, expected %s", string(b), testResponse)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := s.Stop(); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,96 +0,0 @@
|
|||||||
package server
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/tls"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/unistack-org/micro/v3/api/resolver"
|
|
||||||
"github.com/unistack-org/micro/v3/api/server/acme"
|
|
||||||
"github.com/unistack-org/micro/v3/logger"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Option func
|
|
||||||
type Option func(o *Options)
|
|
||||||
|
|
||||||
// Options for api server
|
|
||||||
type Options struct {
|
|
||||||
EnableACME bool
|
|
||||||
EnableCORS bool
|
|
||||||
ACMEProvider acme.Provider
|
|
||||||
EnableTLS bool
|
|
||||||
ACMEHosts []string
|
|
||||||
TLSConfig *tls.Config
|
|
||||||
Resolver resolver.Resolver
|
|
||||||
Wrappers []Wrapper
|
|
||||||
Logger logger.Logger
|
|
||||||
Context context.Context
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewOptions returns new Options
|
|
||||||
func NewOptions(opts ...Option) Options {
|
|
||||||
options := Options{
|
|
||||||
Logger: logger.DefaultLogger,
|
|
||||||
Context: context.Background(),
|
|
||||||
}
|
|
||||||
for _, o := range opts {
|
|
||||||
o(&options)
|
|
||||||
}
|
|
||||||
return options
|
|
||||||
}
|
|
||||||
|
|
||||||
type Wrapper func(h http.Handler) http.Handler
|
|
||||||
|
|
||||||
func WrapHandler(w ...Wrapper) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.Wrappers = append(o.Wrappers, w...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func EnableCORS(b bool) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.EnableCORS = b
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func EnableACME(b bool) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.EnableACME = b
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ACMEHosts(hosts ...string) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.ACMEHosts = hosts
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ACMEProvider(p acme.Provider) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.ACMEProvider = p
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func EnableTLS(b bool) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.EnableTLS = b
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TLSConfig(t *tls.Config) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.TLSConfig = t
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Resolver(r resolver.Resolver) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.Resolver = r
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Logger(l logger.Logger) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.Logger = l
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,15 +0,0 @@
|
|||||||
// Package server provides an API gateway server which handles inbound requests
|
|
||||||
package server
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Server serves api requests
|
|
||||||
type Server interface {
|
|
||||||
Address() string
|
|
||||||
Init(opts ...Option) error
|
|
||||||
Handle(path string, handler http.Handler)
|
|
||||||
Start() error
|
|
||||||
Stop() error
|
|
||||||
}
|
|
@@ -6,13 +6,17 @@ import (
|
|||||||
|
|
||||||
"github.com/unistack-org/micro/v3/logger"
|
"github.com/unistack-org/micro/v3/logger"
|
||||||
"github.com/unistack-org/micro/v3/metadata"
|
"github.com/unistack-org/micro/v3/metadata"
|
||||||
|
"github.com/unistack-org/micro/v3/meter"
|
||||||
"github.com/unistack-org/micro/v3/store"
|
"github.com/unistack-org/micro/v3/store"
|
||||||
|
"github.com/unistack-org/micro/v3/tracer"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewOptions creates Options struct from slice of options
|
// NewOptions creates Options struct from slice of options
|
||||||
func NewOptions(opts ...Option) Options {
|
func NewOptions(opts ...Option) Options {
|
||||||
options := Options{
|
options := Options{
|
||||||
|
Tracer: tracer.DefaultTracer,
|
||||||
Logger: logger.DefaultLogger,
|
Logger: logger.DefaultLogger,
|
||||||
|
Meter: meter.DefaultMeter,
|
||||||
}
|
}
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
o(&options)
|
o(&options)
|
||||||
@@ -21,6 +25,7 @@ func NewOptions(opts ...Option) Options {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Options struct {
|
type Options struct {
|
||||||
|
Name string
|
||||||
// Issuer of the service's account
|
// Issuer of the service's account
|
||||||
Issuer string
|
Issuer string
|
||||||
// ID is the services auth ID
|
// ID is the services auth ID
|
||||||
@@ -41,6 +46,10 @@ type Options struct {
|
|||||||
Addrs []string
|
Addrs []string
|
||||||
// Logger sets the logger
|
// Logger sets the logger
|
||||||
Logger logger.Logger
|
Logger logger.Logger
|
||||||
|
// Meter sets tht meter
|
||||||
|
Meter meter.Meter
|
||||||
|
// Tracer
|
||||||
|
Tracer tracer.Tracer
|
||||||
// Context to store other options
|
// Context to store other options
|
||||||
Context context.Context
|
Context context.Context
|
||||||
}
|
}
|
||||||
@@ -55,6 +64,13 @@ func Addrs(addrs ...string) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Name sets the name
|
||||||
|
func Name(n string) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Name = n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Issuer of the services account
|
// Issuer of the services account
|
||||||
func Issuer(i string) Option {
|
func Issuer(i string) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
@@ -288,3 +304,17 @@ func Logger(l logger.Logger) Option {
|
|||||||
o.Logger = l
|
o.Logger = l
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Meter sets the meter
|
||||||
|
func Meter(m meter.Meter) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Meter = m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tracer sets the meter
|
||||||
|
func Tracer(t tracer.Tracer) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Tracer = t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -14,6 +14,7 @@ var (
|
|||||||
|
|
||||||
// Broker is an interface used for asynchronous messaging.
|
// Broker is an interface used for asynchronous messaging.
|
||||||
type Broker interface {
|
type Broker interface {
|
||||||
|
Name() string
|
||||||
Init(...Option) error
|
Init(...Option) error
|
||||||
Options() Options
|
Options() Options
|
||||||
Address() string
|
Address() string
|
||||||
|
@@ -16,6 +16,10 @@ func NewBroker(opts ...Option) Broker {
|
|||||||
return &noopBroker{opts: NewOptions(opts...)}
|
return &noopBroker{opts: NewOptions(opts...)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *noopBroker) Name() string {
|
||||||
|
return n.opts.Name
|
||||||
|
}
|
||||||
|
|
||||||
// Init initialize broker
|
// Init initialize broker
|
||||||
func (n *noopBroker) Init(opts ...Option) error {
|
func (n *noopBroker) Init(opts ...Option) error {
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
|
@@ -6,36 +6,43 @@ import (
|
|||||||
|
|
||||||
"github.com/unistack-org/micro/v3/codec"
|
"github.com/unistack-org/micro/v3/codec"
|
||||||
"github.com/unistack-org/micro/v3/logger"
|
"github.com/unistack-org/micro/v3/logger"
|
||||||
"github.com/unistack-org/micro/v3/registry"
|
"github.com/unistack-org/micro/v3/meter"
|
||||||
|
"github.com/unistack-org/micro/v3/register"
|
||||||
|
"github.com/unistack-org/micro/v3/tracer"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Options struct
|
// Options struct
|
||||||
type Options struct {
|
type Options struct {
|
||||||
Addrs []string
|
Name string
|
||||||
Secure bool
|
// Addrs useed by broker
|
||||||
|
Addrs []string
|
||||||
// Codec
|
// ErrorHandler executed when errors occur processing messages
|
||||||
Codec codec.Codec
|
|
||||||
|
|
||||||
// Logger the logger
|
|
||||||
Logger logger.Logger
|
|
||||||
// Handler executed when errors occur processing messages
|
|
||||||
ErrorHandler Handler
|
ErrorHandler Handler
|
||||||
|
// Codec used to marshal/unmarshal messages
|
||||||
|
Codec codec.Codec
|
||||||
|
// Logger the used logger
|
||||||
|
Logger logger.Logger
|
||||||
|
// Meter the used for metrics
|
||||||
|
Meter meter.Meter
|
||||||
|
// Tracer used for trace
|
||||||
|
Tracer tracer.Tracer
|
||||||
|
// TLSConfig for secure communication
|
||||||
TLSConfig *tls.Config
|
TLSConfig *tls.Config
|
||||||
// Registry used for clustering
|
// Register used for clustering
|
||||||
Registry registry.Registry
|
Register register.Register
|
||||||
// Other options for implementations of the interface
|
// Context is used for non default options
|
||||||
// can be stored in a context
|
|
||||||
Context context.Context
|
Context context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewOptions create new Options
|
// NewOptions create new Options
|
||||||
func NewOptions(opts ...Option) Options {
|
func NewOptions(opts ...Option) Options {
|
||||||
options := Options{
|
options := Options{
|
||||||
Registry: registry.DefaultRegistry,
|
Register: register.DefaultRegister,
|
||||||
Logger: logger.DefaultLogger,
|
Logger: logger.DefaultLogger,
|
||||||
Context: context.Background(),
|
Context: context.Background(),
|
||||||
|
Meter: meter.DefaultMeter,
|
||||||
|
Codec: codec.DefaultCodec,
|
||||||
|
Tracer: tracer.DefaultTracer,
|
||||||
}
|
}
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
o(&options)
|
o(&options)
|
||||||
@@ -54,8 +61,7 @@ func Context(ctx context.Context) Option {
|
|||||||
type PublishOptions struct {
|
type PublishOptions struct {
|
||||||
// BodyOnly says that only body of the message must be published
|
// BodyOnly says that only body of the message must be published
|
||||||
BodyOnly bool
|
BodyOnly bool
|
||||||
// Other options for implementations of the interface
|
// Context for non default options
|
||||||
// can be stored in a context
|
|
||||||
Context context.Context
|
Context context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,10 +83,10 @@ type SubscribeOptions struct {
|
|||||||
// AutoAck ack messages if handler returns nil err
|
// AutoAck ack messages if handler returns nil err
|
||||||
AutoAck bool
|
AutoAck bool
|
||||||
|
|
||||||
// Handler executed when errors occur processing messages
|
// ErrorHandler executed when errors occur processing messages
|
||||||
ErrorHandler Handler
|
ErrorHandler Handler
|
||||||
|
|
||||||
// Subscribers with the same group name
|
// Group for subscriber, Subscribers with the same group name
|
||||||
// will create a shared subscription where each
|
// will create a shared subscription where each
|
||||||
// receives a subset of messages.
|
// receives a subset of messages.
|
||||||
Group string
|
Group string
|
||||||
@@ -88,8 +94,7 @@ type SubscribeOptions struct {
|
|||||||
// BodyOnly says that consumed only body of the message
|
// BodyOnly says that consumed only body of the message
|
||||||
BodyOnly bool
|
BodyOnly bool
|
||||||
|
|
||||||
// Other options for implementations of the interface
|
// Context is used for non default options
|
||||||
// can be stored in a context
|
|
||||||
Context context.Context
|
Context context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,17 +203,10 @@ func SubscribeGroup(name string) SubscribeOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Registry sets registry option
|
// Register sets register option
|
||||||
func Registry(r registry.Registry) Option {
|
func Register(r register.Register) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
o.Registry = r
|
o.Register = r
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Secure communication with the broker
|
|
||||||
func Secure(b bool) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.Secure = b
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,6 +224,27 @@ func Logger(l logger.Logger) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tracer to be used for tracing
|
||||||
|
func Tracer(t tracer.Tracer) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Tracer = t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Meter sets the meter
|
||||||
|
func Meter(m meter.Meter) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Meter = m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name sets the name
|
||||||
|
func Name(n string) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Name = n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SubscribeContext set context
|
// SubscribeContext set context
|
||||||
func SubscribeContext(ctx context.Context) SubscribeOption {
|
func SubscribeContext(ctx context.Context) SubscribeOption {
|
||||||
return func(o *SubscribeOptions) {
|
return func(o *SubscribeOptions) {
|
||||||
|
@@ -18,6 +18,7 @@ var (
|
|||||||
// It supports Request/Response via Transport and Publishing via the Broker.
|
// It supports Request/Response via Transport and Publishing via the Broker.
|
||||||
// It also supports bidirectional streaming of requests.
|
// It also supports bidirectional streaming of requests.
|
||||||
type Client interface {
|
type Client interface {
|
||||||
|
Name() string
|
||||||
Init(...Option) error
|
Init(...Option) error
|
||||||
Options() Options
|
Options() Options
|
||||||
NewMessage(topic string, msg interface{}, opts ...MessageOption) Message
|
NewMessage(topic string, msg interface{}, opts ...MessageOption) Message
|
||||||
|
@@ -32,3 +32,23 @@ func SetPublishOption(k, v interface{}) PublishOption {
|
|||||||
o.Context = context.WithValue(o.Context, k, v)
|
o.Context = context.WithValue(o.Context, k, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetCallOption returns a function to setup a context with given value
|
||||||
|
func SetCallOption(k, v interface{}) CallOption {
|
||||||
|
return func(o *CallOptions) {
|
||||||
|
if o.Context == nil {
|
||||||
|
o.Context = context.Background()
|
||||||
|
}
|
||||||
|
o.Context = context.WithValue(o.Context, k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetOption returns a function to setup a context with given value
|
||||||
|
func SetOption(k, v interface{}) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
if o.Context == nil {
|
||||||
|
o.Context = context.Background()
|
||||||
|
}
|
||||||
|
o.Context = context.WithValue(o.Context, k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -49,6 +49,10 @@ func NewClient(opts ...Option) Client {
|
|||||||
return &noopClient{opts: NewOptions(opts...)}
|
return &noopClient{opts: NewOptions(opts...)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *noopClient) Name() string {
|
||||||
|
return n.opts.Name
|
||||||
|
}
|
||||||
|
|
||||||
func (n *noopRequest) Service() string {
|
func (n *noopRequest) Service() string {
|
||||||
return n.service
|
return n.service
|
||||||
}
|
}
|
||||||
@@ -183,7 +187,7 @@ func (n *noopClient) Publish(ctx context.Context, p Message, opts ...PublishOpti
|
|||||||
|
|
||||||
options := NewPublishOptions(opts...)
|
options := NewPublishOptions(opts...)
|
||||||
|
|
||||||
md, ok := metadata.FromContext(ctx)
|
md, ok := metadata.FromOutgoingContext(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
md = metadata.New(0)
|
md = metadata.New(0)
|
||||||
}
|
}
|
||||||
|
@@ -7,15 +7,18 @@ import (
|
|||||||
"github.com/unistack-org/micro/v3/broker"
|
"github.com/unistack-org/micro/v3/broker"
|
||||||
"github.com/unistack-org/micro/v3/codec"
|
"github.com/unistack-org/micro/v3/codec"
|
||||||
"github.com/unistack-org/micro/v3/logger"
|
"github.com/unistack-org/micro/v3/logger"
|
||||||
|
"github.com/unistack-org/micro/v3/meter"
|
||||||
"github.com/unistack-org/micro/v3/network/transport"
|
"github.com/unistack-org/micro/v3/network/transport"
|
||||||
"github.com/unistack-org/micro/v3/registry"
|
"github.com/unistack-org/micro/v3/register"
|
||||||
"github.com/unistack-org/micro/v3/router"
|
"github.com/unistack-org/micro/v3/router"
|
||||||
"github.com/unistack-org/micro/v3/selector"
|
"github.com/unistack-org/micro/v3/selector"
|
||||||
"github.com/unistack-org/micro/v3/selector/random"
|
"github.com/unistack-org/micro/v3/selector/random"
|
||||||
|
"github.com/unistack-org/micro/v3/tracer"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Options holds client options
|
// Options holds client options
|
||||||
type Options struct {
|
type Options struct {
|
||||||
|
Name string
|
||||||
// Used to select codec
|
// Used to select codec
|
||||||
ContentType string
|
ContentType string
|
||||||
// Proxy address to send requests via
|
// Proxy address to send requests via
|
||||||
@@ -28,21 +31,21 @@ type Options struct {
|
|||||||
Selector selector.Selector
|
Selector selector.Selector
|
||||||
Transport transport.Transport
|
Transport transport.Transport
|
||||||
Logger logger.Logger
|
Logger logger.Logger
|
||||||
|
Meter meter.Meter
|
||||||
// Lookup used for looking up routes
|
// Lookup used for looking up routes
|
||||||
Lookup LookupFunc
|
Lookup LookupFunc
|
||||||
|
|
||||||
// Connection Pool
|
// Connection Pool
|
||||||
PoolSize int
|
PoolSize int
|
||||||
PoolTTL time.Duration
|
PoolTTL time.Duration
|
||||||
|
Tracer tracer.Tracer
|
||||||
// Middleware for client
|
// Wrapper that used client
|
||||||
Wrappers []Wrapper
|
Wrappers []Wrapper
|
||||||
|
|
||||||
// Default Call Options
|
// CallOptions that used by default
|
||||||
CallOptions CallOptions
|
CallOptions CallOptions
|
||||||
|
|
||||||
// Other options for implementations of the interface
|
// Context is used for non default options
|
||||||
// can be stored in a context
|
|
||||||
Context context.Context
|
Context context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,12 +84,9 @@ type CallOptions struct {
|
|||||||
AuthToken bool
|
AuthToken bool
|
||||||
// Network to lookup the route within
|
// Network to lookup the route within
|
||||||
Network string
|
Network string
|
||||||
|
|
||||||
// Middleware for low level call func
|
// Middleware for low level call func
|
||||||
CallWrappers []CallWrapper
|
CallWrappers []CallWrapper
|
||||||
|
// Context is uded for non default options
|
||||||
// Other options for implementations of the interface
|
|
||||||
// can be stored in a context
|
|
||||||
Context context.Context
|
Context context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,7 +142,6 @@ func NewRequestOptions(opts ...RequestOption) RequestOptions {
|
|||||||
type RequestOptions struct {
|
type RequestOptions struct {
|
||||||
ContentType string
|
ContentType string
|
||||||
Stream bool
|
Stream bool
|
||||||
|
|
||||||
// Other options for implementations of the interface
|
// Other options for implementations of the interface
|
||||||
// can be stored in a context
|
// can be stored in a context
|
||||||
Context context.Context
|
Context context.Context
|
||||||
@@ -167,6 +166,8 @@ func NewOptions(opts ...Option) Options {
|
|||||||
Selector: random.NewSelector(),
|
Selector: random.NewSelector(),
|
||||||
Logger: logger.DefaultLogger,
|
Logger: logger.DefaultLogger,
|
||||||
Broker: broker.DefaultBroker,
|
Broker: broker.DefaultBroker,
|
||||||
|
Meter: meter.DefaultMeter,
|
||||||
|
Tracer: tracer.DefaultTracer,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
@@ -183,6 +184,13 @@ func Broker(b broker.Broker) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tracer to be used for tracing
|
||||||
|
func Tracer(t tracer.Tracer) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Tracer = t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Logger to be used for log mesages
|
// Logger to be used for log mesages
|
||||||
func Logger(l logger.Logger) Option {
|
func Logger(l logger.Logger) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
@@ -190,6 +198,13 @@ func Logger(l logger.Logger) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Meter to be used for metrics
|
||||||
|
func Meter(m meter.Meter) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Meter = m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Codec to be used to encode/decode requests for a given content type
|
// Codec to be used to encode/decode requests for a given content type
|
||||||
func Codec(contentType string, c codec.Codec) Option {
|
func Codec(contentType string, c codec.Codec) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
@@ -232,11 +247,11 @@ func Transport(t transport.Transport) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Registry sets the routers registry
|
// Register sets the routers register
|
||||||
func Registry(r registry.Registry) Option {
|
func Register(r register.Register) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
if o.Router != nil {
|
if o.Router != nil {
|
||||||
o.Router.Init(router.Registry(r))
|
o.Router.Init(router.Register(r))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -277,6 +292,13 @@ func Backoff(fn BackoffFunc) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Name sets the client name
|
||||||
|
func Name(n string) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Name = n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Lookup sets the lookup function to use for resolving service names
|
// Lookup sets the lookup function to use for resolving service names
|
||||||
func Lookup(l LookupFunc) Option {
|
func Lookup(l LookupFunc) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
|
@@ -25,7 +25,7 @@ var (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
// DefaultMaxMsgSize specifies how much data codec can handle
|
// DefaultMaxMsgSize specifies how much data codec can handle
|
||||||
DefaultMaxMsgSize = 1024 * 1024 * 4 // 4Mb
|
DefaultMaxMsgSize int = 1024 * 1024 * 4 // 4Mb
|
||||||
DefaultCodec Codec = NewCodec()
|
DefaultCodec Codec = NewCodec()
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -62,21 +62,6 @@ type Message struct {
|
|||||||
Body []byte
|
Body []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// Option func
|
|
||||||
type Option func(*Options)
|
|
||||||
|
|
||||||
// Options contains codec options
|
|
||||||
type Options struct {
|
|
||||||
MaxMsgSize int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// MaxMsgSize sets the max message size
|
|
||||||
func MaxMsgSize(n int64) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.MaxMsgSize = n
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMessage creates new codec message
|
// NewMessage creates new codec message
|
||||||
func NewMessage(t MessageType) *Message {
|
func NewMessage(t MessageType) *Message {
|
||||||
return &Message{Type: t, Header: metadata.New(0)}
|
return &Message{Type: t, Header: metadata.New(0)}
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
package codec
|
package codec
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
)
|
)
|
||||||
@@ -40,7 +41,7 @@ func (c *noopCodec) ReadBody(conn io.Reader, b interface{}) error {
|
|||||||
case *Frame:
|
case *Frame:
|
||||||
v.Data = buf
|
v.Data = buf
|
||||||
default:
|
default:
|
||||||
return ErrInvalidMessage
|
return json.Unmarshal(buf, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -64,7 +65,11 @@ func (c *noopCodec) Write(conn io.Writer, m *Message, b interface{}) error {
|
|||||||
case []byte:
|
case []byte:
|
||||||
v = vb
|
v = vb
|
||||||
default:
|
default:
|
||||||
return ErrInvalidMessage
|
var err error
|
||||||
|
v, err = json.Marshal(vb)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_, err := conn.Write(v)
|
_, err := conn.Write(v)
|
||||||
return err
|
return err
|
||||||
@@ -98,30 +103,34 @@ func (c *noopCodec) Marshal(v interface{}) ([]byte, error) {
|
|||||||
case *Message:
|
case *Message:
|
||||||
return ve.Body, nil
|
return ve.Body, nil
|
||||||
}
|
}
|
||||||
return nil, ErrInvalidMessage
|
|
||||||
|
return json.Marshal(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *noopCodec) Unmarshal(d []byte, v interface{}) error {
|
func (c *noopCodec) Unmarshal(d []byte, v interface{}) error {
|
||||||
var err error
|
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
switch ve := v.(type) {
|
switch ve := v.(type) {
|
||||||
case string:
|
case string:
|
||||||
ve = string(d)
|
ve = string(d)
|
||||||
|
return nil
|
||||||
case *string:
|
case *string:
|
||||||
*ve = string(d)
|
*ve = string(d)
|
||||||
|
return nil
|
||||||
case []byte:
|
case []byte:
|
||||||
ve = d
|
ve = d
|
||||||
|
return nil
|
||||||
case *[]byte:
|
case *[]byte:
|
||||||
*ve = d
|
*ve = d
|
||||||
|
return nil
|
||||||
case *Frame:
|
case *Frame:
|
||||||
ve.Data = d
|
ve.Data = d
|
||||||
|
return nil
|
||||||
case *Message:
|
case *Message:
|
||||||
ve.Body = d
|
ve.Body = d
|
||||||
default:
|
return nil
|
||||||
err = ErrInvalidMessage
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return json.Unmarshal(d, v)
|
||||||
}
|
}
|
||||||
|
61
codec/options.go
Normal file
61
codec/options.go
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
package codec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/unistack-org/micro/v3/logger"
|
||||||
|
"github.com/unistack-org/micro/v3/meter"
|
||||||
|
"github.com/unistack-org/micro/v3/tracer"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Option func
|
||||||
|
type Option func(*Options)
|
||||||
|
|
||||||
|
// Options contains codec options
|
||||||
|
type Options struct {
|
||||||
|
MaxMsgSize int
|
||||||
|
Meter meter.Meter
|
||||||
|
Logger logger.Logger
|
||||||
|
Tracer tracer.Tracer
|
||||||
|
}
|
||||||
|
|
||||||
|
// MaxMsgSize sets the max message size
|
||||||
|
func MaxMsgSize(n int) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.MaxMsgSize = n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logger sets the logger
|
||||||
|
func Logger(l logger.Logger) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Logger = l
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tracer to be used for tracing
|
||||||
|
func Tracer(t tracer.Tracer) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Tracer = t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Meter sets the meter
|
||||||
|
func Meter(m meter.Meter) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Meter = m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewOptions(opts ...Option) Options {
|
||||||
|
options := Options{
|
||||||
|
Logger: logger.DefaultLogger,
|
||||||
|
Meter: meter.DefaultMeter,
|
||||||
|
Tracer: tracer.DefaultTracer,
|
||||||
|
MaxMsgSize: DefaultMaxMsgSize,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, o := range opts {
|
||||||
|
o(&options)
|
||||||
|
}
|
||||||
|
|
||||||
|
return options
|
||||||
|
}
|
@@ -22,6 +22,7 @@ var (
|
|||||||
|
|
||||||
// Config is an interface abstraction for dynamic configuration
|
// Config is an interface abstraction for dynamic configuration
|
||||||
type Config interface {
|
type Config interface {
|
||||||
|
Name() string
|
||||||
// Init the config
|
// Init the config
|
||||||
Init(opts ...Option) error
|
Init(opts ...Option) error
|
||||||
// Options in the config
|
// Options in the config
|
||||||
|
@@ -5,6 +5,9 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/imdario/mergo"
|
||||||
|
rutil "github.com/unistack-org/micro/v3/util/reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
type defaultConfig struct {
|
type defaultConfig struct {
|
||||||
@@ -29,9 +32,15 @@ func (c *defaultConfig) Load(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
valueOf := reflect.ValueOf(c.opts.Struct)
|
src, err := rutil.Zero(c.opts.Struct)
|
||||||
|
if err == nil {
|
||||||
|
valueOf := reflect.ValueOf(src)
|
||||||
|
if err = c.fillValues(ctx, valueOf); err == nil {
|
||||||
|
err = mergo.Merge(c.opts.Struct, src, mergo.WithOverride, mergo.WithTypeCheck, mergo.WithAppendSlice)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := c.fillValues(ctx, valueOf); err != nil && !c.opts.AllowFail {
|
if err != nil && !c.opts.AllowFail {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +54,7 @@ func (c *defaultConfig) Load(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *defaultConfig) fillValue(ctx context.Context, value reflect.Value, val string) error {
|
func (c *defaultConfig) fillValue(ctx context.Context, value reflect.Value, val string) error {
|
||||||
if !IsEmpty(value) {
|
if !rutil.IsEmpty(value) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
switch value.Kind() {
|
switch value.Kind() {
|
||||||
@@ -242,6 +251,10 @@ func (c *defaultConfig) String() string {
|
|||||||
return "default"
|
return "default"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *defaultConfig) Name() string {
|
||||||
|
return c.opts.Name
|
||||||
|
}
|
||||||
|
|
||||||
func NewConfig(opts ...Option) Config {
|
func NewConfig(opts ...Option) Config {
|
||||||
options := NewOptions(opts...)
|
options := NewOptions(opts...)
|
||||||
if len(options.StructTag) == 0 {
|
if len(options.StructTag) == 0 {
|
||||||
|
@@ -5,9 +5,12 @@ import (
|
|||||||
|
|
||||||
"github.com/unistack-org/micro/v3/codec"
|
"github.com/unistack-org/micro/v3/codec"
|
||||||
"github.com/unistack-org/micro/v3/logger"
|
"github.com/unistack-org/micro/v3/logger"
|
||||||
|
"github.com/unistack-org/micro/v3/meter"
|
||||||
|
"github.com/unistack-org/micro/v3/tracer"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Options struct {
|
type Options struct {
|
||||||
|
Name string
|
||||||
AllowFail bool
|
AllowFail bool
|
||||||
BeforeLoad []func(context.Context, Config) error
|
BeforeLoad []func(context.Context, Config) error
|
||||||
AfterLoad []func(context.Context, Config) error
|
AfterLoad []func(context.Context, Config) error
|
||||||
@@ -15,13 +18,17 @@ type Options struct {
|
|||||||
AfterSave []func(context.Context, Config) error
|
AfterSave []func(context.Context, Config) error
|
||||||
// Struct that holds config data
|
// Struct that holds config data
|
||||||
Struct interface{}
|
Struct interface{}
|
||||||
// struct tag name
|
// StructTag name
|
||||||
StructTag string
|
StructTag string
|
||||||
// logger that will be used
|
// Logger that will be used
|
||||||
Logger logger.Logger
|
Logger logger.Logger
|
||||||
// codec that used for load/save
|
// Meter that will be used
|
||||||
|
Meter meter.Meter
|
||||||
|
// Tracer used for trace
|
||||||
|
Tracer tracer.Tracer
|
||||||
|
// Codec that used for load/save
|
||||||
Codec codec.Codec
|
Codec codec.Codec
|
||||||
// for alternative data
|
// Context for alternative data
|
||||||
Context context.Context
|
Context context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,6 +37,8 @@ type Option func(o *Options)
|
|||||||
func NewOptions(opts ...Option) Options {
|
func NewOptions(opts ...Option) Options {
|
||||||
options := Options{
|
options := Options{
|
||||||
Logger: logger.DefaultLogger,
|
Logger: logger.DefaultLogger,
|
||||||
|
Meter: meter.DefaultMeter,
|
||||||
|
Tracer: tracer.DefaultTracer,
|
||||||
Context: context.Background(),
|
Context: context.Background(),
|
||||||
}
|
}
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
@@ -88,6 +97,13 @@ func Logger(l logger.Logger) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tracer to be used for tracing
|
||||||
|
func Tracer(t tracer.Tracer) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Tracer = t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Struct used as config
|
// Struct used as config
|
||||||
func Struct(v interface{}) Option {
|
func Struct(v interface{}) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
@@ -101,3 +117,10 @@ func StructTag(name string) Option {
|
|||||||
o.StructTag = name
|
o.StructTag = name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Name sets the name
|
||||||
|
func Name(n string) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Name = n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -1,46 +0,0 @@
|
|||||||
package config
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
)
|
|
||||||
|
|
||||||
func IsEmpty(v reflect.Value) bool {
|
|
||||||
switch v.Kind() {
|
|
||||||
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
|
|
||||||
return v.Len() == 0
|
|
||||||
case reflect.Bool:
|
|
||||||
return !v.Bool()
|
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
||||||
return v.Int() == 0
|
|
||||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
|
||||||
return v.Uint() == 0
|
|
||||||
case reflect.Float32, reflect.Float64:
|
|
||||||
return v.Float() == 0
|
|
||||||
case reflect.Interface, reflect.Ptr:
|
|
||||||
if v.IsNil() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return IsEmpty(v.Elem())
|
|
||||||
case reflect.Func:
|
|
||||||
return v.IsNil()
|
|
||||||
case reflect.Invalid:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func Zero(src interface{}) (interface{}, error) {
|
|
||||||
sv := reflect.ValueOf(src)
|
|
||||||
|
|
||||||
if sv.Kind() == reflect.Ptr {
|
|
||||||
sv = sv.Elem()
|
|
||||||
}
|
|
||||||
|
|
||||||
if sv.Kind() == reflect.Invalid {
|
|
||||||
return nil, ErrInvalidStruct
|
|
||||||
}
|
|
||||||
|
|
||||||
dst := reflect.New(sv.Type())
|
|
||||||
|
|
||||||
return dst.Interface(), nil
|
|
||||||
}
|
|
@@ -3,7 +3,7 @@ package config_test
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/unistack-org/micro/v3/config"
|
rutil "github.com/unistack-org/micro/v3/util/reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
@@ -18,7 +18,7 @@ type SubConfig struct {
|
|||||||
|
|
||||||
func TestReflect(t *testing.T) {
|
func TestReflect(t *testing.T) {
|
||||||
cfg1 := &Config{Value: "cfg1", Config: &Config{Value: "cfg1_1"}, SubConfig: &SubConfig{Value: "cfg1"}}
|
cfg1 := &Config{Value: "cfg1", Config: &Config{Value: "cfg1_1"}, SubConfig: &SubConfig{Value: "cfg1"}}
|
||||||
cfg2, err := config.Zero(cfg1)
|
cfg2, err := rutil.Zero(cfg1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
22
context.go
Normal file
22
context.go
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package micro
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
type serviceKey struct{}
|
||||||
|
|
||||||
|
// FromContext retrieves a Service from the Context.
|
||||||
|
func FromContext(ctx context.Context) (Service, bool) {
|
||||||
|
if ctx == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
s, ok := ctx.Value(serviceKey{}).(Service)
|
||||||
|
return s, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewContext returns a new Context with the Service embedded within it.
|
||||||
|
func NewContext(ctx context.Context, s Service) context.Context {
|
||||||
|
if ctx == nil {
|
||||||
|
ctx = context.Background()
|
||||||
|
}
|
||||||
|
return context.WithValue(ctx, serviceKey{}, s)
|
||||||
|
}
|
11
event.go
11
event.go
@@ -6,11 +6,22 @@ import (
|
|||||||
"github.com/unistack-org/micro/v3/client"
|
"github.com/unistack-org/micro/v3/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Event is used to publish messages to a topic
|
||||||
|
type Event interface {
|
||||||
|
// Publish publishes a message to the event topic
|
||||||
|
Publish(ctx context.Context, msg interface{}, opts ...client.PublishOption) error
|
||||||
|
}
|
||||||
|
|
||||||
type event struct {
|
type event struct {
|
||||||
c client.Client
|
c client.Client
|
||||||
topic string
|
topic string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewEvent creates a new event publisher
|
||||||
|
func NewEvent(topic string, c client.Client) Event {
|
||||||
|
return &event{c, topic}
|
||||||
|
}
|
||||||
|
|
||||||
func (e *event) Publish(ctx context.Context, msg interface{}, opts ...client.PublishOption) error {
|
func (e *event) Publish(ctx context.Context, msg interface{}, opts ...client.PublishOption) error {
|
||||||
return e.c.Publish(ctx, e.c.NewMessage(e.topic, msg), opts...)
|
return e.c.Publish(ctx, e.c.NewMessage(e.topic, msg), opts...)
|
||||||
}
|
}
|
||||||
|
@@ -33,7 +33,7 @@ type Store interface {
|
|||||||
type Event struct {
|
type Event struct {
|
||||||
// ID to uniquely identify the event
|
// ID to uniquely identify the event
|
||||||
ID string
|
ID string
|
||||||
// Topic of event, e.g. "registry.service.created"
|
// Topic of event, e.g. "register.service.created"
|
||||||
Topic string
|
Topic string
|
||||||
// Timestamp of the event
|
// Timestamp of the event
|
||||||
Timestamp time.Time
|
Timestamp time.Time
|
||||||
|
21
function.go
21
function.go
@@ -1,3 +1,5 @@
|
|||||||
|
// +build ignore
|
||||||
|
|
||||||
package micro
|
package micro
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -7,11 +9,28 @@ import (
|
|||||||
"github.com/unistack-org/micro/v3/server"
|
"github.com/unistack-org/micro/v3/server"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Function is a one time executing Service
|
||||||
|
type Function interface {
|
||||||
|
// Inherits Service interface
|
||||||
|
Service
|
||||||
|
// Done signals to complete execution
|
||||||
|
Done() error
|
||||||
|
// Handle registers an RPC handler
|
||||||
|
Handle(v interface{}) error
|
||||||
|
// Subscribe registers a subscriber
|
||||||
|
Subscribe(topic string, v interface{}) error
|
||||||
|
}
|
||||||
|
|
||||||
type function struct {
|
type function struct {
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
Service
|
Service
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewFunction returns a new Function for a one time executing Service
|
||||||
|
func NewFunction(opts ...Option) Function {
|
||||||
|
return newFunction(opts...)
|
||||||
|
}
|
||||||
|
|
||||||
func fnHandlerWrapper(f Function) server.HandlerWrapper {
|
func fnHandlerWrapper(f Function) server.HandlerWrapper {
|
||||||
return func(h server.HandlerFunc) server.HandlerFunc {
|
return func(h server.HandlerFunc) server.HandlerFunc {
|
||||||
return func(ctx context.Context, req server.Request, rsp interface{}) error {
|
return func(ctx context.Context, req server.Request, rsp interface{}) error {
|
||||||
@@ -45,7 +64,7 @@ func newFunction(opts ...Option) Function {
|
|||||||
// make context the last thing
|
// make context the last thing
|
||||||
fopts = append(fopts, Context(ctx))
|
fopts = append(fopts, Context(ctx))
|
||||||
|
|
||||||
service := newService(fopts...)
|
service := &service{opts: NewOptions(opts...)}
|
||||||
|
|
||||||
fn := &function{
|
fn := &function{
|
||||||
cancel: cancel,
|
cancel: cancel,
|
||||||
|
@@ -7,18 +7,18 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
rmemory "github.com/unistack-org/micro-registry-memory"
|
rmemory "github.com/unistack-org/micro-register-memory"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFunction(t *testing.T) {
|
func TestFunction(t *testing.T) {
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
|
|
||||||
r := rmemory.NewRegistry()
|
r := rmemory.NewRegister()
|
||||||
|
|
||||||
// create service
|
// create service
|
||||||
fn := NewFunction(
|
fn := NewFunction(
|
||||||
Registry(r),
|
Register(r),
|
||||||
Name("test.function"),
|
Name("test.function"),
|
||||||
AfterStart(func() error {
|
AfterStart(func() error {
|
||||||
wg.Done()
|
wg.Done()
|
||||||
|
20
go.mod
20
go.mod
@@ -3,22 +3,20 @@ module github.com/unistack-org/micro/v3
|
|||||||
go 1.14
|
go 1.14
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/caddyserver/certmagic v0.10.6
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||||
github.com/ef-ds/deque v1.0.4-0.20190904040645-54cb57c252a1
|
github.com/ef-ds/deque v1.0.4
|
||||||
github.com/go-acme/lego/v3 v3.4.0
|
|
||||||
github.com/golang/protobuf v1.4.3
|
github.com/golang/protobuf v1.4.3
|
||||||
github.com/google/uuid v1.1.2
|
github.com/google/uuid v1.2.0
|
||||||
|
github.com/imdario/mergo v0.3.11
|
||||||
github.com/kr/text v0.2.0 // indirect
|
github.com/kr/text v0.2.0 // indirect
|
||||||
github.com/miekg/dns v1.1.31
|
github.com/miekg/dns v1.1.38
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c
|
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c
|
||||||
github.com/stretchr/testify v1.5.1
|
github.com/stretchr/testify v1.7.0
|
||||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
|
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad // indirect
|
||||||
golang.org/x/net v0.0.0-20200904194848-62affa334b73
|
golang.org/x/net v0.0.0-20210119194325-5f4716e94777
|
||||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 // indirect
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect
|
||||||
google.golang.org/protobuf v1.25.0
|
google.golang.org/protobuf v1.25.0
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
||||||
gopkg.in/square/go-jose.v2 v2.4.1 // indirect
|
|
||||||
gopkg.in/yaml.v2 v2.3.0 // indirect
|
|
||||||
)
|
)
|
||||||
|
351
go.sum
351
go.sum
@@ -1,98 +1,21 @@
|
|||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
|
||||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
|
||||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
|
||||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
|
||||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
|
||||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
|
||||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
|
||||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
|
||||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
|
||||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
|
||||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
|
||||||
contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA=
|
|
||||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
|
||||||
github.com/Azure/azure-sdk-for-go v32.4.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
|
||||||
github.com/Azure/go-autorest/autorest v0.1.0/go.mod h1:AKyIcETwSUFxIcs/Wnq/C+kwCtlEYGUVd7FPNb2slmg=
|
|
||||||
github.com/Azure/go-autorest/autorest v0.5.0/go.mod h1:9HLKlQjVBH6U3oDfsXOeVc56THsLPw1L03yban4xThw=
|
|
||||||
github.com/Azure/go-autorest/autorest/adal v0.1.0/go.mod h1:MeS4XhScH55IST095THyTxElntu7WqB7pNbZo8Q5G3E=
|
|
||||||
github.com/Azure/go-autorest/autorest/adal v0.2.0/go.mod h1:MeS4XhScH55IST095THyTxElntu7WqB7pNbZo8Q5G3E=
|
|
||||||
github.com/Azure/go-autorest/autorest/azure/auth v0.1.0/go.mod h1:Gf7/i2FUpyb/sGBLIFxTBzrNzBo7aPXXE3ZVeDRwdpM=
|
|
||||||
github.com/Azure/go-autorest/autorest/azure/cli v0.1.0/go.mod h1:Dk8CUAt/b/PzkfeRsWzVG9Yj3ps8mS8ECztu43rdU8U=
|
|
||||||
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
|
|
||||||
github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
|
|
||||||
github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc=
|
|
||||||
github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8=
|
|
||||||
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
|
|
||||||
github.com/Azure/go-autorest/tracing v0.1.0/go.mod h1:ROEEAFwXycQw7Sn3DXNtEedEvdeRAgDr0izn4z5Ij88=
|
|
||||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
|
||||||
github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks=
|
|
||||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
|
||||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
|
||||||
github.com/akamai/AkamaiOPEN-edgegrid-golang v0.9.0/go.mod h1:zpDJeKyp9ScW4NNrbdr+Eyxvry3ilGPewKoXw3XGN1k=
|
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
|
||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
|
||||||
github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190808125512-07798873deee/go.mod h1:myCDvQSzCW+wB1WAlocEru4wMGJxy+vlxHdhegi1CDQ=
|
|
||||||
github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
|
|
||||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
|
||||||
github.com/aws/aws-sdk-go v1.23.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
|
||||||
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
|
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
|
||||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
|
||||||
github.com/caddyserver/certmagic v0.10.6 h1:sCya6FmfaN74oZE46kqfaFOVoROD/mF36rTQfjN7TZc=
|
|
||||||
github.com/caddyserver/certmagic v0.10.6/go.mod h1:Y8jcUBctgk/IhpAzlHKfimZNyXCkfGgRTC0orl8gROQ=
|
|
||||||
github.com/cenkalti/backoff/v4 v4.0.0 h1:6VeaLF9aI+MAUQ95106HwWzYZgJJpZ4stumjj6RFYAU=
|
|
||||||
github.com/cenkalti/backoff/v4 v4.0.0/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg=
|
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/cloudflare/cloudflare-go v0.10.2/go.mod h1:qhVI5MKwBGhdNU89ZRz2plgYutcJ5PCekLxXn56w6SY=
|
|
||||||
github.com/cpu/goacmedns v0.0.1/go.mod h1:sesf/pNnCYwUevQEQfEwY0Y3DydlQWSGZbaMElOWxok=
|
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
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.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
|
github.com/ef-ds/deque v1.0.4 h1:iFAZNmveMT9WERAkqLJ+oaABF9AcVQ5AjXem/hroniI=
|
||||||
github.com/dnaeon/go-vcr v0.0.0-20180814043457-aafff18a5cc2/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
|
github.com/ef-ds/deque v1.0.4/go.mod h1:gXDnTC3yqvBcHbq2lcExjtAcVrOnJCbMcZXmuj8Z4tg=
|
||||||
github.com/dnsimple/dnsimple-go v0.30.0/go.mod h1:O5TJ0/U6r7AfT8niYNlmohpLbCSG+c71tQlGr9SeGrg=
|
|
||||||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
|
||||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
|
||||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
|
||||||
github.com/ef-ds/deque v1.0.4-0.20190904040645-54cb57c252a1 h1:jFGzikHboUMRXmMBtwD/PbxoTHPs2919Irp/3rxMbvM=
|
|
||||||
github.com/ef-ds/deque v1.0.4-0.20190904040645-54cb57c252a1/go.mod h1:HvODWzv6Y6kBf3Ah2WzN1bHjDUezGLaAhwuWVwfpEJs=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/exoscale/egoscale v0.18.1/go.mod h1:Z7OOdzzTOz1Q1PjQXumlz9Wn/CddH0zSYdCF3rnBKXE=
|
|
||||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
|
||||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
|
||||||
github.com/go-acme/lego/v3 v3.4.0 h1:deB9NkelA+TfjGHVw8J7iKl/rMtffcGMWSMmptvMv0A=
|
|
||||||
github.com/go-acme/lego/v3 v3.4.0/go.mod h1:xYbLDuxq3Hy4bMUT1t9JIuz6GWIWb3m5X+TeTHYaT7M=
|
|
||||||
github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s=
|
|
||||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
|
||||||
github.com/go-ini/ini v1.44.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
|
||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
|
||||||
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
|
||||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
|
||||||
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
|
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
|
||||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||||
@@ -102,292 +25,84 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq
|
|||||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||||
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
|
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
|
||||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
|
||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
|
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
|
||||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
|
||||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
|
||||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
|
||||||
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
|
||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
|
||||||
github.com/gophercloud/gophercloud v0.3.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
|
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
|
||||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
|
||||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
|
||||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
|
||||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
|
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
|
||||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
|
||||||
github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
|
||||||
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhKWFeDesPjMj+wCHReeknARU3wqlyN4=
|
|
||||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
|
||||||
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
|
||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
|
||||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
|
||||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
|
||||||
github.com/klauspost/cpuid v1.2.3 h1:CCtW0xUnWGVINKvE/WWOYKdsPV6mawAtvQuSl8guwQs=
|
|
||||||
github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
|
||||||
github.com/kolo/xmlrpc v0.0.0-20190717152603-07c4ee3fd181/go.mod h1:o03bZfuBwAXHetKXuInt4S7omeXUu62/A845kiycsSQ=
|
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
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/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/labbsr0x/bindman-dns-webhook v1.0.2/go.mod h1:p6b+VCXIR8NYKpDr8/dg1HKfQoRHCdcsROXKvmoehKA=
|
github.com/miekg/dns v1.1.38 h1:MtIY+fmHUVVgv1AXzmKMWcwdCYxTRPG1EDjpqF4RCEw=
|
||||||
github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c027w=
|
github.com/miekg/dns v1.1.38/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||||
github.com/linode/linodego v0.10.0/go.mod h1:cziNP7pbvE3mXIPneHj0oRY8L1WtGEIKlZ8LANE4eXA=
|
|
||||||
github.com/liquidweb/liquidweb-go v1.6.0/go.mod h1:UDcVnAMDkZxpw4Y7NOHkqoeiGacVLEIG/i5J9cyixzQ=
|
|
||||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
|
||||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
|
||||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
|
||||||
github.com/mattn/go-tty v0.0.0-20180219170247-931426f7535a/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
|
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
|
||||||
github.com/miekg/dns v1.1.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
|
||||||
github.com/miekg/dns v1.1.31 h1:sJFOl9BgwbYAWOGEwr61FU28pqsBNdpRBnhGXtO06Oo=
|
|
||||||
github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
|
||||||
github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed/go.mod h1:3rdaFaCv4AyBgu5ALFM0+tSuHrBh6v692nyQe3ikrq0=
|
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
|
||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
|
||||||
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8=
|
|
||||||
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
|
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
github.com/nrdcg/auroradns v1.0.0/go.mod h1:6JPXKzIRzZzMqtTDgueIhTi6rFf1QvYE/HzqidhOhjw=
|
|
||||||
github.com/nrdcg/dnspod-go v0.4.0/go.mod h1:vZSoFSFeQVm2gWLMkyX61LZ8HI3BaqtHZWgPTGKr6KQ=
|
|
||||||
github.com/nrdcg/goinwx v0.6.1/go.mod h1:XPiut7enlbEdntAqalBIqcYcTEVhpv/dKWgDCX2SwKQ=
|
|
||||||
github.com/nrdcg/namesilo v0.2.1/go.mod h1:lwMvfQTyYq+BbjJd30ylEG4GPSS6PII0Tia4rRpRiyw=
|
|
||||||
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
|
||||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
|
||||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
|
||||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
|
||||||
github.com/oracle/oci-go-sdk v7.0.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888=
|
|
||||||
github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014/go.mod h1:joRatxRJaZBsY3JAOEMcoOp05CnZzsx4scTxi95DHyQ=
|
|
||||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
|
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
|
||||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
|
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
|
||||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
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.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
|
||||||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
|
||||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
|
||||||
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
|
|
||||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
|
||||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
|
||||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
|
||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
|
||||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
|
||||||
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
|
|
||||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
|
||||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
|
||||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
|
||||||
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
|
||||||
github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2/go.mod h1:7tZKcyumwBO6qip7RNQ5r77yrssm9bfCowcLEBcU5IA=
|
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
|
||||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
|
||||||
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
|
||||||
github.com/sacloud/libsacloud v1.26.1/go.mod h1:79ZwATmHLIFZIMd7sxA3LwzVy/B77uj3LDoToVTxDoQ=
|
|
||||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
|
||||||
github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
|
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
|
||||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
|
||||||
github.com/timewasted/linode v0.0.0-20160829202747-37e84520dcf7/go.mod h1:imsgLplxEC/etjIhdr3dNzV3JeT27LbVu5pYWm0JCBY=
|
|
||||||
github.com/transip/gotransip v0.0.0-20190812104329-6d8d9179b66f/go.mod h1:i0f4R4o2HM0m3DZYQWsj6/MEowD57VzoH0v3d7igeFY=
|
|
||||||
github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g=
|
|
||||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
|
||||||
github.com/vultr/govultr v0.1.4/go.mod h1:9H008Uxr/C4vFNGLqKx232C206GL0PBHzOP0809bGNA=
|
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
|
||||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
|
||||||
github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
|
|
||||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
|
||||||
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
|
||||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
|
||||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
|
||||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
|
||||||
go.uber.org/ratelimit v0.0.0-20180316092928-c15da0234277/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y=
|
|
||||||
golang.org/x/crypto v0.0.0-20180621125126-a49355c7e3f8/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
|
||||||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
|
|
||||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
|
||||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
|
||||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
|
||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
|
||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
|
||||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
|
||||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
|
||||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
|
||||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
|
||||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
golang.org/x/net v0.0.0-20180611182652-db08ff08e862/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
|
||||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=
|
||||||
golang.org/x/net v0.0.0-20191027093000-83d349e8ac1a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20200904194848-62affa334b73 h1:MXfv8rhZWmFeqX3GNZRsd6vOLoaCHjYEX3qkRo3YBUA=
|
|
||||||
golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20180622082034-63fc586f45fe/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
|
||||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
|
||||||
golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
|
||||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
|
||||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
|
||||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
|
||||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
|
||||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
|
||||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
|
||||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
|
||||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
|
||||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
|
||||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
|
||||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
|
||||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
|
||||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
|
||||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
|
||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
|
||||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
|
||||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
@@ -400,32 +115,12 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
|
|||||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
||||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
|
||||||
gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE=
|
|
||||||
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
|
||||||
gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
|
||||||
gopkg.in/ns1/ns1-go.v2 v2.0.0-20190730140822-b51389932cbc/go.mod h1:VV+3haRsgDiVLxyifmMBrBIuCWFBPYKbRssXB9z67Hw=
|
|
||||||
gopkg.in/resty.v1 v1.9.1/go.mod h1:vo52Hzryw9PnPHcJfPsBiFW62XhNx5OczbV9y+IMpgc=
|
|
||||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
|
||||||
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
|
||||||
gopkg.in/square/go-jose.v2 v2.4.1 h1:H0TmLt7/KmzlrDOpa1F+zr0Tk90PbJYBfsVUmRLrf9Y=
|
|
||||||
gopkg.in/square/go-jose.v2 v2.4.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
|
||||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
|
||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
|
||||||
|
@@ -11,6 +11,7 @@ type Option func(*Options)
|
|||||||
|
|
||||||
// Options holds logger options
|
// Options holds logger options
|
||||||
type Options struct {
|
type Options struct {
|
||||||
|
Name string
|
||||||
// The logging level the logger should log at. default is `InfoLevel`
|
// The logging level the logger should log at. default is `InfoLevel`
|
||||||
Level Level
|
Level Level
|
||||||
// fields to always be logged
|
// fields to always be logged
|
||||||
@@ -72,3 +73,10 @@ func WithContext(ctx context.Context) Option {
|
|||||||
o.Context = ctx
|
o.Context = ctx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithName sets the name
|
||||||
|
func withName(n string) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Name = n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
108
metadata/context.go
Normal file
108
metadata/context.go
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
// Package metadata is a way of defining message headers
|
||||||
|
package metadata
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
type mdIncomingKey struct{}
|
||||||
|
type mdOutgoingKey struct{}
|
||||||
|
type mdKey struct{}
|
||||||
|
|
||||||
|
// FromIncomingContext returns metadata from incoming ctx
|
||||||
|
// returned metadata shoud not be modified or race condition happens
|
||||||
|
func FromIncomingContext(ctx context.Context) (Metadata, bool) {
|
||||||
|
if ctx == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
md, ok := ctx.Value(mdIncomingKey{}).(*rawMetadata)
|
||||||
|
if !ok {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
return md.md, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromOutgoingContext returns metadata from outgoing ctx
|
||||||
|
// returned metadata shoud not be modified or race condition happens
|
||||||
|
func FromOutgoingContext(ctx context.Context) (Metadata, bool) {
|
||||||
|
if ctx == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
md, ok := ctx.Value(mdOutgoingKey{}).(*rawMetadata)
|
||||||
|
if !ok {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
return md.md, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromContext returns metadata from the given context
|
||||||
|
// returned metadata shoud not be modified or race condition happens
|
||||||
|
//
|
||||||
|
// Deprecated: use FromIncomingContext or FromOutgoingContext
|
||||||
|
func FromContext(ctx context.Context) (Metadata, bool) {
|
||||||
|
if ctx == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
md, ok := ctx.Value(mdKey{}).(*rawMetadata)
|
||||||
|
if !ok {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
return md.md, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewContext creates a new context with the given metadata
|
||||||
|
//
|
||||||
|
// Deprecated: use NewIncomingContext or NewOutgoingContext
|
||||||
|
func NewContext(ctx context.Context, md Metadata) context.Context {
|
||||||
|
if ctx == nil {
|
||||||
|
ctx = context.Background()
|
||||||
|
}
|
||||||
|
ctx = context.WithValue(ctx, mdKey{}, &rawMetadata{md})
|
||||||
|
ctx = context.WithValue(ctx, mdIncomingKey{}, &rawMetadata{})
|
||||||
|
ctx = context.WithValue(ctx, mdOutgoingKey{}, &rawMetadata{})
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetOutgoingContext modify outgoing context with given metadata
|
||||||
|
func SetOutgoingContext(ctx context.Context, md Metadata) bool {
|
||||||
|
if ctx == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if omd, ok := ctx.Value(mdOutgoingKey{}).(*rawMetadata); ok {
|
||||||
|
omd.md = md
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetIncomingContext modify incoming context with given metadata
|
||||||
|
func SetIncomingContext(ctx context.Context, md Metadata) bool {
|
||||||
|
if ctx == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if omd, ok := ctx.Value(mdIncomingKey{}).(*rawMetadata); ok {
|
||||||
|
omd.md = md
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewIncomingContext creates a new context with incoming metadata attached
|
||||||
|
func NewIncomingContext(ctx context.Context, md Metadata) context.Context {
|
||||||
|
if ctx == nil {
|
||||||
|
ctx = context.Background()
|
||||||
|
}
|
||||||
|
ctx = context.WithValue(ctx, mdIncomingKey{}, &rawMetadata{md})
|
||||||
|
ctx = context.WithValue(ctx, mdOutgoingKey{}, &rawMetadata{})
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewOutgoingContext creates a new context with outcoming metadata attached
|
||||||
|
func NewOutgoingContext(ctx context.Context, md Metadata) context.Context {
|
||||||
|
if ctx == nil {
|
||||||
|
ctx = context.Background()
|
||||||
|
}
|
||||||
|
ctx = context.WithValue(ctx, mdOutgoingKey{}, &rawMetadata{md})
|
||||||
|
ctx = context.WithValue(ctx, mdIncomingKey{}, &rawMetadata{})
|
||||||
|
return ctx
|
||||||
|
}
|
@@ -2,22 +2,58 @@
|
|||||||
package metadata
|
package metadata
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"net/textproto"
|
"net/textproto"
|
||||||
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
type metadataKey struct{}
|
var (
|
||||||
|
// HeaderPrefix for all headers passed
|
||||||
|
HeaderPrefix = "Micro-"
|
||||||
|
)
|
||||||
|
|
||||||
// Metadata is our way of representing request headers internally.
|
// Metadata is our way of representing request headers internally.
|
||||||
// They're used at the RPC level and translate back and forth
|
// They're used at the RPC level and translate back and forth
|
||||||
// from Transport headers.
|
// from Transport headers.
|
||||||
type Metadata map[string]string
|
type Metadata map[string]string
|
||||||
|
|
||||||
|
type rawMetadata struct {
|
||||||
|
md Metadata
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// DefaultMetadataSize used when need to init new Metadata
|
// defaultMetadataSize used when need to init new Metadata
|
||||||
DefaultMetadataSize = 6
|
defaultMetadataSize = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Iterator struct {
|
||||||
|
cur int
|
||||||
|
cnt int
|
||||||
|
keys []string
|
||||||
|
md Metadata
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iter *Iterator) Next(k, v *string) bool {
|
||||||
|
if iter.cur+1 > iter.cnt {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
*k = iter.keys[iter.cur]
|
||||||
|
*v = iter.md[*k]
|
||||||
|
iter.cur++
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate returns run user func with map key, val sorted by key
|
||||||
|
func (md Metadata) Iterator() *Iterator {
|
||||||
|
iter := &Iterator{md: md, cnt: len(md)}
|
||||||
|
iter.keys = make([]string, 0, iter.cnt)
|
||||||
|
for k := range md {
|
||||||
|
iter.keys = append(iter.keys, k)
|
||||||
|
}
|
||||||
|
sort.Strings(iter.keys)
|
||||||
|
return iter
|
||||||
|
}
|
||||||
|
|
||||||
// Get returns value from metadata by key
|
// Get returns value from metadata by key
|
||||||
func (md Metadata) Get(key string) (string, bool) {
|
func (md Metadata) Get(key string) (string, bool) {
|
||||||
// fast path
|
// fast path
|
||||||
@@ -37,12 +73,9 @@ func (md Metadata) Set(key, val string) {
|
|||||||
// Del is used to remove value from metadata
|
// Del is used to remove value from metadata
|
||||||
func (md Metadata) Del(key string) {
|
func (md Metadata) Del(key string) {
|
||||||
// fast path
|
// fast path
|
||||||
if _, ok := md[key]; ok {
|
delete(md, key)
|
||||||
delete(md, key)
|
// slow path
|
||||||
} else {
|
delete(md, textproto.CanonicalMIMEHeaderKey(key))
|
||||||
// slow path
|
|
||||||
delete(md, textproto.CanonicalMIMEHeaderKey(key))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy makes a copy of the metadata
|
// Copy makes a copy of the metadata
|
||||||
@@ -54,75 +87,18 @@ func Copy(md Metadata) Metadata {
|
|||||||
return nmd
|
return nmd
|
||||||
}
|
}
|
||||||
|
|
||||||
// Del deletes key from metadata
|
|
||||||
func Del(ctx context.Context, key string) context.Context {
|
|
||||||
md, ok := FromContext(ctx)
|
|
||||||
if !ok {
|
|
||||||
md = New(0)
|
|
||||||
}
|
|
||||||
md.Del(key)
|
|
||||||
return context.WithValue(ctx, metadataKey{}, md)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set add key with val to metadata
|
|
||||||
func Set(ctx context.Context, key, val string) context.Context {
|
|
||||||
md, ok := FromContext(ctx)
|
|
||||||
if !ok {
|
|
||||||
md = New(0)
|
|
||||||
}
|
|
||||||
md.Set(key, val)
|
|
||||||
return context.WithValue(ctx, metadataKey{}, md)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get returns a single value from metadata in the context
|
|
||||||
func Get(ctx context.Context, key string) (string, bool) {
|
|
||||||
md, ok := FromContext(ctx)
|
|
||||||
if !ok {
|
|
||||||
return "", ok
|
|
||||||
}
|
|
||||||
return md.Get(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromContext returns metadata from the given context
|
|
||||||
func FromContext(ctx context.Context) (Metadata, bool) {
|
|
||||||
if ctx == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
md, ok := ctx.Value(metadataKey{}).(Metadata)
|
|
||||||
if !ok {
|
|
||||||
return nil, ok
|
|
||||||
}
|
|
||||||
nmd := Copy(md)
|
|
||||||
return nmd, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// New return new sized metadata
|
// New return new sized metadata
|
||||||
func New(size int) Metadata {
|
func New(size int) Metadata {
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
size = DefaultMetadataSize
|
size = defaultMetadataSize
|
||||||
}
|
}
|
||||||
return make(Metadata, size)
|
return make(Metadata, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewContext creates a new context with the given metadata
|
// Merge merges metadata to existing metadata, overwriting if specified
|
||||||
func NewContext(ctx context.Context, md Metadata) context.Context {
|
func Merge(omd Metadata, mmd Metadata, overwrite bool) Metadata {
|
||||||
if ctx == nil {
|
nmd := Copy(omd)
|
||||||
ctx = context.Background()
|
for key, val := range mmd {
|
||||||
}
|
|
||||||
return context.WithValue(ctx, metadataKey{}, Copy(md))
|
|
||||||
}
|
|
||||||
|
|
||||||
// MergeContext merges metadata to existing metadata, overwriting if specified
|
|
||||||
func MergeContext(ctx context.Context, pmd Metadata, overwrite bool) context.Context {
|
|
||||||
if ctx == nil {
|
|
||||||
ctx = context.Background()
|
|
||||||
}
|
|
||||||
md, ok := FromContext(ctx)
|
|
||||||
if !ok {
|
|
||||||
return context.WithValue(ctx, metadataKey{}, Copy(pmd))
|
|
||||||
}
|
|
||||||
nmd := Copy(md)
|
|
||||||
for key, val := range pmd {
|
|
||||||
if _, ok := nmd[key]; ok && !overwrite {
|
if _, ok := nmd[key]; ok && !overwrite {
|
||||||
// skip
|
// skip
|
||||||
} else if val != "" {
|
} else if val != "" {
|
||||||
@@ -131,5 +107,5 @@ func MergeContext(ctx context.Context, pmd Metadata, overwrite bool) context.Con
|
|||||||
nmd.Del(key)
|
nmd.Del(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return context.WithValue(ctx, metadataKey{}, nmd)
|
return nmd
|
||||||
}
|
}
|
||||||
|
@@ -2,26 +2,78 @@ package metadata
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"reflect"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func testCtx(ctx context.Context) {
|
||||||
|
md := New(2)
|
||||||
|
md.Set("Key1", "Val1_new")
|
||||||
|
md.Set("Key3", "Val3")
|
||||||
|
SetOutgoingContext(ctx, md)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPassing(t *testing.T) {
|
||||||
|
ctx := context.TODO()
|
||||||
|
md1 := New(2)
|
||||||
|
md1.Set("Key1", "Val1")
|
||||||
|
md1.Set("Key2", "Val2")
|
||||||
|
|
||||||
|
ctx = NewIncomingContext(ctx, md1)
|
||||||
|
testCtx(ctx)
|
||||||
|
md, ok := FromOutgoingContext(ctx)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("missing metadata from outgoing context")
|
||||||
|
}
|
||||||
|
fmt.Printf("%#+v\n", md)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMerge(t *testing.T) {
|
||||||
|
omd := Metadata{
|
||||||
|
"key1": "val1",
|
||||||
|
}
|
||||||
|
mmd := Metadata{
|
||||||
|
"key2": "val2",
|
||||||
|
}
|
||||||
|
|
||||||
|
nmd := Merge(omd, mmd, true)
|
||||||
|
if len(nmd) != 2 {
|
||||||
|
t.Fatalf("merge failed: %v", nmd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIterator(t *testing.T) {
|
||||||
|
md := Metadata{
|
||||||
|
"1Last": "last",
|
||||||
|
"2First": "first",
|
||||||
|
"3Second": "second",
|
||||||
|
}
|
||||||
|
|
||||||
|
iter := md.Iterator()
|
||||||
|
var k, v string
|
||||||
|
|
||||||
|
for iter.Next(&k, &v) {
|
||||||
|
//fmt.Printf("k: %s, v: %s\n", k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestMedataCanonicalKey(t *testing.T) {
|
func TestMedataCanonicalKey(t *testing.T) {
|
||||||
ctx := Set(context.TODO(), "x-request-id", "12345")
|
md := New(1)
|
||||||
v, ok := Get(ctx, "x-request-id")
|
md.Set("x-request-id", "12345")
|
||||||
|
v, ok := md.Get("x-request-id")
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Fatalf("failed to get x-request-id")
|
t.Fatalf("failed to get x-request-id")
|
||||||
} else if v != "12345" {
|
} else if v != "12345" {
|
||||||
t.Fatalf("invalid metadata value: %s != %s", "12345", v)
|
t.Fatalf("invalid metadata value: %s != %s", "12345", v)
|
||||||
}
|
}
|
||||||
|
|
||||||
v, ok = Get(ctx, "X-Request-Id")
|
v, ok = md.Get("X-Request-Id")
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Fatalf("failed to get x-request-id")
|
t.Fatalf("failed to get x-request-id")
|
||||||
} else if v != "12345" {
|
} else if v != "12345" {
|
||||||
t.Fatalf("invalid metadata value: %s != %s", "12345", v)
|
t.Fatalf("invalid metadata value: %s != %s", "12345", v)
|
||||||
}
|
}
|
||||||
v, ok = Get(ctx, "X-Request-ID")
|
v, ok = md.Get("X-Request-ID")
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Fatalf("failed to get x-request-id")
|
t.Fatalf("failed to get x-request-id")
|
||||||
} else if v != "12345" {
|
} else if v != "12345" {
|
||||||
@@ -31,9 +83,11 @@ func TestMedataCanonicalKey(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMetadataSet(t *testing.T) {
|
func TestMetadataSet(t *testing.T) {
|
||||||
ctx := Set(context.TODO(), "Key", "val")
|
md := New(1)
|
||||||
|
|
||||||
val, ok := Get(ctx, "Key")
|
md.Set("Key", "val")
|
||||||
|
|
||||||
|
val, ok := md.Get("Key")
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Fatal("key Key not found")
|
t.Fatal("key Key not found")
|
||||||
}
|
}
|
||||||
@@ -48,15 +102,8 @@ func TestMetadataDelete(t *testing.T) {
|
|||||||
"Baz": "empty",
|
"Baz": "empty",
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := NewContext(context.TODO(), md)
|
md.Del("Baz")
|
||||||
ctx = Del(ctx, "Baz")
|
_, ok := md.Get("Baz")
|
||||||
|
|
||||||
emd, ok := FromContext(ctx)
|
|
||||||
if !ok {
|
|
||||||
t.Fatal("key Key not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
_, ok = emd["Baz"]
|
|
||||||
if ok {
|
if ok {
|
||||||
t.Fatal("key Baz not deleted")
|
t.Fatal("key Baz not deleted")
|
||||||
}
|
}
|
||||||
@@ -107,42 +154,3 @@ func TestMetadataContext(t *testing.T) {
|
|||||||
t.Errorf("Expected metadata length 1 got %d", i)
|
t.Errorf("Expected metadata length 1 got %d", i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMergeContext(t *testing.T) {
|
|
||||||
type args struct {
|
|
||||||
existing Metadata
|
|
||||||
append Metadata
|
|
||||||
overwrite bool
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
args args
|
|
||||||
want Metadata
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "matching key, overwrite false",
|
|
||||||
args: args{
|
|
||||||
existing: Metadata{"Foo": "bar", "Sumo": "demo"},
|
|
||||||
append: Metadata{"Sumo": "demo2"},
|
|
||||||
overwrite: false,
|
|
||||||
},
|
|
||||||
want: Metadata{"Foo": "bar", "Sumo": "demo"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "matching key, overwrite true",
|
|
||||||
args: args{
|
|
||||||
existing: Metadata{"Foo": "bar", "Sumo": "demo"},
|
|
||||||
append: Metadata{"Sumo": "demo2"},
|
|
||||||
overwrite: true,
|
|
||||||
},
|
|
||||||
want: Metadata{"Foo": "bar", "Sumo": "demo2"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
if got, _ := FromContext(MergeContext(NewContext(context.TODO(), tt.args.existing), tt.args.append, tt.args.overwrite)); !reflect.DeepEqual(got, tt.want) {
|
|
||||||
t.Errorf("MergeContext() = %v, want %v", got, tt.want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
34
meter/context.go
Normal file
34
meter/context.go
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package meter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
type meterKey struct{}
|
||||||
|
|
||||||
|
// FromContext get meter from context
|
||||||
|
func FromContext(ctx context.Context) (Meter, bool) {
|
||||||
|
if ctx == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
c, ok := ctx.Value(meterKey{}).(Meter)
|
||||||
|
return c, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewContext put meter in context
|
||||||
|
func NewContext(ctx context.Context, c Meter) context.Context {
|
||||||
|
if ctx == nil {
|
||||||
|
ctx = context.Background()
|
||||||
|
}
|
||||||
|
return context.WithValue(ctx, meterKey{}, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetOption returns a function to setup a context with given value
|
||||||
|
func SetOption(k, v interface{}) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
if o.Context == nil {
|
||||||
|
o.Context = context.Background()
|
||||||
|
}
|
||||||
|
o.Context = context.WithValue(o.Context, k, v)
|
||||||
|
}
|
||||||
|
}
|
127
meter/meter.go
Normal file
127
meter/meter.go
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
// Package meter is for instrumentation
|
||||||
|
package meter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"sort"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// DefaultMeter is the default meter
|
||||||
|
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
|
||||||
|
DefaultPath = "/metrics"
|
||||||
|
// timingObjectives is the default spread of stats we maintain for timings / histograms:
|
||||||
|
//defaultTimingObjectives = map[float64]float64{0.0: 0, 0.5: 0.05, 0.75: 0.04, 0.90: 0.03, 0.95: 0.02, 0.98: 0.001, 1: 0}
|
||||||
|
// default metric prefix
|
||||||
|
DefaultMetricPrefix = "micro_"
|
||||||
|
// default label prefix
|
||||||
|
DefaultLabelPrefix = "micro_"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Meter is an interface for collecting and instrumenting metrics
|
||||||
|
type Meter interface {
|
||||||
|
Name() string
|
||||||
|
Init(...Option) error
|
||||||
|
Counter(string, ...Option) Counter
|
||||||
|
FloatCounter(string, ...Option) FloatCounter
|
||||||
|
Gauge(string, func() float64, ...Option) Gauge
|
||||||
|
Set(...Option) Meter
|
||||||
|
Histogram(string, ...Option) Histogram
|
||||||
|
Summary(string, ...Option) Summary
|
||||||
|
SummaryExt(string, time.Duration, []float64, ...Option) Summary
|
||||||
|
Write(io.Writer, bool) error
|
||||||
|
Options() Options
|
||||||
|
String() string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Counter is a counter
|
||||||
|
type Counter interface {
|
||||||
|
Add(int)
|
||||||
|
Dec()
|
||||||
|
Get() uint64
|
||||||
|
Inc()
|
||||||
|
Set(uint64)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FloatCounter is a float64 counter
|
||||||
|
type FloatCounter interface {
|
||||||
|
Add(float64)
|
||||||
|
Get() float64
|
||||||
|
Set(float64)
|
||||||
|
Sub(float64)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gauge is a float64 gauge
|
||||||
|
type Gauge interface {
|
||||||
|
Get() float64
|
||||||
|
}
|
||||||
|
|
||||||
|
// Histogram is a histogram for non-negative values with automatically created buckets
|
||||||
|
type Histogram interface {
|
||||||
|
Reset()
|
||||||
|
Update(float64)
|
||||||
|
UpdateDuration(time.Time)
|
||||||
|
// VisitNonZeroBuckets(f func(vmrange string, count uint64))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Summary is the summary
|
||||||
|
type Summary interface {
|
||||||
|
Update(float64)
|
||||||
|
UpdateDuration(time.Time)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Labels struct {
|
||||||
|
keys []string
|
||||||
|
vals []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls Labels) Len() int {
|
||||||
|
return len(ls.keys)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls Labels) Swap(i, j int) {
|
||||||
|
ls.keys[i], ls.keys[j] = ls.keys[j], ls.keys[i]
|
||||||
|
ls.vals[i], ls.vals[j] = ls.vals[j], ls.vals[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls Labels) Less(i, j int) bool {
|
||||||
|
return ls.vals[i] < ls.vals[j]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls Labels) Sort() {
|
||||||
|
sort.Sort(ls)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls Labels) Append(nls Labels) Labels {
|
||||||
|
for n := range nls.keys {
|
||||||
|
ls.keys = append(ls.keys, nls.keys[n])
|
||||||
|
ls.vals = append(ls.vals, nls.vals[n])
|
||||||
|
}
|
||||||
|
return ls
|
||||||
|
}
|
||||||
|
|
||||||
|
type LabelIter struct {
|
||||||
|
labels Labels
|
||||||
|
cnt int
|
||||||
|
cur int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls Labels) Iter() *LabelIter {
|
||||||
|
ls.Sort()
|
||||||
|
return &LabelIter{labels: ls, cnt: len(ls.keys)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iter *LabelIter) Next(k, v *string) bool {
|
||||||
|
if iter.cur+1 > iter.cnt {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
*k = iter.labels.keys[iter.cur]
|
||||||
|
*v = iter.labels.vals[iter.cur]
|
||||||
|
iter.cur++
|
||||||
|
return true
|
||||||
|
}
|
63
meter/meter_test.go
Normal file
63
meter/meter_test.go
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
package meter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNoopMeter(t *testing.T) {
|
||||||
|
meter := NewMeter(Path("/noop"))
|
||||||
|
assert.NotNil(t, meter)
|
||||||
|
assert.Equal(t, "/noop", meter.Options().Path)
|
||||||
|
assert.Implements(t, new(Meter), meter)
|
||||||
|
|
||||||
|
cnt := meter.Counter("counter", Label("server", "noop"))
|
||||||
|
cnt.Inc()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLabels(t *testing.T) {
|
||||||
|
var ls Labels
|
||||||
|
ls.keys = []string{"type", "server"}
|
||||||
|
ls.vals = []string{"noop", "http"}
|
||||||
|
|
||||||
|
ls.Sort()
|
||||||
|
|
||||||
|
if ls.keys[0] != "server" || ls.vals[0] != "http" {
|
||||||
|
t.Fatalf("sort error: %v", ls)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLabelsAppend(t *testing.T) {
|
||||||
|
var ls Labels
|
||||||
|
ls.keys = []string{"type", "server"}
|
||||||
|
ls.vals = []string{"noop", "http"}
|
||||||
|
|
||||||
|
var nls Labels
|
||||||
|
nls.keys = []string{"register"}
|
||||||
|
nls.vals = []string{"gossip"}
|
||||||
|
ls = ls.Append(nls)
|
||||||
|
|
||||||
|
ls.Sort()
|
||||||
|
|
||||||
|
if ls.keys[0] != "register" || ls.vals[0] != "gossip" {
|
||||||
|
t.Fatalf("append error: %v", ls)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIterator(t *testing.T) {
|
||||||
|
var ls Labels
|
||||||
|
ls.keys = []string{"type", "server", "register"}
|
||||||
|
ls.vals = []string{"noop", "http", "gossip"}
|
||||||
|
|
||||||
|
iter := ls.Iter()
|
||||||
|
var k, v string
|
||||||
|
cnt := 0
|
||||||
|
for iter.Next(&k, &v) {
|
||||||
|
if cnt == 1 && (k != "server" || v != "http") {
|
||||||
|
t.Fatalf("iter error: %s != %s || %s != %s", k, "server", v, "http")
|
||||||
|
}
|
||||||
|
cnt++
|
||||||
|
}
|
||||||
|
}
|
162
meter/noop.go
Normal file
162
meter/noop.go
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
package meter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NoopMeter is an noop implementation of Meter
|
||||||
|
type noopMeter struct {
|
||||||
|
opts Options
|
||||||
|
labels Labels
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMeter returns a configured noop reporter:
|
||||||
|
func NewMeter(opts ...Option) Meter {
|
||||||
|
return &noopMeter{opts: NewOptions(opts...)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *noopMeter) Name() string {
|
||||||
|
return r.opts.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init initialize options
|
||||||
|
func (r *noopMeter) Init(opts ...Option) error {
|
||||||
|
for _, o := range opts {
|
||||||
|
o(&r.opts)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Counter implements the Meter interface
|
||||||
|
func (r *noopMeter) Counter(name string, opts ...Option) Counter {
|
||||||
|
options := Options{}
|
||||||
|
for _, o := range opts {
|
||||||
|
o(&options)
|
||||||
|
}
|
||||||
|
return &noopCounter{labels: options.Labels}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FloatCounter implements the Meter interface
|
||||||
|
func (r *noopMeter) FloatCounter(name string, opts ...Option) FloatCounter {
|
||||||
|
return &noopFloatCounter{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gauge implements the Meter interface
|
||||||
|
func (r *noopMeter) Gauge(name string, f func() float64, opts ...Option) Gauge {
|
||||||
|
return &noopGauge{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Summary implements the Meter interface
|
||||||
|
func (r *noopMeter) Summary(name string, opts ...Option) Summary {
|
||||||
|
return &noopSummary{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SummaryExt implements the Meter interface
|
||||||
|
func (r *noopMeter) SummaryExt(name string, window time.Duration, quantiles []float64, opts ...Option) Summary {
|
||||||
|
return &noopSummary{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Histogram implements the Meter interface
|
||||||
|
func (r *noopMeter) Histogram(name string, opts ...Option) Histogram {
|
||||||
|
return &noopHistogram{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set implements the Meter interface
|
||||||
|
func (r *noopMeter) Set(opts ...Option) Meter {
|
||||||
|
m := &noopMeter{opts: r.opts}
|
||||||
|
|
||||||
|
for _, o := range opts {
|
||||||
|
o(&m.opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *noopMeter) Write(w io.Writer, withProcessMetrics bool) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Options implements the Meter interface
|
||||||
|
func (r *noopMeter) Options() Options {
|
||||||
|
return r.opts
|
||||||
|
}
|
||||||
|
|
||||||
|
// String implements the Meter interface
|
||||||
|
func (r *noopMeter) String() string {
|
||||||
|
return "noop"
|
||||||
|
}
|
||||||
|
|
||||||
|
type noopCounter struct {
|
||||||
|
labels Labels
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *noopCounter) Add(int) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *noopCounter) Dec() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *noopCounter) Get() uint64 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *noopCounter) Inc() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *noopCounter) Set(uint64) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
type noopFloatCounter struct{}
|
||||||
|
|
||||||
|
func (r *noopFloatCounter) Add(float64) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *noopFloatCounter) Get() float64 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *noopFloatCounter) Set(float64) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *noopFloatCounter) Sub(float64) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
type noopGauge struct{}
|
||||||
|
|
||||||
|
func (r *noopGauge) Get() float64 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type noopSummary struct{}
|
||||||
|
|
||||||
|
func (r *noopSummary) Update(float64) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *noopSummary) UpdateDuration(time.Time) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
type noopHistogram struct{}
|
||||||
|
|
||||||
|
func (r *noopHistogram) Reset() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *noopHistogram) Update(float64) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *noopHistogram) UpdateDuration(time.Time) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//func (r *noopHistogram) VisitNonZeroBuckets(f func(vmrange string, count uint64)) {}
|
102
meter/options.go
Normal file
102
meter/options.go
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
package meter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/unistack-org/micro/v3/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Option powers the configuration for metrics implementations:
|
||||||
|
type Option func(*Options)
|
||||||
|
|
||||||
|
// Options for metrics implementations:
|
||||||
|
type Options struct {
|
||||||
|
Name string
|
||||||
|
Address string
|
||||||
|
Path string
|
||||||
|
Labels Labels
|
||||||
|
//TimingObjectives map[float64]float64
|
||||||
|
Logger logger.Logger
|
||||||
|
Context context.Context
|
||||||
|
MetricPrefix string
|
||||||
|
LabelPrefix string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewOptions prepares a set of options:
|
||||||
|
func NewOptions(opt ...Option) Options {
|
||||||
|
opts := Options{
|
||||||
|
Address: DefaultAddress,
|
||||||
|
Path: DefaultPath,
|
||||||
|
Context: context.Background(),
|
||||||
|
Logger: logger.DefaultLogger,
|
||||||
|
MetricPrefix: DefaultMetricPrefix,
|
||||||
|
LabelPrefix: DefaultLabelPrefix,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, o := range opt {
|
||||||
|
o(&opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
return opts
|
||||||
|
}
|
||||||
|
|
||||||
|
// Context sets the metrics context
|
||||||
|
func Context(ctx context.Context) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Context = ctx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Path used to serve metrics over HTTP
|
||||||
|
func Path(value string) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Path = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Address is the listen address to serve metrics
|
||||||
|
func Address(value string) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Address = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Labels be added to every metric
|
||||||
|
func Labels(labels []string) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Labels = labels
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
// TimingObjectives defines the desired spread of statistics for histogram / timing metrics:
|
||||||
|
func TimingObjectives(value map[float64]float64) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.TimingObjectives = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Logger sets the logger
|
||||||
|
func Logger(l logger.Logger) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Logger = l
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Label sets the label
|
||||||
|
func Label(key, val string) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Labels.keys = append(o.Labels.keys, key)
|
||||||
|
o.Labels.vals = append(o.Labels.vals, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name sets the name
|
||||||
|
func Name(n string) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Name = n
|
||||||
|
}
|
||||||
|
}
|
232
meter/wrapper/wrapper.go
Normal file
232
meter/wrapper/wrapper.go
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
// +build ignore
|
||||||
|
|
||||||
|
package wrapper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/unistack-org/micro/v3/client"
|
||||||
|
"github.com/unistack-org/micro/v3/meter"
|
||||||
|
"github.com/unistack-org/micro/v3/server"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Options struct {
|
||||||
|
Meter meter.Meter
|
||||||
|
Name string
|
||||||
|
Version string
|
||||||
|
ID string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Option func(*Options)
|
||||||
|
|
||||||
|
func ServiceName(name string) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Name = name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ServiceVersion(version string) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Version = version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ServiceID(id string) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.ID = id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Meter(m meter.Meter) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Meter = m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type wrapper struct {
|
||||||
|
options Options
|
||||||
|
callFunc client.CallFunc
|
||||||
|
client.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClientWrapper(opts ...Option) client.Wrapper {
|
||||||
|
return func(c client.Client) client.Client {
|
||||||
|
handler := &wrapper{
|
||||||
|
labels: labels,
|
||||||
|
Client: c,
|
||||||
|
}
|
||||||
|
|
||||||
|
return handler
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCallWrapper(opts ...Option) client.CallWrapper {
|
||||||
|
labels := getLabels(opts...)
|
||||||
|
|
||||||
|
return func(fn client.CallFunc) client.CallFunc {
|
||||||
|
handler := &wrapper{
|
||||||
|
labels: labels,
|
||||||
|
callFunc: fn,
|
||||||
|
}
|
||||||
|
|
||||||
|
return handler.CallFunc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrapper) CallFunc(ctx context.Context, addr string, req client.Request, rsp interface{}, opts client.CallOptions) error {
|
||||||
|
endpoint := fmt.Sprintf("%s.%s", req.Service(), req.Endpoint())
|
||||||
|
wlabels := append(w.labels, fmt.Sprintf(`%sendpoint="%s"`, DefaultLabelPrefix, endpoint))
|
||||||
|
|
||||||
|
timeCounterSummary := metrics.GetOrCreateSummary(getName("client_request_latency_microseconds", wlabels))
|
||||||
|
timeCounterHistogram := metrics.GetOrCreateSummary(getName("client_request_duration_seconds", wlabels))
|
||||||
|
|
||||||
|
ts := time.Now()
|
||||||
|
err := w.callFunc(ctx, addr, req, rsp, opts)
|
||||||
|
te := time.Since(ts)
|
||||||
|
|
||||||
|
timeCounterSummary.Update(float64(te.Seconds()))
|
||||||
|
timeCounterHistogram.Update(te.Seconds())
|
||||||
|
if err == nil {
|
||||||
|
metrics.GetOrCreateCounter(getName("client_request_total", append(wlabels, fmt.Sprintf(`%sstatus="success"`, DefaultLabelPrefix)))).Inc()
|
||||||
|
} else {
|
||||||
|
metrics.GetOrCreateCounter(getName("client_request_total", append(wlabels, fmt.Sprintf(`%sstatus="failure"`, DefaultLabelPrefix)))).Inc()
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
|
||||||
|
endpoint := fmt.Sprintf("%s.%s", req.Service(), req.Endpoint())
|
||||||
|
wlabels := append(w.labels, fmt.Sprintf(`%sendpoint="%s"`, DefaultLabelPrefix, endpoint))
|
||||||
|
|
||||||
|
timeCounterSummary := metrics.GetOrCreateSummary(getName("client_request_latency_microseconds", wlabels))
|
||||||
|
timeCounterHistogram := metrics.GetOrCreateSummary(getName("client_request_duration_seconds", wlabels))
|
||||||
|
|
||||||
|
ts := time.Now()
|
||||||
|
err := w.Client.Call(ctx, req, rsp, opts...)
|
||||||
|
te := time.Since(ts)
|
||||||
|
|
||||||
|
timeCounterSummary.Update(float64(te.Seconds()))
|
||||||
|
timeCounterHistogram.Update(te.Seconds())
|
||||||
|
if err == nil {
|
||||||
|
metrics.GetOrCreateCounter(getName("client_request_total", append(wlabels, fmt.Sprintf(`%sstatus="success"`, DefaultLabelPrefix)))).Inc()
|
||||||
|
} else {
|
||||||
|
metrics.GetOrCreateCounter(getName("client_request_total", append(wlabels, fmt.Sprintf(`%sstatus="failure"`, DefaultLabelPrefix)))).Inc()
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrapper) Stream(ctx context.Context, req client.Request, opts ...client.CallOption) (client.Stream, error) {
|
||||||
|
endpoint := fmt.Sprintf("%s.%s", req.Service(), req.Endpoint())
|
||||||
|
wlabels := append(w.labels, fmt.Sprintf(`%sendpoint="%s"`, DefaultLabelPrefix, endpoint))
|
||||||
|
|
||||||
|
timeCounterSummary := metrics.GetOrCreateSummary(getName("client_request_latency_microseconds", wlabels))
|
||||||
|
timeCounterHistogram := metrics.GetOrCreateSummary(getName("client_request_duration_seconds", wlabels))
|
||||||
|
|
||||||
|
ts := time.Now()
|
||||||
|
stream, err := w.Client.Stream(ctx, req, opts...)
|
||||||
|
te := time.Since(ts)
|
||||||
|
|
||||||
|
timeCounterSummary.Update(float64(te.Seconds()))
|
||||||
|
timeCounterHistogram.Update(te.Seconds())
|
||||||
|
if err == nil {
|
||||||
|
metrics.GetOrCreateCounter(getName("client_request_total", append(wlabels, fmt.Sprintf(`%sstatus="success"`, DefaultLabelPrefix)))).Inc()
|
||||||
|
} else {
|
||||||
|
metrics.GetOrCreateCounter(getName("client_request_total", append(wlabels, fmt.Sprintf(`%sstatus="failure"`, DefaultLabelPrefix)))).Inc()
|
||||||
|
}
|
||||||
|
|
||||||
|
return stream, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrapper) Publish(ctx context.Context, p client.Message, opts ...client.PublishOption) error {
|
||||||
|
endpoint := p.Topic()
|
||||||
|
wlabels := append(w.labels, fmt.Sprintf(`%sendpoint="%s"`, DefaultLabelPrefix, endpoint))
|
||||||
|
|
||||||
|
timeCounterSummary := metrics.GetOrCreateSummary(getName("publish_message_latency_microseconds", wlabels))
|
||||||
|
timeCounterHistogram := metrics.GetOrCreateSummary(getName("publish_message_duration_seconds", wlabels))
|
||||||
|
|
||||||
|
ts := time.Now()
|
||||||
|
err := w.Client.Publish(ctx, p, opts...)
|
||||||
|
te := time.Since(ts)
|
||||||
|
|
||||||
|
timeCounterSummary.Update(float64(te.Seconds()))
|
||||||
|
timeCounterHistogram.Update(te.Seconds())
|
||||||
|
if err == nil {
|
||||||
|
metrics.GetOrCreateCounter(getName("publish_message_total", append(wlabels, fmt.Sprintf(`%sstatus="success"`, DefaultLabelPrefix)))).Inc()
|
||||||
|
} else {
|
||||||
|
metrics.GetOrCreateCounter(getName("publish_message_total", append(wlabels, fmt.Sprintf(`%sstatus="failure"`, DefaultLabelPrefix)))).Inc()
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHandlerWrapper(opts ...Option) server.HandlerWrapper {
|
||||||
|
labels := getLabels(opts...)
|
||||||
|
|
||||||
|
handler := &wrapper{
|
||||||
|
labels: labels,
|
||||||
|
}
|
||||||
|
|
||||||
|
return handler.HandlerFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrapper) HandlerFunc(fn server.HandlerFunc) server.HandlerFunc {
|
||||||
|
return func(ctx context.Context, req server.Request, rsp interface{}) error {
|
||||||
|
endpoint := req.Endpoint()
|
||||||
|
wlabels := append(w.labels, fmt.Sprintf(`%sendpoint="%s"`, DefaultLabelPrefix, endpoint))
|
||||||
|
|
||||||
|
timeCounterSummary := metrics.GetOrCreateSummary(getName("server_request_latency_microseconds", wlabels))
|
||||||
|
timeCounterHistogram := metrics.GetOrCreateSummary(getName("server_request_duration_seconds", wlabels))
|
||||||
|
|
||||||
|
ts := time.Now()
|
||||||
|
err := fn(ctx, req, rsp)
|
||||||
|
te := time.Since(ts)
|
||||||
|
|
||||||
|
timeCounterSummary.Update(float64(te.Seconds()))
|
||||||
|
timeCounterHistogram.Update(te.Seconds())
|
||||||
|
if err == nil {
|
||||||
|
metrics.GetOrCreateCounter(getName("server_request_total", append(wlabels, fmt.Sprintf(`%sstatus="success"`, DefaultLabelPrefix)))).Inc()
|
||||||
|
} else {
|
||||||
|
metrics.GetOrCreateCounter(getName("server_request_total", append(wlabels, fmt.Sprintf(`%sstatus="failure"`, DefaultLabelPrefix)))).Inc()
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSubscriberWrapper(opts ...Option) server.SubscriberWrapper {
|
||||||
|
labels := getLabels(opts...)
|
||||||
|
|
||||||
|
handler := &wrapper{
|
||||||
|
labels: labels,
|
||||||
|
}
|
||||||
|
|
||||||
|
return handler.SubscriberFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrapper) SubscriberFunc(fn server.SubscriberFunc) server.SubscriberFunc {
|
||||||
|
return func(ctx context.Context, msg server.Message) error {
|
||||||
|
endpoint := msg.Topic()
|
||||||
|
wlabels := append(w.labels, fmt.Sprintf(`%sendpoint="%s"`, DefaultLabelPrefix, endpoint))
|
||||||
|
|
||||||
|
timeCounterSummary := metrics.GetOrCreateSummary(getName("subscribe_message_latency_microseconds", wlabels))
|
||||||
|
timeCounterHistogram := metrics.GetOrCreateSummary(getName("subscribe_message_duration_seconds", wlabels))
|
||||||
|
|
||||||
|
ts := time.Now()
|
||||||
|
err := fn(ctx, msg)
|
||||||
|
te := time.Since(ts)
|
||||||
|
|
||||||
|
timeCounterSummary.Update(float64(te.Seconds()))
|
||||||
|
timeCounterHistogram.Update(te.Seconds())
|
||||||
|
if err == nil {
|
||||||
|
metrics.GetOrCreateCounter(getName("subscribe_message_total", append(wlabels, fmt.Sprintf(`%sstatus="success"`, DefaultLabelPrefix)))).Inc()
|
||||||
|
} else {
|
||||||
|
metrics.GetOrCreateCounter(getName("subscribe_message_total", append(wlabels, fmt.Sprintf(`%sstatus="failure"`, DefaultLabelPrefix)))).Inc()
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
@@ -1,22 +0,0 @@
|
|||||||
metrics
|
|
||||||
=======
|
|
||||||
|
|
||||||
The metrics package provides a simple metrics "Reporter" interface which allows the user to submit counters, gauges and timings (along with key/value tags).
|
|
||||||
|
|
||||||
Implementations
|
|
||||||
---------------
|
|
||||||
|
|
||||||
* Prometheus (pull): will be first
|
|
||||||
* Prometheus (push): certainly achievable
|
|
||||||
* InfluxDB: could quite easily be done
|
|
||||||
* Telegraf: almost identical to the InfluxDB implementation
|
|
||||||
* Micro: Could we provide metrics over Micro's server interface?
|
|
||||||
|
|
||||||
|
|
||||||
Todo
|
|
||||||
----
|
|
||||||
|
|
||||||
* Include a handler middleware which uses the Reporter interface to generate per-request level metrics
|
|
||||||
- Throughput
|
|
||||||
- Errors
|
|
||||||
- Duration
|
|
@@ -1,47 +0,0 @@
|
|||||||
package metrics
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/unistack-org/micro/v3/metadata"
|
|
||||||
)
|
|
||||||
|
|
||||||
// NoopReporter is an noop implementation of Reporter:
|
|
||||||
type noopReporter struct {
|
|
||||||
opts Options
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewReporter returns a configured noop reporter:
|
|
||||||
func NewReporter(opts ...Option) Reporter {
|
|
||||||
return &noopReporter{
|
|
||||||
opts: NewOptions(opts...),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init initialize options
|
|
||||||
func (r *noopReporter) Init(opts ...Option) error {
|
|
||||||
for _, o := range opts {
|
|
||||||
o(&r.opts)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Count implements the Reporter interface Count method:
|
|
||||||
func (r *noopReporter) Count(metricName string, value int64, md metadata.Metadata) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gauge implements the Reporter interface Gauge method:
|
|
||||||
func (r *noopReporter) Gauge(metricName string, value float64, md metadata.Metadata) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Timing implements the Reporter interface Timing method:
|
|
||||||
func (r *noopReporter) Timing(metricName string, value time.Duration, md metadata.Metadata) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Options implements the Reporter interface Optios method:
|
|
||||||
func (r *noopReporter) Options() Options {
|
|
||||||
return r.opts
|
|
||||||
}
|
|
@@ -1,89 +0,0 @@
|
|||||||
package metrics
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/unistack-org/micro/v3/logger"
|
|
||||||
"github.com/unistack-org/micro/v3/metadata"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// The Prometheus metrics will be made available on this port:
|
|
||||||
defaultPrometheusListenAddress = ":9000"
|
|
||||||
// This is the endpoint where the Prometheus metrics will be made available ("/metrics" is the default with Prometheus):
|
|
||||||
defaultPath = "/metrics"
|
|
||||||
// timingObjectives is the default spread of stats we maintain for timings / histograms:
|
|
||||||
defaultTimingObjectives = map[float64]float64{0.0: 0, 0.5: 0.05, 0.75: 0.04, 0.90: 0.03, 0.95: 0.02, 0.98: 0.001, 1: 0}
|
|
||||||
)
|
|
||||||
|
|
||||||
// Option powers the configuration for metrics implementations:
|
|
||||||
type Option func(*Options)
|
|
||||||
|
|
||||||
// Options for metrics implementations:
|
|
||||||
type Options struct {
|
|
||||||
Address string
|
|
||||||
Path string
|
|
||||||
DefaultTags metadata.Metadata
|
|
||||||
TimingObjectives map[float64]float64
|
|
||||||
Logger logger.Logger
|
|
||||||
Context context.Context
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewOptions prepares a set of options:
|
|
||||||
func NewOptions(opt ...Option) Options {
|
|
||||||
opts := Options{
|
|
||||||
Address: defaultPrometheusListenAddress,
|
|
||||||
DefaultTags: metadata.New(2),
|
|
||||||
Path: defaultPath,
|
|
||||||
TimingObjectives: defaultTimingObjectives,
|
|
||||||
Context: context.Background(),
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, o := range opt {
|
|
||||||
o(&opts)
|
|
||||||
}
|
|
||||||
|
|
||||||
return opts
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cntext sets the metrics context
|
|
||||||
func Context(ctx context.Context) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.Context = ctx
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Path used to serve metrics over HTTP:
|
|
||||||
func Path(value string) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.Path = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Address is the listen address to serve metrics on:
|
|
||||||
func Address(value string) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.Address = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultTags will be added to every metric:
|
|
||||||
func DefaultTags(md metadata.Metadata) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.DefaultTags = metadata.Copy(md)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TimingObjectives defines the desired spread of statistics for histogram / timing metrics:
|
|
||||||
func TimingObjectives(value map[float64]float64) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.TimingObjectives = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Logger sets the logger
|
|
||||||
func Logger(l logger.Logger) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.Logger = l
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,21 +0,0 @@
|
|||||||
// Package metrics is for instrumentation and debugging
|
|
||||||
package metrics
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/unistack-org/micro/v3/metadata"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
DefaultReporter Reporter = NewReporter()
|
|
||||||
)
|
|
||||||
|
|
||||||
// Reporter is an interface for collecting and instrumenting metrics
|
|
||||||
type Reporter interface {
|
|
||||||
Init(...Option) error
|
|
||||||
Count(id string, value int64, md metadata.Metadata) error
|
|
||||||
Gauge(id string, value float64, md metadata.Metadata) error
|
|
||||||
Timing(id string, value time.Duration, md metadata.Metadata) error
|
|
||||||
Options() Options
|
|
||||||
}
|
|
@@ -1,17 +0,0 @@
|
|||||||
package metrics
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestNoopReporter(t *testing.T) {
|
|
||||||
// Make a Reporter:
|
|
||||||
reporter := NewReporter(Path("/noop"))
|
|
||||||
assert.NotNil(t, reporter)
|
|
||||||
assert.Equal(t, "/noop", reporter.Options().Path)
|
|
||||||
|
|
||||||
// Check that our implementation is valid:
|
|
||||||
assert.Implements(t, new(Reporter), reporter)
|
|
||||||
}
|
|
@@ -1,50 +0,0 @@
|
|||||||
package wrapper
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/unistack-org/micro/v3/metadata"
|
|
||||||
"github.com/unistack-org/micro/v3/metrics"
|
|
||||||
"github.com/unistack-org/micro/v3/server"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Wrapper provides a HandlerFunc for metrics.Reporter implementations:
|
|
||||||
type Wrapper struct {
|
|
||||||
reporter metrics.Reporter
|
|
||||||
}
|
|
||||||
|
|
||||||
// New returns a *Wrapper configured with the given metrics.Reporter:
|
|
||||||
func New(reporter metrics.Reporter) *Wrapper {
|
|
||||||
return &Wrapper{
|
|
||||||
reporter: reporter,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandlerFunc instruments handlers registered to a service:
|
|
||||||
func (w *Wrapper) HandlerFunc(handlerFunction server.HandlerFunc) server.HandlerFunc {
|
|
||||||
return func(ctx context.Context, req server.Request, rsp interface{}) error {
|
|
||||||
|
|
||||||
// Build some tags to describe the call:
|
|
||||||
tags := metadata.New(2)
|
|
||||||
tags.Set("method", req.Method())
|
|
||||||
|
|
||||||
// Start the clock:
|
|
||||||
callTime := time.Now()
|
|
||||||
|
|
||||||
// Run the handlerFunction:
|
|
||||||
err := handlerFunction(ctx, req, rsp)
|
|
||||||
|
|
||||||
// Add a result tag:
|
|
||||||
if err != nil {
|
|
||||||
tags["status"] = "failure"
|
|
||||||
} else {
|
|
||||||
tags["status"] = "success"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Instrument the result (if the DefaultClient has been configured):
|
|
||||||
w.reporter.Timing("service.handler", time.Since(callTime), tags)
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
119
micro.go
119
micro.go
@@ -1,119 +0,0 @@
|
|||||||
// Package micro is a pluggable framework for microservices
|
|
||||||
package micro
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/unistack-org/micro/v3/broker"
|
|
||||||
"github.com/unistack-org/micro/v3/client"
|
|
||||||
"github.com/unistack-org/micro/v3/server"
|
|
||||||
)
|
|
||||||
|
|
||||||
type serviceKey struct{}
|
|
||||||
|
|
||||||
// Service is an interface that wraps the lower level libraries
|
|
||||||
// within micro. Its a convenience method for building
|
|
||||||
// and initialising services.
|
|
||||||
type Service interface {
|
|
||||||
// The service name
|
|
||||||
Name() string
|
|
||||||
// Init initialises options
|
|
||||||
Init(...Option) error
|
|
||||||
// Options returns the current options
|
|
||||||
Options() Options
|
|
||||||
// Client is used to call services
|
|
||||||
Client() client.Client
|
|
||||||
// Server is for handling requests and events
|
|
||||||
Server() server.Server
|
|
||||||
// Broker is for broker usage
|
|
||||||
Broker() broker.Broker
|
|
||||||
// Run the service
|
|
||||||
Run() error
|
|
||||||
// The service implementation
|
|
||||||
String() string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function is a one time executing Service
|
|
||||||
type Function interface {
|
|
||||||
// Inherits Service interface
|
|
||||||
Service
|
|
||||||
// Done signals to complete execution
|
|
||||||
Done() error
|
|
||||||
// Handle registers an RPC handler
|
|
||||||
Handle(v interface{}) error
|
|
||||||
// Subscribe registers a subscriber
|
|
||||||
Subscribe(topic string, v interface{}) error
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
// Type Event is a future type for acting on asynchronous events
|
|
||||||
type Event interface {
|
|
||||||
// Publish publishes a message to the event topic
|
|
||||||
Publish(ctx context.Context, msg interface{}, opts ...client.PublishOption) error
|
|
||||||
// Subscribe to the event
|
|
||||||
Subscribe(ctx context.Context, v in
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resource is a future type for defining dependencies
|
|
||||||
type Resource interface {
|
|
||||||
// Name of the resource
|
|
||||||
Name() string
|
|
||||||
// Type of resource
|
|
||||||
Type() string
|
|
||||||
// Method of creation
|
|
||||||
Create() error
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Event is used to publish messages to a topic
|
|
||||||
type Event interface {
|
|
||||||
// Publish publishes a message to the event topic
|
|
||||||
Publish(ctx context.Context, msg interface{}, opts ...client.PublishOption) error
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
// HeaderPrefix for all headers passed
|
|
||||||
HeaderPrefix = "Micro-"
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewService creates and returns a new Service based on the packages within.
|
|
||||||
func NewService(opts ...Option) Service {
|
|
||||||
return newService(opts...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromContext retrieves a Service from the Context.
|
|
||||||
func FromContext(ctx context.Context) (Service, bool) {
|
|
||||||
if ctx == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
s, ok := ctx.Value(serviceKey{}).(Service)
|
|
||||||
return s, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewContext returns a new Context with the Service embedded within it.
|
|
||||||
func NewContext(ctx context.Context, s Service) context.Context {
|
|
||||||
if ctx == nil {
|
|
||||||
ctx = context.Background()
|
|
||||||
}
|
|
||||||
return context.WithValue(ctx, serviceKey{}, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFunction returns a new Function for a one time executing Service
|
|
||||||
func NewFunction(opts ...Option) Function {
|
|
||||||
return newFunction(opts...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewEvent creates a new event publisher
|
|
||||||
func NewEvent(topic string, c client.Client) Event {
|
|
||||||
return &event{c, topic}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterHandler is syntactic sugar for registering a handler
|
|
||||||
func RegisterHandler(s server.Server, h interface{}, opts ...server.HandlerOption) error {
|
|
||||||
return s.Handle(s.NewHandler(h, opts...))
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterSubscriber is syntactic sugar for registering a subscriber
|
|
||||||
func RegisterSubscriber(topic string, s server.Server, h interface{}, opts ...server.SubscriberOption) error {
|
|
||||||
return s.Subscribe(s.NewSubscriber(topic, h, opts...))
|
|
||||||
}
|
|
@@ -3,9 +3,11 @@ package network
|
|||||||
import (
|
import (
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/unistack-org/micro/v3/logger"
|
"github.com/unistack-org/micro/v3/logger"
|
||||||
|
"github.com/unistack-org/micro/v3/meter"
|
||||||
"github.com/unistack-org/micro/v3/network/tunnel"
|
"github.com/unistack-org/micro/v3/network/tunnel"
|
||||||
"github.com/unistack-org/micro/v3/proxy"
|
"github.com/unistack-org/micro/v3/proxy"
|
||||||
"github.com/unistack-org/micro/v3/router"
|
"github.com/unistack-org/micro/v3/router"
|
||||||
|
"github.com/unistack-org/micro/v3/tracer"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Option func
|
// Option func
|
||||||
@@ -31,6 +33,10 @@ type Options struct {
|
|||||||
Proxy proxy.Proxy
|
Proxy proxy.Proxy
|
||||||
// Logger
|
// Logger
|
||||||
Logger logger.Logger
|
Logger logger.Logger
|
||||||
|
// Meter
|
||||||
|
Meter meter.Meter
|
||||||
|
// Tracer
|
||||||
|
Tracer tracer.Tracer
|
||||||
}
|
}
|
||||||
|
|
||||||
// Id sets the id of the network node
|
// Id sets the id of the network node
|
||||||
@@ -96,11 +102,34 @@ func Logger(l logger.Logger) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultOptions returns network default options
|
// Meter sets the meter
|
||||||
func DefaultOptions() Options {
|
func Meter(m meter.Meter) Option {
|
||||||
return Options{
|
return func(o *Options) {
|
||||||
|
o.Meter = m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tracer to be used for tracing
|
||||||
|
func Tracer(t tracer.Tracer) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Tracer = t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewOptions returns network default options
|
||||||
|
func NewOptions(opts ...Option) Options {
|
||||||
|
options := Options{
|
||||||
Id: uuid.New().String(),
|
Id: uuid.New().String(),
|
||||||
Name: "go.micro",
|
Name: "go.micro",
|
||||||
Address: ":0",
|
Address: ":0",
|
||||||
|
Logger: logger.DefaultLogger,
|
||||||
|
Meter: meter.DefaultMeter,
|
||||||
|
Tracer: tracer.DefaultTracer,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, o := range opts {
|
||||||
|
o(&options)
|
||||||
|
}
|
||||||
|
|
||||||
|
return options
|
||||||
}
|
}
|
||||||
|
@@ -7,9 +7,12 @@ import (
|
|||||||
|
|
||||||
"github.com/unistack-org/micro/v3/codec"
|
"github.com/unistack-org/micro/v3/codec"
|
||||||
"github.com/unistack-org/micro/v3/logger"
|
"github.com/unistack-org/micro/v3/logger"
|
||||||
|
"github.com/unistack-org/micro/v3/meter"
|
||||||
|
"github.com/unistack-org/micro/v3/tracer"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Options struct {
|
type Options struct {
|
||||||
|
Name string
|
||||||
// Addrs is the list of intermediary addresses to connect to
|
// Addrs is the list of intermediary addresses to connect to
|
||||||
Addrs []string
|
Addrs []string
|
||||||
// Codec is the codec interface to use where headers are not supported
|
// Codec is the codec interface to use where headers are not supported
|
||||||
@@ -26,6 +29,10 @@ type Options struct {
|
|||||||
Timeout time.Duration
|
Timeout time.Duration
|
||||||
// Logger sets the logger
|
// Logger sets the logger
|
||||||
Logger logger.Logger
|
Logger logger.Logger
|
||||||
|
// Meter sets the meter
|
||||||
|
Meter meter.Meter
|
||||||
|
// Tracer
|
||||||
|
Tracer tracer.Tracer
|
||||||
// Other options for implementations of the interface
|
// Other options for implementations of the interface
|
||||||
// can be stored in a context
|
// can be stored in a context
|
||||||
Context context.Context
|
Context context.Context
|
||||||
@@ -35,6 +42,8 @@ type Options struct {
|
|||||||
func NewOptions(opts ...Option) Options {
|
func NewOptions(opts ...Option) Options {
|
||||||
options := Options{
|
options := Options{
|
||||||
Logger: logger.DefaultLogger,
|
Logger: logger.DefaultLogger,
|
||||||
|
Meter: meter.DefaultMeter,
|
||||||
|
Tracer: tracer.DefaultTracer,
|
||||||
Context: context.Background(),
|
Context: context.Background(),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,6 +121,13 @@ func Logger(l logger.Logger) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Meter sets the meter
|
||||||
|
func Meter(m meter.Meter) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Meter = m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Context sets the context
|
// Context sets the context
|
||||||
func Context(ctx context.Context) Option {
|
func Context(ctx context.Context) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
@@ -134,14 +150,6 @@ func Timeout(t time.Duration) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use secure communication. If TLSConfig is not specified we
|
|
||||||
// use InsecureSkipVerify and generate a self signed cert
|
|
||||||
func Secure(b bool) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.Secure = b
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TLSConfig to be used for the transport.
|
// TLSConfig to be used for the transport.
|
||||||
func TLSConfig(t *tls.Config) Option {
|
func TLSConfig(t *tls.Config) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
@@ -162,3 +170,17 @@ func WithTimeout(d time.Duration) DialOption {
|
|||||||
o.Timeout = d
|
o.Timeout = d
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tracer to be used for tracing
|
||||||
|
func Tracer(t tracer.Tracer) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Tracer = t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name sets the name
|
||||||
|
func Name(n string) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Name = n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -41,6 +41,10 @@ func (t *tunBroker) Init(opts ...broker.Option) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *tunBroker) Name() string {
|
||||||
|
return t.opts.Name
|
||||||
|
}
|
||||||
|
|
||||||
func (t *tunBroker) Options() broker.Options {
|
func (t *tunBroker) Options() broker.Options {
|
||||||
return t.opts
|
return t.opts
|
||||||
}
|
}
|
||||||
|
@@ -5,7 +5,9 @@ import (
|
|||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/unistack-org/micro/v3/logger"
|
"github.com/unistack-org/micro/v3/logger"
|
||||||
|
"github.com/unistack-org/micro/v3/meter"
|
||||||
"github.com/unistack-org/micro/v3/network/transport"
|
"github.com/unistack-org/micro/v3/network/transport"
|
||||||
|
"github.com/unistack-org/micro/v3/tracer"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -20,6 +22,7 @@ type Option func(*Options)
|
|||||||
|
|
||||||
// Options provides network configuration options
|
// Options provides network configuration options
|
||||||
type Options struct {
|
type Options struct {
|
||||||
|
Name string
|
||||||
// Id is tunnel id
|
// Id is tunnel id
|
||||||
Id string
|
Id string
|
||||||
// Address is tunnel address
|
// Address is tunnel address
|
||||||
@@ -32,6 +35,10 @@ type Options struct {
|
|||||||
Transport transport.Transport
|
Transport transport.Transport
|
||||||
// Logger
|
// Logger
|
||||||
Logger logger.Logger
|
Logger logger.Logger
|
||||||
|
// Meter
|
||||||
|
Meter meter.Meter
|
||||||
|
// Tracer
|
||||||
|
Tracer tracer.Tracer
|
||||||
}
|
}
|
||||||
|
|
||||||
// DialOption func
|
// DialOption func
|
||||||
@@ -74,6 +81,13 @@ func Logger(l logger.Logger) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Meter sets the meter
|
||||||
|
func Meter(m meter.Meter) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Meter = m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Address sets the tunnel address
|
// Address sets the tunnel address
|
||||||
func Address(a string) Option {
|
func Address(a string) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
@@ -152,9 +166,26 @@ func NewOptions(opts ...Option) Options {
|
|||||||
Id: uuid.New().String(),
|
Id: uuid.New().String(),
|
||||||
Address: DefaultAddress,
|
Address: DefaultAddress,
|
||||||
Token: DefaultToken,
|
Token: DefaultToken,
|
||||||
|
Logger: logger.DefaultLogger,
|
||||||
|
Meter: meter.DefaultMeter,
|
||||||
|
Tracer: tracer.DefaultTracer,
|
||||||
}
|
}
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
o(&options)
|
o(&options)
|
||||||
}
|
}
|
||||||
return options
|
return options
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tracer to be used for tracing
|
||||||
|
func Tracer(t tracer.Tracer) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Tracer = t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name sets the name
|
||||||
|
func Name(n string) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Name = n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
644
options.go
644
options.go
@@ -2,37 +2,44 @@ package micro
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/unistack-org/micro/v3/auth"
|
"github.com/unistack-org/micro/v3/auth"
|
||||||
"github.com/unistack-org/micro/v3/broker"
|
"github.com/unistack-org/micro/v3/broker"
|
||||||
"github.com/unistack-org/micro/v3/client"
|
"github.com/unistack-org/micro/v3/client"
|
||||||
"github.com/unistack-org/micro/v3/config"
|
"github.com/unistack-org/micro/v3/config"
|
||||||
"github.com/unistack-org/micro/v3/debug/profile"
|
|
||||||
"github.com/unistack-org/micro/v3/logger"
|
"github.com/unistack-org/micro/v3/logger"
|
||||||
"github.com/unistack-org/micro/v3/metadata"
|
"github.com/unistack-org/micro/v3/metadata"
|
||||||
"github.com/unistack-org/micro/v3/registry"
|
"github.com/unistack-org/micro/v3/meter"
|
||||||
|
"github.com/unistack-org/micro/v3/register"
|
||||||
"github.com/unistack-org/micro/v3/router"
|
"github.com/unistack-org/micro/v3/router"
|
||||||
"github.com/unistack-org/micro/v3/runtime"
|
|
||||||
"github.com/unistack-org/micro/v3/selector"
|
|
||||||
"github.com/unistack-org/micro/v3/server"
|
"github.com/unistack-org/micro/v3/server"
|
||||||
"github.com/unistack-org/micro/v3/store"
|
"github.com/unistack-org/micro/v3/store"
|
||||||
"github.com/unistack-org/micro/v3/tracer"
|
"github.com/unistack-org/micro/v3/tracer"
|
||||||
|
// "github.com/unistack-org/micro/v3/debug/profile"
|
||||||
|
// "github.com/unistack-org/micro/v3/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Options for micro service
|
// Options for micro service
|
||||||
type Options struct {
|
type Options struct {
|
||||||
Auth auth.Auth
|
Name string
|
||||||
Broker broker.Broker
|
Version string
|
||||||
Logger logger.Logger
|
Metadata metadata.Metadata
|
||||||
Configs []config.Config
|
|
||||||
Client client.Client
|
Auths []auth.Auth
|
||||||
Server server.Server
|
Brokers []broker.Broker
|
||||||
Store store.Store
|
Loggers []logger.Logger
|
||||||
Registry registry.Registry
|
Meters []meter.Meter
|
||||||
Router router.Router
|
Configs []config.Config
|
||||||
Runtime runtime.Runtime
|
Clients []client.Client
|
||||||
Profile profile.Profile
|
Servers []server.Server
|
||||||
|
Stores []store.Store
|
||||||
|
Registers []register.Register
|
||||||
|
Tracers []tracer.Tracer
|
||||||
|
Routers []router.Router
|
||||||
|
// Runtime runtime.Runtime
|
||||||
|
// Profile profile.Profile
|
||||||
|
|
||||||
// Before and After funcs
|
// Before and After funcs
|
||||||
BeforeStart []func(context.Context) error
|
BeforeStart []func(context.Context) error
|
||||||
@@ -48,16 +55,18 @@ type Options struct {
|
|||||||
// NewOptions returns new Options filled with defaults and overrided by provided opts
|
// NewOptions returns new Options filled with defaults and overrided by provided opts
|
||||||
func NewOptions(opts ...Option) Options {
|
func NewOptions(opts ...Option) Options {
|
||||||
options := Options{
|
options := Options{
|
||||||
Context: context.Background(),
|
Context: context.Background(),
|
||||||
Server: server.DefaultServer,
|
Servers: []server.Server{server.DefaultServer},
|
||||||
Client: client.DefaultClient,
|
Clients: []client.Client{client.DefaultClient},
|
||||||
Broker: broker.DefaultBroker,
|
Brokers: []broker.Broker{broker.DefaultBroker},
|
||||||
Registry: registry.DefaultRegistry,
|
Registers: []register.Register{register.DefaultRegister},
|
||||||
Router: router.DefaultRouter,
|
Routers: []router.Router{router.DefaultRouter},
|
||||||
Auth: auth.DefaultAuth,
|
Auths: []auth.Auth{auth.DefaultAuth},
|
||||||
Logger: logger.DefaultLogger,
|
Loggers: []logger.Logger{logger.DefaultLogger},
|
||||||
Configs: []config.Config{config.DefaultConfig},
|
Tracers: []tracer.Tracer{tracer.DefaultTracer},
|
||||||
Store: store.DefaultStore,
|
Meters: []meter.Meter{meter.DefaultMeter},
|
||||||
|
Configs: []config.Config{config.DefaultConfig},
|
||||||
|
Stores: []store.Store{store.DefaultStore},
|
||||||
//Runtime runtime.Runtime
|
//Runtime runtime.Runtime
|
||||||
//Profile profile.Profile
|
//Profile profile.Profile
|
||||||
}
|
}
|
||||||
@@ -70,264 +79,599 @@ func NewOptions(opts ...Option) Options {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Option func
|
// Option func
|
||||||
type Option func(*Options)
|
type Option func(*Options) error
|
||||||
|
|
||||||
// Broker to be used for service
|
// Broker to be used for client and server
|
||||||
func Broker(b broker.Broker) Option {
|
func Broker(b broker.Broker, opts ...BrokerOption) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) error {
|
||||||
o.Broker = b
|
var err error
|
||||||
if o.Client != nil {
|
bopts := brokerOptions{}
|
||||||
// Update Client and Server
|
for _, opt := range opts {
|
||||||
o.Client.Init(client.Broker(b))
|
opt(&bopts)
|
||||||
}
|
}
|
||||||
if o.Server != nil {
|
all := false
|
||||||
o.Server.Init(server.Broker(b))
|
if len(opts) == 0 {
|
||||||
|
all = true
|
||||||
}
|
}
|
||||||
|
for _, srv := range o.Servers {
|
||||||
|
for _, os := range bopts.servers {
|
||||||
|
if srv.Name() == os || all {
|
||||||
|
if err = srv.Init(server.Broker(b)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, cli := range o.Clients {
|
||||||
|
for _, oc := range bopts.clients {
|
||||||
|
if cli.Name() == oc || all {
|
||||||
|
if err = cli.Init(client.Broker(b)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type brokerOptions struct {
|
||||||
|
servers []string
|
||||||
|
clients []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type BrokerOption func(*brokerOptions)
|
||||||
|
|
||||||
|
func BrokerClient(n string) BrokerOption {
|
||||||
|
return func(o *brokerOptions) {
|
||||||
|
o.clients = append(o.clients, n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BrokerServer(n string) BrokerOption {
|
||||||
|
return func(o *brokerOptions) {
|
||||||
|
o.servers = append(o.servers, n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Client to be used for service
|
// Client to be used for service
|
||||||
func Client(c client.Client) Option {
|
func Client(c ...client.Client) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) error {
|
||||||
o.Client = c
|
o.Clients = c
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clients to be used for service
|
||||||
|
func Clients(c ...client.Client) Option {
|
||||||
|
return func(o *Options) error {
|
||||||
|
o.Clients = c
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Context specifies a context for the service.
|
// Context specifies a context for the service.
|
||||||
// Can be used to signal shutdown of the service and for extra option values.
|
// Can be used to signal shutdown of the service and for extra option values.
|
||||||
func Context(ctx context.Context) Option {
|
func Context(ctx context.Context) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) error {
|
||||||
|
// TODO: Pass context to underline stuff ?
|
||||||
o.Context = ctx
|
o.Context = ctx
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// Profile to be used for debug profile
|
// Profile to be used for debug profile
|
||||||
func Profile(p profile.Profile) Option {
|
func Profile(p profile.Profile) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
o.Profile = p
|
o.Profile = p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// Server to be used for service
|
// Server to be used for service
|
||||||
func Server(s server.Server) Option {
|
func Server(s ...server.Server) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) error {
|
||||||
o.Server = s
|
o.Servers = s
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Servers to be used for service
|
||||||
|
func Servers(s ...server.Server) Option {
|
||||||
|
return func(o *Options) error {
|
||||||
|
o.Servers = s
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store sets the store to use
|
// Store sets the store to use
|
||||||
func Store(s store.Store) Option {
|
func Store(s ...store.Store) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) error {
|
||||||
o.Store = s
|
o.Stores = s
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stores sets the store to use
|
||||||
|
func Stores(s ...store.Store) Option {
|
||||||
|
return func(o *Options) error {
|
||||||
|
o.Stores = s
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logger set the logger to use
|
// Logger set the logger to use
|
||||||
func Logger(l logger.Logger) Option {
|
func Logger(l logger.Logger, opts ...LoggerOption) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) error {
|
||||||
o.Logger = l
|
var err error
|
||||||
|
lopts := loggerOptions{}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&lopts)
|
||||||
|
}
|
||||||
|
all := false
|
||||||
|
if len(opts) == 0 {
|
||||||
|
all = true
|
||||||
|
}
|
||||||
|
for _, srv := range o.Servers {
|
||||||
|
for _, os := range lopts.servers {
|
||||||
|
if srv.Name() == os || all {
|
||||||
|
if err = srv.Init(server.Logger(l)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, cli := range o.Clients {
|
||||||
|
for _, oc := range lopts.clients {
|
||||||
|
if cli.Name() == oc || all {
|
||||||
|
if err = cli.Init(client.Logger(l)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, brk := range o.Brokers {
|
||||||
|
for _, ob := range lopts.brokers {
|
||||||
|
if brk.Name() == ob || all {
|
||||||
|
if err = brk.Init(broker.Logger(l)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, reg := range o.Registers {
|
||||||
|
for _, or := range lopts.registers {
|
||||||
|
if reg.Name() == or || all {
|
||||||
|
if err = reg.Init(register.Logger(l)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, str := range o.Stores {
|
||||||
|
for _, or := range lopts.stores {
|
||||||
|
if str.Name() == or || all {
|
||||||
|
if err = str.Init(store.Logger(l)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, mtr := range o.Meters {
|
||||||
|
for _, or := range lopts.meters {
|
||||||
|
if mtr.Name() == or || all {
|
||||||
|
if err = mtr.Init(meter.Logger(l)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, trc := range o.Tracers {
|
||||||
|
for _, ot := range lopts.tracers {
|
||||||
|
if trc.Name() == ot || all {
|
||||||
|
if err = trc.Init(tracer.Logger(l)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Registry sets the registry for the service
|
type LoggerOption func(*loggerOptions)
|
||||||
|
|
||||||
|
type loggerOptions struct {
|
||||||
|
servers []string
|
||||||
|
clients []string
|
||||||
|
brokers []string
|
||||||
|
registers []string
|
||||||
|
stores []string
|
||||||
|
meters []string
|
||||||
|
tracers []string
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
func LoggerServer(n string) LoggerOption {
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Meter set the meter to use
|
||||||
|
func Meter(m ...meter.Meter) Option {
|
||||||
|
return func(o *Options) error {
|
||||||
|
o.Meters = m
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Meters set the meter to use
|
||||||
|
func Meters(m ...meter.Meter) Option {
|
||||||
|
return func(o *Options) error {
|
||||||
|
o.Meters = m
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register sets the register for the service
|
||||||
// and the underlying components
|
// and the underlying components
|
||||||
func Registry(r registry.Registry) Option {
|
func Register(r register.Register, opts ...RegisterOption) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) error {
|
||||||
o.Registry = r
|
var err error
|
||||||
if o.Router != nil {
|
ropts := registerOptions{}
|
||||||
// Update router
|
for _, opt := range opts {
|
||||||
o.Router.Init(router.Registry(r))
|
opt(&ropts)
|
||||||
}
|
}
|
||||||
if o.Server != nil {
|
all := false
|
||||||
// Update server
|
if len(opts) == 0 {
|
||||||
o.Server.Init(server.Registry(r))
|
all = true
|
||||||
}
|
}
|
||||||
if o.Broker != nil {
|
for _, rtr := range o.Routers {
|
||||||
// Update Broker
|
for _, os := range ropts.routers {
|
||||||
o.Broker.Init(broker.Registry(r))
|
if rtr.Name() == os || all {
|
||||||
|
if err = rtr.Init(router.Register(r)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
for _, srv := range o.Servers {
|
||||||
|
for _, os := range ropts.servers {
|
||||||
|
if srv.Name() == os || all {
|
||||||
|
if err = srv.Init(server.Register(r)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, brk := range o.Brokers {
|
||||||
|
for _, os := range ropts.brokers {
|
||||||
|
if brk.Name() == os || all {
|
||||||
|
if err = brk.Init(broker.Register(r)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tracer sets the tracer for the service
|
type registerOptions struct {
|
||||||
func Tracer(t tracer.Tracer) Option {
|
routers []string
|
||||||
return func(o *Options) {
|
servers []string
|
||||||
if o.Server != nil {
|
brokers []string
|
||||||
//todo client trace
|
}
|
||||||
o.Server.Init(server.Tracer(t))
|
|
||||||
}
|
type RegisterOption func(*registerOptions)
|
||||||
|
|
||||||
|
func RegisterRouter(n string) RegisterOption {
|
||||||
|
return func(o *registerOptions) {
|
||||||
|
o.routers = append(o.routers, n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RegisterServer(n string) RegisterOption {
|
||||||
|
return func(o *registerOptions) {
|
||||||
|
o.servers = append(o.servers, n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterBroker(n string) RegisterOption {
|
||||||
|
return func(o *registerOptions) {
|
||||||
|
o.brokers = append(o.brokers, n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Tracer(t tracer.Tracer, opts ...TracerOption) Option {
|
||||||
|
return func(o *Options) error {
|
||||||
|
var err error
|
||||||
|
topts := tracerOptions{}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&topts)
|
||||||
|
}
|
||||||
|
all := false
|
||||||
|
if len(opts) == 0 {
|
||||||
|
all = true
|
||||||
|
}
|
||||||
|
for _, srv := range o.Servers {
|
||||||
|
for _, os := range topts.servers {
|
||||||
|
if srv.Name() == os || all {
|
||||||
|
if err = srv.Init(server.Tracer(t)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, cli := range o.Clients {
|
||||||
|
for _, os := range topts.clients {
|
||||||
|
if cli.Name() == os || all {
|
||||||
|
if err = cli.Init(client.Tracer(t)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, str := range o.Stores {
|
||||||
|
for _, os := range topts.stores {
|
||||||
|
if str.Name() == os || all {
|
||||||
|
if err = str.Init(store.Tracer(t)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, brk := range o.Brokers {
|
||||||
|
for _, os := range topts.brokers {
|
||||||
|
if brk.Name() == os || all {
|
||||||
|
if err = brk.Init(broker.Tracer(t)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type tracerOptions struct {
|
||||||
|
clients []string
|
||||||
|
servers []string
|
||||||
|
brokers []string
|
||||||
|
stores []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type TracerOption func(*tracerOptions)
|
||||||
|
|
||||||
|
func TracerClient(n string) TracerOption {
|
||||||
|
return func(o *tracerOptions) {
|
||||||
|
o.clients = append(o.clients, n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TracerServer(n string) TracerOption {
|
||||||
|
return func(o *tracerOptions) {
|
||||||
|
o.servers = append(o.servers, n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TracerBroker(n string) TracerOption {
|
||||||
|
return func(o *tracerOptions) {
|
||||||
|
o.brokers = append(o.brokers, n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TracerStore(n string) TracerOption {
|
||||||
|
return func(o *tracerOptions) {
|
||||||
|
o.stores = append(o.stores, n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// Auth sets the auth for the service
|
// Auth sets the auth for the service
|
||||||
func Auth(a auth.Auth) Option {
|
func Auth(a auth.Auth) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) error {
|
||||||
o.Auth = a
|
o.Auth = a
|
||||||
if o.Server != nil {
|
if o.Server != nil {
|
||||||
o.Server.Init(server.Auth(a))
|
o.Server.Init(server.Auth(a))
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Config sets the config for the service
|
||||||
|
func Config(c ...config.Config) Option {
|
||||||
|
return func(o *Options) error {
|
||||||
|
o.Configs = c
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configs sets the configs for the service
|
// Configs sets the configs for the service
|
||||||
func Configs(c ...config.Config) Option {
|
func Configs(c ...config.Config) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) error {
|
||||||
o.Configs = c
|
o.Configs = c
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// Selector sets the selector for the service client
|
// Selector sets the selector for the service client
|
||||||
func Selector(s selector.Selector) Option {
|
func Selector(s selector.Selector) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) error {
|
||||||
if o.Client != nil {
|
if o.Client != nil {
|
||||||
o.Client.Init(client.Selector(s))
|
o.Client.Init(client.Selector(s))
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
/*
|
||||||
// Runtime sets the runtime
|
// Runtime sets the runtime
|
||||||
func Runtime(r runtime.Runtime) Option {
|
func Runtime(r runtime.Runtime) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
o.Runtime = r
|
o.Runtime = r
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// Router sets the router
|
// Router sets the router
|
||||||
func Router(r router.Router) Option {
|
func Router(r router.Router, opts ...RouterOption) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) error {
|
||||||
o.Router = r
|
var err error
|
||||||
// Update client
|
ropts := routerOptions{}
|
||||||
if o.Client != nil {
|
for _, opt := range opts {
|
||||||
o.Client.Init(client.Router(r))
|
opt(&ropts)
|
||||||
}
|
}
|
||||||
|
all := false
|
||||||
|
if len(opts) == 0 {
|
||||||
|
all = true
|
||||||
|
}
|
||||||
|
for _, cli := range o.Clients {
|
||||||
|
for _, os := range ropts.clients {
|
||||||
|
if cli.Name() == os || all {
|
||||||
|
if err = cli.Init(client.Router(r)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type routerOptions struct {
|
||||||
|
clients []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type RouterOption func(*routerOptions)
|
||||||
|
|
||||||
|
func RouterClient(n string) RouterOption {
|
||||||
|
return func(o *routerOptions) {
|
||||||
|
o.clients = append(o.clients, n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Address sets the address of the server
|
// Address sets the address of the server
|
||||||
func Address(addr string) Option {
|
func Address(addr string) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) error {
|
||||||
if o.Server != nil {
|
switch len(o.Servers) {
|
||||||
o.Server.Init(server.Address(addr))
|
case 0:
|
||||||
|
return fmt.Errorf("cant set address on nil server")
|
||||||
|
case 1:
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("cant set same address for multiple servers")
|
||||||
}
|
}
|
||||||
|
return o.Servers[0].Init(server.Address(addr))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name of the service
|
// Name of the service
|
||||||
func Name(n string) Option {
|
func Name(n string) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) error {
|
||||||
if o.Server != nil {
|
o.Name = n
|
||||||
o.Server.Init(server.Name(n))
|
return nil
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Version of the service
|
// Version of the service
|
||||||
func Version(v string) Option {
|
func Version(v string) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) error {
|
||||||
if o.Server != nil {
|
o.Version = v
|
||||||
o.Server.Init(server.Version(v))
|
return nil
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Metadata associated with the service
|
// Metadata associated with the service
|
||||||
func Metadata(md metadata.Metadata) Option {
|
func Metadata(md metadata.Metadata) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) error {
|
||||||
if o.Server != nil {
|
o.Metadata = metadata.Copy(md)
|
||||||
o.Server.Init(server.Metadata(md))
|
return nil
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterTTL specifies the TTL to use when registering the service
|
// RegisterTTL specifies the TTL to use when registering the service
|
||||||
func RegisterTTL(t time.Duration) Option {
|
func RegisterTTL(td time.Duration, opts ...RegisterOption) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) error {
|
||||||
if o.Server != nil {
|
var err error
|
||||||
o.Server.Init(server.RegisterTTL(t))
|
ropts := registerOptions{}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&ropts)
|
||||||
}
|
}
|
||||||
|
all := false
|
||||||
|
if len(opts) == 0 {
|
||||||
|
all = true
|
||||||
|
}
|
||||||
|
for _, srv := range o.Servers {
|
||||||
|
for _, os := range ropts.servers {
|
||||||
|
if srv.Name() == os || all {
|
||||||
|
if err = srv.Init(server.RegisterTTL(td)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterInterval specifies the interval on which to re-register
|
// RegisterInterval specifies the interval on which to re-register
|
||||||
func RegisterInterval(t time.Duration) Option {
|
func RegisterInterval(td time.Duration, opts ...RegisterOption) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) error {
|
||||||
if o.Server != nil {
|
var err error
|
||||||
o.Server.Init(server.RegisterInterval(t))
|
ropts := registerOptions{}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&ropts)
|
||||||
}
|
}
|
||||||
}
|
all := false
|
||||||
}
|
if len(opts) == 0 {
|
||||||
|
all = true
|
||||||
// WrapClient is a convenience method for wrapping a Client with
|
|
||||||
// some middleware component. A list of wrappers can be provided.
|
|
||||||
// Wrappers are applied in reverse order so the last is executed first.
|
|
||||||
func WrapClient(w ...client.Wrapper) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
// apply in reverse
|
|
||||||
for i := len(w); i > 0; i-- {
|
|
||||||
o.Client = w[i-1](o.Client)
|
|
||||||
}
|
}
|
||||||
}
|
for _, srv := range o.Servers {
|
||||||
}
|
for _, os := range ropts.servers {
|
||||||
|
if srv.Name() == os || all {
|
||||||
// WrapCall is a convenience method for wrapping a Client CallFunc
|
if err = srv.Init(server.RegisterInterval(td)); err != nil {
|
||||||
func WrapCall(w ...client.CallWrapper) Option {
|
return err
|
||||||
return func(o *Options) {
|
}
|
||||||
o.Client.Init(client.WrapCall(w...))
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// WrapHandler adds a handler Wrapper to a list of options passed into the server
|
|
||||||
func WrapHandler(w ...server.HandlerWrapper) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
var wrappers []server.Option
|
|
||||||
|
|
||||||
for _, wrap := range w {
|
|
||||||
wrappers = append(wrappers, server.WrapHandler(wrap))
|
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
// Init once
|
|
||||||
o.Server.Init(wrappers...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WrapSubscriber adds a subscriber Wrapper to a list of options passed into the server
|
|
||||||
func WrapSubscriber(w ...server.SubscriberWrapper) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
var wrappers []server.Option
|
|
||||||
|
|
||||||
for _, wrap := range w {
|
|
||||||
wrappers = append(wrappers, server.WrapSubscriber(wrap))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init once
|
|
||||||
o.Server.Init(wrappers...)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// BeforeStart run funcs before service starts
|
// BeforeStart run funcs before service starts
|
||||||
func BeforeStart(fn func(context.Context) error) Option {
|
func BeforeStart(fn func(context.Context) error) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) error {
|
||||||
o.BeforeStart = append(o.BeforeStart, fn)
|
o.BeforeStart = append(o.BeforeStart, fn)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// BeforeStop run funcs before service stops
|
// BeforeStop run funcs before service stops
|
||||||
func BeforeStop(fn func(context.Context) error) Option {
|
func BeforeStop(fn func(context.Context) error) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) error {
|
||||||
o.BeforeStop = append(o.BeforeStop, fn)
|
o.BeforeStop = append(o.BeforeStop, fn)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AfterStart run funcs after service starts
|
// AfterStart run funcs after service starts
|
||||||
func AfterStart(fn func(context.Context) error) Option {
|
func AfterStart(fn func(context.Context) error) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) error {
|
||||||
o.AfterStart = append(o.AfterStart, fn)
|
o.AfterStart = append(o.AfterStart, fn)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AfterStop run funcs after service stops
|
// AfterStop run funcs after service stops
|
||||||
func AfterStop(fn func(context.Context) error) Option {
|
func AfterStop(fn func(context.Context) error) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) error {
|
||||||
o.AfterStop = append(o.AfterStop, fn)
|
o.AfterStop = append(o.AfterStop, fn)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -4,7 +4,9 @@ package proxy
|
|||||||
import (
|
import (
|
||||||
"github.com/unistack-org/micro/v3/client"
|
"github.com/unistack-org/micro/v3/client"
|
||||||
"github.com/unistack-org/micro/v3/logger"
|
"github.com/unistack-org/micro/v3/logger"
|
||||||
|
"github.com/unistack-org/micro/v3/meter"
|
||||||
"github.com/unistack-org/micro/v3/router"
|
"github.com/unistack-org/micro/v3/router"
|
||||||
|
"github.com/unistack-org/micro/v3/tracer"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Options for proxy
|
// Options for proxy
|
||||||
@@ -19,11 +21,29 @@ type Options struct {
|
|||||||
Links map[string]client.Client
|
Links map[string]client.Client
|
||||||
// Logger
|
// Logger
|
||||||
Logger logger.Logger
|
Logger logger.Logger
|
||||||
|
// Meter
|
||||||
|
Meter meter.Meter
|
||||||
|
// Tracer
|
||||||
|
Tracer tracer.Tracer
|
||||||
}
|
}
|
||||||
|
|
||||||
// Option func signature
|
// Option func signature
|
||||||
type Option func(o *Options)
|
type Option func(o *Options)
|
||||||
|
|
||||||
|
func NewOptions(opts ...Option) Options {
|
||||||
|
options := Options{
|
||||||
|
Logger: logger.DefaultLogger,
|
||||||
|
Meter: meter.DefaultMeter,
|
||||||
|
Tracer: tracer.DefaultTracer,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, o := range opts {
|
||||||
|
o(&options)
|
||||||
|
}
|
||||||
|
|
||||||
|
return options
|
||||||
|
}
|
||||||
|
|
||||||
// WithEndpoint sets a proxy endpoint
|
// WithEndpoint sets a proxy endpoint
|
||||||
func WithEndpoint(e string) Option {
|
func WithEndpoint(e string) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
@@ -52,6 +72,13 @@ func WithLogger(l logger.Logger) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithMeter specifies the meter to use
|
||||||
|
func WithMeter(m meter.Meter) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Meter = m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// WithLink sets a link for outbound requests
|
// WithLink sets a link for outbound requests
|
||||||
func WithLink(name string, c client.Client) Option {
|
func WithLink(name string, c client.Client) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
@@ -61,3 +88,10 @@ func WithLink(name string, c client.Client) Option {
|
|||||||
o.Links[name] = c
|
o.Links[name] = c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tracer to be used for tracing
|
||||||
|
func Tracer(t tracer.Tracer) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Tracer = t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -1,26 +1,26 @@
|
|||||||
package registry
|
package register
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
)
|
)
|
||||||
|
|
||||||
type registryKey struct{}
|
type registerKey struct{}
|
||||||
|
|
||||||
// FromContext get registry from context
|
// FromContext get register from context
|
||||||
func FromContext(ctx context.Context) (Registry, bool) {
|
func FromContext(ctx context.Context) (Register, bool) {
|
||||||
if ctx == nil {
|
if ctx == nil {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
c, ok := ctx.Value(registryKey{}).(Registry)
|
c, ok := ctx.Value(registerKey{}).(Register)
|
||||||
return c, ok
|
return c, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewContext put registry in context
|
// NewContext put register in context
|
||||||
func NewContext(ctx context.Context, c Registry) context.Context {
|
func NewContext(ctx context.Context, c Register) context.Context {
|
||||||
if ctx == nil {
|
if ctx == nil {
|
||||||
ctx = context.Background()
|
ctx = context.Background()
|
||||||
}
|
}
|
||||||
return context.WithValue(ctx, registryKey{}, c)
|
return context.WithValue(ctx, registerKey{}, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetOption returns a function to setup a context with given value
|
// SetOption returns a function to setup a context with given value
|
@@ -1,4 +1,4 @@
|
|||||||
package registry
|
package register
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
@@ -1,4 +1,4 @@
|
|||||||
package registry
|
package register
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
85
register/noop.go
Normal file
85
register/noop.go
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
package register
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
type noopRegister struct {
|
||||||
|
opts Options
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *noopRegister) Name() string {
|
||||||
|
return n.opts.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init initialize register
|
||||||
|
func (n *noopRegister) Init(opts ...Option) error {
|
||||||
|
for _, o := range opts {
|
||||||
|
o(&n.opts)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Options returns options struct
|
||||||
|
func (n *noopRegister) Options() Options {
|
||||||
|
return n.opts
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect opens connection to register
|
||||||
|
func (n *noopRegister) Connect(ctx context.Context) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disconnect close connection to register
|
||||||
|
func (n *noopRegister) Disconnect(ctx context.Context) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register registers service
|
||||||
|
func (n *noopRegister) Register(ctx context.Context, svc *Service, opts ...RegisterOption) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deregister deregisters service
|
||||||
|
func (n *noopRegister) Deregister(ctx context.Context, svc *Service, opts ...DeregisterOption) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LookupService returns servive info
|
||||||
|
func (n *noopRegister) LookupService(ctx context.Context, name string, opts ...LookupOption) ([]*Service, error) {
|
||||||
|
return []*Service{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListServices listing services
|
||||||
|
func (n *noopRegister) ListServices(ctx context.Context, opts ...ListOption) ([]*Service, error) {
|
||||||
|
return []*Service{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Watch is used to watch for service changes
|
||||||
|
func (n *noopRegister) Watch(ctx context.Context, opts ...WatchOption) (Watcher, error) {
|
||||||
|
return &noopWatcher{done: make(chan struct{}), opts: NewWatchOptions(opts...)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns register string representation
|
||||||
|
func (n *noopRegister) String() string {
|
||||||
|
return "noop"
|
||||||
|
}
|
||||||
|
|
||||||
|
type noopWatcher struct {
|
||||||
|
opts WatchOptions
|
||||||
|
done chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *noopWatcher) Next() (*Result, error) {
|
||||||
|
<-n.done
|
||||||
|
return nil, ErrWatcherStopped
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *noopWatcher) Stop() {
|
||||||
|
close(n.done)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRegister returns a new noop register
|
||||||
|
func NewRegister(opts ...Option) Register {
|
||||||
|
return &noopRegister{opts: NewOptions(opts...)}
|
||||||
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
package registry
|
package register
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@@ -6,16 +6,22 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/unistack-org/micro/v3/logger"
|
"github.com/unistack-org/micro/v3/logger"
|
||||||
|
"github.com/unistack-org/micro/v3/meter"
|
||||||
|
"github.com/unistack-org/micro/v3/tracer"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Options struct {
|
type Options struct {
|
||||||
|
Name string
|
||||||
Addrs []string
|
Addrs []string
|
||||||
Timeout time.Duration
|
Timeout time.Duration
|
||||||
Secure bool
|
|
||||||
TLSConfig *tls.Config
|
TLSConfig *tls.Config
|
||||||
|
|
||||||
// Logger imp
|
// Logger that will be used
|
||||||
Logger logger.Logger
|
Logger logger.Logger
|
||||||
|
// Meter that will be used
|
||||||
|
Meter meter.Meter
|
||||||
|
// Tracer
|
||||||
|
Tracer tracer.Tracer
|
||||||
// Other options for implementations of the interface
|
// Other options for implementations of the interface
|
||||||
// can be stored in a context
|
// can be stored in a context
|
||||||
Context context.Context
|
Context context.Context
|
||||||
@@ -24,6 +30,8 @@ type Options struct {
|
|||||||
func NewOptions(opts ...Option) Options {
|
func NewOptions(opts ...Option) Options {
|
||||||
options := Options{
|
options := Options{
|
||||||
Logger: logger.DefaultLogger,
|
Logger: logger.DefaultLogger,
|
||||||
|
Meter: meter.DefaultMeter,
|
||||||
|
Tracer: tracer.DefaultTracer,
|
||||||
Context: context.Background(),
|
Context: context.Background(),
|
||||||
}
|
}
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
@@ -95,14 +103,14 @@ func NewDeregisterOptions(opts ...DeregisterOption) DeregisterOptions {
|
|||||||
return options
|
return options
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetOptions struct {
|
type LookupOptions struct {
|
||||||
Context context.Context
|
Context context.Context
|
||||||
// Domain to scope the request to
|
// Domain to scope the request to
|
||||||
Domain string
|
Domain string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGetOptions(opts ...GetOption) GetOptions {
|
func NewLookupOptions(opts ...LookupOption) LookupOptions {
|
||||||
options := GetOptions{
|
options := LookupOptions{
|
||||||
Domain: DefaultDomain,
|
Domain: DefaultDomain,
|
||||||
Context: context.Background(),
|
Context: context.Background(),
|
||||||
}
|
}
|
||||||
@@ -129,7 +137,7 @@ func NewListOptions(opts ...ListOption) ListOptions {
|
|||||||
return options
|
return options
|
||||||
}
|
}
|
||||||
|
|
||||||
// Addrs is the registry addresses to use
|
// Addrs is the register addresses to use
|
||||||
func Addrs(addrs ...string) Option {
|
func Addrs(addrs ...string) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
o.Addrs = addrs
|
o.Addrs = addrs
|
||||||
@@ -142,13 +150,6 @@ func Timeout(t time.Duration) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Secure communication with the registry
|
|
||||||
func Secure(b bool) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.Secure = b
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Logger sets the logger
|
// Logger sets the logger
|
||||||
func Logger(l logger.Logger) Option {
|
func Logger(l logger.Logger) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
@@ -156,6 +157,20 @@ func Logger(l logger.Logger) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Meter sets the meter
|
||||||
|
func Meter(m meter.Meter) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Meter = m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tracer sets the tracer
|
||||||
|
func Tracer(t tracer.Tracer) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Tracer = t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Context sets the context
|
// Context sets the context
|
||||||
func Context(ctx context.Context) Option {
|
func Context(ctx context.Context) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
@@ -231,14 +246,14 @@ func DeregisterDomain(d string) DeregisterOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetContext(ctx context.Context) GetOption {
|
func LookupContext(ctx context.Context) LookupOption {
|
||||||
return func(o *GetOptions) {
|
return func(o *LookupOptions) {
|
||||||
o.Context = ctx
|
o.Context = ctx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetDomain(d string) GetOption {
|
func LookupDomain(d string) LookupOption {
|
||||||
return func(o *GetOptions) {
|
return func(o *LookupOptions) {
|
||||||
o.Domain = d
|
o.Domain = d
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -254,3 +269,10 @@ func ListDomain(d string) ListOption {
|
|||||||
o.Domain = d
|
o.Domain = d
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Name sets the name
|
||||||
|
func Name(n string) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Name = n
|
||||||
|
}
|
||||||
|
}
|
@@ -1,5 +1,5 @@
|
|||||||
// Package registry is an interface for service discovery
|
// Package register is an interface for service discovery
|
||||||
package registry
|
package register
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@@ -16,31 +16,32 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// DefaultRegistry is the global default registry
|
// DefaultRegister is the global default register
|
||||||
DefaultRegistry Registry = NewRegistry()
|
DefaultRegister Register = NewRegister()
|
||||||
// ErrNotFound returned when GetService is called and no services found
|
// ErrNotFound returned when LookupService is called and no services found
|
||||||
ErrNotFound = errors.New("service not found")
|
ErrNotFound = errors.New("service not found")
|
||||||
// ErrWatcherStopped returned when when watcher is stopped
|
// ErrWatcherStopped returned when when watcher is stopped
|
||||||
ErrWatcherStopped = errors.New("watcher stopped")
|
ErrWatcherStopped = errors.New("watcher stopped")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Registry provides an interface for service discovery
|
// Register provides an interface for service discovery
|
||||||
// and an abstraction over varying implementations
|
// and an abstraction over varying implementations
|
||||||
// {consul, etcd, zookeeper, ...}
|
// {consul, etcd, zookeeper, ...}
|
||||||
type Registry interface {
|
type Register interface {
|
||||||
|
Name() string
|
||||||
Init(...Option) error
|
Init(...Option) error
|
||||||
Options() Options
|
Options() Options
|
||||||
Connect(context.Context) error
|
Connect(context.Context) error
|
||||||
Disconnect(context.Context) error
|
Disconnect(context.Context) error
|
||||||
Register(context.Context, *Service, ...RegisterOption) error
|
Register(context.Context, *Service, ...RegisterOption) error
|
||||||
Deregister(context.Context, *Service, ...DeregisterOption) error
|
Deregister(context.Context, *Service, ...DeregisterOption) error
|
||||||
GetService(context.Context, string, ...GetOption) ([]*Service, error)
|
LookupService(context.Context, string, ...LookupOption) ([]*Service, error)
|
||||||
ListServices(context.Context, ...ListOption) ([]*Service, error)
|
ListServices(context.Context, ...ListOption) ([]*Service, error)
|
||||||
Watch(context.Context, ...WatchOption) (Watcher, error)
|
Watch(context.Context, ...WatchOption) (Watcher, error)
|
||||||
String() string
|
String() string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Service holds service registry info
|
// Service holds service register info
|
||||||
type Service struct {
|
type Service struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
@@ -49,14 +50,14 @@ type Service struct {
|
|||||||
Nodes []*Node `json:"nodes"`
|
Nodes []*Node `json:"nodes"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Node holds node registry info
|
// Node holds node register info
|
||||||
type Node struct {
|
type Node struct {
|
||||||
Id string `json:"id"`
|
Id string `json:"id"`
|
||||||
Address string `json:"address"`
|
Address string `json:"address"`
|
||||||
Metadata metadata.Metadata `json:"metadata"`
|
Metadata metadata.Metadata `json:"metadata"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Endpoint holds endpoint registry info
|
// Endpoint holds endpoint register info
|
||||||
type Endpoint struct {
|
type Endpoint struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Request *Value `json:"request"`
|
Request *Value `json:"request"`
|
||||||
@@ -83,8 +84,8 @@ type WatchOption func(*WatchOptions)
|
|||||||
// DeregisterOption option is used to deregister service
|
// DeregisterOption option is used to deregister service
|
||||||
type DeregisterOption func(*DeregisterOptions)
|
type DeregisterOption func(*DeregisterOptions)
|
||||||
|
|
||||||
// GetOption option is used to get service
|
// LookupOption option is used to get service
|
||||||
type GetOption func(*GetOptions)
|
type LookupOption func(*LookupOptions)
|
||||||
|
|
||||||
// ListOption option is used to list services
|
// ListOption option is used to list services
|
||||||
type ListOption func(*ListOptions)
|
type ListOption func(*ListOptions)
|
@@ -1,9 +1,9 @@
|
|||||||
package registry
|
package register
|
||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
// Watcher is an interface that returns updates
|
// Watcher is an interface that returns updates
|
||||||
// about services within the registry.
|
// about services within the register.
|
||||||
type Watcher interface {
|
type Watcher interface {
|
||||||
// Next is a blocking call
|
// Next is a blocking call
|
||||||
Next() (*Result, error)
|
Next() (*Result, error)
|
||||||
@@ -17,7 +17,7 @@ type Result struct {
|
|||||||
Service *Service
|
Service *Service
|
||||||
}
|
}
|
||||||
|
|
||||||
// EventType defines registry event type
|
// EventType defines register event type
|
||||||
type EventType int
|
type EventType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -43,14 +43,14 @@ func (t EventType) String() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Event is registry event
|
// Event is register event
|
||||||
type Event struct {
|
type Event struct {
|
||||||
// Id is registry id
|
// Id is register id
|
||||||
Id string
|
Id string
|
||||||
// Type defines type of event
|
// Type defines type of event
|
||||||
Type EventType
|
Type EventType
|
||||||
// Timestamp is event timestamp
|
// Timestamp is event timestamp
|
||||||
Timestamp time.Time
|
Timestamp time.Time
|
||||||
// Service is registry service
|
// Service is register service
|
||||||
Service *Service
|
Service *Service
|
||||||
}
|
}
|
@@ -1,81 +0,0 @@
|
|||||||
package registry
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
)
|
|
||||||
|
|
||||||
type noopRegistry struct {
|
|
||||||
opts Options
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init initialize registry
|
|
||||||
func (n *noopRegistry) Init(opts ...Option) error {
|
|
||||||
for _, o := range opts {
|
|
||||||
o(&n.opts)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Options returns options struct
|
|
||||||
func (n *noopRegistry) Options() Options {
|
|
||||||
return n.opts
|
|
||||||
}
|
|
||||||
|
|
||||||
// Connect opens connection to registry
|
|
||||||
func (n *noopRegistry) Connect(ctx context.Context) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disconnect close connection to registry
|
|
||||||
func (n *noopRegistry) Disconnect(ctx context.Context) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register registers service
|
|
||||||
func (n *noopRegistry) Register(ctx context.Context, svc *Service, opts ...RegisterOption) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deregister deregisters service
|
|
||||||
func (n *noopRegistry) Deregister(ctx context.Context, svc *Service, opts ...DeregisterOption) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetService returns servive info
|
|
||||||
func (n *noopRegistry) GetService(ctx context.Context, name string, opts ...GetOption) ([]*Service, error) {
|
|
||||||
return []*Service{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListServices listing services
|
|
||||||
func (n *noopRegistry) ListServices(ctx context.Context, opts ...ListOption) ([]*Service, error) {
|
|
||||||
return []*Service{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Watch is used to watch for service changes
|
|
||||||
func (n *noopRegistry) Watch(ctx context.Context, opts ...WatchOption) (Watcher, error) {
|
|
||||||
return &noopWatcher{done: make(chan struct{}), opts: NewWatchOptions(opts...)}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns registry string representation
|
|
||||||
func (n *noopRegistry) String() string {
|
|
||||||
return "noop"
|
|
||||||
}
|
|
||||||
|
|
||||||
type noopWatcher struct {
|
|
||||||
opts WatchOptions
|
|
||||||
done chan struct{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *noopWatcher) Next() (*Result, error) {
|
|
||||||
<-n.done
|
|
||||||
return nil, ErrWatcherStopped
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *noopWatcher) Stop() {
|
|
||||||
close(n.done)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewRegistry returns a new noop registry
|
|
||||||
func NewRegistry(opts ...Option) Registry {
|
|
||||||
return &noopRegistry{opts: NewOptions(opts...)}
|
|
||||||
}
|
|
@@ -1,22 +1,22 @@
|
|||||||
// Package registry resolves names using the micro registry
|
// Package register resolves names using the micro register
|
||||||
package registry
|
package register
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/unistack-org/micro/v3/registry"
|
"github.com/unistack-org/micro/v3/register"
|
||||||
"github.com/unistack-org/micro/v3/resolver"
|
"github.com/unistack-org/micro/v3/resolver"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Resolver is a registry network resolver
|
// Resolver is a register network resolver
|
||||||
type Resolver struct {
|
type Resolver struct {
|
||||||
// Registry is the registry to use otherwise we use the defaul
|
// Register is the register to use otherwise we use the defaul
|
||||||
Registry registry.Registry
|
Register register.Register
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve assumes ID is a domain name e.g micro.mu
|
// Resolve assumes ID is a domain name e.g micro.mu
|
||||||
func (r *Resolver) Resolve(name string) ([]*resolver.Record, error) {
|
func (r *Resolver) Resolve(name string) ([]*resolver.Record, error) {
|
||||||
services, err := r.Registry.GetService(context.TODO(), name)
|
services, err := r.Register.LookupService(context.TODO(), name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@@ -5,11 +5,12 @@ import (
|
|||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/unistack-org/micro/v3/logger"
|
"github.com/unistack-org/micro/v3/logger"
|
||||||
"github.com/unistack-org/micro/v3/registry"
|
"github.com/unistack-org/micro/v3/register"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Options are router options
|
// Options are router options
|
||||||
type Options struct {
|
type Options struct {
|
||||||
|
Name string
|
||||||
// Id is router id
|
// Id is router id
|
||||||
Id string
|
Id string
|
||||||
// Address is router address
|
// Address is router address
|
||||||
@@ -18,8 +19,8 @@ type Options struct {
|
|||||||
Gateway string
|
Gateway string
|
||||||
// Network is network address
|
// Network is network address
|
||||||
Network string
|
Network string
|
||||||
// Registry is the local registry
|
// Register is the local register
|
||||||
Registry registry.Registry
|
Register register.Register
|
||||||
// Precache routes
|
// Precache routes
|
||||||
Precache bool
|
Precache bool
|
||||||
// Logger
|
// Logger
|
||||||
@@ -63,10 +64,10 @@ func Logger(l logger.Logger) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Registry sets the local registry
|
// Register sets the local register
|
||||||
func Registry(r registry.Registry) Option {
|
func Register(r register.Register) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
o.Registry = r
|
o.Register = r
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,12 +78,19 @@ func Precache() Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Name of the router
|
||||||
|
func Name(n string) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Name = n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NewOptions returns router default options
|
// NewOptions returns router default options
|
||||||
func NewOptions(opts ...Option) Options {
|
func NewOptions(opts ...Option) Options {
|
||||||
options := Options{
|
options := Options{
|
||||||
Id: uuid.New().String(),
|
Id: uuid.New().String(),
|
||||||
Network: DefaultNetwork,
|
Network: DefaultNetwork,
|
||||||
Registry: registry.DefaultRegistry,
|
Register: register.DefaultRegister,
|
||||||
Logger: logger.DefaultLogger,
|
Logger: logger.DefaultLogger,
|
||||||
Context: context.Background(),
|
Context: context.Background(),
|
||||||
}
|
}
|
||||||
|
@@ -18,6 +18,7 @@ var (
|
|||||||
|
|
||||||
// Router is an interface for a routing control plane
|
// Router is an interface for a routing control plane
|
||||||
type Router interface {
|
type Router interface {
|
||||||
|
Name() string
|
||||||
// Init initializes the router with options
|
// Init initializes the router with options
|
||||||
Init(...Option) error
|
Init(...Option) error
|
||||||
// Options returns the router options
|
// Options returns the router options
|
||||||
|
@@ -3,13 +3,13 @@ package server
|
|||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/unistack-org/micro/v3/registry"
|
"github.com/unistack-org/micro/v3/register"
|
||||||
)
|
)
|
||||||
|
|
||||||
type rpcHandler struct {
|
type rpcHandler struct {
|
||||||
name string
|
name string
|
||||||
handler interface{}
|
handler interface{}
|
||||||
endpoints []*registry.Endpoint
|
endpoints []*register.Endpoint
|
||||||
opts HandlerOptions
|
opts HandlerOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,10 +20,10 @@ func newRpcHandler(handler interface{}, opts ...HandlerOption) Handler {
|
|||||||
hdlr := reflect.ValueOf(handler)
|
hdlr := reflect.ValueOf(handler)
|
||||||
name := reflect.Indirect(hdlr).Type().Name()
|
name := reflect.Indirect(hdlr).Type().Name()
|
||||||
|
|
||||||
var endpoints []*registry.Endpoint
|
var endpoints []*register.Endpoint
|
||||||
|
|
||||||
for m := 0; m < typ.NumMethod(); m++ {
|
for m := 0; m < typ.NumMethod(); m++ {
|
||||||
if e := registry.ExtractEndpoint(typ.Method(m)); e != nil {
|
if e := register.ExtractEndpoint(typ.Method(m)); e != nil {
|
||||||
e.Name = name + "." + e.Name
|
e.Name = name + "." + e.Name
|
||||||
|
|
||||||
for k, v := range options.Metadata[e.Name] {
|
for k, v := range options.Metadata[e.Name] {
|
||||||
@@ -50,7 +50,7 @@ func (r *rpcHandler) Handler() interface{} {
|
|||||||
return r.handler
|
return r.handler
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *rpcHandler) Endpoints() []*registry.Endpoint {
|
func (r *rpcHandler) Endpoints() []*register.Endpoint {
|
||||||
return r.endpoints
|
return r.endpoints
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -13,7 +13,7 @@ import (
|
|||||||
"github.com/unistack-org/micro/v3/broker"
|
"github.com/unistack-org/micro/v3/broker"
|
||||||
"github.com/unistack-org/micro/v3/codec"
|
"github.com/unistack-org/micro/v3/codec"
|
||||||
"github.com/unistack-org/micro/v3/logger"
|
"github.com/unistack-org/micro/v3/logger"
|
||||||
"github.com/unistack-org/micro/v3/registry"
|
"github.com/unistack-org/micro/v3/register"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -34,7 +34,7 @@ const (
|
|||||||
type noopServer struct {
|
type noopServer struct {
|
||||||
h Handler
|
h Handler
|
||||||
opts Options
|
opts Options
|
||||||
rsvc *registry.Service
|
rsvc *register.Service
|
||||||
handlers map[string]Handler
|
handlers map[string]Handler
|
||||||
subscribers map[*subscriber][]broker.Subscriber
|
subscribers map[*subscriber][]broker.Subscriber
|
||||||
registered bool
|
registered bool
|
||||||
@@ -64,6 +64,10 @@ func (n *noopServer) Handle(handler Handler) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *noopServer) Name() string {
|
||||||
|
return n.opts.Name
|
||||||
|
}
|
||||||
|
|
||||||
func (n *noopServer) Subscribe(sb Subscriber) error {
|
func (n *noopServer) Subscribe(sb Subscriber) error {
|
||||||
sub, ok := sb.(*subscriber)
|
sub, ok := sb.(*subscriber)
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -137,10 +141,10 @@ func (n *noopServer) Register() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
var service *registry.Service
|
var service *register.Service
|
||||||
var cacheService bool
|
var cacheService bool
|
||||||
|
|
||||||
service, err = NewRegistryService(n)
|
service, err = NewRegisterService(n)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -168,7 +172,7 @@ func (n *noopServer) Register() error {
|
|||||||
return subscriberList[i].topic > subscriberList[j].topic
|
return subscriberList[i].topic > subscriberList[j].topic
|
||||||
})
|
})
|
||||||
|
|
||||||
endpoints := make([]*registry.Endpoint, 0, len(handlerList)+len(subscriberList))
|
endpoints := make([]*register.Endpoint, 0, len(handlerList)+len(subscriberList))
|
||||||
for _, h := range handlerList {
|
for _, h := range handlerList {
|
||||||
endpoints = append(endpoints, n.handlers[h].Endpoints()...)
|
endpoints = append(endpoints, n.handlers[h].Endpoints()...)
|
||||||
}
|
}
|
||||||
@@ -187,7 +191,7 @@ func (n *noopServer) Register() error {
|
|||||||
|
|
||||||
if !registered {
|
if !registered {
|
||||||
if config.Logger.V(logger.InfoLevel) {
|
if config.Logger.V(logger.InfoLevel) {
|
||||||
config.Logger.Infof(n.opts.Context, "registry [%s] Registering node: %s", config.Registry.String(), service.Nodes[0].Id)
|
config.Logger.Infof(n.opts.Context, "register [%s] Registering node: %s", config.Register.String(), service.Nodes[0].Id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,7 +248,7 @@ func (n *noopServer) Deregister() error {
|
|||||||
config := n.opts
|
config := n.opts
|
||||||
n.RUnlock()
|
n.RUnlock()
|
||||||
|
|
||||||
service, err := NewRegistryService(n)
|
service, err := NewRegisterService(n)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@@ -12,8 +12,9 @@ import (
|
|||||||
"github.com/unistack-org/micro/v3/codec"
|
"github.com/unistack-org/micro/v3/codec"
|
||||||
"github.com/unistack-org/micro/v3/logger"
|
"github.com/unistack-org/micro/v3/logger"
|
||||||
"github.com/unistack-org/micro/v3/metadata"
|
"github.com/unistack-org/micro/v3/metadata"
|
||||||
|
"github.com/unistack-org/micro/v3/meter"
|
||||||
"github.com/unistack-org/micro/v3/network/transport"
|
"github.com/unistack-org/micro/v3/network/transport"
|
||||||
"github.com/unistack-org/micro/v3/registry"
|
"github.com/unistack-org/micro/v3/register"
|
||||||
"github.com/unistack-org/micro/v3/tracer"
|
"github.com/unistack-org/micro/v3/tracer"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -24,10 +25,11 @@ type Option func(*Options)
|
|||||||
type Options struct {
|
type Options struct {
|
||||||
Codecs map[string]codec.Codec
|
Codecs map[string]codec.Codec
|
||||||
Broker broker.Broker
|
Broker broker.Broker
|
||||||
Registry registry.Registry
|
Register register.Register
|
||||||
Tracer tracer.Tracer
|
Tracer tracer.Tracer
|
||||||
Auth auth.Auth
|
Auth auth.Auth
|
||||||
Logger logger.Logger
|
Logger logger.Logger
|
||||||
|
Meter meter.Meter
|
||||||
Transport transport.Transport
|
Transport transport.Transport
|
||||||
Metadata metadata.Metadata
|
Metadata metadata.Metadata
|
||||||
Name string
|
Name string
|
||||||
@@ -78,9 +80,10 @@ func NewOptions(opts ...Option) Options {
|
|||||||
RegisterTTL: DefaultRegisterTTL,
|
RegisterTTL: DefaultRegisterTTL,
|
||||||
RegisterCheck: DefaultRegisterCheck,
|
RegisterCheck: DefaultRegisterCheck,
|
||||||
Logger: logger.DefaultLogger,
|
Logger: logger.DefaultLogger,
|
||||||
|
Meter: meter.DefaultMeter,
|
||||||
Tracer: tracer.DefaultTracer,
|
Tracer: tracer.DefaultTracer,
|
||||||
Broker: broker.DefaultBroker,
|
Broker: broker.DefaultBroker,
|
||||||
Registry: registry.DefaultRegistry,
|
Register: register.DefaultRegister,
|
||||||
Transport: transport.DefaultTransport,
|
Transport: transport.DefaultTransport,
|
||||||
Address: DefaultAddress,
|
Address: DefaultAddress,
|
||||||
Name: DefaultName,
|
Name: DefaultName,
|
||||||
@@ -117,6 +120,13 @@ func Logger(l logger.Logger) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Meter sets the meter option
|
||||||
|
func Meter(m meter.Meter) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Meter = m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Id unique server id
|
// Id unique server id
|
||||||
func Id(id string) Option {
|
func Id(id string) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
@@ -168,10 +178,10 @@ func Context(ctx context.Context) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Registry used for discovery
|
// Register used for discovery
|
||||||
func Registry(r registry.Registry) Option {
|
func Register(r register.Register) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
o.Registry = r
|
o.Register = r
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,7 +213,7 @@ func Metadata(md metadata.Metadata) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterCheck run func before registry service
|
// RegisterCheck run func before register service
|
||||||
func RegisterCheck(fn func(context.Context) error) Option {
|
func RegisterCheck(fn func(context.Context) error) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
o.RegisterCheck = fn
|
o.RegisterCheck = fn
|
||||||
@@ -235,7 +245,6 @@ func TLSConfig(t *tls.Config) Option {
|
|||||||
|
|
||||||
// set the transport tls
|
// set the transport tls
|
||||||
o.Transport.Init(
|
o.Transport.Init(
|
||||||
transport.Secure(true),
|
|
||||||
transport.TLSConfig(t),
|
transport.TLSConfig(t),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@@ -5,23 +5,23 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/unistack-org/micro/v3/metadata"
|
"github.com/unistack-org/micro/v3/metadata"
|
||||||
"github.com/unistack-org/micro/v3/registry"
|
"github.com/unistack-org/micro/v3/register"
|
||||||
"github.com/unistack-org/micro/v3/util/addr"
|
"github.com/unistack-org/micro/v3/util/addr"
|
||||||
"github.com/unistack-org/micro/v3/util/backoff"
|
"github.com/unistack-org/micro/v3/util/backoff"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// DefaultRegisterFunc uses backoff to register service
|
// DefaultRegisterFunc uses backoff to register service
|
||||||
DefaultRegisterFunc = func(svc *registry.Service, config Options) error {
|
DefaultRegisterFunc = func(svc *register.Service, config Options) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
opts := []registry.RegisterOption{
|
opts := []register.RegisterOption{
|
||||||
registry.RegisterTTL(config.RegisterTTL),
|
register.RegisterTTL(config.RegisterTTL),
|
||||||
registry.RegisterDomain(config.Namespace),
|
register.RegisterDomain(config.Namespace),
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i <= config.RegisterAttempts; i++ {
|
for i := 0; i <= config.RegisterAttempts; i++ {
|
||||||
err = config.Registry.Register(config.Context, svc, opts...)
|
err = config.Register.Register(config.Context, svc, opts...)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -32,15 +32,15 @@ var (
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// DefaultDeregisterFunc uses backoff to deregister service
|
// DefaultDeregisterFunc uses backoff to deregister service
|
||||||
DefaultDeregisterFunc = func(svc *registry.Service, config Options) error {
|
DefaultDeregisterFunc = func(svc *register.Service, config Options) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
opts := []registry.DeregisterOption{
|
opts := []register.DeregisterOption{
|
||||||
registry.DeregisterDomain(config.Namespace),
|
register.DeregisterDomain(config.Namespace),
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i <= config.DeregisterAttempts; i++ {
|
for i := 0; i <= config.DeregisterAttempts; i++ {
|
||||||
err = config.Registry.Deregister(config.Context, svc, opts...)
|
err = config.Register.Deregister(config.Context, svc, opts...)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -52,8 +52,8 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewRegistryService returns *registry.Service from Server
|
// NewRegisterService returns *register.Service from Server
|
||||||
func NewRegistryService(s Server) (*registry.Service, error) {
|
func NewRegisterService(s Server) (*register.Service, error) {
|
||||||
opts := s.Options()
|
opts := s.Options()
|
||||||
|
|
||||||
advt := opts.Address
|
advt := opts.Address
|
||||||
@@ -71,7 +71,7 @@ func NewRegistryService(s Server) (*registry.Service, error) {
|
|||||||
addr = host
|
addr = host
|
||||||
}
|
}
|
||||||
|
|
||||||
node := ®istry.Node{
|
node := ®ister.Node{
|
||||||
Id: opts.Name + "-" + opts.Id,
|
Id: opts.Name + "-" + opts.Id,
|
||||||
Address: net.JoinHostPort(addr, port),
|
Address: net.JoinHostPort(addr, port),
|
||||||
}
|
}
|
||||||
@@ -79,12 +79,12 @@ func NewRegistryService(s Server) (*registry.Service, error) {
|
|||||||
|
|
||||||
node.Metadata["server"] = s.String()
|
node.Metadata["server"] = s.String()
|
||||||
node.Metadata["broker"] = opts.Broker.String()
|
node.Metadata["broker"] = opts.Broker.String()
|
||||||
node.Metadata["registry"] = opts.Registry.String()
|
node.Metadata["register"] = opts.Register.String()
|
||||||
|
|
||||||
return ®istry.Service{
|
return ®ister.Service{
|
||||||
Name: opts.Name,
|
Name: opts.Name,
|
||||||
Version: opts.Version,
|
Version: opts.Version,
|
||||||
Nodes: []*registry.Node{node},
|
Nodes: []*register.Node{node},
|
||||||
Metadata: metadata.New(0),
|
Metadata: metadata.New(0),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@@ -8,7 +8,7 @@ import (
|
|||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/unistack-org/micro/v3/codec"
|
"github.com/unistack-org/micro/v3/codec"
|
||||||
"github.com/unistack-org/micro/v3/metadata"
|
"github.com/unistack-org/micro/v3/metadata"
|
||||||
"github.com/unistack-org/micro/v3/registry"
|
"github.com/unistack-org/micro/v3/register"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -29,7 +29,7 @@ var (
|
|||||||
DefaultRegisterCheck = func(context.Context) error { return nil }
|
DefaultRegisterCheck = func(context.Context) error { return nil }
|
||||||
// DefaultRegisterInterval holds interval for register
|
// DefaultRegisterInterval holds interval for register
|
||||||
DefaultRegisterInterval = time.Second * 30
|
DefaultRegisterInterval = time.Second * 30
|
||||||
// DefaultRegisterTTL holds registry record ttl, must be multiple of DefaultRegisterInterval
|
// DefaultRegisterTTL holds register record ttl, must be multiple of DefaultRegisterInterval
|
||||||
DefaultRegisterTTL = time.Second * 90
|
DefaultRegisterTTL = time.Second * 90
|
||||||
// DefaultNamespace will be used if no namespace passed
|
// DefaultNamespace will be used if no namespace passed
|
||||||
DefaultNamespace = "micro"
|
DefaultNamespace = "micro"
|
||||||
@@ -43,6 +43,8 @@ var (
|
|||||||
|
|
||||||
// Server is a simple micro server abstraction
|
// Server is a simple micro server abstraction
|
||||||
type Server interface {
|
type Server interface {
|
||||||
|
// Name returns server name
|
||||||
|
Name() string
|
||||||
// Initialise options
|
// Initialise options
|
||||||
Init(...Option) error
|
Init(...Option) error
|
||||||
// Retrieve the options
|
// Retrieve the options
|
||||||
@@ -147,7 +149,7 @@ type Stream interface {
|
|||||||
type Handler interface {
|
type Handler interface {
|
||||||
Name() string
|
Name() string
|
||||||
Handler() interface{}
|
Handler() interface{}
|
||||||
Endpoints() []*registry.Endpoint
|
Endpoints() []*register.Endpoint
|
||||||
Options() HandlerOptions
|
Options() HandlerOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,6 +159,6 @@ type Handler interface {
|
|||||||
type Subscriber interface {
|
type Subscriber interface {
|
||||||
Topic() string
|
Topic() string
|
||||||
Subscriber() interface{}
|
Subscriber() interface{}
|
||||||
Endpoints() []*registry.Endpoint
|
Endpoints() []*register.Endpoint
|
||||||
Options() SubscriberOptions
|
Options() SubscriberOptions
|
||||||
}
|
}
|
||||||
|
@@ -14,7 +14,7 @@ import (
|
|||||||
"github.com/unistack-org/micro/v3/errors"
|
"github.com/unistack-org/micro/v3/errors"
|
||||||
"github.com/unistack-org/micro/v3/logger"
|
"github.com/unistack-org/micro/v3/logger"
|
||||||
"github.com/unistack-org/micro/v3/metadata"
|
"github.com/unistack-org/micro/v3/metadata"
|
||||||
"github.com/unistack-org/micro/v3/registry"
|
"github.com/unistack-org/micro/v3/register"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -39,7 +39,7 @@ type subscriber struct {
|
|||||||
typ reflect.Type
|
typ reflect.Type
|
||||||
subscriber interface{}
|
subscriber interface{}
|
||||||
handlers []*handler
|
handlers []*handler
|
||||||
endpoints []*registry.Endpoint
|
endpoints []*register.Endpoint
|
||||||
opts SubscriberOptions
|
opts SubscriberOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ func ValidateSubscriber(sub Subscriber) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newSubscriber(topic string, sub interface{}, opts ...SubscriberOption) Subscriber {
|
func newSubscriber(topic string, sub interface{}, opts ...SubscriberOption) Subscriber {
|
||||||
var endpoints []*registry.Endpoint
|
var endpoints []*register.Endpoint
|
||||||
var handlers []*handler
|
var handlers []*handler
|
||||||
|
|
||||||
options := NewSubscriberOptions(opts...)
|
options := NewSubscriberOptions(opts...)
|
||||||
@@ -134,9 +134,9 @@ func newSubscriber(topic string, sub interface{}, opts ...SubscriberOption) Subs
|
|||||||
}
|
}
|
||||||
|
|
||||||
handlers = append(handlers, h)
|
handlers = append(handlers, h)
|
||||||
ep := ®istry.Endpoint{
|
ep := ®ister.Endpoint{
|
||||||
Name: "Func",
|
Name: "Func",
|
||||||
Request: registry.ExtractSubValue(typ),
|
Request: register.ExtractSubValue(typ),
|
||||||
Metadata: metadata.New(2),
|
Metadata: metadata.New(2),
|
||||||
}
|
}
|
||||||
ep.Metadata.Set("topic", topic)
|
ep.Metadata.Set("topic", topic)
|
||||||
@@ -161,9 +161,9 @@ func newSubscriber(topic string, sub interface{}, opts ...SubscriberOption) Subs
|
|||||||
}
|
}
|
||||||
|
|
||||||
handlers = append(handlers, h)
|
handlers = append(handlers, h)
|
||||||
ep := ®istry.Endpoint{
|
ep := ®ister.Endpoint{
|
||||||
Name: name + "." + method.Name,
|
Name: name + "." + method.Name,
|
||||||
Request: registry.ExtractSubValue(method.Type),
|
Request: register.ExtractSubValue(method.Type),
|
||||||
Metadata: metadata.New(2),
|
Metadata: metadata.New(2),
|
||||||
}
|
}
|
||||||
ep.Metadata.Set("topic", topic)
|
ep.Metadata.Set("topic", topic)
|
||||||
@@ -304,7 +304,7 @@ func (s *subscriber) Subscriber() interface{} {
|
|||||||
return s.subscriber
|
return s.subscriber
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *subscriber) Endpoints() []*registry.Endpoint {
|
func (s *subscriber) Endpoints() []*register.Endpoint {
|
||||||
return s.endpoints
|
return s.endpoints
|
||||||
}
|
}
|
||||||
|
|
||||||
|
278
service.go
278
service.go
@@ -1,8 +1,8 @@
|
|||||||
|
// Package micro is a pluggable framework for microservices
|
||||||
package micro
|
package micro
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
rtime "runtime"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/unistack-org/micro/v3/auth"
|
"github.com/unistack-org/micro/v3/auth"
|
||||||
@@ -10,31 +10,86 @@ import (
|
|||||||
"github.com/unistack-org/micro/v3/client"
|
"github.com/unistack-org/micro/v3/client"
|
||||||
"github.com/unistack-org/micro/v3/config"
|
"github.com/unistack-org/micro/v3/config"
|
||||||
"github.com/unistack-org/micro/v3/logger"
|
"github.com/unistack-org/micro/v3/logger"
|
||||||
"github.com/unistack-org/micro/v3/registry"
|
"github.com/unistack-org/micro/v3/meter"
|
||||||
|
"github.com/unistack-org/micro/v3/register"
|
||||||
"github.com/unistack-org/micro/v3/router"
|
"github.com/unistack-org/micro/v3/router"
|
||||||
"github.com/unistack-org/micro/v3/server"
|
"github.com/unistack-org/micro/v3/server"
|
||||||
"github.com/unistack-org/micro/v3/store"
|
"github.com/unistack-org/micro/v3/store"
|
||||||
|
"github.com/unistack-org/micro/v3/tracer"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Service is an interface that wraps the lower level components.
|
||||||
|
// Its works as container with building blocks for service.
|
||||||
|
type Service interface {
|
||||||
|
// The service name
|
||||||
|
Name() string
|
||||||
|
// Init initialises options
|
||||||
|
Init(...Option) error
|
||||||
|
// Options returns the current options
|
||||||
|
Options() Options
|
||||||
|
// Auth is for handling auth
|
||||||
|
Auth(...string) auth.Auth
|
||||||
|
// Logger is for logs
|
||||||
|
Logger(...string) logger.Logger
|
||||||
|
// Config if for config
|
||||||
|
Config(...string) config.Config
|
||||||
|
// Client is for calling services
|
||||||
|
Client(...string) client.Client
|
||||||
|
// Broker is for sending and receiving events
|
||||||
|
Broker(...string) broker.Broker
|
||||||
|
// Server is for handling requests and events
|
||||||
|
Server(...string) server.Server
|
||||||
|
// Store is for key/val store
|
||||||
|
Store(...string) store.Store
|
||||||
|
// Register
|
||||||
|
Register(...string) register.Register
|
||||||
|
// Tracer
|
||||||
|
Tracer(...string) tracer.Tracer
|
||||||
|
// Router
|
||||||
|
Router(...string) router.Router
|
||||||
|
// Meter
|
||||||
|
Meter(...string) meter.Meter
|
||||||
|
|
||||||
|
// Runtime
|
||||||
|
// Runtime(string) (runtime.Runtime, bool)
|
||||||
|
// Profile
|
||||||
|
// Profile(string) (profile.Profile, bool)
|
||||||
|
// Run the service
|
||||||
|
Run() error
|
||||||
|
// The service implementation
|
||||||
|
String() string
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterHandler is syntactic sugar for registering a handler
|
||||||
|
func RegisterHandler(s server.Server, h interface{}, opts ...server.HandlerOption) error {
|
||||||
|
return s.Handle(s.NewHandler(h, opts...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterSubscriber is syntactic sugar for registering a subscriber
|
||||||
|
func RegisterSubscriber(topic string, s server.Server, h interface{}, opts ...server.SubscriberOption) error {
|
||||||
|
return s.Subscribe(s.NewSubscriber(topic, h, opts...))
|
||||||
|
}
|
||||||
|
|
||||||
type service struct {
|
type service struct {
|
||||||
opts Options
|
opts Options
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
// once sync.Once
|
// once sync.Once
|
||||||
}
|
}
|
||||||
|
|
||||||
func newService(opts ...Option) Service {
|
// NewService creates and returns a new Service based on the packages within.
|
||||||
service := &service{opts: NewOptions(opts...)}
|
func NewService(opts ...Option) Service {
|
||||||
return service
|
return &service{opts: NewOptions(opts...)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) Name() string {
|
func (s *service) Name() string {
|
||||||
return s.opts.Server.Options().Name
|
return s.opts.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init initialises options. Additionally it calls cmd.Init
|
// Init initialises options. Additionally it calls cmd.Init
|
||||||
// which parses command line flags. cmd.Init is only called
|
// which parses command line flags. cmd.Init is only called
|
||||||
// on first Init.
|
// on first Init.
|
||||||
func (s *service) Init(opts ...Option) error {
|
func (s *service) Init(opts ...Option) error {
|
||||||
|
var err error
|
||||||
// process options
|
// process options
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
o(&s.opts)
|
o(&s.opts)
|
||||||
@@ -45,60 +100,48 @@ func (s *service) Init(opts ...Option) error {
|
|||||||
// skip config as the struct not passed
|
// skip config as the struct not passed
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := cfg.Init(config.Context(s.opts.Context)); err != nil {
|
if err = cfg.Init(config.Context(s.opts.Context)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := cfg.Load(s.opts.Context); err != nil {
|
if err = cfg.Load(s.opts.Context); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.opts.Logger != nil {
|
for _, log := range s.opts.Loggers {
|
||||||
if err := s.opts.Logger.Init(
|
if err = log.Init(logger.WithContext(s.opts.Context)); err != nil {
|
||||||
logger.WithContext(s.opts.Context),
|
|
||||||
); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.opts.Registry != nil {
|
for _, reg := range s.opts.Registers {
|
||||||
if err := s.opts.Registry.Init(
|
if err = reg.Init(register.Context(s.opts.Context)); err != nil {
|
||||||
registry.Context(s.opts.Context),
|
|
||||||
); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.opts.Broker != nil {
|
for _, brk := range s.opts.Brokers {
|
||||||
if err := s.opts.Broker.Init(
|
if err = brk.Init(broker.Context(s.opts.Context)); err != nil {
|
||||||
broker.Context(s.opts.Context),
|
|
||||||
); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.opts.Store != nil {
|
for _, str := range s.opts.Stores {
|
||||||
if err := s.opts.Store.Init(
|
if err = str.Init(store.Context(s.opts.Context)); err != nil {
|
||||||
store.Context(s.opts.Context),
|
|
||||||
); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.opts.Server != nil {
|
for _, srv := range s.opts.Servers {
|
||||||
if err := s.opts.Server.Init(
|
if err = srv.Init(server.Context(s.opts.Context)); err != nil {
|
||||||
server.Context(s.opts.Context),
|
|
||||||
); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.opts.Client != nil {
|
for _, cli := range s.opts.Clients {
|
||||||
if err := s.opts.Client.Init(
|
if err = cli.Init(client.Context(s.opts.Context)); err != nil {
|
||||||
client.Context(s.opts.Context),
|
|
||||||
); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -110,36 +153,93 @@ func (s *service) Options() Options {
|
|||||||
return s.opts
|
return s.opts
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) Broker() broker.Broker {
|
func (s *service) Broker(names ...string) broker.Broker {
|
||||||
return s.opts.Broker
|
idx := 0
|
||||||
|
if len(names) == 1 {
|
||||||
|
idx = getNameIndex(names[0], s.opts.Brokers)
|
||||||
|
}
|
||||||
|
return s.opts.Brokers[idx]
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) Client() client.Client {
|
func (s *service) Tracer(names ...string) tracer.Tracer {
|
||||||
return s.opts.Client
|
idx := 0
|
||||||
|
if len(names) == 1 {
|
||||||
|
idx = getNameIndex(names[0], s.opts.Tracers)
|
||||||
|
}
|
||||||
|
return s.opts.Tracers[idx]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) Server() server.Server {
|
func (s *service) Config(names ...string) config.Config {
|
||||||
return s.opts.Server
|
idx := 0
|
||||||
|
if len(names) == 1 {
|
||||||
|
idx = getNameIndex(names[0], s.opts.Configs)
|
||||||
|
}
|
||||||
|
return s.opts.Configs[idx]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) Store() store.Store {
|
func (s *service) Client(names ...string) client.Client {
|
||||||
return s.opts.Store
|
idx := 0
|
||||||
|
if len(names) == 1 {
|
||||||
|
idx = getNameIndex(names[0], s.opts.Clients)
|
||||||
|
}
|
||||||
|
return s.opts.Clients[idx]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) Registry() registry.Registry {
|
func (s *service) Server(names ...string) server.Server {
|
||||||
return s.opts.Registry
|
idx := 0
|
||||||
|
if len(names) == 1 {
|
||||||
|
idx = getNameIndex(names[0], s.opts.Servers)
|
||||||
|
}
|
||||||
|
return s.opts.Servers[idx]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) Logger() logger.Logger {
|
func (s *service) Store(names ...string) store.Store {
|
||||||
return s.opts.Logger
|
idx := 0
|
||||||
|
if len(names) == 1 {
|
||||||
|
idx = getNameIndex(names[0], s.opts.Stores)
|
||||||
|
}
|
||||||
|
return s.opts.Stores[idx]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) Auth() auth.Auth {
|
func (s *service) Register(names ...string) register.Register {
|
||||||
return s.opts.Auth
|
idx := 0
|
||||||
|
if len(names) == 1 {
|
||||||
|
idx = getNameIndex(names[0], s.opts.Registers)
|
||||||
|
}
|
||||||
|
return s.opts.Registers[idx]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) Router() router.Router {
|
func (s *service) Logger(names ...string) logger.Logger {
|
||||||
return s.opts.Router
|
idx := 0
|
||||||
|
if len(names) == 1 {
|
||||||
|
idx = getNameIndex(names[0], s.opts.Loggers)
|
||||||
|
}
|
||||||
|
return s.opts.Loggers[idx]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) Auth(names ...string) auth.Auth {
|
||||||
|
idx := 0
|
||||||
|
if len(names) == 1 {
|
||||||
|
idx = getNameIndex(names[0], s.opts.Auths)
|
||||||
|
}
|
||||||
|
return s.opts.Auths[idx]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) Router(names ...string) router.Router {
|
||||||
|
idx := 0
|
||||||
|
if len(names) == 1 {
|
||||||
|
idx = getNameIndex(names[0], s.opts.Routers)
|
||||||
|
}
|
||||||
|
return s.opts.Routers[idx]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) Meter(names ...string) meter.Meter {
|
||||||
|
idx := 0
|
||||||
|
if len(names) == 1 {
|
||||||
|
idx = getNameIndex(names[0], s.opts.Meters)
|
||||||
|
}
|
||||||
|
return s.opts.Meters[idx]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) String() string {
|
func (s *service) String() string {
|
||||||
@@ -153,8 +253,8 @@ func (s *service) Start() error {
|
|||||||
config := s.opts
|
config := s.opts
|
||||||
s.RUnlock()
|
s.RUnlock()
|
||||||
|
|
||||||
if config.Logger.V(logger.InfoLevel) {
|
if config.Loggers[0].V(logger.InfoLevel) {
|
||||||
config.Logger.Infof(s.opts.Context, "starting [service] %s", s.Name())
|
config.Loggers[0].Infof(s.opts.Context, "starting [service] %s", s.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, fn := range s.opts.BeforeStart {
|
for _, fn := range s.opts.BeforeStart {
|
||||||
@@ -169,35 +269,37 @@ func (s *service) Start() error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := cfg.Load(s.opts.Context); err != nil {
|
if err = cfg.Load(s.opts.Context); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.opts.Server == nil {
|
if len(s.opts.Servers) == 0 {
|
||||||
return fmt.Errorf("cant start nil server")
|
return fmt.Errorf("cant start nil server")
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.opts.Registry != nil {
|
for _, reg := range s.opts.Registers {
|
||||||
if err := s.opts.Registry.Connect(s.opts.Context); err != nil {
|
if err = reg.Connect(s.opts.Context); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.opts.Broker != nil {
|
for _, brk := range s.opts.Brokers {
|
||||||
if err := s.opts.Broker.Connect(s.opts.Context); err != nil {
|
if err = brk.Connect(s.opts.Context); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.opts.Store != nil {
|
for _, str := range s.opts.Stores {
|
||||||
if err := s.opts.Store.Connect(s.opts.Context); err != nil {
|
if err = str.Connect(s.opts.Context); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = s.opts.Server.Start(); err != nil {
|
for _, srv := range s.opts.Servers {
|
||||||
return err
|
if err = srv.Start(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, fn := range s.opts.AfterStart {
|
for _, fn := range s.opts.AfterStart {
|
||||||
@@ -214,8 +316,8 @@ func (s *service) Stop() error {
|
|||||||
config := s.opts
|
config := s.opts
|
||||||
s.RUnlock()
|
s.RUnlock()
|
||||||
|
|
||||||
if config.Logger.V(logger.InfoLevel) {
|
if config.Loggers[0].V(logger.InfoLevel) {
|
||||||
config.Logger.Infof(s.opts.Context, "stoppping [service] %s", s.Name())
|
config.Loggers[0].Infof(s.opts.Context, "stoppping [service] %s", s.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
@@ -225,8 +327,10 @@ func (s *service) Stop() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = s.opts.Server.Stop(); err != nil {
|
for _, srv := range s.opts.Servers {
|
||||||
return err
|
if err = srv.Stop(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, fn := range s.opts.AfterStop {
|
for _, fn := range s.opts.AfterStop {
|
||||||
@@ -235,20 +339,20 @@ func (s *service) Stop() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.opts.Registry != nil {
|
for _, reg := range s.opts.Registers {
|
||||||
if err := s.opts.Registry.Disconnect(s.opts.Context); err != nil {
|
if err = reg.Disconnect(s.opts.Context); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.opts.Broker != nil {
|
for _, brk := range s.opts.Brokers {
|
||||||
if err := s.opts.Broker.Disconnect(s.opts.Context); err != nil {
|
if err = brk.Disconnect(s.opts.Context); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.opts.Store != nil {
|
for _, str := range s.opts.Stores {
|
||||||
if err := s.opts.Store.Disconnect(s.opts.Context); err != nil {
|
if err = str.Disconnect(s.opts.Context); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -258,18 +362,19 @@ func (s *service) Stop() error {
|
|||||||
|
|
||||||
func (s *service) Run() error {
|
func (s *service) Run() error {
|
||||||
// start the profiler
|
// start the profiler
|
||||||
if s.opts.Profile != nil {
|
/*
|
||||||
// to view mutex contention
|
if s.opts.Profile != nil {
|
||||||
rtime.SetMutexProfileFraction(5)
|
// to view mutex contention
|
||||||
// to view blocking profile
|
rtime.SetMutexProfileFraction(5)
|
||||||
rtime.SetBlockProfileRate(1)
|
// to view blocking profile
|
||||||
|
rtime.SetBlockProfileRate(1)
|
||||||
|
|
||||||
if err := s.opts.Profile.Start(); err != nil {
|
if err := s.opts.Profile.Start(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
}
|
||||||
|
defer s.opts.Profile.Stop()
|
||||||
}
|
}
|
||||||
defer s.opts.Profile.Stop()
|
*/
|
||||||
}
|
|
||||||
|
|
||||||
if err := s.Start(); err != nil {
|
if err := s.Start(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -279,3 +384,16 @@ func (s *service) Run() error {
|
|||||||
|
|
||||||
return s.Stop()
|
return s.Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type nameIface interface {
|
||||||
|
Name() string
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNameIndex(n string, ifaces ...interface{}) int {
|
||||||
|
for idx, iface := range ifaces {
|
||||||
|
if ifc, ok := iface.(nameIface); ok && ifc.Name() == n {
|
||||||
|
return idx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
@@ -32,3 +32,53 @@ func SetOption(k, v interface{}) Option {
|
|||||||
o.Context = context.WithValue(o.Context, k, v)
|
o.Context = context.WithValue(o.Context, k, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetReadOption returns a function to setup a context with given value
|
||||||
|
func SetReadOption(k, v interface{}) ReadOption {
|
||||||
|
return func(o *ReadOptions) {
|
||||||
|
if o.Context == nil {
|
||||||
|
o.Context = context.Background()
|
||||||
|
}
|
||||||
|
o.Context = context.WithValue(o.Context, k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetWriteOption returns a function to setup a context with given value
|
||||||
|
func SetWriteOption(k, v interface{}) WriteOption {
|
||||||
|
return func(o *WriteOptions) {
|
||||||
|
if o.Context == nil {
|
||||||
|
o.Context = context.Background()
|
||||||
|
}
|
||||||
|
o.Context = context.WithValue(o.Context, k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetListOption returns a function to setup a context with given value
|
||||||
|
func SetListOption(k, v interface{}) ListOption {
|
||||||
|
return func(o *ListOptions) {
|
||||||
|
if o.Context == nil {
|
||||||
|
o.Context = context.Background()
|
||||||
|
}
|
||||||
|
o.Context = context.WithValue(o.Context, k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDeleteOption returns a function to setup a context with given value
|
||||||
|
func SetDeleteOption(k, v interface{}) DeleteOption {
|
||||||
|
return func(o *DeleteOptions) {
|
||||||
|
if o.Context == nil {
|
||||||
|
o.Context = context.Background()
|
||||||
|
}
|
||||||
|
o.Context = context.WithValue(o.Context, k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetExistsOption returns a function to setup a context with given value
|
||||||
|
func SetExistsOption(k, v interface{}) ExistsOption {
|
||||||
|
return func(o *ExistsOptions) {
|
||||||
|
if o.Context == nil {
|
||||||
|
o.Context = context.Background()
|
||||||
|
}
|
||||||
|
o.Context = context.WithValue(o.Context, k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -23,13 +23,18 @@ func (n *noopStore) Options() Options {
|
|||||||
return n.opts
|
return n.opts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Name
|
||||||
|
func (n *noopStore) Name() string {
|
||||||
|
return n.opts.Name
|
||||||
|
}
|
||||||
|
|
||||||
// String returns string representation
|
// String returns string representation
|
||||||
func (n *noopStore) String() string {
|
func (n *noopStore) String() string {
|
||||||
return "noop"
|
return "noop"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read reads store value by key
|
// Read reads store value by key
|
||||||
func (n *noopStore) Exists(ctx context.Context, key string) error {
|
func (n *noopStore) Exists(ctx context.Context, key string, opts ...ExistsOption) error {
|
||||||
return ErrNotFound
|
return ErrNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -2,15 +2,19 @@ package store
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/unistack-org/micro/v3/codec"
|
"github.com/unistack-org/micro/v3/codec"
|
||||||
"github.com/unistack-org/micro/v3/logger"
|
"github.com/unistack-org/micro/v3/logger"
|
||||||
"github.com/unistack-org/micro/v3/metadata"
|
"github.com/unistack-org/micro/v3/metadata"
|
||||||
|
"github.com/unistack-org/micro/v3/meter"
|
||||||
|
"github.com/unistack-org/micro/v3/tracer"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Options contains configuration for the Store
|
// Options contains configuration for the Store
|
||||||
type Options struct {
|
type Options struct {
|
||||||
|
Name string
|
||||||
// Nodes contains the addresses or other connection information of the backing storage.
|
// Nodes contains the addresses or other connection information of the backing storage.
|
||||||
// For example, an etcd implementation would contain the nodes of the cluster.
|
// For example, an etcd implementation would contain the nodes of the cluster.
|
||||||
// A SQL implementation could contain one or more connection strings.
|
// A SQL implementation could contain one or more connection strings.
|
||||||
@@ -23,6 +27,13 @@ type Options struct {
|
|||||||
Codec codec.Codec
|
Codec codec.Codec
|
||||||
// Logger the logger
|
// Logger the logger
|
||||||
Logger logger.Logger
|
Logger logger.Logger
|
||||||
|
// Meter the meter
|
||||||
|
Meter meter.Meter
|
||||||
|
// Tracer the tacer
|
||||||
|
Tracer tracer.Tracer
|
||||||
|
// TLSConfig specifies tls.Config for secure
|
||||||
|
TLSConfig *tls.Config
|
||||||
|
|
||||||
// Context should contain all implementation specific options, using context.WithValue.
|
// Context should contain all implementation specific options, using context.WithValue.
|
||||||
Context context.Context
|
Context context.Context
|
||||||
}
|
}
|
||||||
@@ -33,6 +44,8 @@ func NewOptions(opts ...Option) Options {
|
|||||||
Logger: logger.DefaultLogger,
|
Logger: logger.DefaultLogger,
|
||||||
Context: context.Background(),
|
Context: context.Background(),
|
||||||
Codec: codec.DefaultCodec,
|
Codec: codec.DefaultCodec,
|
||||||
|
Tracer: tracer.DefaultTracer,
|
||||||
|
Meter: meter.DefaultMeter,
|
||||||
}
|
}
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
o(&options)
|
o(&options)
|
||||||
@@ -43,6 +56,13 @@ func NewOptions(opts ...Option) Options {
|
|||||||
// Option sets values in Options
|
// Option sets values in Options
|
||||||
type Option func(o *Options)
|
type Option func(o *Options)
|
||||||
|
|
||||||
|
// TLSConfig specifies a *tls.Config
|
||||||
|
func TLSConfig(t *tls.Config) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.TLSConfig = t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Context pass context to store
|
// Context pass context to store
|
||||||
func Context(ctx context.Context) Option {
|
func Context(ctx context.Context) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
@@ -64,6 +84,27 @@ func Logger(l logger.Logger) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Meter sets the meter
|
||||||
|
func Meter(m meter.Meter) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Meter = m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name the name
|
||||||
|
func Name(n string) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Name = n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tracer sets the tracer
|
||||||
|
func Tracer(t tracer.Tracer) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Tracer = t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Nodes contains the addresses or other connection information of the backing storage.
|
// Nodes contains the addresses or other connection information of the backing storage.
|
||||||
// For example, an etcd implementation would contain the nodes of the cluster.
|
// For example, an etcd implementation would contain the nodes of the cluster.
|
||||||
// A SQL implementation could contain one or more connection strings.
|
// A SQL implementation could contain one or more connection strings.
|
||||||
@@ -98,8 +139,10 @@ func NewReadOptions(opts ...ReadOption) ReadOptions {
|
|||||||
|
|
||||||
// ReadOptions configures an individual Read operation
|
// ReadOptions configures an individual Read operation
|
||||||
type ReadOptions struct {
|
type ReadOptions struct {
|
||||||
Database string
|
Database string
|
||||||
Table string
|
Table string
|
||||||
|
Namespace string
|
||||||
|
Context context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadOption sets values in ReadOptions
|
// ReadOption sets values in ReadOptions
|
||||||
@@ -124,10 +167,12 @@ func NewWriteOptions(opts ...WriteOption) WriteOptions {
|
|||||||
|
|
||||||
// WriteOptions configures an individual Write operation
|
// WriteOptions configures an individual Write operation
|
||||||
type WriteOptions struct {
|
type WriteOptions struct {
|
||||||
Database string
|
Database string
|
||||||
Table string
|
Table string
|
||||||
TTL time.Duration
|
TTL time.Duration
|
||||||
Metadata metadata.Metadata
|
Metadata metadata.Metadata
|
||||||
|
Namespace string
|
||||||
|
Context context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteOption sets values in WriteOptions
|
// WriteOption sets values in WriteOptions
|
||||||
@@ -166,7 +211,10 @@ func NewDeleteOptions(opts ...DeleteOption) DeleteOptions {
|
|||||||
|
|
||||||
// DeleteOptions configures an individual Delete operation
|
// DeleteOptions configures an individual Delete operation
|
||||||
type DeleteOptions struct {
|
type DeleteOptions struct {
|
||||||
Database, Table string
|
Database string
|
||||||
|
Table string
|
||||||
|
Namespace string
|
||||||
|
Context context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteOption sets values in DeleteOptions
|
// DeleteOption sets values in DeleteOptions
|
||||||
@@ -200,7 +248,9 @@ type ListOptions struct {
|
|||||||
// Limit limits the number of returned keys
|
// Limit limits the number of returned keys
|
||||||
Limit uint
|
Limit uint
|
||||||
// Offset when combined with Limit supports pagination
|
// Offset when combined with Limit supports pagination
|
||||||
Offset uint
|
Offset uint
|
||||||
|
Namespace string
|
||||||
|
Context context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListOption sets values in ListOptions
|
// ListOption sets values in ListOptions
|
||||||
@@ -241,3 +291,20 @@ func ListOffset(o uint) ListOption {
|
|||||||
l.Offset = o
|
l.Offset = o
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ExistsOption func(*ExistsOptions)
|
||||||
|
|
||||||
|
type ExistsOptions struct {
|
||||||
|
Namespace string
|
||||||
|
Context context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewExistsOptions(opts ...ExistsOption) ExistsOptions {
|
||||||
|
options := ExistsOptions{
|
||||||
|
Context: context.Background(),
|
||||||
|
}
|
||||||
|
for _, o := range opts {
|
||||||
|
o(&options)
|
||||||
|
}
|
||||||
|
return options
|
||||||
|
}
|
||||||
|
@@ -12,12 +12,15 @@ import (
|
|||||||
var (
|
var (
|
||||||
// ErrNotFound is returned when a key doesn't exist
|
// ErrNotFound is returned when a key doesn't exist
|
||||||
ErrNotFound = errors.New("not found")
|
ErrNotFound = errors.New("not found")
|
||||||
|
// ErrInvalidKey is returned when a key has empty or have invalid format
|
||||||
|
ErrInvalidKey = errors.New("invalid key")
|
||||||
// DefaultStore is the global default store
|
// DefaultStore is the global default store
|
||||||
DefaultStore Store = NewStore()
|
DefaultStore Store = NewStore()
|
||||||
)
|
)
|
||||||
|
|
||||||
// Store is a data storage interface
|
// Store is a data storage interface
|
||||||
type Store interface {
|
type Store interface {
|
||||||
|
Name() string
|
||||||
// Init initialises the store
|
// Init initialises the store
|
||||||
Init(opts ...Option) error
|
Init(opts ...Option) error
|
||||||
// Connect is used when store needs to be connected
|
// Connect is used when store needs to be connected
|
||||||
@@ -25,7 +28,7 @@ type Store interface {
|
|||||||
// Options allows you to view the current options.
|
// Options allows you to view the current options.
|
||||||
Options() Options
|
Options() Options
|
||||||
// Exists check that key exists in store
|
// Exists check that key exists in store
|
||||||
Exists(ctx context.Context, key string) error
|
Exists(ctx context.Context, key string, opts ...ExistsOption) error
|
||||||
// Read reads a single key name to provided value with optional ReadOptions
|
// Read reads a single key name to provided value with optional ReadOptions
|
||||||
Read(ctx context.Context, key string, val interface{}, opts ...ReadOption) error
|
Read(ctx context.Context, key string, val interface{}, opts ...ReadOption) error
|
||||||
// Write writes a value to key name to the store with optional WriteOption
|
// Write writes a value to key name to the store with optional WriteOption
|
||||||
|
@@ -4,16 +4,34 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/unistack-org/micro/v3/logger"
|
"github.com/unistack-org/micro/v3/logger"
|
||||||
|
"github.com/unistack-org/micro/v3/meter"
|
||||||
|
"github.com/unistack-org/micro/v3/tracer"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Options struct {
|
type Options struct {
|
||||||
Nodes []string
|
Nodes []string
|
||||||
Prefix string
|
Prefix string
|
||||||
Logger logger.Logger
|
Logger logger.Logger
|
||||||
|
Tracer tracer.Tracer
|
||||||
|
Meter meter.Meter
|
||||||
}
|
}
|
||||||
|
|
||||||
type Option func(o *Options)
|
type Option func(o *Options)
|
||||||
|
|
||||||
|
func NewOptions(opts ...Option) Options {
|
||||||
|
options := Options{
|
||||||
|
Logger: logger.DefaultLogger,
|
||||||
|
Meter: meter.DefaultMeter,
|
||||||
|
Tracer: tracer.DefaultTracer,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, o := range opts {
|
||||||
|
o(&options)
|
||||||
|
}
|
||||||
|
|
||||||
|
return options
|
||||||
|
}
|
||||||
|
|
||||||
type LeaderOptions struct{}
|
type LeaderOptions struct{}
|
||||||
|
|
||||||
type LeaderOption func(o *LeaderOptions)
|
type LeaderOption func(o *LeaderOptions)
|
||||||
@@ -32,6 +50,20 @@ func Logger(l logger.Logger) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Meter sets the logger
|
||||||
|
func Meter(m meter.Meter) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Meter = m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tracer sets the tracer
|
||||||
|
func Tracer(t tracer.Tracer) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Tracer = t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Nodes sets the addresses to use
|
// Nodes sets the addresses to use
|
||||||
func Nodes(a ...string) Option {
|
func Nodes(a ...string) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
|
@@ -14,11 +14,12 @@ const (
|
|||||||
|
|
||||||
// FromContext returns a span from context
|
// FromContext returns a span from context
|
||||||
func FromContext(ctx context.Context) (traceID string, parentSpanID string, isFound bool) {
|
func FromContext(ctx context.Context) (traceID string, parentSpanID string, isFound bool) {
|
||||||
if ctx == nil {
|
md, ok := metadata.FromIncomingContext(ctx)
|
||||||
|
if !ok {
|
||||||
return "", "", false
|
return "", "", false
|
||||||
}
|
}
|
||||||
traceID, traceOk := metadata.Get(ctx, traceIDKey)
|
traceID, traceOk := md.Get(traceIDKey)
|
||||||
microID, microOk := metadata.Get(ctx, "Micro-Id")
|
microID, microOk := md.Get("Micro-Id")
|
||||||
if !traceOk && !microOk {
|
if !traceOk && !microOk {
|
||||||
isFound = false
|
isFound = false
|
||||||
return
|
return
|
||||||
@@ -26,17 +27,17 @@ func FromContext(ctx context.Context) (traceID string, parentSpanID string, isFo
|
|||||||
if !traceOk {
|
if !traceOk {
|
||||||
traceID = microID
|
traceID = microID
|
||||||
}
|
}
|
||||||
parentSpanID, ok := metadata.Get(ctx, spanIDKey)
|
parentSpanID, ok = md.Get(spanIDKey)
|
||||||
return traceID, parentSpanID, ok
|
return traceID, parentSpanID, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewContext saves the trace and span ids in the context
|
// NewContext saves the trace and span ids in the context
|
||||||
func NewContext(ctx context.Context, traceID, parentSpanID string) context.Context {
|
func NewContext(ctx context.Context, traceID, parentSpanID string) context.Context {
|
||||||
if ctx == nil {
|
md, ok := metadata.FromContext(ctx)
|
||||||
ctx = context.Background()
|
if !ok {
|
||||||
|
md = metadata.New(2)
|
||||||
}
|
}
|
||||||
md := metadata.New(2)
|
|
||||||
md.Set(traceIDKey, traceID)
|
md.Set(traceIDKey, traceID)
|
||||||
md.Set(spanIDKey, parentSpanID)
|
md.Set(spanIDKey, parentSpanID)
|
||||||
return metadata.MergeContext(ctx, md, true)
|
return metadata.NewContext(ctx, md)
|
||||||
}
|
}
|
||||||
|
@@ -6,6 +6,10 @@ type noopTracer struct {
|
|||||||
opts Options
|
opts Options
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *noopTracer) Name() string {
|
||||||
|
return n.opts.Name
|
||||||
|
}
|
||||||
|
|
||||||
// Init initilize tracer
|
// Init initilize tracer
|
||||||
func (n *noopTracer) Init(opts ...Option) error {
|
func (n *noopTracer) Init(opts ...Option) error {
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
@@ -19,6 +23,11 @@ func (n *noopTracer) Start(ctx context.Context, name string) (context.Context, *
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lookup get span from context
|
||||||
|
func (n *noopTracer) Lookup(ctx context.Context) (*Span, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Finish finishes span
|
// Finish finishes span
|
||||||
func (n *noopTracer) Finish(*Span) error {
|
func (n *noopTracer) Finish(*Span) error {
|
||||||
return nil
|
return nil
|
||||||
|
@@ -9,6 +9,7 @@ var (
|
|||||||
|
|
||||||
// Options struct
|
// Options struct
|
||||||
type Options struct {
|
type Options struct {
|
||||||
|
Name string
|
||||||
// Logger is the logger for messages
|
// Logger is the logger for messages
|
||||||
Logger logger.Logger
|
Logger logger.Logger
|
||||||
// Size is the size of ring buffer
|
// Size is the size of ring buffer
|
||||||
@@ -52,3 +53,10 @@ func NewOptions(opts ...Option) Options {
|
|||||||
}
|
}
|
||||||
return options
|
return options
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Name sets the name
|
||||||
|
func Name(n string) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.Name = n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -15,10 +15,14 @@ var (
|
|||||||
|
|
||||||
// Tracer is an interface for distributed tracing
|
// Tracer is an interface for distributed tracing
|
||||||
type Tracer interface {
|
type Tracer interface {
|
||||||
|
Name() string
|
||||||
|
Init(...Option) error
|
||||||
// Start a trace
|
// Start a trace
|
||||||
Start(ctx context.Context, name string) (context.Context, *Span)
|
Start(ctx context.Context, name string) (context.Context, *Span)
|
||||||
// Finish the trace
|
// Finish the trace
|
||||||
Finish(*Span) error
|
Finish(*Span) error
|
||||||
|
// Lookup get span from context
|
||||||
|
Lookup(ctx context.Context) (*Span, error)
|
||||||
// Read the traces
|
// Read the traces
|
||||||
Read(...ReadOption) ([]*Span, error)
|
Read(...ReadOption) ([]*Span, error)
|
||||||
}
|
}
|
@@ -10,10 +10,9 @@ import (
|
|||||||
|
|
||||||
func FromRequest(r *http.Request) context.Context {
|
func FromRequest(r *http.Request) context.Context {
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
md, ok := metadata.FromContext(ctx)
|
md, ok := metadata.FromIncomingContext(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
// create needed map with specific len
|
md = metadata.New(len(r.Header) + 2)
|
||||||
md = make(metadata.Metadata, len(r.Header)+2)
|
|
||||||
}
|
}
|
||||||
for key, val := range r.Header {
|
for key, val := range r.Header {
|
||||||
md.Set(key, strings.Join(val, ","))
|
md.Set(key, strings.Join(val, ","))
|
||||||
@@ -22,5 +21,5 @@ func FromRequest(r *http.Request) context.Context {
|
|||||||
md["Host"] = r.Host
|
md["Host"] = r.Host
|
||||||
// pass http method
|
// pass http method
|
||||||
md["Method"] = r.Method
|
md["Method"] = r.Method
|
||||||
return metadata.NewContext(ctx, md)
|
return metadata.NewIncomingContext(ctx, md)
|
||||||
}
|
}
|
||||||
|
@@ -28,7 +28,7 @@ func TestRequestToContext(t *testing.T) {
|
|||||||
|
|
||||||
for _, d := range testData {
|
for _, d := range testData {
|
||||||
ctx := FromRequest(d.request)
|
ctx := FromRequest(d.request)
|
||||||
md, ok := metadata.FromContext(ctx)
|
md, ok := metadata.FromIncomingContext(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Fatalf("Expected metadata for request %+v", d.request)
|
t.Fatalf("Expected metadata for request %+v", d.request)
|
||||||
}
|
}
|
||||||
|
@@ -8,15 +8,15 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/unistack-org/micro/v3/registry"
|
"github.com/unistack-org/micro/v3/register"
|
||||||
"github.com/unistack-org/micro/v3/registry/memory"
|
"github.com/unistack-org/micro/v3/register/memory"
|
||||||
"github.com/unistack-org/micro/v3/router"
|
"github.com/unistack-org/micro/v3/router"
|
||||||
regRouter "github.com/unistack-org/micro/v3/router/registry"
|
regRouter "github.com/unistack-org/micro/v3/router/register"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRoundTripper(t *testing.T) {
|
func TestRoundTripper(t *testing.T) {
|
||||||
m := memory.NewRegistry()
|
m := memory.NewRegister()
|
||||||
r := regRouter.NewRouter(router.Registry(m))
|
r := regRouter.NewRouter(router.Register(m))
|
||||||
|
|
||||||
rt := NewRoundTripper(WithRouter(r))
|
rt := NewRoundTripper(WithRouter(r))
|
||||||
|
|
||||||
@@ -32,9 +32,9 @@ func TestRoundTripper(t *testing.T) {
|
|||||||
|
|
||||||
go http.Serve(l, nil)
|
go http.Serve(l, nil)
|
||||||
|
|
||||||
m.Register(®istry.Service{
|
m.Register(®ister.Service{
|
||||||
Name: "example.com",
|
Name: "example.com",
|
||||||
Nodes: []*registry.Node{
|
Nodes: []*register.Node{
|
||||||
{
|
{
|
||||||
Id: "1",
|
Id: "1",
|
||||||
Address: l.Addr().String(),
|
Address: l.Addr().String(),
|
||||||
|
597
util/reflect/reflect.go
Normal file
597
util/reflect/reflect.go
Normal file
@@ -0,0 +1,597 @@
|
|||||||
|
package reflect
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"reflect"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
bracketSplitter = regexp.MustCompile(`\[|\]`)
|
||||||
|
ErrInvalidStruct = errors.New("invalid struct specified")
|
||||||
|
ErrInvalidParam = errors.New("invalid url query param provided")
|
||||||
|
)
|
||||||
|
|
||||||
|
func fieldName(name string) string {
|
||||||
|
newstr := make([]rune, 0)
|
||||||
|
upper := false
|
||||||
|
for idx, chr := range name {
|
||||||
|
if idx == 0 {
|
||||||
|
upper = true
|
||||||
|
} else if chr == '_' {
|
||||||
|
upper = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if upper {
|
||||||
|
newstr = append(newstr, unicode.ToUpper(chr))
|
||||||
|
} else {
|
||||||
|
newstr = append(newstr, chr)
|
||||||
|
}
|
||||||
|
upper = false
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(newstr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsEmpty(v reflect.Value) bool {
|
||||||
|
switch getKind(v) {
|
||||||
|
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
|
||||||
|
return v.Len() == 0
|
||||||
|
case reflect.Bool:
|
||||||
|
return !v.Bool()
|
||||||
|
case reflect.Int:
|
||||||
|
return v.Int() == 0
|
||||||
|
case reflect.Uint:
|
||||||
|
return v.Uint() == 0
|
||||||
|
case reflect.Float32:
|
||||||
|
return v.Float() == 0
|
||||||
|
case reflect.Interface, reflect.Ptr:
|
||||||
|
if v.IsNil() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return IsEmpty(v.Elem())
|
||||||
|
case reflect.Func:
|
||||||
|
return v.IsNil()
|
||||||
|
case reflect.Invalid:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func Zero(src interface{}) (interface{}, error) {
|
||||||
|
sv := reflect.ValueOf(src)
|
||||||
|
|
||||||
|
if sv.Kind() == reflect.Ptr {
|
||||||
|
sv = sv.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
if sv.Kind() == reflect.Invalid {
|
||||||
|
return nil, ErrInvalidStruct
|
||||||
|
}
|
||||||
|
|
||||||
|
dst := reflect.New(sv.Type())
|
||||||
|
|
||||||
|
return dst.Interface(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func StructFields(src interface{}) ([]reflect.StructField, error) {
|
||||||
|
var fields []reflect.StructField
|
||||||
|
|
||||||
|
sv := reflect.ValueOf(src)
|
||||||
|
if sv.Kind() == reflect.Ptr {
|
||||||
|
sv = sv.Elem()
|
||||||
|
}
|
||||||
|
if sv.Kind() != reflect.Struct {
|
||||||
|
return nil, ErrInvalidStruct
|
||||||
|
}
|
||||||
|
|
||||||
|
typ := sv.Type()
|
||||||
|
for idx := 0; idx < typ.NumField(); idx++ {
|
||||||
|
fld := typ.Field(idx)
|
||||||
|
val := sv.Field(idx)
|
||||||
|
if !val.CanSet() || len(fld.PkgPath) != 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if val.Kind() == reflect.Struct {
|
||||||
|
infields, err := StructFields(val.Interface())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
fields = append(fields, infields...)
|
||||||
|
} else {
|
||||||
|
fields = append(fields, fld)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CopyDefaults for a from b
|
||||||
|
// a and b should be pointers to the same kind of struct
|
||||||
|
func CopyDefaults(a, b interface{}) {
|
||||||
|
pt := reflect.TypeOf(a)
|
||||||
|
t := pt.Elem()
|
||||||
|
va := reflect.ValueOf(a).Elem()
|
||||||
|
vb := reflect.ValueOf(b).Elem()
|
||||||
|
for i := 0; i < t.NumField(); i++ {
|
||||||
|
aField := va.Field(i)
|
||||||
|
if aField.CanSet() {
|
||||||
|
bField := vb.Field(i)
|
||||||
|
aField.Set(bField)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CopyFrom sets the public members of a from b
|
||||||
|
// a and b should be pointers to structs
|
||||||
|
// a can be a different type from b
|
||||||
|
// Only the Fields which have the same name and assignable type on a
|
||||||
|
// and b will be set.
|
||||||
|
func CopyFrom(a, b interface{}) {
|
||||||
|
ta := reflect.TypeOf(a).Elem()
|
||||||
|
tb := reflect.TypeOf(b).Elem()
|
||||||
|
va := reflect.ValueOf(a).Elem()
|
||||||
|
vb := reflect.ValueOf(b).Elem()
|
||||||
|
for i := 0; i < tb.NumField(); i++ {
|
||||||
|
bField := vb.Field(i)
|
||||||
|
tbField := tb.Field(i)
|
||||||
|
name := tbField.Name
|
||||||
|
aField := va.FieldByName(name)
|
||||||
|
taField, found := ta.FieldByName(name)
|
||||||
|
if found && aField.IsValid() && bField.IsValid() && aField.CanSet() && tbField.Type.AssignableTo(taField.Type) {
|
||||||
|
aField.Set(bField)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func URLMap(query string) (map[string]interface{}, error) {
|
||||||
|
var (
|
||||||
|
mp interface{} = make(map[string]interface{})
|
||||||
|
)
|
||||||
|
|
||||||
|
params := strings.Split(query, "&")
|
||||||
|
|
||||||
|
for _, part := range params {
|
||||||
|
tm, err := queryToMap(part)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
mp = merge(mp, tm)
|
||||||
|
}
|
||||||
|
|
||||||
|
return mp.(map[string]interface{}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func FlattenMap(a map[string]interface{}) map[string]interface{} {
|
||||||
|
// preprocess map
|
||||||
|
nb := make(map[string]interface{}, len(a))
|
||||||
|
for k, v := range a {
|
||||||
|
ps := strings.Split(k, ".")
|
||||||
|
if len(ps) == 1 {
|
||||||
|
nb[k] = v
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
em := make(map[string]interface{})
|
||||||
|
em[ps[len(ps)-1]] = v
|
||||||
|
for i := len(ps) - 2; i > 0; i-- {
|
||||||
|
nm := make(map[string]interface{})
|
||||||
|
nm[ps[i]] = em
|
||||||
|
em = nm
|
||||||
|
}
|
||||||
|
if vm, ok := nb[ps[0]]; ok {
|
||||||
|
// nested map
|
||||||
|
nm := vm.(map[string]interface{})
|
||||||
|
for vk, vv := range em {
|
||||||
|
nm[vk] = vv
|
||||||
|
}
|
||||||
|
nb[ps[0]] = nm
|
||||||
|
} else {
|
||||||
|
nb[ps[0]] = em
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nb
|
||||||
|
}
|
||||||
|
|
||||||
|
func MergeMap(a interface{}, b map[string]interface{}) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ta := reflect.TypeOf(a)
|
||||||
|
if ta.Kind() == reflect.Ptr {
|
||||||
|
ta = ta.Elem()
|
||||||
|
}
|
||||||
|
va := reflect.ValueOf(a)
|
||||||
|
if va.Kind() == reflect.Ptr {
|
||||||
|
va = va.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
for mk, mv := range b {
|
||||||
|
vmv := reflect.ValueOf(mv)
|
||||||
|
name := fieldName(mk)
|
||||||
|
fva := va.FieldByName(name)
|
||||||
|
fta, found := ta.FieldByName(name)
|
||||||
|
if !found || !fva.IsValid() || !fva.CanSet() || fta.PkgPath != "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// fast path via direct assign
|
||||||
|
if vmv.Type().AssignableTo(fta.Type) && !IsEmpty(vmv) {
|
||||||
|
fva.Set(vmv)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch getKind(fva) {
|
||||||
|
case reflect.Bool:
|
||||||
|
err = mergeBool(fva, vmv)
|
||||||
|
case reflect.String:
|
||||||
|
err = mergeString(fva, vmv)
|
||||||
|
case reflect.Int:
|
||||||
|
err = mergeInt(fva, vmv)
|
||||||
|
case reflect.Uint:
|
||||||
|
err = mergeUint(fva, vmv)
|
||||||
|
case reflect.Float32:
|
||||||
|
err = mergeFloat(fva, vmv)
|
||||||
|
case reflect.Array:
|
||||||
|
//fmt.Printf("Array %#+v %#+v\n", fva, vmv)
|
||||||
|
case reflect.Slice:
|
||||||
|
err = mergeSlice(fva, vmv)
|
||||||
|
case reflect.Ptr:
|
||||||
|
if fva.IsNil() {
|
||||||
|
fva.Set(reflect.New(fva.Type().Elem()))
|
||||||
|
if fva.Elem().Type().Kind() == reflect.Struct {
|
||||||
|
for i := 0; i < fva.Elem().NumField(); i++ {
|
||||||
|
field := fva.Elem().Field(i)
|
||||||
|
if field.Type().Kind() == reflect.Ptr && field.IsNil() && fva.Elem().Type().Field(i).Anonymous == true {
|
||||||
|
field.Set(reflect.New(field.Type().Elem()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if nmp, ok := vmv.Interface().(map[string]interface{}); ok {
|
||||||
|
err = MergeMap(fva.Interface(), nmp)
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("cant fill")
|
||||||
|
}
|
||||||
|
case reflect.Struct:
|
||||||
|
if nmp, ok := vmv.Interface().(map[string]interface{}); ok {
|
||||||
|
err = MergeMap(fva.Interface(), nmp)
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("cant fill")
|
||||||
|
}
|
||||||
|
case reflect.Map:
|
||||||
|
//fmt.Printf("Map %#+v %#+v\n", fva, vmv)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func mergeSlice(va, vb reflect.Value) error {
|
||||||
|
switch getKind(vb) {
|
||||||
|
/*
|
||||||
|
case reflect.Int:
|
||||||
|
if vb.Int() == 1 {
|
||||||
|
va.SetBool(true)
|
||||||
|
}
|
||||||
|
case reflect.Uint:
|
||||||
|
if vb.Uint() == 1 {
|
||||||
|
va.SetBool(true)
|
||||||
|
}
|
||||||
|
case reflect.Float64:
|
||||||
|
if vb.Float() == 1 {
|
||||||
|
va.SetBool(true)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
case reflect.String:
|
||||||
|
var err error
|
||||||
|
fn := func(c rune) bool { return c == ',' || c == ';' || c == ' ' }
|
||||||
|
slice := strings.FieldsFunc(vb.String(), fn)
|
||||||
|
va.Set(reflect.MakeSlice(va.Type(), len(slice), len(slice)))
|
||||||
|
for idx, sl := range slice {
|
||||||
|
vl := reflect.ValueOf(sl)
|
||||||
|
switch va.Type().Elem().Kind() {
|
||||||
|
case reflect.Bool:
|
||||||
|
err = mergeBool(va.Index(idx), vl)
|
||||||
|
case reflect.String:
|
||||||
|
err = mergeString(va.Index(idx), vl)
|
||||||
|
case reflect.Ptr:
|
||||||
|
if va.Index(idx).IsNil() {
|
||||||
|
va.Index(idx).Set(reflect.New(va.Index(idx).Type().Elem()))
|
||||||
|
}
|
||||||
|
switch va.Type().Elem().String() {
|
||||||
|
case "*wrapperspb.BoolValue":
|
||||||
|
if eva := reflect.Indirect(va.Index(idx)).FieldByName("Value"); eva.IsValid() {
|
||||||
|
err = mergeBool(eva, vl)
|
||||||
|
}
|
||||||
|
case "*wrapperspb.BytesValue":
|
||||||
|
if eva := va.Index(idx).FieldByName("Value"); eva.IsValid() {
|
||||||
|
err = mergeUint(eva, vl)
|
||||||
|
}
|
||||||
|
case "*wrapperspb.DoubleValue", "*wrapperspb.FloatValue":
|
||||||
|
if eva := reflect.Indirect(va.Index(idx)).FieldByName("Value"); eva.IsValid() {
|
||||||
|
err = mergeFloat(eva, vl)
|
||||||
|
}
|
||||||
|
case "*wrapperspb.Int32Value", "*wrapperspb.Int64Value":
|
||||||
|
if eva := reflect.Indirect(va.Index(idx)).FieldByName("Value"); eva.IsValid() {
|
||||||
|
err = mergeInt(eva, vl)
|
||||||
|
}
|
||||||
|
case "*wrapperspb.StringValue":
|
||||||
|
if eva := reflect.Indirect(va.Index(idx)).FieldByName("Value"); eva.IsValid() {
|
||||||
|
err = mergeString(eva, vl)
|
||||||
|
}
|
||||||
|
case "*wrapperspb.UInt32Value", "*wrapperspb.UInt64Value":
|
||||||
|
if eva := reflect.Indirect(va.Index(idx)).FieldByName("Value"); eva.IsValid() {
|
||||||
|
err = mergeUint(eva, vl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("cant merge %v %s with %v %s", va, va.Kind(), vb, vb.Kind())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func mergeBool(va, vb reflect.Value) error {
|
||||||
|
switch getKind(vb) {
|
||||||
|
case reflect.Int:
|
||||||
|
if vb.Int() == 1 {
|
||||||
|
va.SetBool(true)
|
||||||
|
}
|
||||||
|
case reflect.Uint:
|
||||||
|
if vb.Uint() == 1 {
|
||||||
|
va.SetBool(true)
|
||||||
|
}
|
||||||
|
case reflect.Float32:
|
||||||
|
if vb.Float() == 1 {
|
||||||
|
va.SetBool(true)
|
||||||
|
}
|
||||||
|
case reflect.String:
|
||||||
|
if b, err := strconv.ParseBool(vb.String()); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
va.SetBool(b)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("cant merge %v %s with %v %s", va, va.Kind(), vb, vb.Kind())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func mergeString(va, vb reflect.Value) error {
|
||||||
|
switch getKind(vb) {
|
||||||
|
case reflect.Int:
|
||||||
|
va.SetString(fmt.Sprintf("%d", vb.Int()))
|
||||||
|
case reflect.Uint:
|
||||||
|
va.SetString(fmt.Sprintf("%d", vb.Uint()))
|
||||||
|
case reflect.Float32:
|
||||||
|
va.SetString(fmt.Sprintf("%f", vb.Float()))
|
||||||
|
case reflect.String:
|
||||||
|
va.Set(vb)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("cant merge %v %s with %v %s", va, va.Kind(), vb, vb.Kind())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func mergeInt(va, vb reflect.Value) error {
|
||||||
|
switch getKind(vb) {
|
||||||
|
case reflect.Int:
|
||||||
|
va.Set(vb)
|
||||||
|
case reflect.Uint:
|
||||||
|
va.SetInt(int64(vb.Uint()))
|
||||||
|
case reflect.Float32:
|
||||||
|
va.SetInt(int64(vb.Float()))
|
||||||
|
case reflect.String:
|
||||||
|
if f, err := strconv.ParseInt(vb.String(), 10, va.Type().Bits()); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
va.SetInt(f)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("cant merge %v %s with %v %s", va, va.Kind(), vb, vb.Kind())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func mergeUint(va, vb reflect.Value) error {
|
||||||
|
switch getKind(vb) {
|
||||||
|
case reflect.Int:
|
||||||
|
va.SetUint(uint64(vb.Int()))
|
||||||
|
case reflect.Uint:
|
||||||
|
va.Set(vb)
|
||||||
|
case reflect.Float32:
|
||||||
|
va.SetUint(uint64(vb.Float()))
|
||||||
|
case reflect.String:
|
||||||
|
if f, err := strconv.ParseUint(vb.String(), 10, va.Type().Bits()); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
va.SetUint(f)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("cant merge %v %s with %v %s", va, va.Kind(), vb, vb.Kind())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func mergeFloat(va, vb reflect.Value) error {
|
||||||
|
switch getKind(vb) {
|
||||||
|
case reflect.Int:
|
||||||
|
va.SetFloat(float64(vb.Int()))
|
||||||
|
case reflect.Uint:
|
||||||
|
va.SetFloat(float64(vb.Uint()))
|
||||||
|
case reflect.Float32:
|
||||||
|
va.Set(vb)
|
||||||
|
case reflect.String:
|
||||||
|
if f, err := strconv.ParseFloat(vb.String(), va.Type().Bits()); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
va.SetFloat(f)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("cant merge %v %s with %v %s", va, va.Kind(), vb, vb.Kind())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getKind(val reflect.Value) reflect.Kind {
|
||||||
|
kind := val.Kind()
|
||||||
|
switch {
|
||||||
|
case kind >= reflect.Int && kind <= reflect.Int64:
|
||||||
|
return reflect.Int
|
||||||
|
case kind >= reflect.Uint && kind <= reflect.Uint64:
|
||||||
|
return reflect.Uint
|
||||||
|
case kind >= reflect.Float32 && kind <= reflect.Float64:
|
||||||
|
return reflect.Float32
|
||||||
|
}
|
||||||
|
return kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func btSplitter(str string) []string {
|
||||||
|
r := bracketSplitter.Split(str, -1)
|
||||||
|
for idx, s := range r {
|
||||||
|
if len(s) == 0 {
|
||||||
|
if len(r) > idx+1 {
|
||||||
|
copy(r[idx:], r[idx+1:])
|
||||||
|
r = r[:len(r)-1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// queryToMap turns something like a[b][c]=4 into
|
||||||
|
// map[string]interface{}{
|
||||||
|
// "a": map[string]interface{}{
|
||||||
|
// "b": map[string]interface{}{
|
||||||
|
// "c": 4,
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// }
|
||||||
|
func queryToMap(param string) (map[string]interface{}, error) {
|
||||||
|
rawKey, rawValue, err := splitKeyAndValue(param)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rawValue, err = url.QueryUnescape(rawValue)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rawKey, err = url.QueryUnescape(rawKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pieces := btSplitter(rawKey)
|
||||||
|
key := pieces[0]
|
||||||
|
|
||||||
|
// If len==1 then rawKey has no [] chars and we can just
|
||||||
|
// decode this as key=value into {key: value}
|
||||||
|
if len(pieces) == 1 {
|
||||||
|
return map[string]interface{}{
|
||||||
|
key: rawValue,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// If len > 1 then we have something like a[b][c]=2
|
||||||
|
// so we need to turn this into {"a": {"b": {"c": 2}}}
|
||||||
|
// To do this we break our key into two pieces:
|
||||||
|
// a and b[c]
|
||||||
|
// and then we set {"a": queryToMap("b[c]", value)}
|
||||||
|
ret := make(map[string]interface{})
|
||||||
|
ret[key], err = queryToMap(buildNewKey(rawKey) + "=" + rawValue)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// When URL params have a set of empty brackets (eg a[]=1)
|
||||||
|
// it is assumed to be an array. This will get us the
|
||||||
|
// correct value for the array item and return it as an
|
||||||
|
// []interface{} so that it can be merged properly.
|
||||||
|
if pieces[1] == "" {
|
||||||
|
temp := ret[key].(map[string]interface{})
|
||||||
|
ret[key] = []interface{}{temp[""]}
|
||||||
|
}
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildNewKey will take something like:
|
||||||
|
// origKey = "bar[one][two]"
|
||||||
|
// pieces = [bar one two ]
|
||||||
|
// and return "one[two]"
|
||||||
|
func buildNewKey(origKey string) string {
|
||||||
|
pieces := btSplitter(origKey)
|
||||||
|
|
||||||
|
ret := origKey[len(pieces[0])+1:]
|
||||||
|
ret = ret[:len(pieces[1])] + ret[len(pieces[1])+1:]
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// splitKeyAndValue splits a URL param at the last equal
|
||||||
|
// sign and returns the two strings. If no equal sign is
|
||||||
|
// found, the ErrInvalidParam error is returned.
|
||||||
|
func splitKeyAndValue(param string) (string, string, error) {
|
||||||
|
li := strings.LastIndex(param, "=")
|
||||||
|
if li == -1 {
|
||||||
|
return "", "", ErrInvalidParam
|
||||||
|
}
|
||||||
|
return param[:li], param[li+1:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// merge merges a with b if they are either both slices
|
||||||
|
// or map[string]interface{} types. Otherwise it returns b.
|
||||||
|
func merge(a interface{}, b interface{}) interface{} {
|
||||||
|
if av, aok := a.(map[string]interface{}); aok {
|
||||||
|
if bv, bok := b.(map[string]interface{}); bok {
|
||||||
|
return mergeMapIface(av, bv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if av, aok := a.([]interface{}); aok {
|
||||||
|
if bv, bok := b.([]interface{}); bok {
|
||||||
|
return mergeSliceIface(av, bv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
va := reflect.ValueOf(a)
|
||||||
|
vb := reflect.ValueOf(b)
|
||||||
|
if (va.Type().Kind() == reflect.Slice) && (va.Type().Elem().Kind() == vb.Type().Kind() || vb.Type().ConvertibleTo(va.Type().Elem())) {
|
||||||
|
va = reflect.Append(va, vb.Convert(va.Type().Elem()))
|
||||||
|
return va.Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// mergeMap merges a with b, attempting to merge any nested
|
||||||
|
// values in nested maps but eventually overwriting anything
|
||||||
|
// in a that can't be merged with whatever is in b.
|
||||||
|
func mergeMapIface(a map[string]interface{}, b map[string]interface{}) map[string]interface{} {
|
||||||
|
for bK, bV := range b {
|
||||||
|
if aV, ok := a[bK]; ok {
|
||||||
|
if (reflect.ValueOf(aV).Type().Kind() == reflect.ValueOf(bV).Type().Kind()) ||
|
||||||
|
((reflect.ValueOf(aV).Type().Kind() == reflect.Slice) && reflect.ValueOf(aV).Type().Elem().Kind() == reflect.ValueOf(bV).Type().Kind()) {
|
||||||
|
nV := []interface{}{aV, bV}
|
||||||
|
a[bK] = nV
|
||||||
|
} else {
|
||||||
|
a[bK] = merge(a[bK], bV)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
a[bK] = bV
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
// mergeSlice merges a with b and returns the result.
|
||||||
|
func mergeSliceIface(a []interface{}, b []interface{}) []interface{} {
|
||||||
|
a = append(a, b...)
|
||||||
|
return a
|
||||||
|
}
|
45
util/reflect/reflect_test.go
Normal file
45
util/reflect/reflect_test.go
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package reflect
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestURLSliceVars(t *testing.T) {
|
||||||
|
u, err := url.Parse("http://localhost/v1/test/call/my_name?key=arg1&key=arg2&key=arg3")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mp, err := URLMap(u.RawQuery)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
v, ok := mp["key"]
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("key not exists: %#+v", mp)
|
||||||
|
}
|
||||||
|
|
||||||
|
vm, ok := v.([]interface{})
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("invalid key value")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(vm) != 3 {
|
||||||
|
t.Fatalf("missing key value: %#+v", mp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestURLVars(t *testing.T) {
|
||||||
|
u, err := url.Parse("http://localhost/v1/test/call/my_name?req=key&arg1=arg1&arg2=12345&nested.string_args=str1&nested.string_args=str2&arg2=54321")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mp, err := URLMap(u.RawQuery)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
_ = mp
|
||||||
|
}
|
@@ -1,11 +1,11 @@
|
|||||||
package registry
|
package register
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/unistack-org/micro/v3/registry"
|
"github.com/unistack-org/micro/v3/register"
|
||||||
)
|
)
|
||||||
|
|
||||||
func addNodes(old, neu []*registry.Node) []*registry.Node {
|
func addNodes(old, neu []*register.Node) []*register.Node {
|
||||||
nodes := make([]*registry.Node, len(neu))
|
nodes := make([]*register.Node, len(neu))
|
||||||
// add all new nodes
|
// add all new nodes
|
||||||
for i, n := range neu {
|
for i, n := range neu {
|
||||||
node := *n
|
node := *n
|
||||||
@@ -35,8 +35,8 @@ func addNodes(old, neu []*registry.Node) []*registry.Node {
|
|||||||
return nodes
|
return nodes
|
||||||
}
|
}
|
||||||
|
|
||||||
func delNodes(old, del []*registry.Node) []*registry.Node {
|
func delNodes(old, del []*register.Node) []*register.Node {
|
||||||
var nodes []*registry.Node
|
var nodes []*register.Node
|
||||||
for _, o := range old {
|
for _, o := range old {
|
||||||
var rem bool
|
var rem bool
|
||||||
for _, n := range del {
|
for _, n := range del {
|
||||||
@@ -53,24 +53,24 @@ func delNodes(old, del []*registry.Node) []*registry.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CopyService make a copy of service
|
// CopyService make a copy of service
|
||||||
func CopyService(service *registry.Service) *registry.Service {
|
func CopyService(service *register.Service) *register.Service {
|
||||||
// copy service
|
// copy service
|
||||||
s := ®istry.Service{}
|
s := ®ister.Service{}
|
||||||
*s = *service
|
*s = *service
|
||||||
|
|
||||||
// copy nodes
|
// copy nodes
|
||||||
nodes := make([]*registry.Node, len(service.Nodes))
|
nodes := make([]*register.Node, len(service.Nodes))
|
||||||
for j, node := range service.Nodes {
|
for j, node := range service.Nodes {
|
||||||
n := ®istry.Node{}
|
n := ®ister.Node{}
|
||||||
*n = *node
|
*n = *node
|
||||||
nodes[j] = n
|
nodes[j] = n
|
||||||
}
|
}
|
||||||
s.Nodes = nodes
|
s.Nodes = nodes
|
||||||
|
|
||||||
// copy endpoints
|
// copy endpoints
|
||||||
eps := make([]*registry.Endpoint, len(service.Endpoints))
|
eps := make([]*register.Endpoint, len(service.Endpoints))
|
||||||
for j, ep := range service.Endpoints {
|
for j, ep := range service.Endpoints {
|
||||||
e := ®istry.Endpoint{}
|
e := ®ister.Endpoint{}
|
||||||
*e = *ep
|
*e = *ep
|
||||||
eps[j] = e
|
eps[j] = e
|
||||||
}
|
}
|
||||||
@@ -79,8 +79,8 @@ func CopyService(service *registry.Service) *registry.Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Copy makes a copy of services
|
// Copy makes a copy of services
|
||||||
func Copy(current []*registry.Service) []*registry.Service {
|
func Copy(current []*register.Service) []*register.Service {
|
||||||
services := make([]*registry.Service, len(current))
|
services := make([]*register.Service, len(current))
|
||||||
for i, service := range current {
|
for i, service := range current {
|
||||||
services[i] = CopyService(service)
|
services[i] = CopyService(service)
|
||||||
}
|
}
|
||||||
@@ -88,14 +88,14 @@ func Copy(current []*registry.Service) []*registry.Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Merge merges two lists of services and returns a new copy
|
// Merge merges two lists of services and returns a new copy
|
||||||
func Merge(olist []*registry.Service, nlist []*registry.Service) []*registry.Service {
|
func Merge(olist []*register.Service, nlist []*register.Service) []*register.Service {
|
||||||
var srv []*registry.Service
|
var srv []*register.Service
|
||||||
|
|
||||||
for _, n := range nlist {
|
for _, n := range nlist {
|
||||||
var seen bool
|
var seen bool
|
||||||
for _, o := range olist {
|
for _, o := range olist {
|
||||||
if o.Version == n.Version {
|
if o.Version == n.Version {
|
||||||
sp := ®istry.Service{}
|
sp := ®ister.Service{}
|
||||||
// make copy
|
// make copy
|
||||||
*sp = *o
|
*sp = *o
|
||||||
// set nodes
|
// set nodes
|
||||||
@@ -106,25 +106,25 @@ func Merge(olist []*registry.Service, nlist []*registry.Service) []*registry.Ser
|
|||||||
srv = append(srv, sp)
|
srv = append(srv, sp)
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
sp := ®istry.Service{}
|
sp := ®ister.Service{}
|
||||||
// make copy
|
// make copy
|
||||||
*sp = *o
|
*sp = *o
|
||||||
srv = append(srv, sp)
|
srv = append(srv, sp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !seen {
|
if !seen {
|
||||||
srv = append(srv, Copy([]*registry.Service{n})...)
|
srv = append(srv, Copy([]*register.Service{n})...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return srv
|
return srv
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove removes services and returns a new copy
|
// Remove removes services and returns a new copy
|
||||||
func Remove(old, del []*registry.Service) []*registry.Service {
|
func Remove(old, del []*register.Service) []*register.Service {
|
||||||
var services []*registry.Service
|
var services []*register.Service
|
||||||
|
|
||||||
for _, o := range old {
|
for _, o := range old {
|
||||||
srv := ®istry.Service{}
|
srv := ®ister.Service{}
|
||||||
*srv = *o
|
*srv = *o
|
||||||
|
|
||||||
var rem bool
|
var rem bool
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user