syncbase: implement various mojo stubs

as part of this, adds all the glue needed to synthesize
ctx and call, etc.

Change-Id: I273e3bdcdfa9a0bd59379e4889631616777d321a
diff --git a/x/ref/services/syncbase/server/mojo_call.go b/x/ref/services/syncbase/server/mojo_call.go
new file mode 100644
index 0000000..d0b9dac
--- /dev/null
+++ b/x/ref/services/syncbase/server/mojo_call.go
@@ -0,0 +1,68 @@
+// 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.
+
+// +build mojo
+
+package server
+
+import (
+	"v.io/v23"
+	"v.io/v23/context"
+	"v.io/v23/naming"
+	"v.io/v23/rpc"
+	"v.io/v23/security"
+)
+
+type mojoServerCall struct {
+	sec    security.Call
+	srv    rpc.Server
+	suffix string
+}
+
+// TODO(sadovsky): Synthesize endpoints and discharges as needed.
+func newMojoServerCall(ctx *context.T, srv rpc.Server, suffix string, method rpc.MethodDesc) rpc.ServerCall {
+	p := v23.GetPrincipal(ctx)
+	// HACK: For now, we set the remote (client, i.e. Mojo app) blessing to be the
+	// same as the local (server, i.e. Syncbase Mojo service) blessing.
+	// TODO(sadovsky): Eliminate this hack.
+	blessings := p.BlessingStore().Default()
+	return &mojoServerCall{
+		sec: security.NewCall(&security.CallParams{
+			Method:          method.Name,
+			MethodTags:      method.Tags,
+			Suffix:          suffix,
+			LocalPrincipal:  p,
+			LocalBlessings:  blessings,
+			RemoteBlessings: blessings,
+		}),
+		srv:    srv,
+		suffix: suffix,
+	}
+}
+
+var _ rpc.ServerCall = (*mojoServerCall)(nil)
+
+func (call *mojoServerCall) Security() security.Call {
+	return call.sec
+}
+
+func (call *mojoServerCall) Suffix() string {
+	return call.suffix
+}
+
+func (call *mojoServerCall) LocalEndpoint() naming.Endpoint {
+	return call.sec.LocalEndpoint()
+}
+
+func (call *mojoServerCall) RemoteEndpoint() naming.Endpoint {
+	return call.sec.RemoteEndpoint()
+}
+
+func (call *mojoServerCall) GrantedBlessings() security.Blessings {
+	return security.Blessings{}
+}
+
+func (call *mojoServerCall) Server() rpc.Server {
+	return call.srv
+}
diff --git a/x/ref/services/syncbase/server/mojo_impl.go b/x/ref/services/syncbase/server/mojo_impl.go
index bc7d0d7..8787d0f 100644
--- a/x/ref/services/syncbase/server/mojo_impl.go
+++ b/x/ref/services/syncbase/server/mojo_impl.go
@@ -4,190 +4,480 @@
 
 // +build mojo
 
+// Implementation of Syncbase Mojo stubs. Our strategy is to translate Mojo stub
+// requests into Vanadium stub requests, and Vanadium stub responses into Mojo
+// stub responses. As part of this procedure, we synthesize "fake" ctx and call
+// objects to pass to the Vanadium stubs.
+
 package server
 
 import (
-	wire "mojom/syncbase"
+	"bytes"
+	"fmt"
+	"strings"
+
+	mojom "mojom/syncbase"
+	wire "v.io/syncbase/v23/services/syncbase"
+	nosqlwire "v.io/syncbase/v23/services/syncbase/nosql"
+	"v.io/v23/context"
+	"v.io/v23/rpc"
+	"v.io/v23/security/access"
+	"v.io/v23/services/permissions"
+	"v.io/v23/verror"
+	"v.io/v23/vtrace"
 )
 
+const NoSchema int32 = -1
+
 type mojoImpl struct {
-	s *service
+	ctx  *context.T
+	srv  rpc.Server
+	disp rpc.Dispatcher
 }
 
