Skip to content

Commit

Permalink
feat: db replication
Browse files Browse the repository at this point in the history
  • Loading branch information
PatrickChoDev committed Mar 30, 2024
1 parent cc099d7 commit 9885c31
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 37 deletions.
15 changes: 12 additions & 3 deletions apps/server/src/controller/admin.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export class AdminController {
constructor(
private readonly io: Server,
private readonly adminService: AdminService,
) { }
) {}
async listGames(req: Request, res: Response) {
const games = await this.adminService.listGames()
res.json(games)
Expand Down Expand Up @@ -41,7 +41,13 @@ export class AdminController {
'state',
await this.adminService.getGameState().then((game) => game.id),
)
this.io.sockets.to('scoreboard').emit('scoreboard', await this.adminService.getScoreboard(game.id, game.actions.map((a) => a.key)))
this.io.sockets.to('scoreboard').emit(
'scoreboard',
await this.adminService.getScoreboard(
game.id,
game.actions.map((a) => a.key),
),
)
}

async endGame(req: Request, res: Response) {
Expand All @@ -58,7 +64,10 @@ export class AdminController {
async getGameSummary(req: Request, res: Response) {
const game = await this.adminService.getGameByID(req.params.id)
if (!game) return res.status(404).send({ err: 'Game not found' })
const summary = await this.adminService.getGameSummary(game.id, game.actions.map((a) => a.key))
const summary = await this.adminService.getGameSummary(
game.id,
game.actions.map((a) => a.key),
)
res.json(summary)
}

Expand Down
24 changes: 14 additions & 10 deletions apps/server/src/controller/player.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ export class PlayerController {
constructor(
private readonly io: Server,
private readonly playerService: PlayerService,
) {
}
) {}

async authenticateSocket(socket: Socket) {
const cid = (socket.handshake.headers.cid ||
Expand Down Expand Up @@ -55,36 +54,41 @@ export class PlayerController {
})

socket.on('subscribe', (m, cb) => {
socket.join('scoreboard');
socket.join('scoreboard')
this.playerService.getGameState().then((game) => {
if (game.id && game.game && game.status === 'playing')
this.playerService
.getScoreboard(game.id, game.game.actions.map((a) => a.key))
.getScoreboard(
game.id,
game.game.actions.map((a) => a.key),
)
.then((score) => {
socket.emit('scoreboard', score)
})
})
})

socket.on('submit', async (message) => {
this.logger.debug("Received message: " + String(message).trim())
this.logger.debug('Received message: ' + String(message).trim())
const data = String(message).trim().split(' ')
this.playerService
.submit(socket.user, data[0], parseInt(data[1]))
.then((game) => {
this.logger.debug(`Incremented: ${String(message).trim()}`)
if (game.id && game.game) {
this.logger.debug("Getting scoreboard updated")
this.logger.debug('Getting scoreboard updated')
return this.playerService
.getScoreboard(game.id, game.game.actions.map((a) => a.key))
.getScoreboard(
game.id,
game.game.actions.map((a) => a.key),
)
.then((score) =>
this.io.to('scoreboard').emit('scoreboard', score),
)
}
}
)
})
.catch((err) => {
this.logger.warn("Failed to increment: " + err)
this.logger.warn('Failed to increment: ' + err)
socket.disconnect(true)
})
})
Expand Down
3 changes: 2 additions & 1 deletion apps/server/src/models/game.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import { GameHistory } from './history.model'

export class Game
extends Model<GameAttributes, GameInput>
implements GameAttributes {
implements GameAttributes
{
public id!: string
public title!: string
public description!: string
Expand Down
10 changes: 5 additions & 5 deletions apps/server/src/models/history.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import { Game } from './game.model'

export class GameHistory
extends Model<GameHistoryAttributes, GameHistoryInput>
implements GameHistoryAttributes {
implements GameHistoryAttributes
{
public game_id!: string
public player_id!: string
public key!: string
Expand Down Expand Up @@ -58,7 +59,7 @@ export class GameHistoryRepository {
RedisFunctions,
RedisScripts
>,
) { }
) {}

async createHistory(
game_id: string,
Expand All @@ -70,8 +71,8 @@ export class GameHistoryRepository {
this.redis.keys(`game::${game_id}::*`).then(async (keys) => {
keys.forEach(async (k) => {
if (k !== `game::${game_id}::${key}`) {
const kTotal = parseInt(await this.redis.get(k) || '0')
const decrease = ((Math.floor(Math.abs(total - kTotal) * vote / 100)))
const kTotal = parseInt((await this.redis.get(k)) || '0')
const decrease = Math.floor((Math.abs(total - kTotal) * vote) / 100)
const remain = kTotal - decrease
if (remain > 0) this.redis.decrBy(k, decrease)
}
Expand Down Expand Up @@ -147,5 +148,4 @@ export class GameHistoryRepository {
}))
})
}

}
3 changes: 2 additions & 1 deletion apps/server/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ export async function initServer(app: Express, server: HTTPServer) {
logger.info(' Database Connection has been established successfully.')
})
.catch((err) => {
logger.error('Unable to connect to the database:', { err })
console.error(err)
logger.error(`Unable to connect to the database: ${err}`)
})
sequelizeConnection.sync({ force: process.env.FORCE_DB_SYNC === 'true' })

Expand Down
10 changes: 7 additions & 3 deletions apps/server/src/service/admin.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export class AdminService {
constructor(
private readonly gameRepository: GameRepository,
private readonly gameHistoryRepository: GameHistoryRepository,
) { }
) {}

async getGameByID(id: string) {
return this.gameRepository.getGameById(id)
Expand Down Expand Up @@ -42,9 +42,13 @@ export class AdminService {
.then((score) => {
const total_vote = score.reduce((acc, s) => acc + s.vote, 0)
if (total_vote === 0) {
return score.map((s) => `${s.key} ${(100 / score.length).toFixed(2)}`).join(' ')
return score
.map((s) => `${s.key} ${(100 / score.length).toFixed(2)}`)
.join(' ')
}
return score?.map((s) => `${s.key} ${(s.vote / total_vote * 100).toFixed(2)}`).join(' ')
return score
?.map((s) => `${s.key} ${((s.vote / total_vote) * 100).toFixed(2)}`)
.join(' ')
})
}

Expand Down
10 changes: 7 additions & 3 deletions apps/server/src/service/player.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export class PlayerService {
private readonly gameRepository: GameRepository,
private readonly clientRepository: ClientRepository,
private readonly gameHistoryRepository: GameHistoryRepository,
) { }
) {}

async getGame(id: string) {
return await this.gameRepository.getGameById(id).catch((err) => ({ err }))
Expand Down Expand Up @@ -80,9 +80,13 @@ export class PlayerService {
.then((score) => {
const total_vote = score.reduce((acc, s) => acc + s.vote, 0)
if (total_vote === 0) {
return score.map((s) => `${s.key} ${(100 / score.length).toFixed(2)}`).join(' ')
return score
.map((s) => `${s.key} ${(100 / score.length).toFixed(2)}`)
.join(' ')
}
return score?.map((s) => `${s.key} ${(s.vote / total_vote * 100).toFixed(2)}`).join(' ')
return score
?.map((s) => `${s.key} ${((s.vote / total_vote) * 100).toFixed(2)}`)
.join(' ')
})
}
}
32 changes: 21 additions & 11 deletions apps/server/src/utils/database.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,28 @@
import { Sequelize } from 'sequelize'

function createConnectionPool() {
return new Sequelize({
host: process.env.DB_HOST || 'db',
database: process.env.DB_NAME || 'cutu',
username: process.env.DB_USER || 'postgres',
password: process.env.DB_PASSWORD || 'postgres',
port: parseInt(process.env.DB_PORT || '5432'),
dialect: 'postgres',
sync: {
force: (process.env.NODE_ENV || 'development') !== 'production',
return new Sequelize(
process.env.DB_NAME || 'cutu',
process.env.DB_USER || 'postgres',
process.env.DB_PASS || 'postgres',
{
port: parseInt(process.env.DB_PORT || '5432'),
dialect: 'postgres',
replication: {
read: [
...(process.env.DB_READ_HOST?.split(',').map((url) => ({
host: url,
})) || []),
{ host: process.env.DB_HOST || 'db' },
],
write: { host: process.env.DB_HOST || 'db' },
},
sync: {
force: (process.env.NODE_ENV || 'development') !== 'production',
},
logging: false,
},
logging: false,
})
)
}

export const sequelizeConnection = createConnectionPool()

0 comments on commit 9885c31

Please sign in to comment.