From bd48856a2dfddf4ed79a7caea364672c74b4b8cd Mon Sep 17 00:00:00 2001 From: Bruce Leidl Date: Wed, 24 Feb 2016 01:45:51 +0000 Subject: [PATCH] godbus update --- Godeps/Godeps.json | 4 +- .../src/github.com/godbus/dbus/conn.go | 21 ++- .../src/github.com/godbus/dbus/export.go | 144 +++++++++++------- .../github.com/godbus/dbus/transport_unix.go | 2 +- 4 files changed, 108 insertions(+), 63 deletions(-) diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index b215bf5..86eee87 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -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", diff --git a/Godeps/_workspace/src/github.com/godbus/dbus/conn.go b/Godeps/_workspace/src/github.com/godbus/dbus/conn.go index a4f5394..62bcbed 100644 --- a/Godeps/_workspace/src/github.com/godbus/dbus/conn.go +++ b/Godeps/_workspace/src/github.com/godbus/dbus/conn.go @@ -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 diff --git a/Godeps/_workspace/src/github.com/godbus/dbus/export.go b/Godeps/_workspace/src/github.com/godbus/dbus/export.go index c6440a7..c0d37b1 100644 --- a/Godeps/_workspace/src/github.com/godbus/dbus/export.go +++ b/Godeps/_workspace/src/github.com/godbus/dbus/export.go @@ -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 } diff --git a/Godeps/_workspace/src/github.com/godbus/dbus/transport_unix.go b/Godeps/_workspace/src/github.com/godbus/dbus/transport_unix.go index 3fafeab..a1d00cb 100644 --- a/Godeps/_workspace/src/github.com/godbus/dbus/transport_unix.go +++ b/Godeps/_workspace/src/github.com/godbus/dbus/transport_unix.go @@ -1,4 +1,4 @@ -//+build !windows +//+build !windows,!solaris package dbus