blob: 4b51a008ca12aff70677e00576a7f2009c379481 [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 (
"strings"
wire "v.io/syncbase/v23/services/syncbase"
pubutil "v.io/syncbase/v23/syncbase/util"
"v.io/syncbase/x/ref/services/syncbase/server/interfaces"
"v.io/syncbase/x/ref/services/syncbase/server/nosql"
"v.io/syncbase/x/ref/services/syncbase/server/util"
"v.io/v23/context"
"v.io/v23/rpc"
"v.io/v23/security"
"v.io/v23/verror"
)
type dispatcher struct {
s *service
}
var _ rpc.Dispatcher = (*dispatcher)(nil)
func NewDispatcher(s *service) *dispatcher {
return &dispatcher{s: s}
}
// We always return an AllowEveryone authorizer from Lookup(), and rely on our
// RPC method implementations to perform proper authorization.
var auth security.Authorizer = security.AllowEveryone()
func (disp *dispatcher) Lookup(ctx *context.T, suffix string) (interface{}, security.Authorizer, error) {
suffix = strings.TrimPrefix(suffix, "/")
parts := strings.SplitN(suffix, "/", 2)
if len(suffix) == 0 {
return wire.ServiceServer(disp.s), auth, nil
}
if parts[0] == util.SyncbaseSuffix {
return interfaces.SyncServer(disp.s.sync), auth, nil
}
// Validate all key atoms up front, so that we can avoid doing so in all our
// method implementations.
appName := parts[0]
if !pubutil.ValidName(appName) {
return nil, nil, wire.NewErrInvalidName(nil, suffix)
}
aExists := false
var a *app
if aInt, err := disp.s.App(nil, nil, appName); err == nil {
a = aInt.(*app) // panics on failure, as desired
aExists = true
} else {
if verror.ErrorID(err) != verror.ErrNoExist.ID {
return nil, nil, err
} else {
a = &app{
name: appName,
s: disp.s,
}
}
}
if len(parts) == 1 {
return wire.AppServer(a), auth, nil
}
// All database, table, and row methods require the app to exist. If it
// doesn't, abort early.
if !aExists {
return nil, nil, verror.New(verror.ErrNoExist, nil, a.name)
}
// Note, it's possible for the app to be deleted concurrently with downstream
// handling of this request. Depending on the order in which things execute,
// the client may not get an error, but in any case ultimately the store will
// end up in a consistent state.
return nosql.NewDispatcher(a).Lookup(ctx, parts[1])
}