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.
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