Skip to content

Commit 7888f28

Browse files
committed
feat: support a concatStyle option for Server
1 parent 4342b77 commit 7888f28

File tree

6 files changed

+147
-33
lines changed

6 files changed

+147
-33
lines changed

map.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,8 @@ func (m *serviceMap) register(rcvr interface{}, name string, passReq bool) error
142142
// get returns a registered service given a method name.
143143
//
144144
// The method name uses a dotted notation as in "Service.Method".
145-
func (m *serviceMap) get(method string) (*service, *serviceMethod, error) {
146-
parts := strings.Split(method, ".")
145+
func (m *serviceMap) get(method string, concatStyle string) (*service, *serviceMethod, error) {
146+
parts := strings.Split(method, concatStyle)
147147
if len(parts) != 2 {
148148
err := fmt.Errorf("rpc: service/method request ill-formed: %q", method)
149149
return nil, nil, err

server.go

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,9 @@ type CodecRequest interface {
4040
// NewServer returns a new RPC server.
4141
func NewServer() *Server {
4242
return &Server{
43-
codecs: make(map[string]Codec),
44-
services: new(serviceMap),
43+
codecs: make(map[string]Codec),
44+
services: new(serviceMap),
45+
concatStyle: ".",
4546
}
4647
}
4748

@@ -60,6 +61,16 @@ type Server struct {
6061
interceptFunc func(i *RequestInfo) *http.Request
6162
beforeFunc func(i *RequestInfo)
6263
afterFunc func(i *RequestInfo)
64+
concatStyle string // The style used to concatenate service and method names, e.g., "Service.Method" or "Service/Method"
65+
}
66+
67+
// SetConcatStyle sets the style used to concatenate service and method names.
68+
// The default style is ".".
69+
// This is useful when you want to use a different style, such as "/".
70+
// The style is used in the method name, e.g., "Service.Method" or "Service/Method".
71+
func (s *Server) SetConcatStyle(concatStyle string) *Server {
72+
s.concatStyle = concatStyle
73+
return s
6374
}
6475

6576
// RegisterCodec adds a new codec to the server.
@@ -78,13 +89,13 @@ func (s *Server) RegisterCodec(codec Codec, contentType string) {
7889
//
7990
// Methods from the receiver will be extracted if these rules are satisfied:
8091
//
81-
// - The receiver is exported (begins with an upper case letter) or local
82-
// (defined in the package registering the service).
83-
// - The method name is exported.
84-
// - The method has three arguments: *http.Request, *args, *reply.
85-
// - All three arguments are pointers.
86-
// - The second and third arguments are exported or local.
87-
// - The method has return type error.
92+
// - The receiver is exported (begins with an upper case letter) or local
93+
// (defined in the package registering the service).
94+
// - The method name is exported.
95+
// - The method has three arguments: *http.Request, *args, *reply.
96+
// - All three arguments are pointers.
97+
// - The second and third arguments are exported or local.
98+
// - The method has return type error.
8899
//
89100
// All other methods are ignored.
90101
func (s *Server) RegisterService(receiver interface{}, name string) error {
@@ -99,13 +110,13 @@ func (s *Server) RegisterService(receiver interface{}, name string) error {
99110
//
100111
// Methods from the receiver will be extracted if these rules are satisfied:
101112
//
102-
// - The receiver is exported (begins with an upper case letter) or local
103-
// (defined in the package registering the service).
104-
// - The method name is exported.
105-
// - The method has two arguments: *args, *reply.
106-
// - Both arguments are pointers.
107-
// - Both arguments are exported or local.
108-
// - The method has return type error.
113+
// - The receiver is exported (begins with an upper case letter) or local
114+
// (defined in the package registering the service).
115+
// - The method name is exported.
116+
// - The method has two arguments: *args, *reply.
117+
// - Both arguments are pointers.
118+
// - Both arguments are exported or local.
119+
// - The method has return type error.
109120
//
110121
// All other methods are ignored.
111122
func (s *Server) RegisterTCPService(receiver interface{}, name string) error {
@@ -116,7 +127,7 @@ func (s *Server) RegisterTCPService(receiver interface{}, name string) error {
116127
//
117128
// The method uses a dotted notation as in "Service.Method".
118129
func (s *Server) HasMethod(method string) bool {
119-
if _, _, err := s.services.get(method); err == nil {
130+
if _, _, err := s.services.get(method, s.concatStyle); err == nil {
120131
return true
121132
}
122133
return false
@@ -180,7 +191,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
180191
s.writeError(w, 400, errMethod.Error())
181192
return
182193
}
183-
serviceSpec, methodSpec, errGet := s.services.get(method)
194+
serviceSpec, methodSpec, errGet := s.services.get(method, s.concatStyle)
184195
if errGet != nil {
185196
s.writeError(w, 400, errGet.Error())
186197
return

server_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,52 @@ func TestRegisterService(t *testing.T) {
6060
}
6161
}
6262

63+
func TestRegisterServiceWithSlash(t *testing.T) {
64+
var err error
65+
s := NewServer().SetConcatStyle("/")
66+
service1 := new(Service1)
67+
service2 := new(Service2)
68+
69+
// Inferred name.
70+
err = s.RegisterService(service1, "")
71+
if err != nil || !s.HasMethod("Service1/Multiply") {
72+
t.Errorf("Expected to be registered: Service1/Multiply")
73+
}
74+
// Provided name.
75+
err = s.RegisterService(service1, "Foo")
76+
if err != nil || !s.HasMethod("Foo/Multiply") {
77+
t.Errorf("Expected to be registered: Foo/Multiply")
78+
}
79+
// No methods.
80+
err = s.RegisterService(service2, "")
81+
if err == nil {
82+
t.Errorf("Expected error on service2")
83+
}
84+
}
85+
86+
func TestRegisterServiceWithUnderline(t *testing.T) {
87+
var err error
88+
s := NewServer().SetConcatStyle("_")
89+
service1 := new(Service1)
90+
service2 := new(Service2)
91+
92+
// Inferred name.
93+
err = s.RegisterService(service1, "")
94+
if err != nil || !s.HasMethod("Service1_Multiply") {
95+
t.Errorf("Expected to be registered: Service1_Multiply")
96+
}
97+
// Provided name.
98+
err = s.RegisterService(service1, "Foo")
99+
if err != nil || !s.HasMethod("Foo_Multiply") {
100+
t.Errorf("Expected to be registered: Foo_Multiply")
101+
}
102+
// No methods.
103+
err = s.RegisterService(service2, "")
104+
if err == nil {
105+
t.Errorf("Expected error on service2")
106+
}
107+
}
108+
63109
func TestRegisterTCPService(t *testing.T) {
64110
var err error
65111
s := NewServer()

v2/map.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,8 @@ func (m *serviceMap) register(rcvr interface{}, name string) error {
126126
// get returns a registered service given a method name.
127127
//
128128
// The method name uses a dotted notation as in "Service.Method".
129-
func (m *serviceMap) get(method string) (*service, *serviceMethod, error) {
130-
parts := strings.Split(method, ".")
129+
func (m *serviceMap) get(method string, concatStyle string) (*service, *serviceMethod, error) {
130+
parts := strings.Split(method, concatStyle)
131131
if len(parts) != 2 {
132132
err := fmt.Errorf("rpc: service/method request ill-formed: %q", method)
133133
return nil, nil, err

v2/server.go

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,9 @@ type CodecRequest interface {
4343
// NewServer returns a new RPC server.
4444
func NewServer() *Server {
4545
return &Server{
46-
codecs: make(map[string]Codec),
47-
services: new(serviceMap),
46+
codecs: make(map[string]Codec),
47+
services: new(serviceMap),
48+
concatStyle: ".",
4849
}
4950
}
5051

@@ -64,6 +65,16 @@ type Server struct {
6465
beforeFunc func(i *RequestInfo)
6566
afterFunc func(i *RequestInfo)
6667
validateFunc reflect.Value
68+
concatStyle string // The style used to concatenate service and method names, e.g., "Service.Method" or "Service.Method()"
69+
}
70+
71+
// SetConcatStyle sets the style used to concatenate service and method names.
72+
// The default style is ".".
73+
// This is useful when you want to use a different style, such as "/".
74+
// The style is used in the method name, e.g., "Service.Method" or "Service/Method".
75+
func (s *Server) SetConcatStyle(concatStyle string) *Server {
76+
s.concatStyle = concatStyle
77+
return s
6778
}
6879

6980
// RegisterCodec adds a new codec to the server.
@@ -120,13 +131,13 @@ func (s *Server) RegisterAfterFunc(f func(i *RequestInfo)) {
120131
//
121132
// Methods from the receiver will be extracted if these rules are satisfied:
122133
//
123-
// - The receiver is exported (begins with an upper case letter) or local
124-
// (defined in the package registering the service).
125-
// - The method name is exported.
126-
// - The method has three arguments: *http.Request, *args, *reply.
127-
// - All three arguments are pointers.
128-
// - The second and third arguments are exported or local.
129-
// - The method has return type error.
134+
// - The receiver is exported (begins with an upper case letter) or local
135+
// (defined in the package registering the service).
136+
// - The method name is exported.
137+
// - The method has three arguments: *http.Request, *args, *reply.
138+
// - All three arguments are pointers.
139+
// - The second and third arguments are exported or local.
140+
// - The method has return type error.
130141
//
131142
// All other methods are ignored.
132143
func (s *Server) RegisterService(receiver interface{}, name string) error {
@@ -137,7 +148,7 @@ func (s *Server) RegisterService(receiver interface{}, name string) error {
137148
//
138149
// The method uses a dotted notation as in "Service.Method".
139150
func (s *Server) HasMethod(method string) bool {
140-
if _, _, err := s.services.get(method); err == nil {
151+
if _, _, err := s.services.get(method, s.concatStyle); err == nil {
141152
return true
142153
}
143154
return false
@@ -173,7 +184,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
173184
codecReq.WriteError(w, http.StatusBadRequest, errMethod)
174185
return
175186
}
176-
serviceSpec, methodSpec, errGet := s.services.get(method)
187+
serviceSpec, methodSpec, errGet := s.services.get(method, s.concatStyle)
177188
if errGet != nil {
178189
codecReq.WriteError(w, http.StatusBadRequest, errGet)
179190
return

v2/server_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,52 @@ func TestRegisterService(t *testing.T) {
5959
}
6060
}
6161

62+
func TestRegisterServiceWithSlash(t *testing.T) {
63+
var err error
64+
s := NewServer().SetConcatStyle("/")
65+
service1 := new(Service1)
66+
service2 := new(Service2)
67+
68+
// Inferred name.
69+
err = s.RegisterService(service1, "")
70+
if err != nil || !s.HasMethod("Service1/Multiply") {
71+
t.Errorf("Expected to be registered: Service1/Multiply")
72+
}
73+
// Provided name.
74+
err = s.RegisterService(service1, "Foo")
75+
if err != nil || !s.HasMethod("Foo/Multiply") {
76+
t.Errorf("Expected to be registered: Foo/Multiply")
77+
}
78+
// No methods.
79+
err = s.RegisterService(service2, "")
80+
if err == nil {
81+
t.Errorf("Expected error on service2")
82+
}
83+
}
84+
85+
func TestRegisterServiceWithUnderline(t *testing.T) {
86+
var err error
87+
s := NewServer().SetConcatStyle("_")
88+
service1 := new(Service1)
89+
service2 := new(Service2)
90+
91+
// Inferred name.
92+
err = s.RegisterService(service1, "")
93+
if err != nil || !s.HasMethod("Service1_Multiply") {
94+
t.Errorf("Expected to be registered: Service1_Multiply")
95+
}
96+
// Provided name.
97+
err = s.RegisterService(service1, "Foo")
98+
if err != nil || !s.HasMethod("Foo_Multiply") {
99+
t.Errorf("Expected to be registered: Foo_Multiply")
100+
}
101+
// No methods.
102+
err = s.RegisterService(service2, "")
103+
if err == nil {
104+
t.Errorf("Expected error on service2")
105+
}
106+
}
107+
62108
// MockCodec decodes to Service1.Multiply.
63109
type MockCodec struct {
64110
A, B int

0 commit comments

Comments
 (0)