...

Source file src/github.com/godbus/dbus/v5/default_handler.go

Documentation: github.com/godbus/dbus/v5

     1  package dbus
     2  
     3  import (
     4  	"bytes"
     5  	"reflect"
     6  	"strings"
     7  	"sync"
     8  )
     9  
    10  func newIntrospectIntf(h *defaultHandler) *exportedIntf {
    11  	methods := make(map[string]Method)
    12  	methods["Introspect"] = exportedMethod{
    13  		reflect.ValueOf(func(msg Message) (string, *Error) {
    14  			path := msg.Headers[FieldPath].value.(ObjectPath)
    15  			return h.introspectPath(path), nil
    16  		}),
    17  	}
    18  	return newExportedIntf(methods, true)
    19  }
    20  
    21  //NewDefaultHandler returns an instance of the default
    22  //call handler. This is useful if you want to implement only
    23  //one of the two handlers but not both.
    24  //
    25  // Deprecated: this is the default value, don't use it, it will be unexported.
    26  func NewDefaultHandler() *defaultHandler {
    27  	h := &defaultHandler{
    28  		objects:     make(map[ObjectPath]*exportedObj),
    29  		defaultIntf: make(map[string]*exportedIntf),
    30  	}
    31  	h.defaultIntf["org.freedesktop.DBus.Introspectable"] = newIntrospectIntf(h)
    32  	return h
    33  }
    34  
    35  type defaultHandler struct {
    36  	sync.RWMutex
    37  	objects     map[ObjectPath]*exportedObj
    38  	defaultIntf map[string]*exportedIntf
    39  }
    40  
    41  func (h *defaultHandler) PathExists(path ObjectPath) bool {
    42  	_, ok := h.objects[path]
    43  	return ok
    44  }
    45  
    46  func (h *defaultHandler) introspectPath(path ObjectPath) string {
    47  	subpath := make(map[string]struct{})
    48  	var xml bytes.Buffer
    49  	xml.WriteString("<node>")
    50  	for obj := range h.objects {
    51  		p := string(path)
    52  		if p != "/" {
    53  			p += "/"
    54  		}
    55  		if strings.HasPrefix(string(obj), p) {
    56  			node_name := strings.Split(string(obj[len(p):]), "/")[0]
    57  			subpath[node_name] = struct{}{}
    58  		}
    59  	}
    60  	for s := range subpath {
    61  		xml.WriteString("\n\t<node name=\"" + s + "\"/>")
    62  	}
    63  	xml.WriteString("\n</node>")
    64  	return xml.String()
    65  }
    66  
    67  func (h *defaultHandler) LookupObject(path ObjectPath) (ServerObject, bool) {
    68  	h.RLock()
    69  	defer h.RUnlock()
    70  	object, ok := h.objects[path]
    71  	if ok {
    72  		return object, ok
    73  	}
    74  
    75  	// If an object wasn't found for this exact path,
    76  	// look for a matching subtree registration
    77  	subtreeObject := newExportedObject()
    78  	path = path[:strings.LastIndex(string(path), "/")]
    79  	for len(path) > 0 {
    80  		object, ok = h.objects[path]
    81  		if ok {
    82  			for name, iface := range object.interfaces {
    83  				// Only include this handler if it registered for the subtree
    84  				if iface.isFallbackInterface() {
    85  					subtreeObject.interfaces[name] = iface
    86  				}
    87  			}
    88  			break
    89  		}
    90  
    91  		path = path[:strings.LastIndex(string(path), "/")]
    92  	}
    93  
    94  	for name, intf := range h.defaultIntf {
    95  		if _, exists := subtreeObject.interfaces[name]; exists {
    96  			continue
    97  		}
    98  		subtreeObject.interfaces[name] = intf
    99  	}
   100  
   101  	return subtreeObject, true
   102  }
   103  
   104  func (h *defaultHandler) AddObject(path ObjectPath, object *exportedObj) {
   105  	h.Lock()
   106  	h.objects[path] = object
   107  	h.Unlock()
   108  }
   109  
   110  func (h *defaultHandler) DeleteObject(path ObjectPath) {
   111  	h.Lock()
   112  	delete(h.objects, path)
   113  	h.Unlock()
   114  }
   115  
   116  type exportedMethod struct {
   117  	reflect.Value
   118  }
   119  
   120  func (m exportedMethod) Call(args ...interface{}) ([]interface{}, error) {
   121  	t := m.Type()
   122  
   123  	params := make([]reflect.Value, len(args))
   124  	for i := 0; i < len(args); i++ {
   125  		params[i] = reflect.ValueOf(args[i]).Elem()
   126  	}
   127  
   128  	ret := m.Value.Call(params)
   129  	var err error
   130  	nilErr := false // The reflection will find almost-nils, let's only pass back clean ones!
   131  	if t.NumOut() > 0 {
   132  		if e, ok := ret[t.NumOut()-1].Interface().(*Error); ok { // godbus *Error
   133  			nilErr = ret[t.NumOut()-1].IsNil()
   134  			ret = ret[:t.NumOut()-1]
   135  			err = e
   136  		} else if ret[t.NumOut()-1].Type().Implements(errType) { // Go error
   137  			i := ret[t.NumOut()-1].Interface()
   138  			if i == nil {
   139  				nilErr = ret[t.NumOut()-1].IsNil()
   140  			} else {
   141  				err = i.(error)
   142  			}
   143  			ret = ret[:t.NumOut()-1]
   144  		}
   145  	}
   146  	out := make([]interface{}, len(ret))
   147  	for i, val := range ret {
   148  		out[i] = val.Interface()
   149  	}
   150  	if nilErr || err == nil {
   151  		//concrete type to interface nil is a special case
   152  		return out, nil
   153  	}
   154  	return out, err
   155  }
   156  
   157  func (m exportedMethod) NumArguments() int {
   158  	return m.Value.Type().NumIn()
   159  }
   160  
   161  func (m exportedMethod) ArgumentValue(i int) interface{} {
   162  	return reflect.Zero(m.Type().In(i)).Interface()
   163  }
   164  
   165  func (m exportedMethod) NumReturns() int {
   166  	return m.Value.Type().NumOut()
   167  }
   168  
   169  func (m exportedMethod) ReturnValue(i int) interface{} {
   170  	return reflect.Zero(m.Type().Out(i)).Interface()
   171  }
   172  
   173  func newExportedObject() *exportedObj {
   174  	return &exportedObj{
   175  		interfaces: make(map[string]*exportedIntf),
   176  	}
   177  }
   178  
   179  type exportedObj struct {
   180  	mu         sync.RWMutex
   181  	interfaces map[string]*exportedIntf
   182  }
   183  
   184  func (obj *exportedObj) LookupInterface(name string) (Interface, bool) {
   185  	if name == "" {
   186  		return obj, true
   187  	}
   188  	obj.mu.RLock()
   189  	defer obj.mu.RUnlock()
   190  	intf, exists := obj.interfaces[name]
   191  	return intf, exists
   192  }
   193  
   194  func (obj *exportedObj) AddInterface(name string, iface *exportedIntf) {
   195  	obj.mu.Lock()
   196  	defer obj.mu.Unlock()
   197  	obj.interfaces[name] = iface
   198  }
   199  
   200  func (obj *exportedObj) DeleteInterface(name string) {
   201  	obj.mu.Lock()
   202  	defer obj.mu.Unlock()
   203  	delete(obj.interfaces, name)
   204  }
   205  
   206  func (obj *exportedObj) LookupMethod(name string) (Method, bool) {
   207  	obj.mu.RLock()
   208  	defer obj.mu.RUnlock()
   209  	for _, intf := range obj.interfaces {
   210  		method, exists := intf.LookupMethod(name)
   211  		if exists {
   212  			return method, exists
   213  		}
   214  	}
   215  	return nil, false
   216  }
   217  
   218  func (obj *exportedObj) isFallbackInterface() bool {
   219  	return false
   220  }
   221  
   222  func newExportedIntf(methods map[string]Method, includeSubtree bool) *exportedIntf {
   223  	return &exportedIntf{
   224  		methods:        methods,
   225  		includeSubtree: includeSubtree,
   226  	}
   227  }
   228  
   229  type exportedIntf struct {
   230  	methods map[string]Method
   231  
   232  	// Whether or not this export is for the entire subtree
   233  	includeSubtree bool
   234  }
   235  
   236  func (obj *exportedIntf) LookupMethod(name string) (Method, bool) {
   237  	out, exists := obj.methods[name]
   238  	return out, exists
   239  }
   240  
   241  func (obj *exportedIntf) isFallbackInterface() bool {
   242  	return obj.includeSubtree
   243  }
   244  
   245  //NewDefaultSignalHandler returns an instance of the default
   246  //signal handler. This is useful if you want to implement only
   247  //one of the two handlers but not both.
   248  //
   249  // Deprecated: this is the default value, don't use it, it will be unexported.
   250  func NewDefaultSignalHandler() *defaultSignalHandler {
   251  	return &defaultSignalHandler{}
   252  }
   253  
   254  type defaultSignalHandler struct {
   255  	mu      sync.RWMutex
   256  	closed  bool
   257  	signals []*signalChannelData
   258  }
   259  
   260  func (sh *defaultSignalHandler) DeliverSignal(intf, name string, signal *Signal) {
   261  	sh.mu.RLock()
   262  	defer sh.mu.RUnlock()
   263  	if sh.closed {
   264  		return
   265  	}
   266  	for _, scd := range sh.signals {
   267  		scd.deliver(signal)
   268  	}
   269  }
   270  
   271  func (sh *defaultSignalHandler) Terminate() {
   272  	sh.mu.Lock()
   273  	defer sh.mu.Unlock()
   274  	if sh.closed {
   275  		return
   276  	}
   277  
   278  	for _, scd := range sh.signals {
   279  		scd.close()
   280  		close(scd.ch)
   281  	}
   282  	sh.closed = true
   283  	sh.signals = nil
   284  }
   285  
   286  func (sh *defaultSignalHandler) AddSignal(ch chan<- *Signal) {
   287  	sh.mu.Lock()
   288  	defer sh.mu.Unlock()
   289  	if sh.closed {
   290  		return
   291  	}
   292  	sh.signals = append(sh.signals, &signalChannelData{
   293  		ch:   ch,
   294  		done: make(chan struct{}),
   295  	})
   296  }
   297  
   298  func (sh *defaultSignalHandler) RemoveSignal(ch chan<- *Signal) {
   299  	sh.mu.Lock()
   300  	defer sh.mu.Unlock()
   301  	if sh.closed {
   302  		return
   303  	}
   304  	for i := len(sh.signals) - 1; i >= 0; i-- {
   305  		if ch == sh.signals[i].ch {
   306  			sh.signals[i].close()
   307  			copy(sh.signals[i:], sh.signals[i+1:])
   308  			sh.signals[len(sh.signals)-1] = nil
   309  			sh.signals = sh.signals[:len(sh.signals)-1]
   310  		}
   311  	}
   312  }
   313  
   314  type signalChannelData struct {
   315  	wg   sync.WaitGroup
   316  	ch   chan<- *Signal
   317  	done chan struct{}
   318  }
   319  
   320  func (scd *signalChannelData) deliver(signal *Signal) {
   321  	select {
   322  	case scd.ch <- signal:
   323  	case <-scd.done:
   324  		return
   325  	default:
   326  		scd.wg.Add(1)
   327  		go scd.deferredDeliver(signal)
   328  	}
   329  }
   330  
   331  func (scd *signalChannelData) deferredDeliver(signal *Signal) {
   332  	select {
   333  	case scd.ch <- signal:
   334  	case <-scd.done:
   335  	}
   336  	scd.wg.Done()
   337  }
   338  
   339  func (scd *signalChannelData) close() {
   340  	close(scd.done)
   341  	scd.wg.Wait() // wait until all spawned goroutines return
   342  }
   343  

View as plain text