goshrine_bot 0.1.1 → 0.1.5

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.
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm ruby-1.9.2-p180
data/README.rdoc CHANGED
@@ -15,13 +15,12 @@ The GTP protocol is documented here: http://www.lysator.liu.se/~gunnar/gtp/
15
15
 
16
16
  * Create a normal account on goshrine for your bot.
17
17
  * Email feedback@goshrine.com with the account name, and request that it be changed to a bot account.
18
- * Edit goshrine_bot.yml with your account info.
19
- * Create a database.yml file in the following format:
18
+ * Create a goshrine_bot.yml file in the following format, substituting your bot's login info :
20
19
 
21
- botname:
22
- :login: yourbotlogin
23
- :password: yourbotpassword
24
- :gtp_cmd_line: gnugo --mode gtp --level 1
20
+ botname:
21
+ :login: yourbotlogin
22
+ :password: yourbotpassword
23
+ :gtp_cmd_line: gnugo --mode gtp --level 1
25
24
 
26
25
  * Run goshrine_bot botname
27
26
 
data/TODO.txt CHANGED
@@ -1,2 +1,3 @@
1
1
 
2
- * Shutdown idle engines (to be restarted later) to save on resources.
2
+ * Shutdown idle engines (to be restarted later) to save on resources.
3
+
data/goshrine_bot.gemspec CHANGED
@@ -21,7 +21,9 @@ SPEC = Gem::Specification.new do |s|
21
21
  END_DESCRIPTION
22
22
 
23
23
  s.add_dependency('eventmachine', '>= 0.12.10')
24
- s.add_dependency('json', '>= 1.4.6')
24
+ s.add_dependency('em-http-request', '=1.0.0.beta.3')
25
+ s.add_dependency('faye', '>= 0.5.5')
26
+ s.add_dependency('json', '>= 1.5.0')
25
27
 
26
28
  s.add_development_dependency "rspec"
27
29
 
data/goshrine_bot.yml CHANGED
@@ -1,5 +1,23 @@
1
- botname:
2
- :login: yourbotlogin
3
- :password: yourbotpass
1
+ gnugo:
2
+ :login: gnugo
3
+ :password: atk2sih
4
+ :gtp_cmd_line: gnugo --mode gtp
5
+
6
+ easy_gnugo:
7
+ :login: EasyGnuGo
8
+ :password: jasj308jrke
9
+ :gtp_cmd_line: gnugo --mode gtp --level 1
10
+ :debug: false
11
+
12
+ local_gnugo:
13
+ :server_url: http://localhost:5730
14
+ :login: gnugo
15
+ :password: testpass
4
16
  :gtp_cmd_line: gnugo --mode gtp --level 1
17
+ :debug: false
5
18
 
19
+ mogo:
20
+ :login: mogo
21
+ :password: a0ij45o3i
22
+ :gtp_cmd_line: /home/pete/MoGo_release3/mogo --19 --dontDisplay 1
23
+ :debug: false
@@ -1,4 +1,3 @@
1
-
2
1
  module GoshrineBot
3
2
 
4
3
  class Client
@@ -13,7 +12,6 @@ module GoshrineBot
13
12
  @login = options[:login]
14
13
  @gtp_cmd_line = options[:gtp_cmd_line]
15
14
  @connected = false
16
- @cookie = ""
17
15
  @games = {}
18
16
  end
19
17
 
@@ -25,30 +23,19 @@ module GoshrineBot
25
23
  @my_user_id
26
24
  end
27
25
 
28
- def parse_cookie(headers)
29
- cookies = []
30
- headers.each do |h|
31
- if h.match(/^Set-Cookie: /)
32
- pieces = h[12..-1].split("=")
33
- cookies << "#{pieces[0]}=#{pieces[1].split(";").first}";
34
- end
35
- end
36
- @cookie = cookies.join("; ") + ';'
37
- end
38
-
39
26
  def login(&blk)
40
27
  # login
41
28
  http = http_post('/sessions/create', {'login' => @login, 'password' => @password})
