Skip to content

Commit 7c3f6cd

Browse files
Merge pull request #3 from taylorfinnell/various-tweaks
support multiple countries
2 parents 2e21f88 + d07fcdc commit 7c3f6cd

18 files changed

+178
-85
lines changed

README.md

+8-3
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ class WordFrequencyBot
2424
2525
getter words
2626
27-
def initialize
27+
def initialize(@show : HqTrivia::Model::Show, @coordinator : HqTrivia::Coordinator)
28+
super
2829
@words = {} of String => Int32
2930
end
3031
@@ -36,8 +37,12 @@ class WordFrequencyBot
3637
end
3738
end
3839
39-
bot = WordFrequencyBot.new
40-
bot.play # blocks until there is an active show, pass false to #play for non blocking
40+
coordinator = HqTrivia::HqCoordinator.new("us")
41+
HqTrivia.on_show(coordinator) do |show|
42+
bot = WordFrequencyBot.new(show, coordinator)
43+
44+
bot.play
45+
end
4146
```
4247

4348
Other messages that can be handled include

shard.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: hqtrivia
2-
version: 0.1.1
2+
version: 0.2.0
33

44
authors:
55
- Taylor Finnell <[email protected]>

spec/hqtrivia/bot_spec.cr

+6-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ class MyBot
55

66
getter words
77

8-
def initialize
8+
def initialize(@show : HqTrivia::Model::Show, @coordinator : HqTrivia::Coordinator)
9+
super
910
@words = {} of String => Int32
1011
end
1112

@@ -21,16 +22,17 @@ module HqTrivia
2122
describe Bot do
2223
it "works" do
2324
messages = File.read("./spec/data/fullgame").each_line.to_a
24-
show = Model::Show.new(active: true, prize: 100, show_id: 666, start_time: Time.now)
25-
connection = Connection::Local.new(messages, show)
25+
show = Model::Show.new(active: true, show_type: "hq-us", prize: 100, show_id: 666, start_time: Time.now)
26+
connection = Connection::Local.new(messages)
2627

27-
bot = MyBot.new
28+
bot = MyBot.new(show, LocalCoordinator.new("us"))
2829
bot.play(connection)
2930

3031
bot.words.values.max.should eq(328)
3132
bot.start_time.should eq(show.start_time)
3233
bot.show_id.should eq(show.show_id)
3334
bot.prize.should eq(show.prize)
35+
bot.country.should eq("us")
3436
end
3537
end
3638
end

spec/hqtrivia/connection/local_spec.cr

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ module HqTrivia::Connection
77
{"type":"interaction","ts":"2018-05-02T18:56:04.465Z","itemId":"chat","userId":5169584,"metadata":{"userId":5169584,"message":"🧠","avatarUrl":"https://d2xu1hdomh3nrx.cloudfront.net/72x72/default_avatars/Untitled-1_0001_blue.png","interaction":"chat","username":"kboogie1"},"sent":"2018-05-02T18:56:04.466Z"}
88
MSG
99

10-
show = Model::Show.new(active: true, prize: 100, show_id: 666, start_time: Time.now)
11-
local = Local.new([msg], show)
10+
show = Model::Show.new(active: true, show_type: "hq-us", prize: 100, show_id: 666, start_time: Time.now)
11+
local = Local.new([msg])
1212
local.on_message do |msg|
1313
msg.should be_a(Model::Interaction)
1414
end
15-
local.connect
15+
local.connect(show, LocalCoordinator.new("us"))
1616
end
1717
end
1818
end
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
require "../../spec_helper"
2+
3+
module HqTrivia
4+
describe ShowCoordinator do
5+
it "yields the show if it is active" do
6+
coordinator = LocalCoordinator.new("us", active: true)
7+
show_coord = ShowCoordinator.new(coordinator)
8+
show_coord.on_show do |show|
9+
show.should be_a(Model::Show)
10+
end
11+
end
12+
13+
it "does not yield the show if it is inactive" do
14+
coordinator = LocalCoordinator.new("us", active: false)
15+
show_coord = ShowCoordinator.new(coordinator)
16+
show_coord.on_show(blocking: false) do |show|
17+
raise "bad"
18+
end
19+
end
20+
end
21+
end

spec/hqtrivia_spec.cr

+15
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,19 @@
11
require "./spec_helper"
22

33
describe HqTrivia do
4+
it "yields active shows" do
5+
coordinator = HqTrivia::LocalCoordinator.new("us", active: true)
6+
7+
HqTrivia.on_show(coordinator) do |show|
8+
show.should be_a(HqTrivia::Model::Show)
9+
end
10+
end
11+
12+
it "does not yield inactive shows" do
13+
coordinator = HqTrivia::LocalCoordinator.new("us", active: false)
14+
15+
HqTrivia.on_show(coordinator, blocking: false) do |show|
16+
raise "should not have yielded"
17+
end
18+
end
419
end

src/hqtrivia.cr

+14
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,23 @@ require "./hqtrivia/*"
33
module HqTrivia
44
# :nodoc:
55
@@LOGGER = Logger.new
6+
@@AUTH = Auth.new
67

78
# HqTrivia logging instance
89
def self.logger
910
@@LOGGER
1011
end
12+
13+
def self.logger=(logger)
14+
@@LOGGER = logger
15+
end
16+
17+
def self.auth
18+
@@AUTH
19+
end
20+
21+
def self.on_show(coordinator : Coordinator, blocking = true, &block : Model::Show ->)
22+
show_coordinator = ShowCoordinator.new(coordinator)
23+
show_coordinator.on_show(blocking, &block)
24+
end
1125
end

src/hqtrivia/auth.cr

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module HqTrivia
2+
class Auth
3+
def header(country : String)
4+
HTTP::Headers{"Authorization" => "Bearer #{token(country)}"}
5+
end
6+
7+
private def token(country : String)
8+
ENV["#{country.upcase}_AUTHORIZATION_TOKEN"]
9+
end
10+
end
11+
end

src/hqtrivia/bot.cr

+12-9
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@ require "./model/message_types"
33
module HqTrivia
44
# The HqTrivia bot, given a connection it has call backs for messages received
55
module Bot
6-
@show : HqTrivia::Model::Show?
6+
def initialize(@show : HqTrivia::Model::Show, @coordinator : Coordinator)
7+
end
78

8-
def play(connection = Connection::Hq.new, blocking = true, record_network = false)
9-
connection.on_show do |show|
10-
@show = show
11-
end
9+
def play(connection = HqTrivia::Connection::Hq.new)
10+
HqTrivia.logger.debug("Bot playing #{@coordinator.country} show #{@show.to_json}")
1211

1312
connection.on_message do |message|
1413
handle_message(message)
@@ -18,22 +17,26 @@ module HqTrivia
1817
handle_message(json)
1918
end
2019

21-
connection.connect(blocking, record_network)
20+
connection.connect(@show, @coordinator)
2221
end
2322

2423
# The start time of the current show, nil if no show is going
2524
def start_time
26-
@show.try &.start_time
25+
@show.start_time
2726
end
2827

2928
# The id of the current show, nil if no show is going
3029
def show_id
31-
@show.try &.show_id
30+
@show.show_id
3231
end
3332

3433
# The prize of the current show, nil if no show is going
3534
def prize
36-
@show.try &.prize
35+
@show.prize
36+
end
37+
38+
def country
39+
@coordinator.country
3740
end
3841

3942
{% for msg, index in Model::MessageTypes.constant("MESSAGE_LIST") %}

src/hqtrivia/connection/hq.cr

+12-53
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@ module HqTrivia
99
class Hq
1010
include Interface
1111

12-
class HttpException < Exception
13-
end
14-
1512
# Yields a `Model::WebSocketMessage`
1613
def on_message(&block : HqTrivia::Model::WebSocketMessage ->)
1714
@on_message_callback = block
@@ -21,34 +18,24 @@ module HqTrivia
2118
@on_raw_message_callback = block
2219
end
2320

24-
# Yields a `Model::Show` if a show is active, otherwise nil
25-
def on_show(&block : HqTrivia::Model::Show? ->)
26-
@on_show = block
27-
end
28-
2921
# Connects to the HQ websocket
30-
def connect(blocking = true, record_network = false)
31-
while show = current_show
32-
@on_show.try &.call show
33-
34-
break if show.active || !blocking
35-
36-
HqTrivia.logger.debug("No active show")
37-
sleep 5
22+
def connect(show : Model::Show, coordinator : Coordinator)
23+
if coordinator.current_show.active
24+
open_socket(show, coordinator)
25+
else
26+
HqTrivia.logger.info "Not connecting show (#{coordinator.country}) is no longer active"
3827
end
39-
40-
open_socket(show, record_network) if show.active
4128
end
4229

43-
private def open_socket(show, record_network)
44-
HqTrivia.logger.debug("Connecting...")
30+
private def open_socket(show, coordinator)
31+
HqTrivia.logger.debug("Connecting: #{coordinator.country}")
4532

46-
socket = HTTP::WebSocket.new(show.socket_url.not_nil!, headers: websocket_headers)
33+
socket = HTTP::WebSocket.new(show.socket_url.not_nil!, headers: websocket_headers(coordinator))
4734

48-
HqTrivia.logger.debug("Connected...")
35+
HqTrivia.logger.debug("Connected: #{coordinator.country}")
4936

5037
socket.on_close do
51-
connect(false) # don't block, either the game is still active or it is not
38+
connect(show, coordinator)
5239
end
5340

5441
socket.on_message do |json|
@@ -59,43 +46,15 @@ module HqTrivia
5946
socket.run
6047
end
6148

62-
private def current_show
63-
connection_failed = ->(ex : Exception) do
64-
HqTrivia.logger.debug("Connection to HQ server failed...retrying. #{ex}")
65-
end
66-
67-
retryable(on: HttpException | Socket::Error, tries: 5, wait: 1, callback: connection_failed) do
68-
resp = HTTP::Client.get(current_show_url, headers: authorization_header)
69-
70-
if (200..299).includes?(resp.status_code)
71-
Model::Show.from_json(resp.body)
72-
else
73-
raise HttpException.new("#{resp.body} (#{resp.status_code})")
74-
end
75-
end
76-
end
77-
78-
private def current_show_url
79-
"https://api-quiz.hype.space/shows/now?type=hq"
80-
end
81-
82-
private def authorization_header
83-
HTTP::Headers{"Authorization" => "Bearer #{authorization_token}"}
84-
end
85-
86-
private def authorization_token
87-
ENV["AUTHORIZATION_TOKEN"]?
88-
end
89-
90-
private def websocket_headers
49+
private def websocket_headers(coordinator)
9150
HTTP::Headers{
9251
"x-hq-client" => "iOS/1.2.17",
9352
"x-hq-stk" => "MQ==",
9453
"Host" => "api-quiz.hype.space",
9554
"Connection" => "Keep-Alive",
9655
"Accept-Encoding" => "gzip",
9756
"User-Agent" => "okhttp/3.8.0",
98-
}.merge!(authorization_header)
57+
}.merge!(HqTrivia.auth.header(coordinator.country))
9958
end
10059
end
10160
end

src/hqtrivia/connection/interface.cr

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
module HqTrivia
22
module Connection
33
module Interface
4-
abstract def on_show(&block : HqTrivia::Model::Show? ->)
54
abstract def on_message(&block : HqTrivia::Model::WebSocketMessage ->)
65
abstract def on_raw_message(&block : String ->)
7-
abstract def connect(async = false, record_network = false)
6+
abstract def connect(show : Model::Show, coordinator : Coordinator)
87
end
98
end
109
end

src/hqtrivia/connection/local.cr

+2-8
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ module HqTrivia
33
class Local
44
include Interface
55

6-
def initialize(@raw_messages : Array(String), @show : Model::Show)
6+
def initialize(@raw_messages : Array(String))
77
end
88

99
def on_message(&block : HqTrivia::Model::WebSocketMessage ->)
@@ -14,13 +14,7 @@ module HqTrivia
1414
@on_raw_message_callback = block
1515
end
1616

17-
def on_show(&block : HqTrivia::Model::Show? ->)
18-
@on_show = block
19-
end
20-
21-
def connect(blocking = true, record_network = false)
22-
@on_show.try &.call @show
23-
17+
def connect(show : Model::Show, coordinator : Coordinator)
2418
@raw_messages.each do |msg|
2519
@on_raw_message_callback.try &.call msg
2620
@on_message_callback.try &.call Model::RawWebSocketMessage.decode(msg)

src/hqtrivia/model/show.cr

+4-1
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,16 @@ module HqTrivia
1010
start_time: {type: Time?, key: "startTime"},
1111
broadcast: Broadcast?,
1212
prize: Int32?,
13+
show_type: {type: String?, key: "showType"},
1314
})
1415

1516
def initialize(@active : Bool, @show_id : Int32?, @start_time : Time?,
16-
@prize : Int32)
17+
@prize : Int32, @show_type : String?)
1718
end
1819

1920
def socket_url
21+
raise "Show not active" unless @active
22+
2023
@broadcast.try &.socket_url
2124
end
2225
end

src/hqtrivia/show_coordinator.cr

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
require "./show_coordinator/coordinator"
2+
require "./show_coordinator/*"
3+
4+
module HqTrivia
5+
class ShowCoordinator
6+
def initialize(@coordinator : Coordinator)
7+
end
8+
9+
def on_show(blocking = true, &block : Model::Show ->)
10+
while show = @coordinator.current_show
11+
HqTrivia.logger.debug("Show: #{show.to_json}")
12+
13+
if show.active
14+
return yield show
15+
elsif !blocking
16+
break
17+
else
18+
HqTrivia.logger.debug("#{self.class.name}: No active '#{@coordinator.country}' show")
19+
sleep 5
20+
end
21+
end
22+
end
23+
end
24+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module HqTrivia
2+
abstract class Coordinator
3+
getter country
4+
5+
def initialize(@country : String)
6+
end
7+
8+
abstract def current_show
9+
end
10+
end

0 commit comments

Comments
 (0)