-
Notifications
You must be signed in to change notification settings - Fork 0
/
pushcontext.go
181 lines (143 loc) · 4.7 KB
/
pushcontext.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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
package breeze
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
)
const (
validateURL = "https://api.pushover.net/1/users/validate.json"
pushURL = "https://api.pushover.net/1/messages.json"
receiptURL = "https://api.pushover.net/1/receipts"
soundURL = "https://api.pushover.net/1/sounds.json"
)
// PushContext represents a context that can be used to send push messages. This
// means an app token and a user key.
type PushContext struct {
appToken string
userKey string
// A list of sounds supported by the push context.
SupportedSounds map[string]string
// A list of devices supported by the push context.
SupportedDevices []string
}
// Response represents the response received from the Pushover API. If the
// "Status" field is set to 1, then it was successful. If the status field is
// not 1, then the "Errors" field will contain a list of errors received from
// the API. The devices are gathered when requesting validation of a device.
// The devices field will eventually be exposed as a discovery service.
type Response struct {
Status int `json:"status"`
Request string `json:"request"`
Receipt string `json:"receipt"`
Devices []string `json:"devices"`
Errors []string `json:"errors"`
Sounds map[string]string `json:"sounds"`
}
// PushError represents an error that occured while interacting with the API.
type PushError struct {
RequestResponse Response
}
func (pushError *PushError) Error() string {
requestKey := pushError.RequestResponse.Request
errors := pushError.RequestResponse.Errors
return fmt.Sprintf("Request: %s failed with errors: %s", requestKey,
strings.Join(errors[:], ","))
}
func (pushContext *PushContext) push(pushURL string, values url.Values) (Response, error) {
response, err := http.PostForm(pushURL, values)
if err != nil {
fmt.Println("Handle the error case.")
}
defer response.Body.Close()
decoder := json.NewDecoder(response.Body)
var responseData Response
decoder.Decode(&responseData)
if responseData.Status != 1 {
return Response{}, &PushError{RequestResponse: responseData}
}
return responseData, nil
}
func (pushContext *PushContext) addValues(values url.Values) {
values.Add("token", pushContext.appToken)
values.Add("user", pushContext.userKey)
}
// Push will use the Pushover API to push the given message using the given push
// context.
func (pushContext *PushContext) Push(message *Message) (Response, error) {
parameters := url.Values{}
err := message.validateMessage(pushContext)
if err != nil {
return Response{}, err
}
pushContext.addValues(parameters)
message.addValues(parameters)
return pushContext.push(pushURL, parameters)
}
func (pushContext *PushContext) validatePushContext() error {
parameters := url.Values{}
pushContext.addValues(parameters)
response, err := pushContext.push(validateURL, parameters)
if err != nil {
return err
}
pushContext.SupportedDevices = response.Devices
sounds, err := pushContext.availableSounds()
if err != nil {
return err
}
pushContext.SupportedSounds = sounds
return err
}
func (pushContext *PushContext) get(getURL string, values url.Values) (Response, error) {
var encodedURL *url.URL
encodedURL, err := url.Parse(getURL)
encodedURL.RawQuery = values.Encode()
response, err := http.Get(encodedURL.String())
if err != nil {
return Response{}, err
}
defer response.Body.Close()
decoder := json.NewDecoder(response.Body)
var responseData Response
decoder.Decode(&responseData)
return responseData, nil
}
func (pushContext *PushContext) availableSounds() (map[string]string, error) {
parameters := url.Values{}
pushContext.addValues(parameters)
response, err := pushContext.get(soundURL, parameters)
if err != nil {
return make(map[string]string), err
}
return response.Sounds, nil
}
// IsValidDevice can be used to check if a requested device is valid with the
// given push context.
func (pushContext *PushContext) IsValidDevice(device string) bool {
for _, suppDev := range pushContext.SupportedDevices {
if suppDev == device {
return true
}
}
return false
}
// IsValidSound can be used to check if a requested sound is valid with the
// given push context.
func (pushContext *PushContext) IsValidSound(sound string) bool {
_, ok := pushContext.SupportedSounds[sound]
return ok
}
// NewPushContext is the primary interface for receiving a new PushContext
// struct that can be used to interact with the Pushover API.
func NewPushContext(appToken string, userKey string) (*PushContext, error) {
var pushContext = new(PushContext)
pushContext.appToken = appToken
pushContext.userKey = userKey
err := pushContext.validatePushContext()
if err != nil {
return nil, err
}
return pushContext, nil
}