Compare commits
No commits in common. "v3" and "v3.11.28" have entirely different histories.
@ -1,5 +1,5 @@
|
|||||||
# Micro
|
# Micro
|
||||||
![Coverage](https://img.shields.io/badge/Coverage-44.6%25-yellow)
|
![Coverage](https://img.shields.io/badge/Coverage-45.1%25-yellow)
|
||||||
|
|
||||||
Micro is a standard library for microservices.
|
Micro is a standard library for microservices.
|
||||||
|
|
||||||
|
14
go.mod
14
go.mod
@ -1,12 +1,12 @@
|
|||||||
module go.unistack.org/micro/v3
|
module go.unistack.org/micro/v3
|
||||||
|
|
||||||
go 1.22.0
|
go 1.23.4
|
||||||
|
|
||||||
require (
|
require (
|
||||||
dario.cat/mergo v1.0.1
|
dario.cat/mergo v1.0.1
|
||||||
github.com/DATA-DOG/go-sqlmock v1.5.2
|
github.com/DATA-DOG/go-sqlmock v1.5.0
|
||||||
github.com/KimMachineGun/automemlimit v0.6.1
|
github.com/KimMachineGun/automemlimit v0.6.1
|
||||||
github.com/ash3in/uuidv8 v1.2.0
|
github.com/ash3in/uuidv8 v1.0.1
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/matoous/go-nanoid v1.5.1
|
github.com/matoous/go-nanoid v1.5.1
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||||
@ -14,8 +14,8 @@ require (
|
|||||||
go.uber.org/automaxprocs v1.6.0
|
go.uber.org/automaxprocs v1.6.0
|
||||||
go.unistack.org/micro-proto/v3 v3.4.1
|
go.unistack.org/micro-proto/v3 v3.4.1
|
||||||
golang.org/x/sync v0.10.0
|
golang.org/x/sync v0.10.0
|
||||||
google.golang.org/grpc v1.69.2
|
google.golang.org/grpc v1.68.1
|
||||||
google.golang.org/protobuf v1.36.1
|
google.golang.org/protobuf v1.35.2
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -36,8 +36,8 @@ require (
|
|||||||
github.com/stretchr/testify v1.10.0 // indirect
|
github.com/stretchr/testify v1.10.0 // indirect
|
||||||
go.uber.org/goleak v1.3.0 // indirect
|
go.uber.org/goleak v1.3.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20241210194714-1829a127f884 // indirect
|
golang.org/x/exp v0.0.0-20241210194714-1829a127f884 // indirect
|
||||||
golang.org/x/net v0.33.0 // indirect
|
golang.org/x/net v0.32.0 // indirect
|
||||||
golang.org/x/sys v0.28.0 // indirect
|
golang.org/x/sys v0.28.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241216192217-9240e9c98484 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||||
)
|
)
|
||||||
|
25
go.sum
25
go.sum
@ -1,11 +1,11 @@
|
|||||||
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
|
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
|
||||||
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||||
github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU=
|
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
|
||||||
github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
|
github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||||
github.com/KimMachineGun/automemlimit v0.6.1 h1:ILa9j1onAAMadBsyyUJv5cack8Y1WT26yLj/V+ulKp8=
|
github.com/KimMachineGun/automemlimit v0.6.1 h1:ILa9j1onAAMadBsyyUJv5cack8Y1WT26yLj/V+ulKp8=
|
||||||
github.com/KimMachineGun/automemlimit v0.6.1/go.mod h1:T7xYht7B8r6AG/AqFcUdc7fzd2bIdBKmepfP2S1svPY=
|
github.com/KimMachineGun/automemlimit v0.6.1/go.mod h1:T7xYht7B8r6AG/AqFcUdc7fzd2bIdBKmepfP2S1svPY=
|
||||||
github.com/ash3in/uuidv8 v1.2.0 h1:2oogGdtCPwaVtyvPPGin4TfZLtOGE5F+W++E880G6SI=
|
github.com/ash3in/uuidv8 v1.0.1 h1:dIq1XRkWT8lGA7N5s7WRTB4V3k49WTBLvILz7aCLp80=
|
||||||
github.com/ash3in/uuidv8 v1.2.0/go.mod h1:BnU0wJBxnzdEKmVg4xckBkD+VZuecTFTUP3M0dWgyY4=
|
github.com/ash3in/uuidv8 v1.0.1/go.mod h1:EoyUgCtxNBnrnpc9efw5rVN1cQ+LFGCoJiFuD6maOMw=
|
||||||
github.com/cilium/ebpf v0.16.0 h1:+BiEnHL6Z7lXnlGUsXQPPAE7+kenAd4ES8MQ5min0Ok=
|
github.com/cilium/ebpf v0.16.0 h1:+BiEnHL6Z7lXnlGUsXQPPAE7+kenAd4ES8MQ5min0Ok=
|
||||||
github.com/cilium/ebpf v0.16.0/go.mod h1:L7u2Blt2jMM/vLAVgjxluxtBKlz3/GWjB0dMOEngfwE=
|
github.com/cilium/ebpf v0.16.0/go.mod h1:L7u2Blt2jMM/vLAVgjxluxtBKlz3/GWjB0dMOEngfwE=
|
||||||
github.com/containerd/cgroups/v3 v3.0.4 h1:2fs7l3P0Qxb1nKWuJNFiwhp2CqiKzho71DQkDrHJIo4=
|
github.com/containerd/cgroups/v3 v3.0.4 h1:2fs7l3P0Qxb1nKWuJNFiwhp2CqiKzho71DQkDrHJIo4=
|
||||||
@ -35,7 +35,6 @@ github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtL
|
|||||||
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||||
github.com/jsimonetti/rtnetlink/v2 v2.0.1 h1:xda7qaHDSVOsADNouv7ukSuicKZO7GgVUCXxpaIEIlM=
|
github.com/jsimonetti/rtnetlink/v2 v2.0.1 h1:xda7qaHDSVOsADNouv7ukSuicKZO7GgVUCXxpaIEIlM=
|
||||||
github.com/jsimonetti/rtnetlink/v2 v2.0.1/go.mod h1:7MoNYNbb3UaDHtF8udiJo/RH6VsTKP1pqKLUTVCvToE=
|
github.com/jsimonetti/rtnetlink/v2 v2.0.1/go.mod h1:7MoNYNbb3UaDHtF8udiJo/RH6VsTKP1pqKLUTVCvToE=
|
||||||
github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE=
|
|
||||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
@ -80,8 +79,8 @@ go.unistack.org/micro-proto/v3 v3.4.1 h1:UTjLSRz2YZuaHk9iSlVqqsA50JQNAEK2ZFboGqt
|
|||||||
go.unistack.org/micro-proto/v3 v3.4.1/go.mod h1:okx/cnOhzuCX0ggl/vToatbCupi0O44diiiLLsZ93Zo=
|
go.unistack.org/micro-proto/v3 v3.4.1/go.mod h1:okx/cnOhzuCX0ggl/vToatbCupi0O44diiiLLsZ93Zo=
|
||||||
golang.org/x/exp v0.0.0-20241210194714-1829a127f884 h1:Y/Mj/94zIQQGHVSv1tTtQBDaQaJe62U9bkDZKKyhPCU=
|
golang.org/x/exp v0.0.0-20241210194714-1829a127f884 h1:Y/Mj/94zIQQGHVSv1tTtQBDaQaJe62U9bkDZKKyhPCU=
|
||||||
golang.org/x/exp v0.0.0-20241210194714-1829a127f884/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
|
golang.org/x/exp v0.0.0-20241210194714-1829a127f884/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
|
||||||
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI=
|
||||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
|
||||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
@ -89,12 +88,12 @@ golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
|||||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241216192217-9240e9c98484 h1:Z7FRVJPSMaHQxD0uXU8WdgFh8PseLM8Q8NzhnpMrBhQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 h1:8ZmaLZE4XWrtU3MyClkYqqtl6Oegr3235h7jxsDyqCY=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241216192217-9240e9c98484/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
|
||||||
google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU=
|
google.golang.org/grpc v1.68.1 h1:oI5oTa11+ng8r8XMMN7jAOmWfPZWbYpCFaMUTACxkM0=
|
||||||
google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
|
google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe00waw=
|
||||||
google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
|
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
|
||||||
google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
|
@ -16,25 +16,6 @@ import (
|
|||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v3/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
// always first to have proper check
|
|
||||||
func TestStacktrace(t *testing.T) {
|
|
||||||
ctx := context.TODO()
|
|
||||||
buf := bytes.NewBuffer(nil)
|
|
||||||
l := NewLogger(logger.WithLevel(logger.ErrorLevel), logger.WithOutput(buf),
|
|
||||||
WithHandlerFunc(slog.NewTextHandler),
|
|
||||||
logger.WithAddStacktrace(true),
|
|
||||||
)
|
|
||||||
if err := l.Init(logger.WithFields("key1", "val1")); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
l.Error(ctx, "msg1", errors.New("err"))
|
|
||||||
|
|
||||||
if !bytes.Contains(buf.Bytes(), []byte(`slog_test.go:31`)) {
|
|
||||||
t.Fatalf("logger error not works, buf contains: %s", buf.Bytes())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTime(t *testing.T) {
|
func TestTime(t *testing.T) {
|
||||||
ctx := context.TODO()
|
ctx := context.TODO()
|
||||||
buf := bytes.NewBuffer(nil)
|
buf := bytes.NewBuffer(nil)
|
||||||
@ -51,8 +32,25 @@ func TestTime(t *testing.T) {
|
|||||||
|
|
||||||
l.Error(ctx, "msg1", errors.New("err"))
|
l.Error(ctx, "msg1", errors.New("err"))
|
||||||
|
|
||||||
if !bytes.Contains(buf.Bytes(), []byte(`timestamp=1970-01-01T03:00:00.000000000+03:00`)) &&
|
if !bytes.Contains(buf.Bytes(), []byte(`timestamp=1970-01-01T03:00:00.000000000+03:00`)) {
|
||||||
!bytes.Contains(buf.Bytes(), []byte(`timestamp=1970-01-01T00:00:00.000000000Z`)) {
|
t.Fatalf("logger error not works, buf contains: %s", buf.Bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStacktrace(t *testing.T) {
|
||||||
|
ctx := context.TODO()
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
l := NewLogger(logger.WithLevel(logger.ErrorLevel), logger.WithOutput(buf),
|
||||||
|
WithHandlerFunc(slog.NewTextHandler),
|
||||||
|
logger.WithAddStacktrace(true),
|
||||||
|
)
|
||||||
|
if err := l.Init(logger.WithFields("key1", "val1")); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
l.Error(ctx, "msg1", errors.New("err"))
|
||||||
|
|
||||||
|
if !bytes.Contains(buf.Bytes(), []byte(`slog_test.go:51`)) {
|
||||||
t.Fatalf("logger error not works, buf contains: %s", buf.Bytes())
|
t.Fatalf("logger error not works, buf contains: %s", buf.Bytes())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
package register
|
package register
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"unicode"
|
"unicode"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"go.unistack.org/micro/v3/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ExtractValue from reflect.Type from specified depth
|
// ExtractValue from reflect.Type from specified depth
|
||||||
@ -35,6 +38,53 @@ func ExtractValue(v reflect.Type, d int) string {
|
|||||||
return v.Name()
|
return v.Name()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExtractEndpoint extract *Endpoint from reflect.Method
|
||||||
|
func ExtractEndpoint(method reflect.Method) *Endpoint {
|
||||||
|
if method.PkgPath != "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var rspType, reqType reflect.Type
|
||||||
|
var stream bool
|
||||||
|
mt := method.Type
|
||||||
|
|
||||||
|
switch mt.NumIn() {
|
||||||
|
case 3:
|
||||||
|
reqType = mt.In(1)
|
||||||
|
rspType = mt.In(2)
|
||||||
|
case 4:
|
||||||
|
reqType = mt.In(2)
|
||||||
|
rspType = mt.In(3)
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// are we dealing with a stream?
|
||||||
|
switch rspType.Kind() {
|
||||||
|
case reflect.Func, reflect.Interface:
|
||||||
|
stream = true
|
||||||
|
}
|
||||||
|
|
||||||
|
request := ExtractValue(reqType, 0)
|
||||||
|
response := ExtractValue(rspType, 0)
|
||||||
|
if request == "" || response == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ep := &Endpoint{
|
||||||
|
Name: method.Name,
|
||||||
|
Request: request,
|
||||||
|
Response: response,
|
||||||
|
Metadata: metadata.New(0),
|
||||||
|
}
|
||||||
|
|
||||||
|
if stream {
|
||||||
|
ep.Metadata.Set("stream", fmt.Sprintf("%v", stream))
|
||||||
|
}
|
||||||
|
|
||||||
|
return ep
|
||||||
|
}
|
||||||
|
|
||||||
// ExtractSubValue exctact *Value from reflect.Type
|
// ExtractSubValue exctact *Value from reflect.Type
|
||||||
func ExtractSubValue(typ reflect.Type) string {
|
func ExtractSubValue(typ reflect.Type) string {
|
||||||
var reqType reflect.Type
|
var reqType reflect.Type
|
||||||
|
@ -2,6 +2,8 @@ package register
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TestHandler struct{}
|
type TestHandler struct{}
|
||||||
@ -13,3 +15,40 @@ type TestResponse struct{}
|
|||||||
func (t *TestHandler) Test(ctx context.Context, req *TestRequest, rsp *TestResponse) error {
|
func (t *TestHandler) Test(ctx context.Context, req *TestRequest, rsp *TestResponse) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestExtractEndpoint(t *testing.T) {
|
||||||
|
handler := &TestHandler{}
|
||||||
|
typ := reflect.TypeOf(handler)
|
||||||
|
|
||||||
|
var endpoints []*Endpoint
|
||||||
|
|
||||||
|
for m := 0; m < typ.NumMethod(); m++ {
|
||||||
|
if e := ExtractEndpoint(typ.Method(m)); e != nil {
|
||||||
|
endpoints = append(endpoints, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if i := len(endpoints); i != 1 {
|
||||||
|
t.Fatalf("Expected 1 endpoint, have %d", i)
|
||||||
|
}
|
||||||
|
|
||||||
|
if endpoints[0].Name != "Test" {
|
||||||
|
t.Fatalf("Expected handler Test, got %s", endpoints[0].Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if endpoints[0].Request == "" {
|
||||||
|
t.Fatal("Expected non nil Request")
|
||||||
|
}
|
||||||
|
|
||||||
|
if endpoints[0].Response == "" {
|
||||||
|
t.Fatal("Expected non nil Request")
|
||||||
|
}
|
||||||
|
|
||||||
|
if endpoints[0].Request != "TestRequest" {
|
||||||
|
t.Fatalf("Expected TestRequest got %s", endpoints[0].Request)
|
||||||
|
}
|
||||||
|
|
||||||
|
if endpoints[0].Response != "TestResponse" {
|
||||||
|
t.Fatalf("Expected TestResponse got %s", endpoints[0].Response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -23,10 +23,11 @@ type node struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type record struct {
|
type record struct {
|
||||||
Name string
|
Name string
|
||||||
Version string
|
Version string
|
||||||
Metadata map[string]string
|
Metadata map[string]string
|
||||||
Nodes map[string]*node
|
Nodes map[string]*node
|
||||||
|
Endpoints []*register.Endpoint
|
||||||
}
|
}
|
||||||
|
|
||||||
type memory struct {
|
type memory struct {
|
||||||
@ -58,7 +59,7 @@ func (m *memory) ttlPrune() {
|
|||||||
|
|
||||||
for range prune.C {
|
for range prune.C {
|
||||||
m.Lock()
|
m.Lock()
|
||||||
for namespace, services := range m.records {
|
for domain, services := range m.records {
|
||||||
for service, versions := range services {
|
for service, versions := range services {
|
||||||
for version, record := range versions {
|
for version, record := range versions {
|
||||||
for id, n := range record.Nodes {
|
for id, n := range record.Nodes {
|
||||||
@ -66,7 +67,7 @@ func (m *memory) ttlPrune() {
|
|||||||
if m.opts.Logger.V(logger.DebugLevel) {
|
if m.opts.Logger.V(logger.DebugLevel) {
|
||||||
m.opts.Logger.Debug(m.opts.Context, fmt.Sprintf("Register TTL expired for node %s of service %s", n.ID, service))
|
m.opts.Logger.Debug(m.opts.Context, fmt.Sprintf("Register TTL expired for node %s of service %s", n.ID, service))
|
||||||
}
|
}
|
||||||
delete(m.records[namespace][service][version].Nodes, id)
|
delete(m.records[domain][service][version].Nodes, id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -130,12 +131,17 @@ func (m *memory) Register(_ context.Context, s *register.Service, opts ...regist
|
|||||||
options := register.NewRegisterOptions(opts...)
|
options := register.NewRegisterOptions(opts...)
|
||||||
|
|
||||||
// get the services for this domain from the register
|
// get the services for this domain from the register
|
||||||
srvs, ok := m.records[options.Namespace]
|
srvs, ok := m.records[options.Domain]
|
||||||
if !ok {
|
if !ok {
|
||||||
srvs = make(services)
|
srvs = make(services)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Namespace = options.Namespace
|
// domain is set in metadata so it can be passed to watchers
|
||||||
|
if s.Metadata == nil {
|
||||||
|
s.Metadata = map[string]string{"domain": options.Domain}
|
||||||
|
} else {
|
||||||
|
s.Metadata["domain"] = options.Domain
|
||||||
|
}
|
||||||
|
|
||||||
// ensure the service name exists
|
// ensure the service name exists
|
||||||
r := serviceToRecord(s, options.TTL)
|
r := serviceToRecord(s, options.TTL)
|
||||||
@ -148,7 +154,7 @@ func (m *memory) Register(_ context.Context, s *register.Service, opts ...regist
|
|||||||
if m.opts.Logger.V(logger.DebugLevel) {
|
if m.opts.Logger.V(logger.DebugLevel) {
|
||||||
m.opts.Logger.Debug(m.opts.Context, fmt.Sprintf("Register added new service: %s, version: %s", s.Name, s.Version))
|
m.opts.Logger.Debug(m.opts.Context, fmt.Sprintf("Register added new service: %s, version: %s", s.Name, s.Version))
|
||||||
}
|
}
|
||||||
m.records[options.Namespace] = srvs
|
m.records[options.Domain] = srvs
|
||||||
go m.sendEvent(®ister.Result{Action: "create", Service: s})
|
go m.sendEvent(®ister.Result{Action: "create", Service: s})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,6 +173,9 @@ func (m *memory) Register(_ context.Context, s *register.Service, opts ...regist
|
|||||||
metadata[k] = v
|
metadata[k] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set the 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: ®ister.Node{
|
Node: ®ister.Node{
|
||||||
@ -197,7 +206,7 @@ func (m *memory) Register(_ context.Context, s *register.Service, opts ...regist
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m.records[options.Namespace] = srvs
|
m.records[options.Domain] = srvs
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,8 +216,15 @@ func (m *memory) Deregister(ctx context.Context, s *register.Service, opts ...re
|
|||||||
|
|
||||||
options := register.NewDeregisterOptions(opts...)
|
options := register.NewDeregisterOptions(opts...)
|
||||||
|
|
||||||
|
// domain is set in metadata so it can be passed to watchers
|
||||||
|
if s.Metadata == nil {
|
||||||
|
s.Metadata = map[string]string{"domain": options.Domain}
|
||||||
|
} else {
|
||||||
|
s.Metadata["domain"] = options.Domain
|
||||||
|
}
|
||||||
|
|
||||||
// if the domain doesn't exist, there is nothing to deregister
|
// if the domain doesn't exist, there is nothing to deregister
|
||||||
services, ok := m.records[options.Namespace]
|
services, ok := m.records[options.Domain]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -237,7 +253,7 @@ func (m *memory) Deregister(ctx context.Context, s *register.Service, opts ...re
|
|||||||
// if the nodes not empty, we replace the version in the store and exist, the rest of the logic
|
// if the nodes not empty, we replace the version in the store and exist, the rest of the logic
|
||||||
// is cleanup
|
// is cleanup
|
||||||
if len(version.Nodes) > 0 {
|
if len(version.Nodes) > 0 {
|
||||||
m.records[options.Namespace][s.Name][s.Version] = version
|
m.records[options.Domain][s.Name][s.Version] = version
|
||||||
go m.sendEvent(®ister.Result{Action: "update", Service: s})
|
go m.sendEvent(®ister.Result{Action: "update", Service: s})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -245,7 +261,7 @@ func (m *memory) Deregister(ctx context.Context, s *register.Service, opts ...re
|
|||||||
// if this version was the only version of the service, we can remove the whole service from the
|
// if this version was the only version of the service, we can remove the whole service from the
|
||||||
// register and exit
|
// register and exit
|
||||||
if len(versions) == 1 {
|
if len(versions) == 1 {
|
||||||
delete(m.records[options.Namespace], s.Name)
|
delete(m.records[options.Domain], s.Name)
|
||||||
go m.sendEvent(®ister.Result{Action: "delete", Service: s})
|
go m.sendEvent(®ister.Result{Action: "delete", Service: s})
|
||||||
|
|
||||||
if m.opts.Logger.V(logger.DebugLevel) {
|
if m.opts.Logger.V(logger.DebugLevel) {
|
||||||
@ -255,7 +271,7 @@ func (m *memory) Deregister(ctx context.Context, s *register.Service, opts ...re
|
|||||||
}
|
}
|
||||||
|
|
||||||
// there are other versions of the service running, so only remove this version of it
|
// there are other versions of the service running, so only remove this version of it
|
||||||
delete(m.records[options.Namespace][s.Name], s.Version)
|
delete(m.records[options.Domain][s.Name], s.Version)
|
||||||
go m.sendEvent(®ister.Result{Action: "delete", Service: s})
|
go m.sendEvent(®ister.Result{Action: "delete", Service: s})
|
||||||
if m.opts.Logger.V(logger.DebugLevel) {
|
if m.opts.Logger.V(logger.DebugLevel) {
|
||||||
m.opts.Logger.Debug(m.opts.Context, fmt.Sprintf("Register removed service: %s, version: %s", s.Name, s.Version))
|
m.opts.Logger.Debug(m.opts.Context, fmt.Sprintf("Register removed service: %s, version: %s", s.Name, s.Version))
|
||||||
@ -268,15 +284,15 @@ func (m *memory) LookupService(ctx context.Context, name string, opts ...registe
|
|||||||
options := register.NewLookupOptions(opts...)
|
options := register.NewLookupOptions(opts...)
|
||||||
|
|
||||||
// if it's a wildcard domain, return from all domains
|
// if it's a wildcard domain, return from all domains
|
||||||
if options.Namespace == register.WildcardNamespace {
|
if options.Domain == register.WildcardDomain {
|
||||||
m.RLock()
|
m.RLock()
|
||||||
recs := m.records
|
recs := m.records
|
||||||
m.RUnlock()
|
m.RUnlock()
|
||||||
|
|
||||||
var services []*register.Service
|
var services []*register.Service
|
||||||
|
|
||||||
for namespace := range recs {
|
for domain := range recs {
|
||||||
srvs, err := m.LookupService(ctx, name, append(opts, register.LookupNamespace(namespace))...)
|
srvs, err := m.LookupService(ctx, name, append(opts, register.LookupDomain(domain))...)
|
||||||
if err == register.ErrNotFound {
|
if err == register.ErrNotFound {
|
||||||
continue
|
continue
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
@ -295,7 +311,7 @@ func (m *memory) LookupService(ctx context.Context, name string, opts ...registe
|
|||||||
defer m.RUnlock()
|
defer m.RUnlock()
|
||||||
|
|
||||||
// check the domain exists
|
// check the domain exists
|
||||||
services, ok := m.records[options.Namespace]
|
services, ok := m.records[options.Domain]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, register.ErrNotFound
|
return nil, register.ErrNotFound
|
||||||
}
|
}
|
||||||
@ -312,7 +328,7 @@ func (m *memory) LookupService(ctx context.Context, name string, opts ...registe
|
|||||||
var i int
|
var i int
|
||||||
|
|
||||||
for _, r := range versions {
|
for _, r := range versions {
|
||||||
result[i] = recordToService(r, options.Namespace)
|
result[i] = recordToService(r, options.Domain)
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -323,15 +339,15 @@ func (m *memory) ListServices(ctx context.Context, opts ...register.ListOption)
|
|||||||
options := register.NewListOptions(opts...)
|
options := register.NewListOptions(opts...)
|
||||||
|
|
||||||
// if it's a wildcard domain, list from all domains
|
// if it's a wildcard domain, list from all domains
|
||||||
if options.Namespace == register.WildcardNamespace {
|
if options.Domain == register.WildcardDomain {
|
||||||
m.RLock()
|
m.RLock()
|
||||||
recs := m.records
|
recs := m.records
|
||||||
m.RUnlock()
|
m.RUnlock()
|
||||||
|
|
||||||
var services []*register.Service
|
var services []*register.Service
|
||||||
|
|
||||||
for namespace := range recs {
|
for domain := range recs {
|
||||||
srvs, err := m.ListServices(ctx, append(opts, register.ListNamespace(namespace))...)
|
srvs, err := m.ListServices(ctx, append(opts, register.ListDomain(domain))...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -345,7 +361,7 @@ func (m *memory) ListServices(ctx context.Context, opts ...register.ListOption)
|
|||||||
defer m.RUnlock()
|
defer m.RUnlock()
|
||||||
|
|
||||||
// ensure the domain exists
|
// ensure the domain exists
|
||||||
services, ok := m.records[options.Namespace]
|
services, ok := m.records[options.Domain]
|
||||||
if !ok {
|
if !ok {
|
||||||
return make([]*register.Service, 0), nil
|
return make([]*register.Service, 0), nil
|
||||||
}
|
}
|
||||||
@ -355,7 +371,7 @@ func (m *memory) ListServices(ctx context.Context, opts ...register.ListOption)
|
|||||||
|
|
||||||
for _, service := range services {
|
for _, service := range services {
|
||||||
for _, version := range service {
|
for _, version := range service {
|
||||||
result = append(result, recordToService(version, options.Namespace))
|
result = append(result, recordToService(version, options.Domain))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -410,13 +426,16 @@ func (m *watcher) Next() (*register.Result, error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace := register.DefaultNamespace
|
// extract domain from service metadata
|
||||||
if r.Service.Namespace != "" {
|
var domain string
|
||||||
namespace = r.Service.Namespace
|
if r.Service.Metadata != nil && len(r.Service.Metadata["domain"]) > 0 {
|
||||||
|
domain = r.Service.Metadata["domain"]
|
||||||
|
} else {
|
||||||
|
domain = register.DefaultDomain
|
||||||
}
|
}
|
||||||
|
|
||||||
// only send the event if watching the wildcard or this specific domain
|
// only send the event if watching the wildcard or this specific domain
|
||||||
if m.wo.Namespace == register.WildcardNamespace || m.wo.Namespace == namespace {
|
if m.wo.Domain == register.WildcardDomain || m.wo.Domain == domain {
|
||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
case <-m.exit:
|
case <-m.exit:
|
||||||
@ -435,6 +454,11 @@ func (m *watcher) Stop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func serviceToRecord(s *register.Service, ttl time.Duration) *record {
|
func serviceToRecord(s *register.Service, ttl time.Duration) *record {
|
||||||
|
metadata := make(map[string]string, len(s.Metadata))
|
||||||
|
for k, v := range s.Metadata {
|
||||||
|
metadata[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
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{
|
||||||
@ -444,19 +468,42 @@ func serviceToRecord(s *register.Service, ttl time.Duration) *record {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
endpoints := make([]*register.Endpoint, len(s.Endpoints))
|
||||||
|
copy(endpoints, s.Endpoints)
|
||||||
|
|
||||||
return &record{
|
return &record{
|
||||||
Name: s.Name,
|
Name: s.Name,
|
||||||
Version: s.Version,
|
Version: s.Version,
|
||||||
Nodes: nodes,
|
Metadata: metadata,
|
||||||
|
Nodes: nodes,
|
||||||
|
Endpoints: endpoints,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func recordToService(r *record, namespace string) *register.Service {
|
func recordToService(r *record, domain string) *register.Service {
|
||||||
metadata := make(map[string]string, len(r.Metadata))
|
metadata := make(map[string]string, len(r.Metadata))
|
||||||
for k, v := range r.Metadata {
|
for k, v := range r.Metadata {
|
||||||
metadata[k] = v
|
metadata[k] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set the domain in metadata so it can be determined when a wildcard query is performed
|
||||||
|
metadata["domain"] = domain
|
||||||
|
|
||||||
|
endpoints := make([]*register.Endpoint, len(r.Endpoints))
|
||||||
|
for i, e := range r.Endpoints {
|
||||||
|
md := make(map[string]string, len(e.Metadata))
|
||||||
|
for k, v := range e.Metadata {
|
||||||
|
md[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoints[i] = ®ister.Endpoint{
|
||||||
|
Name: e.Name,
|
||||||
|
Request: e.Request,
|
||||||
|
Response: e.Response,
|
||||||
|
Metadata: md,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
nodes := make([]*register.Node, len(r.Nodes))
|
nodes := make([]*register.Node, len(r.Nodes))
|
||||||
i := 0
|
i := 0
|
||||||
for _, n := range r.Nodes {
|
for _, n := range r.Nodes {
|
||||||
@ -476,7 +523,8 @@ func recordToService(r *record, namespace string) *register.Service {
|
|||||||
return ®ister.Service{
|
return ®ister.Service{
|
||||||
Name: r.Name,
|
Name: r.Name,
|
||||||
Version: r.Version,
|
Version: r.Version,
|
||||||
|
Metadata: metadata,
|
||||||
|
Endpoints: endpoints,
|
||||||
Nodes: nodes,
|
Nodes: nodes,
|
||||||
Namespace: namespace,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -253,32 +253,32 @@ func TestMemoryWildcard(t *testing.T) {
|
|||||||
|
|
||||||
testSrv := ®ister.Service{Name: "foo", Version: "1.0.0"}
|
testSrv := ®ister.Service{Name: "foo", Version: "1.0.0"}
|
||||||
|
|
||||||
if err := m.Register(ctx, testSrv, register.RegisterNamespace("one")); err != nil {
|
if err := m.Register(ctx, testSrv, register.RegisterDomain("one")); err != nil {
|
||||||
t.Fatalf("Register err: %v", err)
|
t.Fatalf("Register err: %v", err)
|
||||||
}
|
}
|
||||||
if err := m.Register(ctx, testSrv, register.RegisterNamespace("two")); err != nil {
|
if err := m.Register(ctx, testSrv, register.RegisterDomain("two")); err != nil {
|
||||||
t.Fatalf("Register err: %v", err)
|
t.Fatalf("Register err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if recs, err := m.ListServices(ctx, register.ListNamespace("one")); err != nil {
|
if recs, err := m.ListServices(ctx, register.ListDomain("one")); err != nil {
|
||||||
t.Errorf("List err: %v", err)
|
t.Errorf("List err: %v", err)
|
||||||
} else if len(recs) != 1 {
|
} else if len(recs) != 1 {
|
||||||
t.Errorf("Expected 1 record, got %v", len(recs))
|
t.Errorf("Expected 1 record, got %v", len(recs))
|
||||||
}
|
}
|
||||||
|
|
||||||
if recs, err := m.ListServices(ctx, register.ListNamespace("*")); err != nil {
|
if recs, err := m.ListServices(ctx, register.ListDomain("*")); err != nil {
|
||||||
t.Errorf("List err: %v", err)
|
t.Errorf("List err: %v", err)
|
||||||
} else if len(recs) != 2 {
|
} else if len(recs) != 2 {
|
||||||
t.Errorf("Expected 2 records, got %v", len(recs))
|
t.Errorf("Expected 2 records, got %v", len(recs))
|
||||||
}
|
}
|
||||||
|
|
||||||
if recs, err := m.LookupService(ctx, testSrv.Name, register.LookupNamespace("one")); err != nil {
|
if recs, err := m.LookupService(ctx, testSrv.Name, register.LookupDomain("one")); err != nil {
|
||||||
t.Errorf("Lookup err: %v", err)
|
t.Errorf("Lookup err: %v", err)
|
||||||
} else if len(recs) != 1 {
|
} else if len(recs) != 1 {
|
||||||
t.Errorf("Expected 1 record, got %v", len(recs))
|
t.Errorf("Expected 1 record, got %v", len(recs))
|
||||||
}
|
}
|
||||||
|
|
||||||
if recs, err := m.LookupService(ctx, testSrv.Name, register.LookupNamespace("*")); err != nil {
|
if recs, err := m.LookupService(ctx, testSrv.Name, register.LookupDomain("*")); err != nil {
|
||||||
t.Errorf("Lookup err: %v", err)
|
t.Errorf("Lookup err: %v", err)
|
||||||
} else if len(recs) != 2 {
|
} else if len(recs) != 2 {
|
||||||
t.Errorf("Expected 2 records, got %v", len(recs))
|
t.Errorf("Expected 2 records, got %v", len(recs))
|
||||||
|
@ -46,17 +46,17 @@ func NewOptions(opts ...Option) Options {
|
|||||||
|
|
||||||
// RegisterOptions holds options for register method
|
// RegisterOptions holds options for register method
|
||||||
type RegisterOptions struct { // nolint: golint,revive
|
type RegisterOptions struct { // nolint: golint,revive
|
||||||
Context context.Context
|
Context context.Context
|
||||||
Namespace string
|
Domain string
|
||||||
TTL time.Duration
|
TTL time.Duration
|
||||||
Attempts int
|
Attempts int
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRegisterOptions returns register options struct filled by opts
|
// NewRegisterOptions returns register options struct filled by opts
|
||||||
func NewRegisterOptions(opts ...RegisterOption) RegisterOptions {
|
func NewRegisterOptions(opts ...RegisterOption) RegisterOptions {
|
||||||
options := RegisterOptions{
|
options := RegisterOptions{
|
||||||
Namespace: DefaultNamespace,
|
Domain: DefaultDomain,
|
||||||
Context: context.Background(),
|
Context: context.Background(),
|
||||||
}
|
}
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
o(&options)
|
o(&options)
|
||||||
@ -72,15 +72,15 @@ type WatchOptions struct {
|
|||||||
// Other options for implementations of the interface
|
// Other options for implementations of the interface
|
||||||
// can be stored in a context
|
// can be stored in a context
|
||||||
Context context.Context
|
Context context.Context
|
||||||
// Namespace to watch
|
// Domain to watch
|
||||||
Namespace string
|
Domain string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWatchOptions returns watch options filled by opts
|
// NewWatchOptions returns watch options filled by opts
|
||||||
func NewWatchOptions(opts ...WatchOption) WatchOptions {
|
func NewWatchOptions(opts ...WatchOption) WatchOptions {
|
||||||
options := WatchOptions{
|
options := WatchOptions{
|
||||||
Namespace: DefaultNamespace,
|
Domain: DefaultDomain,
|
||||||
Context: context.Background(),
|
Context: context.Background(),
|
||||||
}
|
}
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
o(&options)
|
o(&options)
|
||||||
@ -91,8 +91,8 @@ func NewWatchOptions(opts ...WatchOption) WatchOptions {
|
|||||||
// DeregisterOptions holds options for deregister method
|
// DeregisterOptions holds options for deregister method
|
||||||
type DeregisterOptions struct {
|
type DeregisterOptions struct {
|
||||||
Context context.Context
|
Context context.Context
|
||||||
// Namespace the service was registered in
|
// Domain the service was registered in
|
||||||
Namespace string
|
Domain string
|
||||||
// Atempts specify max attempts for deregister
|
// Atempts specify max attempts for deregister
|
||||||
Attempts int
|
Attempts int
|
||||||
}
|
}
|
||||||
@ -100,8 +100,8 @@ type DeregisterOptions struct {
|
|||||||
// NewDeregisterOptions returns options for deregister filled by opts
|
// NewDeregisterOptions returns options for deregister filled by opts
|
||||||
func NewDeregisterOptions(opts ...DeregisterOption) DeregisterOptions {
|
func NewDeregisterOptions(opts ...DeregisterOption) DeregisterOptions {
|
||||||
options := DeregisterOptions{
|
options := DeregisterOptions{
|
||||||
Namespace: DefaultNamespace,
|
Domain: DefaultDomain,
|
||||||
Context: context.Background(),
|
Context: context.Background(),
|
||||||
}
|
}
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
o(&options)
|
o(&options)
|
||||||
@ -112,15 +112,15 @@ func NewDeregisterOptions(opts ...DeregisterOption) DeregisterOptions {
|
|||||||
// LookupOptions holds lookup options
|
// LookupOptions holds lookup options
|
||||||
type LookupOptions struct {
|
type LookupOptions struct {
|
||||||
Context context.Context
|
Context context.Context
|
||||||
// Namespace to scope the request to
|
// Domain to scope the request to
|
||||||
Namespace string
|
Domain string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLookupOptions returns lookup options filled by opts
|
// NewLookupOptions returns lookup options filled by opts
|
||||||
func NewLookupOptions(opts ...LookupOption) LookupOptions {
|
func NewLookupOptions(opts ...LookupOption) LookupOptions {
|
||||||
options := LookupOptions{
|
options := LookupOptions{
|
||||||
Namespace: DefaultNamespace,
|
Domain: DefaultDomain,
|
||||||
Context: context.Background(),
|
Context: context.Background(),
|
||||||
}
|
}
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
o(&options)
|
o(&options)
|
||||||
@ -131,15 +131,15 @@ func NewLookupOptions(opts ...LookupOption) LookupOptions {
|
|||||||
// ListOptions holds the list options for list method
|
// ListOptions holds the list options for list method
|
||||||
type ListOptions struct {
|
type ListOptions struct {
|
||||||
Context context.Context
|
Context context.Context
|
||||||
// Namespace to scope the request to
|
// Domain to scope the request to
|
||||||
Namespace string
|
Domain string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewListOptions returns list options filled by opts
|
// NewListOptions returns list options filled by opts
|
||||||
func NewListOptions(opts ...ListOption) ListOptions {
|
func NewListOptions(opts ...ListOption) ListOptions {
|
||||||
options := ListOptions{
|
options := ListOptions{
|
||||||
Namespace: DefaultNamespace,
|
Domain: DefaultDomain,
|
||||||
Context: context.Background(),
|
Context: context.Background(),
|
||||||
}
|
}
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
o(&options)
|
o(&options)
|
||||||
@ -217,10 +217,10 @@ func RegisterContext(ctx context.Context) RegisterOption { // nolint: golint,rev
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterNamespace secifies register Namespace
|
// RegisterDomain secifies register domain
|
||||||
func RegisterNamespace(d string) RegisterOption { // nolint: golint,revive
|
func RegisterDomain(d string) RegisterOption { // nolint: golint,revive
|
||||||
return func(o *RegisterOptions) {
|
return func(o *RegisterOptions) {
|
||||||
o.Namespace = d
|
o.Domain = d
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,10 +238,10 @@ func WatchContext(ctx context.Context) WatchOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WatchNamespace sets the Namespace for watch
|
// WatchDomain sets the domain for watch
|
||||||
func WatchNamespace(d string) WatchOption {
|
func WatchDomain(d string) WatchOption {
|
||||||
return func(o *WatchOptions) {
|
return func(o *WatchOptions) {
|
||||||
o.Namespace = d
|
o.Domain = d
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,10 +259,10 @@ func DeregisterContext(ctx context.Context) DeregisterOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeregisterNamespace specifies deregister Namespace
|
// DeregisterDomain specifies deregister domain
|
||||||
func DeregisterNamespace(d string) DeregisterOption {
|
func DeregisterDomain(d string) DeregisterOption {
|
||||||
return func(o *DeregisterOptions) {
|
return func(o *DeregisterOptions) {
|
||||||
o.Namespace = d
|
o.Domain = d
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -273,10 +273,10 @@ func LookupContext(ctx context.Context) LookupOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// LookupNamespace sets the Namespace for lookup
|
// LookupDomain sets the domain for lookup
|
||||||
func LookupNamespace(d string) LookupOption {
|
func LookupDomain(d string) LookupOption {
|
||||||
return func(o *LookupOptions) {
|
return func(o *LookupOptions) {
|
||||||
o.Namespace = d
|
o.Domain = d
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,10 +287,10 @@ func ListContext(ctx context.Context) ListOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListNamespace sets the Namespace for list method
|
// ListDomain sets the domain for list method
|
||||||
func ListNamespace(d string) ListOption {
|
func ListDomain(d string) ListOption {
|
||||||
return func(o *ListOptions) {
|
return func(o *ListOptions) {
|
||||||
o.Namespace = d
|
o.Domain = d
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,12 +9,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// WildcardNamespace indicates any Namespace
|
// WildcardDomain indicates any domain
|
||||||
WildcardNamespace = "*"
|
WildcardDomain = "*"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DefaultNamespace to use if none was provided in options
|
// DefaultDomain to use if none was provided in options
|
||||||
var DefaultNamespace = "micro"
|
var DefaultDomain = "micro"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// DefaultRegister is the global default register
|
// DefaultRegister is the global default register
|
||||||
@ -59,17 +59,26 @@ type Register interface {
|
|||||||
|
|
||||||
// Service holds service register info
|
// Service holds service register info
|
||||||
type Service struct {
|
type Service struct {
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name"`
|
||||||
Version string `json:"version,omitempty"`
|
Version string `json:"version"`
|
||||||
Nodes []*Node `json:"nodes,omitempty"`
|
Metadata metadata.Metadata `json:"metadata"`
|
||||||
Namespace string `json:"namespace,omitempty"`
|
Endpoints []*Endpoint `json:"endpoints"`
|
||||||
|
Nodes []*Node `json:"nodes"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Node holds node register info
|
// Node holds node register info
|
||||||
type Node struct {
|
type Node struct {
|
||||||
Metadata metadata.Metadata `json:"metadata,omitempty"`
|
Metadata metadata.Metadata `json:"metadata"`
|
||||||
ID string `json:"id,omitempty"`
|
ID string `json:"id"`
|
||||||
Address string `json:"address,omitempty"`
|
Address string `json:"address"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Endpoint holds endpoint register info
|
||||||
|
type Endpoint struct {
|
||||||
|
Request string `json:"request"`
|
||||||
|
Response string `json:"response"`
|
||||||
|
Metadata metadata.Metadata `json:"metadata"`
|
||||||
|
Name string `json:"name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Option func signature
|
// Option func signature
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@ -31,21 +32,38 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type rpcHandler struct {
|
type rpcHandler struct {
|
||||||
opts HandlerOptions
|
opts HandlerOptions
|
||||||
handler interface{}
|
handler interface{}
|
||||||
name string
|
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)
|
||||||
hdlr := reflect.ValueOf(handler)
|
hdlr := reflect.ValueOf(handler)
|
||||||
name := reflect.Indirect(hdlr).Type().Name()
|
name := reflect.Indirect(hdlr).Type().Name()
|
||||||
|
|
||||||
|
var endpoints []*register.Endpoint
|
||||||
|
|
||||||
|
for m := 0; m < typ.NumMethod(); m++ {
|
||||||
|
if e := register.ExtractEndpoint(typ.Method(m)); e != nil {
|
||||||
|
e.Name = name + "." + e.Name
|
||||||
|
|
||||||
|
for k, v := range options.Metadata[e.Name] {
|
||||||
|
e.Metadata[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoints = append(endpoints, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return &rpcHandler{
|
return &rpcHandler{
|
||||||
name: name,
|
name: name,
|
||||||
handler: handler,
|
handler: handler,
|
||||||
opts: options,
|
endpoints: endpoints,
|
||||||
|
opts: options,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,6 +75,10 @@ func (r *rpcHandler) Handler() interface{} {
|
|||||||
return r.handler
|
return r.handler
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *rpcHandler) Endpoints() []*register.Endpoint {
|
||||||
|
return r.endpoints
|
||||||
|
}
|
||||||
|
|
||||||
func (r *rpcHandler) Options() HandlerOptions {
|
func (r *rpcHandler) Options() HandlerOptions {
|
||||||
return r.opts
|
return r.opts
|
||||||
}
|
}
|
||||||
@ -227,6 +249,35 @@ func (n *noopServer) Register() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
n.RLock()
|
||||||
|
handlerList := make([]string, 0, len(n.handlers))
|
||||||
|
for n := range n.handlers {
|
||||||
|
handlerList = append(handlerList, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(handlerList)
|
||||||
|
|
||||||
|
subscriberList := make([]*subscriber, 0, len(n.subscribers))
|
||||||
|
for e := range n.subscribers {
|
||||||
|
subscriberList = append(subscriberList, e)
|
||||||
|
}
|
||||||
|
sort.Slice(subscriberList, func(i, j int) bool {
|
||||||
|
return subscriberList[i].topic > subscriberList[j].topic
|
||||||
|
})
|
||||||
|
|
||||||
|
endpoints := make([]*register.Endpoint, 0, len(handlerList)+len(subscriberList))
|
||||||
|
for _, h := range handlerList {
|
||||||
|
endpoints = append(endpoints, n.handlers[h].Endpoints()...)
|
||||||
|
}
|
||||||
|
for _, e := range subscriberList {
|
||||||
|
endpoints = append(endpoints, e.Endpoints()...)
|
||||||
|
}
|
||||||
|
n.RUnlock()
|
||||||
|
|
||||||
|
service.Nodes[0].Metadata["protocol"] = "noop"
|
||||||
|
service.Nodes[0].Metadata["transport"] = service.Nodes[0].Metadata["protocol"]
|
||||||
|
service.Endpoints = endpoints
|
||||||
|
|
||||||
n.RLock()
|
n.RLock()
|
||||||
registered := n.registered
|
registered := n.registered
|
||||||
n.RUnlock()
|
n.RUnlock()
|
||||||
@ -525,6 +576,7 @@ func (n *noopServer) Stop() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newSubscriber(topic string, sub interface{}, opts ...SubscriberOption) Subscriber {
|
func newSubscriber(topic string, sub interface{}, opts ...SubscriberOption) Subscriber {
|
||||||
|
var endpoints []*register.Endpoint
|
||||||
var handlers []*handler
|
var handlers []*handler
|
||||||
|
|
||||||
options := NewSubscriberOptions(opts...)
|
options := NewSubscriberOptions(opts...)
|
||||||
@ -543,7 +595,18 @@ func newSubscriber(topic string, sub interface{}, opts ...SubscriberOption) Subs
|
|||||||
}
|
}
|
||||||
|
|
||||||
handlers = append(handlers, h)
|
handlers = append(handlers, h)
|
||||||
|
ep := ®ister.Endpoint{
|
||||||
|
Name: "Func",
|
||||||
|
Request: register.ExtractSubValue(typ),
|
||||||
|
Metadata: metadata.New(2),
|
||||||
|
}
|
||||||
|
ep.Metadata.Set("topic", topic)
|
||||||
|
ep.Metadata.Set("subscriber", "true")
|
||||||
|
endpoints = append(endpoints, ep)
|
||||||
} else {
|
} else {
|
||||||
|
hdlr := reflect.ValueOf(sub)
|
||||||
|
name := reflect.Indirect(hdlr).Type().Name()
|
||||||
|
|
||||||
for m := 0; m < typ.NumMethod(); m++ {
|
for m := 0; m < typ.NumMethod(); m++ {
|
||||||
method := typ.Method(m)
|
method := typ.Method(m)
|
||||||
h := &handler{
|
h := &handler{
|
||||||
@ -559,6 +622,14 @@ func newSubscriber(topic string, sub interface{}, opts ...SubscriberOption) Subs
|
|||||||
}
|
}
|
||||||
|
|
||||||
handlers = append(handlers, h)
|
handlers = append(handlers, h)
|
||||||
|
ep := ®ister.Endpoint{
|
||||||
|
Name: name + "." + method.Name,
|
||||||
|
Request: register.ExtractSubValue(method.Type),
|
||||||
|
Metadata: metadata.New(2),
|
||||||
|
}
|
||||||
|
ep.Metadata.Set("topic", topic)
|
||||||
|
ep.Metadata.Set("subscriber", "true")
|
||||||
|
endpoints = append(endpoints, ep)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -568,6 +639,7 @@ func newSubscriber(topic string, sub interface{}, opts ...SubscriberOption) Subs
|
|||||||
topic: topic,
|
topic: topic,
|
||||||
subscriber: sub,
|
subscriber: sub,
|
||||||
handlers: handlers,
|
handlers: handlers,
|
||||||
|
endpoints: endpoints,
|
||||||
opts: options,
|
opts: options,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -694,6 +766,10 @@ func (s *subscriber) Subscriber() interface{} {
|
|||||||
return s.subscriber
|
return s.subscriber
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *subscriber) Endpoints() []*register.Endpoint {
|
||||||
|
return s.endpoints
|
||||||
|
}
|
||||||
|
|
||||||
func (s *subscriber) Options() SubscriberOptions {
|
func (s *subscriber) Options() SubscriberOptions {
|
||||||
return s.opts
|
return s.opts
|
||||||
}
|
}
|
||||||
@ -704,7 +780,8 @@ type subscriber struct {
|
|||||||
typ reflect.Type
|
typ reflect.Type
|
||||||
subscriber interface{}
|
subscriber interface{}
|
||||||
|
|
||||||
handlers []*handler
|
endpoints []*register.Endpoint
|
||||||
|
handlers []*handler
|
||||||
|
|
||||||
rcvr reflect.Value
|
rcvr reflect.Value
|
||||||
opts SubscriberOptions
|
opts SubscriberOptions
|
||||||
|
@ -17,7 +17,7 @@ var (
|
|||||||
|
|
||||||
opts := []register.RegisterOption{
|
opts := []register.RegisterOption{
|
||||||
register.RegisterTTL(config.RegisterTTL),
|
register.RegisterTTL(config.RegisterTTL),
|
||||||
register.RegisterNamespace(config.Namespace),
|
register.RegisterDomain(config.Namespace),
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i <= config.RegisterAttempts; i++ {
|
for i := 0; i <= config.RegisterAttempts; i++ {
|
||||||
@ -36,7 +36,7 @@ var (
|
|||||||
var err error
|
var err error
|
||||||
|
|
||||||
opts := []register.DeregisterOption{
|
opts := []register.DeregisterOption{
|
||||||
register.DeregisterNamespace(config.Namespace),
|
register.DeregisterDomain(config.Namespace),
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i <= config.DeregisterAttempts; i++ {
|
for i := 0; i <= config.DeregisterAttempts; i++ {
|
||||||
@ -82,8 +82,9 @@ func NewRegisterService(s Server) (*register.Service, error) {
|
|||||||
node.Metadata["register"] = opts.Register.String()
|
node.Metadata["register"] = opts.Register.String()
|
||||||
|
|
||||||
return ®ister.Service{
|
return ®ister.Service{
|
||||||
Name: opts.Name,
|
Name: opts.Name,
|
||||||
Version: opts.Version,
|
Version: opts.Version,
|
||||||
Nodes: []*register.Node{node},
|
Nodes: []*register.Node{node},
|
||||||
|
Metadata: metadata.New(0),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
|
|
||||||
"go.unistack.org/micro/v3/codec"
|
"go.unistack.org/micro/v3/codec"
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v3/metadata"
|
||||||
|
"go.unistack.org/micro/v3/register"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DefaultServer default server
|
// DefaultServer default server
|
||||||
@ -169,6 +170,7 @@ type Stream interface {
|
|||||||
type Handler interface {
|
type Handler interface {
|
||||||
Name() string
|
Name() string
|
||||||
Handler() interface{}
|
Handler() interface{}
|
||||||
|
Endpoints() []*register.Endpoint
|
||||||
Options() HandlerOptions
|
Options() HandlerOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,5 +180,6 @@ type Handler interface {
|
|||||||
type Subscriber interface {
|
type Subscriber interface {
|
||||||
Topic() string
|
Topic() string
|
||||||
Subscriber() interface{}
|
Subscriber() interface{}
|
||||||
|
Endpoints() []*register.Endpoint
|
||||||
Options() SubscriberOptions
|
Options() SubscriberOptions
|
||||||
}
|
}
|
||||||
|
@ -71,6 +71,14 @@ func CopyService(service *register.Service) *register.Service {
|
|||||||
}
|
}
|
||||||
s.Nodes = nodes
|
s.Nodes = nodes
|
||||||
|
|
||||||
|
// copy endpoints
|
||||||
|
eps := make([]*register.Endpoint, len(service.Endpoints))
|
||||||
|
for j, ep := range service.Endpoints {
|
||||||
|
e := ®ister.Endpoint{}
|
||||||
|
*e = *ep
|
||||||
|
eps[j] = e
|
||||||
|
}
|
||||||
|
s.Endpoints = eps
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user