go-tg-screenshot-bot

Форк
0
342 строки · 7.5 Кб
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

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.