blob: ad3d92bcc0bd53aacb236f8dd2730b3d05b4cd0e [file] [log] [blame]
package impl
import (
"fmt"
"strings"
inode "veyron/services/mgmt/node"
"veyron/services/mgmt/node/config"
"veyron2/ipc"
"veyron2/security"
"veyron2/services/mgmt/node"
"veyron2/verror"
)
// internalState wraps state shared between different node manager
// invocations.
type internalState struct {
callback *callbackState
updating *updatingState
}
// dispatcher holds the state of the node manager dispatcher.
type dispatcher struct {
auth security.Authorizer
// internal holds the state that persists across RPC method invocations.
internal *internalState
// config holds the node manager's (immutable) configuration state.
config *config.State
}
const (
appsSuffix = "apps"
nodeSuffix = "nm"
configSuffix = "cfg"
)
var (
errInvalidSuffix = verror.BadArgf("invalid suffix")
errOperationFailed = verror.Internalf("operation failed")
errInProgress = verror.Existsf("operation in progress")
errIncompatibleUpdate = verror.BadArgf("update failed: mismatching app title")
errUpdateNoOp = verror.NotFoundf("no different version available")
errNotExist = verror.NotFoundf("object does not exist")
errInvalidOperation = verror.BadArgf("invalid operation")
)
// NewDispatcher is the node manager dispatcher factory.
func NewDispatcher(auth security.Authorizer, config *config.State) (*dispatcher, error) {
if err := config.Validate(); err != nil {
return nil, fmt.Errorf("Invalid config %v: %v", config, err)
}
return &dispatcher{
auth: auth,
internal: &internalState{
callback: newCallbackState(),
updating: newUpdatingState(),
},
config: config,
}, nil
}
// DISPATCHER INTERFACE IMPLEMENTATION
func (d *dispatcher) Lookup(suffix, method string) (ipc.Invoker, security.Authorizer, error) {
components := strings.Split(suffix, "/")
for i := 0; i < len(components); i++ {
if len(components[i]) == 0 {
components = append(components[:i], components[i+1:]...)
i--
}
}
if len(components) == 0 {
return nil, nil, errInvalidSuffix
}
// The implementation of the node manager is split up into several
// invokers, which are instantiated depending on the receiver name
// prefix.
var receiver interface{}
switch components[0] {
case nodeSuffix:
receiver = node.NewServerNode(&nodeInvoker{
callback: d.internal.callback,
updating: d.internal.updating,
config: d.config,
})
case appsSuffix:
receiver = node.NewServerApplication(&appInvoker{
callback: d.internal.callback,
config: d.config,
suffix: components[1:],
})
case configSuffix:
if len(components) != 2 {
return nil, nil, errInvalidSuffix
}
receiver = inode.NewServerConfig(&configInvoker{
callback: d.internal.callback,
suffix: components[1],
})
default:
return nil, nil, errInvalidSuffix
}
return ipc.ReflectInvoker(receiver), d.auth, nil
}