blob: a73486e359274a262433bee2e025a3598dcd6105 [file] [log] [blame]
// Package toplevelglob implements a Glob invoker that recurses into other
// invokers.
package toplevelglob
import (
"veyron.io/veyron/veyron/lib/glob"
"veyron.io/veyron/veyron2/ipc"
"veyron.io/veyron/veyron2/naming"
"veyron.io/veyron/veyron2/services/mounttable/types"
"veyron.io/veyron/veyron2/verror"
)
type invoker struct {
d ipc.Dispatcher
leaves []string
}
// New returns a new top-level Glob invoker. The invoker implements a Glob
// method that will match the given leaves, and recurse into leaf invokers
// on the given dispatcher.
func New(d ipc.Dispatcher, leaves []string) ipc.Invoker {
return ipc.ReflectInvoker(&invoker{d, leaves})
}
func (i *invoker) Glob(call ipc.ServerCall, pattern string) error {
g, err := glob.Parse(pattern)
if err != nil {
return err
}
if g.Len() == 0 {
call.Send(types.MountEntry{Name: ""})
}
for _, leaf := range i.leaves {
if ok, _, left := g.MatchInitialSegment(leaf); ok {
if err := i.leafGlob(call, leaf, left.String()); err != nil {
return err
}
}
}
return nil
}
func (i *invoker) leafGlob(call ipc.ServerCall, leaf string, pattern string) error {
obj, _, err := i.d.Lookup(leaf, "Glob")
if err != nil {
return err
}
// Lookup must return an invoker if it implements its own glob
invoker, ok := obj.(ipc.Invoker)
if !ok {
return nil
}
if invoker == nil {
return verror.BadArgf("failed to find invoker for %q", leaf)
}
argptrs := []interface{}{&pattern}
leafCall := &localServerCall{call, leaf}
results, err := invoker.Invoke("Glob", leafCall, argptrs)
if err != nil {
return err
}
if len(results) != 1 {
return verror.BadArgf("unexpected number of results. Got %d, want 1", len(results))
}
res := results[0]
if res == nil {
return nil
}
err, ok = res.(error)
if !ok {
return verror.BadArgf("unexpected result type. Got %T, want error", res)
}
return err
}
// An ipc.ServerCall implementation used to Invoke methods on the invokers
// directly. Everything is the same as the original ServerCall, except the
// Stream implementation.
type localServerCall struct {
ipc.ServerCall
name string
}
// Re-Implement ipc.Stream
func (c *localServerCall) Recv(v interface{}) error {
panic("Recv not implemented")
return nil
}
func (c *localServerCall) Send(v interface{}) error {
me, ok := v.(types.MountEntry)
if !ok {
return verror.BadArgf("unexpected stream type. Got %T, want MountEntry", v)
}
me.Name = naming.Join(c.name, me.Name)
return c.ServerCall.Send(me)
}