Browse files

Centralized SteamProfile class with full caching for all 3 types.

  • Loading branch information...
1 parent 1a7834f commit 66dbfe67fae76036b4fbe7b90b20da6e8e207397 @jschuur committed Sep 21, 2011
View
19 NOTES.md
@@ -1,42 +1,33 @@
Currently
---------
* Even on errors, populate form and results
-* loading spinner not always show when clicking on friend sidebar links (image not yet loaded? try adding text too)
* Switch back to pageheader instead of title, so browser history has titles when AJAX loading page headers
-* What happens when there's no friends?
-* load friends list from initial root page load search
-* Check for valid game with new APP_CONFIG['games'] format
Bugs
----
* CSS color on private profile not working
* Dropdowns don't load on about page because JS files are included twice
-* steam privacy state not properly set for authenticated users
* Add right padding to main content column
-* Problem with loading permalink with numeric IDs? http://steam.dev/a/76561197970679651/tf2 Not easily repeatable
-* No loading spinner for sidebar links?
* Can't go forward after you've gone back
* undefined method nickname error (go to http://steam.dev/a/jschuur/l4d and select recurve7) Problem with square brackets?
+* Cached data doesn't return fact that user doesn't own the game.
Next
----
* noscript tags for when JavaScript is disabled.
-* Helper for 'use id or custom_url; Apply to Settings page link.
-* deal with more than 100 friends (multiple API calls)
-* Split achievement loading into separate load and render functions to DRY form submission and permalink loading
-* Put Steam profile pic in sidebar (still, now that it's next to dropdown?)
-* Add Twitter account via settings
-* Checkboxes for 'Tweet new achievements' and 'Get daily summary email'
+* Put Steam profile pic in sidebar above friends list
* Check for no unlocked achievements
* Add achievement images
+* Do I have this achievement?, when looking at someone else's list
+* Non game specific users base page (just the sidebar and then what? Recent achievements across all games?)
More
----
+* Checkboxes for 'Tweet new achievements' and 'Get daily summary email'
* Format flash messages better (as drop downs and triggered from layout)
* Show completion percentage (bar?)
* Tweet new achievements (associate Twitter account)
* Find out which of your friends has the most achievements
-* Do I have this achievement?, when looking at someone else's list
* Email summary of new achievements (including friends?)
* Compare achievements to a friend
* Icon to indicate if you've unlocked an achievement when you're looking at other people's
View
7 app/controllers/achievements_controller.rb
@@ -9,13 +9,14 @@ def index
def show
respond_with do |format|
format.js do
- @achievements = Achievements.new(params[:user], params[:game])
- @title = "#{APP_CONFIG['games'].detect { |g| params[:game] == g['shortname'] }['fullname']} achievements for #{@achievements.id.nickname}"
+ profile = SteamProfile.new(params[:user], :achievements => params[:game])
+ @achievements = profile.achievements
+ @title = "#{APP_CONFIG['games'].detect { |g| params[:game] == g['shortname'] }['fullname']} achievements for #{profile.id.nickname}"
end
format.html { render 'show' }
end
end
-
+
def search
redirect_to achievements_path(:user => params[:user], :game => params[:game])
end
View
2 app/controllers/friends_controller.rb
@@ -2,7 +2,7 @@ class FriendsController < ApplicationController
respond_to :js
def show
- @friends = Friends.new(params[:user])
+ @friends = SteamProfile.new(params[:user], :friends => true).friends
respond_with do |format|
format.js { }
View
21 app/models/achievements.rb
@@ -2,15 +2,13 @@ class Achievements
attr_reader :error, :id
include SteamUtil
- def initialize(user, game)
- if @achievements = load_game_achievements(user, game)
+ def initialize(id, game)
+ if @achievements = load_game_achievements(id, game)
@unlocked = @achievements.find_all { |a| a.unlocked? }.sort {|a,b| -1 * (a.timestamp.to_i <=> b.timestamp.to_i) }
# 4 week history of the number of achievements unlocked
achievements_per_day = @unlocked.map(&:timestamp).compact.reduce(Hash.new(0)) { |hash, timestamp| hash[timestamp.strftime("%D")] += 1; hash }
@sparkline_history = (Date.today-28 .. Date.today).map { |d| achievements_per_day[d.strftime("%D")] }
-
- @id = get_steam_id(user)
end
end
@@ -28,28 +26,25 @@ def sparkline_history
private
- def load_game_achievements(user, game)
- if cached_achievements = $redis.get("achievements_#{user}_#{game}")
+ def load_game_achievements(id, game)
+ if cached_achievements = $redis.get("achievements_#{id.steam_id64}_#{game}")
Marshal.load(cached_achievements)
else
begin
- id = get_steam_id(user)
-
# Save any profile we did a lookup on for later
User.create_with_id(id)
raise "This profile's data is not public." if id.privacy_state != 'public'
stats = id.game_stats(game)
-
- $redis.set("achievements_#{user}_#{game}", Marshal.dump(stats.achievements))
- $redis.expire("achievements_#{user}_#{game}", APP_CONFIG['achievement_cache_time'])
-
rescue Exception => e
@error = e.message
return false
else
- return stats.achievements
+ $redis.set("achievements_#{id.steam_id64}_#{game}", Marshal.dump(stats.achievements))
+ $redis.expire("achievements_#{id.steam_id64}_#{game}", APP_CONFIG['achievement_cache_time'] || 600)
+
+ stats.achievements
end
end
end
View
50 app/models/friends.rb
@@ -2,11 +2,9 @@ class Friends
attr_reader :error
include SteamUtil
- def initialize(user)
- id = get_steam_id(user)
-
+ def initialize(id)
if id.privacy_state == 'public'
- load_friends(id)
+ @friends = load_friends(id)
else
@error = 'No public friend list available'
end
@@ -19,25 +17,35 @@ def all
private
def load_friends(id)
- friends = id.friends.map(&:steam_id64)
- unless friends.empty?
- begin
- WebApi.api_key = STEAM_WEB_API_KEY
-
- # Query for friends 100 at a time from the Steam API
- @friends = []
- until friends.empty? do
- batch_json = WebApi.json 'ISteamUser', 'GetPlayerSummaries', 2, { :steamids => friends.shift(100).join(',') }
- @friends += MultiJson.decode(batch_json)['response']['players']
- end
+ if cached_friends = $redis.get("friends_#{id.steam_id64}")
+ Marshal.load(cached_friends)
+ else
+ friend_ids = id.friends.map(&:steam_id64)
+ unless friend_ids.empty?
+ begin
+ WebApi.api_key = STEAM_WEB_API_KEY
- rescue Exception => e
- @error = e.message
- else
- @friends.each_with_index do |friend, i|
- if friend['profileurl'] && friend['profileurl'].index('/id/')
- @friends[i]['custom_url'] = friend['profileurl'].split('/').last
+ # Query for friends 100 at a time from the Steam API
+ friends = []
+ until friend_ids.empty? do
+ batch_json = WebApi.json 'ISteamUser', 'GetPlayerSummaries', 2, { :steamids => friend_ids.shift(100).join(',') }
+ friends += MultiJson.decode(batch_json)['response']['players']
end
+
+ rescue Exception => e
+ @error = e.message
+ return null
+ else
+ friends.each_with_index do |friend, i|
+ if friend['profileurl'] && friend['profileurl'].index('/id/')
+ friends[i]['custom_url'] = friend['profileurl'].split('/').last
+ end
+ end
+
+ $redis.set("friends_#{id.steam_id64}", Marshal.dump(friends))
+ $redis.expire("friends_#{id.steam_id64}", APP_CONFIG['friends_cache_time'] || 86400)
+
+ friends
end
end
end
View
39 app/models/steam_profile.rb
@@ -0,0 +1,39 @@
+class SteamProfile
+ include SteamUtil
+ attr_reader :error, :id
+
+ def initialize(user, options = {})
+ if @id = load_id(user)
+ @friends = Friends.new(@id) if options[:friends]
+ @achievements = Achievements.new(@id, options[:achievements]) if options[:achievements]
+ end
+ end
+
+ def friends
+ @friends || []
+ end
+
+ def achievements
+ @achievements || []
+ end
+
+ private
+
+ def load_id(user)
+ if cached_id = $redis.get("user_#{user}")
+ Marshal.load(cached_id)
+ else
+ begin
+ id = get_steam_id(user)
+ rescue Exception => e
+ @error = e.message
+ return null
+ else
+ $redis.set("user_#{user}", Marshal.dump(id))
+ $redis.expire("user_#{user}", APP_CONFIG['user_cache_time'] || 604800)
+
+ id
+ end
+ end
+ end
+end
View
8 app/models/thing.rb
@@ -1,8 +0,0 @@
-class Thing
- attr_reader :what
-
- def self.initialize(num)
- puts "initializing"
- @what = num
- end
-end
View
1 app/views/achievements/show.js.erb
@@ -1,6 +1,7 @@
$("#spinner").hide();
<% if @achievements.error %>
$("#errors").html('<%= @achievements.error %>');
+ $("#errors").show();
<% else %>
$("#results").html('<%= escape_javascript(raw render(:partial => 'results')) %>');
$(".page-header h1").html('<%= @title %>');
View
3 config/config.yml
@@ -1,6 +1,7 @@
development: &defaults
achievement_cache_time: 3600 # Seconds to cache achievement data on a per user/game basis
- user_cache_time: 604800
+ user_cache_time: 86400
+ friends_cache_time: 86400
games:
- shortname: tf2
fullname: Team Fortress 2

0 comments on commit 66dbfe6

Please sign in to comment.