From c20e1fcfb3820e32a1b523917d6052ab103f80e0 Mon Sep 17 00:00:00 2001 From: Dan Date: Thu, 23 Nov 2023 15:30:32 +0000 Subject: [PATCH] Add ghost download --- .../race-results.controller.spec.ts | 18 +++++++ .../race-results/race-results.controller.ts | 35 ++++++++++++++ .../src/race-results/race-results.module.ts | 4 +- .../src/race-results/race-results.service.ts | 9 +++- .../bridge-server/src/races/races.service.ts | 7 +++ .../season-standings.module.ts | 8 +++- .../season-standings.service.ts | 42 +++++++++++++++-- .../src/seasons/seasons.controller.ts | 9 +++- .../src/seasons/seasons.module.ts | 6 ++- .../race-details/race-details.component.html | 2 +- .../race-details/race-details.component.scss | 2 +- .../race-details/race-details.component.ts | 47 +++++++------------ .../season-details.component.html | 1 + .../season-details.component.ts | 10 +++- .../src/app/services/auth.service.ts | 2 +- .../src/app/services/race-result.service.ts | 7 +++ .../src/app/services/races.service.ts | 8 ++-- .../src/app/services/replays.service.ts | 2 +- .../src/app/services/seasons.service.ts | 10 ++-- 19 files changed, 178 insertions(+), 51 deletions(-) create mode 100644 packages/bridge-server/src/race-results/race-results.controller.spec.ts create mode 100644 packages/bridge-server/src/race-results/race-results.controller.ts diff --git a/packages/bridge-server/src/race-results/race-results.controller.spec.ts b/packages/bridge-server/src/race-results/race-results.controller.spec.ts new file mode 100644 index 0000000..cc5de58 --- /dev/null +++ b/packages/bridge-server/src/race-results/race-results.controller.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { RaceResultsController } from './race-results.controller'; + +describe('RaceResultsController', () => { + let controller: RaceResultsController; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [RaceResultsController], + }).compile(); + + controller = module.get(RaceResultsController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/packages/bridge-server/src/race-results/race-results.controller.ts b/packages/bridge-server/src/race-results/race-results.controller.ts new file mode 100644 index 0000000..cd37dea --- /dev/null +++ b/packages/bridge-server/src/race-results/race-results.controller.ts @@ -0,0 +1,35 @@ +import { Controller, Get, Header, Param, Res, StreamableFile } from '@nestjs/common'; +import { createReadStream } from 'fs'; +import { join } from 'path'; +import type { Response } from 'express'; +import { RaceResultsService } from './race-results.service'; + +@Controller('race-results') +export class RaceResultsController { + + constructor( + private raceResultsService: RaceResultsService + ) + {} + + @Get(':id/ghost') + async getFile(@Param() params: any, @Res({ passthrough: true }) res: Response): Promise { + console.log(params); + let result = await this.raceResultsService.findOne(params.id); + + const file = createReadStream(join(process.cwd(), result.replayPath)); + res.set({ + 'Content-Type': 'application/json', + 'Content-Disposition': 'attachment; filename="'+result.replayPath+'.gbx"', + }); + return new StreamableFile(file); + } + + @Get(':id/get-ghost') + async getGhostFile(@Param() params: any, @Res() res: Response) { + console.log(params); + let result = await this.raceResultsService.findOne(params.id); + const file = createReadStream(join(process.cwd(), result.replayPath)); + file.pipe(res); + } +} diff --git a/packages/bridge-server/src/race-results/race-results.module.ts b/packages/bridge-server/src/race-results/race-results.module.ts index cc7a511..ef2849b 100644 --- a/packages/bridge-server/src/race-results/race-results.module.ts +++ b/packages/bridge-server/src/race-results/race-results.module.ts @@ -2,10 +2,12 @@ import { Module } from '@nestjs/common'; import { SequelizeModule } from '@nestjs/sequelize'; import { RaceResult } from './race-result.model'; import { RaceResultsService } from './race-results.service'; +import { RaceResultsController } from './race-results.controller'; @Module({ imports: [SequelizeModule.forFeature([RaceResult])], providers: [RaceResultsService], - exports: [SequelizeModule, RaceResultsService] + exports: [SequelizeModule, RaceResultsService], + controllers: [RaceResultsController] }) export class RaceResultsModule {} diff --git a/packages/bridge-server/src/race-results/race-results.service.ts b/packages/bridge-server/src/race-results/race-results.service.ts index 002eddb..64c490a 100644 --- a/packages/bridge-server/src/race-results/race-results.service.ts +++ b/packages/bridge-server/src/race-results/race-results.service.ts @@ -13,10 +13,17 @@ export class RaceResultsService { ) {} + async findOne(id: number) { + return this.raceResultModel.findOne({ + where: {id: id} + }); + } + async getFastestTimesForRace(raceId: number) { return this.raceResultModel.findAll({ + attributes: { include: [[this.sequelize.fn('MIN', this.sequelize.col('time')), 'min_time']] }, where:{ raceId: raceId }, - order: [['time', "ASC"]], + order: [['min_time', "ASC"]], group:['racerId'], include:[Racer] }); diff --git a/packages/bridge-server/src/races/races.service.ts b/packages/bridge-server/src/races/races.service.ts index 08df84c..793281a 100644 --- a/packages/bridge-server/src/races/races.service.ts +++ b/packages/bridge-server/src/races/races.service.ts @@ -28,6 +28,13 @@ export class RacesService { }); } + async findManyBySeason( seasonId: number) { + return this.raceModel.findAll({ + where: { seasonId : seasonId }, + include:[RaceResult] + }) + } + async findOneBySeasonAndMapUID(seasonId: number, mapUID: string) { return this.raceModel.findOne({ where: {seasonId: seasonId, mapUID: mapUID} }) } diff --git a/packages/bridge-server/src/season-standings/season-standings.module.ts b/packages/bridge-server/src/season-standings/season-standings.module.ts index 7420b65..bfa0d90 100644 --- a/packages/bridge-server/src/season-standings/season-standings.module.ts +++ b/packages/bridge-server/src/season-standings/season-standings.module.ts @@ -2,9 +2,15 @@ import { Module } from '@nestjs/common'; import { SequelizeModule } from '@nestjs/sequelize'; import { SeasonStanding } from './season-standing.model'; import { SeasonStandingsService } from './season-standings.service'; +import { RaceResultsModule } from 'src/race-results/race-results.module'; +import { RacesModule } from 'src/races/races.module'; @Module({ - imports: [SequelizeModule.forFeature([SeasonStanding])], + imports: [ + SequelizeModule.forFeature([SeasonStanding]), + RaceResultsModule, + RacesModule + ], providers: [SeasonStandingsService], exports: [SequelizeModule, SeasonStandingsService] }) diff --git a/packages/bridge-server/src/season-standings/season-standings.service.ts b/packages/bridge-server/src/season-standings/season-standings.service.ts index 00124e3..84b4441 100644 --- a/packages/bridge-server/src/season-standings/season-standings.service.ts +++ b/packages/bridge-server/src/season-standings/season-standings.service.ts @@ -2,13 +2,17 @@ import { Injectable } from '@nestjs/common'; import { InjectModel } from '@nestjs/sequelize'; import { SeasonStanding } from './season-standing.model'; import { Sequelize } from 'sequelize-typescript'; +import { RaceResultsService } from 'src/race-results/race-results.service'; +import { RacesService } from 'src/races/races.service'; @Injectable() export class SeasonStandingsService { constructor( @InjectModel(SeasonStanding) private seasonStandingModel: typeof SeasonStanding, - private sequelize: Sequelize + private sequelize: Sequelize, + private raceResultsService: RaceResultsService, + private racesService: RacesService ) {} @@ -30,7 +34,39 @@ export class SeasonStandingsService { } } - updateStandings(seasonId: number) { - + async updateStandings(seasonId: number) { + let racesInSeason = await this.racesService.findManyBySeason(seasonId); + console.log(racesInSeason); + // find unique racers in this season + // for each race in the season + /* + if( this.race.racers == undefined) { + console.log("No racers in race-details") + return; + } + for( let racer_id of this.race?.racers ) { + this.racersService.getRacer(racer_id).subscribe( data => { + if(data != undefined) { + this.racers.set(racer_id, data); + } + }); + + this.raceResultService.getRaceResultsForRacerInRace(racer_id, this.race.id).subscribe( data => { + if(data != undefined) { + this.raceResults.set(racer_id, data); + let result = this.getBestTimeForRacer(racer_id); + if (result != undefined) { + this.sortedResults.push(result) + this.sortedResults.sort((a, b) => { + if( a.time == b.time ) { return 0 }; + if( a.time < b.time ) { return -1}; + return 1; + }) + this.sortedResults = [...this.sortedResults]; + } + } + }); + } + */ } } diff --git a/packages/bridge-server/src/seasons/seasons.controller.ts b/packages/bridge-server/src/seasons/seasons.controller.ts index 9e9e9c9..202fdbd 100644 --- a/packages/bridge-server/src/seasons/seasons.controller.ts +++ b/packages/bridge-server/src/seasons/seasons.controller.ts @@ -1,11 +1,13 @@ import { Body, Controller, Get, Param, Post, UseGuards } from '@nestjs/common'; import { SeasonsService } from './seasons.service'; +import { SeasonStandingsService } from 'src/season-standings/season-standings.service'; import { AuthGuard } from 'src/auth/auth.guard'; @Controller('seasons') export class SeasonsController { constructor( - private seasonsService: SeasonsService + private seasonsService: SeasonsService, + private seasonStandingsService: SeasonStandingsService, ) {} @Get() @@ -18,6 +20,11 @@ export class SeasonsController { return this.seasonsService.findOne(params.id); } + @Get(':id/refresh') + updateSeason(@Param() params: any) { + return this.seasonStandingsService.updateStandings(params.id); + } + @UseGuards(AuthGuard) @Post() create(@Body() body: any) { diff --git a/packages/bridge-server/src/seasons/seasons.module.ts b/packages/bridge-server/src/seasons/seasons.module.ts index 6f4d316..599d663 100644 --- a/packages/bridge-server/src/seasons/seasons.module.ts +++ b/packages/bridge-server/src/seasons/seasons.module.ts @@ -3,9 +3,13 @@ import { SequelizeModule } from '@nestjs/sequelize'; import { Season } from './season.model'; import { SeasonsController } from './seasons.controller'; import { SeasonsService } from './seasons.service'; +import { SeasonStandingsModule } from 'src/season-standings/season-standings.module'; @Module({ - imports: [SequelizeModule.forFeature([Season])], + imports: [ + SequelizeModule.forFeature([Season]), + SeasonStandingsModule + ], providers: [SeasonsService], controllers: [SeasonsController], exports: [SequelizeModule, SeasonsService] diff --git a/packages/bridge-ui/src/app/components/race-details/race-details.component.html b/packages/bridge-ui/src/app/components/race-details/race-details.component.html index 28eb72a..40c0837 100644 --- a/packages/bridge-ui/src/app/components/race-details/race-details.component.html +++ b/packages/bridge-ui/src/app/components/race-details/race-details.component.html @@ -29,7 +29,7 @@ Ghost - + diff --git a/packages/bridge-ui/src/app/components/race-details/race-details.component.scss b/packages/bridge-ui/src/app/components/race-details/race-details.component.scss index b94d987..a522ac3 100644 --- a/packages/bridge-ui/src/app/components/race-details/race-details.component.scss +++ b/packages/bridge-ui/src/app/components/race-details/race-details.component.scss @@ -1,3 +1,3 @@ .img-thumbnail{ - width: 400px; + width: 300px; } \ No newline at end of file diff --git a/packages/bridge-ui/src/app/components/race-details/race-details.component.ts b/packages/bridge-ui/src/app/components/race-details/race-details.component.ts index ca8772c..ee6d13b 100644 --- a/packages/bridge-ui/src/app/components/race-details/race-details.component.ts +++ b/packages/bridge-ui/src/app/components/race-details/race-details.component.ts @@ -63,36 +63,6 @@ export class RaceDetailsComponent { }) this.sortedResults = [...this.sortedResults]; }) - - /* - if( this.race.racers == undefined) { - console.log("No racers in race-details") - return; - } - for( let racer_id of this.race?.racers ) { - this.racersService.getRacer(racer_id).subscribe( data => { - if(data != undefined) { - this.racers.set(racer_id, data); - } - }); - - this.raceResultService.getRaceResultsForRacerInRace(racer_id, this.race.id).subscribe( data => { - if(data != undefined) { - this.raceResults.set(racer_id, data); - let result = this.getBestTimeForRacer(racer_id); - if (result != undefined) { - this.sortedResults.push(result) - this.sortedResults.sort((a, b) => { - if( a.time == b.time ) { return 0 }; - if( a.time < b.time ) { return -1}; - return 1; - }) - this.sortedResults = [...this.sortedResults]; - } - } - }); - } - */ } getBestTimeForRacer(racer_id: string): RaceEntry | undefined { @@ -133,4 +103,21 @@ export class RaceDetailsComponent { return "" } + + blob: Blob = new Blob(); + + onClickDownloadGhost(raceResult: any) { + console.log(raceResult) + this.raceResultService.getGhost(raceResult.id).subscribe(data => { + this.blob = new Blob([data as any], {type: 'application/octet-stream'}); + console.log(this.blob); + + var downloadURL = window.URL.createObjectURL(this.blob); + var link = document.createElement('a'); + link.href = downloadURL; + link.download = this.race?.mapName + " - " + raceResult.racer.gameHandle + ".gbx"; + link.click(); + link.remove(); + }); + } } diff --git a/packages/bridge-ui/src/app/pages/season-details/season-details.component.html b/packages/bridge-ui/src/app/pages/season-details/season-details.component.html index 7524c7f..44fa52c 100644 --- a/packages/bridge-ui/src/app/pages/season-details/season-details.component.html +++ b/packages/bridge-ui/src/app/pages/season-details/season-details.component.html @@ -5,6 +5,7 @@ @if(isAuthed()) { +
} diff --git a/packages/bridge-ui/src/app/pages/season-details/season-details.component.ts b/packages/bridge-ui/src/app/pages/season-details/season-details.component.ts index c7b5486..f9b777e 100644 --- a/packages/bridge-ui/src/app/pages/season-details/season-details.component.ts +++ b/packages/bridge-ui/src/app/pages/season-details/season-details.component.ts @@ -37,6 +37,8 @@ export class SeasonDetailsComponent { season?: Season; races: Race[] = []; + seasonId: string = ""; + constructor( private route: ActivatedRoute, private seasonsService: SeasonsService, @@ -46,8 +48,8 @@ export class SeasonDetailsComponent { ) {} ngOnInit() { - const id = String(this.route.snapshot.paramMap.get('id')); - this.seasonsService.getSeason(id).subscribe( data => { + this.seasonId = String(this.route.snapshot.paramMap.get('id')); + this.seasonsService.getSeason(this.seasonId).subscribe( data => { this.season = data; console.log(data); if (this.season) { @@ -73,4 +75,8 @@ export class SeasonDetailsComponent { data: { seasonId: id } }); } + + forceUpdate(id: string) { + this.seasonsService.updateSeason(this.seasonId); + } } diff --git a/packages/bridge-ui/src/app/services/auth.service.ts b/packages/bridge-ui/src/app/services/auth.service.ts index b6bf618..a9f231e 100644 --- a/packages/bridge-ui/src/app/services/auth.service.ts +++ b/packages/bridge-ui/src/app/services/auth.service.ts @@ -7,7 +7,7 @@ import { jwtDecode } from "jwt-decode"; providedIn: 'root' }) export class AuthService { - serverEndpoint = "http://localhost:3000/" + serverEndpoint = "http://172.16.40.146:3000/" constructor(private httpClient: HttpClient) { } diff --git a/packages/bridge-ui/src/app/services/race-result.service.ts b/packages/bridge-ui/src/app/services/race-result.service.ts index 724d92b..6c06a76 100644 --- a/packages/bridge-ui/src/app/services/race-result.service.ts +++ b/packages/bridge-ui/src/app/services/race-result.service.ts @@ -76,4 +76,11 @@ export class RaceResultService { }); return from(promise); } + + getGhost(raceResultId: string) { + const httpOptions = { + responseType: 'blob' as 'json' + }; + return this.httpClient.get("http://172.16.40.146:3000/race-results/"+raceResultId+"/get-ghost", httpOptions); + } } diff --git a/packages/bridge-ui/src/app/services/races.service.ts b/packages/bridge-ui/src/app/services/races.service.ts index 0f1ae8f..e6443e5 100644 --- a/packages/bridge-ui/src/app/services/races.service.ts +++ b/packages/bridge-ui/src/app/services/races.service.ts @@ -17,18 +17,18 @@ export class RacesService { } getRace(id: string) { - return this.httpClient.get("http://localhost:3000/races/"+id); + return this.httpClient.get("http://172.16.40.146:3000/races/"+id); } getRaceResults(id: string) { - return this.httpClient.get("http://localhost:3000/races/"+id+"/results"); + return this.httpClient.get("http://172.16.40.146:3000/races/"+id+"/results"); } getMapInfo(mapUID: string) { - return this.httpClient.get("http://localhost:3000/races/map/"+mapUID); + return this.httpClient.get("http://172.16.40.146:3000/races/map/"+mapUID); } create(mapUID: string, startDate: Date, endDate: Date, seasonId: number) { - return this.httpClient.post("http://localhost:3000/races", { mapUID: mapUID, startDate: startDate, endDate: endDate, seasonId: seasonId}); + return this.httpClient.post("http://172.16.40.146:3000/races", { mapUID: mapUID, startDate: startDate, endDate: endDate, seasonId: seasonId}); } } diff --git a/packages/bridge-ui/src/app/services/replays.service.ts b/packages/bridge-ui/src/app/services/replays.service.ts index d9c8cbb..48030c9 100644 --- a/packages/bridge-ui/src/app/services/replays.service.ts +++ b/packages/bridge-ui/src/app/services/replays.service.ts @@ -6,7 +6,7 @@ import { Observable } from "rxjs"; providedIn: 'root' }) export class ReplaysService { - server_route: string = "http://localhost:3000/" + server_route: string = "http://172.16.40.146:3000/" constructor(private httpClient: HttpClient) { } diff --git a/packages/bridge-ui/src/app/services/seasons.service.ts b/packages/bridge-ui/src/app/services/seasons.service.ts index f705994..095ec0c 100644 --- a/packages/bridge-ui/src/app/services/seasons.service.ts +++ b/packages/bridge-ui/src/app/services/seasons.service.ts @@ -34,7 +34,7 @@ export class SeasonsService { } let promise = new Promise>((resolve, reject) =>{ - this.httpClient.get>("http://localhost:3000/seasons/").subscribe(data => { + this.httpClient.get>("http://172.16.40.146:3000/seasons/").subscribe(data => { let seasons: Season[] = []; for(let server_season of data) { let _season = this.convertToClientSeason(server_season); @@ -65,7 +65,7 @@ export class SeasonsService { } let promise = new Promise((resolve, reject) =>{ - this.httpClient.get>("http://localhost:3000/seasons/"+id).subscribe(data => { + this.httpClient.get>("http://172.16.40.146:3000/seasons/"+id).subscribe(data => { let _season = this.convertToClientSeason(data); console.log(data); console.log(_season); @@ -76,6 +76,10 @@ export class SeasonsService { } create(title: string, subTitle: string, startingDate: Date) { - return this.httpClient.post("http://localhost:3000/seasons/", {title, subTitle, startingDate}); + return this.httpClient.post("http://172.16.40.146:3000/seasons/", {title, subTitle, startingDate}); + } + + updateSeason(id: string) { + this.httpClient.get("http://172.16.40.146:3000/seasons/"+id+"/refresh").subscribe(data => { }); } }