lita-sonos-commander 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8df08a9fd7ffbbe94ff51a5cc8ffbb77c26ab062
|
4
|
+
data.tar.gz: 6ce9bbb507eeec26eb03b8dc5715393762e487c6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e9699b15935e3210d61dcc4414097d3a176de14674ec8fbe5849ece61e0db6b751636a006ec71890d58e4126a21f9ac7dc1603ac6fb1d1a5bcb44f4290191310
|
7
|
+
data.tar.gz: 5ee1e48df4353a064d6edde6166de70ff064891f7fd1435ce653f4ceaae92b1b579de7f8a39ce1bebd83f007fb2ca69e0d1465288b17faaa91c692bb2bb509f9
|
@@ -1,47 +1,58 @@
|
|
1
|
-
Lita::CommanderMiddleware
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
Lita::Handlers::SonosCommander.add_socket(ws)
|
1
|
+
class Lita::CommanderMiddleware
|
2
|
+
def self.build(open_sockets:)
|
3
|
+
new.build open_sockets: open_sockets
|
4
|
+
end
|
7
5
|
|
8
|
-
|
6
|
+
attr_reader :env, :open_sockets
|
7
|
+
|
8
|
+
def build(open_sockets:)
|
9
|
+
@open_sockets = open_sockets
|
10
|
+
|
11
|
+
return lambda do |env|
|
12
|
+
if Faye::WebSocket.websocket?(env)
|
13
|
+
@env = env
|
14
|
+
handle_env_has_socket
|
15
|
+
else
|
16
|
+
[
|
17
|
+
200,
|
18
|
+
{ 'Content-Type' => 'text/plain' },
|
19
|
+
['Hello from a Lita chatbot! Feed me a websocket connection!']
|
20
|
+
]
|
21
|
+
end
|
9
22
|
end
|
23
|
+
end
|
10
24
|
|
11
|
-
|
12
|
-
|
25
|
+
def build_socket(env)
|
26
|
+
ws = Faye::WebSocket.new(env)
|
27
|
+
open_sockets << ws
|
28
|
+
Lita.logger.debug "Sonos client count: #{open_sockets.count}"
|
29
|
+
ws
|
30
|
+
end
|
13
31
|
|
14
|
-
|
15
|
-
|
32
|
+
def close_socket(ws)
|
33
|
+
open_sockets.delete_if { |s| s == ws }
|
34
|
+
Lita.logger.debug "Sonos client count: #{open_sockets.count}"
|
35
|
+
p [:close, event.code, event.reason]
|
36
|
+
ws = nil
|
37
|
+
end
|
16
38
|
|
17
|
-
|
18
|
-
|
19
|
-
|
39
|
+
def handle_message(ws, event)
|
40
|
+
ws.send({ message: event.data }.to_json)
|
41
|
+
maybe_send_debug_message(ws)
|
42
|
+
end
|
20
43
|
|
21
|
-
|
22
|
-
|
44
|
+
def maybe_send_debug_message(ws)
|
45
|
+
sleep 0.5
|
46
|
+
ws.send({ message: 'WE DID IT TWITCH', command: 'echo' }.to_json)
|
47
|
+
end
|
23
48
|
|
24
|
-
|
25
|
-
|
26
|
-
|
49
|
+
def handle_env_has_socket
|
50
|
+
ws = build_socket(env)
|
51
|
+
|
52
|
+
ws.on(:message) { |event| handle_message(ws, event) }
|
53
|
+
ws.on(:close) { |event| close_socket(ws) }
|
27
54
|
|
28
55
|
# Return async Rack response
|
29
56
|
ws.rack_response
|
30
|
-
|
31
|
-
else
|
32
|
-
# Normal HTTP request
|
33
|
-
[200, {'Content-Type' => 'text/plain'}, ['Hello']]
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def register_faye(arg)
|
38
|
-
@@_sockets ||= []
|
39
|
-
middleware = robot.registry.config.http.middleware
|
40
|
-
result = middleware.use App
|
41
|
-
end
|
42
|
-
|
43
|
-
def sonos_connector(request, response)
|
44
|
-
middlewares.each do |mw|
|
45
|
-
mw.middleware.call(request.env)
|
46
57
|
end
|
47
58
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'pry'
|
2
|
+
|
1
3
|
require 'json'
|
2
4
|
require 'faye/websocket'
|
3
5
|
require 'uri'
|
@@ -6,70 +8,93 @@ module Lita
|
|
6
8
|
module Handlers
|
7
9
|
class SonosCommander < Handler
|
8
10
|
|
9
|
-
|
11
|
+
# START:socket_registry
|
12
|
+
@_sockets ||= []
|
13
|
+
|
14
|
+
def self.sockets
|
15
|
+
@_sockets
|
16
|
+
end
|
17
|
+
|
18
|
+
def sockets
|
19
|
+
self.class.sockets
|
20
|
+
end
|
21
|
+
# END:socket_registry
|
22
|
+
|
23
|
+
# START:routing
|
24
|
+
http.get '/sonos/listen', :websocket_creator
|
10
25
|
|
11
|
-
route
|
12
|
-
route
|
26
|
+
route(/^play url (http.+)/i, :handle_sonos_play_url)
|
27
|
+
route(/^speak words (.+)/i, :handle_sonos_say_text)
|
13
28
|
|
14
29
|
on :loaded, :register_faye
|
30
|
+
# END:routing
|
15
31
|
|
16
|
-
|
17
|
-
|
18
|
-
|
32
|
+
# START:create_sockets
|
33
|
+
def websocket_creator(request, _response)
|
34
|
+
# could probably skip straight to the Commander middleware
|
35
|
+
# but it's cleaner to leave them all in play.
|
36
|
+
|
37
|
+
middleware_registry.each do |mw|
|
38
|
+
mw.middleware.call(request.env)
|
39
|
+
end
|
19
40
|
end
|
41
|
+
# END:create_sockets
|
42
|
+
|
43
|
+
# START:chat_handlers
|
44
|
+
def handle_sonos_play_url(message)
|
45
|
+
return message.reply('No clients found!') unless sockets.any?
|
20
46
|
|
21
|
-
def sonos_say_text(message)
|
22
47
|
text = message.matches.last.last
|
23
|
-
|
24
|
-
end
|
48
|
+
play_url message.matches.last.last
|
25
49
|
|
26
|
-
|
27
|
-
puts "emitting #{command} \t #{data}"
|
28
|
-
sockets.each do |ws|
|
29
|
-
ws.send(
|
30
|
-
{ command: command, data: { text: data, volume: 20 } }.to_json
|
31
|
-
)
|
32
|
-
end
|
50
|
+
message.reply "Command sent: [play_url] #{text}!"
|
33
51
|
end
|
34
52
|
|
35
|
-
def
|
36
|
-
|
53
|
+
def play_url(url)
|
54
|
+
emit_message command: 'play_url', data: URI.escape(url)
|
37
55
|
end
|
38
56
|
|
39
|
-
def
|
40
|
-
|
41
|
-
end
|
57
|
+
def handle_sonos_say_text(message)
|
58
|
+
return message.reply('No clients found!') unless sockets.any?
|
42
59
|
|
43
|
-
|
44
|
-
|
45
|
-
end
|
60
|
+
text = message.matches.last.last
|
61
|
+
say_text text
|
46
62
|
|
47
|
-
|
48
|
-
puts "Tracking socket #{socket}"
|
49
|
-
@@_sockets ||= []
|
50
|
-
@@_sockets << socket
|
63
|
+
message.reply "Command sent: [play_text] #{text}!"
|
51
64
|
end
|
52
65
|
|
53
|
-
def
|
54
|
-
|
55
|
-
sockets.delete_if { |s| s == socket }
|
66
|
+
def say_text(text)
|
67
|
+
emit_message command: 'play_text', data: text
|
56
68
|
end
|
69
|
+
# END:chat_handlers
|
57
70
|
|
58
|
-
|
71
|
+
# START:faye_hookup
|
72
|
+
def register_faye(_arg)
|
73
|
+
socket_manager = Lita::CommanderMiddleware.build(open_sockets: sockets)
|
74
|
+
middleware_registry.use socket_manager
|
59
75
|
end
|
60
76
|
|
61
|
-
def
|
62
|
-
|
63
|
-
middleware = robot.registry.config.http.middleware
|
64
|
-
result = middleware.use Lita::CommanderMiddleware
|
77
|
+
def middleware_registry
|
78
|
+
robot.registry.config.http.middleware
|
65
79
|
end
|
80
|
+
# END:faye_hookup
|
66
81
|
|
67
|
-
|
68
|
-
|
69
|
-
|
82
|
+
# START:message_emission
|
83
|
+
def emit_message(command:, data:)
|
84
|
+
puts "emitting #{command} \t #{data}"
|
85
|
+
|
86
|
+
sockets.each do |ws|
|
87
|
+
ws.send serialize(command: command, text: data)
|
70
88
|
end
|
71
89
|
end
|
72
90
|
|
91
|
+
def serialize(command:, text:)
|
92
|
+
{
|
93
|
+
command: command,
|
94
|
+
data: { text: text, volume: 20 }
|
95
|
+
}.to_json
|
96
|
+
end
|
97
|
+
# END:message_emission
|
73
98
|
|
74
99
|
Lita.register_handler(self)
|
75
100
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |spec|
|
2
2
|
spec.name = 'lita-sonos-commander'
|
3
|
-
spec.version = '1.
|
3
|
+
spec.version = '1.1.0'
|
4
4
|
spec.authors = ['Daniel J. Pritchett']
|
5
5
|
spec.email = ['dpritchett@gmail.com']
|
6
6
|
spec.description = 'Control your Sonos with Lita chatbot commands'
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'date'
|
3
|
+
|
4
|
+
describe Lita::CommanderMiddleware do
|
5
|
+
let(:handler) { double 'handler' }
|
6
|
+
let(:result) { subject.build({}) }
|
7
|
+
|
8
|
+
it 'returns a lambda' do
|
9
|
+
result = subject.class.build(open_sockets: [])
|
10
|
+
expect(result.is_a?(Proc)).to be_truthy
|
11
|
+
end
|
12
|
+
end
|
@@ -11,51 +11,104 @@ describe Lita::Handlers::SonosCommander, lita_handler: true do
|
|
11
11
|
describe 'routes' do
|
12
12
|
it {
|
13
13
|
is_expected.to route_http(:get, '/sonos/listen')
|
14
|
-
.to(:
|
14
|
+
.to(:websocket_creator)
|
15
15
|
}
|
16
16
|
|
17
|
-
it {
|
18
|
-
.to(
|
17
|
+
it {
|
18
|
+
is_expected.to(route('Lita play url http://zombo.com')
|
19
|
+
.to(:handle_sonos_play_url))
|
20
|
+
}
|
21
|
+
it {
|
22
|
+
is_expected.to(route('Lita play url https://www.youtube.com/watch?v=dQw4w9WgXcQ')
|
23
|
+
.to(:handle_sonos_play_url))
|
24
|
+
}
|
25
|
+
it {
|
26
|
+
is_expected.to(route('Lita speak words i like turtles')
|
27
|
+
.to(:handle_sonos_say_text))
|
28
|
+
}
|
29
|
+
|
30
|
+
it { is_expected.to route_event(:loaded).to(:register_faye) }
|
19
31
|
end
|
20
32
|
# END:routes
|
21
33
|
|
22
|
-
describe '
|
23
|
-
|
24
|
-
|
34
|
+
describe 'sending messages to clients' do
|
35
|
+
let(:client) { double('socket client') }
|
36
|
+
before { subject.stub(:sockets).and_return [client] }
|
37
|
+
|
38
|
+
it 'should :send some commanding json to the client' do
|
39
|
+
expect(client).to receive(:send).with(/play_url.+http.+volume/)
|
40
|
+
|
41
|
+
subject.play_url 'http://bana.nas'
|
25
42
|
end
|
26
|
-
end
|
27
|
-
# START:save_message
|
28
|
-
describe ':save_message' do
|
29
|
-
let(:body) { 'hello, alexa!' }
|
30
|
-
it 'saves a message and acknowledges' do
|
31
|
-
result = subject.save_message(username: 'dpritchett', message: body)
|
32
43
|
|
33
|
-
|
44
|
+
it 'should :send some commanding json to the client' do
|
45
|
+
expect(client).to receive(:send).with(/play_text.+turtles.+volume/)
|
46
|
+
|
47
|
+
subject.say_text 'i like turtles'
|
34
48
|
end
|
35
49
|
|
36
|
-
it
|
50
|
+
it 'can grab a message from chat and store it' do
|
51
|
+
send_message 'lita speak words i like turtles'
|
52
|
+
response = replies.last
|
53
|
+
|
54
|
+
expect(response).to match(/No clients found/i)
|
55
|
+
end
|
37
56
|
end
|
38
|
-
# END:save_message
|
39
57
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
58
|
+
describe 'socket registry' do
|
59
|
+
let(:sockets) { subject.sockets }
|
60
|
+
it 'has a socket registry shared amongst instances of the handler' do
|
61
|
+
sockets << 'banana'
|
62
|
+
another_one = Lita::Handlers::SonosCommander.new({})
|
63
|
+
|
64
|
+
expect(another_one.sockets).to include('banana')
|
44
65
|
end
|
45
66
|
|
46
|
-
it '
|
47
|
-
|
48
|
-
|
67
|
+
it 'allows addition and deletion to the socket registry via array methods' do
|
68
|
+
canary = rand(10_000).to_s
|
69
|
+
sockets << canary
|
70
|
+
expect(sockets).to include(canary)
|
71
|
+
|
72
|
+
sockets.delete_if { |socket| socket.eql? canary }
|
73
|
+
expect(sockets).to_not include(canary)
|
49
74
|
end
|
50
75
|
end
|
51
|
-
# END:alexify
|
52
76
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
77
|
+
describe 'text serializer' do
|
78
|
+
it 'creates a json payload' do
|
79
|
+
result = subject.serialize(command: 'phone_call', text: 'call your mother')
|
80
|
+
|
81
|
+
deserialized = JSON.parse(result)
|
82
|
+
|
83
|
+
expect(deserialized.fetch('command')).to eq 'phone_call'
|
84
|
+
expect(deserialized.dig('data', 'volume')).to_not be_falsey
|
85
|
+
end
|
58
86
|
end
|
59
87
|
|
60
|
-
|
88
|
+
describe 'socket middleware registration' do
|
89
|
+
let(:middlewares) { double 'middlewares' }
|
90
|
+
before { subject.stub(:middleware_registry).and_return(middlewares) }
|
91
|
+
|
92
|
+
let(:commander) { double 'commander' }
|
93
|
+
before { Lita::CommanderMiddleware.stub(:build).and_return(commander) }
|
94
|
+
|
95
|
+
it 'should register the commander middleware' do
|
96
|
+
expect(middlewares).to receive(:use).with(commander)
|
97
|
+
|
98
|
+
subject.register_faye(nil)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe ':websocket_creator' do
|
103
|
+
let(:request) { double 'request' }
|
104
|
+
let(:request_env) { double 'request' }
|
105
|
+
let(:middleware) { double 'middleware' }
|
106
|
+
|
107
|
+
before { subject.stub_chain(:middleware_registry, :each).and_return [middleware] }
|
108
|
+
before { request.stub(:env).and_return(request_env) }
|
61
109
|
|
110
|
+
it 'passes incoming any request environments to registered middlewares' do
|
111
|
+
subject.websocket_creator(request, nil)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lita-sonos-commander
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel J. Pritchett
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-04-
|
11
|
+
date: 2018-04-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: lita
|
@@ -156,6 +156,7 @@ files:
|
|
156
156
|
- lib/lita/handlers/sonos_commander.rb
|
157
157
|
- lita-sonos-commander.gemspec
|
158
158
|
- locales/en.yml
|
159
|
+
- spec/lita/commander_middleware_spec.rb
|
159
160
|
- spec/lita/handlers/sonos_commander_spec.rb
|
160
161
|
- spec/spec_helper.rb
|
161
162
|
homepage: https://github.com/dpritchett/lita-sonos-commander
|
@@ -184,5 +185,6 @@ signing_key:
|
|
184
185
|
specification_version: 4
|
185
186
|
summary: Control your Sonos with Lita chatbot commands
|
186
187
|
test_files:
|
188
|
+
- spec/lita/commander_middleware_spec.rb
|
187
189
|
- spec/lita/handlers/sonos_commander_spec.rb
|
188
190
|
- spec/spec_helper.rb
|