internet_scrabble_club 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.ruby-version +1 -1
  4. data/Rakefile +1 -1
  5. data/bin/scraper.rb +12 -0
  6. data/bin/spectator.rb +91 -0
  7. data/internet_scrabble_club.gemspec +3 -4
  8. data/lib/internet_scrabble_club.rb +1 -1
  9. data/lib/internet_scrabble_club/client.rb +34 -30
  10. data/lib/internet_scrabble_club/client/callback_queue.rb +22 -0
  11. data/lib/internet_scrabble_club/client/middleware.rb +7 -4
  12. data/lib/internet_scrabble_club/client/middleware/request/echo_ping.rb +23 -0
  13. data/lib/internet_scrabble_club/client/middleware/request/keep_alive.rb +31 -0
  14. data/lib/internet_scrabble_club/client/middleware/response/emit.rb +20 -0
  15. data/lib/internet_scrabble_club/client/middleware/response/parse.rb +26 -0
  16. data/lib/internet_scrabble_club/client/middleware/response/read.rb +21 -0
  17. data/lib/internet_scrabble_club/client/middleware/response/transform.rb +22 -0
  18. data/lib/internet_scrabble_club/client/response_parsers.rb +17 -0
  19. data/lib/internet_scrabble_club/client/response_parsers/base.rb +78 -0
  20. data/lib/internet_scrabble_club/client/response_parsers/close.rb +14 -0
  21. data/lib/internet_scrabble_club/client/response_parsers/examine.rb +15 -0
  22. data/lib/internet_scrabble_club/client/response_parsers/examine/history.rb +51 -0
  23. data/lib/internet_scrabble_club/client/response_parsers/history.rb +17 -0
  24. data/lib/internet_scrabble_club/client/response_parsers/login.rb +14 -0
  25. data/lib/internet_scrabble_club/client/response_parsers/ping.rb +13 -0
  26. data/lib/internet_scrabble_club/client/response_parsers/ping/reply.rb +12 -0
  27. data/lib/internet_scrabble_club/client/response_parsers/seek.rb +15 -0
  28. data/lib/internet_scrabble_club/client/response_parsers/unseek.rb +14 -0
  29. data/lib/internet_scrabble_club/client/response_parsers/who.rb +13 -0
  30. data/lib/internet_scrabble_club/client/response_parsers/who/list.rb +16 -0
  31. data/lib/internet_scrabble_club/client/response_parsers/who/move.rb +14 -0
  32. data/lib/internet_scrabble_club/client/response_transformers.rb +2 -0
  33. data/lib/internet_scrabble_club/client/response_transformers/base.rb +50 -0
  34. data/lib/internet_scrabble_club/client/response_transformers/examine/history.rb +22 -0
  35. metadata +31 -32
  36. data/lib/internet_scrabble_club/client/extensions/authentication.rb +0 -21
  37. data/lib/internet_scrabble_club/client/extensions/echo_ping.rb +0 -17
  38. data/lib/internet_scrabble_club/client/extensions/keep_alive.rb +0 -16
  39. data/lib/internet_scrabble_club/client/middleware/emit.rb +0 -18
  40. data/lib/internet_scrabble_club/client/middleware/parse.rb +0 -24
  41. data/lib/internet_scrabble_club/client/middleware/read.rb +0 -19
  42. data/lib/internet_scrabble_club/client/middleware/transform.rb +0 -20
  43. data/lib/internet_scrabble_club/message_parsers.rb +0 -17
  44. data/lib/internet_scrabble_club/message_parsers/base.rb +0 -76
  45. data/lib/internet_scrabble_club/message_parsers/close.rb +0 -12
  46. data/lib/internet_scrabble_club/message_parsers/examine.rb +0 -13
  47. data/lib/internet_scrabble_club/message_parsers/examine/history.rb +0 -49
  48. data/lib/internet_scrabble_club/message_parsers/history.rb +0 -15
  49. data/lib/internet_scrabble_club/message_parsers/login.rb +0 -12
  50. data/lib/internet_scrabble_club/message_parsers/ping.rb +0 -11
  51. data/lib/internet_scrabble_club/message_parsers/ping/reply.rb +0 -11
  52. data/lib/internet_scrabble_club/message_parsers/seek.rb +0 -13
  53. data/lib/internet_scrabble_club/message_parsers/unseek.rb +0 -12
  54. data/lib/internet_scrabble_club/message_parsers/who.rb +0 -11
  55. data/lib/internet_scrabble_club/message_parsers/who/list.rb +0 -14
  56. data/lib/internet_scrabble_club/message_parsers/who/move.rb +0 -12
  57. data/lib/internet_scrabble_club/message_transformers.rb +0 -3
  58. data/lib/internet_scrabble_club/message_transformers/base.rb +0 -48
  59. data/lib/internet_scrabble_club/message_transformers/examine/history.rb +0 -32
  60. data/lib/internet_scrabble_club/message_transformers/history.rb +0 -14
  61. data/lib/internet_scrabble_club/message_transformers/who/move.rb +0 -14
  62. 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: dcfdf5998716687a13e1783db2b02bfce70d52df
