gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

default_handler.go (7691B)


      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 }