object.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. package dbus
  2. import (
  3. "context"
  4. "errors"
  5. "strings"
  6. )
  7. // BusObject is the interface of a remote object on which methods can be
  8. // invoked.
  9. type BusObject interface {
  10. Call(method string, flags Flags, args ...interface{}) *Call
  11. CallWithContext(ctx context.Context, method string, flags Flags, args ...interface{}) *Call
  12. Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call
  13. GoWithContext(ctx context.Context, method string, flags Flags, ch chan *Call, args ...interface{}) *Call
  14. AddMatchSignal(iface, member string, options ...MatchOption) *Call
  15. RemoveMatchSignal(iface, member string, options ...MatchOption) *Call
  16. GetProperty(p string) (Variant, error)
  17. StoreProperty(p string, value interface{}) error
  18. SetProperty(p string, v interface{}) error
  19. Destination() string
  20. Path() ObjectPath
  21. }
  22. // Object represents a remote object on which methods can be invoked.
  23. type Object struct {
  24. conn *Conn
  25. dest string
  26. path ObjectPath
  27. }
  28. // Call calls a method with (*Object).Go and waits for its reply.
  29. func (o *Object) Call(method string, flags Flags, args ...interface{}) *Call {
  30. return <-o.createCall(context.Background(), method, flags, make(chan *Call, 1), args...).Done
  31. }
  32. // CallWithContext acts like Call but takes a context
  33. func (o *Object) CallWithContext(ctx context.Context, method string, flags Flags, args ...interface{}) *Call {
  34. return <-o.createCall(ctx, method, flags, make(chan *Call, 1), args...).Done
  35. }
  36. // AddMatchSignal subscribes BusObject to signals from specified interface,
  37. // method (member). Additional filter rules can be added via WithMatch* option constructors.
  38. // Note: To filter events by object path you have to specify this path via an option.
  39. //
  40. // Deprecated: use (*Conn) AddMatchSignal instead.
  41. func (o *Object) AddMatchSignal(iface, member string, options ...MatchOption) *Call {
  42. base := []MatchOption{
  43. withMatchType("signal"),
  44. WithMatchInterface(iface),
  45. WithMatchMember(member),
  46. }
  47. options = append(base, options...)
  48. return o.conn.BusObject().Call(
  49. "org.freedesktop.DBus.AddMatch",
  50. 0,
  51. formatMatchOptions(options),
  52. )
  53. }
  54. // RemoveMatchSignal unsubscribes BusObject from signals from specified interface,
  55. // method (member). Additional filter rules can be added via WithMatch* option constructors
  56. //
  57. // Deprecated: use (*Conn) RemoveMatchSignal instead.
  58. func (o *Object) RemoveMatchSignal(iface, member string, options ...MatchOption) *Call {
  59. base := []MatchOption{
  60. withMatchType("signal"),
  61. WithMatchInterface(iface),
  62. WithMatchMember(member),
  63. }
  64. options = append(base, options...)
  65. return o.conn.BusObject().Call(
  66. "org.freedesktop.DBus.RemoveMatch",
  67. 0,
  68. formatMatchOptions(options),
  69. )
  70. }
  71. // Go calls a method with the given arguments asynchronously. It returns a
  72. // Call structure representing this method call. The passed channel will
  73. // return the same value once the call is done. If ch is nil, a new channel
  74. // will be allocated. Otherwise, ch has to be buffered or Go will panic.
  75. //
  76. // If the flags include FlagNoReplyExpected, ch is ignored and a Call structure
  77. // is returned with any error in Err and a closed channel in Done containing
  78. // the returned Call as it's one entry.
  79. //
  80. // If the method parameter contains a dot ('.'), the part before the last dot
  81. // specifies the interface on which the method is called.
  82. func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call {
  83. return o.createCall(context.Background(), method, flags, ch, args...)
  84. }
  85. // GoWithContext acts like Go but takes a context
  86. func (o *Object) GoWithContext(ctx context.Context, method string, flags Flags, ch chan *Call, args ...interface{}) *Call {
  87. return o.createCall(ctx, method, flags, ch, args...)
  88. }
  89. func (o *Object) createCall(ctx context.Context, method string, flags Flags, ch chan *Call, args ...interface{}) *Call {
  90. if ctx == nil {
  91. panic("nil context")
  92. }
  93. iface := ""
  94. i := strings.LastIndex(method, ".")
  95. if i != -1 {
  96. iface = method[:i]
  97. }
  98. method = method[i+1:]
  99. msg := new(Message)
  100. msg.Type = TypeMethodCall
  101. msg.Flags = flags & (FlagNoAutoStart | FlagNoReplyExpected)
  102. msg.Headers = make(map[HeaderField]Variant)
  103. msg.Headers[FieldPath] = MakeVariant(o.path)
  104. msg.Headers[FieldDestination] = MakeVariant(o.dest)
  105. msg.Headers[FieldMember] = MakeVariant(method)
  106. if iface != "" {
  107. msg.Headers[FieldInterface] = MakeVariant(iface)
  108. }
  109. msg.Body = args
  110. if len(args) > 0 {
  111. msg.Headers[FieldSignature] = MakeVariant(SignatureOf(args...))
  112. }
  113. return o.conn.SendWithContext(ctx, msg, ch)
  114. }
  115. // GetProperty calls org.freedesktop.DBus.Properties.Get on the given
  116. // object. The property name must be given in interface.member notation.
  117. func (o *Object) GetProperty(p string) (Variant, error) {
  118. var result Variant
  119. err := o.StoreProperty(p, &result)
  120. return result, err
  121. }
  122. // StoreProperty calls org.freedesktop.DBus.Properties.Get on the given
  123. // object. The property name must be given in interface.member notation.
  124. // It stores the returned property into the provided value.
  125. func (o *Object) StoreProperty(p string, value interface{}) error {
  126. idx := strings.LastIndex(p, ".")
  127. if idx == -1 || idx+1 == len(p) {
  128. return errors.New("dbus: invalid property " + p)
  129. }
  130. iface := p[:idx]
  131. prop := p[idx+1:]
  132. return o.Call("org.freedesktop.DBus.Properties.Get", 0, iface, prop).
  133. Store(value)
  134. }
  135. // SetProperty calls org.freedesktop.DBus.Properties.Set on the given
  136. // object. The property name must be given in interface.member notation.
  137. func (o *Object) SetProperty(p string, v interface{}) error {
  138. idx := strings.LastIndex(p, ".")
  139. if idx == -1 || idx+1 == len(p) {
  140. return errors.New("dbus: invalid property " + p)
  141. }
  142. iface := p[:idx]
  143. prop := p[idx+1:]
  144. return o.Call("org.freedesktop.DBus.Properties.Set", 0, iface, prop, v).Err
  145. }
  146. // Destination returns the destination that calls on (o *Object) are sent to.
  147. func (o *Object) Destination() string {
  148. return o.dest
  149. }
  150. // Path returns the path that calls on (o *Object") are sent to.
  151. func (o *Object) Path() ObjectPath {
  152. return o.path
  153. }