Skip to content

Commit

Permalink
refactor(queue): make QueueState an enum (#1704)
Browse files Browse the repository at this point in the history
  • Loading branch information
garrappachc committed Jun 5, 2022
1 parent 9f6756b commit 1b0b903
Show file tree
Hide file tree
Showing 8 changed files with 46 additions and 34 deletions.
3 changes: 2 additions & 1 deletion src/queue/controllers/queue.controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { QueueAnnouncementsService } from '../services/queue-announcements.servi
import { FriendsService } from '../services/friends.service';
import { Tf2ClassName } from '@/shared/models/tf2-class-name';
import { MapPoolService } from '../services/map-pool.service';
import { QueueState } from '../queue-state';

jest.mock('../services/queue-config.service');
jest.mock('../services/queue.service');
Expand Down Expand Up @@ -64,7 +65,7 @@ describe('Queue Controller', () => {
playerId: null,
},
];
queueService.state = 'waiting';
queueService.state = QueueState.waiting;

queueAnnouncementsService.substituteRequests.mockResolvedValue([
{
Expand Down
3 changes: 2 additions & 1 deletion src/queue/gateways/queue.gateway.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { Events } from '@/events/events';
import { Socket } from 'socket.io';
import { Tf2ClassName } from '@/shared/models/tf2-class-name';
import { QueueSlotWrapper } from '../controllers/queue-slot-wrapper';
import { QueueState } from '../queue-state';

jest.mock('../services/queue.service');
jest.mock('socket.io');
Expand Down Expand Up @@ -169,7 +170,7 @@ describe('QueueGateway', () => {

describe('when the queueStateChange event is fired', () => {
beforeEach(() => {
events.queueStateChange.next({ state: 'ready' });
events.queueStateChange.next({ state: QueueState.ready });
});

it('should emit the event over the socket', () => {
Expand Down
14 changes: 10 additions & 4 deletions src/queue/queue-state.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
// waiting: waiting for players
// ready: players are expected to ready up
// launching: the game is being launched
export type QueueState = 'waiting' | 'ready' | 'launching';
export enum QueueState {
// waiting for players to join the queue
waiting = 'waiting',

// players are expected to ready up
ready = 'ready',

// everybody has readied up, the game is being launched
launching = 'launching',
}
3 changes: 2 additions & 1 deletion src/queue/services/auto-game-launcher.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { MapVoteService } from './map-vote.service';
import { GamesService } from '@/games/services/games.service';
import { FriendsService } from './friends.service';
import { Events } from '@/events/events';
import { QueueState } from '../queue-state';

jest.mock('./friends.service');
jest.mock('./queue.service');
Expand Down Expand Up @@ -80,7 +81,7 @@ describe('AutoGameLauncherService', () => {

it('should launch the game and reset the queue', async () => {
return new Promise<void>((resolve) => {
events.queueStateChange.next({ state: 'launching' });
events.queueStateChange.next({ state: QueueState.launching });

setImmediate(() => {
expect(queueService.reset).toHaveBeenCalled();
Expand Down
5 changes: 3 additions & 2 deletions src/queue/services/friends.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import { Tf2ClassName } from '@/shared/models/tf2-class-name';
import { PlayerAlreadyMarkedAsFriendError } from '../errors/player-already-marked-as-friend.error';
import { PlayerNotInTheQueueError } from '../errors/player-not-in-the-queue.error';
import { CannotMarkPlayerAsFriendError } from '../errors/cannot-mark-player-as-friend.error';
import { QueueState } from '../queue-state';

class QueueServiceStub {
state = 'waiting';
state = QueueState.waiting;
slots: QueueSlot[] = [
{
id: 0,
Expand Down Expand Up @@ -64,7 +65,7 @@ describe('FriendsService', () => {

describe('markFriend()', () => {
it('should fail if the queue is in launching state', () => {
queueService.state = 'launching';
queueService.state = QueueState.launching;
expect(() =>
service.markFriend('FAKE_MEDIC', 'FAKE_DM_CLASS'),
).toThrowError('cannot make friends at this stage');
Expand Down
3 changes: 2 additions & 1 deletion src/queue/services/friends.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Events } from '@/events/events';
import { PlayerNotInTheQueueError } from '../errors/player-not-in-the-queue.error';
import { CannotMarkPlayerAsFriendError } from '../errors/cannot-mark-player-as-friend.error';
import { PlayerAlreadyMarkedAsFriendError } from '../errors/player-already-marked-as-friend.error';
import { QueueState } from '../queue-state';

export interface Friendship {
sourcePlayerId: string;
Expand All @@ -21,7 +22,7 @@ export class FriendsService implements OnModuleInit {
}

markFriend(sourcePlayerId: string, targetPlayerId: string) {
if (this.queueService.state === 'launching') {
if (this.queueService.state === QueueState.launching) {
throw new Error('cannot make friends at this stage');
}

Expand Down
15 changes: 8 additions & 7 deletions src/queue/services/queue.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { PlayerNotInTheQueueError } from '../errors/player-not-in-the-queue.erro
import { WrongQueueStateError } from '../errors/wrong-queue-state.error';
import { Connection, Types } from 'mongoose';
import { CACHE_MANAGER } from '@nestjs/common';
import { QueueState } from '../queue-state';

jest.mock('@/players/services/players.service');
jest.mock('@/players/services/player-bans.service');
Expand Down Expand Up @@ -206,7 +207,7 @@ describe('QueueService', () => {
player: null,
},
],
state: 'waiting',
state: QueueState.waiting,
});

await service.onModuleInit();
Expand All @@ -223,7 +224,7 @@ describe('QueueService', () => {
});

it('should be empty initially', () => {
expect(service.state).toEqual('waiting');
expect(service.state).toEqual(QueueState.waiting);
expect(service.slots.length).toBe(12);
expect(service.slots.every((s) => s.playerId === null)).toBe(true);
expect(service.slots.every((s) => s.ready === false)).toBe(true);
Expand Down Expand Up @@ -385,7 +386,7 @@ describe('QueueService', () => {
expect(key).toEqual('queue');
expect(value).toEqual({
slots: expect.any(Array),
state: 'waiting',
state: QueueState.waiting,
});
expect(
value.slots.find((s) => s.playerId === player.id),
Expand Down Expand Up @@ -437,7 +438,7 @@ describe('QueueService', () => {
expect(key).toEqual('queue');
expect(value).toEqual({
slots: expect.any(Array),
state: 'waiting',
state: QueueState.waiting,
});
expect(value.slots.every((s) => s.playerId === null)).toBe(true);
resolve();
Expand Down Expand Up @@ -476,7 +477,7 @@ describe('QueueService', () => {
expect(key).toEqual('queue');
expect(value).toEqual({
slots: expect.any(Array),
state: 'waiting',
state: QueueState.waiting,
});
expect(value.slots.every((s) => s.playerId === null)).toBe(true);
resolve();
Expand Down Expand Up @@ -518,7 +519,7 @@ describe('QueueService', () => {
});

it('should change the state to ready', () => {
expect(service.state).toEqual('ready');
expect(service.state).toEqual(QueueState.ready);
});

describe('#readyUp()', () => {
Expand Down Expand Up @@ -568,7 +569,7 @@ describe('QueueService', () => {
});

it('should go back to the waiting state', () => {
expect(service.state).toEqual('waiting');
expect(service.state).toEqual(QueueState.waiting);
});
});
});
Expand Down
34 changes: 17 additions & 17 deletions src/queue/services/queue.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ interface Queue {
@Injectable()
export class QueueService implements OnModuleInit, OnModuleDestroy {
slots: QueueSlot[] = [];
state: QueueState = 'waiting';
state: QueueState = QueueState.waiting;

private logger = new Logger(QueueService.name);
private timer?: NodeJS.Timer;
Expand Down Expand Up @@ -121,7 +121,7 @@ export class QueueService implements OnModuleInit, OnModuleDestroy {
async join(slotId: number, playerId: string): Promise<QueueSlot[]> {
return await this.mutex.runExclusive(async () => {
try {
if (this.state === 'launching') {
if (this.state === QueueState.launching) {
throw new CannotJoinAtThisQueueStateError(this.state);
}

Expand Down Expand Up @@ -155,7 +155,7 @@ export class QueueService implements OnModuleInit, OnModuleDestroy {
targetSlot.playerId = playerId;

if (
this.state === 'ready' ||
this.state === QueueState.ready ||
this.playerCount === this.requiredPlayerCount
) {
targetSlot.ready = true;
Expand Down Expand Up @@ -186,7 +186,7 @@ export class QueueService implements OnModuleInit, OnModuleDestroy {
leave(playerId: string): QueueSlot {
const slot = this.findSlotByPlayerId(playerId);
if (slot) {
if (slot.ready && this.state !== 'waiting') {
if (slot.ready && this.state !== QueueState.waiting) {
throw new CannotLeaveAtThisQueueStateError(this.state);
}

Expand All @@ -201,7 +201,7 @@ export class QueueService implements OnModuleInit, OnModuleDestroy {
}

kick(...playerIds: string[]) {
if (this.state === 'launching') {
if (this.state === QueueState.launching) {
return;
}

Expand All @@ -223,7 +223,7 @@ export class QueueService implements OnModuleInit, OnModuleDestroy {
}

readyUp(playerId: string): QueueSlot {
if (this.state !== 'ready') {
if (this.state !== QueueState.ready) {
throw new WrongQueueStateError(this.state);
}

Expand All @@ -243,35 +243,35 @@ export class QueueService implements OnModuleInit, OnModuleDestroy {
private maybeUpdateState() {
// check whether we can change state
switch (this.state) {
case 'waiting':
case QueueState.waiting:
if (this.playerCount === this.requiredPlayerCount) {
this.setState('ready');
this.setState(QueueState.ready);
}
break;

case 'ready':
case QueueState.ready:
if (this.playerCount === 0) {
this.setState('waiting');
this.setState(QueueState.waiting);
} else if (this.readyPlayerCount === this.requiredPlayerCount) {
this.setState('launching');
this.setState(QueueState.launching);
}
break;

case 'launching':
this.setState('waiting');
case QueueState.launching:
this.setState(QueueState.waiting);
break;
}
}

private onStateChange(state: QueueState) {
switch (state) {
case 'ready':
case QueueState.ready:
clearTimeout(this.timer);
this.timer = setTimeout(() => this.onReadyUpTimeout(), readyUpTimeout);
break;

case 'launching':
case 'waiting':
case QueueState.launching:
case QueueState.waiting:
clearTimeout(this.timer);
break;
}
Expand Down Expand Up @@ -336,7 +336,7 @@ export class QueueService implements OnModuleInit, OnModuleDestroy {
const slots = this.slots.filter((s) => !!s.playerId);
slots.forEach((s) => (s.ready = false));
this.events.queueSlotsChange.next({ slots });
this.setState('waiting');
this.setState(QueueState.waiting);
}

private setState(state: QueueState) {
Expand Down

0 comments on commit 1b0b903

Please sign in to comment.