CoolFace
Apppublic

sanket3280/code-execution

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
leaderboard.service.js212 linesDownload Raw Back to services
1const redisClient = require('../config/redis');2 3/**4 * Leaderboard Service5 * Uses Redis sorted sets for efficient leaderboard operations6 */7class LeaderboardService {8  /**9   * Create a new leaderboard10   * @param {string} name - Unique name for the leaderboard11   * @param {number} expireTime - Time in seconds until the leaderboard expires (0 = never)12   */13  static async createLeaderboard(name, expireTime = 0) {14    try {15      // Check if leaderboard already exists16      const exists = await redisClient.exists(`leaderboard:${name}`);17      if (exists) {18        // Clear existing leaderboard19        await redisClient.del(`leaderboard:${name}`);20      }21      22      // Set expiration if specified23      if (expireTime > 0) {24        await redisClient.set(`leaderboard:${name}:info`, JSON.stringify({ 25          created: Date.now(),26          expires: Date.now() + (expireTime * 1000)27        }));28        await redisClient.expire(`leaderboard:${name}:info`, expireTime);29        await redisClient.expire(`leaderboard:${name}`, expireTime);30      }31      32      return true;33    } catch (error) {34      console.error('Error creating leaderboard:', error);35      return false;36    }37  }38 39  /**40   * Add or update a user's score in the leaderboard41   * @param {string} leaderboardName - Name of the leaderboard42   * @param {string} userId - User ID43   * @param {number} score - User's score44   * @param {Object} userData - Additional user data to store45   */46  static async updateScore(leaderboardName, userId, score, userData = {}) {47    try {48      // Update score in the sorted set49      await redisClient.zadd(`leaderboard:${leaderboardName}`, score, userId);50      51      // Store additional user data52      if (Object.keys(userData).length > 0) {53        await redisClient.hset(54          `leaderboard:${leaderboardName}:users`,55          userId,56          JSON.stringify({57            ...userData,58            score,59            lastUpdated: Date.now()60          })61        );62      }63      64      return true;65    } catch (error) {66      console.error('Error updating score:', error);67      return false;68    }69  }70 71  /**72   * Get a user's rank in the leaderboard73   * @param {string} leaderboardName - Name of the leaderboard74   * @param {string} userId - User ID75   * @returns {number} User's rank (0-based) or -1 if not found76   */77  static async getUserRank(leaderboardName, userId) {78    try {79      // Get user's rank (0-based)80      const rank = await redisClient.zrevrank(`leaderboard:${leaderboardName}`, userId);81      return rank !== null ? rank : -1;82    } catch (error) {83      console.error('Error getting user rank:', error);84      return -1;85    }86  }87 88  /**89   * Get a user's score in the leaderboard90   * @param {string} leaderboardName - Name of the leaderboard91   * @param {string} userId - User ID92   * @returns {number} User's score or null if not found93   */94  static async getUserScore(leaderboardName, userId) {95    try {96      const score = await redisClient.zscore(`leaderboard:${leaderboardName}`, userId);97      return score !== null ? parseFloat(score) : null;98    } catch (error) {99      console.error('Error getting user score:', error);100      return null;101    }102  }103 104  /**105   * Get the top users from the leaderboard106   * @param {string} leaderboardName - Name of the leaderboard107   * @param {number} start - Start position (0-based)108   * @param {number} end - End position (inclusive)109   * @returns {Array} Array of [userId, score] pairs110   */111  static async getTopUsers(leaderboardName, start = 0, end = 9) {112    try {113      // Get top users with scores114      const leaderboard = await redisClient.zrevrange(115        `leaderboard:${leaderboardName}`,116        start,117        end,118        'WITHSCORES'119      );120      121      // Format the result as an array of [userId, score] pairs122      const result = [];123      for (let i = 0; i < leaderboard.length; i += 2) {124        const userId = leaderboard[i];125        const score = parseFloat(leaderboard[i + 1]);126        127        // Get additional user data if available128        let userData = {};129        const userDataStr = await redisClient.hget(130          `leaderboard:${leaderboardName}:users`,131          userId132        );133        134        if (userDataStr) {135          userData = JSON.parse(userDataStr);136        }137        138        result.push({139          userId,140          score,141          rank: start + i / 2 + 1, // 1-based rank142          ...userData143        });144      }145      146      return result;147    } catch (error) {148      console.error('Error getting top users:', error);149      return [];150    }151  }152 153  /**154   * Get the total number of users in the leaderboard155   * @param {string} leaderboardName - Name of the leaderboard156   * @returns {number} Total number of users157   */158  static async getTotalUsers(leaderboardName) {159    try {160      return await redisClient.zcard(`leaderboard:${leaderboardName}`);161    } catch (error) {162      console.error('Error getting total users:', error);163      return 0;164    }165  }166 167  /**168   * Get users around a specific user in the leaderboard169   * @param {string} leaderboardName - Name of the leaderboard170   * @param {string} userId - User ID171   * @param {number} range - Number of users to get on each side172   * @returns {Array} Array of users around the specified user173   */174  static async getUsersAroundUser(leaderboardName, userId, range = 5) {175    try {176      // Get user's rank177      const rank = await this.getUserRank(leaderboardName, userId);178      if (rank === -1) {179        return [];180      }181      182      // Calculate start and end positions183      const start = Math.max(0, rank - range);184      const end = rank + range;185      186      // Get users in range187      return await this.getTopUsers(leaderboardName, start, end);188    } catch (error) {189      console.error('Error getting users around user:', error);190      return [];191    }192  }193 194  /**195   * Delete a leaderboard196   * @param {string} leaderboardName - Name of the leaderboard197   * @returns {boolean} Success status198   */199  static async deleteLeaderboard(leaderboardName) {200    try {201      await redisClient.del(`leaderboard:${leaderboardName}`);202      await redisClient.del(`leaderboard:${leaderboardName}:users`);203      await redisClient.del(`leaderboard:${leaderboardName}:info`);204      return true;205    } catch (error) {206      console.error('Error deleting leaderboard:', error);207      return false;208    }209  }210}211 212module.exports = LeaderboardService;