Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
8061d56
Changes
teejusb Mar 30, 2024
a9dd78b
Fix issues + update dependencies
teejusb Mar 31, 2024
91dd115
Emit state
teejusb Mar 31, 2024
47f4926
Fix linting
teejusb Jul 20, 2024
b843ee6
Add internal clientId, basic message handling
adketuri Oct 29, 2024
9ce0907
Handle createLobby message
adketuri Oct 30, 2024
65199cd
Manage connections, room joining/leaving
adketuri Oct 31, 2024
3f53a97
Convert more message types
adketuri Oct 31, 2024
cda638a
Correct a double disconnect, pass down the expected Socket instead of…
adketuri Nov 1, 2024
5612486
Remove unused socket.io server field
adketuri Nov 1, 2024
88e2727
Tighten up handler callbacks
adketuri Nov 1, 2024
447e45a
Catch any malformed messages so the server doesn't crash
adketuri Nov 1, 2024
1c28412
Update tests, remove socket.io
adketuri Nov 2, 2024
6544462
Create a service for handling clients
adketuri Nov 2, 2024
62dd07d
Bind message listeners
adketuri Nov 3, 2024
64bff86
Swap to Records
adketuri Dec 7, 2024
5ef647e
Add updateMachine payloads
adketuri Dec 7, 2024
91df72c
Remove unused import
adketuri Dec 8, 2024
ecbb2bd
Move towards some generic ResponseStatus messaging
adketuri Dec 8, 2024
0712420
Add response helpers
adketuri Dec 8, 2024
8a966f6
Add song select, machine updates
adketuri Dec 8, 2024
60ddccc
Remove redundant response messages
adketuri Dec 8, 2024
635912d
Rename to event and data
adketuri Dec 8, 2024
b75ee73
Log failures
adketuri Dec 8, 2024
ce6679c
Log the messages
adketuri Dec 8, 2024
93daffe
Clear song info
adketuri Dec 8, 2024
2878bd4
Look at p1 and p2
adketuri Dec 8, 2024
e66e628
Correctly merge machine updates
adketuri Dec 8, 2024
78eb4b2
Clean up some logging
adketuri Dec 8, 2024
026fd95
Make ready mandatory. Add new screen state.
adketuri Dec 8, 2024
4c1889d
Tidy up the machine state broadcasts, update tests
adketuri Dec 9, 2024
dc601a0
Remove room if the last player left, remove extra logging
adketuri Dec 13, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,120 changes: 602 additions & 518 deletions package-lock.json

Large diffs are not rendered by default.

22 changes: 13 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,29 +27,34 @@
"posttest": "npm run lint"
},
"dependencies": {
"@nestjs/common": "^9.0.0",
"@nestjs/core": "^9.0.0",
"@nestjs/platform-express": "^9.0.0",
"@nestjs/platform-socket.io": "^9.4.0",
"@nestjs/websockets": "^9.4.0",
"@nestjs/common": "^10.3.7",
"@nestjs/core": "^10.3.7",
"@nestjs/platform-express": "^10.3.7",
"@nestjs/platform-ws": "^10.3.7",
"@nestjs/websockets": "^10.3.7",
"lodash": "^4.17.21",
"reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2",
"rxjs": "^7.2.0",
"socket.io-client": "^4.6.1"
"uuid": "^11.0.2",
"ws": "^8.18.0"
},
"devDependencies": {
"@nestjs/cli": "^9.0.0",
"@nestjs/schematics": "^9.0.0",
"@nestjs/testing": "^9.0.0",
"@nestjs/testing": "^10.3.7",
"@types/express": "^4.17.13",
"@types/jest": "28.1.8",
"@types/lodash": "^4.17.13",
"@types/node": "^16.0.0",
"@types/supertest": "^2.0.11",
"@types/ws": "^8.5.12",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0",
"eslint": "^8.0.1",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0",
"gts": "^3.1.1",
"jest": "28.1.3",
"prettier": "^2.3.2",
"source-map-support": "^0.5.20",
Expand All @@ -58,8 +63,7 @@
"ts-loader": "^9.2.3",
"ts-node": "^10.0.0",
"tsconfig-paths": "4.1.0",
"typescript": "^4.7.4",
"gts": "^3.1.1"
"typescript": "^4.7.4"
},
"jest": {
"moduleFileExtensions": [
Expand Down
3 changes: 2 additions & 1 deletion src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { EventsModule } from './events/events.module';
import { ClientModule } from './clients/client.module';

@Module({
imports: [EventsModule],
imports: [EventsModule, ClientModule],
controllers: [AppController],
providers: [AppService],
})
Expand Down
8 changes: 8 additions & 0 deletions src/clients/client.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Module } from '@nestjs/common';
import { ClientService } from './client.service';

@Module({
providers: [ClientService],
exports: [ClientService],
})
export class ClientModule {}
86 changes: 86 additions & 0 deletions src/clients/client.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { Injectable } from '@nestjs/common';
import WebSocket = require('ws');
import { EventMessage } from '../events/events.types';
import { SocketId, LobbyCode, ROOMMAN } from '../types/models.types';
import { v4 as uuid } from 'uuid';
@Injectable()
export class ClientService {
// Mapping from socketId to the lobby code for the spectators.
private clients: Record<SocketId, WebSocket> = {};

getSocketId(targetSocket: WebSocket): SocketId {
for (const [socketId, socket] of Object.entries(this.clients)) {
if (socket === targetSocket) return socketId;
}
throw new Error('Socket not found');
}

/** Sends a message to all connected clients */
sendAll(response: EventMessage) {
for (const client of Object.values(this.clients)) {
if (client.readyState === WebSocket.OPEN) {
client.send(JSON.stringify(response));
}
}
}

/** Sends a message to a specific socket */
sendSocket(response: EventMessage, socketId: SocketId) {
const socket = this.clients[socketId];
if (!socket || socket.readyState !== WebSocket.OPEN) {
console.warn('Cannot send to socket, socket is not connected');
return;
}
socket.send(JSON.stringify(response));
}

/** Sends a message to all clients in a particular lobby */
sendLobby(response: EventMessage, code: LobbyCode) {
for (const [socketId, socket] of Object.entries(this.clients)) {
// skip clients not in the lobby
if (!ROOMMAN.isJoined(socketId, code)) return;

if (socket.readyState === WebSocket.OPEN) {
socket.send(JSON.stringify(response));
}
}
}

disconnect(socketId: SocketId, reason?: string) {
console.log('Client disconnecting', socketId);
if (!this.clients[socketId]) {
console.warn(`Client ${socketId} not connected`);
return;
}

const message: EventMessage = {
event: 'clientDisconnected',
data: { reason: reason || 'Just because' },
};

const client = this.clients[socketId];
if (!client) return;

if (client.readyState === WebSocket.OPEN) {
client.close(1000, JSON.stringify(message));
}
delete this.clients[socketId];
}

connect(socket: WebSocket): string {
// Assert we're not already connected
console.log('Client connecting');
const entry = Object.entries(this.clients).find(
([, value]) => socket === value,
);
if (entry) {
console.warn(`Socket ${entry[0]} is already connected`);
return entry[0];
}

// Generate an id for the entry, set and return it
const socketId = uuid();
this.clients[socketId] = socket;
return socketId;
}
}
Loading
Loading