forked from lucashpandolfo/dbus
-
Notifications
You must be signed in to change notification settings - Fork 0
/
introspect.lisp
125 lines (100 loc) · 4.79 KB
/
introspect.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
;;;; +----------------------------------------------------------------+
;;;; | DBUS DEATH, 2010-2011 |
;;;; +----------------------------------------------------------------+
(in-package #:dbus)
;;;; Support for introspection of D-BUS objects
(defclass object ()
((connection :initarg :connection :reader object-connection)
(path :initarg :path :reader object-path)
(destination :initarg :destination :reader object-destination)
(interfaces :initform (make-hash-table :test 'equal) :reader object-interfaces)))
(defmethod print-object ((object object) stream)
(print-unreadable-object (object stream :type t)
(format stream "~S" (object-path object)))
object)
(defun object-interface (name object)
(gethash name (object-interfaces object)))
(defun (setf object-interface) (interface name object)
(setf (gethash name (object-interfaces object)) interface))
(defun list-object-interfaces (object)
(hash-table-values (object-interfaces object)))
(defun make-object (connection path destination interfaces)
(let ((object (make-instance 'object :connection connection :path path :destination destination)))
(dolist (interface interfaces)
(setf (object-interface (interface-name interface) object) interface))
object))
(defclass interface ()
((name :initarg :name :reader interface-name)
(methods :initform (make-hash-table :test 'equal) :reader interface-methods)))
(defmethod print-object ((interface interface) stream)
(print-unreadable-object (interface stream :type t)
(format stream "~S" (interface-name interface)))
interface)
(defun interface-method (name interface)
(gethash name (interface-methods interface)))
(defun (setf interface-method) (method name interface)
(setf (gethash name (interface-methods interface)) method))
(defun list-interface-methods (interface)
(hash-table-values (interface-methods interface)))
(defun make-interface (name methods)
(let ((interface (make-instance 'interface :name name)))
(dolist (method methods)
(setf (interface-method (method-name method) interface) method))
interface))
(defclass method ()
((name :initarg :name :reader method-name)
(signature :initarg :signature :reader method-signature)))
(defmethod print-object ((method method) stream)
(print-unreadable-object (method stream :type t)
(format stream "~S" (method-name method)))
method)
(defun make-method (name signature)
(make-instance 'method :name name :signature signature))
(defun dont-resolve-entities (a b)
(declare (ignore a b))
(make-in-memory-input-stream nil))
(defmacro defaulted-attribute (name default-value &body forms)
`(let ((_ (or (optional-attribute ,name _) ,default-value)))
,@forms))
(defun parse-introspection-document (input)
(with-xspam-source (make-xspam-source input :entity-resolver #'dont-resolve-entities)
(element :node
(let (interfaces)
(one-or-more
(element :interface
(let (interface-name)
(attribute :name (setf interface-name _))
(let (methods)
(zero-or-more
(element :method
(let (method-name)
(attribute :name (setf method-name _))
(let ((signature (make-string-output-stream)))
(zero-or-more
(element :arg
(defaulted-attribute :direction "in"
(when (equal _ "in")
(attribute :type
(write-string _ signature))))))
(push (make-method method-name (get-output-stream-string signature)) methods)))))
(push (make-interface interface-name (nreverse methods)) interfaces)))))
(nreverse interfaces)))))
(defun make-object-from-introspection (connection path destination)
(make-object connection path destination
(parse-introspection-document
(fetch-introspection-document connection path destination))))
(defun fetch-introspection-document (connection path destination)
(invoke-method connection "Introspect"
:path path
:destination destination
:interface "org.freedesktop.DBus.Introspectable"))
(defun object-invoke (object interface-name method-name &rest args)
(invoke-method (object-connection object)
method-name
:path (object-path object)
:interface interface-name
:destination (object-destination object)
:signature (signature-for-method method-name interface-name object)
:arguments args))
(defun signature-for-method (method-name interface-name object)
(method-signature (interface-method method-name (object-interface interface-name object))))