42
- http.callback {|response|
43
- #puts "login returned: #{response[:status]}"
44
- if response[:status].to_i == 401
29
+ http.callback {
30
+ if http.response_header.status == 401
45
31
  puts "Invalid Login or Password"
46
32
  EventMachine::stop
47
33
  else
48
- parse_cookie(response[:headers])
49
- user = JSON.parse(response[:content])
34
+ user = JSON.parse(http.response)
35
+ puts "Got #{user.inspect}"
50
36
  @queue_id = user['queue_id']
51
37
  @my_user_id = user['id']
38
+ @faye_token = user['faye_token']
52
39
  if user['user_type'] != 'bot'
53
40
  puts "Account #{user['login']} is not registered as a robot!"
54
41
  EventMachine::stop
@@ -63,36 +50,33 @@ module GoshrineBot
63
50
  }
64
51
  end
65
52
 
66
- def http_post(url, data = nil)
67
- headers = {'Accept' => 'application/json', :cookie => @cookie}
68
- if data.is_a? Hash
69
- data = data.to_params
70
- contenttype = "application/x-www-form-urlencoded"
71
- else
72
- contenttype = "application/octet-stream"
73
- end
74
- #puts "Posting #{data}"
75
- GoshrineBot::HttpClient.request(
76
- :host => @base_url.host,
77
- :port => @base_url.port,
78
- :contenttype => contenttype,
79
- :request => url,
80
- :verb => 'POST',
81
- :content => data,
82
- :custom_headers => headers)
53
+ def http_post(path, data = nil)
54
+ conn = EM::HttpRequest.new("#{@base_url}#{path}")
55
+ conn.use CookiePersist
56
+ headers = {'Accept' => 'application/json'}
57
+
58
+ http = conn.post(:head => headers, :body => data)
59
+
60
+ http.headers { |head|
61
+ CookiePersist.cookies << head[EM::HttpClient::SET_COOKIE]
62
+ }
63
+ http
83
64
  end
84
65
 
85
- def http_get(url)
86
- headers = {'Accept' => 'application/json', :cookie => @cookie}
87
- GoshrineBot::HttpClient.request(
88
- :host => @base_url.host,
89
- :port => @base_url.port,
90
- :request => url,
91
- :custom_headers => headers)
66
+ def http_get(path)
67
+ conn = EM::HttpRequest.new("#{@base_url}#{path}")
68
+ conn.use CookiePersist
69
+
70
+ http = conn.get(:head => {'Accept' => 'application/json'})
71
+
72
+ http.headers { |head|
73
+ CookiePersist.cookies << head[EM::HttpClient::SET_COOKIE]
74
+ }
75
+ http
92
76
  end
93
77
 
94
78
  def subscribe
95
- @client.subscribe("/user/private/" + @queue_id) do |m|
79
+ @faye_client.subscribe("/user/private/" + @queue_id) do |m|
96
80
  msg_type = m["type"]
97
81
  case msg_type
98
82
  when 'match_requested'
@@ -104,14 +88,18 @@ module GoshrineBot
104
88
  end
105
89
  #@msg_queue_in.push(doc)
106
90
  end
107
- @client.subscribe("/room/1") do |m|
91
+ @faye_client.subscribe("/room/1") do |m|
108
92
  #@msg_queue_in.push(doc)
109
93
  end
110
94
  end
111
95
 
112
96
  def run
113
97
  login {
114
- @client = Faye::Client.new((@base_url + '/events').to_s, :timeout => 120, :cookie => @cookie)
98
+ puts "Starting faye client"
99
+ @faye_client = Faye::Client.new((@base_url + '/events').to_s, :cookie => @cookie)
100
+ if @faye_token
101
+ @faye_client.add_extension(FayeAuthExt.new(@my_user_id, @faye_token))
102
+ end
115
103
  subscribe
116
104
  load_existing_games {
117
105
  EM::add_periodic_timer( 60 ) {
@@ -125,10 +113,9 @@ module GoshrineBot
125
113
 
126
114
  def load_existing_games(&blk)
127
115
  http = http_get('/game/active')
128
- http.callback {|response|
116
+ http.callback {
129
117
  #puts "Got #{response.inspect}"
130
- parse_cookie(response[:headers])
131
- games = JSON.parse(response[:content])
118
+ games = JSON.parse(http.response)
132
119
  puts "#{games.count} game(s) in progress"
133
120
  games.each do |game_attrs|
134
121
  game = GameInProgress.new(self)
@@ -146,10 +133,10 @@ module GoshrineBot
146
133
  def add_game(game)
147
134
  @games[game.game_id] = game
148
135
  game.make_move # does nothing if its not our turn, or the game is not started
149
- @client.subscribe("/game/private/" + game.token + '/' + @queue_id) do |m|
136
+ @faye_client.subscribe("/game/private/" + game.token + '/' + @queue_id) do |m|
150
137
  game.private_message(m)
151
138
  end
152
- @client.subscribe("/game/play/" + game.token) do |m|
139
+ @faye_client.subscribe("/game/play/" + game.token) do |m|
153
140
  game.play_message(m)
154
141
  end
155
142
  end
@@ -157,8 +144,8 @@ module GoshrineBot
157
144
  def handle_match_accept(token)
158
145
  game = GameInProgress.new(self)
159
146
  http = http_get("/g/#{token}")
160
- http.callback {|response|
161
- attrs = JSON.parse(response[:content])
147
+ http.callback {
148
+ attrs = JSON.parse(http.response)
162
149
  game.update_from_game_list(attrs)
163
150
  add_game(game)
164
151
  }
@@ -168,8 +155,8 @@ module GoshrineBot
168
155
  game = GameInProgress.new(self)
169
156
  game.update_from_match_request(request)
170
157
  http = http_get("/match/accept?id=#{game.challenge_id}")
171
- http.callback {|response|
172
- attrs = JSON.parse(response[:content])
158
+ http.callback {
159
+ attrs = JSON.parse(http.response)
173
160
  game.update_from_game_list(attrs)
174
161
  add_game(game)
175
162
  }
@@ -0,0 +1,45 @@
1
+ # Borrowed from HTTParty, a great rubygem from John Nunemaker (thanks!)
2
+ class CookieHash < Hash #:nodoc:
3
+ CLIENT_COOKIES = %w{path expires domain path secure HTTPOnly HttpOnly}
4
+
5
+ def add_cookies(value)
6
+ case value
7
+ when Hash
8
+ merge!(value)
9
+ when String
10
+ value.split('; ').each do |cookie|
11
+ array = cookie.split('=')
12
+ self[array[0].to_sym] = array[1]
13
+ end
14
+ else
15
+ raise "add_cookies only takes a Hash or a String"
16
+ end
17
+ end
18
+
19
+ def to_cookie_string
20
+ delete_if { |k, v| CLIENT_COOKIES.include?(k.to_s) }.collect { |k, v| "#{k}=#{v}" }.join("; ")
21
+ end
22
+ end
23
+
24
+ class CookiePersist
25
+ def self.cookies
26
+ Thread.current[:cookies] ||= []
27
+ end
28
+
29
+ def self.cookie_hash
30
+ CookieHash.new.tap { |hsh|
31
+ cookies.uniq.each { |c| hsh.add_cookies(c) }
32
+ }
33
+ end
34
+
35
+ def self.request(head, body)
36
+ head['cookie'] = cookie_hash.to_cookie_string
37
+ #puts "Sending cookies: #{head['cookie']}"
38
+ [head, body]
39
+ end
40
+
41
+ def self.response(resp)
42
+ resp
43
+ end
44
+ end
45
+
@@ -0,0 +1,17 @@
1
+ class FayeAuthExt
2
+ def initialize(user_id, token)
3
+ @user_id = user_id
4
+ @token = token
5
+ end
6
+
7
+ def outgoing(message, callback)
8
+ # Add ext field if it's not present
9
+ message['ext'] ||= {}
10
+
11
+ # Set the auth token
12
+ message['ext']['authToken'] = "#{@user_id}:#{@token}"
13
+
14
+ # Carry on and send the message to the server
15
+ callback.call(message)
16
+ end
17
+ end
@@ -0,0 +1,43 @@
1
+ require 'em-http'
2
+ require 'em-http/version'
3
+ require 'json'
4
+ require 'uri'
5
+
6
+ module Faye
7
+
8
+ class HttpTransport < Transport
9
+
10
+ def request(message, timeout)
11
+ retry_block = retry_block(message, timeout)
12
+
13
+ content = JSON.unparse(message)
14
+ params = {
15
+ :head => {
16
+ 'Content-Type' => 'application/json',
17
+ 'host' => URI.parse(@endpoint).host,
18
+ 'Content-Length' => content.length
19
+ },
20
+ :body => content,
21
+ :timeout => -1 # for em-http-request < 1.0
22
+ }
23
+ if EventMachine::HttpRequest::VERSION.split('.')[0].to_i >= 1
24
+ options = { # for em-http-request >= 1.0
25
+ :inactivity_timeout => 0, # connection inactivity (post-setup) timeout (0 = disable timeout)
26
+ }
27
+ request = EventMachine::HttpRequest.new(@endpoint, options).post(params)
28
+ else
29
+ request = EventMachine::HttpRequest.new(@endpoint).post(params)
30
+ end
31
+ request.callback do
32
+ begin
33
+ receive(JSON.parse(request.response))
34
+ rescue
35
+ retry_block.call
36
+ end
37
+ end
38
+ request.errback { retry_block.call }
39
+ end
40
+ end
41
+
42
+ end
43
+
@@ -38,7 +38,7 @@ module GoshrineBot
38
38
  handle_move(m["data"])
39
39
  #puts "Going to update board"
40
40
  when 'resignedBy'
41
- puts "Game resigned by #{m["data"]}"
41
+ puts "Game resigned by opponent."
42
42
  stop_gtp_client
43
43
  when 'updateForUndo'
44
44
  # TODO - handle undos?
@@ -180,8 +180,8 @@ module GoshrineBot
180
180
  rgo_coord = gtp_coord_to_goshrine_coord(response_move.upcase, board_size)
181
181
  http = @client.http_post("/game/#{token}/move/#{rgo_coord}")
182
182
  end
183
- http.callback {|response|
184
- if response[:status] == 200
183
+ http.callback {
184
+ if http.response_header.status == 200
185
185
  self.moves << [my_color, response_move]
186
186
  else
187
187
  puts "Could not make move: #{response.inspect}"
@@ -49,7 +49,7 @@ module GoshrineBot
49
49
  end
50
50
 
51
51
  def start
52
- puts "Starting GoShrine bot client: #{options[:bot_name]}."
52
+ puts "Starting GoShrine (v#{GoshrineBot::VERSION}) bot client: #{options[:bot_name]}."
53
53
 
54
54
  client = Client.new(options)
55
55
  client.run
data/lib/goshrine_bot.rb CHANGED
@@ -1,10 +1,13 @@
1
1
  require 'rubygems'
2
2
  require 'json'
3
3
  require 'eventmachine'
4
+ require 'em-http'
5
+ require 'faye'
6
+ require 'logger'
4
7
 
5
8
  module GoshrineBot
6
9
 
7
- VERSION = "0.1.1"
10
+ VERSION = "0.1.5"
8
11
 
9
12
  STDOUT.sync = true
10
13
 
@@ -14,12 +17,15 @@ module GoshrineBot
14
17
  gtp_stdio_client
15
18
  runner
16
19
  game
17
- core_ext/hash
18
- faye
19
- httpclient
20
-
20
+ cookies
21
+ faye_transport_patch
22
+ faye_auth_ext
23
+ core_ext/hash
21
24
  ].each do |lib|
22
25
  require File.join(ROOT, 'goshrine_bot', lib)
23
26
  end
24
27
 
28
+ #Faye.logger = Logger.new(STDOUT)
29
+ #Faye::Logging.log_level = :debug
30
+
25
31
  end
metadata CHANGED
@@ -1,12 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: goshrine_bot
3
3
  version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 1
8
- - 1
9
- version: 0.1.1
4
+ prerelease:
5
+ version: 0.1.5
10
6
  platform: ruby
11
7
  authors:
12
8
  - Pete Schwamb
@@ -14,8 +10,7 @@ autorequire:
14
10
  bindir: bin
15
11
  cert_chain: []
16
12
 
17
- date: 2010-10-22 00:00:00 -05:00
18
- default_executable:
13
+ date: 2011-05-18 00:00:00 Z
19
14
  dependencies:
20
15
  - !ruby/object:Gem::Dependency
21
16
  name: eventmachine
@@ -25,41 +20,53 @@ dependencies:
25
20
  requirements:
26
21
  - - ">="
27
22
  - !ruby/object:Gem::Version
28
- segments:
29
- - 0
30
- - 12
31
- - 10
32
23
  version: 0.12.10
33
24
  type: :runtime
34
25
  version_requirements: *id001
35
26
  - !ruby/object:Gem::Dependency
36
- name: json
27
+ name: em-http-request
37
28
  prerelease: false
38
29
  requirement: &id002 !ruby/object:Gem::Requirement
39
30
  none: false
40
31
  requirements:
41
- - - ">="
32
+ - - "="
42
33
  - !ruby/object:Gem::Version
43
- segments:
44
- - 1
45
- - 4
46
- - 6
47
- version: 1.4.6
34
+ version: 1.0.0.beta.3
48
35
  type: :runtime
49
36
  version_requirements: *id002
50
37
  - !ruby/object:Gem::Dependency
51
- name: rspec
38
+ name: faye
52
39
  prerelease: false
53
40
  requirement: &id003 !ruby/object:Gem::Requirement
54
41
  none: false
55
42
  requirements:
56
43
  - - ">="
57
44
  - !ruby/object:Gem::Version
58
- segments:
59
- - 0
45
+ version: 0.5.5
46
+ type: :runtime
47
+ version_requirements: *id003
48
+ - !ruby/object:Gem::Dependency
49
+ name: json
50
+ prerelease: false
51
+ requirement: &id004 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: 1.5.0
57
+ type: :runtime
58
+ version_requirements: *id004
59
+ - !ruby/object:Gem::Dependency
60
+ name: rspec
61
+ prerelease: false
62
+ requirement: &id005 !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
60
67
  version: "0"
61
68
  type: :development
62
- version_requirements: *id003
69
+ version_requirements: *id005
63
70
  description: The GoShrine bot client is a library that allows you connect a local Go playing program that speaks GTP (like gnugo) to http://goshrine.com.
64
71
  email:
65
72
  - pete@schwamb.net
@@ -70,6 +77,7 @@ extensions: []
70
77
  extra_rdoc_files: []
71
78
 
72
79
  files:
80
+ - .rvmrc
73
81
  - History.txt
74
82
  - Manifest.txt
75
83
  - README.rdoc
@@ -80,23 +88,13 @@ files:
80
88
  - goshrine_bot.yml
81
89
  - lib/goshrine_bot.rb
82
90
  - lib/goshrine_bot/client.rb
91
+ - lib/goshrine_bot/cookies.rb
83
92
  - lib/goshrine_bot/core_ext/hash.rb
84
- - lib/goshrine_bot/faye.rb
85
- - lib/goshrine_bot/faye/channel.rb
86
- - lib/goshrine_bot/faye/client.rb
87
- - lib/goshrine_bot/faye/connection.rb
88
- - lib/goshrine_bot/faye/error.rb
89
- - lib/goshrine_bot/faye/grammar.rb
90
- - lib/goshrine_bot/faye/namespace.rb
91
- - lib/goshrine_bot/faye/rack_adapter.rb
92
- - lib/goshrine_bot/faye/server.rb
93
- - lib/goshrine_bot/faye/timeouts.rb
94
- - lib/goshrine_bot/faye/transport.rb
93
+ - lib/goshrine_bot/faye_auth_ext.rb
94
+ - lib/goshrine_bot/faye_transport_patch.rb
95
95
  - lib/goshrine_bot/game.rb
96
96
  - lib/goshrine_bot/gtp_stdio_client.rb
97
- - lib/goshrine_bot/httpclient.rb
98
97
  - lib/goshrine_bot/runner.rb
99
- has_rdoc: true
100
98
  homepage: http://github.com/ps2/goshrine_bot
101
99
  licenses: []
102
100
 
@@ -110,21 +108,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
110
108
  requirements:
111
109
  - - ">="
112
110
  - !ruby/object:Gem::Version
113
- segments:
114
- - 0
115
111
  version: "0"
116
112
  required_rubygems_version: !ruby/object:Gem::Requirement
117
113
  none: false
118
114
  requirements:
119
115
  - - ">="
120
116
  - !ruby/object:Gem::Version
121
- segments:
122
- - 0
123
117
  version: "0"
124
118
  requirements: []
125
119
 
126
120
  rubyforge_project:
127
- rubygems_version: 1.3.7
121
+ rubygems_version: 1.8.2
128
122
  signing_key:
129
123
  specification_version: 3
130
124
  summary: A client to connect GTP go programs to GoShrine