4
- data.tar.gz: 778e23b7e995aaa4828c6a76ab2578bcced7d7b2
3
+ metadata.gz: dfbc285681699ddf19091435e5a89d134670f332
4
+ data.tar.gz: 249f4e0d5f7681ec4fb2bfa42c7585f411ab09e7
5
5
  SHA512:
6
- metadata.gz: 63b67073d577c4d9ab3b4df1409674f3f0fdbb8000579d16c3fd2caf545aa11699224c608310921ba90d4bc4f5613ce847b6df5571e21660fff917ecede1ee3f
7
- data.tar.gz: 6917a3c52eca3a6eb058ea7a301c1b871f0c6bc8fc96c023862d1b41df9440705ae1a5c3bb7cfcda19781c7bcc8101637702e3b347c8a01bfced349bbacad600
6
+ metadata.gz: 4f5829c3508db7f815e57fb9630b964d773dca34a51822c90d4db67ca97cdd0bc1a37e3841f681e65647df3f8e773af62fde9cca3797fd2286a199a70d367bd6
7
+ data.tar.gz: 13ac5b2ef5ff307b5045c73a2ab319b8247a447d0e27a77e5375b057fe66a98c575a2c02164ee24a3efd17902fe6c61719c59d2d90457724393dd522d96f7f1c
data/.gitignore CHANGED
@@ -3,6 +3,7 @@
3
3
  .bundle
4
4
  .config
5
5
  .yardoc
6
+ .Rhistory
6
7
  Gemfile.lock
7
8
  InstalledFiles
8
9
  _yardoc
@@ -15,3 +16,4 @@ spec/reports
15
16
  test/tmp
16
17
  test/version_tmp
17
18
  tmp
19
+ data/
@@ -1 +1 @@
1
- rbx-2.2.6
1
+ rbx-2.2.10
data/Rakefile CHANGED
@@ -1 +1 @@
1
- require "bundler/gem_tasks"
1
+ require 'bundler/gem_tasks'
@@ -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
@@ -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
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
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'
@@ -1,3 +1,3 @@
1
1
  module InternetScrabbleClub
2
- VERSION = '0.1.1'
2
+ VERSION = '0.2.0'
3
3
  end
@@ -6,72 +6,76 @@ require 'celluloid/autostart'
6
6
  require 'events'
7
7
  require 'middleware'
8
8
 
9
- require_relative 'multi_queue'
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 = '50.97.175.138', port = 1330)
31
+ def initialize(host = DEFAULT_HOST, port = DEFAULT_PORT)
38
32
  @socket = TCPSocket.new(host, port)
39
- @command_callback_queue = MultiQueue.new
33
+ @command_callback_queue = Client::CallbackQueue.new
34
+
40
35
  @event_emitter = Events::EventEmitter.new
41
- @event_emitter.on(:message) { |message| yield_command_callback(message) }
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 { middleware.call({}) }
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 on_message(&callback)
51
- @event_emitter.on(:message, &callback)
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 send_message(command, *arguments, &callback)
55
- message = ['0', command, *arguments].join(' ')
56
- @command_callback_queue.enqueue(command.downcase.to_sym, callback)
57
- @socket.write("\0" << message.length << message)
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(message)
65
- command_callback = @command_callback_queue.dequeue(message.command) { proc {} }
66
- command_callback.call(message)
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 middleware
70
- @middleware ||= ::Middleware::Builder.new.tap { |mw|
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/emit'
2
- require_relative 'middleware/parse'
3
- require_relative 'middleware/read'
4
- require_relative 'middleware/transform'
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