-func NewMojoImpl(s interface{}) *mojoImpl {
-	return &mojoImpl{s: s.(*service)}
+func NewMojoImpl(ctx *context.T, srv rpc.Server, disp rpc.Dispatcher) *mojoImpl {
+	return &mojoImpl{ctx: ctx, srv: srv, disp: disp}
 }
 
-// TODO(sadovsky): Implement all stubs. The high-level plan is to translate Mojo
-// requests into Vanadium requests by constructing suitable ctx and call objects
-// and then performing the same work that server.Dispatcher and nosql.Dispatcher
-// do (perhaps with some refactoring to share dispatcher code).
+func methodDesc(desc rpc.InterfaceDesc, name string) rpc.MethodDesc {
+	for _, method := range desc.Methods {
+		if method.Name == name {
+			return method
+		}
+	}
+	panic(fmt.Sprintf("unknown method: %s.%s", desc.Name, name))
+}
 
-// TODO(sadovsky): Implement security hack, where we derive a client blessing
-// from the Syncbase server's blessing.
+func (m *mojoImpl) newCtxCall(suffix string, method rpc.MethodDesc) (*context.T, rpc.ServerCall) {
+	ctx, _ := vtrace.WithNewTrace(m.ctx)
+	return ctx, newMojoServerCall(m.ctx, m.srv, suffix, method)
+}
+
+////////////////////////////////////////
+// Struct converters
+
+func toMojoError(err error) mojom.Error {
+	if err == nil {
+		return mojom.Error{}
+	}
+	return mojom.Error{
+		Id:         string(verror.ErrorID(err)),
+		ActionCode: uint32(verror.Action(err)),
+		Msg:        err.Error(),
+	}
+}
+
+func toV23Perms(mPerms mojom.Perms) (access.Permissions, error) {
+	return access.ReadPermissions(strings.NewReader(mPerms.Json))
+}
+
+func toMojoPerms(vPerms access.Permissions) (mojom.Perms, error) {
+	b := new(bytes.Buffer)
+	if err := vPerms.WriteTo(b); err != nil {
+		return mojom.Perms{}, err
+	}
+	return mojom.Perms{Json: b.String()}, nil
+}
+
+////////////////////////////////////////
+// Stub getters
+
+func (m *mojoImpl) lookupAndAuthorize(ctx *context.T, call rpc.ServerCall, suffix string) (interface{}, error) {
+	resInt, auth, err := m.disp.Lookup(ctx, suffix)
+	if err != nil {
+		return nil, err
+	}
+	if err := auth.Authorize(ctx, call.Security()); err != nil {
+		return nil, verror.New(verror.ErrNoAccess, ctx, err)
+	}
+	return resInt, nil
+}
+
+func (m *mojoImpl) getService(ctx *context.T, call rpc.ServerCall) (wire.ServiceServerStubMethods, error) {
+	resInt, err := m.lookupAndAuthorize(ctx, call, "")
+	if err != nil {
+		return nil, err
+	}
+	if res, ok := resInt.(wire.ServiceServerStubMethods); !ok {
+		return nil, verror.NewErrInternal(ctx)
+	} else {
+		return res, nil
+	}
+}
+
+func (m *mojoImpl) getApp(ctx *context.T, call rpc.ServerCall, name string) (wire.AppServerStubMethods, error) {
+	resInt, err := m.lookupAndAuthorize(ctx, call, name)
+	if err != nil {
+		return nil, err
+	}
+	if res, ok := resInt.(wire.AppServerStubMethods); !ok {
+		return nil, verror.NewErrInternal(ctx)
+	} else {
+		return res, nil
+	}
+}
+
+func (m *mojoImpl) getDb(ctx *context.T, call rpc.ServerCall, name string) (nosqlwire.DatabaseServerStubMethods, error) {
+	resInt, err := m.lookupAndAuthorize(ctx, call, name)
+	if err != nil {
+		return nil, err
+	}
+	if res, ok := resInt.(nosqlwire.DatabaseServerStubMethods); !ok {
+		return nil, verror.NewErrInternal(ctx)
+	} else {
+		return res, nil
+	}
+}
+
+func (m *mojoImpl) getTable(ctx *context.T, call rpc.ServerCall, name string) (nosqlwire.TableServerStubMethods, error) {
+	resInt, err := m.lookupAndAuthorize(ctx, call, name)
+	if err != nil {
+		return nil, err
+	}
+	if res, ok := resInt.(nosqlwire.TableServerStubMethods); !ok {
+		return nil, verror.NewErrInternal(ctx)
+	} else {
+		return res, nil
+	}
+}
+
+func (m *mojoImpl) getRow(ctx *context.T, call rpc.ServerCall, name string) (nosqlwire.RowServerStubMethods, error) {
+	resInt, err := m.lookupAndAuthorize(ctx, call, name)
+	if err != nil {
+		return nil, err
+	}
+	if res, ok := resInt.(nosqlwire.RowServerStubMethods); !ok {
+		return nil, verror.NewErrInternal(ctx)
+	} else {
+		return res, nil
+	}
+}
 
 ////////////////////////////////////////
 // Service
 
-func (m *mojoImpl) ServiceGetPermissions() (wire.Error, wire.Perms, string, error) {
-	return wire.Error{}, wire.Perms{}, "", nil
+// TODO(sadovsky): All stub implementations return a nil error (the last return
+// value), since that error doesn't make it back to the IPC client. Chat with
+// rogulenko@ about whether we should change the Go Mojo stub generator to drop
+// these errors.
+func (m *mojoImpl) ServiceGetPermissions() (mojom.Error, mojom.Perms, string, error) {
+	ctx, call := m.newCtxCall("", methodDesc(permissions.ObjectDesc, "GetPermissions"))
+	stub, err := m.getService(ctx, call)
+	if err != nil {
+		return toMojoError(err), mojom.Perms{}, "", nil
+	}
+	vPerms, version, err := stub.GetPermissions(ctx, call)
+	if err != nil {
+		return toMojoError(err), mojom.Perms{}, "", nil
+	}
+	mPerms, err := toMojoPerms(vPerms)
+	if err != nil {
+		return toMojoError(err), mojom.Perms{}, "", nil
+	}
+	return toMojoError(err), mPerms, version, nil
 }
 
-func (m *mojoImpl) ServiceSetPermissions(perms wire.Perms, version string) (wire.Error, error) {
-	return wire.Error{}, nil
+func (m *mojoImpl) ServiceSetPermissions(mPerms mojom.Perms, version string) (mojom.Error, error) {
+	ctx, call := m.newCtxCall("", methodDesc(permissions.ObjectDesc, "SetPermissions"))
+	stub, err := m.getService(ctx, call)
+	if err != nil {
+		return toMojoError(err), nil
+	}
+	vPerms, err := toV23Perms(mPerms)
+	if err != nil {
+		return toMojoError(err), nil
+	}
+	err = stub.SetPermissions(ctx, call, vPerms, version)
+	return toMojoError(err), nil
 }
 
 ////////////////////////////////////////
 // App
 
-func (m *mojoImpl) AppCreate(name string, perms wire.Perms) (wire.Error, error) {
-	return wire.Error{}, nil
+func (m *mojoImpl) AppCreate(name string, mPerms mojom.Perms) (mojom.Error, error) {
+	ctx, call := m.newCtxCall(name, methodDesc(wire.AppDesc, "Create"))
+	stub, err := m.getApp(ctx, call, name)
+	if err != nil {
+		return toMojoError(err), nil
+	}
+	vPerms, err := toV23Perms(mPerms)
+	if err != nil {
+		return toMojoError(err), nil
+	}
+	err = stub.Create(ctx, call, vPerms)
+	return toMojoError(err), nil
 }
 
-func (m *mojoImpl) AppDelete(name string) (wire.Error, error) {
-	return wire.Error{}, nil
+func (m *mojoImpl) AppDelete(name string) (mojom.Error, error) {
+	ctx, call := m.newCtxCall(name, methodDesc(wire.AppDesc, "Delete"))
+	stub, err := m.getApp(ctx, call, name)
+	if err != nil {
+		return toMojoError(err), nil
+	}
+	err = stub.Delete(ctx, call)
+	return toMojoError(err), nil
 }
 
-func (m *mojoImpl) AppExists(name string) (wire.Error, bool, error) {
-	return wire.Error{}, false, nil
+func (m *mojoImpl) AppExists(name string) (mojom.Error, bool, error) {
+	ctx, call := m.newCtxCall(name, methodDesc(wire.AppDesc, "Exists"))
+	stub, err := m.getApp(ctx, call, name)
+	if err != nil {
+		return toMojoError(err), false, nil
+	}
+	exists, err := stub.Exists(ctx, call)
+	return toMojoError(err), exists, nil
 }
 
-func (m *mojoImpl) AppGetPermissions(name string) (wire.Error, wire.Perms, string, error) {
-	return wire.Error{}, wire.Perms{}, "", nil
+func (m *mojoImpl) AppGetPermissions(name string) (mojom.Error, mojom.Perms, string, error) {
+	ctx, call := m.newCtxCall(name, methodDesc(permissions.ObjectDesc, "GetPermissions"))
+	stub, err := m.getApp(ctx, call, name)
+	if err != nil {
+		return toMojoError(err), mojom.Perms{}, "", nil
+	}
+	vPerms, version, err := stub.GetPermissions(ctx, call)
+	if err != nil {
+		return toMojoError(err), mojom.Perms{}, "", nil
+	}
+	mPerms, err := toMojoPerms(vPerms)
+	if err != nil {
+		return toMojoError(err), mojom.Perms{}, "", nil
+	}
+	return toMojoError(err), mPerms, version, nil
 }
 
-func (m *mojoImpl) AppSetPermissions(name string, perms wire.Perms, version string) (wire.Error, error) {
-	return wire.Error{}, nil
+func (m *mojoImpl) AppSetPermissions(name string, mPerms mojom.Perms, version string) (mojom.Error, error) {
+	ctx, call := m.newCtxCall(name, methodDesc(permissions.ObjectDesc, "SetPermissions"))
+	stub, err := m.getApp(ctx, call, name)
+	if err != nil {
+		return toMojoError(err), nil
+	}
+	vPerms, err := toV23Perms(mPerms)
+	if err != nil {
+		return toMojoError(err), nil
+	}
+	err = stub.SetPermissions(ctx, call, vPerms, version)
+	return toMojoError(err), nil
 }
 
 ////////////////////////////////////////
 // nosql.Database
 
-func (m *mojoImpl) DbCreate(name string, perms wire.Perms) (wire.Error, error) {
-	return wire.Error{}, nil
+func (m *mojoImpl) DbCreate(name string, mPerms mojom.Perms) (mojom.Error, error) {
+	ctx, call := m.newCtxCall(name, methodDesc(nosqlwire.DatabaseDesc, "Create"))
+	stub, err := m.getDb(ctx, call, name)
+	if err != nil {
+		return toMojoError(err), nil
+	}
+	vPerms, err := toV23Perms(mPerms)
+	if err != nil {
+		return toMojoError(err), nil
+	}
+	err = stub.Create(ctx, call, nil, vPerms)
+	return toMojoError(err), nil
 }
 
-func (m *mojoImpl) DbDelete(name string) (wire.Error, error) {
-	return wire.Error{}, nil
+func (m *mojoImpl) DbDelete(name string) (mojom.Error, error) {
+	ctx, call := m.newCtxCall(name, methodDesc(nosqlwire.DatabaseDesc, "Delete"))
+	stub, err := m.getDb(ctx, call, name)
+	if err != nil {
+		return toMojoError(err), nil
+	}
+	err = stub.Delete(ctx, call, NoSchema)
+	return toMojoError(err), nil
 }
 
-func (m *mojoImpl) DbExists(name string) (wire.Error, bool, error) {
-	return wire.Error{}, false, nil
+func (m *mojoImpl) DbExists(name string) (mojom.Error, bool, error) {
+	ctx, call := m.newCtxCall(name, methodDesc(nosqlwire.DatabaseDesc, "Exists"))
+	stub, err := m.getDb(ctx, call, name)
+	if err != nil {
+		return toMojoError(err), false, nil
+	}
+	exists, err := stub.Exists(ctx, call, NoSchema)
+	return toMojoError(err), exists, nil
 }
 
-func (m *mojoImpl) DbExec(name string, query string, stream wire.ExecStream_Request) (wire.Error, error) {
-	return wire.Error{}, nil
+func (m *mojoImpl) DbExec(name string, query string, stream mojom.ExecStream_Request) (mojom.Error, error) {
+	return mojom.Error{}, nil
 }
 
-func (m *mojoImpl) DbBeginBatch(name string, bo *wire.BatchOptions) (wire.Error, string, error) {
-	return wire.Error{}, "", nil
+func (m *mojoImpl) DbBeginBatch(name string, bo *mojom.BatchOptions) (mojom.Error, string, error) {
+	return mojom.Error{}, "", nil
 }
 
-func (m *mojoImpl) DbCommit(name string) (wire.Error, error) {
-	return wire.Error{}, nil
+func (m *mojoImpl) DbCommit(name string) (mojom.Error, error) {
+	return mojom.Error{}, nil
 }
 
-func (m *mojoImpl) DbAbort(name string) (wire.Error, error) {
-	return wire.Error{}, nil
+func (m *mojoImpl) DbAbort(name string) (mojom.Error, error) {
+	return mojom.Error{}, nil
 }
 
-func (m *mojoImpl) DbGetPermissions(name string) (wire.Error, wire.Perms, string, error) {
-	return wire.Error{}, wire.Perms{}, "", nil
+func (m *mojoImpl) DbGetPermissions(name string) (mojom.Error, mojom.Perms, string, error) {
+	ctx, call := m.newCtxCall(name, methodDesc(permissions.ObjectDesc, "GetPermissions"))
+	stub, err := m.getDb(ctx, call, name)
+	if err != nil {
+		return toMojoError(err), mojom.Perms{}, "", nil
+	}
+	vPerms, version, err := stub.GetPermissions(ctx, call)
+	if err != nil {
+		return toMojoError(err), mojom.Perms{}, "", nil
+	}
+	mPerms, err := toMojoPerms(vPerms)
+	if err != nil {
+		return toMojoError(err), mojom.Perms{}, "", nil
+	}
+	return toMojoError(err), mPerms, version, nil
 }
 
-func (m *mojoImpl) DbSetPermissions(name string, perms wire.Perms, version string) (wire.Error, error) {
-	return wire.Error{}, nil
+func (m *mojoImpl) DbSetPermissions(name string, mPerms mojom.Perms, version string) (mojom.Error, error) {
+	ctx, call := m.newCtxCall(name, methodDesc(permissions.ObjectDesc, "SetPermissions"))
+	stub, err := m.getDb(ctx, call, name)
+	if err != nil {
+		return toMojoError(err), nil
+	}
+	vPerms, err := toV23Perms(mPerms)
+	if err != nil {
+		return toMojoError(err), nil
+	}
+	err = stub.SetPermissions(ctx, call, vPerms, version)
+	return toMojoError(err), nil
 }
 
 ////////////////////////////////////////
 // nosql.Database:SyncGroupManager
 
-func (m *mojoImpl) DbGetSyncGroupNames(name string) (wire.Error, []string, error) {
-	return wire.Error{}, nil, nil
+func (m *mojoImpl) DbGetSyncGroupNames(name string) (mojom.Error, []string, error) {
+	return mojom.Error{}, nil, nil
 }
 
-func (m *mojoImpl) DbCreateSyncGroup(name, sgName string, spec wire.SyncGroupSpec, myInfo wire.SyncGroupMemberInfo) (wire.Error, error) {
-	return wire.Error{}, nil
+func (m *mojoImpl) DbCreateSyncGroup(name, sgName string, spec mojom.SyncGroupSpec, myInfo mojom.SyncGroupMemberInfo) (mojom.Error, error) {
+	return mojom.Error{}, nil
 }
 
-func (m *mojoImpl) DbJoinSyncGroup(name, sgName string, myInfo wire.SyncGroupMemberInfo) (wire.Error, error) {
-	return wire.Error{}, nil
+func (m *mojoImpl) DbJoinSyncGroup(name, sgName string, myInfo mojom.SyncGroupMemberInfo) (mojom.Error, error) {
+	return mojom.Error{}, nil
 }
 
-func (m *mojoImpl) DbLeaveSyncGroup(name, sgName string) (wire.Error, error) {
-	return wire.Error{}, nil
+func (m *mojoImpl) DbLeaveSyncGroup(name, sgName string) (mojom.Error, error) {
+	return mojom.Error{}, nil
 }
 
-func (m *mojoImpl) DbDestroySyncGroup(name, sgName string) (wire.Error, error) {
-	return wire.Error{}, nil
+func (m *mojoImpl) DbDestroySyncGroup(name, sgName string) (mojom.Error, error) {
+	return mojom.Error{}, nil
 }
 
-func (m *mojoImpl) DbEjectFromSyncGroup(name, sgName string, member string) (wire.Error, error) {
-	return wire.Error{}, nil
+func (m *mojoImpl) DbEjectFromSyncGroup(name, sgName string, member string) (mojom.Error, error) {
+	return mojom.Error{}, nil
 }
 
-func (m *mojoImpl) DbGetSyncGroupSpec(name, sgName string) (wire.Error, wire.SyncGroupSpec, string, error) {
-	return wire.Error{}, wire.SyncGroupSpec{}, "", nil
+func (m *mojoImpl) DbGetSyncGroupSpec(name, sgName string) (mojom.Error, mojom.SyncGroupSpec, string, error) {
+	return mojom.Error{}, mojom.SyncGroupSpec{}, "", nil
 }
 
-func (m *mojoImpl) DbSetSyncGroupSpec(name, sgName string, spec wire.SyncGroupSpec, version string) (wire.Error, error) {
-	return wire.Error{}, nil
+func (m *mojoImpl) DbSetSyncGroupSpec(name, sgName string, spec mojom.SyncGroupSpec, version string) (mojom.Error, error) {
+	return mojom.Error{}, nil
 }
 
-func (m *mojoImpl) DbGetSyncGroupMembers(name, sgName string) (wire.Error, map[string]wire.SyncGroupMemberInfo, error) {
-	return wire.Error{}, nil, nil
+func (m *mojoImpl) DbGetSyncGroupMembers(name, sgName string) (mojom.Error, map[string]mojom.SyncGroupMemberInfo, error) {
+	return mojom.Error{}, nil, nil
 }
 
 ////////////////////////////////////////
 // nosql.Table
 
-func (m *mojoImpl) TableCreate(name string, perms wire.Perms) (wire.Error, error) {
-	return wire.Error{}, nil
+func (m *mojoImpl) TableCreate(name string, mPerms mojom.Perms) (mojom.Error, error) {
+	ctx, call := m.newCtxCall(name, methodDesc(nosqlwire.TableDesc, "Create"))
+	stub, err := m.getTable(ctx, call, name)
+	if err != nil {
+		return toMojoError(err), nil
+	}
+	vPerms, err := toV23Perms(mPerms)
+	if err != nil {
+		return toMojoError(err), nil
+	}
+	err = stub.Create(ctx, call, NoSchema, vPerms)
+	return toMojoError(err), nil
 }
 
-func (m *mojoImpl) TableDelete(name string) (wire.Error, error) {
-	return wire.Error{}, nil
+func (m *mojoImpl) TableDelete(name string) (mojom.Error, error) {
+	ctx, call := m.newCtxCall(name, methodDesc(nosqlwire.TableDesc, "Delete"))
+	stub, err := m.getTable(ctx, call, name)
+	if err != nil {
+		return toMojoError(err), nil
+	}
+	err = stub.Delete(ctx, call, NoSchema)
+	return toMojoError(err), nil
 }
 
-func (m *mojoImpl) TableExists(name string) (wire.Error, bool, error) {
-	return wire.Error{}, false, nil
+func (m *mojoImpl) TableExists(name string) (mojom.Error, bool, error) {
+	ctx, call := m.newCtxCall(name, methodDesc(nosqlwire.TableDesc, "Exists"))
+	stub, err := m.getTable(ctx, call, name)
+	if err != nil {
+		return toMojoError(err), false, nil
+	}
+	exists, err := stub.Exists(ctx, call, NoSchema)
+	return toMojoError(err), exists, nil
 }
 
-func (m *mojoImpl) TableDeleteRowRange(name string, start, limit []byte) (wire.Error, error) {
-	return wire.Error{}, nil
+func (m *mojoImpl) TableDeleteRowRange(name string, start, limit []byte) (mojom.Error, error) {
+	return mojom.Error{}, nil
 }
 
-func (m *mojoImpl) TableScan(name string, start, limit []byte, stream wire.ScanStream_Request) (wire.Error, error) {
-	return wire.Error{}, nil
+func (m *mojoImpl) TableScan(name string, start, limit []byte, stream mojom.ScanStream_Request) (mojom.Error, error) {
+	return mojom.Error{}, nil
 }
 
-func (m *mojoImpl) TableGetPermissions(name, key string) (wire.Error, []wire.PrefixPerms, error) {
-	return wire.Error{}, nil, nil
+func (m *mojoImpl) TableGetPermissions(name, key string) (mojom.Error, []mojom.PrefixPerms, error) {
+	return mojom.Error{}, nil, nil
 }
 
-func (m *mojoImpl) TableSetPermissions(name, prefix string, perms wire.Perms) (wire.Error, error) {
-	return wire.Error{}, nil
+func (m *mojoImpl) TableSetPermissions(name, prefix string, mPerms mojom.Perms) (mojom.Error, error) {
+	return mojom.Error{}, nil
 }
 
-func (m *mojoImpl) TableDeletePermissions(name, prefix string) (wire.Error, error) {
-	return wire.Error{}, nil
+func (m *mojoImpl) TableDeletePermissions(name, prefix string) (mojom.Error, error) {
+	return mojom.Error{}, nil
 }
 
 ////////////////////////////////////////
 // nosql.Row
 
-func (m *mojoImpl) RowExists(name string) (wire.Error, bool, error) {
-	return wire.Error{}, false, nil
+func (m *mojoImpl) RowExists(name string) (mojom.Error, bool, error) {
+	ctx, call := m.newCtxCall(name, methodDesc(nosqlwire.RowDesc, "Exists"))
+	stub, err := m.getRow(ctx, call, name)
+	if err != nil {
+		return toMojoError(err), false, nil
+	}
+	exists, err := stub.Exists(ctx, call, NoSchema)
+	return toMojoError(err), exists, nil
 }
 
-func (m *mojoImpl) RowGet(name string) (wire.Error, []byte, error) {
-	return wire.Error{}, nil, nil
+func (m *mojoImpl) RowGet(name string) (mojom.Error, []byte, error) {
+	ctx, call := m.newCtxCall(name, methodDesc(nosqlwire.RowDesc, "Get"))
+	stub, err := m.getRow(ctx, call, name)
+	if err != nil {
+		return toMojoError(err), nil, nil
+	}
+	value, err := stub.Get(ctx, call, NoSchema)
+	return toMojoError(err), value, nil
 }
 
-func (m *mojoImpl) RowPut(name string, value []byte) (wire.Error, error) {
-	return wire.Error{}, nil
+func (m *mojoImpl) RowPut(name string, value []byte) (mojom.Error, error) {
+	ctx, call := m.newCtxCall(name, methodDesc(nosqlwire.RowDesc, "Put"))
+	stub, err := m.getRow(ctx, call, name)
+	if err != nil {
+		return toMojoError(err), nil
+	}
+	err = stub.Put(ctx, call, NoSchema, value)
+	return toMojoError(err), nil
 }
 
-func (m *mojoImpl) RowDelete(name string) (wire.Error, error) {
-	return wire.Error{}, nil
+func (m *mojoImpl) RowDelete(name string) (mojom.Error, error) {
+	ctx, call := m.newCtxCall(name, methodDesc(nosqlwire.RowDesc, "Delete"))
+	stub, err := m.getRow(ctx, call, name)
+	if err != nil {
+		return toMojoError(err), nil
+	}
+	err = stub.Delete(ctx, call, NoSchema)
+	return toMojoError(err), nil
 }
diff --git a/x/ref/services/syncbase/syncbased/main.go b/x/ref/services/syncbase/syncbased/main.go
index 7fc1e6d..8def540 100644
--- a/x/ref/services/syncbase/syncbased/main.go
+++ b/x/ref/services/syncbase/syncbased/main.go
@@ -10,6 +10,7 @@
 	"v.io/syncbase/x/ref/services/syncbase/server"
 	"v.io/v23"
 	"v.io/v23/context"
+	"v.io/v23/rpc"
 	"v.io/v23/security"
 	"v.io/v23/security/access"
 	"v.io/x/lib/vlog"
@@ -35,10 +36,9 @@
 	return perms
 }
 
-// TODO(sadovsky): We return interface{} as a quick hack to support Mojo. The
-// actual return value is of type *server.service, which we don't want to
-// export.
-func Serve(ctx *context.T) interface{} {
+// TODO(sadovsky): We return rpc.Server and rpc.Dispatcher as a quick hack to
+// support Mojo.
+func Serve(ctx *context.T) (rpc.Server, rpc.Dispatcher) {
 	s, err := v23.NewServer(ctx)
 	if err != nil {
 		vlog.Fatal("v23.NewServer() failed: ", err)
@@ -77,5 +77,5 @@
 		vlog.Info("Mounted at: ", *name)
 	}
 
-	return service
+	return s, d
 }
diff --git a/x/ref/services/syncbase/syncbased/mojo_main.go b/x/ref/services/syncbase/syncbased/mojo_main.go
index 48272bb..b478d4e 100644
--- a/x/ref/services/syncbase/syncbased/mojo_main.go
+++ b/x/ref/services/syncbase/syncbased/mojo_main.go
@@ -21,20 +21,26 @@
 
 	"v.io/syncbase/x/ref/services/syncbase/server"
 	"v.io/v23"
+	"v.io/v23/context"
+	"v.io/v23/rpc"
 )
 
 //#include "mojo/public/c/system/types.h"
 import "C"
 
 type delegate struct {
-	service interface{} // actual type is *server.service
-	stubs   []*bindings.Stub
+	ctx   *context.T
+	srv   rpc.Server
+	disp  rpc.Dispatcher
+	stubs []*bindings.Stub
 }
 
-func (d *delegate) Initialize(ctx application.Context) {}
+func (d *delegate) Initialize(ctx application.Context) {
+	d.srv, d.disp = Serve(d.ctx)
+}
 
 func (d *delegate) Create(req syncbase.Syncbase_Request) {
-	impl := server.NewMojoImpl(d.service)
+	impl := server.NewMojoImpl(d.ctx, d.srv, d.disp)
 	stub := syncbase.NewSyncbaseStub(req, impl, bindings.GetAsyncWaiter())
 	d.stubs = append(d.stubs, stub)
 	go func() {
@@ -64,7 +70,7 @@
 func MojoMain(handle C.MojoHandle) C.MojoResult {
 	ctx, shutdown := v23.Init()
 	defer shutdown()
-	application.Run(&delegate{service: Serve(ctx)}, system.MojoHandle(handle))
+	application.Run(&delegate{ctx: ctx}, system.MojoHandle(handle))
 	return C.MOJO_RESULT_OK
 }