Compare commits

...

80 Commits

Author SHA1 Message Date
2a548634fd config: add Save/Load options
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-06-20 23:57:13 +03:00
598dddc476 util/reflect: fix time.Time StructFields parsing
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-06-19 15:58:36 +03:00
887b48f1e7 util/reflect: improve StructFields func
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-06-17 12:53:23 +03:00
6e55d07636 client: allow to publish body only
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-06-13 12:20:35 +03:00
919520219c client: WithBodyOnly publish option
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-06-11 14:14:41 +03:00
60a5e737f8 util/reflect: return pointer from helper funcs
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-05-25 22:44:22 +03:00
34f0b209cc codec: add ability to control codec via struct tags
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-05-25 22:20:39 +03:00
ba8e1889fe dependabot
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-05-16 17:18:56 +03:00
dae5c57a60 Create dependabot.yml 2021-05-15 14:46:22 +03:00
ea590d57df meter/wrapper: add inflight request/message count (#47)
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-05-10 17:59:40 +03:00
Renovate Bot
9aa6969836 fix(deps): update golang.org/x/net commit hash to 4163338 2021-05-10 14:29:32 +00:00
Renovate Bot
c00c705c24 fix(deps): update golang.org/x/net commit hash to 16afe75 2021-05-08 09:02:01 +00:00
Renovate Bot
0239f795d8 fix(deps): update golang.org/x/net commit hash to 7fd8e65 2021-05-03 10:07:41 +00:00
Renovate Bot
e69b43881d fix(deps): update golang.org/x/net commit hash to f8dd838 2021-05-01 23:20:59 +00:00
3a48a613fe not fail on lint now
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-04-27 08:36:11 +03:00
86626c5922 fieldalignment of all structs to save memory
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-04-27 08:32:47 +03:00
ee11f39a2f fieldaligment
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-04-27 00:03:18 +03:00
3bdfdd8fd2 meter: fix labels
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-04-27 00:03:18 +03:00
6dfdff7fd8 fieldaligment
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-04-27 00:03:18 +03:00
00a4785df3 fixup
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-04-27 00:03:18 +03:00
Renovate Bot
bae3b0ef94 fix(deps): update golang.org/x/net commit hash to 5f58ad6 2021-04-23 23:52:34 +00:00
Renovate Bot
89b0565062 fix(deps): update golang.org/x/net commit hash to 4e50805 2021-04-22 03:04:18 +00:00
1f8b0aeb61 store: remove unused Value type
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-04-22 00:57:06 +03:00
Renovate Bot
5b6f849e0a fix(deps): update golang.org/x/net commit hash to 798c215 2021-04-20 23:13:59 +00:00
Renovate Bot
3b416fffde fix(deps): update golang.org/x/net commit hash to d25e304 2021-04-20 15:04:17 +00:00
3a60103aed server: drop Internal option
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-04-20 12:45:14 +03:00
41837a67f8 register: drop verbose values export
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-04-20 12:39:21 +03:00
852f19598d util/reflect: fix protobuf field name detection
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-04-19 11:34:28 +03:00
6537b35773 util/reflect: add interface merging
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-04-19 01:19:37 +03:00
b733f1316f remove stale generate stuff
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-04-16 17:36:27 +03:00
Renovate Bot
840af5574c fix(deps): update golang.org/x/net commit hash to e915ea6 2021-04-16 00:56:52 +00:00
Renovate Bot
56e5b7001c fix(deps): update golang.org/x/net commit hash to 0645797 2021-04-14 21:41:15 +00:00
Renovate Bot
11dc6fd752 fix(deps): update golang.org/x/net commit hash to afb366f 2021-04-10 11:09:36 +00:00
a2695d8699 util/reflect: rewrite struct merging with map
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-04-10 01:22:40 +03:00
618421de05 client: allow to set content-type for call
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-04-09 23:09:12 +03:00
Renovate Bot
30baaabd9f fix(deps): update golang.org/x/net commit hash to a5a99cb 2021-04-05 19:46:46 +00:00
df5bce1191 util/reflect: fix StructURLValues
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-04-03 11:50:23 +03:00
Renovate Bot
089d0fe4df fix(deps): update golang.org/x/net commit hash to 0fccb6f 2021-03-31 22:50:38 +00:00
a06f535303 util/reflect: add StructURLValues func
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-04-01 00:30:26 +03:00
Renovate Bot
eba586a329 fix(deps): update golang.org/x/net commit hash to cb1fcc7 2021-03-31 09:19:27 +00:00
Renovate Bot
d74a8645e8 fix(deps): update golang.org/x/net commit hash to e572328 2021-03-31 00:52:53 +00:00
Renovate Bot
5a00786192 fix(deps): update golang.org/x/net commit hash to cd0ac97 2021-03-30 22:28:38 +00:00
Renovate Bot
b3e9941634 fix(deps): update golang.org/x/net commit hash to c8897c2 2021-03-30 16:02:28 +00:00
Renovate Bot
a5a5904302 fix(deps): update golang.org/x/net commit hash to 22f4162 2021-03-30 11:44:00 +00:00
Renovate Bot
a59832e57e fix(deps): update golang.org/x/net commit hash to df645c7 2021-03-30 05:11:12 +00:00
0e42033e7f meter/handler: more idiomatic option handling
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-29 17:51:44 +03:00
52d8255974 service init with own context
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-28 23:42:02 +03:00
9830cb48a9 fix compilation
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-28 19:31:03 +03:00
92d7ab2105 regen handlers
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-28 19:28:01 +03:00
d2935ef399 meter/handler: fix proto and generated code
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-28 19:18:11 +03:00
ce4c96ae0a server/health: add health check handler
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-28 19:18:11 +03:00
Renovate Bot
14026d15be fix(deps): update golang.org/x/net commit hash to 61e0566 2021-03-27 01:29:30 +00:00
Renovate Bot
2df0c7643e fix(deps): update golang.org/x/net commit hash to 6b15177 2021-03-26 19:17:30 +00:00
e13c2c48fd client: use router.DefaultRouter in NewOptions helper
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-26 17:45:55 +03:00
8db55d2e55 router: use dns as default router
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-26 17:43:39 +03:00
ed61cad961 meter/handler: regen
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-26 15:45:09 +03:00
040fc4548f client: add TLSConfig option
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-26 15:44:34 +03:00
6189a1b980 add SkipEndpoints for wrappers
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-25 23:30:38 +03:00
eb2a450a7b meter/handler: fix func signature
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-25 12:36:48 +03:00
Renovate Bot
d2a30a5da1 fix(deps): update golang.org/x/net commit hash to d1beb07 2021-03-24 23:28:38 +00:00
65889c66f6 meter/wrapper: add DefaultSkipEndpoints
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-25 00:06:38 +03:00
dcdf133d5b server: mask router
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-24 13:26:36 +03:00
8742b55305 auth: fix Init method
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-24 13:12:03 +03:00
4a64ee72f7 meter/handler: provide default metrics handler
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-23 17:26:29 +03:00
881d7afeea meter/handler: provide initial meter handler
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-23 17:12:13 +03:00
8c95448535 util/reflect: add IsZero helper
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-21 16:17:50 +03:00
c1dc041d8c client: fix NewOptions with CallOptions filling
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-16 19:09:49 +03:00
Renovate Bot
25be0ac0f0 fix(deps): update golang.org/x/net commit hash to d523dce 2021-03-16 13:12:17 +00:00
Renovate Bot
86f73cac4e fix(deps): update golang.org/x/net commit hash to 34ac3e1 2021-03-15 22:09:13 +00:00
485eda6ce9 meter/wrapper: fix wrapper build
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-15 00:49:26 +03:00
dbbdb24631 meter: rework labels
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-15 00:44:13 +03:00
723ceb4f32 regsiter: fix extractor
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-12 16:09:20 +03:00
bac9869bb3 register: support map in ExtractValue
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-12 15:48:05 +03:00
610427445f codec: provide proto for codec.Frame
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-11 07:42:42 +03:00
Renovate Bot
c84a66c713 fix(deps): update module github.com/imdario/mergo to v0.3.12 2021-03-10 00:35:57 +00:00
00eaae717b lint fixes
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-06 23:44:54 +03:00
a102e95433 spell fixes
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-06 23:33:37 +03:00
39f66cc86c add logger wrapper, fix default logger fields method
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-06 23:26:47 +03:00
bbbcb22565 fieldalignment of all structs to save memory
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-06 19:45:13 +03:00
cb70dfa664 meter/wrapper: use meter.DefaultMeter in NewOptions
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-05 17:40:03 +03:00
147 changed files with 3500 additions and 2154 deletions

19
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
# Maintain dependencies for GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
# Maintain dependencies for Golang
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "daily"

15
.github/generate.sh vendored
View File

@@ -1,15 +0,0 @@
#!/bin/bash -e
find . -type f -name '*.pb.*.go' -o -name '*.pb.go' -a ! -name 'message.pb.go' -delete
PROTOS=$(find . -type f -name '*.proto' | grep -v proto/google/api)
mkdir -p proto/google/api
curl -s -o proto/google/api/annotations.proto -L https://raw.githubusercontent.com/googleapis/googleapis/master/google/api/annotations.proto
curl -s -o proto/google/api/http.proto -L https://raw.githubusercontent.com/googleapis/googleapis/master/google/api/http.proto
for PROTO in $PROTOS; do
echo $PROTO
protoc -I./proto -I. -I$(dirname $PROTO) --go-grpc_out=paths=source_relative:. --go_out=paths=source_relative:. --micro_out=paths=source_relative:. $PROTO
done
rm -r proto

20
.github/renovate.json vendored
View File

@@ -1,20 +0,0 @@
{
"extends": [
"config:base"
],
"postUpdateOptions": ["gomodTidy"],
"packageRules": [
{
"matchUpdateTypes": ["minor", "patch", "pin", "digest"],
"automerge": true
},
{
"groupName": "all deps",
"separateMajorMinor": true,
"groupSlug": "all",
"packagePatterns": [
"*"
]
}
]
}

13
.github/stale.sh vendored
View File

@@ -1,13 +0,0 @@
#!/bin/bash -ex
export PATH=$PATH:$(pwd)/bin
export GO111MODULE=on
export GOBIN=$(pwd)/bin
#go get github.com/rvflash/goup@v0.4.1
#goup -v ./...
#go get github.com/psampaz/go-mod-outdated@v0.6.0
go list -u -m -mod=mod -json all | go-mod-outdated -update -direct -ci || true
#go list -u -m -json all | go-mod-outdated -update

View File

@@ -53,7 +53,7 @@ jobs:
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.
version: v1.30 version: v1.39
# Optional: working directory, useful for monorepos # Optional: working directory, useful for monorepos
# working-directory: somedir # working-directory: somedir
# Optional: golangci-lint command line arguments. # Optional: golangci-lint command line arguments.

View File

@@ -53,7 +53,7 @@ jobs:
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.
version: v1.30 version: v1.39
# Optional: working directory, useful for monorepos # Optional: working directory, useful for monorepos
# working-directory: somedir # working-directory: somedir
# Optional: golangci-lint command line arguments. # Optional: golangci-lint command line arguments.

View File

@@ -1,30 +1,44 @@
run: run:
concurrency: 4
deadline: 5m deadline: 5m
modules-download-mode: readonly issues-exit-code: 1
skip-files: tests: true
- ".*\\.pb\\.go$"
- ".*\\.pb\\.micro\\.go$" linters-settings:
govet:
check-shadowing: true
enable:
- fieldalignment
linters: linters:
disable-all: false
enable-all: false
enable: enable:
- megacheck
- staticcheck
- deadcode
- varcheck
- gosimple
- unused
- prealloc
- scopelint
- gocritic
- goimports
- unconvert
- govet - govet
- nakedret - deadcode
- errcheck
- govet
- ineffassign
- staticcheck
- structcheck - structcheck
- gosec
disable:
- maligned
- interfacer
- typecheck - typecheck
- dupl - unused
- varcheck
- bodyclose
- gci
- goconst
- gocritic
- gosimple
- gofmt
- gofumpt
- goimports
- golint
- gosec
- makezero
- misspell
- nakedret
- nestif
- nilerr
- noctx
- prealloc
- unconvert
- unparam
disable-all: false

View File

@@ -34,20 +34,20 @@ type Option func(*Options) error
type Endpoint struct { type Endpoint struct {
// Name Greeter.Hello // Name Greeter.Hello
Name string Name string
// Description e.g what's this endpoint for // Desciption for endpoint
Description string Description string
// Handler e.g rpc, proxy // Handler e.g rpc, proxy
Handler string Handler string
// Body destination
// "*" or "" - top level message value
// "string" - inner message value
Body string
// Host e.g example.com // Host e.g example.com
Host []string Host []string
// Method e.g GET, POST // Method e.g GET, POST
Method []string Method []string
// Path e.g /greeter. Expect POSIX regex // Path e.g /greeter. Expect POSIX regex
Path []string Path []string
// Body destination
// "*" or "" - top level message value
// "string" - inner message value
Body string
// Stream flag // Stream flag
Stream bool Stream bool
} }

View File

@@ -149,5 +149,4 @@ func TestValidate(t *testing.T) {
if err := Validate(epPcreInvalid); err == nil { if err := Validate(epPcreInvalid); err == nil {
t.Fatalf("invalid pcre %v", epPcreInvalid.Path[0]) t.Fatalf("invalid pcre %v", epPcreInvalid.Path[0])
} }
} }

View File

@@ -6,18 +6,16 @@ import (
"github.com/unistack-org/micro/v3/logger" "github.com/unistack-org/micro/v3/logger"
) )
var ( // DefaultMaxRecvSize specifies max recv size for handler
// DefaultMaxRecvSize specifies max recv size for handler var DefaultMaxRecvSize int64 = 1024 * 1024 * 100 // 10Mb
DefaultMaxRecvSize int64 = 1024 * 1024 * 100 // 10Mb
)
// Options struct holds handler options // Options struct holds handler options
type Options struct { type Options struct {
MaxRecvSize int64
Namespace string
Router router.Router Router router.Router
Client client.Client Client client.Client
Logger logger.Logger Logger logger.Logger
Namespace string
MaxRecvSize int64
} }
// Option func signature // Option func signature

View File

