<commit_before>import * as memshared from "memshared";
import * as msgpack from "msgpack-lite";

import { merge, spliceOne } from "./Utils";
import { Client, Protocol, Room, generateId, isValidId } from "./index";

import { debugMatchMaking } from "./Debug";

export type ClientOptions = { clientId: string } & any;

export interface RoomWithScore {
  room: Room;
  score: number;
};

export class MatchMaker {

  private handlers: {[id: string]: any[]} = {};
  private availableRooms: {[name: string]: Room[]} = {};
  private roomsById: {[name: number]: Room} = {};
  private roomCount: number = 0;

  // room references by client id
  protected sessions: {[sessionId: string]: Room} = {};
  protected connectingClientByRoom: {[roomId: string]: {[clientId: string]: any}} = {};

  public execute (client: Client, message: any) {
    if (message[0] == Protocol.JOIN_ROOM) {
      this.onJoinRoomRequest(message[1], message[2], false, (err: string, room: Room) => {
        if (err) {
          let roomId = (room) ? room.roomId : message[1];
          client.send(msgpack.encode([Protocol.JOIN_ERROR, roomId, err]), { binary: true });
        }
      });

    } else if (message[0] == Protocol.ROOM_DATA) {
      // send message directly to specific room
      let room = this.getRoomById( message[1] );
      if (room) { room.onMessage(client, message[2]); }

    } else {
      this.sessions[ client.sessionId ].onMessage(client, message);
    }

  }

  /**
   * Create/joins a particular client in a room running in a worker process.
   *
   * The client doesn't join instantly because this method is called from the
   * match-making process. The client will request a new WebSocket connection
   * to effectively join into the room created/joined by this method.
   */
  public onJoinRoomRequest (roomToJoin: string, clientOptions: ClientOptions, allowCreateRoom: boolean, callback: (err: string, room: Room) => any): void {
    var room: Room;
    let err: string;

    clientOptions.sessionId = generateId();

    if (!this.hasHandler(roomToJoin) && isValidId(roomToJoin)) {
      room = this.joinById(roomToJoin, clientOptions);

    } else {
      room = this.requestToJoinRoom( roomToJoin, clientOptions ).room
        || (allowCreateRoom && this.create( roomToJoin, clientOptions ));
    }

    if ( room ) {
      //
      // Reserve a seat for clientId
      //
      if (!this.connectingClientByRoom[ room.roomId ]) {
        this.connectingClientByRoom[ room.roomId ] = {};
      }

      this.connectingClientByRoom[ room.roomId ][ clientOptions.clientId ] = clientOptions;

    } else {
      err = "join_request_fail";
    }

    callback(err, room);<commit_msg>Don't try to create a room that don't have an handler<commit_after>import * as memshared from "memshared";
import * as msgpack from "msgpack-lite";

import { merge, spliceOne } from "./Utils";
import { Client, Protocol, Room, generateId, isValidId } from "./index";

import { debugMatchMaking } from "./Debug";

export type ClientOptions = { clientId: string } & any;

export interface RoomWithScore {
  room: Room;
  score: number;
};

export class MatchMaker {

  private handlers: {[id: string]: any[]} = {};
  private availableRooms: {[name: string]: Room[]} = {};
  private roomsById: {[name: number]: Room} = {};
  private roomCount: number = 0;

  // room references by client id
  protected sessions: {[sessionId: string]: Room} = {};
  protected connectingClientByRoom: {[roomId: string]: {[clientId: string]: any}} = {};

  public execute (client: Client, message: any) {
    if (message[0] == Protocol.JOIN_ROOM) {
      this.onJoinRoomRequest(message[1], message[2], false, (err: string, room: Room) => {
        if (err) {
          let roomId = (room) ? room.roomId : message[1];
          client.send(msgpack.encode([Protocol.JOIN_ERROR, roomId, err]), { binary: true });
        }
      });

    } else if (message[0] == Protocol.ROOM_DATA) {
      // send message directly to specific room
      let room = this.getRoomById( message[1] );
      if (room) { room.onMessage(client, message[2]); }

    } else {
      this.sessions[ client.sessionId ].onMessage(client, message);
    }

  }

  /**
   * Create/joins a particular client in a room running in a worker process.
   *
   * The client doesn't join instantly because this method is called from the
   * match-making process. The client will request a new WebSocket connection
   * to effectively join into the room created/joined by this method.
   */
  public onJoinRoomRequest (roomToJoin: string, clientOptions: ClientOptions, allowCreateRoom: boolean, callback: (err: string, room: Room) => any): void {
    var room: Room;
    let err: string;

    clientOptions.sessionId = generateId();

    if (!this.hasHandler(roomToJoin)) {
      if (isValidId(roomToJoin)) {
        room = this.joinById(roomToJoin, clientOptions);
      }
    } else {
      room = this.requestToJoinRoom( roomToJoin, clientOptions ).room
        || (allowCreateRoom && this.create( roomToJoin, clientOptions ));
    }

    if ( room ) {
      //
      // Reserve a seat for clientId
      //
      if (!this.connectingClientByRoom[ room.roomId ]) {
        this.connectingClientByRoom[ room.roomId ] = {};
      }

      this.connectingClientByRoom[ room.roomId ][ clientOptions.clientId ] = clientOptions;

    } else {
      err = "join_request_fail";
    }

    callback(err, room);
{'fraction_non_alphanumeric': 0.1313895552684997, 'fraction_numerical': 0.002952574275696623, 'mean_word_length': 3.182098765432099, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '870736', 'n_tokens_mistral': 1646, 'n_tokens_neox': 1605, 'n_words': 478}