-
Notifications
You must be signed in to change notification settings - Fork 1
/
alexa.go
151 lines (127 loc) · 3.22 KB
/
alexa.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
package alexa
import (
"encoding/json"
"net/http"
"strings"
)
// HandleFunc represents the handler function.
type HandleFunc func(ResponseWriter, *Request) error
// Alexa represents the Alexa app.
type Alexa struct {
ApplicationID string
IgnoreTimestamp bool
IgnoreCertVerify bool
onSessionStarted HandleFunc
onAudioPlayer HandleFunc
onLaunch HandleFunc
onIntent HandleFunc
onSessionEnded HandleFunc
}
// Options represents Alexa app options.
type Options struct {
ApplicationID string
IgnoreTimestamp bool
IgnoreCertVerify bool
}
// NewApp creates a new Alexa app.
func NewApp(opt *Options) *Alexa {
return &Alexa{
ApplicationID: opt.ApplicationID,
IgnoreTimestamp: opt.IgnoreTimestamp,
IgnoreCertVerify: opt.IgnoreCertVerify,
}
}
// OnSessionStarted sets the session started handler.
func (a *Alexa) OnSessionStarted(h HandleFunc) {
a.onSessionStarted = h
}
// OnAudioPlayer sets the audio player handler.
func (a *Alexa) OnAudioPlayer(h HandleFunc) {
a.onAudioPlayer = h
}
// OnLaunch sets the launch handler.
func (a *Alexa) OnLaunch(h HandleFunc) {
a.onLaunch = h
}
// OnIntent sets the intent handler.
func (a *Alexa) OnIntent(h HandleFunc) {
a.onIntent = h
}
// OnSessionEnded sets the session ended handler.
func (a *Alexa) OnSessionEnded(h HandleFunc) {
a.onSessionEnded = h
}
// Process handles a request passed from Alexa.
func (a *Alexa) Process(r *Request) (*Response, error) {
w := NewResponse()
if err := a.verifyApplicationID(r); err != nil {
return nil, err
}
if err := a.verifyTimestamp(r); err != nil {
return w, err
}
if r.Session.New && a.onSessionStarted != nil {
if err := a.onSessionStarted(w, r); err != nil {
return nil, err
}
}
switch r.Request.Type {
case "LaunchRequest":
if a.onLaunch != nil {
if err := a.onLaunch(w, r); err != nil {
return nil, err
}
}
case "IntentRequest":
if a.onIntent != nil {
if err := a.onIntent(w, r); err != nil {
return nil, err
}
}
case "SessionEndedRequest":
if a.onSessionEnded != nil {
if err := a.onSessionEnded(w, r); err != nil {
return nil, err
}
}
default:
if strings.HasPrefix("AudioPlayer", r.Request.Type) {
if a.onAudioPlayer != nil {
if err := a.onAudioPlayer(w, r); err != nil {
return nil, err
}
}
}
break
}
return w, nil
}
// Handler returns a http handler to hook Alexa app into a http server.
func (a *Alexa) Handler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var req *Request
w.Header().Set("Content-Type", "application/json; charset=utf-8")
// Bail if POST method.
if strings.ToUpper(r.Method) != "POST" {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
// Verify Alexa request.
if err := a.verifyAlexaRequest(r); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// Bail if JSON decode failes.
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
resp, err := a.Process(req)
// Bail if process request failes.
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
json.NewEncoder(w).Encode(resp)
})
}