func extractResourceFromArgs(rpc *core.RPC) (resource string, err error) { if rpc.GetArgsOneof() == nil { return "", fmt.Errorf("Could not find args") } args, ok := rpc.GetArgsOneof().(*core.RPC_Args) if !ok { return "", fmt.Errorf("Unexpected type of args for newResource") } if len(args.Args.Element) != 1 { return "", fmt.Errorf("Unexpected number of args for newResource") } el := args.Args.Element[0] if el.GetJsonValueOneof() == nil { return "", fmt.Errorf("Unexpected arg for newResource") } strArg, ok := el.GetJsonValueOneof().(*core.JSON_JsonString) if !ok { return "", fmt.Errorf("Unexpected arg type for newResource") } resource = strArg.JsonString if resource == "" { return "", fmt.Errorf("Invalid resource empty string") } return resource, nil }
// HandleRPC is an internal method. Do not use! func (server *Server) HandleRPC( ctx context.Context, rpc *core.RPC) (reply *core.RPCReply, err error) { err = setInternalRPCGateway(ctx) if err != nil { return nil, err } leverURL, err := extractLeverURL(ctx) if err != nil { return nil, err } if rpc.GetArgsOneof() == nil { return nil, fmt.Errorf("RPC has no args oneof") } server.lock.RLock() entry, handlerOK := server.handlers[leverURL.Method] resourceOK := true if leverURL.Resource != "" { _, resourceOK = server.resources[leverURL.Resource] } server.lock.RUnlock() if !handlerOK { return nil, fmt.Errorf("Method not found") } if !resourceOK { return nil, fmt.Errorf("Resource not found") } err = server.maybeHandleResourceLifecycle(leverURL, rpc) if err != nil { return nil, err } return callHandler(ctx, leverURL.Resource, entry, rpc, nil) }
func callHandler( ctx context.Context, resource string, entry *handlerEntry, rpc *core.RPC, grpcStream core.LeverRPC_HandleStreamingRPCServer) ( reply *core.RPCReply, err error) { // Prepare args for handler. var callArgs []reflect.Value if entry.isMethod { callArgs = append(callArgs, reflect.ValueOf(entry.obj)) } isStreaming := (grpcStream != nil) if isStreaming { callArgs = append( callArgs, reflect.ValueOf(newServerStream(grpcStream))) } else { if entry.hasContext { callArgs = append(callArgs, reflect.ValueOf(ctx)) } } if resource != "" { callArgs = append(callArgs, reflect.ValueOf(resource)) } switch args := rpc.GetArgsOneof().(type) { case *core.RPC_Args: var values []reflect.Value values, err = decodeArgsAsValue(args.Args, entry, isStreaming) if err != nil { return nil, err } callArgs = append(callArgs, values...) case *core.RPC_ByteArgs: callArgs = append(callArgs, reflect.ValueOf(args.ByteArgs)) default: return nil, fmt.Errorf("Invalid args") } // Call handler. result := reflect.ValueOf(entry.handler).Call(callArgs) // Interpret result. errIndex := 1 if isStreaming { errIndex = 0 } if entry.isByteErrorResult { var errBytesResult []byte v := result[errIndex].Interface() if v != nil { var ok bool errBytesResult, ok = result[errIndex].Interface().([]byte) if !ok { errBytesResult = result[errIndex].Interface().(BytesError).GetBytes() } if errBytesResult != nil { if !isStreaming { return &core.RPCReply{ ResultOneof: &core.RPCReply_ByteError{ ByteError: errBytesResult, }, }, nil } err = grpcStream.Send(&core.StreamMessage{ MessageOneof: &core.StreamMessage_ByteError{ ByteError: errBytesResult, }, }) return nil, err } } } else { v := result[errIndex].Interface() if v != nil { theError, isErrorType := v.(error) if isErrorType { // For error type, just use the string returned by Error(). v = theError.Error() } var encodedErr *core.JSON encodedErr, err = encodeArg(v) if err != nil { return nil, err } if !isStreaming { return &core.RPCReply{ ResultOneof: &core.RPCReply_Error{ Error: encodedErr, }, }, nil } err = grpcStream.Send(&core.StreamMessage{ MessageOneof: &core.StreamMessage_Error{ Error: encodedErr, }, }) return nil, err } } if isStreaming { // Stream case - no reply sent back. return nil, nil } // Non-stream case - build reply. if entry.isByteResult { return &core.RPCReply{ ResultOneof: &core.RPCReply_ByteResult{ ByteResult: result[0].Interface().([]byte), }, }, nil } encodedResult, err := encodeArg(result[0].Interface()) if err != nil { return nil, err } return &core.RPCReply{ ResultOneof: &core.RPCReply_Result{ Result: encodedResult, }, }, nil }