WIP mrpc wrote some docs, tried to make some progress on request/response types
This commit is contained in:
parent
0460a7745c
commit
bb0eeaff16
@ -1,15 +1,13 @@
|
|||||||
package mrpc
|
package mrpc
|
||||||
|
|
||||||
import "context"
|
// Debug data is arbitrary data embedded in a Request by the Client or in its
|
||||||
|
// Response by the Server. Debug data is organized into namespaces to help avoid
|
||||||
// Debug data is arbitrary data embedded in a Call's request by the Client or in
|
// conflicts while still preserving serializability.
|
||||||
// its Response by the Server. Debug data is organized into namespaces to help
|
|
||||||
// avoid conflicts while still preserving serializability.
|
|
||||||
//
|
//
|
||||||
// Debug data is intended to be used for debugging purposes only, and should
|
// Debug data is intended to be used for debugging purposes only, and should
|
||||||
// never be used to effect the path-of-action a Call takes. Put another way:
|
// never be used to effect the path-of-action a call takes. Put another way:
|
||||||
// when implementing a Call always assume that the Debug info has been
|
// when implementing a call always assume that the Debug info has been
|
||||||
// accidentally removed from the Call's request/response.
|
// accidentally removed from the call's Request/Response.
|
||||||
type Debug map[string]map[string]interface{}
|
type Debug map[string]map[string]interface{}
|
||||||
|
|
||||||
// Copy returns an identical copy of the Debug being called upon
|
// Copy returns an identical copy of the Debug being called upon
|
||||||
@ -25,10 +23,11 @@ func (d Debug) Copy() Debug {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set returns a copy of the Debug instance with the key set to the value within
|
// Set returns a copy of the Debug instance with the key set to the value within
|
||||||
// the given namespace.
|
// the given namespace. If Debug is nil a new instance is created and returned
|
||||||
|
// with the key set.
|
||||||
func (d Debug) Set(ns, key string, val interface{}) Debug {
|
func (d Debug) Set(ns, key string, val interface{}) Debug {
|
||||||
if d == nil {
|
if d == nil {
|
||||||
return Debug{ns: map[string]interface{}{key, val}}
|
return Debug{ns: map[string]interface{}{key: val}}
|
||||||
}
|
}
|
||||||
d = d.Copy()
|
d = d.Copy()
|
||||||
if d[ns] == nil {
|
if d[ns] == nil {
|
||||||
@ -47,21 +46,3 @@ func (d Debug) Get(ns, key string) (interface{}, bool) {
|
|||||||
val, ok := d[ns][key]
|
val, ok := d[ns][key]
|
||||||
return val, ok
|
return val, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
type debugKey int
|
|
||||||
|
|
||||||
// CtxWithDebug returns a new Context with the given Debug embedded in it,
|
|
||||||
// overwriting any previously embedded Debug.
|
|
||||||
func CtxWithDebug(ctx context.Context, d Debug) context.Context {
|
|
||||||
return context.WithValue(ctx, debugKey(0), d)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CtxDebug returns the Debug instance embedded in the Context, or nil if none
|
|
||||||
// has been embedded.
|
|
||||||
func CtxDebug(ctx context.Context) Debug {
|
|
||||||
d := ctx.Value(debugKey(0))
|
|
||||||
if d == nil {
|
|
||||||
return Debug(nil)
|
|
||||||
}
|
|
||||||
return d.(Debug)
|
|
||||||
}
|
|
||||||
|
73
mrpc/mrpc.go
73
mrpc/mrpc.go
@ -15,8 +15,14 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Request TODO
|
// TODO Request is making things difficult. It wants to be split into two types,
|
||||||
|
// like the Response is, but naming them is annoying. ClientRequest and
|
||||||
|
// HandlerRequest? RequestReader? Maybe 4 arguments to Client isn't that much...
|
||||||
|
|
||||||
|
// Request describes an RPC request being processed by a Handler
|
||||||
type Request struct {
|
type Request struct {
|
||||||
|
// Depending on the implementation of Client, Context may be canceled to
|
||||||
|
// indicate the Client has canceled the request.
|
||||||
Context context.Context
|
Context context.Context
|
||||||
|
|
||||||
// The name of the RPC method being called.
|
// The name of the RPC method being called.
|
||||||
@ -25,24 +31,38 @@ type Request struct {
|
|||||||
// Unmarshal takes in a pointer and unmarshals the RPC request's arguments
|
// Unmarshal takes in a pointer and unmarshals the RPC request's arguments
|
||||||
// into it. The properties of the unmarshaling are dependent on the
|
// into it. The properties of the unmarshaling are dependent on the
|
||||||
// underlying implementation of the protocol.
|
// underlying implementation of the protocol.
|
||||||
//
|
|
||||||
// This should only be called within ServeRPC.
|
|
||||||
Unmarshal func(interface{}) error
|
Unmarshal func(interface{}) error
|
||||||
|
|
||||||
|
// Debugging information being carried with the Request. See Debug's docs
|
||||||
|
// for more on how it is intended to be used
|
||||||
|
Debug Debug
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResponseWriter TODO
|
// ResponseWriter is used to capture the response of an RPC request being
|
||||||
|
// processed by a Handler
|
||||||
type ResponseWriter struct {
|
type ResponseWriter struct {
|
||||||
Context context.Context
|
// Response should be overwritten with whatever response to the call should
|
||||||
|
// be. The exact nature and behavior of how the response value is treated is
|
||||||
|
// dependent on the RPC implementation.
|
||||||
|
Response interface{}
|
||||||
|
|
||||||
Respond func(interface{})
|
// Debug may be overwritten to provide debugging information back to the
|
||||||
Err func(error)
|
// Client with the Response. See Debug's docs for more on how it is intended
|
||||||
|
// to be used.
|
||||||
|
Debug Debug
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reponse TODO
|
// Reponse describes the response from the RPC call being returned to the
|
||||||
|
// Client.
|
||||||
type Response struct {
|
type Response struct {
|
||||||
Context context.Context
|
// Unmarshal takes in a pointer value into which the Client will unmarshal
|
||||||
|
// the response value. The exact nature and behavior of how the pointer
|
||||||
|
// value is treated is dependend on the RPC implementation.
|
||||||
Unmarshal func(interface{}) error
|
Unmarshal func(interface{}) error
|
||||||
Err error
|
|
||||||
|
// Debug will be whatever debug information was set by the server when
|
||||||
|
// responding to the call.
|
||||||
|
Debug Debug
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handler is a type which serves RPC calls. For each incoming Requests the
|
// Handler is a type which serves RPC calls. For each incoming Requests the
|
||||||
@ -63,27 +83,17 @@ func (hf HandlerFunc) ServeRPC(r Request, rw *ResponseWriter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Client is an entity which can perform RPC calls against a remote endpoint.
|
// Client is an entity which can perform RPC calls against a remote endpoint.
|
||||||
//
|
|
||||||
// res should be a pointer into which the result of the RPC call will be
|
|
||||||
// unmarshaled according to Client's implementation. args will be marshaled and
|
|
||||||
// sent to the remote endpoint according to Client's implementation.
|
|
||||||
type Client interface {
|
type Client interface {
|
||||||
CallRPC(ctx context.Context, method string, args interface{}) Response
|
CallRPC(Request) Response
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClientFunc can be used to wrap an individual function which fits the CallRPC
|
// ClientFunc can be used to wrap an individual function which fits the CallRPC
|
||||||
// signature, and use that function as a Client
|
// signature, and use that function as a Client
|
||||||
type ClientFunc func(context.Context, string, interface{}) Response
|
type ClientFunc func(Request) Response
|
||||||
|
|
||||||
// CallRPC implements the method for the Client interface by calling the
|
// CallRPC implements the method for the Client interface by calling the
|
||||||
// underlying function
|
// underlying function
|
||||||
func (cf ClientFunc) CallRPC(
|
func (cf ClientFunc) CallRPC(r Request) { return cf(r) }
|
||||||
ctx context.Context,
|
|
||||||
method string,
|
|
||||||
args interface{},
|
|
||||||
) Response {
|
|
||||||
return cf(ctx, method, args)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReflectClient returns a Client whose CallRPC method will use reflection to
|
// ReflectClient returns a Client whose CallRPC method will use reflection to
|
||||||
// call the given Handler's ServeRPC method directly, using reflect.Value's Set
|
// call the given Handler's ServeRPC method directly, using reflect.Value's Set
|
||||||
@ -111,25 +121,14 @@ func ReflectClient(h Handler) Client {
|
|||||||
Method: method,
|
Method: method,
|
||||||
Unmarshal: func(i interface{}) error { return into(i, args) },
|
Unmarshal: func(i interface{}) error { return into(i, args) },
|
||||||
}
|
}
|
||||||
var res interface{}
|
rw := ResponseWriter{}
|
||||||
var resErr error
|
|
||||||
rw := ResponseWriter{
|
|
||||||
Context: context.Background(),
|
|
||||||
Respond: func(i interface{}) { res = i },
|
|
||||||
Err: func(err error) { resErr = err },
|
|
||||||
}
|
|
||||||
|
|
||||||
h.ServeRPC(req, &rw)
|
h.ServeRPC(req, &rw)
|
||||||
|
|
||||||
return Response{
|
return Response{
|
||||||
Context: rw.Context,
|
|
||||||
Unmarshal: func(i interface{}) error {
|
Unmarshal: func(i interface{}) error {
|
||||||
if resErr != nil {
|
return into(i, rw.Response)
|
||||||
return resErr
|
|
||||||
}
|
|
||||||
return into(i, res)
|
|
||||||
},
|
},
|
||||||
Err: resErr,
|
Debug: rw.Debug,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user