Documentation
¶
Overview ¶
Package handler provides implementations of the jrpc2.Assigner interface, and support for adapting functions to the jrpc2.Handler interface.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Args ¶
type Args []interface{}
Args is a wrapper that decodes an array of positional parameters into concrete locations.
Unmarshaling a JSON value into an Args value v succeeds if the JSON encodes an array with length len(v), and unmarshaling each subvalue i into the corresponding v[i] succeeds. As a special case, if v[i] == nil the corresponding value is discarded.
Marshaling an Args value v into JSON succeeds if each element of the slice is JSON marshalable, and yields a JSON array of length len(v) containing the JSON values corresponding to the elements of v.
Usage example:
func Handler(ctx context.Context, req *jrpc2.Request) (interface{}, error) { var x, y int var s string if err := req.UnmarshalParams(&handler.Args{&x, &y, &s}); err != nil { return nil, err } // do useful work with x, y, and s }
Example (Marshal) ¶
package main import ( "encoding/json" "fmt" "log" "github.com/creachadair/jrpc2/handler" ) func main() { bits, err := json.Marshal(handler.Args{1, "foo", false, nil}) if err != nil { log.Fatalf("Encoding failed: %v", err) } fmt.Println(string(bits)) }
Output: [1,"foo",false,null]
Example (Unmarshal) ¶
package main import ( "encoding/json" "fmt" "log" "github.com/creachadair/jrpc2/handler" ) func main() { const input = `[25, false, "apple"]` var count int var item string if err := json.Unmarshal([]byte(input), &handler.Args{&count, nil, &item}); err != nil { log.Fatalf("Decoding failed: %v", err) } fmt.Printf("count=%d, item=%q\n", count, item) }
Output: count=25, item="apple"
func (Args) MarshalJSON ¶
MarshalJSON supports JSON marshaling for a.
func (Args) UnmarshalJSON ¶
UnmarshalJSON supports JSON unmarshaling for a.
type Func ¶
A Func adapts a function having the correct signature to a jrpc2.Handler.
func New ¶
func New(fn interface{}) Func
New adapts a function to a jrpc2.Handler. The concrete value of fn must be function accepted by Check. The resulting Func will handle JSON encoding and decoding, call fn, and report appropriate errors.
New is intended for use during program initialization, and will panic if the type of fn does not have one of the accepted forms. Programs that need to check for possible errors should call handler.Check directly, and use the Wrap method of the resulting FuncInfo to obtain the wrapper.
func NewPos ¶ added in v0.28.4
NewPos adapts a function to a jrpc2.Handler. The concrete value of fn must be a function accepted by Positional. The resulting Func will handle JSON encoding and decoding, call fn, and report appropriate errors.
NewPos is intended for use during program initialization, and will panic if the type of fn does not have one of the accepted forms. Programs that need to check for possible errors should call handler.Positional directly, and use the Wrap method of the resulting FuncInfo to obtain the wrapper.
type FuncInfo ¶ added in v0.21.2
type FuncInfo struct { Type reflect.Type // the complete function type Argument reflect.Type // the non-context argument type, or nil IsVariadic bool // true if the function is variadic on its argument Result reflect.Type // the non-error result type, or nil ReportsError bool // true if the function reports an error // contains filtered or unexported fields }
FuncInfo captures type signature information from a valid handler function.
func Check ¶ added in v0.21.2
Check checks whether fn can serve as a jrpc2.Handler. The concrete value of fn must be a function with one of the following type signature schemes, for JSON-marshalable types X and Y:
func(context.Context) error func(context.Context) Y func(context.Context) (Y, error) func(context.Context, X) error func(context.Context, X) Y func(context.Context, X) (Y, error) func(context.Context, ...X) error func(context.Context, ...X) Y func(context.Context, ...X) (Y, error) func(context.Context, *jrpc2.Request) error func(context.Context, *jrpc2.Request) Y func(context.Context, *jrpc2.Request) (Y, error) func(context.Context, *jrpc2.Request) (interface{}, error)
If fn does not have one of these forms, Check reports an error.
Note that the JSON-RPC standard restricts encoded parameter values to arrays and objects. Check will accept argument types that do not encode to arrays or objects, but the wrapper will report an error when decoding the request.
The recommended solution is to define a struct type for your parameters. For arbitrary single value types, however, another approach is to wrap it in a 1-element array, for example:
func(ctx context.Context, sp [1]string) error { s := sp[0] // pull the actual argument out of the array // ... }
Example ¶
package main import ( "context" "fmt" "log" "github.com/creachadair/jrpc2/handler" ) func main() { fi, err := handler.Check(func(_ context.Context, ss []string) int { return len(ss) }) if err != nil { log.Fatalf("Check failed: %v", err) } fmt.Printf("Argument type: %v\n", fi.Argument) fmt.Printf("Result type: %v\n", fi.Result) fmt.Printf("Reports error? %v\n", fi.ReportsError) fmt.Printf("Wrapped type: %T\n", fi.Wrap()) }
Output: Argument type: []string Result type: int Reports error? false Wrapped type: handler.Func
func Positional ¶ added in v0.28.3
Positional checks whether fn can serve as a jrpc2.Handler. The concrete value of fn must be a function with one of the following type signature schemes:
func(context.Context, X1, x2, ..., Xn) (Y, error) func(context.Context, X1, x2, ..., Xn) Y func(context.Context, X1, x2, ..., Xn) error
For JSON-marshalable types X_i and Y. If fn does not have one of these forms, Positional reports an error. The given names must match the number of non-context arguments exactly. Variadic functions are not supported.
In contrast to Check, this function allows any number of arguments, but the caller must provide names for them. Positional creates an anonymous struct type whose fields correspond to the non-context arguments of fn. The names are used as the JSON field keys for the corresponding parameters.
When converted into a handler.Func, the wrapped function accepts a JSON object with the field keys named. For example, given:
func add(ctx context.Context, x, y int) int { return x + y } fi, err := handler.Positional(add, "first", "second") // ... call := fi.Wrap()
the resulting JSON-RPC handler accepts a parameter object like:
{"first": 17, "second": 23}
where "first" is mapped to argument x and "second" to argument y. Unknown field keys generate an error. The field names are not required to match the parameter names declared by the function; it is the names assigned here that determine which object keys are accepted.
Example ¶
package main import ( "context" "fmt" "log" "github.com/creachadair/jrpc2" "github.com/creachadair/jrpc2/handler" ) func main() { fn := func(ctx context.Context, name string, age int, accurate bool) error { fmt.Printf("%s is %d years old (fact check: %v)\n", name, age, accurate) return nil } call := handler.NewPos(fn, "name", "age", "accurate") req, err := jrpc2.ParseRequests([]byte(`{ "jsonrpc": "2.0", "id": 1, "method": "foo", "params": { "name": "Dennis", "age": 37, "accurate": true } }`)) if err != nil { log.Fatalf("Parse: %v", err) } if _, err := call(context.Background(), req[0]); err != nil { log.Fatalf("Call: %v", err) } }
Output: Dennis is 37 years old (fact check: true)
func (*FuncInfo) Wrap ¶ added in v0.21.2
Wrap adapts the function represented by fi in a Func that satisfies the jrpc2.Handler interface. The wrapped function can obtain the *jrpc2.Request value from its context argument using the jrpc2.InboundRequest helper.
This method panics if fi == nil or if it does not represent a valid function type. A FuncInfo returned by a successful call to Check is always valid.
type Map ¶
A Map is a trivial implementation of the jrpc2.Assigner interface that looks up method names in a map of static jrpc2.Handler values.
type Obj ¶ added in v0.6.2
type Obj map[string]interface{}
Obj is a wrapper that maps object fields into concrete locations.
Unmarshaling a JSON text into an Obj value v succeeds if the JSON encodes an object, and unmarshaling the value for each key k of the object into v[k] succeeds. If k does not exist in v, it is ignored.
Marshaling an Obj into JSON works as for an ordinary map.
Example (Unmarshal) ¶
package main import ( "encoding/json" "fmt" "log" "github.com/creachadair/jrpc2/handler" ) func main() { const input = `{"uid": 501, "name": "P. T. Barnum", "tags": [1, 3]}` var uid int var name string if err := json.Unmarshal([]byte(input), &handler.Obj{ "uid": &uid, "name": &name, }); err != nil { log.Fatalf("Decoding failed: %v", err) } fmt.Printf("uid=%d, name=%q\n", uid, name) }
Output: uid=501, name="P. T. Barnum"
func (Obj) UnmarshalJSON ¶ added in v0.6.2
UnmarshalJSON supports JSON unmarshaling into o.
type ServiceMap ¶
A ServiceMap combines multiple assigners into one, permitting a server to export multiple services under different names.
func (ServiceMap) Assign ¶
Assign splits the inbound method name as Service.Method, and passes the Method portion to the corresponding Service assigner. If method does not have the form Service.Method, or if Service is not set in m, the lookup fails and returns nil.
func (ServiceMap) Names ¶
func (m ServiceMap) Names() []string
Names reports the composed names of all the methods in the service, each having the form Service.Method.