blob: c52a630c54e5792979b43bfa149d0b040201ec73 [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package server
import (
"v.io/v23/context"
"v.io/v23/naming"
"v.io/v23/rpc"
"v.io/v23/vdl"
"v.io/v23/vdlroot/signature"
"v.io/v23/verror"
"v.io/v23/vtrace"
)
var typedNil []int
const pkgPath = "v.io/x/ref/services/wspr/internal/rpc/server"
// Errors.
var (
ErrWrongNumberOfArgs = verror.Register(pkgPath+".ErrWrongNumberOfArgs", verror.NoRetry, "{1:}{2:} Method {3} got {4} args, want {5}{:_}")
ErrMethodNotFoundInSignature = verror.Register(pkgPath+".ErrMethodNotFoundInSignature", verror.NoRetry, "{1:}{2:} Method {3} not found in signature{:_}")
)
// invoker holds a delegate function to call on invoke and a list of methods that
// are available for be called.
type invoker struct {
// delegate function to call when an invoke request comes in
invokeFunc remoteInvokeFunc
signature []signature.Interface
globFunc remoteGlobFunc
}
var _ rpc.Invoker = (*invoker)(nil)
// newInvoker is an invoker factory
func newInvoker(signature []signature.Interface, invokeFunc remoteInvokeFunc, globFunc remoteGlobFunc) rpc.Invoker {
i := &invoker{invokeFunc, signature, globFunc}
return i
}
// Prepare implements the Invoker interface.
func (i *invoker) Prepare(methodName string, numArgs int) ([]interface{}, []*vdl.Value, error) {
method, err := i.MethodSignature(nil, nil, methodName)
if err != nil {
return nil, nil, err
}
if got, want := numArgs, len(method.InArgs); got != want {
return nil, nil, verror.New(ErrWrongNumberOfArgs, nil, methodName, got, want)
}
argptrs := make([]interface{}, len(method.InArgs))
for ix, arg := range method.InArgs {
argptrs[ix] = vdl.ZeroValue(arg.Type)
}
return argptrs, method.Tags, nil
}
// Invoke implements the Invoker interface.
func (i *invoker) Invoke(ctx *context.T, call rpc.StreamServerCall, methodName string, argptrs []interface{}) ([]interface{}, error) {
replychan := i.invokeFunc(ctx, call, methodName, argptrs)
// Wait for the result
reply := <-replychan
if reply.Err != nil {
return nil, reply.Err
}
vtrace.GetStore(ctx).Merge(reply.TraceResponse)
// Convert the reply.Results from []*vdl.Value to []interface{}
results := make([]interface{}, len(reply.Results))
for i, r := range reply.Results {
results[i] = r
}
return results, nil
}
// TODO(bjornick,rthellend): Find a reasonable way to implement this for JS.
func (i *invoker) Globber() *rpc.GlobState {
if i.globFunc == nil {
return nil
}
return &rpc.GlobState{AllGlobber: i}
}
func (i *invoker) Glob__(ctx *context.T, call rpc.ServerCall, pattern string) (<-chan naming.GlobReply, error) {
return i.globFunc(ctx, call, pattern)
}
func (i *invoker) Signature(ctx *context.T, call rpc.ServerCall) ([]signature.Interface, error) {
return i.signature, nil
}
func (i *invoker) MethodSignature(ctx *context.T, call rpc.ServerCall, method string) (signature.Method, error) {
if methodSig, ok := signature.FirstMethod(i.signature, method); ok {
return methodSig, nil
}
return signature.Method{}, verror.New(ErrMethodNotFoundInSignature, ctx, method)
}