Compare commits
	
		
			2 Commits
		
	
	
		
			v3.11.35
			...
			vtolstov-p
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 629087ec7e | ||
| c576abf26a | 
| @@ -1,5 +1,5 @@ | ||||
| # Micro  | ||||
|  | ||||
|  | ||||
|  | ||||
| Micro is a standard library for microservices. | ||||
|  | ||||
|   | ||||
| @@ -3,8 +3,6 @@ package codec | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
|  | ||||
| 	"gopkg.in/yaml.v3" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| @@ -56,22 +54,3 @@ func (m *RawMessage) UnmarshalJSON(data []byte) error { | ||||
| 	*m = append((*m)[0:0], data...) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // MarshalYAML returns m as the JSON encoding of m. | ||||
| func (m *RawMessage) MarshalYAML() ([]byte, error) { | ||||
| 	if m == nil { | ||||
| 		return []byte("null"), nil | ||||
| 	} else if len(*m) == 0 { | ||||
| 		return []byte("null"), nil | ||||
| 	} | ||||
| 	return *m, nil | ||||
| } | ||||
|  | ||||
| // UnmarshalYAML sets *m to a copy of data. | ||||
| func (m *RawMessage) UnmarshalYAML(n *yaml.Node) error { | ||||
| 	if m == nil { | ||||
| 		return errors.New("RawMessage UnmarshalYAML on nil pointer") | ||||
| 	} | ||||
| 	*m = append((*m)[0:0], []byte(n.Value)...) | ||||
| 	return nil | ||||
| } | ||||
|   | ||||
| @@ -1,7 +1,5 @@ | ||||
| package codec | ||||
|  | ||||
| import "gopkg.in/yaml.v3" | ||||
|  | ||||
| // Frame gives us the ability to define raw data to send over the pipes | ||||
| type Frame struct { | ||||
| 	Data []byte | ||||
| @@ -22,17 +20,6 @@ func (m *Frame) UnmarshalJSON(data []byte) error { | ||||
| 	return m.Unmarshal(data) | ||||
| } | ||||
|  | ||||
| // MarshalYAML returns frame data | ||||
| func (m *Frame) MarshalYAML() ([]byte, error) { | ||||
| 	return m.Marshal() | ||||
| } | ||||
|  | ||||
| // UnmarshalYAML set frame data | ||||
| func (m *Frame) UnmarshalYAML(n *yaml.Node) error { | ||||
| 	m.Data = []byte(n.Value) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // ProtoMessage noop func | ||||
| func (m *Frame) ProtoMessage() {} | ||||
|  | ||||
|   | ||||
							
								
								
									
										14
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								go.mod
									
									
									
									
									
								
							| @@ -1,12 +1,12 @@ | ||||
| module go.unistack.org/micro/v3 | ||||
|  | ||||
| go 1.22.0 | ||||
| go 1.23.4 | ||||
|  | ||||
| require ( | ||||
| 	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/ash3in/uuidv8 v1.2.0 | ||||
| 	github.com/ash3in/uuidv8 v1.0.1 | ||||
| 	github.com/google/uuid v1.6.0 | ||||
| 	github.com/matoous/go-nanoid v1.5.1 | ||||
| 	github.com/patrickmn/go-cache v2.1.0+incompatible | ||||
| @@ -14,8 +14,8 @@ require ( | ||||
| 	go.uber.org/automaxprocs v1.6.0 | ||||
| 	go.unistack.org/micro-proto/v3 v3.4.1 | ||||
| 	golang.org/x/sync v0.10.0 | ||||
| 	google.golang.org/grpc v1.69.2 | ||||
| 	google.golang.org/protobuf v1.36.1 | ||||
| 	google.golang.org/grpc v1.68.1 | ||||
| 	google.golang.org/protobuf v1.35.2 | ||||
| 	gopkg.in/yaml.v3 v3.0.1 | ||||
| ) | ||||
|  | ||||
| @@ -36,8 +36,8 @@ require ( | ||||
| 	github.com/stretchr/testify v1.10.0 // indirect | ||||
| 	go.uber.org/goleak v1.3.0 // indirect | ||||
| 	golang.org/x/exp v0.0.0-20241210194714-1829a127f884 // indirect | ||||
| 	golang.org/x/net v0.33.0 // indirect | ||||
| 	golang.org/x/net v0.32.0 // indirect | ||||
| 	golang.org/x/sys v0.28.0 // indirect | ||||
| 	google.golang.org/genproto/googleapis/rpc v0.0.0-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 | ||||
| ) | ||||
|   | ||||
							
								
								
									
										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/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.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= | ||||
| github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= | ||||
| github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= | ||||
| github.com/KimMachineGun/automemlimit v0.6.1 h1:ILa9j1onAAMadBsyyUJv5cack8Y1WT26yLj/V+ulKp8= | ||||
| github.com/KimMachineGun/automemlimit v0.6.1/go.mod h1:T7xYht7B8r6AG/AqFcUdc7fzd2bIdBKmepfP2S1svPY= | ||||
| github.com/ash3in/uuidv8 v1.2.0 h1:2oogGdtCPwaVtyvPPGin4TfZLtOGE5F+W++E880G6SI= | ||||
| github.com/ash3in/uuidv8 v1.2.0/go.mod h1:BnU0wJBxnzdEKmVg4xckBkD+VZuecTFTUP3M0dWgyY4= | ||||
| github.com/ash3in/uuidv8 v1.0.1 h1:dIq1XRkWT8lGA7N5s7WRTB4V3k49WTBLvILz7aCLp80= | ||||
| github.com/ash3in/uuidv8 v1.0.1/go.mod h1:EoyUgCtxNBnrnpc9efw5rVN1cQ+LFGCoJiFuD6maOMw= | ||||
| github.com/cilium/ebpf v0.16.0 h1:+BiEnHL6Z7lXnlGUsXQPPAE7+kenAd4ES8MQ5min0Ok= | ||||
| github.com/cilium/ebpf v0.16.0/go.mod h1:L7u2Blt2jMM/vLAVgjxluxtBKlz3/GWjB0dMOEngfwE= | ||||
| github.com/containerd/cgroups/v3 v3.0.4 h1:2fs7l3P0Qxb1nKWuJNFiwhp2CqiKzho71DQkDrHJIo4= | ||||
| @@ -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/jsimonetti/rtnetlink/v2 v2.0.1 h1:xda7qaHDSVOsADNouv7ukSuicKZO7GgVUCXxpaIEIlM= | ||||
| 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.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= | ||||
| 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= | ||||
| golang.org/x/exp v0.0.0-20241210194714-1829a127f884 h1:Y/Mj/94zIQQGHVSv1tTtQBDaQaJe62U9bkDZKKyhPCU= | ||||
| golang.org/x/exp v0.0.0-20241210194714-1829a127f884/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= | ||||
| golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= | ||||
| golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= | ||||
| golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= | ||||
| golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= | ||||
| golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= | ||||
| golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= | ||||
| golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| @@ -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/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= | ||||
| golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= | ||||
| google.golang.org/genproto/googleapis/rpc v0.0.0-20241216192217-9240e9c98484 h1:Z7FRVJPSMaHQxD0uXU8WdgFh8PseLM8Q8NzhnpMrBhQ= | ||||
| google.golang.org/genproto/googleapis/rpc v0.0.0-20241216192217-9240e9c98484/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA= | ||||
| google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU= | ||||
| google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= | ||||
| google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= | ||||
| google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= | ||||
| google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 h1:8ZmaLZE4XWrtU3MyClkYqqtl6Oegr3235h7jxsDyqCY= | ||||
| google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= | ||||
| google.golang.org/grpc v1.68.1 h1:oI5oTa11+ng8r8XMMN7jAOmWfPZWbYpCFaMUTACxkM0= | ||||
| google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe00waw= | ||||
| google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= | ||||
| google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= | ||||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||
| gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= | ||||
| gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= | ||||
|   | ||||
| @@ -22,7 +22,6 @@ const ( | ||||
| 	badKey = "!BADKEY" | ||||
| 	// defaultCallerSkipCount used by logger | ||||
| 	defaultCallerSkipCount = 3 | ||||
| 	timeFormat             = "2006-01-02T15:04:05.000000000Z07:00" | ||||
| ) | ||||
|  | ||||
| var reTrace = regexp.MustCompile(`.*/slog/logger\.go.*\n`) | ||||
| @@ -65,7 +64,6 @@ func (s *slogLogger) renameAttr(_ []string, a slog.Attr) slog.Attr { | ||||
| 		a.Key = s.opts.SourceKey | ||||
| 	case slog.TimeKey: | ||||
| 		a.Key = s.opts.TimeKey | ||||
| 		a.Value = slog.StringValue(a.Value.Time().Format(timeFormat)) | ||||
| 	case slog.MessageKey: | ||||
| 		a.Key = s.opts.MessageKey | ||||
| 	case slog.LevelKey: | ||||
|   | ||||
| @@ -9,14 +9,12 @@ import ( | ||||
| 	"log/slog" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/google/uuid" | ||||
| 	"go.unistack.org/micro/v3/logger" | ||||
| 	"go.unistack.org/micro/v3/metadata" | ||||
| ) | ||||
|  | ||||
| // always first to have proper check | ||||
| func TestStacktrace(t *testing.T) { | ||||
| 	ctx := context.TODO() | ||||
| 	buf := bytes.NewBuffer(nil) | ||||
| @@ -30,29 +28,7 @@ func TestStacktrace(t *testing.T) { | ||||
|  | ||||
| 	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) { | ||||
| 	ctx := context.TODO() | ||||
| 	buf := bytes.NewBuffer(nil) | ||||
| 	l := NewLogger(logger.WithLevel(logger.ErrorLevel), logger.WithOutput(buf), | ||||
| 		WithHandlerFunc(slog.NewTextHandler), | ||||
| 		logger.WithAddStacktrace(true), | ||||
| 		logger.WithTimeFunc(func() time.Time { | ||||
| 			return time.Unix(0, 0) | ||||
| 		}), | ||||
| 	) | ||||
| 	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(`timestamp=1970-01-01T03:00:00.000000000+03:00`)) && | ||||
| 		!bytes.Contains(buf.Bytes(), []byte(`timestamp=1970-01-01T00:00:00.000000000Z`)) { | ||||
| 	if !bytes.Contains(buf.Bytes(), []byte(`slog_test.go:29`)) { | ||||
| 		t.Fatalf("logger error not works, buf contains: %s", buf.Bytes()) | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -1,9 +1,12 @@ | ||||
| package register | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"reflect" | ||||
| 	"unicode" | ||||
| 	"unicode/utf8" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/metadata" | ||||
| ) | ||||
|  | ||||
| // ExtractValue from reflect.Type from specified depth | ||||
| @@ -35,6 +38,53 @@ func ExtractValue(v reflect.Type, d int) string { | ||||
| 	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 | ||||
| func ExtractSubValue(typ reflect.Type) string { | ||||
| 	var reqType reflect.Type | ||||
|   | ||||
| @@ -2,6 +2,8 @@ package register | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"reflect" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| type TestHandler struct{} | ||||
| @@ -13,3 +15,40 @@ type TestResponse struct{} | ||||
| func (t *TestHandler) Test(ctx context.Context, req *TestRequest, rsp *TestResponse) error { | ||||
| 	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 { | ||||
| 	Name     string | ||||
| 	Version  string | ||||
| 	Metadata map[string]string | ||||
| 	Nodes    map[string]*node | ||||
| 	Name      string | ||||
| 	Version   string | ||||
| 	Metadata  map[string]string | ||||
| 	Nodes     map[string]*node | ||||
| 	Endpoints []*register.Endpoint | ||||
| } | ||||
|  | ||||
| type memory struct { | ||||
| @@ -58,7 +59,7 @@ func (m *memory) ttlPrune() { | ||||
|  | ||||
| 	for range prune.C { | ||||
| 		m.Lock() | ||||
| 		for namespace, services := range m.records { | ||||
| 		for domain, services := range m.records { | ||||
| 			for service, versions := range services { | ||||
| 				for version, record := range versions { | ||||
| 					for id, n := range record.Nodes { | ||||
| @@ -66,7 +67,7 @@ func (m *memory) ttlPrune() { | ||||
| 							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)) | ||||
| 							} | ||||
| 							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...) | ||||
|  | ||||
| 	// get the services for this domain from the register | ||||
| 	srvs, ok := m.records[options.Namespace] | ||||
| 	srvs, ok := m.records[options.Domain] | ||||
| 	if !ok { | ||||
| 		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 | ||||
| 	r := serviceToRecord(s, options.TTL) | ||||
| @@ -148,8 +154,8 @@ func (m *memory) Register(_ context.Context, s *register.Service, opts ...regist | ||||
| 		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.records[options.Namespace] = srvs | ||||
| 		go m.sendEvent(®ister.Result{Action: register.EventCreate, Service: s}) | ||||
| 		m.records[options.Domain] = srvs | ||||
| 		go m.sendEvent(®ister.Result{Action: "create", Service: s}) | ||||
| 	} | ||||
|  | ||||
| 	var addedNodes bool | ||||
| @@ -167,6 +173,9 @@ func (m *memory) Register(_ context.Context, s *register.Service, opts ...regist | ||||
| 			metadata[k] = v | ||||
| 		} | ||||
|  | ||||
| 		// set the domain | ||||
| 		metadata["domain"] = options.Domain | ||||
|  | ||||
| 		// add the node | ||||
| 		srvs[s.Name][s.Version].Nodes[n.ID] = &node{ | ||||
| 			Node: ®ister.Node{ | ||||
| @@ -185,7 +194,7 @@ func (m *memory) Register(_ context.Context, s *register.Service, opts ...regist | ||||
| 		if m.opts.Logger.V(logger.DebugLevel) { | ||||
| 			m.opts.Logger.Debug(m.opts.Context, fmt.Sprintf("Register added new node to service: %s, version: %s", s.Name, s.Version)) | ||||
| 		} | ||||
| 		go m.sendEvent(®ister.Result{Action: register.EventUpdate, Service: s}) | ||||
| 		go m.sendEvent(®ister.Result{Action: "update", Service: s}) | ||||
| 	} else { | ||||
| 		// refresh TTL and timestamp | ||||
| 		for _, n := range s.Nodes { | ||||
| @@ -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 | ||||
| } | ||||
|  | ||||
| @@ -207,8 +216,15 @@ func (m *memory) Deregister(ctx context.Context, s *register.Service, opts ...re | ||||
|  | ||||
| 	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 | ||||
| 	services, ok := m.records[options.Namespace] | ||||
| 	services, ok := m.records[options.Domain] | ||||
| 	if !ok { | ||||
| 		return nil | ||||
| 	} | ||||
| @@ -237,16 +253,16 @@ 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 | ||||
| 	// is cleanup | ||||
| 	if len(version.Nodes) > 0 { | ||||
| 		m.records[options.Namespace][s.Name][s.Version] = version | ||||
| 		go m.sendEvent(®ister.Result{Action: register.EventUpdate, Service: s}) | ||||
| 		m.records[options.Domain][s.Name][s.Version] = version | ||||
| 		go m.sendEvent(®ister.Result{Action: "update", Service: s}) | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	// if this version was the only version of the service, we can remove the whole service from the | ||||
| 	// register and exit | ||||
| 	if len(versions) == 1 { | ||||
| 		delete(m.records[options.Namespace], s.Name) | ||||
| 		go m.sendEvent(®ister.Result{Action: register.EventDelete, Service: s}) | ||||
| 		delete(m.records[options.Domain], s.Name) | ||||
| 		go m.sendEvent(®ister.Result{Action: "delete", Service: s}) | ||||
|  | ||||
| 		if m.opts.Logger.V(logger.DebugLevel) { | ||||
| 			m.opts.Logger.Debug(m.opts.Context, fmt.Sprintf("Register removed service: %s", s.Name)) | ||||
| @@ -255,8 +271,8 @@ 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 | ||||
| 	delete(m.records[options.Namespace][s.Name], s.Version) | ||||
| 	go m.sendEvent(®ister.Result{Action: register.EventDelete, Service: s}) | ||||
| 	delete(m.records[options.Domain][s.Name], s.Version) | ||||
| 	go m.sendEvent(®ister.Result{Action: "delete", Service: s}) | ||||
| 	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)) | ||||
| 	} | ||||
| @@ -268,15 +284,15 @@ func (m *memory) LookupService(ctx context.Context, name string, opts ...registe | ||||
| 	options := register.NewLookupOptions(opts...) | ||||
|  | ||||
| 	// if it's a wildcard domain, return from all domains | ||||
| 	if options.Namespace == register.WildcardNamespace { | ||||
| 	if options.Domain == register.WildcardDomain { | ||||
| 		m.RLock() | ||||
| 		recs := m.records | ||||
| 		m.RUnlock() | ||||
|  | ||||
| 		var services []*register.Service | ||||
|  | ||||
| 		for namespace := range recs { | ||||
| 			srvs, err := m.LookupService(ctx, name, append(opts, register.LookupNamespace(namespace))...) | ||||
| 		for domain := range recs { | ||||
| 			srvs, err := m.LookupService(ctx, name, append(opts, register.LookupDomain(domain))...) | ||||
| 			if err == register.ErrNotFound { | ||||
| 				continue | ||||
| 			} else if err != nil { | ||||
| @@ -295,7 +311,7 @@ func (m *memory) LookupService(ctx context.Context, name string, opts ...registe | ||||
| 	defer m.RUnlock() | ||||
|  | ||||
| 	// check the domain exists | ||||
| 	services, ok := m.records[options.Namespace] | ||||
| 	services, ok := m.records[options.Domain] | ||||
| 	if !ok { | ||||
| 		return nil, register.ErrNotFound | ||||
| 	} | ||||
| @@ -312,7 +328,7 @@ func (m *memory) LookupService(ctx context.Context, name string, opts ...registe | ||||
| 	var i int | ||||
|  | ||||
| 	for _, r := range versions { | ||||
| 		result[i] = recordToService(r, options.Namespace) | ||||
| 		result[i] = recordToService(r, options.Domain) | ||||
| 		i++ | ||||
| 	} | ||||
|  | ||||
| @@ -323,15 +339,15 @@ func (m *memory) ListServices(ctx context.Context, opts ...register.ListOption) | ||||
| 	options := register.NewListOptions(opts...) | ||||
|  | ||||
| 	// if it's a wildcard domain, list from all domains | ||||
| 	if options.Namespace == register.WildcardNamespace { | ||||
| 	if options.Domain == register.WildcardDomain { | ||||
| 		m.RLock() | ||||
| 		recs := m.records | ||||
| 		m.RUnlock() | ||||
|  | ||||
| 		var services []*register.Service | ||||
|  | ||||
| 		for namespace := range recs { | ||||
| 			srvs, err := m.ListServices(ctx, append(opts, register.ListNamespace(namespace))...) | ||||
| 		for domain := range recs { | ||||
| 			srvs, err := m.ListServices(ctx, append(opts, register.ListDomain(domain))...) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| @@ -345,7 +361,7 @@ func (m *memory) ListServices(ctx context.Context, opts ...register.ListOption) | ||||
| 	defer m.RUnlock() | ||||
|  | ||||
| 	// ensure the domain exists | ||||
| 	services, ok := m.records[options.Namespace] | ||||
| 	services, ok := m.records[options.Domain] | ||||
| 	if !ok { | ||||
| 		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 _, 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 | ||||
| 			} | ||||
|  | ||||
| 			namespace := register.DefaultNamespace | ||||
| 			if r.Service.Namespace != "" { | ||||
| 				namespace = r.Service.Namespace | ||||
| 			// extract domain from service metadata | ||||
| 			var domain string | ||||
| 			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 | ||||
| 			if m.wo.Namespace == register.WildcardNamespace || m.wo.Namespace == namespace { | ||||
| 			if m.wo.Domain == register.WildcardDomain || m.wo.Domain == domain { | ||||
| 				return r, nil | ||||
| 			} | ||||
| 		case <-m.exit: | ||||
| @@ -435,6 +454,11 @@ func (m *watcher) Stop() { | ||||
| } | ||||
|  | ||||
| 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)) | ||||
| 	for _, n := range s.Nodes { | ||||
| 		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{ | ||||
| 		Name:    s.Name, | ||||
| 		Version: s.Version, | ||||
| 		Nodes:   nodes, | ||||
| 		Name:      s.Name, | ||||
| 		Version:   s.Version, | ||||
| 		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)) | ||||
| 	for k, v := range r.Metadata { | ||||
| 		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)) | ||||
| 	i := 0 | ||||
| 	for _, n := range r.Nodes { | ||||
| @@ -476,7 +523,8 @@ func recordToService(r *record, namespace string) *register.Service { | ||||
| 	return ®ister.Service{ | ||||
| 		Name:      r.Name, | ||||
| 		Version:   r.Version, | ||||
| 		Metadata:  metadata, | ||||
| 		Endpoints: endpoints, | ||||
| 		Nodes:     nodes, | ||||
| 		Namespace: namespace, | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -253,32 +253,32 @@ func TestMemoryWildcard(t *testing.T) { | ||||
|  | ||||
| 	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) | ||||
| 	} | ||||
| 	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) | ||||
| 	} | ||||
|  | ||||
| 	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) | ||||
| 	} else if len(recs) != 1 { | ||||
| 		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) | ||||
| 	} else if len(recs) != 2 { | ||||
| 		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) | ||||
| 	} else if len(recs) != 1 { | ||||
| 		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) | ||||
| 	} else if len(recs) != 2 { | ||||
| 		t.Errorf("Expected 2 records, got %v", len(recs)) | ||||
|   | ||||
| @@ -5,7 +5,6 @@ import ( | ||||
| 	"crypto/tls" | ||||
| 	"time" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/codec" | ||||
| 	"go.unistack.org/micro/v3/logger" | ||||
| 	"go.unistack.org/micro/v3/meter" | ||||
| 	"go.unistack.org/micro/v3/tracer" | ||||
| @@ -27,8 +26,6 @@ type Options struct { | ||||
| 	Name string | ||||
| 	// Addrs specifies register addrs | ||||
| 	Addrs []string | ||||
| 	// Codec used to marshal/unmarshal data in register | ||||
| 	Codec codec.Codec | ||||
| 	// Timeout specifies timeout | ||||
| 	Timeout time.Duration | ||||
| } | ||||
| @@ -40,7 +37,6 @@ func NewOptions(opts ...Option) Options { | ||||
| 		Meter:   meter.DefaultMeter, | ||||
| 		Tracer:  tracer.DefaultTracer, | ||||
| 		Context: context.Background(), | ||||
| 		Codec:   codec.NewCodec(), | ||||
| 	} | ||||
| 	for _, o := range opts { | ||||
| 		o(&options) | ||||
| @@ -50,17 +46,17 @@ func NewOptions(opts ...Option) Options { | ||||
|  | ||||
| // RegisterOptions holds options for register method | ||||
| type RegisterOptions struct { // nolint: golint,revive | ||||
| 	Context   context.Context | ||||
| 	Namespace string | ||||
| 	TTL       time.Duration | ||||
| 	Attempts  int | ||||
| 	Context  context.Context | ||||
| 	Domain   string | ||||
| 	TTL      time.Duration | ||||
| 	Attempts int | ||||
| } | ||||
|  | ||||
| // NewRegisterOptions returns register options struct filled by opts | ||||
| func NewRegisterOptions(opts ...RegisterOption) RegisterOptions { | ||||
| 	options := RegisterOptions{ | ||||
| 		Namespace: DefaultNamespace, | ||||
| 		Context:   context.Background(), | ||||
| 		Domain:  DefaultDomain, | ||||
| 		Context: context.Background(), | ||||
| 	} | ||||
| 	for _, o := range opts { | ||||
| 		o(&options) | ||||
| @@ -76,15 +72,15 @@ type WatchOptions struct { | ||||
| 	// Other options for implementations of the interface | ||||
| 	// can be stored in a context | ||||
| 	Context context.Context | ||||
| 	// Namespace to watch | ||||
| 	Namespace string | ||||
| 	// Domain to watch | ||||
| 	Domain string | ||||
| } | ||||
|  | ||||
| // NewWatchOptions returns watch options filled by opts | ||||
| func NewWatchOptions(opts ...WatchOption) WatchOptions { | ||||
| 	options := WatchOptions{ | ||||
| 		Namespace: DefaultNamespace, | ||||
| 		Context:   context.Background(), | ||||
| 		Domain:  DefaultDomain, | ||||
| 		Context: context.Background(), | ||||
| 	} | ||||
| 	for _, o := range opts { | ||||
| 		o(&options) | ||||
| @@ -95,8 +91,8 @@ func NewWatchOptions(opts ...WatchOption) WatchOptions { | ||||
| // DeregisterOptions holds options for deregister method | ||||
| type DeregisterOptions struct { | ||||
| 	Context context.Context | ||||
| 	// Namespace the service was registered in | ||||
| 	Namespace string | ||||
| 	// Domain the service was registered in | ||||
| 	Domain string | ||||
| 	// Atempts specify max attempts for deregister | ||||
| 	Attempts int | ||||
| } | ||||
| @@ -104,8 +100,8 @@ type DeregisterOptions struct { | ||||
| // NewDeregisterOptions returns options for deregister filled by opts | ||||
| func NewDeregisterOptions(opts ...DeregisterOption) DeregisterOptions { | ||||
| 	options := DeregisterOptions{ | ||||
| 		Namespace: DefaultNamespace, | ||||
| 		Context:   context.Background(), | ||||
| 		Domain:  DefaultDomain, | ||||
| 		Context: context.Background(), | ||||
| 	} | ||||
| 	for _, o := range opts { | ||||
| 		o(&options) | ||||
| @@ -116,15 +112,15 @@ func NewDeregisterOptions(opts ...DeregisterOption) DeregisterOptions { | ||||
| // LookupOptions holds lookup options | ||||
| type LookupOptions struct { | ||||
| 	Context context.Context | ||||
| 	// Namespace to scope the request to | ||||
| 	Namespace string | ||||
| 	// Domain to scope the request to | ||||
| 	Domain string | ||||
| } | ||||
|  | ||||
| // NewLookupOptions returns lookup options filled by opts | ||||
| func NewLookupOptions(opts ...LookupOption) LookupOptions { | ||||
| 	options := LookupOptions{ | ||||
| 		Namespace: DefaultNamespace, | ||||
| 		Context:   context.Background(), | ||||
| 		Domain:  DefaultDomain, | ||||
| 		Context: context.Background(), | ||||
| 	} | ||||
| 	for _, o := range opts { | ||||
| 		o(&options) | ||||
| @@ -134,17 +130,16 @@ func NewLookupOptions(opts ...LookupOption) LookupOptions { | ||||
|  | ||||
| // ListOptions holds the list options for list method | ||||
| type ListOptions struct { | ||||
| 	// Context used to store additional options | ||||
| 	Context context.Context | ||||
| 	// Namespace to scope the request to | ||||
| 	Namespace string | ||||
| 	// Domain to scope the request to | ||||
| 	Domain string | ||||
| } | ||||
|  | ||||
| // NewListOptions returns list options filled by opts | ||||
| func NewListOptions(opts ...ListOption) ListOptions { | ||||
| 	options := ListOptions{ | ||||
| 		Namespace: DefaultNamespace, | ||||
| 		Context:   context.Background(), | ||||
| 		Domain:  DefaultDomain, | ||||
| 		Context: context.Background(), | ||||
| 	} | ||||
| 	for _, o := range opts { | ||||
| 		o(&options) | ||||
| @@ -222,10 +217,10 @@ func RegisterContext(ctx context.Context) RegisterOption { // nolint: golint,rev | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // RegisterNamespace secifies register Namespace | ||||
| func RegisterNamespace(d string) RegisterOption { // nolint: golint,revive | ||||
| // RegisterDomain secifies register domain | ||||
| func RegisterDomain(d string) RegisterOption { // nolint: golint,revive | ||||
| 	return func(o *RegisterOptions) { | ||||
| 		o.Namespace = d | ||||
| 		o.Domain = d | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -243,10 +238,10 @@ func WatchContext(ctx context.Context) WatchOption { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WatchNamespace sets the Namespace for watch | ||||
| func WatchNamespace(d string) WatchOption { | ||||
| // WatchDomain sets the domain for watch | ||||
| func WatchDomain(d string) WatchOption { | ||||
| 	return func(o *WatchOptions) { | ||||
| 		o.Namespace = d | ||||
| 		o.Domain = d | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -264,10 +259,10 @@ func DeregisterContext(ctx context.Context) DeregisterOption { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // DeregisterNamespace specifies deregister Namespace | ||||
| func DeregisterNamespace(d string) DeregisterOption { | ||||
| // DeregisterDomain specifies deregister domain | ||||
| func DeregisterDomain(d string) DeregisterOption { | ||||
| 	return func(o *DeregisterOptions) { | ||||
| 		o.Namespace = d | ||||
| 		o.Domain = d | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -278,10 +273,10 @@ func LookupContext(ctx context.Context) LookupOption { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // LookupNamespace sets the Namespace for lookup | ||||
| func LookupNamespace(d string) LookupOption { | ||||
| // LookupDomain sets the domain for lookup | ||||
| func LookupDomain(d string) LookupOption { | ||||
| 	return func(o *LookupOptions) { | ||||
| 		o.Namespace = d | ||||
| 		o.Domain = d | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -292,10 +287,10 @@ func ListContext(ctx context.Context) ListOption { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // ListNamespace sets the Namespace for list method | ||||
| func ListNamespace(d string) ListOption { | ||||
| // ListDomain sets the domain for list method | ||||
| func ListDomain(d string) ListOption { | ||||
| 	return func(o *ListOptions) { | ||||
| 		o.Namespace = d | ||||
| 		o.Domain = d | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -305,9 +300,3 @@ func Name(n string) Option { | ||||
| 		o.Name = n | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func Codec(c codec.Codec) Option { | ||||
| 	return func(o *Options) { | ||||
| 		o.Codec = c | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -9,12 +9,12 @@ import ( | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	// WildcardNamespace indicates any Namespace | ||||
| 	WildcardNamespace = "*" | ||||
| 	// WildcardDomain indicates any domain | ||||
| 	WildcardDomain = "*" | ||||
| ) | ||||
|  | ||||
| // DefaultNamespace to use if none was provided in options | ||||
| var DefaultNamespace = "micro" | ||||
| // DefaultDomain to use if none was provided in options | ||||
| var DefaultDomain = "micro" | ||||
|  | ||||
| var ( | ||||
| 	// DefaultRegister is the global default register | ||||
| @@ -59,17 +59,26 @@ type Register interface { | ||||
|  | ||||
| // Service holds service register info | ||||
| type Service struct { | ||||
| 	Name      string  `json:"name,omitempty"` | ||||
| 	Version   string  `json:"version,omitempty"` | ||||
| 	Nodes     []*Node `json:"nodes,omitempty"` | ||||
| 	Namespace string  `json:"namespace,omitempty"` | ||||
| 	Name      string            `json:"name"` | ||||
| 	Version   string            `json:"version"` | ||||
| 	Metadata  metadata.Metadata `json:"metadata"` | ||||
| 	Endpoints []*Endpoint       `json:"endpoints"` | ||||
| 	Nodes     []*Node           `json:"nodes"` | ||||
| } | ||||
|  | ||||
| // Node holds node register info | ||||
| type Node struct { | ||||
| 	Metadata metadata.Metadata `json:"metadata,omitempty"` | ||||
| 	ID       string            `json:"id,omitempty"` | ||||
| 	Address  string            `json:"address,omitempty"` | ||||
| 	Metadata metadata.Metadata `json:"metadata"` | ||||
| 	ID       string            `json:"id"` | ||||
| 	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 | ||||
|   | ||||
| @@ -15,31 +15,31 @@ type Watcher interface { | ||||
| // the watcher. Actions can be create, update, delete | ||||
| type Result struct { | ||||
| 	// Service holds register service | ||||
| 	Service *Service `json:"service,omitempty"` | ||||
| 	Service *Service | ||||
| 	// Action holds the action | ||||
| 	Action EventType `json:"action,omitempty"` | ||||
| 	Action string | ||||
| } | ||||
|  | ||||
| // EventType defines register event type | ||||
| type EventType int | ||||
|  | ||||
| const ( | ||||
| 	// EventCreate is emitted when a new service is registered | ||||
| 	EventCreate EventType = iota | ||||
| 	// EventDelete is emitted when an existing service is deregistered | ||||
| 	EventDelete | ||||
| 	// EventUpdate is emitted when an existing service is updated | ||||
| 	EventUpdate | ||||
| 	// Create is emitted when a new service is registered | ||||
| 	Create EventType = iota | ||||
| 	// Delete is emitted when an existing service is deregistered | ||||
| 	Delete | ||||
| 	// Update is emitted when an existing service is updated | ||||
| 	Update | ||||
| ) | ||||
|  | ||||
| // String returns human readable event type | ||||
| func (t EventType) String() string { | ||||
| 	switch t { | ||||
| 	case EventCreate: | ||||
| 	case Create: | ||||
| 		return "create" | ||||
| 	case EventDelete: | ||||
| 	case Delete: | ||||
| 		return "delete" | ||||
| 	case EventUpdate: | ||||
| 	case Update: | ||||
| 		return "update" | ||||
| 	default: | ||||
| 		return "unknown" | ||||
| @@ -49,11 +49,11 @@ func (t EventType) String() string { | ||||
| // Event is register event | ||||
| type Event struct { | ||||
| 	// Timestamp is event timestamp | ||||
| 	Timestamp time.Time `json:"timestamp,omitempty"` | ||||
| 	Timestamp time.Time | ||||
| 	// Service is register service | ||||
| 	Service *Service `json:"service,omitempty"` | ||||
| 	Service *Service | ||||
| 	// ID is register id | ||||
| 	ID string `json:"id,omitempty"` | ||||
| 	ID string | ||||
| 	// Type defines type of event | ||||
| 	Type EventType `json:"type,omitempty"` | ||||
| 	Type EventType | ||||
| } | ||||
|   | ||||
| @@ -5,6 +5,7 @@ import ( | ||||
| 	"fmt" | ||||
| 	"reflect" | ||||
| 	"runtime/debug" | ||||
| 	"sort" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"time" | ||||
| @@ -31,21 +32,38 @@ const ( | ||||
| ) | ||||
|  | ||||
| type rpcHandler struct { | ||||
| 	opts    HandlerOptions | ||||
| 	handler interface{} | ||||
| 	name    string | ||||
| 	opts      HandlerOptions | ||||
| 	handler   interface{} | ||||
| 	name      string | ||||
| 	endpoints []*register.Endpoint | ||||
| } | ||||
|  | ||||
| func newRPCHandler(handler interface{}, opts ...HandlerOption) Handler { | ||||
| 	options := NewHandlerOptions(opts...) | ||||
|  | ||||
| 	typ := reflect.TypeOf(handler) | ||||
| 	hdlr := reflect.ValueOf(handler) | ||||
| 	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{ | ||||
| 		name:    name, | ||||
| 		handler: handler, | ||||
| 		opts:    options, | ||||
| 		name:      name, | ||||
| 		handler:   handler, | ||||
| 		endpoints: endpoints, | ||||
| 		opts:      options, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -57,6 +75,10 @@ func (r *rpcHandler) Handler() interface{} { | ||||
| 	return r.handler | ||||
| } | ||||
|  | ||||
| func (r *rpcHandler) Endpoints() []*register.Endpoint { | ||||
| 	return r.endpoints | ||||
| } | ||||
|  | ||||
| func (r *rpcHandler) Options() HandlerOptions { | ||||
| 	return r.opts | ||||
| } | ||||
| @@ -227,6 +249,35 @@ func (n *noopServer) Register() error { | ||||
| 		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() | ||||
| 	registered := n.registered | ||||
| 	n.RUnlock() | ||||
| @@ -525,6 +576,7 @@ func (n *noopServer) Stop() error { | ||||
| } | ||||
|  | ||||
| func newSubscriber(topic string, sub interface{}, opts ...SubscriberOption) Subscriber { | ||||
| 	var endpoints []*register.Endpoint | ||||
| 	var handlers []*handler | ||||
|  | ||||
| 	options := NewSubscriberOptions(opts...) | ||||
| @@ -543,7 +595,18 @@ func newSubscriber(topic string, sub interface{}, opts ...SubscriberOption) Subs | ||||
| 		} | ||||
|  | ||||
| 		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 { | ||||
| 		hdlr := reflect.ValueOf(sub) | ||||
| 		name := reflect.Indirect(hdlr).Type().Name() | ||||
|  | ||||
| 		for m := 0; m < typ.NumMethod(); m++ { | ||||
| 			method := typ.Method(m) | ||||
| 			h := &handler{ | ||||
| @@ -559,6 +622,14 @@ func newSubscriber(topic string, sub interface{}, opts ...SubscriberOption) Subs | ||||
| 			} | ||||
|  | ||||
| 			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, | ||||
| 		subscriber: sub, | ||||
| 		handlers:   handlers, | ||||
| 		endpoints:  endpoints, | ||||
| 		opts:       options, | ||||
| 	} | ||||
| } | ||||
| @@ -694,6 +766,10 @@ func (s *subscriber) Subscriber() interface{} { | ||||
| 	return s.subscriber | ||||
| } | ||||
|  | ||||
| func (s *subscriber) Endpoints() []*register.Endpoint { | ||||
| 	return s.endpoints | ||||
| } | ||||
|  | ||||
| func (s *subscriber) Options() SubscriberOptions { | ||||
| 	return s.opts | ||||
| } | ||||
| @@ -704,7 +780,8 @@ type subscriber struct { | ||||
| 	typ        reflect.Type | ||||
| 	subscriber interface{} | ||||
|  | ||||
| 	handlers []*handler | ||||
| 	endpoints []*register.Endpoint | ||||
| 	handlers  []*handler | ||||
|  | ||||
| 	rcvr reflect.Value | ||||
| 	opts SubscriberOptions | ||||
|   | ||||
| @@ -17,7 +17,7 @@ var ( | ||||
|  | ||||
| 		opts := []register.RegisterOption{ | ||||
| 			register.RegisterTTL(config.RegisterTTL), | ||||
| 			register.RegisterNamespace(config.Namespace), | ||||
| 			register.RegisterDomain(config.Namespace), | ||||
| 		} | ||||
|  | ||||
| 		for i := 0; i <= config.RegisterAttempts; i++ { | ||||
| @@ -36,7 +36,7 @@ var ( | ||||
| 		var err error | ||||
|  | ||||
| 		opts := []register.DeregisterOption{ | ||||
| 			register.DeregisterNamespace(config.Namespace), | ||||
| 			register.DeregisterDomain(config.Namespace), | ||||
| 		} | ||||
|  | ||||
| 		for i := 0; i <= config.DeregisterAttempts; i++ { | ||||
| @@ -82,8 +82,9 @@ func NewRegisterService(s Server) (*register.Service, error) { | ||||
| 	node.Metadata["register"] = opts.Register.String() | ||||
|  | ||||
| 	return ®ister.Service{ | ||||
| 		Name:    opts.Name, | ||||
| 		Version: opts.Version, | ||||
| 		Nodes:   []*register.Node{node}, | ||||
| 		Name:     opts.Name, | ||||
| 		Version:  opts.Version, | ||||
| 		Nodes:    []*register.Node{node}, | ||||
| 		Metadata: metadata.New(0), | ||||
| 	}, nil | ||||
| } | ||||
|   | ||||
| @@ -7,6 +7,7 @@ import ( | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/codec" | ||||
| 	"go.unistack.org/micro/v3/metadata" | ||||
| 	"go.unistack.org/micro/v3/register" | ||||
| ) | ||||
|  | ||||
| // DefaultServer default server | ||||
| @@ -169,6 +170,7 @@ type Stream interface { | ||||
| type Handler interface { | ||||
| 	Name() string | ||||
| 	Handler() interface{} | ||||
| 	Endpoints() []*register.Endpoint | ||||
| 	Options() HandlerOptions | ||||
| } | ||||
|  | ||||
| @@ -178,5 +180,6 @@ type Handler interface { | ||||
| type Subscriber interface { | ||||
| 	Topic() string | ||||
| 	Subscriber() interface{} | ||||
| 	Endpoints() []*register.Endpoint | ||||
| 	Options() SubscriberOptions | ||||
| } | ||||
|   | ||||
| @@ -8,7 +8,6 @@ import ( | ||||
| 	"time" | ||||
|  | ||||
| 	uuidv8 "github.com/ash3in/uuidv8" | ||||
| 	"github.com/google/uuid" | ||||
| 	nanoid "github.com/matoous/go-nanoid" | ||||
| ) | ||||
|  | ||||
| @@ -97,10 +96,6 @@ func New(opts ...Option) (string, error) { | ||||
| 	return "", errors.New("invalid option, Type unspecified") | ||||
| } | ||||
|  | ||||
| func ToUUID(s string) uuid.UUID { | ||||
| 	return uuid.MustParse(s) | ||||
| } | ||||
|  | ||||
| // Must is the same as New but fatals on error | ||||
| func MustNew(opts ...Option) string { | ||||
| 	id, err := New(opts...) | ||||
|   | ||||
| @@ -7,14 +7,5 @@ func TestUUIDv8(t *testing.T) { | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	_ = id | ||||
| } | ||||
|  | ||||
| func TestToUUID(t *testing.T) { | ||||
| 	id, err := New() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	u := ToUUID(id) | ||||
| 	_ = u | ||||
| 	t.Logf("xxx %s\n", id) | ||||
| } | ||||
|   | ||||
| @@ -71,6 +71,14 @@ func CopyService(service *register.Service) *register.Service { | ||||
| 	} | ||||
| 	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 | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user