@@ -8,9 +8,12 @@ import (
// Options struct // Options struct
type Options struct { type Options struct {
Handler string // Context is for external defined options
Context context.Context
// Handler name
Handler string
// ServicePrefix is the prefix
ServicePrefix string ServicePrefix string
Context context.Context
} }
// Option func // Option func

View File

@@ -15,12 +15,12 @@ import (
// NewResolver creates new subdomain api resolver // NewResolver creates new subdomain api resolver
func NewResolver(parent resolver.Resolver, opts ...resolver.Option) resolver.Resolver { func NewResolver(parent resolver.Resolver, opts ...resolver.Option) resolver.Resolver {
options := resolver.NewOptions(opts...) options := resolver.NewOptions(opts...)
return &subdomainResolver{options, parent} return &subdomainResolver{opts: options, Resolver: parent}
} }
type subdomainResolver struct { type subdomainResolver struct {
opts resolver.Options
resolver.Resolver resolver.Resolver
opts resolver.Options
} }
// Resolve resolve endpoint based on subdomain // Resolve resolve endpoint based on subdomain

View File

@@ -19,9 +19,7 @@ type vpathResolver struct {
opts resolver.Options opts resolver.Options
} }
var ( var re = regexp.MustCompile("^v[0-9]+$")
re = regexp.MustCompile("^v[0-9]+$")
)
// Resolve endpoint // Resolve endpoint
func (r *vpathResolver) Resolve(req *http.Request, opts ...resolver.ResolveOption) (*resolver.Endpoint, error) { func (r *vpathResolver) Resolve(req *http.Request, opts ...resolver.ResolveOption) (*resolver.Endpoint, error) {

View File

@@ -11,11 +11,16 @@ import (
// Options holds the options for api router // Options holds the options for api router
type Options struct { type Options struct {
Handler string // Register for service lookup
Register register.Register Register register.Register
// Resolver to use
Resolver resolver.Resolver Resolver resolver.Resolver
Logger logger.Logger // Logger micro logger
Context context.Context Logger logger.Logger
// Context is for external options
Context context.Context
// Handler name
Handler string
} }
// Option func signature // Option func signature

View File

@@ -7,10 +7,8 @@ import (
"github.com/unistack-org/micro/v3/api" "github.com/unistack-org/micro/v3/api"
) )
var ( // DefaultRouter contains default router implementation
// DefaultRouter contains default router implementation var DefaultRouter Router
DefaultRouter Router
)
// Router is used to determine an endpoint for a request // Router is used to determine an endpoint for a request
type Router interface { type Router interface {

View File

@@ -30,7 +30,7 @@ var (
// Auth provides authentication and authorization // Auth provides authentication and authorization
type Auth interface { type Auth interface {
// Init the auth // Init the auth
Init(opts ...Option) Init(opts ...Option) error
// Options set for auth // Options set for auth
Options() Options Options() Options
// Generate a new account // Generate a new account
@@ -53,30 +53,30 @@ type Auth interface {
// Account provided by an auth provider // Account provided by an auth provider
type Account struct { type Account struct {
// ID of the account e.g. email // Metadata any other associated metadata
Metadata metadata.Metadata `json:"metadata"`
// ID of the account e.g. email or uuid
ID string `json:"id"` ID string `json:"id"`
// Type of the account, e.g. service // Type of the account, e.g. service
Type string `json:"type"` Type string `json:"type"`
// Issuer of the account // Issuer of the account
Issuer string `json:"issuer"` Issuer string `json:"issuer"`
// Any other associated metadata
Metadata metadata.Metadata `json:"metadata"`
// Scopes the account has access to
Scopes []string `json:"scopes"`
// Secret for the account, e.g. the password // Secret for the account, e.g. the password
Secret string `json:"secret"` Secret string `json:"secret"`
// Scopes the account has access to
Scopes []string `json:"scopes"`
} }
// Token can be short or long lived // Token can be short or long lived
type Token struct { type Token struct {
// The token to be used for accessing resources
AccessToken string `json:"access_token"`
// RefreshToken to be used to generate a new token
RefreshToken string `json:"refresh_token"`
// Time of token creation // Time of token creation
Created time.Time `json:"created"` Created time.Time `json:"created"`
// Time of token expiry // Time of token expiry
Expiry time.Time `json:"expiry"` Expiry time.Time `json:"expiry"`
// The token to be used for accessing resources
AccessToken string `json:"access_token"`
// RefreshToken to be used to generate a new token
RefreshToken string `json:"refresh_token"`
} }
// Expired returns a boolean indicating if the token needs to be refreshed // Expired returns a boolean indicating if the token needs to be refreshed
@@ -106,17 +106,15 @@ const (
// Rule is used to verify access to a resource // Rule is used to verify access to a resource
type Rule struct { type Rule struct {
// ID of the rule, e.g. "public" // Resource that rule belongs to
ID string
// Scope the rule requires, a blank scope indicates open to the public and * indicates the rule
// applies to any valid account
Scope string
// Resource the rule applies to
Resource *Resource Resource *Resource
// Access determines if the rule grants or denies access to the resource // ID of the rule
ID string
// Scope of the rule
Scope string
// Access flag allow/deny
Access Access Access Access
// Priority the rule should take when verifying a request, the higher the value the sooner the // Priority holds the rule priority
// rule will be applied
Priority int32 Priority int32
} }

View File

@@ -14,10 +14,11 @@ func (n *noopAuth) String() string {
} }
// Init the auth // Init the auth
func (n *noopAuth) Init(opts ...Option) { func (n *noopAuth) Init(opts ...Option) error {
for _, o := range opts { for _, o := range opts {
o(&n.opts) o(&n.opts)
} }
return nil
} }
// Options set for auth // Options set for auth

View File

@@ -26,33 +26,34 @@ func NewOptions(opts ...Option) Options {
// Options struct holds auth options // Options struct holds auth options
type Options struct { type Options struct {
Name string // Context holds the external options
// Issuer of the service's account Context context.Context
Issuer string // Meter used for metrics
// ID is the services auth ID Meter meter.Meter
ID string // Logger used for logging
// Secret is used to authenticate the service Logger logger.Logger
Secret string // Tracer used for tracing
Tracer tracer.Tracer
// Store used for stre data
Store store.Store
// Token is the services token used to authenticate itself // Token is the services token used to authenticate itself
Token *Token Token *Token
// PublicKey for decoding JWTs
PublicKey string
// PrivateKey for encoding JWTs
PrivateKey string
// LoginURL is the relative url path where a user can login // LoginURL is the relative url path where a user can login
LoginURL string LoginURL string
// Store to back auth // PrivateKey for encoding JWTs
Store store.Store PrivateKey string
// PublicKey for decoding JWTs
PublicKey string
// Secret is used to authenticate the service
Secret string
// ID is the services auth ID
ID string
// Issuer of the service's account
Issuer string
// Name holds the auth name
Name string
// Addrs sets the addresses of auth // Addrs sets the addresses of auth
Addrs []string Addrs []string
// Logger sets the logger
Logger logger.Logger
// Meter sets tht meter
Meter meter.Meter
// Tracer
Tracer tracer.Tracer
// Context to store other options
Context context.Context
} }
// Option func // Option func
@@ -124,18 +125,12 @@ func LoginURL(url string) Option {
// GenerateOptions struct // GenerateOptions struct
type GenerateOptions struct { type GenerateOptions struct {
// Metadata associated with the account
Metadata metadata.Metadata Metadata metadata.Metadata
// Scopes the account has access too
Scopes []string
// Provider of the account, e.g. oauth
Provider string Provider string
// Type of the account, e.g. user Type string
Type string Secret string
// Secret used to authenticate the account Issuer string
Secret string Scopes []string
// Issuer of the account, e.g. micro
Issuer string
} }
// GenerateOption func // GenerateOption func
@@ -194,16 +189,11 @@ func NewGenerateOptions(opts ...GenerateOption) GenerateOptions {
// TokenOptions struct // TokenOptions struct
type TokenOptions struct { type TokenOptions struct {
// ID for the account ID string
ID string Secret string
// Secret for the account
Secret string
// RefreshToken is used to refesh a token
RefreshToken string RefreshToken string
// Expiry is the time the token should live for Issuer string
Expiry time.Duration Expiry time.Duration
// Issuer of the account
Issuer string
} }
// TokenOption func // TokenOption func

View File

@@ -24,11 +24,11 @@ func TestVerify(t *testing.T) {
} }
tt := []struct { tt := []struct {
Name string Error error
Rules []*Rule
Account *Account Account *Account
Resource *Resource Resource *Resource
Error error Name string
Rules []*Rule
}{ }{
{ {
Name: "NoRules", Name: "NoRules",

View File

@@ -7,10 +7,8 @@ import (
"github.com/unistack-org/micro/v3/metadata" "github.com/unistack-org/micro/v3/metadata"
) )
var ( // DefaultBroker default broker
// DefaultBroker default broker var DefaultBroker Broker = NewBroker()
DefaultBroker Broker = NewBroker()
)
// Broker is an interface used for asynchronous messaging. // Broker is an interface used for asynchronous messaging.
type Broker interface { type Broker interface {

View File

@@ -13,28 +13,27 @@ import (
) )
type memoryBroker struct { type memoryBroker struct {
opts Options
addr string
sync.RWMutex
connected bool
Subscribers map[string][]*memorySubscriber Subscribers map[string][]*memorySubscriber
addr string
opts Options
sync.RWMutex
connected bool
} }
type memoryEvent struct { type memoryEvent struct {
opts Options
topic string
err error err error
message interface{} message interface{}
topic string
opts Options
} }
type memorySubscriber struct { type memorySubscriber struct {
id string ctx context.Context
topic string
exit chan bool exit chan bool
handler Handler handler Handler
id string
topic string
opts SubscribeOptions opts SubscribeOptions
ctx context.Context
} }
func (m *memoryBroker) Options() Options { func (m *memoryBroker) Options() Options {

View File

@@ -13,25 +13,26 @@ import (
// Options struct // Options struct
type Options struct { type Options struct {
Name string // Tracer used for tracing
// Addrs useed by broker
Addrs []string
// ErrorHandler executed when errors occur processing messages
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 Tracer tracer.Tracer
// TLSConfig for secure communication // Register can be used for clustering
TLSConfig *tls.Config
// Register used for clustering
Register register.Register Register register.Register
// Context is used for non default options // Codec holds the codec for marshal/unmarshal
Codec codec.Codec
// Logger used for logging
Logger logger.Logger
// Meter used for metrics
Meter meter.Meter
// Context holds external options
Context context.Context Context context.Context
// TLSConfig holds tls.TLSConfig options
TLSConfig *tls.Config
// ErrorHandler used when broker can't unmarshal incoming message
ErrorHandler Handler
// Name holds the broker name
Name string
// Addrs holds the broker address
Addrs []string
} }
// NewOptions create new Options // NewOptions create new Options
@@ -59,10 +60,10 @@ func Context(ctx context.Context) Option {
// PublishOptions struct // PublishOptions struct
type PublishOptions struct { type PublishOptions struct {
// BodyOnly says that only body of the message must be published // Context holds external options
BodyOnly bool
// Context for non default options
Context context.Context Context context.Context
// BodyOnly flag says the message contains raw body bytes
BodyOnly bool
} }
// NewPublishOptions creates PublishOptions struct // NewPublishOptions creates PublishOptions struct
@@ -80,22 +81,16 @@ func NewPublishOptions(opts ...PublishOption) PublishOptions {
// SubscribeOptions struct // SubscribeOptions struct
type SubscribeOptions struct { type SubscribeOptions struct {
// AutoAck ack messages if handler returns nil err // Context holds external options
AutoAck bool
// ErrorHandler executed when errors occur processing messages
ErrorHandler Handler
// Group for subscriber, Subscribers with the same group name
// will create a shared subscription where each
// receives a subset of messages.
Group string
// BodyOnly says that consumed only body of the message
BodyOnly bool
// Context is used for non default options
Context context.Context Context context.Context
// ErrorHandler used when broker can't unmarshal incoming message
ErrorHandler Handler
// Group holds consumer group
Group string
// AutoAck flag specifies auto ack of incoming message when no error happens
AutoAck bool
// BodyOnly flag specifies that message contains only body bytes without header
BodyOnly bool
} }
// Option func // Option func

View File

@@ -21,12 +21,12 @@ type Source struct {
// Package is packaged format for source // Package is packaged format for source
type Package struct { type Package struct {
// Source of the package
Source *Source
// Name of the package // Name of the package
Name string Name string
// Location of the package // Location of the package
Path string Path string
// Type of package e.g tarball, binary, docker // Type of package e.g tarball, binary, docker
Type string Type string
// Source of the package
Source *Source
} }

View File

@@ -9,16 +9,10 @@ import (
"github.com/unistack-org/micro/v3/metadata" "github.com/unistack-org/micro/v3/metadata"
) )
var ( // DefaultCodecs will be used to encode/decode data
// DefaultCodecs will be used to encode/decode data var DefaultCodecs = map[string]codec.Codec{
DefaultCodecs = map[string]codec.Codec{ "application/octet-stream": codec.NewCodec(),
//"application/json": cjson.NewCodec, }
//"application/json-rpc": cjsonrpc.NewCodec,
//"application/protobuf": cproto.NewCodec,
//"application/proto-rpc": cprotorpc.NewCodec,
"application/octet-stream": codec.NewCodec(),
}
)
type noopClient struct { type noopClient struct {
opts Options opts Options
@@ -31,12 +25,12 @@ type noopMessage struct {
} }
type noopRequest struct { type noopRequest struct {
body interface{}
codec codec.Codec
service string service string
method string method string
endpoint string endpoint string
contentType string contentType string
body interface{}
codec codec.Codec
stream bool stream bool
} }
@@ -227,5 +221,8 @@ func (n *noopClient) Publish(ctx context.Context, p Message, opts ...PublishOpti
return n.opts.Broker.Publish(ctx, topic, &broker.Message{ return n.opts.Broker.Publish(ctx, topic, &broker.Message{
Header: md, Header: md,
Body: body, Body: body,
}, broker.PublishContext(options.Context)) },
broker.PublishContext(options.Context),
broker.PublishBodyOnly(options.BodyOnly),
)
} }

View File

@@ -2,6 +2,7 @@ package client
import ( import (
"context" "context"
"crypto/tls"
"time" "time"
"github.com/unistack-org/micro/v3/broker" "github.com/unistack-org/micro/v3/broker"
@@ -18,35 +19,42 @@ import (
// Options holds client options // Options holds client options
type Options struct { type Options struct {
Name string // Selector used to select needed address
// Used to select codec Selector selector.Selector
ContentType string // Logger used to log messages
// Proxy address to send requests via Logger logger.Logger
Proxy string // Tracer used for tracing
Tracer tracer.Tracer
// Plugged interfaces // Broker used to publish messages
Broker broker.Broker Broker broker.Broker
Codecs map[string]codec.Codec // Meter used for metrics
Router router.Router Meter meter.Meter
Selector selector.Selector // Router used to get route
Router router.Router
// Transport used for transfer messages
Transport transport.Transport Transport transport.Transport
Logger logger.Logger // Context is used for external options
Meter meter.Meter
// Lookup used for looking up routes
Lookup LookupFunc
// Connection Pool
PoolSize int
PoolTTL time.Duration
Tracer tracer.Tracer
// Wrapper that used client
Wrappers []Wrapper
// CallOptions that used by default
CallOptions CallOptions
// Context is used for non default options
Context context.Context Context context.Context
// Lookup func used to get destination addr
Lookup LookupFunc
// Codecs map
Codecs map[string]codec.Codec
// TLSConfig specifies tls.Config for secure connection
TLSConfig *tls.Config
// Proxy is used for proxy requests
Proxy string
// ContentType is used to select codec
ContentType string
// Name is the client name
Name string
// Wrappers contains wrappers
Wrappers []Wrapper
// CallOptions contains default CallOptions
CallOptions CallOptions
// PoolSize connection pool size
PoolSize int
// PoolTTL connection pool ttl
PoolTTL time.Duration
} }
// NewCallOptions creates new call options struct // NewCallOptions creates new call options struct
@@ -60,34 +68,36 @@ func NewCallOptions(opts ...CallOption) CallOptions {
// CallOptions holds client call options // CallOptions holds client call options
type CallOptions struct { type CallOptions struct {
// Address of remote hosts // Router used for route
Address []string
// Backoff func
Backoff BackoffFunc
// DialTimeout is the transport Dial Timeout
DialTimeout time.Duration
// Retries is the number of Call attempts
Retries int
// Retry func to be used for retries
Retry RetryFunc
// RequestTimeout specifies request timeout
RequestTimeout time.Duration
// Router to use for this call
Router router.Router Router router.Router
// Selector to use for the call // Selector selects addr
Selector selector.Selector Selector selector.Selector
// SelectOptions to use when selecting a route // Context used for deadline
SelectOptions []selector.SelectOption
// StreamTimeout timeout for the stream
StreamTimeout time.Duration
// AuthToken specifies the auth token as the authorization header
AuthToken bool
// Network to lookup the route within
Network string
// CallWrappers is for low level call func
CallWrappers []CallWrapper
// Context is used for non default options
Context context.Context Context context.Context
// Retry func used for retries
Retry RetryFunc
// Backoff func used for backoff when retry
Backoff BackoffFunc
// Network name
Network string
// Content-Type
ContentType string
// CallWrappers call wrappers
CallWrappers []CallWrapper
// SelectOptions selector options
SelectOptions []selector.SelectOption
// Address specifies static addr list
Address []string
// Retries specifies retries num
Retries int
// StreamTimeout stream timeout
StreamTimeout time.Duration
// RequestTimeout request timeout
RequestTimeout time.Duration
// DialTimeout dial timeout
DialTimeout time.Duration
// AuthToken flag
AuthToken bool
} }
// Context pass context to client // Context pass context to client
@@ -108,10 +118,12 @@ func NewPublishOptions(opts ...PublishOption) PublishOptions {
// PublishOptions holds publish options // PublishOptions holds publish options
type PublishOptions struct { type PublishOptions struct {
// Exchange is the routing exchange for the message // BodyOnly will publish only message body
Exchange string BodyOnly bool
// Context holds additional options // Context used for external options
Context context.Context Context context.Context
// Exchange topic exchange name
Exchange string
} }
// NewMessageOptions creates message options struct // NewMessageOptions creates message options struct
@@ -125,6 +137,7 @@ func NewMessageOptions(opts ...MessageOption) MessageOptions {
// MessageOptions holds client message options // MessageOptions holds client message options
type MessageOptions struct { type MessageOptions struct {
// ContentType specify content-type of message
ContentType string ContentType string
} }
@@ -139,12 +152,12 @@ func NewRequestOptions(opts ...RequestOption) RequestOptions {
// RequestOptions holds client request options // RequestOptions holds client request options
type RequestOptions struct { type RequestOptions struct {
// ContentType specify content-type of request // Context used for external options
ContentType string
// Stream says that request is the streaming
Stream bool
// Context can hold other options
Context context.Context Context context.Context
// ContentType specify content-type of message
ContentType string
// Stream flag
Stream bool
} }
// NewOptions creates new options struct // NewOptions creates new options struct
@@ -154,20 +167,23 @@ func NewOptions(opts ...Option) Options {
ContentType: DefaultContentType, ContentType: DefaultContentType,
Codecs: make(map[string]codec.Codec), Codecs: make(map[string]codec.Codec),
CallOptions: CallOptions{ CallOptions: CallOptions{
Context: context.Background(),
Backoff: DefaultBackoff, Backoff: DefaultBackoff,
Retry: DefaultRetry, Retry: DefaultRetry,
Retries: DefaultRetries, Retries: DefaultRetries,
RequestTimeout: DefaultRequestTimeout, RequestTimeout: DefaultRequestTimeout,
DialTimeout: transport.DefaultDialTimeout, DialTimeout: transport.DefaultDialTimeout,
}, },
Lookup: LookupRoute, Lookup: LookupRoute,
PoolSize: DefaultPoolSize, PoolSize: DefaultPoolSize,
PoolTTL: DefaultPoolTTL, PoolTTL: DefaultPoolTTL,
Selector: random.NewSelector(), Selector: random.NewSelector(),
Logger: logger.DefaultLogger, Logger: logger.DefaultLogger,
Broker: broker.DefaultBroker, Broker: broker.DefaultBroker,
Meter: meter.DefaultMeter, Meter: meter.DefaultMeter,
Tracer: tracer.DefaultTracer, Tracer: tracer.DefaultTracer,
Router: router.DefaultRouter,
Transport: transport.DefaultTransport,
} }
for _, o := range opts { for _, o := range opts {
@@ -305,6 +321,22 @@ func Lookup(l LookupFunc) Option {
} }
} }
// TLSConfig specifies a *tls.Config
func TLSConfig(t *tls.Config) Option {
return func(o *Options) {
// set the internal tls
o.TLSConfig = t
// set the default transport if one is not
// already set. Required for Init call below.
// set the transport tls
o.Transport.Init(
transport.TLSConfig(t),
)
}
}
// Retries sets the retry count when making the request. // Retries sets the retry count when making the request.
func Retries(i int) Option { func Retries(i int) Option {
return func(o *Options) { return func(o *Options) {
@@ -347,6 +379,13 @@ func WithExchange(e string) PublishOption {
} }
} }
// WithBodyOnly publish only message body
func WithBodyOnly(b bool) PublishOption {
return func(o *PublishOptions) {
o.BodyOnly = b
}
}
// PublishContext sets the context in publish options // PublishContext sets the context in publish options
func PublishContext(ctx context.Context) PublishOption { func PublishContext(ctx context.Context) PublishOption {
return func(o *PublishOptions) { return func(o *PublishOptions) {
@@ -354,6 +393,13 @@ func PublishContext(ctx context.Context) PublishOption {
} }
} }
// WithContentType specifies call content type
func WithContentType(ct string) CallOption {
return func(o *CallOptions) {
o.ContentType = ct
}
}
// WithAddress sets the remote addresses to use rather than using service discovery // WithAddress sets the remote addresses to use rather than using service discovery
func WithAddress(a ...string) CallOption { func WithAddress(a ...string) CallOption {
return func(o *CallOptions) { return func(o *CallOptions) {
@@ -458,16 +504,16 @@ func WithMessageContentType(ct string) MessageOption {
} }
} }
// WithContentType specifies request content type // StreamingRequest specifies that request is streaming
func WithContentType(ct string) RequestOption { func StreamingRequest(b bool) RequestOption {
return func(o *RequestOptions) {
o.Stream = b
}
}
// RequestContentType specifies request content type
func RequestContentType(ct string) RequestOption {
return func(o *RequestOptions) { return func(o *RequestOptions) {
o.ContentType = ct o.ContentType = ct
} }
} }
// StreamingRequest specifies that request is streaming
func StreamingRequest() RequestOption {
return func(o *RequestOptions) {
o.Stream = true
}
}

View File

@@ -5,12 +5,12 @@ import (
) )
type testRequest struct { type testRequest struct {
codec codec.Codec
body interface{}
service string service string
method string method string
endpoint string endpoint string
contentType string contentType string
codec codec.Codec
body interface{}
opts RequestOptions opts RequestOptions
} }

View File

@@ -28,6 +28,8 @@ var (
DefaultMaxMsgSize int = 1024 * 1024 * 4 // 4Mb DefaultMaxMsgSize int = 1024 * 1024 * 4 // 4Mb
// DefaultCodec is the global default codec // DefaultCodec is the global default codec
DefaultCodec Codec = NewCodec() DefaultCodec Codec = NewCodec()
// DefaultTagName specifies struct tag name to control codec Marshal/Unmarshal
DefaultTagName = "codec"
) )
// MessageType specifies message type for codec // MessageType specifies message type for codec
@@ -51,16 +53,14 @@ type Codec interface {
// the communication, likely followed by the body. // the communication, likely followed by the body.
// In the case of an error, body may be nil. // In the case of an error, body may be nil.
type Message struct { type Message struct {
Id string Header metadata.Metadata
Type MessageType
Target string Target string
Method string Method string
Endpoint string Endpoint string
Error string Error string
Id string
// The values read from the socket Body []byte
Header metadata.Metadata Type MessageType
Body []byte
} }
// NewMessage creates new codec message // NewMessage creates new codec message

6
codec/frame.go Normal file
View File

@@ -0,0 +1,6 @@
package codec
// Frame gives us the ability to define raw data to send over the pipes
type Frame struct {
Data []byte
}

28
codec/frame.proto Normal file
View File

@@ -0,0 +1,28 @@
// Copyright 2021 Unistack LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
syntax = "proto3";
package micro.codec;
option cc_enable_arenas = true;
option go_package = "github.com/unistack-org/micro/v3/codec;codec";
option java_multiple_files = true;
option java_outer_classname = "MicroCodec";
option java_package = "micro.codec";
option objc_class_prefix = "MCODEC";
message Frame {
bytes data = 1;
}

View File

@@ -5,13 +5,7 @@ import (
"io" "io"
) )
type noopCodec struct { type noopCodec struct{}
}
// Frame gives us the ability to define raw data to send over the pipes
type Frame struct {
Data []byte
}
func (c *noopCodec) ReadHeader(conn io.Reader, m *Message, t MessageType) error { func (c *noopCodec) ReadHeader(conn io.Reader, m *Message, t MessageType) error {
return nil return nil

View File

@@ -11,10 +11,14 @@ type Option func(*Options)
// Options contains codec options // Options contains codec options
type Options struct { type Options struct {
// Meter used for metrics
Meter meter.Meter
// Logger used for logging
Logger logger.Logger
// Tracer used for tracing
Tracer tracer.Tracer
// MaxMsgSize specifies max messages size that reads by codec
MaxMsgSize int MaxMsgSize int
Meter meter.Meter
Logger logger.Logger
Tracer tracer.Tracer
} }
// MaxMsgSize sets the max message size // MaxMsgSize sets the max message size

View File

@@ -6,10 +6,8 @@ import (
"errors" "errors"
) )
var ( // DefaultConfig default config
// DefaultConfig default config var DefaultConfig Config = NewConfig()
DefaultConfig Config = NewConfig()
)
var ( var (
// ErrCodecMissing is returned when codec needed and not specified // ErrCodecMissing is returned when codec needed and not specified
@@ -22,25 +20,27 @@ var (
// Config is an interface abstraction for dynamic configuration // Config is an interface abstraction for dynamic configuration
type Config interface { type Config interface {
// Name returns name of config
Name() string Name() string
// Init the config // Init the config
Init(opts ...Option) error Init(opts ...Option) error
// Options in the config // Options in the config
Options() Options Options() Options
// Load config from sources // Load config from sources
Load(context.Context) error Load(context.Context, ...LoadOption) error
// Save config to sources // Save config to sources
Save(context.Context) error Save(context.Context, ...SaveOption) error
// Watch a value for changes // Watch a value for changes
// Watch(interface{}) (Watcher, error) //Watch(context.Context) (Watcher, error)
// String returns config type name
String() string String() string
} }
// Watcher is the config watcher // Watcher is the config watcher
//type Watcher interface { type Watcher interface {
// Next() (, error) // Next() (, error)
// Stop() error Stop() error
//} }
// Load loads config from config sources // Load loads config from config sources
func Load(ctx context.Context, cs ...Config) error { func Load(ctx context.Context, cs ...Config) error {

View File

@@ -25,18 +25,27 @@ func (c *defaultConfig) Init(opts ...Option) error {
return nil return nil
} }
func (c *defaultConfig) Load(ctx context.Context) error { func (c *defaultConfig) Load(ctx context.Context, opts ...LoadOption) error {
for _, fn := range c.opts.BeforeLoad { for _, fn := range c.opts.BeforeLoad {
if err := fn(ctx, c); err != nil && !c.opts.AllowFail { if err := fn(ctx, c); err != nil && !c.opts.AllowFail {
return err return err
} }
} }
options := NewLoadOptions(opts...)
mopts := []func(*mergo.Config){mergo.WithTypeCheck}
if options.Override {
mopts = append(mopts, mergo.WithOverride)
}
if options.Append {
mopts = append(mopts, mergo.WithAppendSlice)
}
src, err := rutil.Zero(c.opts.Struct) src, err := rutil.Zero(c.opts.Struct)
if err == nil { if err == nil {
valueOf := reflect.ValueOf(src) valueOf := reflect.ValueOf(src)
if err = c.fillValues(ctx, valueOf); err == nil { if err = c.fillValues(valueOf); err == nil {
err = mergo.Merge(c.opts.Struct, src, mergo.WithOverride, mergo.WithTypeCheck, mergo.WithAppendSlice) err = mergo.Merge(c.opts.Struct, src, mopts...)
} }
} }
@@ -54,7 +63,7 @@ func (c *defaultConfig) Load(ctx context.Context) error {
} }
//nolint:gocyclo //nolint:gocyclo
func (c *defaultConfig) fillValue(ctx context.Context, value reflect.Value, val string) error { func (c *defaultConfig) fillValue(value reflect.Value, val string) error {
if !rutil.IsEmpty(value) { if !rutil.IsEmpty(value) {
return nil return nil
} }
@@ -71,10 +80,10 @@ func (c *defaultConfig) fillValue(ctx context.Context, value reflect.Value, val
kv := strings.FieldsFunc(nval, func(c rune) bool { return c == '=' }) kv := strings.FieldsFunc(nval, func(c rune) bool { return c == '=' })
mkey := reflect.Indirect(reflect.New(kt)) mkey := reflect.Indirect(reflect.New(kt))
mval := reflect.Indirect(reflect.New(et)) mval := reflect.Indirect(reflect.New(et))
if err := c.fillValue(ctx, mkey, kv[0]); err != nil { if err := c.fillValue(mkey, kv[0]); err != nil {
return err return err
} }
if err := c.fillValue(ctx, mval, kv[1]); err != nil { if err := c.fillValue(mval, kv[1]); err != nil {
return err return err
} }
value.SetMapIndex(mkey, mval) value.SetMapIndex(mkey, mval)
@@ -84,7 +93,7 @@ func (c *defaultConfig) fillValue(ctx context.Context, value reflect.Value, val
value.Set(reflect.MakeSlice(reflect.SliceOf(value.Type().Elem()), len(nvals), len(nvals))) value.Set(reflect.MakeSlice(reflect.SliceOf(value.Type().Elem()), len(nvals), len(nvals)))
for idx, nval := range nvals { for idx, nval := range nvals {
nvalue := reflect.Indirect(reflect.New(value.Type().Elem())) nvalue := reflect.Indirect(reflect.New(value.Type().Elem()))
if err := c.fillValue(ctx, nvalue, nval); err != nil { if err := c.fillValue(nvalue, nval); err != nil {
return err return err
} }
value.Index(idx).Set(nvalue) value.Index(idx).Set(nvalue)
@@ -173,7 +182,7 @@ func (c *defaultConfig) fillValue(ctx context.Context, value reflect.Value, val
return nil return nil
} }
func (c *defaultConfig) fillValues(ctx context.Context, valueOf reflect.Value) error { func (c *defaultConfig) fillValues(valueOf reflect.Value) error {
var values reflect.Value var values reflect.Value
if valueOf.Kind() == reflect.Ptr { if valueOf.Kind() == reflect.Ptr {
@@ -200,7 +209,7 @@ func (c *defaultConfig) fillValues(ctx context.Context, valueOf reflect.Value) e
switch value.Kind() { switch value.Kind() {
case reflect.Struct: case reflect.Struct:
value.Set(reflect.Indirect(reflect.New(value.Type()))) value.Set(reflect.Indirect(reflect.New(value.Type())))
if err := c.fillValues(ctx, value); err != nil { if err := c.fillValues(value); err != nil {
return err return err
} }
continue continue
@@ -214,7 +223,7 @@ func (c *defaultConfig) fillValues(ctx context.Context, valueOf reflect.Value) e
value.Set(reflect.New(value.Type().Elem())) value.Set(reflect.New(value.Type().Elem()))
} }
value = value.Elem() value = value.Elem()
if err := c.fillValues(ctx, value); err != nil { if err := c.fillValues(value); err != nil {
return err return err
} }
continue continue
@@ -224,7 +233,7 @@ func (c *defaultConfig) fillValues(ctx context.Context, valueOf reflect.Value) e
continue continue
} }
if err := c.fillValue(ctx, value, tag); err != nil { if err := c.fillValue(value, tag); err != nil {
return err return err
} }
} }
@@ -232,7 +241,7 @@ func (c *defaultConfig) fillValues(ctx context.Context, valueOf reflect.Value) e
return nil return nil
} }
func (c *defaultConfig) Save(ctx context.Context) error { func (c *defaultConfig) Save(ctx context.Context, opts ...SaveOption) error {
for _, fn := range c.opts.BeforeSave { for _, fn := range c.opts.BeforeSave {
if err := fn(ctx, c); err != nil && !c.opts.AllowFail { if err := fn(ctx, c); err != nil && !c.opts.AllowFail {
return err return err

View File

@@ -10,30 +10,30 @@ import (
type Cfg struct { type Cfg struct {
StringValue string `default:"string_value"` StringValue string `default:"string_value"`
IntValue int `default:"99"`
IgnoreValue string `json:"-"` IgnoreValue string `json:"-"`
StructValue struct { StructValue struct {
StringValue string `default:"string_value"` StringValue string `default:"string_value"`
} }
IntValue int `default:"99"`
} }
func TestDefault(t *testing.T) { func TestDefault(t *testing.T) {
ctx := context.Background() ctx := context.Background()
conf := &Cfg{IntValue: 10} conf := &Cfg{IntValue: 10}
blfn := func(ctx context.Context, cfg config.Config) error { blfn := func(ctx context.Context, cfg config.Config) error {
conf, ok := cfg.Options().Struct.(*Cfg) nconf, ok := cfg.Options().Struct.(*Cfg)
if !ok { if !ok {
return fmt.Errorf("failed to get Struct from options: %v", cfg.Options()) return fmt.Errorf("failed to get Struct from options: %v", cfg.Options())
} }
conf.StringValue = "before_load" nconf.StringValue = "before_load"
return nil return nil
} }
alfn := func(ctx context.Context, cfg config.Config) error { alfn := func(ctx context.Context, cfg config.Config) error {
conf, ok := cfg.Options().Struct.(*Cfg) nconf, ok := cfg.Options().Struct.(*Cfg)
if !ok { if !ok {
return fmt.Errorf("failed to get Struct from options: %v", cfg.Options()) return fmt.Errorf("failed to get Struct from options: %v", cfg.Options())
} }
conf.StringValue = "after_load" nconf.StringValue = "after_load"
return nil return nil
} }

View File

@@ -11,26 +11,32 @@ import (
// Options hold the config options // Options hold the config options
type Options struct { type Options struct {
Name string // Struct holds the destination config struct
AllowFail bool
BeforeLoad []func(context.Context, Config) error
AfterLoad []func(context.Context, Config) error
BeforeSave []func(context.Context, Config) error
AfterSave []func(context.Context, Config) error
// Struct that holds config data
Struct interface{} Struct interface{}
// StructTag name
StructTag string
// Logger that will be used
Logger logger.Logger
// Meter that will be used
Meter meter.Meter
// Tracer used for trace
Tracer tracer.Tracer
// Codec that used for load/save // Codec that used for load/save
Codec codec.Codec Codec codec.Codec
// Context for alternative data // Tracer that will be used
Tracer tracer.Tracer
// Meter that will be used
Meter meter.Meter
// Logger that will be used
Logger logger.Logger
// Context used for external options
Context context.Context Context context.Context
// Name of the config
Name string
// StructTag name
StructTag string
// BeforeSave contains slice of funcs that runs before save
BeforeSave []func(context.Context, Config) error
// AfterLoad contains slice of funcs that runs after load
AfterLoad []func(context.Context, Config) error
// BeforeLoad contains slice of funcs that runs before load
BeforeLoad []func(context.Context, Config) error
// AfterSave contains slice of funcs that runs after save
AfterSave []func(context.Context, Config) error
// AllowFail flag to allow fail in config source
AllowFail bool
} }
// Option function signature // Option function signature
@@ -51,6 +57,52 @@ func NewOptions(opts ...Option) Options {
return options return options
} }
// LoadOption function signature
type LoadOption func(o *LoadOptions)
// LoadOptions struct
type LoadOptions struct {
Override bool
Append bool
}
func NewLoadOptions(opts ...LoadOption) LoadOptions {
options := LoadOptions{}
for _, o := range opts {
o(&options)
}
return options
}
// LoadOverride override values when load
func LoadOverride(b bool) LoadOption {
return func(o *LoadOptions) {
o.Override = b
}
}
// LoadAppend override values when load
func LoadAppend(b bool) LoadOption {
return func(o *LoadOptions) {
o.Append = b
}
}
// SaveOption function signature
type SaveOption func(o *SaveOptions)
// SaveOptions struct
type SaveOptions struct {
}
func NewSaveOptions(opts ...SaveOption) SaveOptions {
options := SaveOptions{}
for _, o := range opts {
o(&options)
}
return options
}
// AllowFail allows config source to fail // AllowFail allows config source to fail
func AllowFail(b bool) Option { func AllowFail(b bool) Option {
return func(o *Options) { return func(o *Options) {

View File

@@ -7,9 +7,9 @@ import (
) )
type Config struct { type Config struct {
Value string
SubConfig *SubConfig SubConfig *SubConfig
Config *Config Config *Config
Value string
} }
type SubConfig struct { type SubConfig struct {

View File

@@ -37,10 +37,14 @@ var (
// Error type // Error type
type Error struct { type Error struct {
Id string // Id holds error id or service, usually someting like my_service or uuid
Code int32 Id string
// Detail holds some useful details about error
Detail string Detail string
// Status usually holds text of http status
Status string Status string
// Code holds error code
Code int32
} }
// Error satisfies error interface // Error satisfies error interface
@@ -49,7 +53,7 @@ func (e *Error) Error() string {
return string(b) return string(b)
} }
// New generates a custom error. // New generates a custom error
func New(id, detail string, code int32) error { func New(id, detail string, code int32) error {
return &Error{ return &Error{
Id: id, Id: id,

View File

@@ -17,7 +17,6 @@ func TestFromError(t *testing.T) {
if merr.Id != "go.micro.test" || merr.Code != 404 { if merr.Id != "go.micro.test" || merr.Code != 404 {
t.Fatalf("invalid conversation %v != %v", err, merr) t.Fatalf("invalid conversation %v != %v", err, merr)
} }
} }
func TestEqual(t *testing.T) { func TestEqual(t *testing.T) {
@@ -32,7 +31,6 @@ func TestEqual(t *testing.T) {
if Equal(err1, err3) { if Equal(err1, err3) {
t.Fatal("errors must be not equal") t.Fatal("errors must be not equal")
} }
} }
func TestErrors(t *testing.T) { func TestErrors(t *testing.T) {

View File

@@ -44,10 +44,10 @@ func TestDag(t *testing.T) {
var steps [][]string var steps [][]string
fn := func(n dag.Vertex, idx int) error { fn := func(n dag.Vertex, idx int) error {
if idx == 0 { if idx == 0 {
steps = make([][]string, 1, 1) steps = make([][]string, 1)
steps[0] = make([]string, 0, 1) steps[0] = make([]string, 0, 1)
} else if idx >= len(steps) { } else if idx >= len(steps) {
tsteps := make([][]string, idx+1, idx+1) tsteps := make([][]string, idx+1)
copy(tsteps, steps) copy(tsteps, steps)
steps = tsteps steps = tsteps
steps[idx] = make([]string, 0, 1) steps[idx] = make([]string, 0, 1)

View File

@@ -1,7 +1,17 @@
// Package flow is an interface used for saga pattern messaging // Package flow is an interface used for saga pattern microservice workflow
package flow package flow
type Step interface { type Step interface {
// Endpoint returns service_name.service_method // Endpoint returns rpc endpoint service_name.service_method or broker topic
Endpoint() string Endpoint() string
} }
type Workflow interface {
Steps() [][]Step
Stop() error
}
type Flow interface {
Start(Workflow) error
Stop(Workflow)
}

View File

@@ -1,3 +0,0 @@
package micro
//go:generate ./.github/generate.sh

4
go.mod
View File

@@ -6,8 +6,8 @@ require (
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 github.com/ef-ds/deque v1.0.4
github.com/google/uuid v1.2.0 github.com/google/uuid v1.2.0
github.com/imdario/mergo v0.3.11 github.com/imdario/mergo v0.3.12
github.com/patrickmn/go-cache v2.1.0+incompatible github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/silas/dag v0.0.0-20210121180416-41cf55125c34 github.com/silas/dag v0.0.0-20210121180416-41cf55125c34
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 golang.org/x/net v0.0.0-20210510120150-4163338589ed
) )

11
go.sum
View File

@@ -4,17 +4,18 @@ github.com/ef-ds/deque v1.0.4 h1:iFAZNmveMT9WERAkqLJ+oaABF9AcVQ5AjXem/hroniI=
github.com/ef-ds/deque v1.0.4/go.mod h1:gXDnTC3yqvBcHbq2lcExjtAcVrOnJCbMcZXmuj8Z4tg= github.com/ef-ds/deque v1.0.4/go.mod h1:gXDnTC3yqvBcHbq2lcExjtAcVrOnJCbMcZXmuj8Z4tg=
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/silas/dag v0.0.0-20210121180416-41cf55125c34 h1:vBfVmA5mZhsQa2jr1FOL9nfA37N/jnbBmi5XUfviVTI= github.com/silas/dag v0.0.0-20210121180416-41cf55125c34 h1:vBfVmA5mZhsQa2jr1FOL9nfA37N/jnbBmi5XUfviVTI=
github.com/silas/dag v0.0.0-20210121180416-41cf55125c34/go.mod h1:7RTUFBdIRC9nZ7/3RyRNH1bdqIShrDejd1YbLwgPS+I= github.com/silas/dag v0.0.0-20210121180416-41cf55125c34/go.mod h1:7RTUFBdIRC9nZ7/3RyRNH1bdqIShrDejd1YbLwgPS+I=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= golang.org/x/net v0.0.0-20210510120150-4163338589ed h1:p9UgmWI9wKpfYmgaV/IZKGdXc5qEK45tDwwwDyjS26I=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
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=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=

View File

@@ -21,9 +21,9 @@ func init() {
} }
type defaultLogger struct { type defaultLogger struct {
sync.RWMutex
opts Options
enc *json.Encoder enc *json.Encoder
opts Options
sync.RWMutex
} }
// Init(opts...) should only overwrite provided options // Init(opts...) should only overwrite provided options
@@ -49,10 +49,18 @@ func (l *defaultLogger) V(level Level) bool {
} }
func (l *defaultLogger) Fields(fields map[string]interface{}) Logger { func (l *defaultLogger) Fields(fields map[string]interface{}) Logger {
l.Lock() nl := &defaultLogger{opts: l.opts, enc: l.enc}
l.opts.Fields = copyFields(fields) nl.opts.Fields = make(map[string]interface{}, len(l.opts.Fields)+len(fields))
l.Unlock() l.RLock()
return l for k, v := range l.opts.Fields {
nl.opts.Fields[k] = v
}
l.RUnlock()
for k, v := range fields {
nl.opts.Fields[k] = v
}
return nl
} }
func copyFields(src map[string]interface{}) map[string]interface{} { func copyFields(src map[string]interface{}) map[string]interface{} {
@@ -153,7 +161,9 @@ func (l *defaultLogger) Log(ctx context.Context, level Level, args ...interface{
} }
fields["timestamp"] = time.Now().Format("2006-01-02 15:04:05") fields["timestamp"] = time.Now().Format("2006-01-02 15:04:05")
fields["msg"] = fmt.Sprint(args...) if len(args) > 0 {
fields["msg"] = fmt.Sprint(args...)
}
l.RLock() l.RLock()
_ = l.enc.Encode(fields) _ = l.enc.Encode(fields)
@@ -178,7 +188,7 @@ func (l *defaultLogger) Logf(ctx context.Context, level Level, msg string, args
fields["timestamp"] = time.Now().Format("2006-01-02 15:04:05") fields["timestamp"] = time.Now().Format("2006-01-02 15:04:05")
if len(args) > 0 { if len(args) > 0 {
fields["msg"] = fmt.Sprintf(msg, args...) fields["msg"] = fmt.Sprintf(msg, args...)
} else { } else if msg != "" {
fields["msg"] = msg fields["msg"] = msg
} }
l.RLock() l.RLock()

View File

@@ -11,17 +11,18 @@ type Option func(*Options)
// Options holds logger options // Options holds logger options
type Options struct { type Options struct {
Name string // Out holds the output writer
// The logging level the logger should log at. default is `InfoLevel`
Level Level
// fields to always be logged
Fields map[string]interface{}
// It's common to set this to a file, or leave it default which is `os.Stderr`
Out io.Writer Out io.Writer
// Caller skip frame count for file:line info // Context holds exernal options
CallerSkipCount int
// Alternative options
Context context.Context Context context.Context
// Fields holds additional metadata
Fields map[string]interface{}
// Name holds the logger name
Name string
// CallerSkipCount number of frmaes to skip
CallerSkipCount int
// The logging level the logger should log
Level Level
} }
// NewOptions creates new options struct // NewOptions creates new options struct
@@ -75,7 +76,7 @@ func WithContext(ctx context.Context) Option {
} }
// WithName sets the name // WithName sets the name
func withName(n string) Option { func WithName(n string) Option {
return func(o *Options) { return func(o *Options) {
o.Name = n o.Name = n
} }

410
logger/wrapper/wrapper.go Normal file
View File

@@ -0,0 +1,410 @@
// Package wrapper provides wrapper for Logger
package wrapper
import (
"context"
"fmt"
"github.com/unistack-org/micro/v3/client"
"github.com/unistack-org/micro/v3/logger"
"github.com/unistack-org/micro/v3/server"
)
var (
DefaultClientCallObserver = func(ctx context.Context, req client.Request, rsp interface{}, opts []client.CallOption, err error) []string {
labels := []string{"service", req.Service(), "endpoint", req.Endpoint()}
if err != nil {
labels = append(labels, "error", err.Error())
}
return labels
}
DefaultClientStreamObserver = func(ctx context.Context, req client.Request, opts []client.CallOption, stream client.Stream, err error) []string {
labels := []string{"service", req.Service(), "endpoint", req.Endpoint()}
if err != nil {
labels = append(labels, "error", err.Error())
}
return labels
}
DefaultClientPublishObserver = func(ctx context.Context, msg client.Message, opts []client.PublishOption, err error) []string {
labels := []string{"endpoint", msg.Topic()}
if err != nil {
labels = append(labels, "error", err.Error())
}
return labels
}
DefaultServerHandlerObserver = func(ctx context.Context, req server.Request, rsp interface{}, err error) []string {
labels := []string{"service", req.Service(), "endpoint", req.Endpoint()}
if err != nil {
labels = append(labels, "error", err.Error())
}
return labels
}
DefaultServerSubscriberObserver = func(ctx context.Context, msg server.Message, err error) []string {
labels := []string{"endpoint", msg.Topic()}
if err != nil {
labels = append(labels, "error", err.Error())
}
return labels
}
DefaultClientCallFuncObserver = func(ctx context.Context, addr string, req client.Request, rsp interface{}, opts client.CallOptions, err error) []string {
labels := []string{"service", req.Service(), "endpoint", req.Endpoint()}
if err != nil {
labels = append(labels, "error", err.Error())
}
return labels
}
DefaultSkipEndpoints = []string{"Meter.Metrics"}
)
type lWrapper struct {
client.Client
serverHandler server.HandlerFunc
serverSubscriber server.SubscriberFunc
clientCallFunc client.CallFunc
opts Options
}
type (
ClientCallObserver func(context.Context, client.Request, interface{}, []client.CallOption, error) []string
ClientStreamObserver func(context.Context, client.Request, []client.CallOption, client.Stream, error) []string
ClientPublishObserver func(context.Context, client.Message, []client.PublishOption, error) []string
ClientCallFuncObserver func(context.Context, string, client.Request, interface{}, client.CallOptions, error) []string
ServerHandlerObserver func(context.Context, server.Request, interface{}, error) []string
ServerSubscriberObserver func(context.Context, server.Message, error) []string
)
// Options struct for wrapper
type Options struct {
// Logger that used for log
Logger logger.Logger
// ServerHandlerObservers funcs
ServerHandlerObservers []ServerHandlerObserver
// ServerSubscriberObservers funcs
ServerSubscriberObservers []ServerSubscriberObserver
// ClientCallObservers funcs
ClientCallObservers []ClientCallObserver
// ClientStreamObservers funcs
ClientStreamObservers []ClientStreamObserver
// ClientPublishObservers funcs
ClientPublishObservers []ClientPublishObserver
// ClientCallFuncObservers funcs
ClientCallFuncObservers []ClientCallFuncObserver
// SkipEndpoints
SkipEndpoints []string
// Level for logger
Level logger.Level
// Enabled flag
Enabled bool
}
// Option func signature
type Option func(*Options)
// NewOptions creates Options from Option slice
func NewOptions(opts ...Option) Options {
options := Options{
Logger: logger.DefaultLogger,
Level: logger.TraceLevel,
ClientCallObservers: []ClientCallObserver{DefaultClientCallObserver},
ClientStreamObservers: []ClientStreamObserver{DefaultClientStreamObserver},
ClientPublishObservers: []ClientPublishObserver{DefaultClientPublishObserver},
ClientCallFuncObservers: []ClientCallFuncObserver{DefaultClientCallFuncObserver},
ServerHandlerObservers: []ServerHandlerObserver{DefaultServerHandlerObserver},
ServerSubscriberObservers: []ServerSubscriberObserver{DefaultServerSubscriberObserver},
SkipEndpoints: DefaultSkipEndpoints,
}
for _, o := range opts {
o(&options)
}
return options
}
// WithEnabled enable/diable flag
func WithEnabled(b bool) Option {
return func(o *Options) {
o.Enabled = b
}
}
// WithLevel log level
func WithLevel(l logger.Level) Option {
return func(o *Options) {
o.Level = l
}
}
// WithLogger logger
func WithLogger(l logger.Logger) Option {
return func(o *Options) {
o.Logger = l
}
}
// WithClientCallObservers funcs
func WithClientCallObservers(ob ...ClientCallObserver) Option {
return func(o *Options) {
o.ClientCallObservers = ob
}
}
// WithClientStreamObservers funcs
func WithClientStreamObservers(ob ...ClientStreamObserver) Option {
return func(o *Options) {
o.ClientStreamObservers = ob
}
}
// WithClientPublishObservers funcs
func WithClientPublishObservers(ob ...ClientPublishObserver) Option {
return func(o *Options) {
o.ClientPublishObservers = ob
}
}
// WithClientCallFuncObservers funcs
func WithClientCallFuncObservers(ob ...ClientCallFuncObserver) Option {
return func(o *Options) {
o.ClientCallFuncObservers = ob
}
}
// WithServerHandlerObservers funcs
func WithServerHandlerObservers(ob ...ServerHandlerObserver) Option {
return func(o *Options) {
o.ServerHandlerObservers = ob
}
}
// WithServerSubscriberObservers funcs
func WithServerSubscriberObservers(ob ...ServerSubscriberObserver) Option {
return func(o *Options) {
o.ServerSubscriberObservers = ob
}
}
// SkipEndpoins
func SkipEndpoints(eps ...string) Option {
return func(o *Options) {
o.SkipEndpoints = append(o.SkipEndpoints, eps...)
}
}
func (l *lWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
err := l.Client.Call(ctx, req, rsp, opts...)
endpoint := fmt.Sprintf("%s.%s", req.Service(), req.Endpoint())
for _, ep := range l.opts.SkipEndpoints {
if ep == endpoint {
return err
}
}
if !l.opts.Enabled {
return err
}
var labels []string
for _, o := range l.opts.ClientCallObservers {
labels = append(labels, o(ctx, req, rsp, opts, err)...)
}
fields := make(map[string]interface{}, len(labels)/2)
for i := 0; i < len(labels); i += 2 {
fields[labels[i]] = labels[i+1]
}
l.opts.Logger.Fields(fields).Log(ctx, l.opts.Level)
return err
}
func (l *lWrapper) Stream(ctx context.Context, req client.Request, opts ...client.CallOption) (client.Stream, error) {
stream, err := l.Client.Stream(ctx, req, opts...)
endpoint := fmt.Sprintf("%s.%s", req.Service(), req.Endpoint())
for _, ep := range l.opts.SkipEndpoints {
if ep == endpoint {
return stream, err
}
}
if !l.opts.Enabled {
return stream, err
}
var labels []string
for _, o := range l.opts.ClientStreamObservers {
labels = append(labels, o(ctx, req, opts, stream, err)...)
}
fields := make(map[string]interface{}, len(labels)/2)
for i := 0; i < len(labels); i += 2 {
fields[labels[i]] = labels[i+1]
}
l.opts.Logger.Fields(fields).Log(ctx, l.opts.Level)
return stream, err
}
func (l *lWrapper) Publish(ctx context.Context, msg client.Message, opts ...client.PublishOption) error {
err := l.Client.Publish(ctx, msg, opts...)
endpoint := msg.Topic()
for _, ep := range l.opts.SkipEndpoints {
if ep == endpoint {
return err
}
}
if !l.opts.Enabled {
return err
}
var labels []string
for _, o := range l.opts.ClientPublishObservers {
labels = append(labels, o(ctx, msg, opts, err)...)
}
fields := make(map[string]interface{}, len(labels)/2)
for i := 0; i < len(labels); i += 2 {
fields[labels[i]] = labels[i+1]
}
l.opts.Logger.Fields(fields).Log(ctx, l.opts.Level)
return err
}
func (l *lWrapper) ServerHandler(ctx context.Context, req server.Request, rsp interface{}) error {
err := l.serverHandler(ctx, req, rsp)
endpoint := req.Endpoint()
for _, ep := range l.opts.SkipEndpoints {
if ep == endpoint {
return err
}
}
if !l.opts.Enabled {
return err
}
var labels []string
for _, o := range l.opts.ServerHandlerObservers {
labels = append(labels, o(ctx, req, rsp, err)...)
}
fields := make(map[string]interface{}, len(labels)/2)
for i := 0; i < len(labels); i += 2 {
fields[labels[i]] = labels[i+1]
}
l.opts.Logger.Fields(fields).Log(ctx, l.opts.Level)
return err
}
func (l *lWrapper) ServerSubscriber(ctx context.Context, msg server.Message) error {
err := l.serverSubscriber(ctx, msg)
endpoint := msg.Topic()
for _, ep := range l.opts.SkipEndpoints {
if ep == endpoint {
return err
}
}
if !l.opts.Enabled {
return err
}
var labels []string
for _, o := range l.opts.ServerSubscriberObservers {
labels = append(labels, o(ctx, msg, err)...)
}
fields := make(map[string]interface{}, len(labels)/2)
for i := 0; i < len(labels); i += 2 {
fields[labels[i]] = labels[i+1]
}
l.opts.Logger.Fields(fields).Log(ctx, l.opts.Level)
return err
}
// NewClientWrapper accepts an open options and returns a Client Wrapper
func NewClientWrapper(opts ...Option) client.Wrapper {
return func(c client.Client) client.Client {
options := NewOptions()
for _, o := range opts {
o(&options)
}
return &lWrapper{opts: options, Client: c}
}
}
// NewClientCallWrapper accepts an options and returns a Call Wrapper
func NewClientCallWrapper(opts ...Option) client.CallWrapper {
return func(h client.CallFunc) client.CallFunc {
options := NewOptions()
for _, o := range opts {
o(&options)
}
l := &lWrapper{opts: options, clientCallFunc: h}
return l.ClientCallFunc
}
}
func (l *lWrapper) ClientCallFunc(ctx context.Context, addr string, req client.Request, rsp interface{}, opts client.CallOptions) error {
err := l.clientCallFunc(ctx, addr, req, rsp, opts)
endpoint := fmt.Sprintf("%s.%s", req.Service(), req.Endpoint())
for _, ep := range l.opts.SkipEndpoints {
if ep == endpoint {
return err
}
}
if !l.opts.Enabled {
return err
}
var labels []string
for _, o := range l.opts.ClientCallFuncObservers {
labels = append(labels, o(ctx, addr, req, rsp, opts, err)...)
}
fields := make(map[string]interface{}, len(labels)/2)
for i := 0; i < len(labels); i += 2 {
fields[labels[i]] = labels[i+1]
}
l.opts.Logger.Fields(fields).Log(ctx, l.opts.Level)
return err
}
// NewServerHandlerWrapper accepts an options and returns a Handler Wrapper
func NewServerHandlerWrapper(opts ...Option) server.HandlerWrapper {
return func(h server.HandlerFunc) server.HandlerFunc {
options := NewOptions()
for _, o := range opts {
o(&options)
}
l := &lWrapper{opts: options, serverHandler: h}
return l.ServerHandler
}
}
// NewServerSubscriberWrapper accepts an options and returns a Subscriber Wrapper
func NewServerSubscriberWrapper(opts ...Option) server.SubscriberWrapper {
return func(h server.SubscriberFunc) server.SubscriberFunc {
options := NewOptions()
for _, o := range opts {
o(&options)
}
l := &lWrapper{opts: options, serverSubscriber: h}
return l.ServerSubscriber
}
}

View File

@@ -5,9 +5,11 @@ import (
"context" "context"
) )
type mdIncomingKey struct{} type (
type mdOutgoingKey struct{} mdIncomingKey struct{}
type mdKey struct{} mdOutgoingKey struct{}
mdKey struct{}
)
// FromIncomingContext returns metadata from incoming ctx // FromIncomingContext returns metadata from incoming ctx
// returned metadata shoud not be modified or race condition happens // returned metadata shoud not be modified or race condition happens

View File

@@ -6,10 +6,8 @@ import (
"sort" "sort"
) )
var ( // HeaderPrefix for all headers passed
// HeaderPrefix for all headers passed var HeaderPrefix = "Micro-"
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
@@ -20,17 +18,15 @@ type rawMetadata struct {
md Metadata md Metadata
} }
var ( // defaultMetadataSize used when need to init new Metadata
// defaultMetadataSize used when need to init new Metadata var defaultMetadataSize = 2
defaultMetadataSize = 2
)
// Iterator used to iterate over metadata with order // Iterator used to iterate over metadata with order
type Iterator struct { type Iterator struct {
md Metadata
keys []string
cur int cur int
cnt int cnt int
keys []string
md Metadata
} }
// Next advance iterator to next element // Next advance iterator to next element
@@ -112,6 +108,7 @@ func Merge(omd Metadata, mmd Metadata, overwrite bool) Metadata {
return nmd return nmd
} }
// Pairs from which metadata created
func Pairs(kv ...string) (Metadata, bool) { func Pairs(kv ...string) (Metadata, bool) {
if len(kv)%2 == 1 { if len(kv)%2 == 1 {
return nil, false return nil, false

View File

@@ -76,7 +76,7 @@ func TestIterator(t *testing.T) {
var k, v string var k, v string
for iter.Next(&k, &v) { for iter.Next(&k, &v) {
//fmt.Printf("k: %s, v: %s\n", k, v) // fmt.Printf("k: %s, v: %s\n", k, v)
} }
} }
@@ -102,7 +102,6 @@ func TestMedataCanonicalKey(t *testing.T) {
} 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)
} }
} }
func TestMetadataSet(t *testing.T) { func TestMetadataSet(t *testing.T) {
@@ -130,7 +129,6 @@ func TestMetadataDelete(t *testing.T) {
if ok { if ok {
t.Fatal("key Baz not deleted") t.Fatal("key Baz not deleted")
} }
} }
func TestNilContext(t *testing.T) { func TestNilContext(t *testing.T) {

3
meter/generate.go Normal file
View File

@@ -0,0 +1,3 @@
package meter
//go:generate protoc -I./handler -I../ -I/home/vtolstov/.cache/go-path/pkg/mod/github.com/unistack-org/micro-proto@v0.0.1 --micro_out=components=micro|http|server,standalone=false,debug=true,paths=source_relative:./handler handler/handler.proto

67
meter/handler/handler.go Normal file
View File

@@ -0,0 +1,67 @@
package handler
import (
"bytes"
"context"
"github.com/unistack-org/micro/v3/codec"
"github.com/unistack-org/micro/v3/errors"
"github.com/unistack-org/micro/v3/meter"
)
// guard to fail early
var _ MeterServer = &Handler{}
type Handler struct {
opts Options
}
type Option func(*Options)
type Options struct {
Meter meter.Meter
Name string
MeterOptions []meter.Option
}
func Meter(m meter.Meter) Option {
return func(o *Options) {
o.Meter = m
}
}
func Name(name string) Option {
return func(o *Options) {
o.Name = name
}
}
func MeterOptions(opts ...meter.Option) Option {
return func(o *Options) {
o.MeterOptions = append(o.MeterOptions, opts...)
}
}
func NewOptions(opts ...Option) Options {
options := Options{Meter: meter.DefaultMeter}
for _, o := range opts {
o(&options)
}
return options
}
func NewHandler(opts ...Option) *Handler {
options := NewOptions(opts...)
return &Handler{opts: options}
}
func (h *Handler) Metrics(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error {
buf := bytes.NewBuffer(nil)
if err := h.opts.Meter.Write(buf, h.opts.MeterOptions...); err != nil {
return errors.InternalServerError(h.opts.Name, "%v", err)
}
rsp.Data = buf.Bytes()
return nil
}

View File

@@ -0,0 +1,28 @@
syntax = "proto3";
package micro.meter.handler;
option go_package = "github.com/unistack-org/micro/v3/meter/handler;handler";
import "api/annotations.proto";
import "openapiv2/annotations.proto";
import "codec/frame.proto";
service Meter {
rpc Metrics(micro.codec.Frame) returns (micro.codec.Frame) {
option (micro.openapiv2.openapiv2_operation) = {
operation_id: "Metrics";
responses: {
key: "default";
value: {
description: "Error response";
schema: {
json_schema: {
ref: "micro.codec.Frame";
}
}
}
}
};
option (micro.api.http) = { get: "/metrics"; };
};
};

View File

@@ -0,0 +1,24 @@
// Code generated by protoc-gen-micro
// source: handler.proto
package handler
import (
context "context"
api "github.com/unistack-org/micro/v3/api"
codec "github.com/unistack-org/micro/v3/codec"
)
func NewMeterEndpoints() []*api.Endpoint {
return []*api.Endpoint{
&api.Endpoint{
Name: "Meter.Metrics",
Path: []string{"/metrics"},
Method: []string{"GET"},
Handler: "rpc",
},
}
}
type MeterServer interface {
Metrics(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error
}

View File

@@ -0,0 +1,33 @@
// Code generated by protoc-gen-micro
// source: handler.proto
package handler
import (
context "context"
api "github.com/unistack-org/micro/v3/api"
codec "github.com/unistack-org/micro/v3/codec"
server "github.com/unistack-org/micro/v3/server"
)
type meterServer struct {
MeterServer
}
func (h *meterServer) Metrics(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error {
return h.MeterServer.Metrics(ctx, req, rsp)
}
func RegisterMeterServer(s server.Server, sh MeterServer, opts ...server.HandlerOption) error {
type meter interface {
Metrics(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error
}
type Meter struct {
meter
}
h := &meterServer{sh}
var nopts []server.HandlerOption
for _, endpoint := range NewMeterEndpoints() {
nopts = append(nopts, api.WithEndpoint(endpoint))
}
return s.Handle(s.NewHandler(&Meter{h}, append(nopts, opts...)...))
}

View File

@@ -3,6 +3,7 @@ package meter
import ( import (
"io" "io"
"reflect"
"sort" "sort"
"time" "time"
) )
@@ -28,13 +29,13 @@ var (
type Meter interface { type Meter interface {
Name() string Name() string
Init(opts ...Option) error Init(opts ...Option) error
Counter(name string, opts ...Option) Counter Counter(name string, labels ...string) Counter
FloatCounter(name string, opts ...Option) FloatCounter FloatCounter(name string, labels ...string) FloatCounter
Gauge(name string, fn func() float64, opts ...Option) Gauge Gauge(name string, fn func() float64, labels ...string) Gauge
Set(opts ...Option) Meter Set(opts ...Option) Meter
Histogram(name string, opts ...Option) Histogram Histogram(name string, labels ...string) Histogram
Summary(name string, opts ...Option) Summary Summary(name string, labels ...string) Summary
SummaryExt(name string, window time.Duration, quantiles []float64, opts ...Option) Summary SummaryExt(name string, window time.Duration, quantiles []float64, labels ...string) Summary
Write(w io.Writer, opts ...Option) error Write(w io.Writer, opts ...Option) error
Options() Options Options() Options
String() string String() string
@@ -76,66 +77,36 @@ type Summary interface {
UpdateDuration(time.Time) UpdateDuration(time.Time)
} }
// Labels holds the metrics labels with k, v type byKey []string
type Labels struct {
keys []string func (k byKey) Len() int { return len(k) / 2 }
vals []string func (k byKey) Less(i, j int) bool { return k[i*2] < k[j*2] }
func (k byKey) Swap(i, j int) {
k[i*2], k[i*2+1], k[j*2], k[j*2+1] = k[j*2], k[j*2+1], k[i*2], k[i*2+1]
} }
// Append adds labels to label set func Sort(slice *[]string) {
func (ls Labels) Append(nls Labels) Labels { bk := byKey(*slice)
for n := range nls.keys { if bk.Len() <= 1 {
ls.keys = append(ls.keys, nls.keys[n]) return
ls.vals = append(ls.vals, nls.vals[n])
} }
return ls sort.Sort(bk)
} v := reflect.ValueOf(slice).Elem()
cnt := 0
// Len returns number of labels key := 0
func (ls Labels) Len() int { val := 1
return len(ls.keys) for key < v.Len() {
} if len(bk) > key+2 && bk[key] == bk[key+2] {
key += 2
type labels Labels val += 2
continue
func (ls labels) Len() int { }
return len(ls.keys) v.Index(cnt).Set(v.Index(key))
} cnt++
v.Index(cnt).Set(v.Index(val))
func (ls labels) Sort() { cnt++
sort.Sort(ls) key += 2
} val += 2
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.keys[i] < ls.keys[j]
}
// LabelIter holds the
type LabelIter struct {
labels Labels
cnt int
cur int
}
// Iter returns labels iterator
func (ls Labels) Iter() *LabelIter {
labels(ls).Sort()
return &LabelIter{labels: ls, cnt: len(ls.keys)}
}
// Next advance itarator to new pos
func (iter *LabelIter) Next(k, v *string) bool {
if iter.cur+1 > iter.cnt {
return false
} }
v.SetLen(cnt)
*k = iter.labels.keys[iter.cur]
*v = iter.labels.vals[iter.cur]
iter.cur++
return true
} }

View File

@@ -10,46 +10,15 @@ func TestNoopMeter(t *testing.T) {
t.Fatalf("invalid options parsing: %v", m.Options()) t.Fatalf("invalid options parsing: %v", m.Options())
} }
cnt := m.Counter("counter", Label("server", "noop")) cnt := m.Counter("counter", "server", "noop")
cnt.Inc() cnt.Inc()
} }
func TestLabelsAppend(t *testing.T) { func TestLabelsSort(t *testing.T) {
var ls Labels ls := []string{"server", "http", "register", "mdns", "broker", "broker1", "broker", "broker2", "server", "tcp"}
ls.keys = []string{"type", "server"} Sort(&ls)
ls.vals = []string{"noop", "http"}
var nls Labels if ls[0] != "broker" || ls[1] != "broker2" {
nls.keys = []string{"register"} t.Fatalf("sort error: %v", ls)
nls.vals = []string{"gossip"}
ls = ls.Append(nls)
//ls.Sort()
if ls.keys[0] != "type" || ls.vals[0] != "noop" {
t.Fatalf("append error: %v", ls)
}
}
func TestIterator(t *testing.T) {
options := NewOptions(
Label("name", "svc1"),
Label("version", "0.0.1"),
Label("id", "12345"),
Label("type", "noop"),
Label("server", "http"),
Label("register", "gossip"),
Label("aa", "kk"),
Label("zz", "kk"),
)
iter := options.Labels.Iter()
var k, v string
cnt := 0
for iter.Next(&k, &v) {
if cnt == 4 && (k != "server" || v != "http") {
t.Fatalf("iter error: %s != %s || %s != %s", k, "server", v, "http")
}
cnt++
} }
} }

View File

@@ -28,57 +28,33 @@ func (r *noopMeter) Init(opts ...Option) error {
} }
// Counter implements the Meter interface // Counter implements the Meter interface
func (r *noopMeter) Counter(name string, opts ...Option) Counter { func (r *noopMeter) Counter(name string, labels ...string) Counter {
options := Options{} return &noopCounter{labels: labels}
for _, o := range opts {
o(&options)
}
return &noopCounter{labels: options.Labels}
} }
// FloatCounter implements the Meter interface // FloatCounter implements the Meter interface
func (r *noopMeter) FloatCounter(name string, opts ...Option) FloatCounter { func (r *noopMeter) FloatCounter(name string, labels ...string) FloatCounter {
options := Options{} return &noopFloatCounter{labels: labels}
for _, o := range opts {
o(&options)
}
return &noopFloatCounter{labels: options.Labels}
} }
// Gauge implements the Meter interface // Gauge implements the Meter interface
func (r *noopMeter) Gauge(name string, f func() float64, opts ...Option) Gauge { func (r *noopMeter) Gauge(name string, f func() float64, labels ...string) Gauge {
options := Options{} return &noopGauge{labels: labels}
for _, o := range opts {
o(&options)
}
return &noopGauge{labels: options.Labels}
} }
// Summary implements the Meter interface // Summary implements the Meter interface
func (r *noopMeter) Summary(name string, opts ...Option) Summary { func (r *noopMeter) Summary(name string, labels ...string) Summary {
options := Options{} return &noopSummary{labels: labels}
for _, o := range opts {
o(&options)
}
return &noopSummary{labels: options.Labels}
} }
// SummaryExt implements the Meter interface // SummaryExt implements the Meter interface
func (r *noopMeter) SummaryExt(name string, window time.Duration, quantiles []float64, opts ...Option) Summary { func (r *noopMeter) SummaryExt(name string, window time.Duration, quantiles []float64, labels ...string) Summary {
options := Options{} return &noopSummary{labels: labels}
for _, o := range opts {
o(&options)
}
return &noopSummary{labels: options.Labels}
} }
// Histogram implements the Meter interface // Histogram implements the Meter interface
func (r *noopMeter) Histogram(name string, opts ...Option) Histogram { func (r *noopMeter) Histogram(name string, labels ...string) Histogram {
options := Options{} return &noopHistogram{labels: labels}
for _, o := range opts {
o(&options)
}
return &noopHistogram{labels: options.Labels}
} }
// Set implements the Meter interface // Set implements the Meter interface
@@ -107,15 +83,13 @@ func (r *noopMeter) String() string {
} }
type noopCounter struct { type noopCounter struct {
labels Labels labels []string
} }
func (r *noopCounter) Add(int) { func (r *noopCounter) Add(int) {
} }
func (r *noopCounter) Dec() { func (r *noopCounter) Dec() {
} }
func (r *noopCounter) Get() uint64 { func (r *noopCounter) Get() uint64 {
@@ -123,19 +97,16 @@ func (r *noopCounter) Get() uint64 {
} }
func (r *noopCounter) Inc() { func (r *noopCounter) Inc() {
} }
func (r *noopCounter) Set(uint64) { func (r *noopCounter) Set(uint64) {
} }
type noopFloatCounter struct { type noopFloatCounter struct {
labels Labels labels []string
} }
func (r *noopFloatCounter) Add(float64) { func (r *noopFloatCounter) Add(float64) {
} }
func (r *noopFloatCounter) Get() float64 { func (r *noopFloatCounter) Get() float64 {
@@ -143,15 +114,13 @@ func (r *noopFloatCounter) Get() float64 {
} }
func (r *noopFloatCounter) Set(float64) { func (r *noopFloatCounter) Set(float64) {
} }
func (r *noopFloatCounter) Sub(float64) { func (r *noopFloatCounter) Sub(float64) {
} }
type noopGauge struct { type noopGauge struct {
labels Labels labels []string
} }
func (r *noopGauge) Get() float64 { func (r *noopGauge) Get() float64 {
@@ -159,31 +128,26 @@ func (r *noopGauge) Get() float64 {
} }
type noopSummary struct { type noopSummary struct {
labels Labels labels []string
} }
func (r *noopSummary) Update(float64) { func (r *noopSummary) Update(float64) {
} }
func (r *noopSummary) UpdateDuration(time.Time) { func (r *noopSummary) UpdateDuration(time.Time) {
} }
type noopHistogram struct { type noopHistogram struct {
labels Labels labels []string
} }
func (r *noopHistogram) Reset() { func (r *noopHistogram) Reset() {
} }
func (r *noopHistogram) Update(float64) { func (r *noopHistogram) Update(float64) {
} }
func (r *noopHistogram) UpdateDuration(time.Time) { func (r *noopHistogram) UpdateDuration(time.Time) {
} }
//func (r *noopHistogram) VisitNonZeroBuckets(f func(vmrange string, count uint64)) {} // func (r *noopHistogram) VisitNonZeroBuckets(f func(vmrange string, count uint64)) {}

View File

@@ -11,17 +11,26 @@ type Option func(*Options)
// Options for metrics implementations: // Options for metrics implementations:
type Options struct { type Options struct {
Name string // Logger used for logging
Logger logger.Logger
// Context holds external options
Context context.Context
// Name holds the meter name
Name string
// Address holds the address that serves metrics
Address string Address string
Path string // Path holds the path for metrics
Labels Labels Path string
//TimingObjectives map[float64]float64 // MetricPrefix holds the prefix for all metrics
Logger logger.Logger MetricPrefix string
Context context.Context // LabelPrefix holds the prefix for all labels
MetricPrefix string LabelPrefix string
LabelPrefix string // Labels holds the default labels
Labels []string
// WriteProcessMetrics flag to write process metrics
WriteProcessMetrics bool WriteProcessMetrics bool
WriteFDMetrics bool // WriteFDMetrics flag to write fd metrics
WriteFDMetrics bool
} }
// NewOptions prepares a set of options: // NewOptions prepares a set of options:
@@ -79,11 +88,9 @@ func Logger(l logger.Logger) Option {
} }
} }
// Label sets the label func Labels(ls ...string) Option {
func Label(key, val string) Option {
return func(o *Options) { return func(o *Options) {
o.Labels.keys = append(o.Labels.keys, key) o.Labels = append(o.Labels, ls...)
o.Labels.vals = append(o.Labels.vals, val)
} }
} }

View File

@@ -11,34 +11,49 @@ import (
) )
var ( var (
ClientRequestDurationSeconds = "client_request_duration_seconds" ClientRequestDurationSeconds = "client_request_duration_seconds"
ClientRequestLatencyMicroseconds = "client_request_latency_microseconds" ClientRequestLatencyMicroseconds = "client_request_latency_microseconds"
ClientRequestTotal = "client_request_total" ClientRequestTotal = "client_request_total"
ServerRequestDurationSeconds = "server_request_duration_seconds" ClientRequestInflight = "client_request_inflight"
ServerRequestLatencyMicroseconds = "server_request_latency_microseconds"
ServerRequestTotal = "server_request_total" ServerRequestDurationSeconds = "server_request_duration_seconds"
PublishMessageDurationSeconds = "publish_message_duration_seconds" ServerRequestLatencyMicroseconds = "server_request_latency_microseconds"
PublishMessageLatencyMicroseconds = "publish_message_latency_microseconds" ServerRequestTotal = "server_request_total"
PublishMessageTotal = "publish_message_total" ServerRequestInflight = "server_request_inflight"
PublishMessageDurationSeconds = "publish_message_duration_seconds"
PublishMessageLatencyMicroseconds = "publish_message_latency_microseconds"
PublishMessageTotal = "publish_message_total"
PublishMessageInflight = "publish_message_inflight"
SubscribeMessageDurationSeconds = "subscribe_message_duration_seconds" SubscribeMessageDurationSeconds = "subscribe_message_duration_seconds"
SubscribeMessageLatencyMicroseconds = "subscribe_message_latency_microseconds" SubscribeMessageLatencyMicroseconds = "subscribe_message_latency_microseconds"
SubscribeMessageTotal = "subscribe_message_total" SubscribeMessageTotal = "subscribe_message_total"
SubscribeMessageInflight = "subscribe_message_inflight"
labelSuccess = "success" labelSuccess = "success"
labelFailure = "failure" labelFailure = "failure"
labelStatus = "status" labelStatus = "status"
labelEndpoint = "endpoint" labelEndpoint = "endpoint"
// DefaultSkipEndpoints contains list of endpoints that not evaluted by wrapper
DefaultSkipEndpoints = []string{"Meter.Metrics"}
) )
type Options struct { type Options struct {
Meter meter.Meter Meter meter.Meter
lopts []meter.Option lopts []meter.Option
SkipEndpoints []string
} }
type Option func(*Options) type Option func(*Options)
func NewOptions(opts ...Option) Options { func NewOptions(opts ...Option) Options {
options := Options{lopts: make([]meter.Option, 0, 5)} options := Options{
Meter: meter.DefaultMeter,
lopts: make([]meter.Option, 0, 5),
SkipEndpoints: DefaultSkipEndpoints,
}
for _, o := range opts { for _, o := range opts {
o(&options) o(&options)
} }
@@ -47,19 +62,19 @@ func NewOptions(opts ...Option) Options {
func ServiceName(name string) Option { func ServiceName(name string) Option {
return func(o *Options) { return func(o *Options) {
o.lopts = append(o.lopts, meter.Label("name", name)) o.lopts = append(o.lopts, meter.Labels("name", name))
} }
} }
func ServiceVersion(version string) Option { func ServiceVersion(version string) Option {
return func(o *Options) { return func(o *Options) {
o.lopts = append(o.lopts, meter.Label("version", version)) o.lopts = append(o.lopts, meter.Labels("version", version))
} }
} }
func ServiceID(id string) Option { func ServiceID(id string) Option {
return func(o *Options) { return func(o *Options) {
o.lopts = append(o.lopts, meter.Label("id", id)) o.lopts = append(o.lopts, meter.Labels("id", id))
} }
} }
@@ -69,10 +84,16 @@ func Meter(m meter.Meter) Option {
} }
} }
func SkipEndoints(eps ...string) Option {
return func(o *Options) {
o.SkipEndpoints = append(o.SkipEndpoints, eps...)
}
}
type wrapper struct { type wrapper struct {
opts Options
callFunc client.CallFunc
client.Client client.Client
callFunc client.CallFunc
opts Options
} }
func NewClientWrapper(opts ...Option) client.Wrapper { func NewClientWrapper(opts ...Option) client.Wrapper {
@@ -97,69 +118,90 @@ func NewCallWrapper(opts ...Option) client.CallWrapper {
func (w *wrapper) CallFunc(ctx context.Context, addr string, req client.Request, rsp interface{}, opts client.CallOptions) error { 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()) endpoint := fmt.Sprintf("%s.%s", req.Service(), req.Endpoint())
for _, ep := range w.opts.SkipEndpoints {
if ep == endpoint {
return w.callFunc(ctx, addr, req, rsp, opts)
}
}
labels := make([]string, 0, 4)
labels = append(labels, labelEndpoint, endpoint)
w.opts.Meter.Counter(ClientRequestInflight, labels...).Inc()
ts := time.Now() ts := time.Now()
err := w.callFunc(ctx, addr, req, rsp, opts) err := w.callFunc(ctx, addr, req, rsp, opts)
te := time.Since(ts) te := time.Since(ts)
w.opts.Meter.Counter(ClientRequestInflight, labels...).Dec()
lopts := w.opts.lopts w.opts.Meter.Summary(ClientRequestLatencyMicroseconds, labels...).Update(te.Seconds())
lopts = append(lopts, meter.Label(labelEndpoint, endpoint)) w.opts.Meter.Histogram(ClientRequestDurationSeconds, labels...).Update(te.Seconds())
w.opts.Meter.Summary(ClientRequestLatencyMicroseconds, lopts...).Update(float64(te.Seconds()))
w.opts.Meter.Histogram(ClientRequestDurationSeconds, lopts...).Update(float64(te.Seconds()))
if err == nil { if err == nil {
lopts = append(lopts, meter.Label(labelStatus, labelSuccess)) labels = append(labels, labelStatus, labelSuccess)
} else { } else {
lopts = append(lopts, meter.Label(labelStatus, labelFailure)) labels = append(labels, labelStatus, labelFailure)
} }
w.opts.Meter.Counter(ClientRequestTotal, lopts...).Inc() w.opts.Meter.Counter(ClientRequestTotal, labels...).Inc()
return err return err
} }
func (w *wrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error { 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()) endpoint := fmt.Sprintf("%s.%s", req.Service(), req.Endpoint())
for _, ep := range w.opts.SkipEndpoints {
if ep == endpoint {
return w.Client.Call(ctx, req, rsp, opts...)
}
}
labels := make([]string, 0, 4)
labels = append(labels, labelEndpoint, endpoint)
w.opts.Meter.Counter(ClientRequestInflight, labels...).Inc()
ts := time.Now() ts := time.Now()
err := w.Client.Call(ctx, req, rsp, opts...) err := w.Client.Call(ctx, req, rsp, opts...)
te := time.Since(ts) te := time.Since(ts)
w.opts.Meter.Counter(ClientRequestInflight, labels...).Dec()
lopts := w.opts.lopts w.opts.Meter.Summary(ClientRequestLatencyMicroseconds, labels...).Update(te.Seconds())
lopts = append(lopts, meter.Label(labelEndpoint, endpoint)) w.opts.Meter.Histogram(ClientRequestDurationSeconds, labels...).Update(te.Seconds())
w.opts.Meter.Summary(ClientRequestLatencyMicroseconds, lopts...).Update(float64(te.Seconds()))
w.opts.Meter.Histogram(ClientRequestDurationSeconds, lopts...).Update(float64(te.Seconds()))
if err == nil { if err == nil {
lopts = append(lopts, meter.Label(labelStatus, labelSuccess)) labels = append(labels, labelStatus, labelSuccess)
} else { } else {
lopts = append(lopts, meter.Label(labelStatus, labelFailure)) labels = append(labels, labelStatus, labelFailure)
} }
w.opts.Meter.Counter(ClientRequestTotal, lopts...).Inc() w.opts.Meter.Counter(ClientRequestTotal, labels...).Inc()
return err return err
} }
func (w *wrapper) Stream(ctx context.Context, req client.Request, opts ...client.CallOption) (client.Stream, error) { 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()) endpoint := fmt.Sprintf("%s.%s", req.Service(), req.Endpoint())
for _, ep := range w.opts.SkipEndpoints {
if ep == endpoint {
return w.Client.Stream(ctx, req, opts...)
}
}
labels := make([]string, 0, 4)
labels = append(labels, labelEndpoint, endpoint)
w.opts.Meter.Counter(ClientRequestInflight, labels...).Inc()
ts := time.Now() ts := time.Now()
stream, err := w.Client.Stream(ctx, req, opts...) stream, err := w.Client.Stream(ctx, req, opts...)
te := time.Since(ts) te := time.Since(ts)
w.opts.Meter.Counter(ClientRequestInflight, labels...).Dec()
lopts := w.opts.lopts w.opts.Meter.Summary(ClientRequestLatencyMicroseconds, labels...).Update(te.Seconds())
lopts = append(lopts, meter.Label(labelEndpoint, endpoint)) w.opts.Meter.Histogram(ClientRequestDurationSeconds, labels...).Update(te.Seconds())
w.opts.Meter.Summary(ClientRequestLatencyMicroseconds, lopts...).Update(float64(te.Seconds()))
w.opts.Meter.Histogram(ClientRequestDurationSeconds, lopts...).Update(float64(te.Seconds()))
if err == nil { if err == nil {
lopts = append(lopts, meter.Label(labelStatus, labelSuccess)) labels = append(labels, labelStatus, labelSuccess)
} else { } else {
lopts = append(lopts, meter.Label(labelStatus, labelFailure)) labels = append(labels, labelStatus, labelFailure)
} }
w.opts.Meter.Counter(ClientRequestTotal, lopts...).Inc() w.opts.Meter.Counter(ClientRequestTotal, labels...).Inc()
return stream, err return stream, err
} }
@@ -167,22 +209,24 @@ func (w *wrapper) Stream(ctx context.Context, req client.Request, opts ...client
func (w *wrapper) Publish(ctx context.Context, p client.Message, opts ...client.PublishOption) error { func (w *wrapper) Publish(ctx context.Context, p client.Message, opts ...client.PublishOption) error {
endpoint := p.Topic() endpoint := p.Topic()
labels := make([]string, 0, 4)
labels = append(labels, labelEndpoint, endpoint)
w.opts.Meter.Counter(PublishMessageInflight, labels...).Inc()
ts := time.Now() ts := time.Now()
err := w.Client.Publish(ctx, p, opts...) err := w.Client.Publish(ctx, p, opts...)
te := time.Since(ts) te := time.Since(ts)
w.opts.Meter.Counter(PublishMessageInflight, labels...).Dec()
lopts := w.opts.lopts w.opts.Meter.Summary(PublishMessageLatencyMicroseconds, labels...).Update(te.Seconds())
lopts = append(lopts, meter.Label(labelEndpoint, endpoint)) w.opts.Meter.Histogram(PublishMessageDurationSeconds, labels...).Update(te.Seconds())
w.opts.Meter.Summary(PublishMessageLatencyMicroseconds, lopts...).Update(float64(te.Seconds()))
w.opts.Meter.Histogram(PublishMessageDurationSeconds, lopts...).Update(float64(te.Seconds()))
if err == nil { if err == nil {
lopts = append(lopts, meter.Label(labelStatus, labelSuccess)) labels = append(labels, labelStatus, labelSuccess)
} else { } else {
lopts = append(lopts, meter.Label(labelStatus, labelFailure)) labels = append(labels, labelStatus, labelFailure)
} }
w.opts.Meter.Counter(PublishMessageTotal, lopts...).Inc() w.opts.Meter.Counter(PublishMessageTotal, labels...).Inc()
return err return err
} }
@@ -197,23 +241,30 @@ func NewHandlerWrapper(opts ...Option) server.HandlerWrapper {
func (w *wrapper) HandlerFunc(fn server.HandlerFunc) server.HandlerFunc { func (w *wrapper) HandlerFunc(fn 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 {
endpoint := req.Endpoint() endpoint := req.Endpoint()
for _, ep := range w.opts.SkipEndpoints {
if ep == endpoint {
return fn(ctx, req, rsp)
}
}
labels := make([]string, 0, 4)
labels = append(labels, labelEndpoint, endpoint)
w.opts.Meter.Counter(ServerRequestInflight, labels...).Inc()
ts := time.Now() ts := time.Now()
err := fn(ctx, req, rsp) err := fn(ctx, req, rsp)
te := time.Since(ts) te := time.Since(ts)
w.opts.Meter.Counter(ServerRequestInflight, labels...).Dec()
lopts := w.opts.lopts w.opts.Meter.Summary(ServerRequestLatencyMicroseconds, labels...).Update(te.Seconds())
lopts = append(lopts, meter.Label(labelEndpoint, endpoint)) w.opts.Meter.Histogram(ServerRequestDurationSeconds, labels...).Update(te.Seconds())
w.opts.Meter.Summary(ServerRequestLatencyMicroseconds, lopts...).Update(float64(te.Seconds()))
w.opts.Meter.Histogram(ServerRequestDurationSeconds, lopts...).Update(float64(te.Seconds()))
if err == nil { if err == nil {
lopts = append(lopts, meter.Label(labelStatus, labelSuccess)) labels = append(labels, labelStatus, labelSuccess)
} else { } else {
lopts = append(lopts, meter.Label(labelStatus, labelFailure)) labels = append(labels, labelStatus, labelFailure)
} }
w.opts.Meter.Counter(ServerRequestTotal, lopts...).Inc() w.opts.Meter.Counter(ServerRequestTotal, labels...).Inc()
return err return err
} }
@@ -230,22 +281,24 @@ func (w *wrapper) SubscriberFunc(fn server.SubscriberFunc) server.SubscriberFunc
return func(ctx context.Context, msg server.Message) error { return func(ctx context.Context, msg server.Message) error {
endpoint := msg.Topic() endpoint := msg.Topic()
labels := make([]string, 0, 4)
labels = append(labels, labelEndpoint, endpoint)
w.opts.Meter.Counter(SubscribeMessageInflight, labels...).Inc()
ts := time.Now() ts := time.Now()
err := fn(ctx, msg) err := fn(ctx, msg)
te := time.Since(ts) te := time.Since(ts)
w.opts.Meter.Counter(SubscribeMessageInflight, labels...).Dec()
lopts := w.opts.lopts w.opts.Meter.Summary(SubscribeMessageLatencyMicroseconds, labels...).Update(te.Seconds())
lopts = append(lopts, meter.Label(labelEndpoint, endpoint)) w.opts.Meter.Histogram(SubscribeMessageDurationSeconds, labels...).Update(te.Seconds())
w.opts.Meter.Summary(SubscribeMessageLatencyMicroseconds, lopts...).Update(float64(te.Seconds()))
w.opts.Meter.Histogram(SubscribeMessageDurationSeconds, lopts...).Update(float64(te.Seconds()))
if err == nil { if err == nil {
lopts = append(lopts, meter.Label(labelStatus, labelSuccess)) labels = append(labels, labelStatus, labelSuccess)
} else { } else {
lopts = append(lopts, meter.Label(labelStatus, labelFailure)) labels = append(labels, labelStatus, labelFailure)
} }
w.opts.Meter.Counter(SubscribeMessageTotal, lopts...).Inc() w.opts.Meter.Counter(SubscribeMessageTotal, labels...).Inc()
return err return err
} }

View File

@@ -15,6 +15,18 @@ type Option func(*Options)
// Options configure network // Options configure network
type Options struct { type Options struct {
// Router used for routing
Router router.Router
// Proxy holds the proxy
Proxy proxy.Proxy
// Logger used for logging
Logger logger.Logger
// Meter used for metrics
Meter meter.Meter
// Tracer used for tracing
Tracer tracer.Tracer
// Tunnel used for transfer data
Tunnel tunnel.Tunnel
// Id of the node // Id of the node
Id string Id string
// Name of the network // Name of the network
@@ -25,18 +37,6 @@ type Options struct {
Advertise string Advertise string
// Nodes is a list of nodes to connect to // Nodes is a list of nodes to connect to
Nodes []string Nodes []string
// Tunnel is network tunnel
Tunnel tunnel.Tunnel
// Router is network router
Router router.Router
// Proxy is network proxy
Proxy proxy.Proxy
// 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

View File

@@ -14,19 +14,14 @@ import (
) )
type memorySocket struct { type memorySocket struct {
recv chan *Message
send chan *Message
// sock exit
exit chan bool
// listener exit
lexit chan bool
local string
remote string
// for send/recv transport.Timeout
timeout time.Duration
ctx context.Context ctx context.Context
recv chan *Message
exit chan bool
lexit chan bool
send chan *Message
local string
remote string
timeout time.Duration
sync.RWMutex sync.RWMutex
} }
@@ -36,19 +31,19 @@ type memoryClient struct {
} }
type memoryListener struct { type memoryListener struct {
addr string lopts ListenOptions
ctx context.Context
exit chan bool exit chan bool
conn chan *memorySocket conn chan *memorySocket
lopts ListenOptions addr string
topts Options topts Options
sync.RWMutex sync.RWMutex
ctx context.Context
} }
type memoryTransport struct { type memoryTransport struct {
opts Options
sync.RWMutex
listeners map[string]*memoryListener listeners map[string]*memoryListener
opts Options
sync.RWMutex
} }
func (ms *memorySocket) Recv(m *Message) error { func (ms *memorySocket) Recv(m *Message) error {

View File

@@ -27,9 +27,9 @@ func TestMemoryTransport(t *testing.T) {
if len(os.Getenv("INTEGRATION_TESTS")) == 0 { if len(os.Getenv("INTEGRATION_TESTS")) == 0 {
t.Logf("Server Received %s", string(m.Body)) t.Logf("Server Received %s", string(m.Body))
} }
if err := sock.Send(&Message{ if cerr := sock.Send(&Message{
Body: []byte(`pong`), Body: []byte(`pong`),
}); err != nil { }); cerr != nil {
return return
} }
} }
@@ -60,7 +60,6 @@ func TestMemoryTransport(t *testing.T) {
t.Logf("Client Received %s", string(m.Body)) t.Logf("Client Received %s", string(m.Body))
} }
} }
} }
func TestListener(t *testing.T) { func TestListener(t *testing.T) {

View File

@@ -13,26 +13,24 @@ import (
// Options struct holds the transport options // Options struct holds the transport options
type Options struct { type Options struct {
Name string // Meter used for metrics
// Addrs is the list of intermediary addresses to connect to
Addrs []string
// Codec is the codec interface to use where headers are not supported
// by the transport and the entire payload must be encoded
Codec codec.Codec
// TLSConfig to secure the connection. The assumption is that this
// is mTLS keypair
TLSConfig *tls.Config
// Timeout sets the timeout for Send/Recv
Timeout time.Duration
// Logger sets the logger
Logger logger.Logger
// Meter sets the meter
Meter meter.Meter Meter meter.Meter
// Tracer sets the tracer // Tracer used for tracing
Tracer tracer.Tracer Tracer tracer.Tracer
// Other options for implementations of the interface // Codec used for marshal/unmarshal messages
// can be stored in a context Codec codec.Codec
// Logger used for logging
Logger logger.Logger
// Context holds external options
Context context.Context Context context.Context
// TLSConfig holds tls.TLSConfig options
TLSConfig *tls.Config
// Name holds the transport name
Name string
// Addrs holds the transport addrs
Addrs []string
// Timeout holds the timeout
Timeout time.Duration
} }
// NewOptions returns new options // NewOptions returns new options
@@ -53,18 +51,12 @@ func NewOptions(opts ...Option) Options {
// DialOptions struct // DialOptions struct
type DialOptions struct { type DialOptions struct {
// Tells the transport this is a streaming connection with // Context holds the external options
// multiple calls to send/recv and that send may not even be called
Stream bool
// Timeout for dialing
Timeout time.Duration
// TODO: add tls options when dialling
// Currently set in global options
// Other options for implementations of the interface
// can be stored in a context
Context context.Context Context context.Context
// Timeout holds the timeout
Timeout time.Duration
// Stream flag
Stream bool
} }
// NewDialOptions returns new DialOptions // NewDialOptions returns new DialOptions
@@ -85,10 +77,10 @@ func NewDialOptions(opts ...DialOption) DialOptions {
type ListenOptions struct { type ListenOptions struct {
// TODO: add tls options when listening // TODO: add tls options when listening
// Currently set in global options // Currently set in global options
// Context holds the external options
// Other options for implementations of the interface
// can be stored in a context
Context context.Context Context context.Context
// TLSConfig holds the *tls.Config options
TLSConfig *tls.Config
} }
// NewListenOptions returns new ListenOptions // NewListenOptions returns new ListenOptions

View File

@@ -12,27 +12,28 @@ import (
) )
type tunBroker struct { type tunBroker struct {
opts broker.Options
tunnel tunnel.Tunnel tunnel tunnel.Tunnel
opts broker.Options
} }
type tunSubscriber struct { type tunSubscriber struct {
topic string
handler broker.Handler
opts broker.SubscribeOptions
closed chan bool
listener tunnel.Listener listener tunnel.Listener
handler broker.Handler
closed chan bool
topic string
opts broker.SubscribeOptions
} }
type tunEvent struct { type tunEvent struct {
topic string
message *broker.Message message *broker.Message
topic string
} }
// used to access tunnel from options context // used to access tunnel from options context
type tunnelKey struct{} type (
type tunnelAddr struct{} tunnelKey struct{}
tunnelAddr struct{}
)
func (t *tunBroker) Init(opts ...broker.Option) error { func (t *tunBroker) Init(opts ...broker.Option) error {
for _, o := range opts { for _, o := range opts {

View File

@@ -22,23 +22,24 @@ type Option func(*Options)
// Options provides network configuration options // Options provides network configuration options
type Options struct { type Options struct {
Name string // Logger used for logging
// Id is tunnel id
Id string
// Address is tunnel address
Address string
// Nodes are remote nodes
Nodes []string
// The shared auth token
Token string
// Transport listens to incoming connections
Transport transport.Transport
// Logger
Logger logger.Logger Logger logger.Logger
// Meter // Meter used for metrics
Meter meter.Meter Meter meter.Meter
// Tracer // Tracer used for tracing
Tracer tracer.Tracer Tracer tracer.Tracer
// Transport used for communication
Transport transport.Transport
// Token the shared auth token
Token string
// Name holds the tunnel name
Name string
// ID holds the tunnel id
ID string
// Address holds the tunnel address
Address string
// Nodes holds the tunnel nodes
Nodes []string
} }
// DialOption func // DialOption func
@@ -61,16 +62,16 @@ type ListenOption func(*ListenOptions)
// ListenOptions provides listen options // ListenOptions provides listen options
type ListenOptions struct { type ListenOptions struct {
// specify mode of the session // Mode specify mode of the session
Mode Mode Mode Mode
// The read timeout // Timeout the read timeout
Timeout time.Duration Timeout time.Duration
} }
// Id sets the tunnel id // ID sets the tunnel id
func Id(id string) Option { func ID(id string) Option {
return func(o *Options) { return func(o *Options) {
o.Id = id o.ID = id
} }
} }
@@ -163,7 +164,7 @@ func DialWait(b bool) DialOption {
// NewOptions returns router default options with filled values // NewOptions returns router default options with filled values
func NewOptions(opts ...Option) Options { func NewOptions(opts ...Option) Options {
options := Options{ options := Options{
Id: uuid.New().String(), ID: uuid.New().String(),
Address: DefaultAddress, Address: DefaultAddress,
Token: DefaultToken, Token: DefaultToken,
Logger: logger.DefaultLogger, Logger: logger.DefaultLogger,

View File

@@ -10,9 +10,8 @@ import (
) )
type tunTransport struct { type tunTransport struct {
tunnel tunnel.Tunnel
options transport.Options options transport.Options
tunnel tunnel.Tunnel
} }
type tunnelKey struct{} type tunnelKey struct{}
@@ -88,7 +87,7 @@ func NewTransport(opts ...transport.Option) transport.Transport {
} }
// initialise // initialise
//t.Init(opts...) // t.Init(opts...)
return t return t
} }

View File

@@ -9,10 +9,8 @@ import (
"github.com/unistack-org/micro/v3/network/transport" "github.com/unistack-org/micro/v3/network/transport"
) )
var ( // DefaultTunnel contains default tunnel implementation
// DefaultTunnel contains default tunnel implementation var DefaultTunnel Tunnel
DefaultTunnel Tunnel
)
const ( const (
// Unicast send over one link // Unicast send over one link

View File

@@ -17,39 +17,48 @@ import (
"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/profiler"
// "github.com/unistack-org/micro/v3/runtime"
) )
// Options for micro service // Options for micro service
type Options struct { type Options struct {
Name string // Context holds external options or cancel stuff
Version string
Metadata metadata.Metadata
Auths []auth.Auth
Brokers []broker.Broker
Loggers []logger.Logger
Meters []meter.Meter
Configs []config.Config
Clients []client.Client
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
BeforeStart []func(context.Context) error
BeforeStop []func(context.Context) error
AfterStart []func(context.Context) error
AfterStop []func(context.Context) error
// Other options for implementations of the interface
// can be stored in a context
Context context.Context Context context.Context
// Metadata holds service metadata
Metadata metadata.Metadata
// Version holds service version
Version string
// Name holds service name
Name string
// Brokers holds brokers
Brokers []broker.Broker
// Loggers holds loggers
Loggers []logger.Logger
// Meters holds meter
Meters []meter.Meter
// Configs holds config
Configs []config.Config
// Clients holds clients
Clients []client.Client
// Auths holds auths
Auths []auth.Auth
// Stores holds stores
Stores []store.Store
// Registers holds registers
Registers []register.Register
// Tracers holds tracers
Tracers []tracer.Tracer
// Routers holds routers
Routers []router.Router
// BeforeStart holds funcs that runs before service starts
BeforeStart []func(context.Context) error
// BeforeStop holds funcs that runs before service stops
BeforeStop []func(context.Context) error
// AfterStart holds funcs that runs after service starts
AfterStart []func(context.Context) error
// AfterStop holds funcs that runs after service stops
AfterStop []func(context.Context) error
// Servers holds servers
Servers []server.Server
} }
// NewOptions returns new Options filled with defaults and overrided by provided opts // NewOptions returns new Options filled with defaults and overrided by provided opts
@@ -67,8 +76,8 @@ func NewOptions(opts ...Option) Options {
Meters: []meter.Meter{meter.DefaultMeter}, Meters: []meter.Meter{meter.DefaultMeter},
Configs: []config.Config{config.DefaultConfig}, Configs: []config.Config{config.DefaultConfig},
Stores: []store.Store{store.DefaultStore}, Stores: []store.Store{store.DefaultStore},
//Runtime runtime.Runtime // Runtime runtime.Runtime
//Profile profile.Profile // Profile profile.Profile
} }
for _, o := range opts { for _, o := range opts {

View File

@@ -11,15 +11,13 @@ import (
) )
type httpProfile struct { type httpProfile struct {
server *http.Server
sync.Mutex sync.Mutex
running bool running bool
server *http.Server
} }
var ( // DefaultAddress for http profiler
// DefaultAddress for http profiler var DefaultAddress = ":6060"
DefaultAddress = ":6060"
)
// Start the profiler // Start the profiler
func (h *httpProfile) Start() error { func (h *httpProfile) Start() error {

View File

@@ -13,16 +13,12 @@ import (
) )
type profiler struct { type profiler struct {
opts profile.Options exit chan bool
cpuFile *os.File
memFile *os.File
opts profile.Options
sync.Mutex sync.Mutex
running bool running bool
exit chan bool
// where the cpu profile is written
cpuFile *os.File
// where the mem profile is written
memFile *os.File
} }
func (p *profiler) writeHeap(f *os.File) { func (p *profiler) writeHeap(f *os.File) {

View File

@@ -11,10 +11,8 @@ type Profiler interface {
String() string String() string
} }
var ( // DefaultProfiler holds the default profiler
// DefaultProfiler holds the default profiler var DefaultProfiler Profiler = NewProfiler()
DefaultProfiler Profiler = NewProfiler()
)
// Options holds the options for profiler // Options holds the options for profiler
type Options struct { type Options struct {

View File

@@ -11,20 +11,20 @@ import (
// Options for proxy // Options for proxy
type Options struct { type Options struct {
// Specific endpoint to always call // Tracer used for tracing
Endpoint string
// The default client to use
Client client.Client
// The default router to use
Router router.Router
// Extra links for different clients
Links map[string]client.Client
// Logger
Logger logger.Logger
// Meter
Meter meter.Meter
// Tracer
Tracer tracer.Tracer Tracer tracer.Tracer
// Client for communication
Client client.Client
// Router for routing
Router router.Router
// Logger used for logging
Logger logger.Logger
// Meter used for metrics
Meter meter.Meter
// Links holds the communication links
Links map[string]client.Client
// Endpoint holds the destination address
Endpoint string
} }
// Option func signature // Option func signature

View File

@@ -7,10 +7,8 @@ import (
"github.com/unistack-org/micro/v3/server" "github.com/unistack-org/micro/v3/server"
) )
var ( // DefaultEndpoint holds default proxy address
// DefaultEndpoint holds default proxy address var DefaultEndpoint = "localhost:9090"
DefaultEndpoint = "localhost:9090"
)
// Proxy can be used as a proxy server for micro services // Proxy can be used as a proxy server for micro services
type Proxy interface { type Proxy interface {

View File

@@ -3,7 +3,6 @@ package register
import ( import (
"fmt" "fmt"
"reflect" "reflect"
"strings"
"unicode" "unicode"
"unicode/utf8" "unicode/utf8"
@@ -11,20 +10,21 @@ import (
) )
// ExtractValue from reflect.Type from specified depth // ExtractValue from reflect.Type from specified depth
func ExtractValue(v reflect.Type, d int) *Value { func ExtractValue(v reflect.Type, d int) string {
if d == 3 { if d == 3 {
return nil return ""
} }
if v == nil { if v == nil {
return nil return ""
} }
if v.Kind() == reflect.Ptr { if v.Kind() == reflect.Ptr {
v = v.Elem() v = v.Elem()
} }
if len(v.Name()) == 0 { // slices and maps don't have a defined name
return nil if (v.Kind() == reflect.Slice || v.Kind() == reflect.Map) || len(v.Name()) == 0 {
return ""
} }
// get the rune character // get the rune character
@@ -32,48 +32,10 @@ func ExtractValue(v reflect.Type, d int) *Value {
// crude check for is unexported field // crude check for is unexported field
if unicode.IsLower(a) { if unicode.IsLower(a) {
return nil return ""
} }
arg := &Value{ return v.Name()
Name: v.Name(),
Type: v.Name(),
}
switch v.Kind() {
case reflect.Struct:
for i := 0; i < v.NumField(); i++ {
f := v.Field(i)
val := ExtractValue(f.Type, d+1)
if val == nil {
continue
}
// if we can find a json tag use it
if tags := f.Tag.Get("json"); len(tags) > 0 {
parts := strings.Split(tags, ",")
if parts[0] == "-" || parts[0] == "omitempty" {
continue
}
val.Name = parts[0]
}
// if there's no name default it
if len(val.Name) == 0 {
val.Name = v.Field(i).Name
}
arg.Values = append(arg.Values, val)
}
case reflect.Slice:
p := v.Elem()
if p.Kind() == reflect.Ptr {
p = p.Elem()
}
arg.Type = "[]" + p.Name()
}
return arg
} }
// ExtractEndpoint extract *Endpoint from reflect.Method // ExtractEndpoint extract *Endpoint from reflect.Method
@@ -105,7 +67,7 @@ func ExtractEndpoint(method reflect.Method) *Endpoint {
request := ExtractValue(reqType, 0) request := ExtractValue(reqType, 0)
response := ExtractValue(rspType, 0) response := ExtractValue(rspType, 0)
if request == nil || response == nil { if request == "" || response == "" {
return nil return nil
} }
@@ -124,7 +86,7 @@ func ExtractEndpoint(method reflect.Method) *Endpoint {
} }
// ExtractSubValue exctact *Value from reflect.Type // ExtractSubValue exctact *Value from reflect.Type
func ExtractSubValue(typ reflect.Type) *Value { func ExtractSubValue(typ reflect.Type) string {
var reqType reflect.Type var reqType reflect.Type
switch typ.NumIn() { switch typ.NumIn() {
case 1: case 1:
@@ -134,7 +96,7 @@ func ExtractSubValue(typ reflect.Type) *Value {
case 3: case 3:
reqType = typ.In(2) reqType = typ.In(2)
default: default:
return nil return ""
} }
return ExtractValue(reqType, 0) return ExtractValue(reqType, 0)
} }

View File

@@ -36,28 +36,21 @@ func TestExtractEndpoint(t *testing.T) {
t.Fatalf("Expected handler Test, got %s", endpoints[0].Name) t.Fatalf("Expected handler Test, got %s", endpoints[0].Name)
} }
if endpoints[0].Request == nil { if endpoints[0].Request == "" {
t.Fatal("Expected non nil Request") t.Fatal("Expected non nil Request")
} }
if endpoints[0].Response == nil { if endpoints[0].Response == "" {
t.Fatal("Expected non nil Request") t.Fatal("Expected non nil Request")
} }
if endpoints[0].Request.Name != "TestRequest" { if endpoints[0].Request != "TestRequest" {
t.Fatalf("Expected TestRequest got %s", endpoints[0].Request.Name) t.Fatalf("Expected TestRequest got %s", endpoints[0].Request)
} }
if endpoints[0].Response.Name != "TestResponse" { if endpoints[0].Response != "TestResponse" {
t.Fatalf("Expected TestResponse got %s", endpoints[0].Response.Name) t.Fatalf("Expected TestResponse got %s", endpoints[0].Response)
}
if endpoints[0].Request.Type != "TestRequest" {
t.Fatalf("Expected TestRequest type got %s", endpoints[0].Request.Type)
}
if endpoints[0].Response.Type != "TestResponse" {
t.Fatalf("Expected TestResponse type got %s", endpoints[0].Response.Type)
} }
t.Logf("XXX %#+v\n", endpoints[0])
} }

View File

@@ -16,9 +16,9 @@ var (
) )
type node struct { type node struct {
*Node
TTL time.Duration
LastSeen time.Time LastSeen time.Time
*Node
TTL time.Duration
} }
type record struct { type record struct {
@@ -30,10 +30,9 @@ type record struct {
} }
type memory struct { type memory struct {
opts Options
// records is a KV map with domain name as the key and a services map as the value
records map[string]services records map[string]services
watchers map[string]*watcher watchers map[string]*watcher
opts Options
sync.RWMutex sync.RWMutex
} }
@@ -65,7 +64,7 @@ func (m *memory) ttlPrune() {
for id, n := range record.Nodes { for id, n := range record.Nodes {
if n.TTL != 0 && time.Since(n.LastSeen) > n.TTL { if n.TTL != 0 && time.Since(n.LastSeen) > n.TTL {
if m.opts.Logger.V(logger.DebugLevel) { if m.opts.Logger.V(logger.DebugLevel) {
m.opts.Logger.Debugf(m.opts.Context, "Register TTL expired for node %s of service %s", n.Id, service) m.opts.Logger.Debugf(m.opts.Context, "Register TTL expired for node %s of service %s", n.ID, service)
} }
delete(m.records[domain][service][version].Nodes, id) delete(m.records[domain][service][version].Nodes, id)
} }
@@ -162,7 +161,7 @@ func (m *memory) Register(ctx context.Context, s *Service, opts ...RegisterOptio
for _, n := range s.Nodes { for _, n := range s.Nodes {
// check if already exists // check if already exists
if _, ok := srvs[s.Name][s.Version].Nodes[n.Id]; ok { if _, ok := srvs[s.Name][s.Version].Nodes[n.ID]; ok {
continue continue
} }
@@ -177,9 +176,9 @@ func (m *memory) Register(ctx context.Context, s *Service, opts ...RegisterOptio
metadata["domain"] = options.Domain metadata["domain"] = options.Domain
// add the node // add the node
srvs[s.Name][s.Version].Nodes[n.Id] = &node{ srvs[s.Name][s.Version].Nodes[n.ID] = &node{
Node: &Node{ Node: &Node{
Id: n.Id, ID: n.ID,
Address: n.Address, Address: n.Address,
Metadata: metadata, Metadata: metadata,
}, },
@@ -201,8 +200,8 @@ func (m *memory) Register(ctx context.Context, s *Service, opts ...RegisterOptio
if m.opts.Logger.V(logger.DebugLevel) { if m.opts.Logger.V(logger.DebugLevel) {
m.opts.Logger.Debugf(m.opts.Context, "Updated registration for service: %s, version: %s", s.Name, s.Version) m.opts.Logger.Debugf(m.opts.Context, "Updated registration for service: %s, version: %s", s.Name, s.Version)
} }
srvs[s.Name][s.Version].Nodes[n.Id].TTL = options.TTL srvs[s.Name][s.Version].Nodes[n.ID].TTL = options.TTL
srvs[s.Name][s.Version].Nodes[n.Id].LastSeen = time.Now() srvs[s.Name][s.Version].Nodes[n.ID].LastSeen = time.Now()
} }
} }
@@ -242,11 +241,11 @@ func (m *memory) Deregister(ctx context.Context, s *Service, opts ...DeregisterO
// deregister all of the service nodes from this version // deregister all of the service nodes from this version
for _, n := range s.Nodes { for _, n := range s.Nodes {
if _, ok := version.Nodes[n.Id]; ok { if _, ok := version.Nodes[n.ID]; ok {
if m.opts.Logger.V(logger.DebugLevel) { if m.opts.Logger.V(logger.DebugLevel) {
m.opts.Logger.Debugf(m.opts.Context, "Register removed node from service: %s, version: %s", s.Name, s.Version) m.opts.Logger.Debugf(m.opts.Context, "Register removed node from service: %s, version: %s", s.Name, s.Version)
} }
delete(version.Nodes, n.Id) delete(version.Nodes, n.ID)
} }
} }
@@ -405,10 +404,10 @@ func (m *memory) String() string {
} }
type watcher struct { type watcher struct {
id string
wo WatchOptions
res chan *Result res chan *Result
exit chan bool exit chan bool
wo WatchOptions
id string
} }
func (m *watcher) Next() (*Result, error) { func (m *watcher) Next() (*Result, error) {
@@ -458,7 +457,7 @@ func serviceToRecord(s *Service, ttl time.Duration) *record {
nodes := make(map[string]*node, len(s.Nodes)) nodes := make(map[string]*node, len(s.Nodes))
for _, n := range s.Nodes { for _, n := range s.Nodes {
nodes[n.Id] = &node{ nodes[n.ID] = &node{
Node: n, Node: n,
TTL: ttl, TTL: ttl,
LastSeen: time.Now(), LastSeen: time.Now(),
@@ -490,40 +489,31 @@ func recordToService(r *record, domain string) *Service {
endpoints := make([]*Endpoint, len(r.Endpoints)) endpoints := make([]*Endpoint, len(r.Endpoints))
for i, e := range r.Endpoints { for i, e := range r.Endpoints {
request := new(Value) md := make(map[string]string, len(e.Metadata))
if e.Request != nil {
*request = *e.Request
}
response := new(Value)
if e.Response != nil {
*response = *e.Response
}
metadata := make(map[string]string, len(e.Metadata))
for k, v := range e.Metadata { for k, v := range e.Metadata {
metadata[k] = v md[k] = v
} }
endpoints[i] = &Endpoint{ endpoints[i] = &Endpoint{
Name: e.Name, Name: e.Name,
Request: request, Request: e.Request,
Response: response, Response: e.Response,
Metadata: metadata, Metadata: md,
} }
} }
nodes := make([]*Node, len(r.Nodes)) nodes := make([]*Node, len(r.Nodes))
i := 0 i := 0
for _, n := range r.Nodes { for _, n := range r.Nodes {
metadata := make(map[string]string, len(n.Metadata)) md := make(map[string]string, len(n.Metadata))
for k, v := range n.Metadata { for k, v := range n.Metadata {
metadata[k] = v md[k] = v
} }
nodes[i] = &Node{ nodes[i] = &Node{
Id: n.Id, ID: n.ID,
Address: n.Address, Address: n.Address,
Metadata: metadata, Metadata: md,
} }
i++ i++
} }

View File

@@ -8,72 +8,70 @@ import (
"time" "time"
) )
var ( var testData = map[string][]*Service{
testData = map[string][]*Service{ "foo": {
"foo": { {
{ Name: "foo",
Name: "foo", Version: "1.0.0",
Version: "1.0.0", Nodes: []*Node{
Nodes: []*Node{ {
{ ID: "foo-1.0.0-123",
Id: "foo-1.0.0-123", Address: "localhost:9999",
Address: "localhost:9999",
},
{
Id: "foo-1.0.0-321",
Address: "localhost:9999",
},
}, },
}, {
{ ID: "foo-1.0.0-321",
Name: "foo", Address: "localhost:9999",
Version: "1.0.1",
Nodes: []*Node{
{
Id: "foo-1.0.1-321",
Address: "localhost:6666",
},
},
},
{
Name: "foo",
Version: "1.0.3",
Nodes: []*Node{
{
Id: "foo-1.0.3-345",
Address: "localhost:8888",
},
}, },
}, },
}, },
"bar": { {
{ Name: "foo",
Name: "bar", Version: "1.0.1",
Version: "default", Nodes: []*Node{
Nodes: []*Node{ {
{ ID: "foo-1.0.1-321",
Id: "bar-1.0.0-123", Address: "localhost:6666",
Address: "localhost:9999",
},
{
Id: "bar-1.0.0-321",
Address: "localhost:9999",
},
},
},
{
Name: "bar",
Version: "latest",
Nodes: []*Node{
{
Id: "bar-1.0.1-321",
Address: "localhost:6666",
},
}, },
}, },
}, },
} {
) Name: "foo",
Version: "1.0.3",
Nodes: []*Node{
{
ID: "foo-1.0.3-345",
Address: "localhost:8888",
},
},
},
},
"bar": {
{
Name: "bar",
Version: "default",
Nodes: []*Node{
{
ID: "bar-1.0.0-123",
Address: "localhost:9999",
},
{
ID: "bar-1.0.0-321",
Address: "localhost:9999",
},
},
},
{
Name: "bar",
Version: "latest",
Nodes: []*Node{
{
ID: "bar-1.0.1-321",
Address: "localhost:6666",
},
},
},
},
}
//nolint:gocyclo //nolint:gocyclo
func TestMemoryRegistry(t *testing.T) { func TestMemoryRegistry(t *testing.T) {

View File

@@ -12,20 +12,22 @@ import (
// Options holds options for register // Options holds options for register
type Options struct { type Options struct {
Name string // Tracer used for tracing
Addrs []string
Timeout time.Duration
TLSConfig *tls.Config
// Logger that will be used
Logger logger.Logger
// Meter that will be used
Meter meter.Meter
// Tracer
Tracer tracer.Tracer Tracer tracer.Tracer
// Other options for implementations of the interface // Context holds external options
// can be stored in a context
Context context.Context Context context.Context
// Logged used for logging
Logger logger.Logger
// Meter used for metrics
Meter meter.Meter
// TLSConfig holds tls.TLSConfig options
TLSConfig *tls.Config
// Name holds the name of register
Name string
// Addrs specifies register addrs
Addrs []string
// Timeout specifies timeout
Timeout time.Duration
} }
// NewOptions returns options that filled by opts // NewOptions returns options that filled by opts
@@ -42,15 +44,12 @@ func NewOptions(opts ...Option) Options {
return options return options
} }
// nolint: golint
// RegisterOptions holds options for register method // RegisterOptions holds options for register method
type RegisterOptions struct { type RegisterOptions struct {
TTL time.Duration Context context.Context
// Other options for implementations of the interface Domain string
// can be stored in a context TTL time.Duration
Context context.Context
// Domain to register the service in
Domain string
// Attempts specify attempts for register
Attempts int Attempts int
} }
@@ -198,6 +197,7 @@ func TLSConfig(t *tls.Config) Option {
} }
} }
// nolint: golint
// RegisterAttempts specifies register atempts count // RegisterAttempts specifies register atempts count
func RegisterAttempts(t int) RegisterOption { func RegisterAttempts(t int) RegisterOption {
return func(o *RegisterOptions) { return func(o *RegisterOptions) {
@@ -205,6 +205,7 @@ func RegisterAttempts(t int) RegisterOption {
} }
} }
// nolint: golint
// RegisterTTL specifies register ttl // RegisterTTL specifies register ttl
func RegisterTTL(t time.Duration) RegisterOption { func RegisterTTL(t time.Duration) RegisterOption {
return func(o *RegisterOptions) { return func(o *RegisterOptions) {
@@ -212,6 +213,7 @@ func RegisterTTL(t time.Duration) RegisterOption {
} }
} }
// nolint: golint
// RegisterContext sets the register context // RegisterContext sets the register context
func RegisterContext(ctx context.Context) RegisterOption { func RegisterContext(ctx context.Context) RegisterOption {
return func(o *RegisterOptions) { return func(o *RegisterOptions) {
@@ -219,6 +221,7 @@ func RegisterContext(ctx context.Context) RegisterOption {
} }
} }
// nolint: golint
// RegisterDomain secifies register domain // RegisterDomain secifies register domain
func RegisterDomain(d string) RegisterOption { func RegisterDomain(d string) RegisterOption {
return func(o *RegisterOptions) { return func(o *RegisterOptions) {

View File

@@ -52,30 +52,24 @@ type Service struct {
// Node holds node register info // Node holds node register info
type Node struct { type Node struct {
Id string `json:"id"`
Address string `json:"address"`
Metadata metadata.Metadata `json:"metadata"` Metadata metadata.Metadata `json:"metadata"`
ID string `json:"id"`
Address string `json:"address"`
} }
// Endpoint holds endpoint register info // Endpoint holds endpoint register info
type Endpoint struct { type Endpoint struct {
Name string `json:"name"` Request string `json:"request"`
Request *Value `json:"request"` Response string `json:"response"`
Response *Value `json:"response"`
Metadata metadata.Metadata `json:"metadata"` Metadata metadata.Metadata `json:"metadata"`
} Name string `json:"name"`
// Value holds additional kv stuff
type Value struct {
Name string `json:"name"`
Type string `json:"type"`
Values []*Value `json:"values"`
} }
// Option func signature // Option func signature
type Option func(*Options) type Option func(*Options)
// RegisterOption option is used to register service // RegisterOption option is used to register service
// nolint: golint
type RegisterOption func(*RegisterOptions) type RegisterOption func(*RegisterOptions)
// WatchOption option is used to watch service changes // WatchOption option is used to watch service changes

View File

@@ -7,14 +7,17 @@ import "time"
type Watcher interface { type Watcher interface {
// Next is a blocking call // Next is a blocking call
Next() (*Result, error) Next() (*Result, error)
// Stop stops the watcher
Stop() Stop()
} }
// Result is returned by a call to Next on // Result is returned by a call to Next on
// the watcher. Actions can be create, update, delete // the watcher. Actions can be create, update, delete
type Result struct { type Result struct {
Action string // Service holds register service
Service *Service Service *Service
// Action holds the action
Action string
} }
// EventType defines register event type // EventType defines register event type
@@ -45,12 +48,12 @@ func (t EventType) String() string {
// Event is register event // Event is register event
type Event struct { type Event struct {
// Id is register id
Id string
// Type defines type of event
Type EventType
// Timestamp is event timestamp // Timestamp is event timestamp
Timestamp time.Time Timestamp time.Time
// Service is register service // Service is register service
Service *Service Service *Service
// ID is register id
ID string
// Type defines type of event
Type EventType
} }

View File

@@ -12,9 +12,9 @@ import (
// Resolver is a DNS network resolve // Resolver is a DNS network resolve
type Resolver struct { type Resolver struct {
// The resolver address to use
Address string
goresolver *net.Resolver goresolver *net.Resolver
// Address of resolver to use
Address string
sync.RWMutex sync.RWMutex
} }

91
router/dns.go Normal file
View File

@@ -0,0 +1,91 @@
package router
import (
"fmt"
"net"
"strconv"
)
// NewRouter returns an initialized dns router
func NewRouter(opts ...Option) Router {
options := NewOptions(opts...)
return &dns{options}
}
type dns struct {
options Options
}
func (d *dns) Init(opts ...Option) error {
for _, o := range opts {
o(&d.options)
}
return nil
}
func (d *dns) Options() Options {
return d.options
}
func (d *dns) Table() Table {
return nil
}
func (d *dns) Close() error {
return nil
}
func (d *dns) Lookup(opts ...QueryOption) ([]Route, error) {
options := NewQuery(opts...)
// check to see if we have the port provided in the service, e.g. go-micro-srv-foo:8000
host, port, err := net.SplitHostPort(options.Service)
if err == nil {
// lookup the service using A records
ips, err := net.LookupHost(host)
if err != nil {
return nil, err
}
p, _ := strconv.Atoi(port)
// convert the ip addresses to routes
result := make([]Route, len(ips))
for i, ip := range ips {
result[i] = Route{
Service: options.Service,
Address: fmt.Sprintf("%s:%d", ip, uint16(p)),
}
}
return result, nil
}
// we didn't get the port so we'll lookup the service using SRV records. If we can't lookup the
// service using the SRV record, we return the error.
_, nodes, err := net.LookupSRV(options.Service, "tcp", d.options.Network)
if err != nil {
return nil, err
}
// convert the nodes (net services) to routes
result := make([]Route, len(nodes))
for i, n := range nodes {
result[i] = Route{
Service: options.Service,
Address: fmt.Sprintf("%s:%d", n.Target, n.Port),
Network: d.options.Network,
}
}
return result, nil
}
func (d *dns) Watch(opts ...WatchOption) (Watcher, error) {
return nil, nil
}
func (d *dns) Name() string {
return d.options.Name
}
func (d *dns) String() string {
return "dns"
}

View File

@@ -10,23 +10,15 @@ import (
// Options are router options // Options are router options
type Options struct { type Options struct {
Name string Logger logger.Logger
// Id is router id Context context.Context
Id string
// Address is router address
Address string
// Gateway is network gateway
Gateway string
// Network is network address
Network string
// Register is the local register
Register register.Register Register register.Register
// Precache routes Name string
Gateway string
Network string
Id string
Address string
Precache bool Precache bool
// Logger
Logger logger.Logger
// Context for additional options
Context context.Context
} }
// Id sets Router Id // Id sets Router Id

View File

@@ -15,10 +15,10 @@ var (
// Route is network route // Route is network route
type Route struct { type Route struct {
// Metadata for the route
Metadata metadata.Metadata
// Service is destination service name // Service is destination service name
Service string Service string
// Address is service node address
Address string
// Gateway is route gateway // Gateway is route gateway
Gateway string Gateway string
// Network is network address // Network is network address
@@ -27,10 +27,10 @@ type Route struct {
Router string Router string
// Link is network link // Link is network link
Link string Link string
// Address is service node address
Address string
// Metric is the route cost metric // Metric is the route cost metric
Metric int64 Metric int64
// Metadata for the route
Metadata metadata.Metadata
} }
// Hash returns route hash sum. // Hash returns route hash sum.

View File

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

View File

@@ -5,10 +5,8 @@ import (
"time" "time"
) )
var ( // ErrWatcherStopped is returned when routing table watcher has been stopped
// ErrWatcherStopped is returned when routing table watcher has been stopped var ErrWatcherStopped = errors.New("watcher stopped")
ErrWatcherStopped = errors.New("watcher stopped")
)
// EventType defines routing table event // EventType defines routing table event
type EventType int type EventType int
@@ -38,14 +36,14 @@ func (t EventType) String() string {
// Event is returned by a call to Next on the watcher. // Event is returned by a call to Next on the watcher.
type Event struct { type Event struct {
// Unique id of the event
Id string
// Type defines type of event
Type EventType
// Timestamp is event timestamp // Timestamp is event timestamp
Timestamp time.Time Timestamp time.Time
// Id of the event
Id string
// Route is table route // Route is table route
Route Route Route Route
// Type defines type of event
Type EventType
} }
// Watcher defines routing table watcher interface // Watcher defines routing table watcher interface

View File

@@ -10,18 +10,12 @@ import (
// Options configure runtime // Options configure runtime
type Options struct { type Options struct {
// Scheduler for updates
Scheduler Scheduler Scheduler Scheduler
// Service type to manage Client client.Client
Type string Logger logger.Logger
// Source of the services repository Type string
Source string Source string
// Base image to use Image string
Image string
// Client to use when making requests
Client client.Client
// Logger
Logger logger.Logger
} }
// Option func signature // Option func signature
@@ -77,42 +71,26 @@ type ReadOption func(o *ReadOptions)
// CreateOptions configure runtime services // CreateOptions configure runtime services
type CreateOptions struct { type CreateOptions struct {
// Command to execut Context context.Context
Command []string Output io.Writer
// Args to pass into command
Args []string
// Environment to configure
Env []string
// Log output
Output io.Writer
// Type of service to create
Type string
// Retries before failing deploy
Retries int
// Specify the image to use
Image string
// Namespace to create the service in
Namespace string
// Specify the context to use
Context context.Context
// Secrets to use
Secrets map[string]string
// Resources to allocate the service
Resources *Resources Resources *Resources
Secrets map[string]string
Image string
Namespace string
Type string
Command []string
Args []string
Env []string
Retries int
} }
// ReadOptions queries runtime services // ReadOptions queries runtime services
type ReadOptions struct { type ReadOptions struct {
// Service name Context context.Context
Service string Service string
// Version queries services with given version Version string
Version string Type string
// Type of service
Type string
// Namespace the service is running in
Namespace string Namespace string
// Specify the context to use
Context context.Context
} }
// CreateType sets the type of service to create // CreateType sets the type of service to create
@@ -238,12 +216,9 @@ type UpdateOption func(o *UpdateOptions)
// UpdateOptions struct // UpdateOptions struct
type UpdateOptions struct { type UpdateOptions struct {
// Namespace the service is running in Context context.Context
Secrets map[string]string
Namespace string Namespace string
// Specify the context to use
Context context.Context
// Secrets to use
Secrets map[string]string
} }
// UpdateSecret sets a secret to provide the service with // UpdateSecret sets a secret to provide the service with
@@ -276,10 +251,8 @@ type DeleteOption func(o *DeleteOptions)
// DeleteOptions struct // DeleteOptions struct
type DeleteOptions struct { type DeleteOptions struct {
// Namespace the service is running in Context context.Context
Namespace string Namespace string
// Specify the context to use
Context context.Context
} }
// DeleteNamespace sets the namespace // DeleteNamespace sets the namespace
@@ -301,14 +274,10 @@ type LogsOption func(o *LogsOptions)
// LogsOptions configure runtime logging // LogsOptions configure runtime logging
type LogsOptions struct { type LogsOptions struct {
// How many existing lines to show Context context.Context
Count int64
// Stream new lines?
Stream bool
// Namespace the service is running in
Namespace string Namespace string
// Specify the context to use Count int64
Context context.Context Stream bool
} }
// LogsCount confiures how many existing lines to show // LogsCount confiures how many existing lines to show

View File

@@ -8,10 +8,8 @@ import (
"github.com/unistack-org/micro/v3/metadata" "github.com/unistack-org/micro/v3/metadata"
) )
var ( // ErrAlreadyExists error
// ErrAlreadyExists error var ErrAlreadyExists = errors.New("already exists")
ErrAlreadyExists = errors.New("already exists")
)
// Runtime is a service runtime manager // Runtime is a service runtime manager
type Runtime interface { type Runtime interface {
@@ -37,15 +35,20 @@ type Runtime interface {
// Logs returns a log stream // Logs returns a log stream
type Logs interface { type Logs interface {
// Error returns error
Error() error Error() error
// Chan return chan log
Chan() chan Log Chan() chan Log
// Stop stops the log stream
Stop() error Stop() error
} }
// Log is a log message // Log is a log message
type Log struct { type Log struct {
Message string // Metadata holds metadata
Metadata metadata.Metadata Metadata metadata.Metadata
// Message holds the message
Message string
} }
// Scheduler is a runtime service scheduler // Scheduler is a runtime service scheduler
@@ -84,28 +87,28 @@ func (t EventType) String() string {
// Event is notification event // Event is notification event
type Event struct { type Event struct {
// ID of the event // Timestamp of event
ID string
// Type is event type
Type EventType
// Timestamp is event timestamp
Timestamp time.Time Timestamp time.Time
// Service the event relates to // Service the event relates to
Service *Service Service *Service
// Options to use when processing the event // Options to use when processing the event
Options *CreateOptions Options *CreateOptions
// ID of the event
ID string
// Type is event type
Type EventType
} }
// Service is runtime service // Service is runtime service
type Service struct { type Service struct {
// Metadata stores metadata
Metadata metadata.Metadata
// Name of the service // Name of the service
Name string Name string
// Version of the service // Version of the service
Version string Version string
// url location of source // Name of the service
Source string Source string
// Metadata stores metadata
Metadata metadata.Metadata
} }
// Resources which are allocated to a serivce // Resources which are allocated to a serivce

View File

@@ -5,10 +5,8 @@ import (
"errors" "errors"
) )
var ( // ErrNoneAvailable is returned by select when no routes were provided to select from
// ErrNoneAvailable is returned by select when no routes were provided to select from var ErrNoneAvailable = errors.New("none available")
ErrNoneAvailable = errors.New("none available")
)
// Selector selects a route from a pool // Selector selects a route from a pool
type Selector interface { type Selector interface {

3
server/generate.go Normal file
View File

@@ -0,0 +1,3 @@
package server
//go:generate protoc -I./health -I../ -I/home/vtolstov/.cache/go-path/pkg/mod/github.com/unistack-org/micro-proto@v0.0.1 --micro_out=components=micro|http|server,standalone=false,debug=true,paths=source_relative:./health health/health.proto

View File

@@ -7,13 +7,13 @@ import (
) )
type rpcHandler struct { type rpcHandler struct {
name string
handler interface{}
endpoints []*register.Endpoint
opts HandlerOptions opts HandlerOptions
handler interface{}
name string
endpoints []*register.Endpoint
} }
func newRpcHandler(handler interface{}, opts ...HandlerOption) Handler { func newRPCHandler(handler interface{}, opts ...HandlerOption) Handler {
options := NewHandlerOptions(opts...) options := NewHandlerOptions(opts...)
typ := reflect.TypeOf(handler) typ := reflect.TypeOf(handler)

82
server/health/health.go Normal file
View File

@@ -0,0 +1,82 @@
package health
import (
"context"
"github.com/unistack-org/micro/v3/codec"
"github.com/unistack-org/micro/v3/errors"
)
var _ HealthServer = &Handler{}
type Handler struct {
opts Options
}
type CheckFunc func(context.Context) error
type Option func(*Options)
type Options struct {
Version string
Name string
LiveChecks []CheckFunc
ReadyChecks []CheckFunc
}
func LiveChecks(fns ...CheckFunc) Option {
return func(o *Options) {
o.LiveChecks = append(o.LiveChecks, fns...)
}
}
func ReadyChecks(fns ...CheckFunc) Option {
return func(o *Options) {
o.ReadyChecks = append(o.ReadyChecks, fns...)
}
}
func Name(name string) Option {
return func(o *Options) {
o.Name = name
}
}
func Version(version string) Option {
return func(o *Options) {
o.Version = version
}
}
func NewHandler(opts ...Option) *Handler {
options := Options{}
for _, o := range opts {
o(&options)
}
return &Handler{opts: options}
}
func (h *Handler) Live(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error {
var err error
for _, fn := range h.opts.LiveChecks {
if err = fn(ctx); err != nil {
return errors.ServiceUnavailable(h.opts.Name, "%v", err)
}
}
return nil
}
func (h *Handler) Ready(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error {
var err error
for _, fn := range h.opts.ReadyChecks {
if err = fn(ctx); err != nil {
return errors.ServiceUnavailable(h.opts.Name, "%v", err)
}
}
return nil
}
func (h *Handler) Version(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error {
rsp.Data = []byte(h.opts.Version)
return nil
}

View File

@@ -0,0 +1,62 @@
syntax = "proto3";
package micro.server.health;
option go_package = "github.com/unistack-org/micro/v3/server/health;health";
import "api/annotations.proto";
import "openapiv2/annotations.proto";
import "codec/frame.proto";
service Health {
rpc Live(micro.codec.Frame) returns (micro.codec.Frame) {
option (micro.openapiv2.openapiv2_operation) = {
operation_id: "Live";
responses: {
key: "default";
value: {
description: "Error response";
schema: {
json_schema: {
ref: "micro.codec.Frame";
}
}
}
}
};
option (micro.api.http) = { get: "/live"; };
};
rpc Ready(micro.codec.Frame) returns (micro.codec.Frame) {
option (micro.openapiv2.openapiv2_operation) = {
operation_id: "Ready";
responses: {
key: "default";
value: {
description: "Error response";
schema: {
json_schema: {
ref: "micro.codec.Frame";
}
}
}
}
};
option (micro.api.http) = { get: "/ready"; };
};
rpc Version(micro.codec.Frame) returns (micro.codec.Frame) {
option (micro.openapiv2.openapiv2_operation) = {
operation_id: "Version";
responses: {
key: "default";
value: {
description: "Error response";
schema: {
json_schema: {
ref: "micro.codec.Frame";
}
}
}
}
};
option (micro.api.http) = { get: "/version"; };
};
};

View File

@@ -0,0 +1,38 @@
// Code generated by protoc-gen-micro
// source: health.proto
package health
import (
context "context"
api "github.com/unistack-org/micro/v3/api"
codec "github.com/unistack-org/micro/v3/codec"
)
func NewHealthEndpoints() []*api.Endpoint {
return []*api.Endpoint{
&api.Endpoint{
Name: "Health.Live",
Path: []string{"/live"},
Method: []string{"GET"},
Handler: "rpc",
},
&api.Endpoint{
Name: "Health.Ready",
Path: []string{"/ready"},
Method: []string{"GET"},
Handler: "rpc",
},
&api.Endpoint{
Name: "Health.Version",
Path: []string{"/version"},
Method: []string{"GET"},
Handler: "rpc",
},
}
}
type HealthServer interface {
Live(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error
Ready(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error
Version(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error
}

View File

@@ -0,0 +1,43 @@
// Code generated by protoc-gen-micro
// source: health.proto
package health
import (
context "context"
api "github.com/unistack-org/micro/v3/api"
codec "github.com/unistack-org/micro/v3/codec"
server "github.com/unistack-org/micro/v3/server"
)
type healthServer struct {
HealthServer
}
func (h *healthServer) Live(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error {
return h.HealthServer.Live(ctx, req, rsp)
}
func (h *healthServer) Ready(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error {
return h.HealthServer.Ready(ctx, req, rsp)
}
func (h *healthServer) Version(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error {
return h.HealthServer.Version(ctx, req, rsp)
}
func RegisterHealthServer(s server.Server, sh HealthServer, opts ...server.HandlerOption) error {
type health interface {
Live(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error
Ready(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error
Version(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error
}
type Health struct {
health
}
h := &healthServer{sh}
var nopts []server.HandlerOption
for _, endpoint := range NewHealthEndpoints() {
nopts = append(nopts, api.WithEndpoint(endpoint))
}
return s.Handle(s.NewHandler(&Health{h}, append(nopts, opts...)...))
}

View File

@@ -6,9 +6,6 @@ import (
"sync" "sync"
"time" "time"
// cjson "github.com/unistack-org/micro-codec-json"
// cjsonrpc "github.com/unistack-org/micro-codec-jsonrpc"
// cproto "github.com/unistack-org/micro-codec-proto"
// cprotorpc "github.com/unistack-org/micro-codec-protorpc" // cprotorpc "github.com/unistack-org/micro-codec-protorpc"
"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"
@@ -16,16 +13,10 @@ import (
"github.com/unistack-org/micro/v3/register" "github.com/unistack-org/micro/v3/register"
) )
var ( // DefaultCodecs will be used to encode/decode
// DefaultCodecs will be used to encode/decode var DefaultCodecs = map[string]codec.Codec{
DefaultCodecs = map[string]codec.Codec{ "application/octet-stream": codec.NewCodec(),
//"application/json": cjson.NewCodec, }
//"application/json-rpc": cjsonrpc.NewCodec,
//"application/protobuf": cproto.NewCodec,
//"application/proto-rpc": cprotorpc.NewCodec,
"application/octet-stream": codec.NewCodec(),
}
)
const ( const (
defaultContentType = "application/json" defaultContentType = "application/json"
@@ -33,15 +24,15 @@ const (
type noopServer struct { type noopServer struct {
h Handler h Handler
opts Options wg *sync.WaitGroup
rsvc *register.Service rsvc *register.Service
handlers map[string]Handler handlers map[string]Handler
subscribers map[*subscriber][]broker.Subscriber subscribers map[*subscriber][]broker.Subscriber
registered bool
started bool
exit chan chan error exit chan chan error
wg *sync.WaitGroup opts Options
sync.RWMutex sync.RWMutex
registered bool
started bool
} }
// NewServer returns new noop server // NewServer returns new noop server
@@ -103,7 +94,7 @@ func (n *noopServer) Subscribe(sb Subscriber) error {
} }
func (n *noopServer) NewHandler(h interface{}, opts ...HandlerOption) Handler { func (n *noopServer) NewHandler(h interface{}, opts ...HandlerOption) Handler {
return newRpcHandler(h, opts...) return newRPCHandler(h, opts...)
} }
func (n *noopServer) NewSubscriber(topic string, sb interface{}, opts ...SubscriberOption) Subscriber { func (n *noopServer) NewSubscriber(topic string, sb interface{}, opts ...SubscriberOption) Subscriber {
@@ -158,23 +149,16 @@ func (n *noopServer) Register() error {
} }
n.RLock() n.RLock()
// Maps are ordered randomly, sort the keys for consistency handlerList := make([]string, 0, len(n.handlers))
var handlerList []string for n := range n.handlers {
for n, e := range n.handlers { handlerList = append(handlerList, n)
// Only advertise non internal handlers
if !e.Options().Internal {
handlerList = append(handlerList, n)
}
} }
sort.Strings(handlerList) sort.Strings(handlerList)
var subscriberList []*subscriber subscriberList := make([]*subscriber, 0, len(n.subscribers))
for e := range n.subscribers { for e := range n.subscribers {
// Only advertise non internal subscribers subscriberList = append(subscriberList, e)
if !e.Options().Internal {
subscriberList = append(subscriberList, e)
}
} }
sort.Slice(subscriberList, func(i, j int) bool { sort.Slice(subscriberList, func(i, j int) bool {
return subscriberList[i].topic > subscriberList[j].topic return subscriberList[i].topic > subscriberList[j].topic
@@ -190,7 +174,7 @@ func (n *noopServer) Register() error {
n.RUnlock() n.RUnlock()
service.Nodes[0].Metadata["protocol"] = "noop" service.Nodes[0].Metadata["protocol"] = "noop"
service.Nodes[0].Metadata["transport"] = "noop" service.Nodes[0].Metadata["transport"] = service.Nodes[0].Metadata["protocol"]
service.Endpoints = endpoints service.Endpoints = endpoints
n.RLock() n.RLock()
@@ -199,7 +183,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, "register [%s] Registering node: %s", config.Register.String(), service.Nodes[0].Id) config.Logger.Infof(n.opts.Context, "register [%s] Registering node: %s", config.Register.String(), service.Nodes[0].ID)
} }
} }
@@ -262,7 +246,7 @@ func (n *noopServer) Deregister() error {
} }
if config.Logger.V(logger.InfoLevel) { if config.Logger.V(logger.InfoLevel) {
config.Logger.Infof(n.opts.Context, "deregistering node: %s", service.Nodes[0].Id) config.Logger.Infof(n.opts.Context, "deregistering node: %s", service.Nodes[0].ID)
} }
if err := DefaultDeregisterFunc(service, config); err != nil { if err := DefaultDeregisterFunc(service, config); err != nil {
@@ -344,9 +328,10 @@ func (n *noopServer) Start() error {
} }
// use RegisterCheck func before register // use RegisterCheck func before register
// nolint: nestif
if err := config.RegisterCheck(config.Context); err != nil { if err := config.RegisterCheck(config.Context); err != nil {
if config.Logger.V(logger.ErrorLevel) { if config.Logger.V(logger.ErrorLevel) {
config.Logger.Errorf(n.opts.Context, "server %s-%s register check error: %s", config.Name, config.Id, err) config.Logger.Errorf(n.opts.Context, "server %s-%s register check error: %s", config.Name, config.ID, err)
} }
} else { } else {
// announce self to the world // announce self to the world
@@ -378,25 +363,26 @@ func (n *noopServer) Start() error {
registered := n.registered registered := n.registered
n.RUnlock() n.RUnlock()
rerr := config.RegisterCheck(config.Context) rerr := config.RegisterCheck(config.Context)
// nolint: nestif
if rerr != nil && registered { if rerr != nil && registered {
if config.Logger.V(logger.ErrorLevel) { if config.Logger.V(logger.ErrorLevel) {
config.Logger.Errorf(n.opts.Context, "server %s-%s register check error: %s, deregister it", config.Name, config.Id, rerr) config.Logger.Errorf(n.opts.Context, "server %s-%s register check error: %s, deregister it", config.Name, config.ID, rerr)
} }
// deregister self in case of error // deregister self in case of error
if err := n.Deregister(); err != nil { if err := n.Deregister(); err != nil {
if config.Logger.V(logger.ErrorLevel) { if config.Logger.V(logger.ErrorLevel) {
config.Logger.Errorf(n.opts.Context, "server %s-%s deregister error: %s", config.Name, config.Id, err) config.Logger.Errorf(n.opts.Context, "server %s-%s deregister error: %s", config.Name, config.ID, err)
} }
} }
} else if rerr != nil && !registered { } else if rerr != nil && !registered {
if config.Logger.V(logger.ErrorLevel) { if config.Logger.V(logger.ErrorLevel) {
config.Logger.Errorf(n.opts.Context, "server %s-%s register check error: %s", config.Name, config.Id, rerr) config.Logger.Errorf(n.opts.Context, "server %s-%s register check error: %s", config.Name, config.ID, rerr)
} }
continue continue
} }
if err := n.Register(); err != nil { if err := n.Register(); err != nil {
if config.Logger.V(logger.ErrorLevel) { if config.Logger.V(logger.ErrorLevel) {
config.Logger.Errorf(n.opts.Context, "server %s-%s register error: %s", config.Name, config.Id, err) config.Logger.Errorf(n.opts.Context, "server %s-%s register error: %s", config.Name, config.ID, err)
} }
} }
// wait for exit // wait for exit

View File

@@ -23,50 +23,66 @@ type Option func(*Options)
// Options server struct // Options server struct
type Options struct { type Options struct {
Codecs map[string]codec.Codec // Context holds the external options and can be used for server shutdown
Broker broker.Broker Context context.Context
Register register.Register // Broker holds the server broker
Tracer tracer.Tracer Broker broker.Broker
Auth auth.Auth // Register holds the register
Logger logger.Logger Register register.Register
Meter meter.Meter // Tracer holds the tracer
Transport transport.Transport Tracer tracer.Tracer
Metadata metadata.Metadata // Auth holds the auth
Name string Auth auth.Auth
Address string // Logger holds the logger
Advertise string Logger logger.Logger
Id string // Meter holds the meter
Namespace string Meter meter.Meter
Version string // Transport holds the transport
HdlrWrappers []HandlerWrapper Transport transport.Transport
SubWrappers []SubscriberWrapper
// RegisterCheck runs a check function before registering the service /*
RegisterCheck func(context.Context) error // Router for requests
// The register expiry time Router Router
RegisterTTL time.Duration */
// The interval on which to register
RegisterInterval time.Duration
// RegisterAttempts specify how many times try to register
RegisterAttempts int
// DeegisterAttempts specify how many times try to deregister
DeregisterAttempts int
// The router for requests
Router Router
// TLSConfig specifies tls.Config for secure serving
TLSConfig *tls.Config
Wait *sync.WaitGroup
// Listener may be passed if already created // Listener may be passed if already created
Listener net.Listener Listener net.Listener
// MaxConn limit connections to server // Wait group
Wait *sync.WaitGroup
// TLSConfig specifies tls.Config for secure serving
TLSConfig *tls.Config
// Metadata holds the server metadata
Metadata metadata.Metadata
// RegisterCheck run before register server
RegisterCheck func(context.Context) error
// Codecs map to handle content-type
Codecs map[string]codec.Codec
// ID holds the id of the server
ID string
// Namespace for te server
Namespace string
// Name holds the server name
Name string
// Address holds the server address
Address string
// Advertise holds the advertise address
Advertise string
// Version holds the server version
Version string
// SubWrappers holds the server subscribe wrappers
SubWrappers []SubscriberWrapper
// HdlrWrappers holds the handler wrappers
HdlrWrappers []HandlerWrapper
// RegisterAttempts holds the number of register attempts before error
RegisterAttempts int
// RegisterInterval holds he interval for re-register
RegisterInterval time.Duration
// RegisterTTL specifies TTL for register record
RegisterTTL time.Duration
// MaxConn limits number of connections
MaxConn int MaxConn int
// Other options for implementations of the interface // DeregisterAttempts holds the number of deregister attempts before error
// can be stored in a context DeregisterAttempts int
Context context.Context
} }
// NewOptions returns new options struct with default or passed values // NewOptions returns new options struct with default or passed values
@@ -88,7 +104,7 @@ func NewOptions(opts ...Option) Options {
Address: DefaultAddress, Address: DefaultAddress,
Name: DefaultName, Name: DefaultName,
Version: DefaultVersion, Version: DefaultVersion,
Id: DefaultId, ID: DefaultID,
Namespace: DefaultNamespace, Namespace: DefaultNamespace,
} }
@@ -127,10 +143,10 @@ func Meter(m meter.Meter) Option {
} }
} }
// 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) {
o.Id = id o.ID = id
} }
} }
@@ -250,12 +266,14 @@ func TLSConfig(t *tls.Config) Option {
} }
} }
/*
// WithRouter sets the request router // WithRouter sets the request router
func WithRouter(r Router) Option { func WithRouter(r Router) Option {
return func(o *Options) { return func(o *Options) {
o.Router = r o.Router = r
} }
} }
*/
// Wait tells the server to wait for requests to finish before exiting // Wait tells the server to wait for requests to finish before exiting
// If `wg` is nil, server only wait for completion of rpc handler. // If `wg` is nil, server only wait for completion of rpc handler.
@@ -303,9 +321,10 @@ type HandlerOption func(*HandlerOptions)
// HandlerOptions struct // HandlerOptions struct
type HandlerOptions struct { type HandlerOptions struct {
Internal bool // Context holds external options
Context context.Context
// Metadata for hondler
Metadata map[string]metadata.Metadata Metadata map[string]metadata.Metadata
Context context.Context
} }
// NewHandlerOptions creates new HandlerOptions // NewHandlerOptions creates new HandlerOptions
@@ -327,13 +346,14 @@ type SubscriberOption func(*SubscriberOptions)
// SubscriberOptions struct // SubscriberOptions struct
type SubscriberOptions struct { type SubscriberOptions struct {
// AutoAck defaults to true. When a handler returns // Context holds the external options
// with a nil error the message is acked. Context context.Context
AutoAck bool // Queue holds the subscription queue
Queue string Queue string
Internal bool // AutoAck flag for auto ack messages after processing
AutoAck bool
// BodyOnly flag specifies that message without headers
BodyOnly bool BodyOnly bool
Context context.Context
} }
// NewSubscriberOptions create new SubscriberOptions // NewSubscriberOptions create new SubscriberOptions
@@ -358,23 +378,6 @@ func EndpointMetadata(name string, md metadata.Metadata) HandlerOption {
} }
} }
// InternalHandler options specifies that a handler is not advertised
// to the discovery system. In the future this may also limit request
// to the internal network or authorised user.
func InternalHandler(b bool) HandlerOption {
return func(o *HandlerOptions) {
o.Internal = b
}
}
// InternalSubscriber options specifies that a subscriber is not advertised
// to the discovery system.
func InternalSubscriber(b bool) SubscriberOption {
return func(o *SubscriberOptions) {
o.Internal = b
}
}
// DisableAutoAck will disable auto acking of messages // DisableAutoAck will disable auto acking of messages
// after they have been handled. // after they have been handled.
func DisableAutoAck() SubscriberOption { func DisableAutoAck() SubscriberOption {

View File

@@ -72,7 +72,7 @@ func NewRegisterService(s Server) (*register.Service, error) {
} }
node := &register.Node{ node := &register.Node{
Id: opts.Name + "-" + opts.Id, ID: opts.Name + "-" + opts.ID,
Address: net.JoinHostPort(addr, port), Address: net.JoinHostPort(addr, port),
} }
node.Metadata = metadata.Copy(opts.Metadata) node.Metadata = metadata.Copy(opts.Metadata)

View File

@@ -6,12 +6,12 @@ import (
) )
type rpcMessage struct { type rpcMessage struct {
payload interface{}
codec codec.Codec
header metadata.Metadata
topic string topic string
contentType string contentType string
payload interface{}
header metadata.Metadata
body []byte body []byte
codec codec.Codec
} }
func (r *rpcMessage) ContentType() string { func (r *rpcMessage) ContentType() string {

View File

@@ -11,10 +11,8 @@ import (
"github.com/unistack-org/micro/v3/register" "github.com/unistack-org/micro/v3/register"
) )
var ( // DefaultServer default server
// DefaultServer default server var DefaultServer Server = NewServer()
DefaultServer Server = NewServer()
)
var ( var (
// DefaultAddress will be used if no address passed // DefaultAddress will be used if no address passed
@@ -23,8 +21,8 @@ var (
DefaultName = "server" DefaultName = "server"
// DefaultVersion will be used if no version passed // DefaultVersion will be used if no version passed
DefaultVersion = "latest" DefaultVersion = "latest"
// DefaultId will be used if no id passed // DefaultID will be used if no id passed
DefaultId = uuid.New().String() DefaultID = uuid.New().String()
// DefaultRegisterCheck holds func that run before register server // DefaultRegisterCheck holds func that run before register server
DefaultRegisterCheck = func(context.Context) error { return nil } DefaultRegisterCheck = func(context.Context) error { return nil }
// DefaultRegisterInterval holds interval for register // DefaultRegisterInterval holds interval for register
@@ -65,6 +63,7 @@ type Server interface {
String() string String() string
} }
/*
// Router handle serving messages // Router handle serving messages
type Router interface { type Router interface {
// ProcessMessage processes a message // ProcessMessage processes a message
@@ -72,6 +71,7 @@ type Router interface {
// ServeRequest processes a request to completion // ServeRequest processes a request to completion
ServeRequest(ctx context.Context, req Request, rsp Response) error ServeRequest(ctx context.Context, req Request, rsp Response) error
} }
*/
// Message is an async message interface // Message is an async message interface
type Message interface { type Message interface {

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