Skip to content

Commit 1f88464

Browse files
Merge pull request #6 from taylorfinnell/words
HQ Words support
2 parents 6fc7e73 + a15381f commit 1f88464

33 files changed

+1128
-16
lines changed

README.md

+17-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# hqtrivia
22

3-
A small framework for building HQ Trivia bots.
3+
A small framework for building HQ Trivia and HQ Words bots.
44

55
## Installation
66

@@ -45,19 +45,30 @@ HqTrivia.on_show(coordinator) do |show|
4545
end
4646
```
4747

48-
Other messages that can be handled include
48+
**HQ Trivia Messagges**
4949

5050
- `HqTriva::Model::Question`
5151
- `HqTriva::Model::QuestionSummary`
52-
- `HqTriva::Model::QuestionClosed`
5352
- `HqTriva::Model::QuestionFinished`
53+
- `HqTriva::Model::GameSummary`
54+
55+
**HQ Words Messaegs**
56+
57+
- `HqTriva::Model::ShowWheel`
58+
- `HqTriva::Model::HideWheel`
59+
- `HqTriva::Model::StartRound`
60+
- `HqTriva::Model::EndRound`
61+
- `HqTriva::Model::WordsGameResult`
62+
63+
**Shared Messages**
64+
65+
- `HqTriva::Model::QuestionClosed`
5466
- `HqTriva::Model::PostGame`
5567
- `HqTriva::Model::Interaction`
56-
- `HqTriva::Model::GameSummary`
68+
- `HqTriva::Model::UnknownMessage`
5769
- `HqTriva::Model::BroadcastStats`
5870
- `HqTriva::Model::BroadcastEnded`
59-
- `HqTriva::Model::UnknownMessage`
60-
71+
- `HqTriva::Model::Kicked`
6172

6273
## Contributors
6374

shard.yml

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

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

spec/data/words

+838
Large diffs are not rendered by default.

spec/hqtrivia/bot_spec.cr

+40
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,33 @@ class MyBot
1818
end
1919
end
2020

21+
class WordsBot
22+
include HqTrivia::Bot
23+
24+
getter round_starts
25+
getter round_ends
26+
getter reveals
27+
28+
def initialize(@show : HqTrivia::Model::Show, @coordinator : HqTrivia::Coordinator)
29+
super
30+
@round_starts = 0
31+
@round_ends = 0
32+
@reveals = 0
33+
end
34+
35+
def handle_message(message : HqTrivia::Model::StartRound)
36+
@round_starts += 1
37+
end
38+
39+
def handle_message(message : HqTrivia::Model::EndRound)
40+
@round_ends += 1
41+
end
42+
43+
def handle_message(message : HqTrivia::Model::LetterReveal)
44+
@reveals += 1
45+
end
46+
end
47+
2148
module HqTrivia
2249
describe Bot do
2350
it "works" do
@@ -34,5 +61,18 @@ module HqTrivia
3461
bot.prize.should eq(show.prize)
3562
bot.country.should eq("us")
3663
end
64+
65+
it "works with words" do
66+
messages = File.read("./spec/data/words").each_line.to_a
67+
show = Model::Show.new(active: true, show_type: "hq-us", game_type: "words", prize: 100, show_id: 666, start_time: Time.now)
68+
connection = Connection::Local.new(messages)
69+
70+
bot = WordsBot.new(show, LocalCoordinator.new("us"))
71+
bot.play(connection)
72+
73+
bot.reveals.should eq(16)
74+
bot.round_starts.should eq(8)
75+
bot.round_ends.should eq(8)
76+
end
3777
end
3878
end

src/hqtrivia.cr

+6
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,29 @@
11
require "./hqtrivia/*"
22

3+
# Framework for creating HQ Trivia and HQ Words bots
34
module HqTrivia
45
# :nodoc:
56
@@LOGGER = Logger.new
7+
8+
# :nodoc:
69
@@AUTH = Auth.new
710

811
# HqTrivia logging instance
912
def self.logger
1013
@@LOGGER
1114
end
1215

16+
# Set the logger to an IO
1317
def self.logger=(logger)
1418
@@LOGGER = logger
1519
end
1620

21+
# Auth singleton
1722
def self.auth
1823
@@AUTH
1924
end
2025

26+
# When an active `Show` is seen, it's yielded to the block
2127
def self.on_show(coordinator : Coordinator, blocking = true, &block : Model::Show ->)
2228
show_coordinator = ShowCoordinator.new(coordinator)
2329
show_coordinator.on_show(blocking, &block)

src/hqtrivia/auth.cr

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,23 @@
11
module HqTrivia
2+
# Manages bearer tokens for various countries
23
class Auth
4+
# Given a *country* it returns the bearer token from the ENV
35
def header(country : String)
4-
HTTP::Headers{"Authorization" => "Bearer #{token(country)}"}
6+
HTTP::Headers{
7+
"Authorization" => "Bearer #{token(country)}",
8+
"x-hq-device" => "iPhone10,4",
9+
"x-hq-client" => "iOS/1.3.27 b121",
10+
"accept-language" => "en-us",
11+
"x-hq-stk" => "MQ==",
12+
"x-hq-deviceclass" => "phone",
13+
"x-hq-timezone" => "America/Chicago",
14+
"user-agent" => "HQ-iOS/121 CFNetwork/975.0.3 Darwin/18.2.0",
15+
"x-hq-country" => "us",
16+
"x-hq-lang" => "en",
17+
}
518
end
619

20+
# :nodoc:
721
private def token(country : String)
822
ENV["#{country.upcase}_AUTHORIZATION_TOKEN"]
923
end

src/hqtrivia/bot.cr

+3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ module HqTrivia
66
def initialize(@show : HqTrivia::Model::Show, @coordinator : Coordinator)
77
end
88

9+
# Play the game on the given *connection*
910
def play(connection = HqTrivia::Connection::Hq.new)
1011
HqTrivia.logger.debug("Bot playing #{@coordinator.country} show #{@show.to_json}")
1112

@@ -50,9 +51,11 @@ module HqTrivia
5051
end
5152
{% end %}
5253

54+
# Called when an unknown message is seen
5355
protected def handle_message(message : Model::UnknownMessage)
5456
end
5557

58+
# Called with raw JSON
5659
protected def handle_message(message : String)
5760
end
5861
end

src/hqtrivia/connection/hq.cr

+5-1
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,22 @@ module HqTrivia
1717
@on_message_callback = block
1818
end
1919

20+
# Yields raw JSON to the block
2021
def on_raw_message(&block : String ->)
2122
@on_raw_message_callback = block
2223
end
2324

2425
# Connects to the HQ websocket
2526
def connect(show : Model::Show, coordinator : Coordinator)
26-
if coordinator.current_show.active
27+
show = coordinator.current_show
28+
if show && show.active
2729
open_socket(show, coordinator)
2830
else
2931
HqTrivia.logger.info "Not connecting show (#{coordinator.country}) is no longer active"
3032
end
3133
end
3234

35+
# :nodoc:
3336
private def open_socket(show, coordinator)
3437
HqTrivia.logger.debug("Connecting: #{coordinator.country}")
3538

@@ -52,6 +55,7 @@ module HqTrivia
5255
socket.run
5356
end
5457

58+
# :nodoc:
5559
private def websocket_headers(coordinator)
5660
HTTP::Headers{
5761
"x-hq-client" => "iOS/1.2.17",

src/hqtrivia/connection/interface.cr

+5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
module HqTrivia
22
module Connection
33
module Interface
4+
# Called anytime a valid websocket message is sent
45
abstract def on_message(&block : HqTrivia::Model::WebSocketMessage ->)
6+
7+
# Called on any websocket message, sending the raw json to the block
58
abstract def on_raw_message(&block : String ->)
9+
10+
# Connect to a *show* using the given *coordinator*
611
abstract def connect(show : Model::Show, coordinator : Coordinator)
712
end
813
end

src/hqtrivia/connection/local.cr

+5
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,24 @@
11
module HqTrivia
22
module Connection
3+
# Local connection, given an array of messaegs, it parses them and yields
4+
# them to the block
35
class Local
46
include Interface
57

68
def initialize(@raw_messages : Array(String))
79
end
810

11+
# Called anytime a valid websocket message is sent
912
def on_message(&block : HqTrivia::Model::WebSocketMessage ->)
1013
@on_message_callback = block
1114
end
1215

16+
# Called on any websocket message, sending the raw json to the block
1317
def on_raw_message(&block : String ->)
1418
@on_raw_message_callback = block
1519
end
1620

21+
# Connect to a *show* using the given *coordinator*
1722
def connect(show : Model::Show, coordinator : Coordinator)
1823
@raw_messages.each do |msg|
1924
@on_raw_message_callback.try &.call msg

src/hqtrivia/model/broadcast_ended.cr

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
module HqTrivia
22
module Model
33
# Sent from the server when the broadcast has ended, this can either be
4-
# because the show has actually ended, or your client lost connection.
4+
# because the show has actually ended, or your client lost connection. Used
5+
# in both Trivia and Words
56
class BroadcastEnded
67
include WebSocketMessage
78

src/hqtrivia/model/broadcast_stats.cr

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module HqTrivia
22
module Model
33
# Sent from the server containing various statistics about the broadcast at
4-
# that point in time.
4+
# that point in time. Used in both Trivia and Words
55
class BroadcastStats
66
include WebSocketMessage
77

@@ -14,6 +14,7 @@ module HqTrivia
1414
sent: Time,
1515
})
1616

17+
# Information about player counts, etc
1718
class ViewerCounts
1819
JSON.mapping({
1920
connected: Int32,

src/hqtrivia/model/end_round.cr

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
module HqTrivia
2+
module Model
3+
# Represents a round end in HQ Words
4+
class EndRound
5+
include WebSocketMessage
6+
7+
JSON.mapping({
8+
type: String,
9+
ts: Time,
10+
answer: Array(String),
11+
hint: String,
12+
show_id: {key: "showId", type: Int32},
13+
round_id: {key: "roundId", type: Int32},
14+
round_number: {key: "roundNumber", type: Int32},
15+
round_duration_ms: {key: "roundDurationMs", type: Int32},
16+
correct_answers: {key: "correctAnswers", type: Int32},
17+
incorrect_answers: {key: "incorrectAnswers", type: Int32},
18+
c: Int32,
19+
sent: Time,
20+
})
21+
end
22+
end
23+
end

src/hqtrivia/model/game_summary.cr

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ module HqTrivia
1616
sent: Time,
1717
})
1818

19+
# Winner information
1920
class Winner
2021
JSON.mapping({
2122
name: String,

src/hqtrivia/model/hide_wheel.cr

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
module HqTrivia
2+
module Model
3+
# Not sure, but used in HQ Words
4+
class HideWheel
5+
include WebSocketMessage
6+
7+
JSON.mapping({
8+
type: String,
9+
ts: Time,
10+
show_id: {key: "showId", type: Int32},
11+
round_id: {key: "roundId", type: Int32},
12+
c: Int32,
13+
sent: Time,
14+
})
15+
end
16+
end
17+
end

src/hqtrivia/model/int_coerce.cr

+4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
module HqTrivia
22
module Model
3+
# For coercing string ints to actual ints
34
class IntCoerce
5+
# Attempts to coerce a string int, ie "123" into an actual int. Works
6+
# even if it already is an Int32
47
def self.from_json(json : JSON::PullParser)
58
if val = json.read?(Int32)
69
val
@@ -9,6 +12,7 @@ module HqTrivia
912
end
1013
end
1114

15+
# Converts an Int32 back to a string
1216
def self.to_json(value, builder)
1317
builder.string value.to_s
1418
end

src/hqtrivia/model/interaction.cr

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module HqTrivia
22
module Model
33
# Sent from the server when a user intercts with the game, for instance a
4-
# chat message.
4+
# chat message. Used in both Trivia and Words
55
class Interaction
66
include WebSocketMessage
77

@@ -14,6 +14,7 @@ module HqTrivia
1414
sent: Time,
1515
})
1616

17+
# User metadata
1718
class Metadata
1819
JSON.mapping({
1920
user_id: {key: "userId", type: Int32},

src/hqtrivia/model/letter_reveal.cr

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
module HqTrivia
2+
module Model
3+
# When a letter is shown in HQ Words
4+
class LetterReveal
5+
include WebSocketMessage
6+
7+
JSON.mapping({
8+
type: String,
9+
ts: Time,
10+
show_id: {key: "showId", type: Int32},
11+
round_id: {key: "roundId", type: Int32},
12+
puzzle_state: {key: "puzzleState", type: Array(String)},
13+
reveal: String,
14+
c: Int32,
15+
sent: Time,
16+
})
17+
end
18+
end
19+
end

src/hqtrivia/model/message_types.cr

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ require "json"
22

33
module HqTrivia
44
module Model
5+
# :nodoc:
56
class MessageTypes
7+
# :nodoc:
68
MESSAGE_LIST = %w(broadcastEnded broadcastStats gameSummary interaction postGame question
7-
questionClosed questionFinished questionSummary kicked)
9+
questionClosed questionFinished questionSummary kicked endRound hideWheel letterReveal showWheel startRound wordsGameResult)
810
end
911
end
1012
end

0 commit comments

Comments
 (0)