alexa-rails 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +165 -0
- data/Rakefile +36 -0
- data/app/assets/config/alexa_manifest.js +2 -0
- data/app/assets/javascripts/alexa/application.js +13 -0
- data/app/assets/stylesheets/alexa/application.css +15 -0
- data/app/controllers/alexa/application_controller.rb +6 -0
- data/app/controllers/alexa/intent_handlers_controller.rb +49 -0
- data/app/helpers/alexa/application_helper.rb +4 -0
- data/app/helpers/alexa/context_helper.rb +23 -0
- data/app/helpers/alexa/render_helper.rb +24 -0
- data/app/jobs/alexa/application_job.rb +4 -0
- data/app/mailers/alexa/application_mailer.rb +6 -0
- data/app/models/alexa/application_record.rb +5 -0
- data/app/models/alexa/usage.rb +11 -0
- data/app/models/alexa/user.rb +17 -0
- data/app/views/alexa/_response.json.erb +18 -0
- data/app/views/alexa/output/_card.json.erb +13 -0
- data/app/views/alexa/output/_ssml.json.erb +7 -0
- data/app/views/alexa/output/cards/_ask_for_permissions_consent.json.erb +6 -0
- data/app/views/alexa/output/cards/_simple.json.erb +5 -0
- data/app/views/alexa/permission_consents/device_address.text.erb +7 -0
- data/app/views/layouts/alexa/application.html.erb +14 -0
- data/config/routes.rb +3 -0
- data/lib/alexa/context.rb +38 -0
- data/lib/alexa/device.rb +61 -0
- data/lib/alexa/engine.rb +5 -0
- data/lib/alexa/intent_handlers/base.rb +158 -0
- data/lib/alexa/request.rb +97 -0
- data/lib/alexa/response.rb +85 -0
- data/lib/alexa/responses/bye.rb +26 -0
- data/lib/alexa/responses/delegate.rb +18 -0
- data/lib/alexa/responses/permission_consents/device_address.rb +28 -0
- data/lib/alexa/session.rb +35 -0
- data/lib/alexa/slot.rb +50 -0
- data/lib/alexa/version.rb +3 -0
- data/lib/alexa-rails.rb +19 -0
- data/lib/generators/alexa/migrations_generator.rb +22 -0
- data/lib/generators/alexa/templates/create_alexa_usages.rb +13 -0
- data/lib/generators/alexa/templates/create_alexa_users.rb +13 -0
- data/lib/tasks/alexa_tasks.rake +4 -0
- metadata +115 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1885e37fc556e96fc1cc6d08e6643a2643e19bb9
|
4
|
+
data.tar.gz: ab032623d44c9c2fbdfa85f75d437ae17dcda44d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0e86743175bfc943c911c35aa6d079475501ea3a8c3a02958fd749b2358b3445b6172a0bfd3fad58e075470e5bcaa668371caf709ec197a141c40d416019e8ec
|
7
|
+
data.tar.gz: 2eee6244d1f954b2b86e03af208a198e5051459857b1578a62ab1c1954c058c08a73798877622a91bc8495a659119db2e861f51563102ea4b94cb5f0888b4f75
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2018
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
# Alexa
|
2
|
+
`alexa-rails` is a ruby gem which is a mountable rails engine that will add abilities to your Ruby on Rails application to handle Amazon alexa requests and responses.
|
3
|
+
|
4
|
+
## Intallation/Usage
|
5
|
+
|
6
|
+
Do the usual by adding the following to your Gemfile:
|
7
|
+
|
8
|
+
```ruby
|
9
|
+
gem install alexa-rails
|
10
|
+
```
|
11
|
+
|
12
|
+
### Migrations
|
13
|
+
|
14
|
+
The gem provides migrations that are needed to use few features of the gem.
|
15
|
+
For example: Saving or reading the user's skill usage count.
|
16
|
+
To generate the migrations, run the following
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
$ rails generate alexa:migrations
|
20
|
+
$ rake db:migrate
|
21
|
+
```
|
22
|
+
|
23
|
+
### Configuration
|
24
|
+
|
25
|
+
Set alexa skill IDs in environment config (ex: config/environments/development.rb).
|
26
|
+
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
# config/environments/development.rb
|
30
|
+
|
31
|
+
config.x.alexa.skill_ids = [
|
32
|
+
"amzn1.ask.skill.xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx"
|
33
|
+
]
|
34
|
+
```
|
35
|
+
|
36
|
+
Mount the engine for routes handling in your routes
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
# config/routes.rb
|
40
|
+
|
41
|
+
Rails.application.routes.draw do
|
42
|
+
...
|
43
|
+
mount Alexa::Engine, at: "/alexa"
|
44
|
+
end
|
45
|
+
```
|
46
|
+
|
47
|
+
### Request handling
|
48
|
+
|
49
|
+
After the above steps, your application is ready to accept requests from Alexa
|
50
|
+
servers at `/alexa/intent_handlers`.
|
51
|
+
You will have to provide that in the HTTPS endpoint URL for your skill.
|
52
|
+
|
53
|
+
To handle an intent, you will have to create an intent handler class.
|
54
|
+
For example, if your intent is named `PlaceOrder`, you will have to create
|
55
|
+
the following file under you `app/lib/intent_handlers` directory.
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
module Alexa
|
59
|
+
module IntentHandlers
|
60
|
+
class PlaceOrder < Alexa::IntentHandlers::Base
|
61
|
+
def handle
|
62
|
+
...
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
```
|
68
|
+
|
69
|
+
All intent handlers should contain a `#handle` method that has required logic
|
70
|
+
as to how to handle the intent request. For example, adding session variables,
|
71
|
+
setting response to elicit slots, etc.
|
72
|
+
|
73
|
+
Adding session variable:
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
session.merge!(my_var: value)
|
77
|
+
```
|
78
|
+
|
79
|
+
#### Slot elicitations
|
80
|
+
|
81
|
+
Depending on your conditions, you can set the reponse to elicit a specific
|
82
|
+
slot and the respecitve views are used.
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
response.elicit_slot!(:SlotName)
|
86
|
+
```
|
87
|
+
|
88
|
+
### Views
|
89
|
+
|
90
|
+
The content for speech and display cards is not set in the intent handler
|
91
|
+
classes.
|
92
|
+
We follow rails convention and expect all response content for intents to be
|
93
|
+
in their respective view files.
|
94
|
+
|
95
|
+
Also, the views are context locale dependant.
|
96
|
+
|
97
|
+
Given an intent named `PlaceOrder`, you view files would be
|
98
|
+
|
99
|
+
* SSML: `views/alexa/en_us/intent_handlers/place_order/speech.ssml.erb`
|
100
|
+
* Card: `views/alexa/en_us/intent_handlers/place_order/display.text.erb`
|
101
|
+
|
102
|
+
In case of slot elicitations, follow a similar convention but make sure you
|
103
|
+
name the `ssml` and `text` files with the same name as the slot that is being
|
104
|
+
elicited. For example, in the `PlaceOrder` intent, the elicatation for `Address`
|
105
|
+
slot would have the following views
|
106
|
+
|
107
|
+
* SSML: `views/alexa/en_us/intent_handlers/place_order/elicitations/address.ssml.erb`
|
108
|
+
* Card: `views/alexa/en_us/intent_handlers/place_order/elicitations/address.text.erb`
|
109
|
+
|
110
|
+
#### SSML
|
111
|
+
|
112
|
+
##### Re-prompts
|
113
|
+
|
114
|
+
By default, there is no re-prompt SSML is added to the response.
|
115
|
+
However, re-prompt SSML can be set in the ssml view of the intent response or
|
116
|
+
a slot elicitation view with a `content_for :repromt_ssml` like this:
|
117
|
+
|
118
|
+
```erb
|
119
|
+
What is your address?
|
120
|
+
|
121
|
+
<% content_for :repromt_ssml do %>
|
122
|
+
Where would you like the pizza to be delivered?
|
123
|
+
<% end %>
|
124
|
+
```
|
125
|
+
|
126
|
+
#### Cards
|
127
|
+
|
128
|
+
##### Type & Title
|
129
|
+
|
130
|
+
By default, the card type is set to `Simple`.
|
131
|
+
To change the card type and title, use the `content_for` blocks in the `text`
|
132
|
+
view file for the response as follows:
|
133
|
+
|
134
|
+
```erb
|
135
|
+
<% content_for :card_type do %>
|
136
|
+
Simple
|
137
|
+
<% end %>
|
138
|
+
<% content_for :card_title do %>
|
139
|
+
Get your pizza
|
140
|
+
<% end %>
|
141
|
+
|
142
|
+
```
|
143
|
+
|
144
|
+
## Installation
|
145
|
+
Add this line to your application's Gemfile:
|
146
|
+
|
147
|
+
```ruby
|
148
|
+
gem 'alexa'
|
149
|
+
```
|
150
|
+
|
151
|
+
And then execute:
|
152
|
+
```bash
|
153
|
+
$ bundle
|
154
|
+
```
|
155
|
+
|
156
|
+
Or install it yourself as:
|
157
|
+
```bash
|
158
|
+
$ gem install alexa
|
159
|
+
```
|
160
|
+
|
161
|
+
## Contributing
|
162
|
+
Contribution directions go here.
|
163
|
+
|
164
|
+
## License
|
165
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'Alexa'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.md')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
|
18
|
+
load 'rails/tasks/engine.rake'
|
19
|
+
|
20
|
+
|
21
|
+
load 'rails/tasks/statistics.rake'
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
require 'bundler/gem_tasks'
|
26
|
+
|
27
|
+
require 'rake/testtask'
|
28
|
+
|
29
|
+
Rake::TestTask.new(:test) do |t|
|
30
|
+
t.libs << 'test'
|
31
|
+
t.pattern = 'test/**/*_test.rb'
|
32
|
+
t.verbose = false
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
task default: :test
|
@@ -0,0 +1,13 @@
|
|
1
|
+
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
2
|
+
// listed below.
|
3
|
+
//
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
5
|
+
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
|
6
|
+
//
|
7
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
8
|
+
// compiled file. JavaScript code in this file should be added after the last require_* statement.
|
9
|
+
//
|
10
|
+
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
|
11
|
+
// about supported directives.
|
12
|
+
//
|
13
|
+
//= require_tree .
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
10
|
+
* files in this directory. Styles in this file should be added after the last require_* statement.
|
11
|
+
* It is generally better to create a new file per style scope.
|
12
|
+
*
|
13
|
+
*= require_tree .
|
14
|
+
*= require_self
|
15
|
+
*/
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require_dependency "alexa/application_controller"
|
2
|
+
|
3
|
+
module Alexa
|
4
|
+
class IntentHandlersController < ApplicationController
|
5
|
+
include Alexa::ContextHelper
|
6
|
+
include Alexa::RenderHelper
|
7
|
+
skip_before_action :verify_authenticity_token
|
8
|
+
|
9
|
+
def create
|
10
|
+
@resp = nil
|
11
|
+
if alexa_request.valid?
|
12
|
+
if alexa_request.intent_request?
|
13
|
+
case alexa_request.intent_name
|
14
|
+
when 'AMAZON.CancelIntent'
|
15
|
+
@resp = Alexa::IntentHandlers::GoodBye.new(alexa_context).handle
|
16
|
+
when 'AMAZON.StopIntent'
|
17
|
+
@resp = Alexa::IntentHandlers::GoodBye.new(alexa_context).handle
|
18
|
+
when 'AMAZON.HelpIntent'
|
19
|
+
@resp = Alexa::IntentHandlers::Help.new(alexa_context).handle
|
20
|
+
else
|
21
|
+
@resp = "Alexa::IntentHandlers::#{alexa_request.intent_name}"
|
22
|
+
.constantize
|
23
|
+
.new(alexa_context)
|
24
|
+
.handle
|
25
|
+
end
|
26
|
+
elsif alexa_request.launch_request?
|
27
|
+
@resp = Alexa::IntentHandlers::LaunchApp.new(alexa_context).handle
|
28
|
+
elsif alexa_request.session_ended_request?
|
29
|
+
@resp = Alexa::IntentHandlers::SessionEnd.new(alexa_context).handle
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
alexa_response = @resp
|
34
|
+
respond_for_alexa_with(alexa_response)
|
35
|
+
end
|
36
|
+
|
37
|
+
helper_method def intent
|
38
|
+
@resp.intent
|
39
|
+
end
|
40
|
+
|
41
|
+
helper_method def slots
|
42
|
+
intent.slots
|
43
|
+
end
|
44
|
+
|
45
|
+
helper_method def context
|
46
|
+
alexa_context
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Alexa
|
2
|
+
module ContextHelper
|
3
|
+
def alexa_response
|
4
|
+
@_alexa_response
|
5
|
+
end
|
6
|
+
|
7
|
+
def alexa_response=(resp)
|
8
|
+
@_alexa_response = resp
|
9
|
+
end
|
10
|
+
|
11
|
+
def context_alexa_user
|
12
|
+
alexa_context.user
|
13
|
+
end
|
14
|
+
|
15
|
+
def alexa_context
|
16
|
+
@_alexa_context ||= Alexa::Context.new(alexa_request)
|
17
|
+
end
|
18
|
+
|
19
|
+
def alexa_request
|
20
|
+
@_alexa_request ||= Alexa::Request.new(request)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Alexa
|
2
|
+
module RenderHelper
|
3
|
+
def respond_for_alexa_with(alexa_response)
|
4
|
+
if alexa_response.nil?
|
5
|
+
render :not_found
|
6
|
+
else
|
7
|
+
# render json: alexa_response
|
8
|
+
if alexa_response.is_a?(Alexa::Responses::Delegate)
|
9
|
+
render json: alexa_response
|
10
|
+
else
|
11
|
+
render partial: 'alexa/response.json', locals: { response: alexa_response }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def render(*args)
|
19
|
+
options = args.extract_options!
|
20
|
+
options[:template] = "/app/views/"
|
21
|
+
super(*(args << options))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Alexa
|
2
|
+
class User < ActiveRecord::Base
|
3
|
+
self.table_name = 'alexa_users'
|
4
|
+
has_many :usages, class_name: "Alexa::Usage", foreign_key: "alexa_user_id"
|
5
|
+
|
6
|
+
def update_usage(intent_name:)
|
7
|
+
usage = usages.where(intent_name: intent_name).first_or_initialize
|
8
|
+
usage.increment_count!
|
9
|
+
end
|
10
|
+
|
11
|
+
def usage_count_for(intent_name:)
|
12
|
+
usage = usages.where(intent_name: intent_name).first
|
13
|
+
return 0 if usage.nil?
|
14
|
+
usage.count
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
{
|
2
|
+
"version": "1.0",
|
3
|
+
"sessionAttributes": <%= raw (response.intent.session || {}).to_json %>,
|
4
|
+
"response": {
|
5
|
+
"directives": <%= raw response.directives.to_json %>,
|
6
|
+
"outputSpeech": <%= raw render(partial: 'alexa/output/ssml', locals: { response: response }) %>,
|
7
|
+
"card": <%= raw render(partial: 'alexa/output/card', locals: { response: response }) %>,
|
8
|
+
<% if content_for(:repromt_ssml).present? %>
|
9
|
+
"reprompt": {
|
10
|
+
"outputSpeech": {
|
11
|
+
"type": "SSML",
|
12
|
+
"ssml": <%= raw content_for(:repromt_ssml).strip.gsub(/\n/, "").to_json %>
|
13
|
+
}
|
14
|
+
},
|
15
|
+
<% end %>
|
16
|
+
"shouldEndSession": <%= response.end_session? %>
|
17
|
+
}
|
18
|
+
}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<% content = render(
|
2
|
+
file: response.partial_path(format: :text),
|
3
|
+
locals: { response: response }
|
4
|
+
) %>
|
5
|
+
<% card_type = (content_for(:card_type) || "Simple").strip %>
|
6
|
+
|
7
|
+
<%= raw render(
|
8
|
+
partial: "alexa/output/cards/#{card_type.downcase}",
|
9
|
+
locals: {
|
10
|
+
response: response,
|
11
|
+
content: content
|
12
|
+
}
|
13
|
+
) %>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Alexa</title>
|
5
|
+
<%= stylesheet_link_tag "alexa/application", media: "all" %>
|
6
|
+
<%= javascript_include_tag "alexa/application" %>
|
7
|
+
<%= csrf_meta_tags %>
|
8
|
+
</head>
|
9
|
+
<body>
|
10
|
+
|
11
|
+
<%= yield %>
|
12
|
+
|
13
|
+
</body>
|
14
|
+
</html>
|
data/config/routes.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
module Alexa
|
2
|
+
class Context
|
3
|
+
attr_accessor :request
|
4
|
+
|
5
|
+
def initialize(alexa_request)
|
6
|
+
@request = alexa_request
|
7
|
+
end
|
8
|
+
|
9
|
+
def user
|
10
|
+
@_user ||= Alexa::User.where(
|
11
|
+
amazon_id: request.user_id
|
12
|
+
).first_or_create
|
13
|
+
end
|
14
|
+
|
15
|
+
def session
|
16
|
+
request.session
|
17
|
+
end
|
18
|
+
|
19
|
+
def locale
|
20
|
+
request.locale
|
21
|
+
end
|
22
|
+
|
23
|
+
def device
|
24
|
+
@_device ||= Alexa::Device.new(
|
25
|
+
attributes: request.params["context"]["System"]["device"],
|
26
|
+
context: self
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
def api_endpoint
|
31
|
+
request.params["context"]["System"]["apiEndpoint"]
|
32
|
+
end
|
33
|
+
|
34
|
+
def api_access_token
|
35
|
+
request.params["context"]["System"]["apiAccessToken"]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/alexa/device.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
##
|
2
|
+
# This class represents the +device+ part in the request.
|
3
|
+
#
|
4
|
+
module Alexa
|
5
|
+
class Device
|
6
|
+
attr_accessor :attributes
|
7
|
+
def initialize(attributes: {}, context:)
|
8
|
+
@attributes = attributes
|
9
|
+
@context = context
|
10
|
+
end
|
11
|
+
|
12
|
+
##
|
13
|
+
# Return device id
|
14
|
+
def id
|
15
|
+
attributes["deviceId"]
|
16
|
+
end
|
17
|
+
|
18
|
+
def audio_supported?
|
19
|
+
attributes["supportedInterfaces"].keys.include?("AudioPlayer")
|
20
|
+
end
|
21
|
+
|
22
|
+
def video_supported?
|
23
|
+
attributes["supportedInterfaces"].keys.include?("VideoApp")
|
24
|
+
end
|
25
|
+
|
26
|
+
##
|
27
|
+
# Return device location from amazon.
|
28
|
+
# Makes an API to amazon alexa's device location service and returns the
|
29
|
+
# location hash
|
30
|
+
def location
|
31
|
+
@_location ||= get_location
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def get_location
|
37
|
+
url = "#{@context.api_endpoint}/v1/devices/#{id}/settings/address"
|
38
|
+
conn = Faraday.new(url: url) do |conn|
|
39
|
+
conn.options["open_timeout"] = 2
|
40
|
+
conn.options["timeout"] = 3
|
41
|
+
conn.adapter :net_http
|
42
|
+
conn.headers["Authorization"] = "Bearer #{@context.api_access_token}"
|
43
|
+
end
|
44
|
+
begin
|
45
|
+
resp = conn.get
|
46
|
+
if resp.status == 200
|
47
|
+
return JSON.parse(resp.body)
|
48
|
+
end
|
49
|
+
rescue Faraday::ConnectionFailed, JSON::ParserError => e
|
50
|
+
Raven.capture_exception(
|
51
|
+
e,
|
52
|
+
extra: {
|
53
|
+
deviceId: id,
|
54
|
+
apiEndPoint: @context.api_endpoint
|
55
|
+
}
|
56
|
+
)
|
57
|
+
return {}
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|