support remote server group handler

This commit is contained in:
Umputun
2019-06-25 20:06:30 -05:00
parent f30937c55e
commit db6c387fe9
3 changed files with 72 additions and 8 deletions
+1 -1
View File
@@ -59,7 +59,7 @@ func (r *Client) Call(method string, args ...interface{}) (*Response, error) {
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return nil, errors.Errorf("bad status %d for %s", resp.StatusCode, method)
return nil, errors.Errorf("bad status %s for %s", resp.Status, method)
}
cr := Response{}
+22
View File
@@ -40,6 +40,9 @@ type Server struct {
}
}
// Encoder is a function to encode call's result to Response
type Encoder func(id uint64, resp interface{}, e error) (Response, error)
// ServerFn handler registered for each method with Add
// Implementations provided by consumer and define response logic.
type ServerFn func(id uint64, params json.RawMessage) Response
@@ -107,10 +110,29 @@ func (s *Server) Shutdown() error {
// Add method handler
func (s *Server) Add(method string, fn ServerFn) {
s.httpServer.Lock()
defer s.httpServer.Unlock()
if s.httpServer.Server != nil {
log.Printf("[WARN] ignored method %s, can't be added to activated server", method)
return
}
s.funcs.once.Do(func() {
s.funcs.m = map[string]ServerFn{}
})
s.funcs.m[method] = fn
log.Printf("[INFO] add handler for %s", method)
}
// HandlersGroup alias for map of handlers
type HandlersGroup map[string]ServerFn
// Group of handlers with common prefix
func (s *Server) Group(prefix string, m HandlersGroup) {
for k, v := range m {
s.Add(prefix+"."+k, v)
}
}
func (s *Server) handler(w http.ResponseWriter, r *http.Request) {
+49 -7
View File
@@ -40,6 +40,7 @@ func TestServerPrimitiveTypes(t *testing.T) {
})
go func() { s.Run(9091) }()
defer func() { assert.NoError(t, s.Shutdown()) }()
time.Sleep(10 * time.Millisecond)
// check with direct http call
@@ -64,7 +65,6 @@ func TestServerPrimitiveTypes(t *testing.T) {
err = json.Unmarshal(*r.Result, &res)
assert.Equal(t, respData{Res1: "res blah", Res2: true}, res)
assert.Equal(t, uint64(1), r.ID)
assert.NoError(t, s.Shutdown())
}
func TestServerWithObject(t *testing.T) {
@@ -94,6 +94,7 @@ func TestServerWithObject(t *testing.T) {
})
go func() { s.Run(9091) }()
defer func() { assert.NoError(t, s.Shutdown()) }()
time.Sleep(10 * time.Millisecond)
c := Client{API: "http://127.0.0.1:9091/v1/cmd", Client: http.Client{}}
@@ -104,8 +105,6 @@ func TestServerWithObject(t *testing.T) {
res := respData{}
err = json.Unmarshal(*r.Result, &res)
assert.Equal(t, respData{Res1: "res blah", Res2: true}, res)
assert.NoError(t, s.Shutdown())
}
func TestServerMethodNotImplemented(t *testing.T) {
@@ -148,6 +147,7 @@ func TestServerWithAuth(t *testing.T) {
go func() { s.Run(9091) }()
time.Sleep(10 * time.Millisecond)
defer func() { assert.NoError(t, s.Shutdown()) }()
c := Client{API: "http://127.0.0.1:9091/v1/cmd", Client: http.Client{}, AuthUser: "user", AuthPasswd: "passwd"}
r, err := c.Call("test", "blah", 42, true)
@@ -160,9 +160,7 @@ func TestServerWithAuth(t *testing.T) {
c = Client{API: "http://127.0.0.1:9091/v1/cmd", Client: http.Client{}}
_, err = c.Call("test", "blah", 42, true)
assert.EqualError(t, err, "bad status 401 for test")
assert.NoError(t, s.Shutdown())
assert.EqualError(t, err, "bad status 401 Unauthorized for test")
}
func TestServerErrReturn(t *testing.T) {
@@ -186,13 +184,57 @@ func TestServerErrReturn(t *testing.T) {
})
go func() { s.Run(9091) }()
defer func() { assert.NoError(t, s.Shutdown()) }()
time.Sleep(10 * time.Millisecond)
c := Client{API: "http://127.0.0.1:9091/v1/cmd", Client: http.Client{}, AuthUser: "user", AuthPasswd: "passwd"}
_, err := c.Call("test", "blah", 42, true)
assert.EqualError(t, err, "some error")
}
assert.NoError(t, s.Shutdown())
func TestServerGroup(t *testing.T) {
s := Server{API: "/v1/cmd"}
s.Group("pre", HandlersGroup{
"fn1": func(id uint64, params json.RawMessage) Response {
return Response{}
},
"fn2": func(id uint64, params json.RawMessage) Response {
return Response{}
},
})
go func() { s.Run(9091) }()
defer func() { assert.NoError(t, s.Shutdown()) }()
time.Sleep(10 * time.Millisecond)
c := Client{API: "http://127.0.0.1:9091/v1/cmd", Client: http.Client{}}
_, err := c.Call("fn1")
assert.EqualError(t, err, "bad status 501 Not Implemented for fn1")
_, err = c.Call("pre.fn1")
assert.NoError(t, err)
_, err = c.Call("pre.fn2")
assert.NoError(t, err)
}
func TestServerAddLate(t *testing.T) {
s := Server{API: "/v1/cmd"}
s.Add("fn1", func(id uint64, params json.RawMessage) Response {
return Response{}
})
go func() { s.Run(9091) }()
defer func() { assert.NoError(t, s.Shutdown()) }()
time.Sleep(10 * time.Millisecond)
// too late, ignored after run
s.Add("fn2", func(id uint64, params json.RawMessage) Response {
return Response{}
})
c := Client{API: "http://127.0.0.1:9091/v1/cmd", Client: http.Client{}}
_, err := c.Call("fn1")
assert.NoError(t, err)
_, err = c.Call("fn2")
assert.EqualError(t, err, "bad status 501 Not Implemented for fn2")
}
func TestServerNoHandlers(t *testing.T) {