godbus update

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

4
Godeps/Godeps.json generated

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

@ -46,7 +46,7 @@ type Conn struct {
calls map[uint32]*Call calls map[uint32]*Call
callsLck sync.RWMutex callsLck sync.RWMutex
handlers map[ObjectPath]map[string]exportWithMapping handlers map[ObjectPath]map[string]exportedObj
handlersLck sync.RWMutex handlersLck sync.RWMutex
out chan *Message out chan *Message
@ -157,7 +157,7 @@ func newConn(tr transport) (*Conn, error) {
conn.transport = tr conn.transport = tr
conn.calls = make(map[uint32]*Call) conn.calls = make(map[uint32]*Call)
conn.out = make(chan *Message, 10) 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.nextSerial = 1
conn.serialUsed = map[uint32]bool{0: true} conn.serialUsed = map[uint32]bool{0: true}
conn.busObj = conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus") 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 // 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. // 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 // Multiple of these channels can be registered at the same time.
// channel that already is registered will remove it from the list of the
// registered channels.
// //
// These channels are "overwritten" by Eavesdrop; i.e., if there currently is a // These channels are "overwritten" by Eavesdrop; i.e., if there currently is a
// channel for eavesdropped messages, this channel receives all signals, and // channel for eavesdropped messages, this channel receives all signals, and
@ -512,6 +510,19 @@ func (conn *Conn) Signal(ch chan<- *Signal) {
conn.signalsLck.Unlock() 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 // SupportsUnixFDs returns whether the underlying transport supports passing of
// unix file descriptors. If this is false, method calls containing unix file // unix file descriptors. If this is false, method calls containing unix file
// descriptors will return an error and emitted signals containing them will // 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 // exportedObj represents an exported object. It stores a precomputed
// mapping to allow for exporting lower-case methods, etc. // method table that represents the methods exported on the bus.
type exportWithMapping struct { type exportedObj struct {
export interface{} methods map[string]reflect.Value
// Method name mapping; key -> struct method, value -> dbus method.
mapping map[string]string
// Whether or not this export is for the entire subtree // Whether or not this export is for the entire subtree
includeSubtree bool 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 is a type which can be used in exported methods to receive the message
// sender. // sender.
type Sender string type Sender string
func exportedMethod(export exportWithMapping, name string) reflect.Value { func computeMethodName(name string, mapping map[string]string) string {
if export.export == nil { newname, ok := mapping[name]
return reflect.Value{} if ok {
} name = newname
// 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{}
}
}
} }
return name
}
value := reflect.ValueOf(export.export) func getMethods(in interface{}, mapping map[string]string) map[string]reflect.Value {
m := value.MethodByName(name) if in == nil {
return nil
// 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{}
} }
t := m.Type() 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 || if t.NumOut() == 0 ||
t.Out(t.NumOut()-1) != reflect.TypeOf(&errmsgInvalidArg) { t.Out(t.NumOut()-1) != reflect.TypeOf(&errmsgInvalidArg) ||
methtype.PkgPath != "" {
return reflect.Value{} 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 // 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 // to handle the given path. If a verbatim one isn't found, it will check for
// a subtree registration for the path as well. // 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() conn.handlersLck.RLock()
defer conn.handlersLck.RUnlock() 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 // If handlers weren't found for this exact path, look for a matching subtree
// registration // registration
handlers = make(map[string]exportWithMapping) handlers = make(map[string]exportedObj)
path = path[:strings.LastIndex(string(path), "/")] path = path[:strings.LastIndex(string(path), "/")]
for len(path) > 0 { for len(path) > 0 {
var subtreeHandlers map[string]exportWithMapping var subtreeHandlers map[string]exportedObj
subtreeHandlers, ok = conn.handlers[path] subtreeHandlers, ok = conn.handlers[path]
if ok { if ok {
for iface, handler := range subtreeHandlers { for iface, handler := range subtreeHandlers {
@ -146,19 +139,20 @@ func (conn *Conn) handleCall(msg *Message) {
} }
var m reflect.Value var m reflect.Value
var exists bool
if hasIface { if hasIface {
iface := handlers[ifaceName] iface := handlers[ifaceName]
m = exportedMethod(iface, name) m, exists = iface.Method(name)
} else { } else {
for _, v := range handlers { for _, v := range handlers {
m = exportedMethod(v, name) m, exists = v.Method(name)
if m.IsValid() { if exists {
break break
} }
} }
} }
if !m.IsValid() { if !exists {
conn.sendError(errmsgUnknownMethod, sender, serial) conn.sendError(errmsgUnknownMethod, sender, serial)
return 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 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. // 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 { 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 // 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 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. // 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 { 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. // 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() { if !path.IsValid() {
return fmt.Errorf(`dbus: Invalid path name: "%s"`, path) 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() defer conn.handlersLck.Unlock()
// Remove a previous export if the interface is nil // Remove a previous export if the interface is nil
if v == nil { if methods == nil {
if _, ok := conn.handlers[path]; ok { if _, ok := conn.handlers[path]; ok {
delete(conn.handlers[path], iface) delete(conn.handlers[path], iface)
if len(conn.handlers[path]) == 0 { 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 // If this is the first handler for this path, make a new map to hold all
// handlers for this path. // handlers for this path.
if _, ok := conn.handlers[path]; !ok { if _, ok := conn.handlers[path]; !ok {
conn.handlers[path] = make(map[string]exportWithMapping) conn.handlers[path] = make(map[string]exportedObj)
} }
// Finally, save this handler // 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 return nil
} }

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

Loading…
Cancel
Save