# frozen_string_literal: true require 'net/http' class SyncError < StandardError; end class CommitLeaderboardSync attr_accessor :queue_file_path, :leaderboard_api_url, :api_secret def run(args) process_args(args) print_configuration unless File.exist?(@queue_file_path) abort('>> Commit queue file does not exist.') end unless @leaderboard_api_url.match?(URI::DEFAULT_PARSER.make_regexp) abort('>> Invalid API URL.') end commits = JSON.parse(File.read(@queue_file_path)) send_commits(commits) end private def process_args(args) if args[0].blank? abort('>> No API secret given.') end @api_secret = args[0] @queue_file_path = File.expand_path(args[1] || '~/.renuo_commit_leaderboard.json') @leaderboard_api_url = args[2] || 'https://dashboard.renuo.ch/api/v1/add_commits' end def print_configuration puts 'Running commit leaderboard sync with:' puts '-----------------------------' puts "API secret: #{@api_secret}" puts "Queue file path: #{@queue_file_path}" puts "Leaderboard API URL: #{@leaderboard_api_url}" end # rubocop:disable Metrics/MethodLength def send_commits(commits) next_queue = [] until commits.empty? commit = commits.shift payload = { commit: commit }.to_json puts 'Sending commit to leaderboard...' print_payload(payload) begin handle_response(send_commit(payload)) rescue SyncError => e puts e.message next_queue << commit end end File.write(@queue_file_path, JSON.generate(next_queue)) end # rubocop:enable Metrics/MethodLength def send_commit(payload) uri = URI(@leaderboard_api_url) http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = uri.scheme == 'https' request = Net::HTTP::Post.new(uri.path, { 'Content-Type' => 'application/json', 'Accept' => 'application/json' }) request['LEADERBOARD_SIGNATURE'] = generate_signature_for_payload(@api_secret, payload) request.body = payload http.request(request) end def print_payload(payload) puts JSON.pretty_generate(payload) end # rubocop:disable Metrics/MethodLength def handle_response(response) case response.code.to_i when 200 puts '>> Successfully sent commits to the leaderboard.' when 401 abort('>> Unauthorized. Please check your secret.') when 403 abort('>> Forbidden. Please check your secret.') when 404 abort('>> Not found. Please check the URL.') else raise SyncError, "Failed to send commits to the leaderboard:\n#{response.code} - #{response.body}" end end # rubocop:enable Metrics/MethodLength def clear_queue File.write(@queue_file_path, '[]') end def generate_signature_for_payload(secret_key, payload) signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), secret_key, payload) "sig=#{signature}" end end