forked from szatmary/sonos
-
Notifications
You must be signed in to change notification settings - Fork 1
/
QPlay.go
115 lines (106 loc) · 2.87 KB
/
QPlay.go
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
package qplay
import (
"bytes"
"encoding/xml"
"errors"
"io/ioutil"
"net/http"
"net/url"
)
const (
_ServiceURN = "urn:schemas-upnp-org:service:QPlay:1"
_EncodingSchema = "http://schemas.xmlsoap.org/soap/encoding/"
_EnvelopeSchema = "http://schemas.xmlsoap.org/soap/envelope/"
)
type Service struct {
ControlEndpoint *url.URL
EventEndpoint *url.URL
}
func NewService(deviceUrl *url.URL) *Service {
c, err := url.Parse(`/QPlay/Control`)
if nil != err {
panic(err)
}
e, err := url.Parse(`/QPlay/Event`)
if nil != err {
panic(err)
}
return &Service{
ControlEndpoint: deviceUrl.ResolveReference(c),
EventEndpoint: deviceUrl.ResolveReference(e),
}
}
type Envelope struct {
XMLName xml.Name `xml:"s:Envelope"`
Xmlns string `xml:"xmlns:s,attr"`
EncodingStyle string `xml:"s:encodingStyle,attr"`
Body Body `xml:"s:Body"`
}
type Body struct {
XMLName xml.Name `xml:"s:Body"`
QPlayAuth *QPlayAuthArgs `xml:"u:QPlayAuth,omitempty"`
}
type EnvelopeResponse struct {
XMLName xml.Name `xml:"Envelope"`
Xmlns string `xml:"xmlns:s,attr"`
EncodingStyle string `xml:"encodingStyle,attr"`
Body BodyResponse `xml:"Body"`
}
type BodyResponse struct {
XMLName xml.Name `xml:"Body"`
QPlayAuth *QPlayAuthResponse `xml:"QPlayAuthResponse,omitempty"`
}
func (s *Service) exec(actionName string, httpClient *http.Client, envelope *Envelope) (*EnvelopeResponse, error) {
marshaled, err := xml.Marshal(envelope)
if err != nil {
return nil, err
}
postBody := []byte(`<?xml version="1.0"?>`)
postBody = append(postBody, marshaled...)
req, err := http.NewRequest(`POST`, s.ControlEndpoint.String(), bytes.NewBuffer(postBody))
if err != nil {
return nil, err
}
req.Header.Set(`Content-Type`, `text/xml; charset="utf-8"`)
req.Header.Set(`SOAPAction`, _ServiceURN+`#`+actionName)
res, err := httpClient.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
responseBody, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
}
var envelopeResponse EnvelopeResponse
err = xml.Unmarshal(responseBody, &envelopeResponse)
if err != nil {
return nil, err
}
return &envelopeResponse, nil
}
type QPlayAuthArgs struct {
Xmlns string `xml:"xmlns:u,attr"`
Seed string `xml:"Seed"`
}
type QPlayAuthResponse struct {
Code string `xml:"Code"`
MID string `xml:"MID"`
DID string `xml:"DID"`
}
func (s *Service) QPlayAuth(httpClient *http.Client, args *QPlayAuthArgs) (*QPlayAuthResponse, error) {
args.Xmlns = _ServiceURN
r, err := s.exec(`QPlayAuth`, httpClient,
&Envelope{
EncodingStyle: _EncodingSchema,
Xmlns: _EnvelopeSchema,
Body: Body{QPlayAuth: args},
})
if err != nil {
return nil, err
}
if r.Body.QPlayAuth == nil {
return nil, errors.New(`unexpected respose from service calling qplay.QPlayAuth()`)
}
return r.Body.QPlayAuth, nil
}