blob: e88b7c78453906bc7f6bcebb4002b67adf3a14f1 [file] [log] [blame]
package main
import (
"flag"
"fmt"
"log"
"v.io/v23"
"v.io/v23/context"
"v.io/v23/options"
"v.io/v23/security"
"v.io/v23/vdl"
"mojo/public/go/application"
"mojo/public/go/bindings"
"mojo/public/go/system"
"mojo/public/interfaces/bindings/mojom_types"
"mojo/public/interfaces/bindings/v23proxy"
"v.io/x/mojo/transcoder"
_ "v.io/x/ref/runtime/factories/static"
)
//#include "mojo/public/c/system/types.h"
import "C"
func init() {
flag.String("child-connection-id", "", "")
flag.String("mojo-platform-channel-handle", "", "")
}
type v23HeaderReceiver struct {
delegate *V23ServerDelegate
v23Name string
ifaceSig mojom_types.MojomInterface
desc map[string]mojom_types.UserDefinedType
serviceName string
handle system.MessagePipeHandle
}
func (r *v23HeaderReceiver) SetupProxy(v23Name string, ifaceSig mojom_types.MojomInterface, desc map[string]mojom_types.UserDefinedType, serviceName string, handle system.MessagePipeHandle) (err error) {
log.Printf("[server] In SetupProxy(%s, %v, %v, %s, %v)\n", v23Name, ifaceSig, desc, serviceName, handle)
r.v23Name = v23Name
r.ifaceSig = ifaceSig
r.desc = desc
r.serviceName = serviceName
r.handle = handle
go func() {
connector := bindings.NewConnector(r.handle, bindings.GetAsyncWaiter())
// Read generic calls in a loop
stub := &genericStub{
header: r,
ctx: r.delegate.ctx,
connector: connector,
}
bindingStub := bindings.NewStub(connector, stub)
for {
if err := bindingStub.ServeRequest(); err != nil {
connectionError, ok := err.(*bindings.ConnectionError)
if !ok || !connectionError.Closed() {
log.Println(err)
}
break
}
}
r.delegate.stubs = append(r.delegate.stubs, bindingStub)
}()
return nil
}
type byteCopyingPayload []byte
func (bcp byteCopyingPayload) Encode(encoder *bindings.Encoder) error {
encoder.WriteRawBytes(bcp)
return nil
}
func (bcp byteCopyingPayload) Decode(decoder *bindings.Decoder) error {
panic("not supported")
}
type genericStub struct {
header *v23HeaderReceiver
ctx *context.T
connector *bindings.Connector
}
func (s *genericStub) Accept(message *bindings.Message) (err error) {
/*if int(message.Header.Type) >= len(s.header.ifaceSig.Methods) {
return fmt.Errorf("Method had index %d, but interface only has %d methods",
message.Header.Type, len(s.header.ifaceSig.Methods))
}*/
if _, ok := s.header.ifaceSig.Methods[message.Header.Type]; !ok {
return fmt.Errorf("Method had index %d, but interface only has %d methods",
message.Header.Type, len(s.header.ifaceSig.Methods))
}
methodSig := s.header.ifaceSig.Methods[message.Header.Type]
methodName := *methodSig.DeclData.ShortName
// Should we perform validation of flags like generated methods?
// Does this handle 0-arg methods?
messageBytes := message.Payload
response, err := s.Call(s.header.v23Name, methodName, messageBytes, methodSig.Parameters, methodSig.ResponseParams)
if err != nil {
return err
}
responseHeader := bindings.MessageHeader{
Type: message.Header.Type,
Flags: bindings.MessageIsResponseFlag,
RequestId: message.Header.RequestId,
}
responseMessage, err := bindings.EncodeMessage(responseHeader, byteCopyingPayload(response))
if err != nil {
return err
}
return s.connector.WriteMessage(responseMessage)
}
func (s *genericStub) Call(name, method string, value []byte, inParamsType mojom_types.MojomStruct, outParamsType *mojom_types.MojomStruct) ([]byte, error) {
log.Printf("server: %s.%s: %#v", name, method, inParamsType)
inVType := transcoder.MojomStructToVDLType(inParamsType, s.header.desc)
var outVType *vdl.Type
if outParamsType != nil {
outVType = transcoder.MojomStructToVDLType(*outParamsType, s.header.desc)
}
// Decode the vdl.Value from the mojom bytes and mojom type.
inVdlValue, err := transcoder.DecodeValue(value, inVType)
if err != nil {
return nil, fmt.Errorf("transcoder.DecodeValue failed: %v", err)
}
// inVdlValue is a struct, but we need to send []interface.
inargs := splitVdlValueByMojomType(inVdlValue, inVType)
inargsIfc := make([]interface{}, len(inargs))
for i := range inargs {
inargsIfc[i] = inargs[i]
}
// We know that the v23proxy (on the other side) will give us back a bunch of
// data in []interface{}. so we'll want to decode them into *vdl.Value.
log.Printf("%s %v\n", method, outParamsType)
outargs := make([]*vdl.Value, len(outParamsType.Fields))
outptrs := make([]interface{}, len(outargs))
for i := range outargs {
outptrs[i] = &outargs[i]
}
// Now, run the call without any authorization.
if err := v23.GetClient(s.ctx).Call(s.ctx, name, method, inargsIfc, outptrs, options.ServerAuthorizer{security.AllowEveryone()}); err != nil {
return nil, err
}
// Now convert the []interface{} into a *vdl.Value (struct).
outVdlValue := combineVdlValueByMojomType(outargs, outVType)
// Finally, encode this *vdl.Value (struct) into mojom bytes and send the response.
result, err := transcoder.Encode(outVdlValue)
if err != nil {
return nil, fmt.Errorf("transcoder.Encode failed: %v", err)
}
return result, nil
}
type V23ServerDelegate struct {
ctx *context.T
stubs []*bindings.Stub
shutdown v23.Shutdown
}
func (delegate *V23ServerDelegate) Initialize(context application.Context) {
log.Printf("V23ServerDelegate.Initialize...")
// Start up v23 whenever a v23proxy is begun.
// This is done regardless of whether we are initializing this v23proxy for use
// as a client or as a server.
ctx, shutdown := v23.Init()
delegate.ctx = ctx
delegate.shutdown = shutdown
// TODO(alexfandrianto): Does Mojo stop us from creating too many v23proxy?
// Is it 1 per shell? Ideally, each device will only serve 1 of these v23proxy,
// but it is not problematic to have extra.
/*s := MakeServer(ctx)
err := s.ServeDispatcher("", &V23ProxyDispatcher{
appctx: context,
})*/
_, s, err := v23.WithNewDispatchingServer(ctx, "", &V23ProxyDispatcher{
appctx: context,
})
if err != nil {
log.Panic("Error serving service: ", err)
}
endpoints := s.Status().Endpoints
fmt.Printf("Listening at: /%v\n", endpoints[0])
}
/*func MakeServer(ctx *context.T) rpc.Server {
s, err := v23.NewServer(ctx)
if err != nil {
log.Panic("Failure creating server: ", err)
}
endpoints, err := s.Listen(v23.GetListenSpec(ctx))
if err != nil {
log.Panic("Error listening to service: ", err)
}
fmt.Printf("Listening at: /%v\n", endpoints[0])
return s
}*/
type V23ProxyDispatcher struct {
appctx application.Context
}
func (v23pd *V23ProxyDispatcher) Lookup(ctx *context.T, suffix string) (interface{}, security.Authorizer, error) {
log.Printf("Dispatcher: %s", suffix)
return fakeService{
appctx: v23pd.appctx,
suffix: suffix,
ids: bindings.NewCounter(),
}, security.AllowEveryone(), nil
}
func (delegate *V23ServerDelegate) Create(request v23proxy.V23_Request) {
headerReceiver := &v23HeaderReceiver{delegate: delegate}
v23Stub := v23proxy.NewV23Stub(request, headerReceiver, bindings.GetAsyncWaiter())
delegate.stubs = append(delegate.stubs, v23Stub)
go func() {
// Read header message
if err := v23Stub.ServeRequest(); err != nil {
connectionError, ok := err.(*bindings.ConnectionError)
if !ok || !connectionError.Closed() {
log.Println(err)
}
return
}
}()
}
func (delegate *V23ServerDelegate) AcceptConnection(connection *application.Connection) {
log.Printf("V23ServerDelegate.AcceptConnection...")
connection.ProvideServices(&v23proxy.V23_ServiceFactory{delegate})
}
func (delegate *V23ServerDelegate) Quit() {
log.Printf("V23ServerDelegate.Quit...")
for _, stub := range delegate.stubs {
stub.Close()
}
delegate.shutdown()
}
//export MojoMain
func MojoMain(handle C.MojoHandle) C.MojoResult {
application.Run(&V23ServerDelegate{}, system.MojoHandle(handle))
return C.MOJO_RESULT_OK
}
func main() {
}