Skip to content

Commit

Permalink
Merge pull request #139 from game-node-app/dev
Browse files Browse the repository at this point in the history
Tidying up Importer system for PSN
  • Loading branch information
Lamarcke authored Jan 6, 2025
2 parents f465060 + c6fee44 commit 9d12ad6
Show file tree
Hide file tree
Showing 10 changed files with 162 additions and 53 deletions.
2 changes: 1 addition & 1 deletion server_swagger.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { ExternalGameService } from './external-game.service';

describe('ExternalGameService', () => {
let service: ExternalGameService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [ExternalGameService],
}).compile();

service = module.get<ExternalGameService>(ExternalGameService);
});

it('should be defined', () => {
expect(service).toBeDefined();
});
});
64 changes: 64 additions & 0 deletions src/game/game-repository/external-game/external-game.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { GameExternalGame } from "../entities/game-external-game.entity";
import { In, Repository } from "typeorm";
import { days } from "@nestjs/throttler";
import { EGameExternalGameCategory } from "../game-repository.constants";
import { toMap } from "../../../utils/toMap";
import { Game } from "../entities/game.entity";

@Injectable()
export class ExternalGameService {
constructor(
@InjectRepository(GameExternalGame)
private readonly gameExternalGameRepository: Repository<GameExternalGame>,
) {}

private reOrderBySourceIds(
originalIds: string[],
unOrderedGames: GameExternalGame[],
) {
const gamesMap = toMap(unOrderedGames, "uid");

return originalIds
.map((id) => {
return gamesMap.get(id);
})
.filter((game) => game != undefined) as GameExternalGame[];
}

async getExternalGamesForGameIds(gameIds: number[]) {
return this.gameExternalGameRepository.find({
where: {
gameId: In(gameIds),
},
cache: {
id: `external-games-ids-${gameIds}`,
milliseconds: days(1),
},
});
}

/**
* Returns a list of GameExternalGame for each sourceId (referred to as uid)
* @param sourceIds
* @param category
*/
public async getExternalGamesForSourceIds(
sourceIds: string[],
category: EGameExternalGameCategory,
) {
const externalGames = await this.gameExternalGameRepository.find({
where: {
uid: In(sourceIds),
category,
},
cache: {
id: `external-games-ids-${category}-${sourceIds}`,
milliseconds: days(1),
},
});

return this.reOrderBySourceIds(sourceIds, externalGames);
}
}
16 changes: 13 additions & 3 deletions src/game/game-repository/game-repository.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ import { GameCompanyLogo } from "./entities/game-company-logo.entity";
import { GamePlayerPerspective } from "./entities/game-player-perspective.entity";
import { GameRepositoryCreateService } from "./game-repository-create.service";
import { StatisticsQueueModule } from "../../statistics/statistics-queue/statistics-queue.module";
import { GameRepositoryCacheService } from './game-repository-cache.service';
import { GameRepositoryCacheService } from "./game-repository-cache.service";
import { ExternalGameService } from "./external-game/external-game.service";

/**
* This is a pretty big module, with lots of dependencies.
Expand Down Expand Up @@ -55,8 +56,17 @@ import { GameRepositoryCacheService } from './game-repository-cache.service';
]),
forwardRef(() => StatisticsQueueModule),
],
providers: [GameRepositoryService, GameRepositoryCreateService, GameRepositoryCacheService],
exports: [GameRepositoryService, GameRepositoryCreateService],
providers: [
GameRepositoryService,
GameRepositoryCreateService,
GameRepositoryCacheService,
ExternalGameService,
],
exports: [
GameRepositoryService,
GameRepositoryCreateService,
ExternalGameService,
],
controllers: [GameRepositoryController],
})
export class GameRepositoryModule {}
33 changes: 0 additions & 33 deletions src/game/game-repository/game-repository.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,37 +224,4 @@ export class GameRepositoryService {

return iconsNames;
}

async getExternalGamesForGameIds(gameIds: number[]) {
return this.gameExternalGameRepository.find({
where: {
gameId: In(gameIds),
},
cache: {
id: `external-games-ids-${gameIds}`,
milliseconds: days(1),
},
});
}

/**
*
* @param sourceIds
* @param category
*/
async getExternalGamesForSourceIds(
sourceIds: string[],
category: EGameExternalGameCategory,
) {
return this.gameExternalGameRepository.find({
where: {
uid: In(sourceIds),
category,
},
cache: {
id: `external-games-ids-${category}-${sourceIds}`,
milliseconds: days(1),
},
});
}
}
2 changes: 1 addition & 1 deletion src/game/game-repository/game-repository.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
externalGameCategoryToIconMap,
platformAbbreviationToIconMap,
} from "./game-repository.constants";
import { Game } from "./entities/game.entity";
import { toMap } from "../../utils/toMap";

