codeforces 0.0.9 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- ZDI4YzZkNzdmN2NhZmU0ZDFmY2FiODI4MDRjZDU5ZTlhZDkxYjEzYg==
4
+ YWU0ZDA0N2FlYTY5YmM1ZTViODRlMDdkYzE4YTNkMWQ2ZjdlODE4ZA==
5
5
  data.tar.gz: !binary |-
6
- ZjQxOGUzYWU3MDE2ODI1MmNlZTkwYmY5NmJiNWNhMDg1YmVlNDFkNQ==
6
+ ZTM5MDA4NGIwZDE5ODA3ZjllMDM2MTg4MTY5YTdhYTZkOTUwYTY3Ng==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- OWRmZGNmMmJkYzZiZTUzMTA5YTg1ZDFkOTVjNjUyOGMyNGM5MjM1MDc5YmNm
10
- YjU4YmNlYjQ2YWJjZmE2YTk4NTQyNjQ0NjBlZTAxZGU3M2ZmZjI0ZmE4ZjFl
11
- MzY3NDg4YTYzNzMwNWQ0Mzc5NWU0YWJkNzI4NTdlODBhZDBkMWE=
9
+ ZGE4M2NlNTlmN2JiMDkzOThkMWVmNGI4OTRkYWU1NzIwZjFlMGI4MjczYWJi
10
+ NGZhMTE4MmU2ZGJiY2YxODgzODM2NjJiNTk0ZjU0NGJjZWZlNmI2ZWI2NTE5
11
+ ZTZiNjZhNzA4NTk1NmUwZDU2MWY3OTAzZDM3Y2I2NmVkMmQ5NWM=
12
12
  data.tar.gz: !binary |-
13
- YzAzYWZmMGRlYzUyMzk5ODRlMTg0ZTE4ZDEyMzgyYmQxMjA3ZjVkOTJmYjc4
14
- ZTcyODIyZjE2NTI4Y2M0ZGNlMTc2MzViNDA0ZjdlMzI5ODVmMGUxN2U0ODMy
15
- NjQ0MmEyYmI5ZDI5M2RjM2Y5MTlmMzQwYjhmMWRhYmExOWYxYzk=
13
+ YTY3MTJlZmJkMTM5NjNhYmMwNWFkZjliYjJlNjkyZjhmYWFjOWZiMWY3NzEx
14
+ YWI4YmYxOTAzZjdjMGQ0MDFkN2JmYWM2ZTViYjMzYzEyNjMwMDEyMWEyN2E1
15
+ Y2U5MTMyNWQzODNlYmY5OTkzZDg0YmVhMzgzZmVmY2UyMzk4MWE=
@@ -10,8 +10,8 @@ class Codeforces::Api
10
10
 
11
11
  def info(handles, options = {})
12
12
  handles = [handles] unless handles.is_a?(Array)
13
- options[:query] ||= {}
14
- options[:query][:handles] = multi_values(handles)
13
+ options[:data] ||= {}
14
+ options[:data][:handles] = multi_values(handles)
15
15
  post("user.info", options)
16
16
  end
17
17
 
@@ -2,6 +2,8 @@ require "sawyer"
2
2
  require "logger"
3
3
  require "uri"
4
4
  require "addressable/uri"
5
+ require "time"
6
+ require "digest/sha2"
5
7
  require "codeforces/api"
6
8
  require "codeforces/client"
7
9
  require "codeforces/helper"
@@ -13,11 +15,17 @@ class Codeforces::Client
13
15
 
14
16
  DEFAULT_ENDPOINT = "http://codeforces.com/api/"
15
17
  DEFAULT_PAGE_COUNT = 50
18
+ DEFAULT_API_KEY = ENV["CODEFORCES_API_KEY"]
19
+ DEFAULT_API_SECRET = ENV["CODEFORCES_API_SECRET"]
16
20
 
17
21
  attr_reader :endpoint
22
+ attr_reader :api_key
23
+ attr_reader :api_secret
18
24
 
