-
Notifications
You must be signed in to change notification settings - Fork 2
/
http_service.go
153 lines (139 loc) · 4.82 KB
/
http_service.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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package wemo
import (
"bytes"
"context"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
)
func (s *SwitchService) handleSetup(w http.ResponseWriter, r *http.Request) {
log.Printf("RX: setup request from: %s", r.RemoteAddr)
w.Header().Set("Content-Type", "text/xml")
writeSetupXML(w, s.name, s.uuid, s.serial)
}
func writeSetupXML(w io.Writer, name, uuid, serial string) {
fmt.Fprint(w, `<?xml version="1.0"?>`)
fmt.Fprint(w, `<root xmlns="urn:Belkin:device-1-0">`)
fmt.Fprint(w, `<specVersion><major>1</major><minor>0</minor></specVersion>`)
fmt.Fprint(w, `<device>`)
fmt.Fprint(w, `<deviceType>urn:Belkin:device:controllee:1</deviceType>`)
fmt.Fprintf(w, `<friendlyName>%s</friendlyName>`, name)
fmt.Fprint(w, `<manufacturer>Belkin International Inc.</manufacturer>`)
fmt.Fprint(w, `<manufacturerURL>http://www.belkin.com</manufacturerURL>`)
fmt.Fprint(w, `<modelDescription>Belkin Plugin Socket 1.0</modelDescription>`)
fmt.Fprint(w, `<modelName>Socket</modelName>`)
fmt.Fprint(w, `<modelNumber>1</modelNumber>`)
fmt.Fprint(w, `<modelURL>http://www.belkin.com/plugin/</modelURL>`)
fmt.Fprint(w, `<modelName>Socket</modelName>`)
fmt.Fprint(w, `<modelNumber>1</modelNumber>`)
fmt.Fprint(w, `<modelDescription>Belkin Plugin Socket 1.0</modelDescription>`)
fmt.Fprintf(w, `<UDN>uuid:%s</UDN>`, uuid)
fmt.Fprintf(w, `<serialNumber>%s</serialNumber>`, serial)
fmt.Fprint(w, `<binaryState>1</binaryState>`)
fmt.Fprint(w, `<serviceList>`)
fmt.Fprint(w, `<service>`)
fmt.Fprint(w, `<serviceType>urn:Belkin:service:basicevent:1</serviceType>`)
fmt.Fprint(w, `<serviceId>urn:Belkin:serviceId:basicevent1</serviceId>`)
fmt.Fprint(w, `<controlURL>/upnp/control/basicevent1</controlURL>`)
fmt.Fprint(w, `<eventSubURL>/upnp/event/basicevent1</eventSubURL>`)
fmt.Fprint(w, `<SCPDURL>/eventservice.xml</SCPDURL>`)
fmt.Fprint(w, `</service>`)
fmt.Fprint(w, `</serviceList>`)
fmt.Fprint(w, `</device>`)
fmt.Fprint(w, `</root>`)
}
func (s *SwitchService) handleUpnpControlBasicEvent1(w http.ResponseWriter, r *http.Request) {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, "cannot read body", http.StatusBadRequest)
return
}
r.Body.Close()
s.mu.Lock()
w.Header().Set("Content-Type", "text/xml")
if bytes.Contains(body, []byte("SetBinaryState")) {
var state bool
ctx := r.Context()
switch {
case bytes.Contains(body, []byte("<BinaryState>1</BinaryState>")):
log.Printf(`RX: turn on. name="%s"`, s.name)
state = runCallback(ctx, s.onCallback, s.state)
sendRelayState(w, state, "Set")
case bytes.Contains(body, []byte("<BinaryState>0</BinaryState>")):
log.Printf(`RX: turn off. name="%s"`, s.name)
state = runCallback(ctx, s.offCallback, s.state)
sendRelayState(w, state, "Set")
}
s.state = state
}
if bytes.Contains(body, []byte("GetBinaryState")) {
log.Printf(`RX: sync binary state. name="%s" state="%t"`, s.name, s.state)
sendRelayState(w, s.state, "Get")
}
s.mu.Unlock()
}
func runCallback(ctx context.Context, command func(ctx context.Context, state bool) bool, state bool) bool {
if command == nil {
return !state
}
return command(ctx, state)
}
func sendRelayState(w io.Writer, state bool, method string) {
fmt.Fprint(w, `<?xml version="1.0"?>`)
fmt.Fprint(w, `<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">`)
fmt.Fprint(w, `<s:Body>`)
fmt.Fprintf(w, `<u:%sBinaryStateResponse xmlns:u="urn:Belkin:service:basicevent:1">`, method)
if state {
fmt.Fprint(w, `<BinaryState>1</BinaryState>`)
} else {
fmt.Fprint(w, `<BinaryState>0</BinaryState>`)
}
fmt.Fprintf(w, `</u:%sBinaryStateResponse>`, method)
fmt.Fprint(w, `</s:Body>`)
fmt.Fprint(w, `</s:Envelope>`)
}
func handleEventService(w http.ResponseWriter, r *http.Request) {
log.Printf("EventService request from: %s", r.RemoteAddr)
w.Header().Set("Content-Type", "text/xml")
fmt.Fprint(w, `<?xml version="1.0"?>
<scpd xmlns="urn:Belkin:service-1-0">
<actionList>
<action>
<name>SetBinaryState</name>
<argumentList>
<argument>
<retval/>
<name>BinaryState</name>
<relatedStateVariable>BinaryState</relatedStateVariable>
<direction>in</direction>
</argument>
</argumentList>
</action>
<action>
<name>GetBinaryState</name>
<argumentList>
<argument>
<retval/>
<name>BinaryState</name>
<relatedStateVariable>BinaryState</relatedStateVariable>
<direction>out</direction>
</argument>
</argumentList>
</action>
</actionList>
<serviceStateTable>
<stateVariable sendEvents="yes">
<name>BinaryState</name>
<dataType>Boolean</dataType>
<defaultValue>0</defaultValue>
</stateVariable>
<stateVariable sendEvents="yes">
<name>level</name>
<dataType>string</dataType>
<defaultValue>0</defaultValue>
</stateVariable>
</serviceStateTable>
</scpd>`)
}