export function getIconNamesForPlatformAbbreviations(abbreviations: string[]) {
const iconsNames: string[] = [];
Expand Down
3 changes: 2 additions & 1 deletion src/importer/dto/importer-paginated-response.dto.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { GameExternalGame } from "../../game/game-repository/entities/game-external-game.entity";
import { PaginationInfo } from "../../utils/pagination/pagination-response.dto";
import { ImporterResponseItemDto } from "./importer-response-item.dto";

export class ImporterPaginatedResponseDto {
data: GameExternalGame[];
data: ImporterResponseItemDto[];
pagination: PaginationInfo;
}
9 changes: 9 additions & 0 deletions src/importer/dto/importer-response-item.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { GameExternalGame } from "../../game/game-repository/entities/game-external-game.entity";

export class ImporterResponseItemDto extends GameExternalGame {
/**
* The preferred platform to use when adding this importer item to a user's collection.
* @see CollectionsEntriesService#createOrUpdate
*/
preferredPlatformId: number;
}
66 changes: 54 additions & 12 deletions src/importer/importer.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@ import { ImporterIgnoredEntry } from "./entity/importer-ignored-entry.entity";
import { ConnectionsService } from "../connections/connections.service";
import { EConnectionType } from "../connections/connections.constants";
import { SteamSyncService } from "../sync/steam/steam-sync.service";
import { GameRepositoryService } from "../game/game-repository/game-repository.service";
import { ImporterStatusUpdateRequestDto } from "./dto/importer-status-update-request.dto";
import { EImporterSource } from "./importer.constants";
import { EGameExternalGameCategory } from "../game/game-repository/game-repository.constants";
import { GameExternalGame } from "../game/game-repository/entities/game-external-game.entity";
import { ImporterUnprocessedRequestDto } from "./dto/importer-unprocessed-request.dto";
import { TPaginationData } from "../utils/pagination/pagination-response.dto";
import { ImporterEntry } from "./entity/importer-entry.entity";
import { PsnSyncService } from "../sync/psn/psn-sync.service";
import { HttpStatusCode } from "axios";
import { ImporterResponseItemDto } from "./dto/importer-response-item.dto";
import { ExternalGameService } from "../game/game-repository/external-game/external-game.service";

@Injectable()
export class ImporterService {
Expand All @@ -26,7 +26,7 @@ export class ImporterService {
private readonly ignoredEntryRepository: Repository<ImporterIgnoredEntry>,
private readonly connectionsService: ConnectionsService,
private readonly steamSyncService: SteamSyncService,
private readonly gameRepositoryService: GameRepositoryService,
private readonly externalGameService: ExternalGameService,
private readonly psnSyncService: PsnSyncService,
) {}

Expand Down Expand Up @@ -72,15 +72,25 @@ export class ImporterService {
const gamesUids = games.map((item) => `${item.game.id}`);

const externalGames =
await this.gameRepositoryService.getExternalGamesForSourceIds(
await this.externalGameService.getExternalGamesForSourceIds(
gamesUids,
EGameExternalGameCategory.Steam,
);

return externalGames.filter(
const filteredGames = externalGames.filter(
(externalGame) =>
!ignoredExternalGamesIds.includes(externalGame.id),
);

return filteredGames.map(
(item): ImporterResponseItemDto => ({
...item,
/* PC platform ID
* @see GamePlatform#id
*/
preferredPlatformId: 6,
}),
);
}

private async findUnprocessedPsnEntries(userId: string) {
Expand Down Expand Up @@ -114,28 +124,60 @@ export class ImporterService {
);
}

const gamesUids = games.map((item) => {
const gameUids = games.map((item) => {
return `${item.concept.id}`;
});

const uniqueGameUids = Array.from(new Set(gameUids));

const externalGames =
await this.gameRepositoryService.getExternalGamesForSourceIds(
gamesUids,
EGameExternalGameCategory.Steam,
await this.externalGameService.getExternalGamesForSourceIds(
uniqueGameUids,
EGameExternalGameCategory.PlaystationStoreUs,
);

return externalGames.filter(
const filteredGames = externalGames.filter(
(externalGame) =>
!ignoredExternalGamesIds.includes(externalGame.id),
);

return filteredGames.map((item): ImporterResponseItemDto => {
const relatedOriginalGame = games.find(
(game) => `${game.concept.id}` === item.uid,
)!;

/*
* @see GamePlatform#id
*/
let targetPlatformId: number;
switch (relatedOriginalGame.category) {
case "ps4_game":
// ps4 platform id
targetPlatformId = 48;
break;
case "ps5_game":
// ps5 platform id
targetPlatformId = 167;
break;
default:
// ps4 platform id
targetPlatformId = 48;
break;
}

return {
...item,
preferredPlatformId: targetPlatformId,
};
});
}

public async findUnprocessedEntries(
userId: string,
source: EImporterSource,
dto: ImporterUnprocessedRequestDto,
): Promise<TPaginationData<GameExternalGame>> {
let entries: GameExternalGame[] = [];
): Promise<TPaginationData<ImporterResponseItemDto>> {
let entries: ImporterResponseItemDto[] = [];
switch (source) {
case EImporterSource.STEAM:
entries = await this.findUnprocessedSteamEntries(userId);
Expand Down
2 changes: 0 additions & 2 deletions src/utils/toMap.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { Game } from "../game/game-repository/entities/game.entity";

type IdentifierType<T, K extends keyof T> = T[K] extends number
? number
: T[K] extends string
Expand Down

0 comments on commit 9d12ad6

Please sign in to comment.