19
- def initialize(endpoint = DEFAULT_ENDPOINT)
20
- @endpoint = endpoint
25
+ def initialize(options = {})
26
+ @endpoint = options.fetch(:endpoint, DEFAULT_ENDPOINT)
27
+ @api_key = options.fetch(:api_key, DEFAULT_API_KEY)
28
+ @api_secret = options.fetch(:api_secret, DEFAULT_API_SECRET)
21
29
  end
22
30
 
23
31
  def logger
@@ -33,25 +41,30 @@ class Codeforces::Client
33
41
  end
34
42
 
35
43
  def get(path, options = {})
36
- request_uri = ::Addressable::URI.new
37
- options[:query] ||= {}
38
- request_uri.query_values = options[:query]
39
- request(:get, "#{path}#{request_uri.query.empty? ? "" : "?#{request_uri.query}"}", options[:data], options).result
44
+ request(:get, path, options).result
40
45
  end
41
46
 
42
47
  def post(path, options = {})
43
- request_uri = ::Addressable::URI.new
44
- options[:query] ||= {}
45
- request_uri.query_values = options[:query]
46
- request(:post, path, request_uri.query).result
48
+ request(:post, path, options).result
47
49
  end
48
50
 
49
- def request(method, path, data, options = {})
50
- logger.debug "#{method.upcase} #{URI.join endpoint, path}"
51
- @last_response = agent.call(method, path, data)
51
+ def request(method, path, options = {})
52
+ request_uri = ::Addressable::URI.new
53
+ query = {}
54
+ query.merge!(options[:query]) unless options[:query].nil?
55
+ request_uri.query_values = query
56
+
57
+ enable_auth!(path, request_uri, query) unless api_key.nil?
58
+
59
+ path += "?#{request_uri.query}" unless request_uri.query.empty?
60
+
61
+ @last_response = agent.call(method, path, options[:data])
62
+
63
+ logger.debug "#{method.upcase} #{::URI.join endpoint, path}"
64
+ logger.debug "Status: #{last_response.data.status}"
52
65
 
53
66
  unless last_response.data.status === "OK"
54
- raise "Error: #{last_response.data.status}"
67
+ raise "Error: #{last_response.data.status} #{last_response.data.comment}"
55
68
  end
56
69
 
57
70
  last_response.data
@@ -109,5 +122,37 @@ class Codeforces::Client
109
122
  logger
110
123
  end
111
124
 
125
+ def enable_auth!(path, request_uri, query)
126
+ query.merge!({:time => server_time})
127
+ query.merge!({:apiKey => api_key})
128
+ request_uri.query_values = query
129
+
130
+ # calc signature
131
+ seed = api_sig_seed(654321, path, request_uri)
132
+ hash = ::Digest::SHA512.hexdigest(seed)
133
+ query.merge!({:apiSig => "654321#{hash}"})
134
+ request_uri.query_values = query
135
+
136
+ logger.debug "Enable Auth"
137
+ logger.debug "API signature seed: #{seed}"
138
+ end
139
+
140
+ def is_old_time?(t)
141
+ t.nil? || ::Time.now.to_i - t > 30
142
+ end
143
+
144
+ def server_time
145
+ return @server_time unless is_old_time?(@server_time)
146
+
147
+ logger.debug "Resolve Server Time"
148
+ @server_time = ::Net::HTTP.start("codeforces.com", 80) do |http|
149
+ ::Time.parse(http.head("/")["date"]).to_i
150
+ end
151
+ end
152
+
153
+ def api_sig_seed(rand, path, uri)
154
+ "#{rand}/#{path}?#{uri.query}##{api_secret}"
155
+ end
156
+
112
157
  end
113
158
 
@@ -1,4 +1,4 @@
1
1
  module Codeforces
2
- VERSION = "0.0.9"
2
+ VERSION = "0.0.10"
3
3
  end
4
4
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: codeforces
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.0.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hiroyuki Sano