blob: b097b6d550d3485762996eb2938272a6d3b27164 [file] [log] [blame]
package server
import (
"veyron.io/veyron/veyron2/ipc"
"veyron.io/veyron/veyron2/security"
"veyron.io/veyron/veyron2/verror"
)
var typedNil []int
// invoker holds a delegate function to call on invoke and a list of methods that
// are available for be called.
type invoker struct {
// signature of the service this invoker belogs to
sig ipc.ServiceSignature
// delegate function to call when an invoke request comes in
invokeFunc remoteInvokeFunc
// map of special methods like "Signature" which invoker handles on behalf of the actual service
predefinedInvokers map[string]ipc.Invoker
}
// newInvoker is an invoker factory
func newInvoker(sig ipc.ServiceSignature, invokeFunc remoteInvokeFunc) (ipc.Invoker, error) {
predefinedInvokers := make(map[string]ipc.Invoker)
// Special handling for predefined "signature" method
predefinedInvokers["Signature"] = newSignatureInvoker(sig)
i := &invoker{sig, invokeFunc, predefinedInvokers}
return i, nil
}
// Prepare implements the Invoker interface.
func (i *invoker) Prepare(methodName string, numArgs int) ([]interface{}, security.Label, error) {
if pi := i.predefinedInvokers[methodName]; pi != nil {
return pi.Prepare(methodName, numArgs)
}
method, ok := i.sig.Methods[methodName]
if !ok {
return nil, security.AdminLabel, verror.NoExistf("method name not found in IDL: %s", methodName)
}
argptrs := make([]interface{}, len(method.InArgs))
for ix := range method.InArgs {
var x interface{}
argptrs[ix] = &x // Accept AnyData
}
securityLabel := methodSecurityLabel(method)
return argptrs, securityLabel, nil
}
// Invoke implements the Invoker interface.
func (i *invoker) Invoke(methodName string, call ipc.ServerCall, argptrs []interface{}) ([]interface{}, error) {
if pi := i.predefinedInvokers[methodName]; pi != nil {
return pi.Invoke(methodName, call, argptrs)
}
if _, ok := i.sig.Methods[methodName]; !ok {
return nil, verror.NoExistf("method name not found in IDL: %s", methodName)
}
replychan := i.invokeFunc(methodName, argptrs, call)
// Wait for the result
reply := <-replychan
var err error = nil
if reply.Err != nil {
err = reply.Err
}
for i, v := range reply.Results {
if v == nil {
reply.Results[i] = typedNil
}
}
// We always assume JavaScript services might return error.
// JavaScript returns non-error results in reply.Results & error in reply.Err
// We add the error as the last result of the ipc invoke call since last
// out arg is where application error is expected to be.
results := make([]interface{}, len(reply.Results)+1)
results = append(reply.Results, err)
return results, nil
}
// methodSecurityLabel returns the security label for a given method.
func methodSecurityLabel(methodSig ipc.MethodSignature) security.Label {
// TODO(bprosnitz) Get the security label and return it here.
return security.AdminLabel
}