internet_scrabble_club 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.ruby-version +1 -1
- data/Rakefile +1 -1
- data/bin/scraper.rb +12 -0
- data/bin/spectator.rb +91 -0
- data/internet_scrabble_club.gemspec +3 -4
- data/lib/internet_scrabble_club.rb +1 -1
- data/lib/internet_scrabble_club/client.rb +34 -30
- data/lib/internet_scrabble_club/client/callback_queue.rb +22 -0
- data/lib/internet_scrabble_club/client/middleware.rb +7 -4
- data/lib/internet_scrabble_club/client/middleware/request/echo_ping.rb +23 -0
- data/lib/internet_scrabble_club/client/middleware/request/keep_alive.rb +31 -0
- data/lib/internet_scrabble_club/client/middleware/response/emit.rb +20 -0
- data/lib/internet_scrabble_club/client/middleware/response/parse.rb +26 -0
- data/lib/internet_scrabble_club/client/middleware/response/read.rb +21 -0
- data/lib/internet_scrabble_club/client/middleware/response/transform.rb +22 -0
- data/lib/internet_scrabble_club/client/response_parsers.rb +17 -0
- data/lib/internet_scrabble_club/client/response_parsers/base.rb +78 -0
- data/lib/internet_scrabble_club/client/response_parsers/close.rb +14 -0
- data/lib/internet_scrabble_club/client/response_parsers/examine.rb +15 -0
- data/lib/internet_scrabble_club/client/response_parsers/examine/history.rb +51 -0
- data/lib/internet_scrabble_club/client/response_parsers/history.rb +17 -0
- data/lib/internet_scrabble_club/client/response_parsers/login.rb +14 -0
- data/lib/internet_scrabble_club/client/response_parsers/ping.rb +13 -0
- data/lib/internet_scrabble_club/client/response_parsers/ping/reply.rb +12 -0
- data/lib/internet_scrabble_club/client/response_parsers/seek.rb +15 -0
- data/lib/internet_scrabble_club/client/response_parsers/unseek.rb +14 -0
- data/lib/internet_scrabble_club/client/response_parsers/who.rb +13 -0
- data/lib/internet_scrabble_club/client/response_parsers/who/list.rb +16 -0
- data/lib/internet_scrabble_club/client/response_parsers/who/move.rb +14 -0
- data/lib/internet_scrabble_club/client/response_transformers.rb +2 -0
- data/lib/internet_scrabble_club/client/response_transformers/base.rb +50 -0
- data/lib/internet_scrabble_club/client/response_transformers/examine/history.rb +22 -0
- metadata +31 -32
- data/lib/internet_scrabble_club/client/extensions/authentication.rb +0 -21
- data/lib/internet_scrabble_club/client/extensions/echo_ping.rb +0 -17
- data/lib/internet_scrabble_club/client/extensions/keep_alive.rb +0 -16
- data/lib/internet_scrabble_club/client/middleware/emit.rb +0 -18
- data/lib/internet_scrabble_club/client/middleware/parse.rb +0 -24
- data/lib/internet_scrabble_club/client/middleware/read.rb +0 -19
- data/lib/internet_scrabble_club/client/middleware/transform.rb +0 -20
- data/lib/internet_scrabble_club/message_parsers.rb +0 -17
- data/lib/internet_scrabble_club/message_parsers/base.rb +0 -76
- data/lib/internet_scrabble_club/message_parsers/close.rb +0 -12
- data/lib/internet_scrabble_club/message_parsers/examine.rb +0 -13
- data/lib/internet_scrabble_club/message_parsers/examine/history.rb +0 -49
- data/lib/internet_scrabble_club/message_parsers/history.rb +0 -15
- data/lib/internet_scrabble_club/message_parsers/login.rb +0 -12
- data/lib/internet_scrabble_club/message_parsers/ping.rb +0 -11
- data/lib/internet_scrabble_club/message_parsers/ping/reply.rb +0 -11
- data/lib/internet_scrabble_club/message_parsers/seek.rb +0 -13
- data/lib/internet_scrabble_club/message_parsers/unseek.rb +0 -12
- data/lib/internet_scrabble_club/message_parsers/who.rb +0 -11
- data/lib/internet_scrabble_club/message_parsers/who/list.rb +0 -14
- data/lib/internet_scrabble_club/message_parsers/who/move.rb +0 -12
- data/lib/internet_scrabble_club/message_transformers.rb +0 -3
- data/lib/internet_scrabble_club/message_transformers/base.rb +0 -48
- data/lib/internet_scrabble_club/message_transformers/examine/history.rb +0 -32
- data/lib/internet_scrabble_club/message_transformers/history.rb +0 -14
- data/lib/internet_scrabble_club/message_transformers/who/move.rb +0 -14
- data/lib/internet_scrabble_club/multi_queue.rb +0 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dfbc285681699ddf19091435e5a89d134670f332
|
4
|
+
data.tar.gz: 249f4e0d5f7681ec4fb2bfa42c7585f411ab09e7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4f5829c3508db7f815e57fb9630b964d773dca34a51822c90d4db67ca97cdd0bc1a37e3841f681e65647df3f8e773af62fde9cca3797fd2286a199a70d367bd6
|
7
|
+
data.tar.gz: 13ac5b2ef5ff307b5045c73a2ab319b8247a447d0e27a77e5375b057fe66a98c575a2c02164ee24a3efd17902fe6c61719c59d2d90457724393dd522d96f7f1c
|
data/.gitignore
CHANGED
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
rbx-2.2.
|
1
|
+
rbx-2.2.10
|
data/Rakefile
CHANGED
@@ -1 +1 @@
|
|
1
|
-
require
|
1
|
+
require 'bundler/gem_tasks'
|
data/bin/scraper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# TODO: Move to rake task
|
2
|
+
|
3
|
+
require 'internet_scrabble_club/scraper/players'
|
4
|
+
require 'internet_scrabble_club/scraper/games'
|
5
|
+
|
6
|
+
Celluloid.shutdown_timeout = 2 * 60
|
7
|
+
|
8
|
+
InternetScrabbleClub::Scraper::Players.new('iscscraper', 'da39a3ee5e')
|
9
|
+
# InternetScrabbleClub::Scraper::Games.new('iscscraper', 'da39a3ee5e')
|
10
|
+
|
11
|
+
# TODO: Use supervisor group
|
12
|
+
sleep
|
data/bin/spectator.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
require 'celluloid'
|
6
|
+
require 'internet_scrabble_club/client'
|
7
|
+
|
8
|
+
Celluloid.logger.level = Logger::INFO
|
9
|
+
|
10
|
+
class Spectator
|
11
|
+
include Celluloid
|
12
|
+
include InternetScrabbleClub::Entities
|
13
|
+
|
14
|
+
def initialize(nickname, password)
|
15
|
+
@client = InternetScrabbleClub::Client.new
|
16
|
+
@client.authenticate(nickname, password)
|
17
|
+
@client.on_message { |message| handle_message(message) }
|
18
|
+
end
|
19
|
+
|
20
|
+
def handle_message(message)
|
21
|
+
puts message.inspect
|
22
|
+
# case message.command
|
23
|
+
# when /(UN)?SEEK/
|
24
|
+
# 10.times { |i| @client.send_message('EXAMINE', 'HISTORY', message.nickname, i) }
|
25
|
+
# when /EXAMINE/
|
26
|
+
# game_attributes = construct_game_from_message(message)
|
27
|
+
# persist_game(game_attributes)
|
28
|
+
# end
|
29
|
+
end
|
30
|
+
|
31
|
+
# private
|
32
|
+
|
33
|
+
# def persist_game(game_attributes)
|
34
|
+
# game = Game.create!(game_attributes)
|
35
|
+
# report_game_created(game)
|
36
|
+
# end
|
37
|
+
|
38
|
+
# def report_game_created(game)
|
39
|
+
# puts "(#{game.id}), at #{game.date}, by #{game.players.map(&:nickname).join(' & ')}, #{game.plays.count} plays in total."
|
40
|
+
# end
|
41
|
+
|
42
|
+
# def construct_game_from_message(message)
|
43
|
+
# players = collect_from_setup(message) do |setup|
|
44
|
+
# nickname, rating = setup.values_at(:nickname, :rating)
|
45
|
+
# player = Player.new(nickname: nickname, rating: rating)
|
46
|
+
# end
|
47
|
+
|
48
|
+
# initial_racks = collect_from_setup(message) { |setup| setup.fetch(:initial_rack) }
|
49
|
+
# final_scores = collect_from_setup(message) { |setup| setup.fetch(:final_score) }
|
50
|
+
|
51
|
+
# create_play_object = ->(play_attributes) {
|
52
|
+
# case play_attributes.delete(:type)
|
53
|
+
# when 'MOVE' then Plays::Move.new(play_attributes)
|
54
|
+
# when 'CHANGE' then Plays::Change.new(play_attributes)
|
55
|
+
# when 'PAS' then Plays::Pass.new(play_attributes)
|
56
|
+
# end
|
57
|
+
# }
|
58
|
+
|
59
|
+
# first_player_plays = message.first_player.plays.map do |play|
|
60
|
+
# create_play_object.call(play.to_h.merge(player: players[0]))
|
61
|
+
# end
|
62
|
+
|
63
|
+
# second_player_plays = message.second_player.plays.map do |play|
|
64
|
+
# create_play_object.call(play.to_h.merge(player: players[1]))
|
65
|
+
# end
|
66
|
+
|
67
|
+
# plays = first_player_plays.zip(second_player_plays)
|
68
|
+
# .flatten(1).compact.each_with_index.map { |play, index| play.index = index; play }
|
69
|
+
|
70
|
+
# { date: message.date,
|
71
|
+
# dictionary_code: message.dictionary_code,
|
72
|
+
# initial_racks: initial_racks,
|
73
|
+
# final_scores: final_scores,
|
74
|
+
# plays: plays,
|
75
|
+
# players: players
|
76
|
+
# }
|
77
|
+
# end
|
78
|
+
|
79
|
+
# def collect_from_setup(message)
|
80
|
+
# [:first, :second].collect { |prefix| yield(message.send(:"#{prefix}_player").setup) }
|
81
|
+
# end
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
if ARGV.length < 2
|
86
|
+
fail "Please provide nickname and password: bin/spectator <nickname> <password>"
|
87
|
+
end
|
88
|
+
|
89
|
+
Spectator.new(ARGV[0], ARGV[1])
|
90
|
+
|
91
|
+
sleep
|
@@ -1,7 +1,6 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
|
4
|
-
require 'internet_scrabble_club'
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require File.expand_path('../lib/internet_scrabble_club', __FILE__)
|
5
4
|
|
6
5
|
Gem::Specification.new do |spec|
|
7
6
|
spec.name = 'internet_scrabble_club'
|
@@ -6,72 +6,76 @@ require 'celluloid/autostart'
|
|
6
6
|
require 'events'
|
7
7
|
require 'middleware'
|
8
8
|
|
9
|
-
require_relative '
|
10
|
-
|
11
|
-
require_relative 'client/extensions/authentication'
|
12
|
-
require_relative 'client/extensions/echo_ping'
|
13
|
-
require_relative 'client/extensions/keep_alive'
|
14
|
-
|
15
|
-
require_relative 'client/middleware'
|
9
|
+
require_relative './client/callback_queue'
|
10
|
+
require_relative './client/middleware'
|
16
11
|
|
17
12
|
module InternetScrabbleClub
|
18
13
|
|
19
14
|
class Client
|
20
15
|
include Celluloid::IO
|
21
16
|
|
22
|
-
prepend Extensions::Authentication
|
23
|
-
prepend Extensions::EchoPing
|
24
|
-
prepend Extensions::KeepAlive
|
25
|
-
|
26
17
|
finalizer :finalize
|
27
18
|
|
28
19
|
attr_writer :socket, :middleware
|
29
20
|
attr_writer :command_callback_queue, :event_emitter
|
30
21
|
|
22
|
+
DEFAULT_HOST = '50.97.175.138'
|
23
|
+
DEFAULT_PORT = 1330
|
24
|
+
|
31
25
|
class InvalidCredentials < StandardError
|
32
26
|
def initialize(message = nil)
|
33
27
|
super(message || "Could not authenticate; the provided credentials are invalid.")
|
34
28
|
end
|
35
29
|
end
|
36
30
|
|
37
|
-
def initialize(host =
|
31
|
+
def initialize(host = DEFAULT_HOST, port = DEFAULT_PORT)
|
38
32
|
@socket = TCPSocket.new(host, port)
|
39
|
-
@command_callback_queue =
|
33
|
+
@command_callback_queue = Client::CallbackQueue.new
|
34
|
+
|
40
35
|
@event_emitter = Events::EventEmitter.new
|
41
|
-
@event_emitter.on(:
|
36
|
+
@event_emitter.on(:response) { |response| yield_command_callback(response) }
|
37
|
+
|
38
|
+
Celluloid.every(50) { send_request('SEEK') }
|
42
39
|
|
43
40
|
async.run
|
44
41
|
end
|
45
42
|
|
46
43
|
def run
|
47
|
-
loop {
|
44
|
+
loop { middleware_stack.call({}) }
|
45
|
+
end
|
46
|
+
|
47
|
+
def authenticate(nickname, password, &callback)
|
48
|
+
send_request('LOGIN', nickname, password, 1871, '?', &callback)
|
48
49
|
end
|
49
50
|
|
50
|
-
def
|
51
|
-
@event_emitter.on(:
|
51
|
+
def on_response(command_regex = /.*/, &callback)
|
52
|
+
@event_emitter.on(:response) do |response|
|
53
|
+
callback.call(response) if response[:command] =~ command_regex
|
54
|
+
end
|
52
55
|
end
|
53
56
|
|
54
|
-
def
|
55
|
-
|
56
|
-
@command_callback_queue.enqueue(command
|
57
|
-
@socket.write("\0" <<
|
57
|
+
def send_request(command, *arguments, &callback)
|
58
|
+
request = ['0', command, *arguments].join(' ')
|
59
|
+
@command_callback_queue.enqueue(command, callback)
|
60
|
+
@socket.write("\0" << request.length << request)
|
58
61
|
end
|
59
62
|
|
60
63
|
def finalize
|
61
64
|
@socket.close if @socket
|
62
65
|
end
|
63
66
|
|
64
|
-
private def yield_command_callback(
|
65
|
-
command_callback = @command_callback_queue.dequeue(
|
66
|
-
command_callback.call(
|
67
|
+
private def yield_command_callback(response)
|
68
|
+
command_callback = @command_callback_queue.dequeue(response[:command]) { proc {} }
|
69
|
+
command_callback.call(response)
|
67
70
|
end
|
68
71
|
|
69
|
-
private def
|
70
|
-
@
|
71
|
-
mw.use(Middleware::Read, @socket)
|
72
|
-
mw.use(Middleware::Parse)
|
73
|
-
mw.use(Middleware::Transform)
|
74
|
-
mw.use(Middleware::Emit, @event_emitter)
|
72
|
+
private def middleware_stack
|
73
|
+
@middleware_stack ||= ::Middleware::Builder.new.tap { |mw|
|
74
|
+
mw.use(Middleware::Response::Read, @socket)
|
75
|
+
mw.use(Middleware::Response::Parse)
|
76
|
+
mw.use(Middleware::Response::Transform)
|
77
|
+
mw.use(Middleware::Response::Emit, @event_emitter)
|
78
|
+
mw.use(Middleware::Request::EchoPing, self)
|
75
79
|
}
|
76
80
|
end
|
77
81
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module InternetScrabbleClub
|
2
|
+
class Client
|
3
|
+
|
4
|
+
class CallbackQueue
|
5
|
+
def initialize
|
6
|
+
@queues = Hash.new { Array.new }
|
7
|
+
end
|
8
|
+
|
9
|
+
def enqueue(command, callback)
|
10
|
+
@queues[command] += [callback]
|
11
|
+
end
|
12
|
+
|
13
|
+
def dequeue(command, default = nil)
|
14
|
+
return @queues[command].shift if @queues[command].any?
|
15
|
+
return yield(command) if block_given?
|
16
|
+
return default unless default.nil?
|
17
|
+
fail ArgumentError, "Missing callback handler for command #{command}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -1,4 +1,7 @@
|
|
1
|
-
require_relative 'middleware/
|
2
|
-
require_relative 'middleware/
|
3
|
-
|
4
|
-
require_relative 'middleware/
|
1
|
+
require_relative 'middleware/request/echo_ping'
|
2
|
+
require_relative 'middleware/request/keep_alive'
|
3
|
+
|
4
|
+
require_relative 'middleware/response/emit'
|
5
|
+
require_relative 'middleware/response/parse'
|
6
|
+
require_relative 'middleware/response/read'
|
7
|
+
require_relative 'middleware/response/transform'
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module InternetScrabbleClub
|
2
|
+
class Client
|
3
|
+
module Middleware
|
4
|
+
module Request
|
5
|
+
|
6
|
+
class EchoPing
|
7
|
+
def initialize(stack, client)
|
8
|
+
@stack, @client = stack, client
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
if env.fetch(:response).values_at(:command, :sub_command) == %w(PING REPLY)
|
13
|
+
@client.send_request('PING', 'REPLY')
|
14
|
+
end
|
15
|
+
|
16
|
+
@stack.call(env)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'celluloid'
|
2
|
+
require 'celluloid/logger'
|
3
|
+
|
4
|
+
module InternetScrabbleClub
|
5
|
+
class Client
|
6
|
+
module Middleware
|
7
|
+
module Request
|
8
|
+
|
9
|
+
class KeepAlive
|
10
|
+
def initialize(stack, client)
|
11
|
+
@stack, @client = stack, client
|
12
|
+
Celluloid.every(50) { keep_alive; log_keep_alive }
|
13
|
+
end
|
14
|
+
|
15
|
+
def keep_alive
|
16
|
+
@client.send_request('SEEK')
|
17
|
+
end
|
18
|
+
|
19
|
+
private def log_keep_alive
|
20
|
+
Celluloid::Logger.info("Sent keep alive command!")
|
21
|
+
end
|
22
|
+
|
23
|
+
def call(env)
|
24
|
+
@stack.call(env)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module InternetScrabbleClub
|
2
|
+
class Client
|
3
|
+
module Middleware
|
4
|
+
module Response
|
5
|
+
|
6
|
+
class Emit
|
7
|
+
def initialize(stack, event_emitter)
|
8
|
+
@stack, @event_emitter = stack, event_emitter
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
@event_emitter.emit(:response, env[:response])
|
13
|
+
@stack.call(env)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'parslet'
|
2
|
+
require 'celluloid/logger'
|
3
|
+
require_relative '../../response_parsers'
|
4
|
+
|
5
|
+
module InternetScrabbleClub
|
6
|
+
class Client
|
7
|
+
module Middleware
|
8
|
+
module Response
|
9
|
+
|
10
|
+
class Parse
|
11
|
+
def initialize(stack, response_parser = ResponseParsers::Base.new)
|
12
|
+
@stack, @response_parser = stack, response_parser
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(env)
|
16
|
+
env[:response] = @response_parser.parse(env[:response])
|
17
|
+
@stack.call(env)
|
18
|
+
rescue Parslet::ParseFailed
|
19
|
+
Celluloid::Logger.warn("Failed to parse response: #{env[:response]}")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module InternetScrabbleClub
|
2
|
+
class Client
|
3
|
+
module Middleware
|
4
|
+
module Response
|
5
|
+
|
6
|
+
class Read
|
7
|
+
def initialize(stack, socket)
|
8
|
+
@stack, @socket = stack, socket
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
response_length = @socket.getc.ord * 256 + @socket.getc.ord
|
13
|
+
env[:response] = @socket.read(response_length)
|
14
|
+
@stack.call(env)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative '../../response_transformers'
|
2
|
+
|
3
|
+
module InternetScrabbleClub
|
4
|
+
class Client
|
5
|
+
module Middleware
|
6
|
+
module Response
|
7
|
+
|
8
|
+
class Transform
|
9
|
+
def initialize(stack, response_transformer = ResponseTransformers::Base.new)
|
10
|
+
@stack, @response_transformer = stack, response_transformer
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
env[:response] = @response_transformer.apply(env[:response])
|
15
|
+
@stack.call(env)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|