godbus update

pull/16/head
Bruce Leidl 9 years ago
parent 0462cf1f23
commit bd48856a2d

4
Godeps/Godeps.json generated

@ -4,8 +4,8 @@
"Deps": [
{
"ImportPath": "github.com/godbus/dbus",
"Comment": "v3-6-ga1b8ba5",
"Rev": "a1b8ba5163b7f041b22761461eabd02b70d1f824"
"Comment": "v3-15-g230e4b2",
"Rev": "230e4b23db2fd81c53eaa0073f76659d4849ce51"
},
{
"ImportPath": "github.com/op/go-logging",

@ -46,7 +46,7 @@ type Conn struct {
calls map[uint32]*Call
callsLck sync.RWMutex
handlers map[ObjectPath]map[string]exportWithMapping
handlers map[ObjectPath]map[string]exportedObj
handlersLck sync.RWMutex
out chan *Message
@ -157,7 +157,7 @@ func newConn(tr transport) (*Conn, error) {
conn.transport = tr
conn.calls = make(map[uint32]*Call)
conn.out = make(chan *Message, 10)
conn.handlers = make(map[ObjectPath]map[string]exportWithMapping)
conn.handlers = make(map[ObjectPath]map[string]exportedObj)
conn.nextSerial = 1
conn.serialUsed = map[uint32]bool{0: true}
conn.busObj = conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus")
@ -499,9 +499,7 @@ func (conn *Conn) sendReply(dest string, serial uint32, values ...interface{}) {
// The caller has to make sure that ch is sufficiently buffered; if a message
// arrives when a write to c is not possible, it is discarded.
//
// Multiple of these channels can be registered at the same time. Passing a
// channel that already is registered will remove it from the list of the
// registered channels.
// Multiple of these channels can be registered at the same time.
//
// These channels are "overwritten" by Eavesdrop; i.e., if there currently is a
// channel for eavesdropped messages, this channel receives all signals, and
@ -512,6 +510,19 @@ func (conn *Conn) Signal(ch chan<- *Signal) {
conn.signalsLck.Unlock()
}
// RemoveSignal removes the given channel from the list of the registered channels.
func (conn *Conn) RemoveSignal(ch chan<- *Signal) {
conn.signalsLck.Lock()
for i := len(conn.signals) - 1; i >= 0; i-- {
if ch == conn.signals[i] {
copy(conn.signals[i:], conn.signals[i+1:])
conn.signals[len(conn.signals)-1] = nil
conn.signals = conn.signals[:len(conn.signals)-1]
}
}
conn.signalsLck.Unlock()
}
// SupportsUnixFDs returns whether the underlying transport supports passing of
// unix file descriptors. If this is false, method calls containing unix file
// descriptors will return an error and emitted signals containing them will

@ -22,67 +22,60 @@ var (
}
)
// exportWithMapping represents an exported struct along with a method name
// mapping to allow for exporting lower-case methods, etc.
type exportWithMapping struct {
export interface{}
// Method name mapping; key -> struct method, value -> dbus method.
mapping map[string]string
// exportedObj represents an exported object. It stores a precomputed
// method table that represents the methods exported on the bus.
type exportedObj struct {
methods map[string]reflect.Value
// Whether or not this export is for the entire subtree
includeSubtree bool
}
func (obj exportedObj) Method(name string) (reflect.Value, bool) {
out, exists := obj.methods[name]
return out, exists
}
// Sender is a type which can be used in exported methods to receive the message
// sender.
type Sender string
func exportedMethod(export exportWithMapping, name string) reflect.Value {
if export.export == nil {
return reflect.Value{}
}
// If a mapping was included in the export, check the map to see if we
// should be looking for a different method in the export.
if export.mapping != nil {
for key, value := range export.mapping {
if value == name {
name = key
break
}
// Catch the case where a method is aliased but the client is calling
// the original, e.g. the "Foo" method was exported mapped to
// "foo," and dbus client called the original "Foo."
if key == name {
return reflect.Value{}
}
}
func computeMethodName(name string, mapping map[string]string) string {
newname, ok := mapping[name]
if ok {
name = newname
}
return name
}
value := reflect.ValueOf(export.export)
m := value.MethodByName(name)
// Catch the case of attempting to call an unexported method
method, ok := value.Type().MethodByName(name)
if !m.IsValid() || !ok || method.PkgPath != "" {
return reflect.Value{}
func getMethods(in interface{}, mapping map[string]string) map[string]reflect.Value {
if in == nil {
return nil
}
t := m.Type()
if t.NumOut() == 0 ||
t.Out(t.NumOut()-1) != reflect.TypeOf(&errmsgInvalidArg) {
return reflect.Value{}
methods := make(map[string]reflect.Value)
val := reflect.ValueOf(in)
typ := val.Type()
for i := 0; i < typ.NumMethod(); i++ {
methtype := typ.Method(i)
method := val.Method(i)
t := method.Type()
// only track valid methods must return *Error as last arg
// and must be exported
if t.NumOut() == 0 ||
t.Out(t.NumOut()-1) != reflect.TypeOf(&errmsgInvalidArg) ||
methtype.PkgPath != "" {
continue
}
// map names while building table
methods[computeMethodName(methtype.Name, mapping)] = method
}
return m
return methods
}
// searchHandlers will look through all registered handlers looking for one
// to handle the given path. If a verbatim one isn't found, it will check for
// a subtree registration for the path as well.
func (conn *Conn) searchHandlers(path ObjectPath) (map[string]exportWithMapping, bool) {
func (conn *Conn) searchHandlers(path ObjectPath) (map[string]exportedObj, bool) {
conn.handlersLck.RLock()
defer conn.handlersLck.RUnlock()
@ -93,10 +86,10 @@ func (conn *Conn) searchHandlers(path ObjectPath) (map[string]exportWithMapping,
// If handlers weren't found for this exact path, look for a matching subtree
// registration
handlers = make(map[string]exportWithMapping)
handlers = make(map[string]exportedObj)
path = path[:strings.LastIndex(string(path), "/")]
for len(path) > 0 {
var subtreeHandlers map[string]exportWithMapping
var subtreeHandlers map[string]exportedObj
subtreeHandlers, ok = conn.handlers[path]
if ok {
for iface, handler := range subtreeHandlers {
@ -146,19 +139,20 @@ func (conn *Conn) handleCall(msg *Message) {
}
var m reflect.Value
var exists bool
if hasIface {
iface := handlers[ifaceName]
m = exportedMethod(iface, name)
m, exists = iface.Method(name)
} else {
for _, v := range handlers {
m = exportedMethod(v, name)
if m.IsValid() {
m, exists = v.Method(name)
if exists {
break
}
}
}
if !m.IsValid() {
if !exists {
conn.sendError(errmsgUnknownMethod, sender, serial)
return
}
@ -303,7 +297,7 @@ func (conn *Conn) Export(v interface{}, path ObjectPath, iface string) error {
// The keys in the map are the real method names (exported on the struct), and
// the values are the method names to be exported on DBus.
func (conn *Conn) ExportWithMap(v interface{}, mapping map[string]string, path ObjectPath, iface string) error {
return conn.exportWithMap(v, mapping, path, iface, false)
return conn.export(getMethods(v, mapping), path, iface, false)
}
// ExportSubtree works exactly like Export but registers the given value for
@ -326,11 +320,48 @@ func (conn *Conn) ExportSubtree(v interface{}, path ObjectPath, iface string) er
// The keys in the map are the real method names (exported on the struct), and
// the values are the method names to be exported on DBus.
func (conn *Conn) ExportSubtreeWithMap(v interface{}, mapping map[string]string, path ObjectPath, iface string) error {
return conn.exportWithMap(v, mapping, path, iface, true)
return conn.export(getMethods(v, mapping), path, iface, true)
}
// ExportMethodTable like Export registers the given methods as an object
// on the message bus. Unlike Export the it uses a method table to define
// the object instead of a native go object.
//
// The method table is a map from method name to function closure
// representing the method. This allows an object exported on the bus to not
// necessarily be a native go object. It can be useful for generating exposed
// methods on the fly.
//
// Any non-function objects in the method table are ignored.
func (conn *Conn) ExportMethodTable(methods map[string]interface{}, path ObjectPath, iface string) error {
return conn.exportMethodTable(methods, path, iface, false)
}
// Like ExportSubtree, but with the same caveats as ExportMethodTable.
func (conn *Conn) ExportSubtreeMethodTable(methods map[string]interface{}, path ObjectPath, iface string) error {
return conn.exportMethodTable(methods, path, iface, true)
}
func (conn *Conn) exportMethodTable(methods map[string]interface{}, path ObjectPath, iface string, includeSubtree bool) error {
out := make(map[string]reflect.Value)
for name, method := range methods {
rval := reflect.ValueOf(method)
if rval.Kind() != reflect.Func {
continue
}
t := rval.Type()
// only track valid methods must return *Error as last arg
if t.NumOut() == 0 ||
t.Out(t.NumOut()-1) != reflect.TypeOf(&errmsgInvalidArg) {
continue
}
out[name] = rval
}
return conn.export(out, path, iface, includeSubtree)
}
// exportWithMap is the worker function for all exports/registrations.
func (conn *Conn) exportWithMap(v interface{}, mapping map[string]string, path ObjectPath, iface string, includeSubtree bool) error {
func (conn *Conn) export(methods map[string]reflect.Value, path ObjectPath, iface string, includeSubtree bool) error {
if !path.IsValid() {
return fmt.Errorf(`dbus: Invalid path name: "%s"`, path)
}
@ -339,7 +370,7 @@ func (conn *Conn) exportWithMap(v interface{}, mapping map[string]string, path O
defer conn.handlersLck.Unlock()
// Remove a previous export if the interface is nil
if v == nil {
if methods == nil {
if _, ok := conn.handlers[path]; ok {
delete(conn.handlers[path], iface)
if len(conn.handlers[path]) == 0 {
@ -353,11 +384,14 @@ func (conn *Conn) exportWithMap(v interface{}, mapping map[string]string, path O
// If this is the first handler for this path, make a new map to hold all
// handlers for this path.
if _, ok := conn.handlers[path]; !ok {
conn.handlers[path] = make(map[string]exportWithMapping)
conn.handlers[path] = make(map[string]exportedObj)
}
// Finally, save this handler
conn.handlers[path][iface] = exportWithMapping{export: v, mapping: mapping, includeSubtree: includeSubtree}
conn.handlers[path][iface] = exportedObj{
methods: methods,
includeSubtree: includeSubtree,
}
return nil
}

@ -1,4 +1,4 @@
//+build !windows
//+build !windows,!solaris
package dbus

Loading…
Cancel
Save