This commit is contained in:
19
backend/redis-scripts/add-result-increment.lua
Normal file
19
backend/redis-scripts/add-result-increment.lua
Normal file
@@ -0,0 +1,19 @@
|
||||
local redis_call = redis.call
|
||||
local leaderboard_scores_key, leaderboard_results_key = KEYS[1], KEYS[2]
|
||||
|
||||
local leaderboard_expiration_time = ARGV[1]
|
||||
local user_id = ARGV[2]
|
||||
local xp_gained = tonumber(ARGV[3])
|
||||
local user_data = ARGV[4]
|
||||
|
||||
redis_call('ZINCRBY', leaderboard_scores_key, xp_gained, user_id)
|
||||
redis_call('HSET', leaderboard_results_key, user_id, user_data)
|
||||
|
||||
local number_of_results = redis_call('ZCARD', leaderboard_scores_key)
|
||||
|
||||
if (number_of_results == 1) then
|
||||
redis_call('EXPIREAT', leaderboard_scores_key, leaderboard_expiration_time)
|
||||
redis_call('EXPIREAT', leaderboard_results_key, leaderboard_expiration_time)
|
||||
end
|
||||
|
||||
return redis_call('ZREVRANK', leaderboard_scores_key, user_id)
|
||||
38
backend/redis-scripts/add-result.lua
Normal file
38
backend/redis-scripts/add-result.lua
Normal file
@@ -0,0 +1,38 @@
|
||||
local redis_call = redis.call
|
||||
local leaderboard_scores_key, leaderboard_results_key = KEYS[1], KEYS[2]
|
||||
|
||||
local max_results = tonumber(ARGV[1])
|
||||
local leaderboard_expiration_time = ARGV[2]
|
||||
local user_id = ARGV[3]
|
||||
local result_score = ARGV[4]
|
||||
local result_data = ARGV[5]
|
||||
|
||||
local number_of_results_changed = redis_call('ZADD', leaderboard_scores_key, 'GT', 'CH', result_score, user_id)
|
||||
|
||||
if (number_of_results_changed == 1) then
|
||||
redis_call('HSET', leaderboard_results_key, user_id, result_data)
|
||||
end
|
||||
|
||||
local number_of_results = redis_call('ZCARD', leaderboard_scores_key)
|
||||
|
||||
local removed_user_id = nil
|
||||
|
||||
if (number_of_results > max_results) then
|
||||
local user_with_lowest_score = redis_call('ZPOPMIN', leaderboard_scores_key)
|
||||
removed_user_id = user_with_lowest_score[1]
|
||||
|
||||
if (removed_user_id ~= nil) then
|
||||
redis_call('HDEL', leaderboard_results_key, removed_user_id)
|
||||
end
|
||||
end
|
||||
|
||||
if (number_of_results == 1) then -- Indicates that this is the first score of the day, set the leaderboard keys to expire at specified time
|
||||
redis_call('EXPIREAT', leaderboard_scores_key, leaderboard_expiration_time)
|
||||
redis_call('EXPIREAT', leaderboard_results_key, leaderboard_expiration_time)
|
||||
end
|
||||
|
||||
if (number_of_results_changed == 1 and removed_user_id ~= user_id) then
|
||||
return redis_call('ZREVRANK', leaderboard_scores_key, user_id)
|
||||
end
|
||||
|
||||
return nil
|
||||
51
backend/redis-scripts/get-rank.lua
Normal file
51
backend/redis-scripts/get-rank.lua
Normal file
@@ -0,0 +1,51 @@
|
||||
-- Helper to split CSV string into a list
|
||||
local function split_csv(csv)
|
||||
local result = {}
|
||||
for user_id in string.gmatch(csv, '([^,]+)') do
|
||||
table.insert(result, user_id)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
local redis_call = redis.call
|
||||
local leaderboard_scores_key, leaderboard_results_key = KEYS[1], KEYS[2]
|
||||
|
||||
local user_id = ARGV[1]
|
||||
local include_scores = ARGV[2]
|
||||
local user_ids_csv = ARGV[3]
|
||||
|
||||
local rank = nil
|
||||
local friendsRank = nil
|
||||
local result = {}
|
||||
local score = ''
|
||||
|
||||
|
||||
-- filtered leaderboard
|
||||
if user_ids_csv ~= "" then
|
||||
|
||||
local filtered_user_ids = split_csv(user_ids_csv)
|
||||
local scored_users = {}
|
||||
for _, user_id in ipairs(filtered_user_ids) do
|
||||
local score = redis_call('ZSCORE', leaderboard_scores_key, user_id)
|
||||
if score then
|
||||
local number_score = tonumber(score)
|
||||
table.insert(scored_users, {user_id = user_id, score = number_score})
|
||||
end
|
||||
end
|
||||
table.sort(scored_users, function(a, b) return a.score > b.score end)
|
||||
|
||||
for i = 1, #scored_users do
|
||||
if scored_users[i].user_id == user_id then
|
||||
friendsRank = i - 1
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
rank = redis_call('ZREVRANK', leaderboard_scores_key, user_id)
|
||||
if (include_scores == "true") then
|
||||
score = redis_call('ZSCORE', leaderboard_scores_key, user_id)
|
||||
end
|
||||
result = redis_call('HGET', leaderboard_results_key, user_id)
|
||||
|
||||
return {rank, score, result, friendsRank}
|
||||
84
backend/redis-scripts/get-results.lua
Normal file
84
backend/redis-scripts/get-results.lua
Normal file
@@ -0,0 +1,84 @@
|
||||
-- Helper to split CSV string into a list
|
||||
local function split_csv(csv)
|
||||
local result = {}
|
||||
for user_id in string.gmatch(csv, '([^,]+)') do
|
||||
table.insert(result, user_id)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
local redis_call = redis.call
|
||||
local leaderboard_scores_key, leaderboard_results_key = KEYS[1], KEYS[2]
|
||||
|
||||
local min_rank = tonumber(ARGV[1])
|
||||
local max_rank = tonumber(ARGV[2])
|
||||
local include_scores = ARGV[3]
|
||||
local user_ids_csv = ARGV[4]
|
||||
|
||||
local results = {}
|
||||
local scores = {}
|
||||
local ranks = {}
|
||||
local count = nil
|
||||
local min_score = {user_id = nil, score = nil}
|
||||
|
||||
|
||||
-- filtered leaderboard
|
||||
if user_ids_csv ~= "" then
|
||||
|
||||
local filtered_user_ids = split_csv(user_ids_csv)
|
||||
local scored_users = {}
|
||||
for _, user_id in ipairs(filtered_user_ids) do
|
||||
local score = redis_call('ZSCORE', leaderboard_scores_key, user_id)
|
||||
if score then
|
||||
local number_score = tonumber(score)
|
||||
table.insert(scored_users, {user_id = user_id, score = number_score})
|
||||
end
|
||||
end
|
||||
table.sort(scored_users, function(a, b) return a.score > b.score end)
|
||||
|
||||
|
||||
if #scored_users > 0 then
|
||||
min_score = {scored_users[#scored_users].user_id, scored_users[#scored_users].score}
|
||||
end
|
||||
count = #scored_users
|
||||
|
||||
for i = min_rank + 1, math.min(max_rank + 1, #scored_users) do
|
||||
local entry = scored_users[i]
|
||||
local user_id = entry.user_id
|
||||
local score = tostring(entry.score)
|
||||
|
||||
local result_data = redis_call('HGET', leaderboard_results_key, user_id)
|
||||
|
||||
if result_data ~= nil then
|
||||
results[#results + 1] = result_data
|
||||
|
||||
local global_rank = redis_call('ZREVRANK', leaderboard_scores_key, user_id)
|
||||
ranks[#ranks + 1] = global_rank or -1 -- -1 if not found
|
||||
end
|
||||
|
||||
if include_scores == "true" then
|
||||
scores[#scores + 1] = score
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
else
|
||||
-- global leaderboard
|
||||
local scores_in_range = redis_call('ZRANGE', leaderboard_scores_key, min_rank, max_rank, 'REV')
|
||||
min_score = redis_call('ZRANGE', leaderboard_scores_key, 0, 0, 'WITHSCORES')
|
||||
count = redis_call('ZCARD', leaderboard_scores_key)
|
||||
|
||||
for _, user_id in ipairs(scores_in_range) do
|
||||
local result_data = redis_call('HGET', leaderboard_results_key, user_id)
|
||||
|
||||
if (include_scores == "true") then
|
||||
scores[#scores + 1] = redis_call('ZSCORE', leaderboard_scores_key, user_id)
|
||||
end
|
||||
|
||||
if (result_data ~= nil) then
|
||||
results[#results + 1] = result_data
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return {results, scores, count, min_score, ranks}
|
||||
23
backend/redis-scripts/purge-results.lua
Normal file
23
backend/redis-scripts/purge-results.lua
Normal file
@@ -0,0 +1,23 @@
|
||||
local redis_call = redis.call
|
||||
local string_match = string.match
|
||||
|
||||
local user_id = ARGV[1]
|
||||
local leaderboards_namespace = ARGV[2]
|
||||
|
||||
local current_cursor = '0'
|
||||
local match_pattern = leaderboards_namespace .. '*'
|
||||
|
||||
repeat
|
||||
local result = redis_call('SCAN', current_cursor, 'MATCH', match_pattern)
|
||||
local next_cursor, matched_keys = result[1], result[2]
|
||||
|
||||
for _, key in ipairs(matched_keys) do
|
||||
if (string_match(key, 'results')) then
|
||||
redis_call('HDEL', key, user_id)
|
||||
elseif (string_match(key, 'scores')) then
|
||||
redis_call('ZREM', key, user_id)
|
||||
end
|
||||
end
|
||||
|
||||
current_cursor = next_cursor
|
||||
until (current_cursor == '0')
|
||||
Reference in New Issue
Block a user