Discord-InterChat/InterChat

View on GitHub
src/services/LobbyMatchingService.ts

Summary

Maintainability
A
1 hr
Test Coverage
import type { QueuedChannel, ServerPreferences } from '#types/ChatLobby.d.ts';
import db from '#main/utils/Db.js';
import getRedis from '#main/utils/Redis.js';
import { PrismaClient } from '@prisma/client';
import { Redis } from 'ioredis';

export class MatchingService {
  private readonly db: PrismaClient;
  private readonly redis: Redis;

  constructor() {
    this.db = db;
    this.redis = getRedis();
  }

  async findMatch(serverId: string, preferences: ServerPreferences): Promise<QueuedChannel | null> {
    const serverHistory = await this.db.serverHistory.findUnique({
      where: { serverId },
    });

    const recentLobbyIds =
      serverHistory?.recentLobbies
        .sort((a, b) => b.timestamp - a.timestamp)
        .slice(0, 3)
        .map((l) => l.lobbyId) || [];

    const waitingServers = await this.redis.zrange('waiting_pool', 0, -1);

    for (const serverData of waitingServers) {
      const data: QueuedChannel = JSON.parse(serverData);
      if (data.serverId === serverId) continue;

      const otherServerHistory = await this.db.serverHistory.findUnique({
        where: { serverId: data.serverId },
      });

      // Check if in the past 2 calls they have been in a lobby together
      const hasRecentInteraction = recentLobbyIds.some((lobbyId, i) =>
        i <= 2 && otherServerHistory?.recentLobbies.some((l) => l.lobbyId === lobbyId),
      );

      if (!hasRecentInteraction) {
        // Regular matching
        if (preferences.maxServersInLobby === data.preferences.maxServersInLobby) {
          // TODO: make it possible for servers to join already created lobbies later if they don't match immediately
          return data;
        }
      }
    }

    return null;
  }
}