codeforces 0.0.9 → 0.0.10

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