goshrine_bot 0.1.1 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
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