object.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. package dbus
  2. import (
  3. "errors"
  4. "strings"
  5. )
  6. // BusObject is the interface of a remote object on which methods can be
  7. // invoked.
  8. type BusObject interface {
  9. Call(method string, flags Flags, args ...interface{}) *Call
  10. Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call
  11. GetProperty(p string) (Variant, error)
  12. Destination() string
  13. Path() ObjectPath
  14. }
  15. // Object represents a remote object on which methods can be invoked.
  16. type Object struct {
  17. conn *Conn
  18. dest string
  19. path ObjectPath
  20. }
  21. // Call calls a method with (*Object).Go and waits for its reply.
  22. func (o *Object) Call(method string, flags Flags, args ...interface{}) *Call {
  23. return <-o.Go(method, flags, make(chan *Call, 1), args...).Done
  24. }
  25. // AddMatchSignal subscribes BusObject to signals from specified interface and
  26. // method (member).
  27. func (o *Object) AddMatchSignal(iface, member string) *Call {
  28. return o.Call(
  29. "org.freedesktop.DBus.AddMatch",
  30. 0,
  31. "type='signal',interface='"+iface+"',member='"+member+"'",
  32. )
  33. }
  34. // Go calls a method with the given arguments asynchronously. It returns a
  35. // Call structure representing this method call. The passed channel will
  36. // return the same value once the call is done. If ch is nil, a new channel
  37. // will be allocated. Otherwise, ch has to be buffered or Go will panic.
  38. //
  39. // If the flags include FlagNoReplyExpected, ch is ignored and a Call structure
  40. // is returned of which only the Err member is valid.
  41. //
  42. // If the method parameter contains a dot ('.'), the part before the last dot
  43. // specifies the interface on which the method is called.
  44. func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call {
  45. iface := ""
  46. i := strings.LastIndex(method, ".")
  47. if i != -1 {
  48. iface = method[:i]
  49. }
  50. method = method[i+1:]
  51. msg := new(Message)
  52. msg.Type = TypeMethodCall
  53. msg.serial = o.conn.getSerial()
  54. msg.Flags = flags & (FlagNoAutoStart | FlagNoReplyExpected)
  55. msg.Headers = make(map[HeaderField]Variant)
  56. msg.Headers[FieldPath] = MakeVariant(o.path)
  57. msg.Headers[FieldDestination] = MakeVariant(o.dest)
  58. msg.Headers[FieldMember] = MakeVariant(method)
  59. if iface != "" {
  60. msg.Headers[FieldInterface] = MakeVariant(iface)
  61. }
  62. msg.Body = args
  63. if len(args) > 0 {
  64. msg.Headers[FieldSignature] = MakeVariant(SignatureOf(args...))
  65. }
  66. if msg.Flags&FlagNoReplyExpected == 0 {
  67. if ch == nil {
  68. ch = make(chan *Call, 10)
  69. } else if cap(ch) == 0 {
  70. panic("dbus: unbuffered channel passed to (*Object).Go")
  71. }
  72. call := &Call{
  73. Destination: o.dest,
  74. Path: o.path,
  75. Method: method,
  76. Args: args,
  77. Done: ch,
  78. }
  79. o.conn.callsLck.Lock()
  80. o.conn.calls[msg.serial] = call
  81. o.conn.callsLck.Unlock()
  82. o.conn.outLck.RLock()
  83. if o.conn.closed {
  84. call.Err = ErrClosed
  85. call.Done <- call
  86. } else {
  87. o.conn.out <- msg
  88. }
  89. o.conn.outLck.RUnlock()
  90. return call
  91. }
  92. o.conn.outLck.RLock()
  93. defer o.conn.outLck.RUnlock()
  94. if o.conn.closed {
  95. return &Call{Err: ErrClosed}
  96. }
  97. o.conn.out <- msg
  98. return &Call{Err: nil}
  99. }
  100. // GetProperty calls org.freedesktop.DBus.Properties.GetProperty on the given
  101. // object. The property name must be given in interface.member notation.
  102. func (o *Object) GetProperty(p string) (Variant, error) {
  103. idx := strings.LastIndex(p, ".")
  104. if idx == -1 || idx+1 == len(p) {
  105. return Variant{}, errors.New("dbus: invalid property " + p)
  106. }
  107. iface := p[:idx]
  108. prop := p[idx+1:]
  109. result := Variant{}
  110. err := o.Call("org.freedesktop.DBus.Properties.Get", 0, iface, prop).Store(&result)
  111. if err != nil {
  112. return Variant{}, err
  113. }
  114. return result, nil
  115. }
  116. // Destination returns the destination that calls on o are sent to.
  117. func (o *Object) Destination() string {
  118. return o.dest
  119. }
  120. // Path returns the path that calls on o are sent to.
  121. func (o *Object) Path() ObjectPath {
  122. return o.path
  123. }