From 40939795096c0b7a1791d71d920b84ff283fb550 Mon Sep 17 00:00:00 2001
From: Luke Shumaker <shumakl@purdue.edu>
Date: Fri, 25 Apr 2014 11:09:09 -0400
Subject: Sampling methods WIP

---
 lib/sampling/riot_api.rb | 169 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 169 insertions(+)
 create mode 100644 lib/sampling/riot_api.rb

(limited to 'lib/sampling/riot_api.rb')

diff --git a/lib/sampling/riot_api.rb b/lib/sampling/riot_api.rb
new file mode 100644
index 0000000..3de4185
--- /dev/null
+++ b/lib/sampling/riot_api.rb
@@ -0,0 +1,169 @@
+module Sampling
+	module RiotApi
+		##
+		# Return whether or not this sampling method works with the specified game.
+		# Spoiler: It only works with League of Legends (or subclasses of it).
+		public
+		def works_with?(game)
+			if api_key.nil? or region.nil?
+				return false
+			end
+			if game.name == "League of Legends"
+				return true
+			end
+			unless game.parent.nil?
+				return works_with?(game.parent)
+			end
+		end
+
+		##
+		# This sampling method uses remote IDs
+		public
+		def uses_remote?
+			return true
+		end
+
+		##
+		# When given a summoner name for a user, figure out the summoner ID.
+		public
+		def set_remote_name(user, game, summoner_name)
+			Delayed::Job.enqueue(UsernameJob.new(user, game, summoner_name), :queue => api_name)
+		end
+		private
+		class UsernameJob < Job
+			def initialize(user, game, summoner_name)
+				@user_id = user.id
+				@game_id = game.id
+				# Escape any funny stuff
+				summoner_names = [summoner_name].map{|name|Sampling::RiotApi::standardize(name.gsub(',',''))}
+				# Generate the request
+				super("v1.3/summoner/by-name/%{summonerNames}", { :summonerNames => summoner_names.join(",") })
+			end
+			def handle(data)
+				user = User.find(@user_id)
+				game = Game.find(@game_id)
+				
+				normalized_summoner_name = data.keys.first
+				remote_data = {
+					:id   => data[normalized_summoner_name]["id"],
+					:name => data[normalized_summoner_name]["name"],
+				}
+
+				user.set_remote_username(game, remote_data)
+			end
+		end	
+
+		##
+		# When given data from RemoteUsername#value, give back a readable name to display.
+		# Here, this is the summoner name.
+		public
+		def get_remote_name(data)
+			data["name"]
+		end
+
+		##
+		# Fetch all the statistics for a match.
+		public
+		def sampling_start(match)
+			@match.teams.each do |team|
+				team.users.each do |user|
+					Delayed::Job.enqueue(MatchJob.new(user, match), :queue => api_name)
+				end
+			end
+		end
+		private
+		class FetchStatisticsJob < Job
+			def initialize(user, match)
+				@user_id = user.id
+				@match_id = match.id
+				# Get the summoner id
+				summoner = user.get_remote_username(match.tournament_stage.tournament.game)
+				if summoner.nil?
+					raise "Someone didn't enter their summoner name"
+				end
+				# Generate the request
+				super("v1.3/game/by-summoner/%{summonerId}/recent", { :summonerId => summoner["id"] })
+			end
+			def handle(data)
+				user = User.find(@user_id)
+				match = Match.find(@match_id)
+				Statistic.create(user: user, match: match, value: TODO)
+			end
+		end
+
+		public
+		def sampling_done?(match)
+			# TODO
+		end
+
+		public
+		def render_user_interaction(match, user)
+			return ""
+		end
+
+		public
+		def handle_user_interaction(match, user)
+		end
+
+		########################################################################
+
+		private
+		def api_name
+			"prod.api.pvp.net/api/lol"
+		end
+
+		private
+		def api_key
+			ENV["RIOT_API_KEY"]
+		end
+
+		private
+		def region
+			ENV["RIOT_API_REGION"]
+		end
+
+		private
+		def url(request, args={})
+			"https://prod.api.pvp.net/api/lol/#{region}/#{request % args.merge(args){|k,v|url_escape(v)}}?#{api_key}"
+		end
+
+		private
+		def url_escape(string)
+			URI::escape(string.to_s, /[^a-zA-Z0-9._~!$&'()*+,;=:@-]/)
+		end
+
+		private
+		def standardize(summoner_name)
+			summoner_name.to_s.downcase.gsub(' ', '')
+		end
+
+		private
+		class Job < ThrottledApiRequest.new(api_name, 10.seconds, 10)
+			def initialize(request, args={})
+					@url = Sampling::RiotApi::url(request, args)
+			end
+
+			def perform
+				response = open(@url)
+				status = response.status
+				data = JSON::parse(response.read)
+
+				# Error codes that RIOT uses:
+				#   "400"=>"Bad request"
+				#   "401"=>"Unauthorized"
+				#   "429"=>"Rate limit exceeded"
+				#   "500"=>"Internal server error"
+				#   "503"=>"Service unavailable"
+				#   "404"=>"Not found"
+				# Should probably handle these better
+				if status[0] != "200"
+					raise "GET #{@url} => #{status.join(" ")}"
+				end
+				self.handle(data)
+			end
+
+			def handle(data)
+			end
+		end
+	end
+end
-- 
cgit v1.2.3-2-g168b