Skip to content

Commit

Permalink
Fix attack log
Browse files Browse the repository at this point in the history
  • Loading branch information
csuvajit committed Apr 13, 2024
1 parent fef68fa commit 4bb70b2
Show file tree
Hide file tree
Showing 11 changed files with 101 additions and 228 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/aws-ecr-push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:

strategy:
matrix:
service: [service-auth, service-capital, service-clans, service-wars]
service: [service-auth, service-clans]

runs-on: buildjet-4vcpu-ubuntu-2204-arm

Expand Down
54 changes: 26 additions & 28 deletions apps/service-auth/src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { KafkaConsumerModule, KafkaProducerModule } from '@app/kafka';
import { MongoDbModule } from '@app/mongodb';
import { RedisModule } from '@app/redis';
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { ConfigModule } from '@nestjs/config';
import { AuthModule } from './auth/auth.module';
import { ClansModule } from './clans/clans.module';
import { ConsumerModule } from './consumer/consumer.module';
import { GuildsModule } from './guilds/guilds.module';
import { LinksModule } from './links/links.module';
import { PlayersModule } from './players/players.module';
Expand All @@ -20,31 +18,31 @@ import { PlayersModule } from './players/players.module';
GuildsModule,
LinksModule,
PlayersModule,
KafkaProducerModule.forRootAsync({
useFactory: (configService: ConfigService) => {
return {
kafkaConfig: {
clientId: 'kafka-client-id',
brokers: [configService.getOrThrow('KAFKA_BROKER')],
},
producerConfig: {},
};
},
inject: [ConfigService],
}),
KafkaConsumerModule.forRootAsync({
useFactory: (configService: ConfigService) => {
return {
kafkaConfig: {
clientId: 'kafka-client-id',
brokers: [configService.getOrThrow('KAFKA_BROKER')],
},
consumerConfig: { groupId: 'kafka-consumer-group' },
};
},
inject: [ConfigService],
}),
ConsumerModule,
// KafkaProducerModule.forRootAsync({
// useFactory: (configService: ConfigService) => {
// return {
// kafkaConfig: {
// clientId: 'kafka-client-id',
// brokers: [configService.getOrThrow('KAFKA_BROKER')],
// },
// producerConfig: {},
// };
// },
// inject: [ConfigService],
// }),
// KafkaConsumerModule.forRootAsync({
// useFactory: (configService: ConfigService) => {
// return {
// kafkaConfig: {
// clientId: 'kafka-client-id',
// brokers: [configService.getOrThrow('KAFKA_BROKER')],
// },
// consumerConfig: { groupId: 'kafka-consumer-group' },
// };
// },
// inject: [ConfigService],
// }),
// ConsumerModule,
],
controllers: [],
providers: [],
Expand Down
27 changes: 2 additions & 25 deletions apps/service-auth/src/clans/clans.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
ClanWarsEntity,
PlayerLinksEntity,
} from '@app/entities';
import { getPreviousBestAttack } from '@app/helper';
import { Inject, Injectable, NotFoundException } from '@nestjs/common';
import { APIClanWarAttack, APIWarClan } from 'clashofclans.js';
import { Collection } from 'mongodb';
Expand Down Expand Up @@ -293,7 +294,7 @@ export class ClansService {
member.participated += 1;

for (const atk of m.attacks ?? []) {
const previousBestAttack = this.getPreviousBestAttack(__attacks, opponent, atk);
const previousBestAttack = getPreviousBestAttack(__attacks, opponent, atk);
member.attacks += 1;
member.stars += atk.stars;
member.newStars += previousBestAttack
Expand Down Expand Up @@ -337,28 +338,4 @@ export class ClansService {
if (clan.stars > opponent.stars) return 'won';
return 'lost';
}

private getPreviousBestAttack(
attacks: APIClanWarAttack[],
opponent: APIWarClan,
atk: APIClanWarAttack,
) {
const defender = opponent.members.find((m) => m.tag === atk.defenderTag);
const defenderDefenses = attacks.filter((atk) => atk.defenderTag === defender?.tag);
const isFresh =
defenderDefenses.length === 0 ||
atk.order === Math.min(...defenderDefenses.map((d) => d.order));
const previousBestAttack = isFresh
? null
: [...attacks]
.filter(
(_atk) =>
_atk.defenderTag === defender?.tag &&
_atk.order < atk.order &&
_atk.attackerTag !== atk.attackerTag,
)
.sort((a, b) => b.destructionPercentage ** b.stars - a.destructionPercentage ** a.stars)
.at(0) ?? null;
return isFresh ? null : previousBestAttack;
}
}
26 changes: 9 additions & 17 deletions apps/service-auth/src/consumer/consumer.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,19 @@ import { KAFKA_CONSUMER } from '@app/kafka';
import { Inject, Injectable } from '@nestjs/common';
import { Consumer } from 'kafkajs';

enum LogType {
CLAN_LEVEL_CHANGE = 'clan_level_change',
CLAN_WAR_LEAGUE_CHANGE = 'clan_war_league_change',
CAPITAL_LEAGUE_CHANGE = 'capital_league_change',
CLAN_MEMBER_CHANGE = 'clan_member_change',
}

@Injectable()
export class ConsumerService {
constructor(@Inject(KAFKA_CONSUMER) private consumer: Consumer) {}

async onModuleInit() {
await this.consumer.subscribe({ topics: Object.values(LogType), fromBeginning: true });

await this.consumer.run({
eachMessage: async ({ message, topic }) => {
console.log({
topic,
value: message.value?.toString(),
});
},
});
// await this.consumer.subscribe({ topics: Object.values(LogType), fromBeginning: true });
// await this.consumer.run({
// eachMessage: async ({ topic, message }) => {
// console.log({
// topic,
// value: message.value?.toString(),
// });
// },
// });
}
}
31 changes: 0 additions & 31 deletions apps/service-auth/src/players/dto/attack-history-output.dto.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,5 @@
import { ApiProperty } from '@nestjs/swagger';

export class AttackHistoryAggregated {
id: number;
warType: number;
startTime: string;
endTime: string;
clan: {
name: string;
tag: string;
};
opponent: {
name: string;
tag: string;
};
members: {
name: string;
tag: string;
townhallLevel: number;
mapPosition: number;
attacks?: {
stars: number;
defenderTag: string;
destructionPercentage: number;
}[];
}[];
defenders: {
tag: string;
townhallLevel: number;
mapPosition: number;
}[];
}

export class AttackRecord {
stars: number;
defenderTag: string;
Expand Down
156 changes: 33 additions & 123 deletions apps/service-auth/src/players/players.service.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Collections } from '@app/constants';
import { ClanWarsEntity } from '@app/entities';
import { getPreviousBestAttack } from '@app/helper';
import { Inject, Injectable } from '@nestjs/common';
import moment from 'moment';
import { Collection } from 'mongodb';
import { AttackHistoryAggregated, AttackHistoryOutput, CWLAttackSummaryOutput } from './dto';
import { AttackHistoryOutput, CWLAttackSummaryOutput } from './dto';

@Injectable()
export class PlayersService {
Expand All @@ -13,17 +14,10 @@ export class PlayersService {
) {}

async getClanWarHistory(playerTag: string, months: number) {
const cursor = this.clanWarsCollection.aggregate<AttackHistoryAggregated>([
const cursor = this.clanWarsCollection.aggregate<ClanWarsEntity>([
{
$match: {
$or: [
{
'clan.members.tag': playerTag,
},
{
'opponent.members.tag': playerTag,
},
],
$or: [{ 'clan.members.tag': playerTag }, { 'opponent.members.tag': playerTag }],
preparationStartTime: {
$gte: moment().startOf('month').subtract(months, 'month').toDate(),
},
Expand All @@ -37,127 +31,43 @@ export class PlayersService {
_id: -1,
},
},
{
$set: {
members: {
$filter: {
input: {
$concatArrays: ['$opponent.members', '$clan.members'],
},
as: 'member',
cond: {
$eq: ['$$member.tag', playerTag],
},
},
},
},
},
{
$set: {
defenderTags: {
$arrayElemAt: ['$members.attacks.defenderTag', 0],
},
},
},
{
$set: {
defenders: {
$filter: {
input: {
$concatArrays: ['$opponent.members', '$clan.members'],
},
as: 'member',
cond: {
$in: [
'$$member.tag',
{
$cond: [{ $anyElementTrue: [['$defenderTags']] }, '$defenderTags', []],
},
],
},
},
},
},
},
{
$project: {
id: 1,
warType: 1,
startTime: '$preparationStartTime',
endTime: '$preparationStartTime',
clan: {
$cond: [
{
$in: [playerTag, '$clan.members.tag'],
},
{
name: '$clan.name',
tag: '$clan.tag',
},
{
name: '$opponent.name',
tag: '$opponent.tag',
},
],
},
opponent: {
$cond: [
{
$in: [playerTag, '$clan.members.tag'],
},
{
name: '$opponent.name',
tag: '$opponent.tag',
},
{
name: '$clan.name',
tag: '$clan.tag',
},
],
},
members: {
tag: 1,
name: 1,
townhallLevel: 1,
mapPosition: 1,
attacks: {
stars: 1,
defenderTag: 1,
destructionPercentage: 1,
},
},
defenders: {
tag: 1,
townhallLevel: 1,
mapPosition: 1,
},
},
},
]);

const history = await cursor.toArray();

const wars: AttackHistoryOutput[] = [];
for (const war of history) {
const attacker = war.members.at(0)!;
const attacks = (attacker.attacks ?? []).map((attack) => {
const defender = war.defenders.find((defender) => defender.tag === attack.defenderTag)!;
return { ...attack, defender };

for await (const war of cursor) {
const isPlayerInClan = war.clan.members.find((mem) => mem.tag === playerTag);
const clan = isPlayerInClan ? war.clan : war.opponent;
const opponent = isPlayerInClan ? war.opponent : war.clan;

clan.members.sort((a, b) => a.mapPosition - b.mapPosition);
opponent.members.sort((a, b) => a.mapPosition - b.mapPosition);

const __attacks = clan.members.map((mem) => mem.attacks ?? []).flat();
const attacker = clan.members.find((mem) => mem.tag === playerTag)!;

const attacks = (attacker.attacks ?? []).map((atk) => {
const previousBestAttack = getPreviousBestAttack(__attacks, opponent, atk);
const defender = opponent.members.find((mem) => mem.tag === atk.defenderTag)!;

return {
...atk,
newStars: previousBestAttack
? Math.max(0, atk.stars - previousBestAttack.stars)
: atk.stars,
oldStars: previousBestAttack?.stars ?? 0,
defender,
};
});

wars.push({
id: war.id,
warType: war.warType,
startTime: war.startTime,
clan,
opponent,
endTime: war.endTime,
clan: war.clan,
opponent: war.opponent,
attacker: {
name: attacker.name,
tag: attacker.tag,
townhallLevel: attacker.townhallLevel,
mapPosition: attacker.mapPosition,
},
startTime: war.startTime,
warType: war.warType,
attacker,
attacks,
});
}
Expand Down
2 changes: 2 additions & 0 deletions apps/service-clans/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ async function bootstrap() {
const app = await NestFactory.create(ServiceClansModule);
const logger = new Logger('NestApplication');

app.enableShutdownHooks();

const port = process.env.PORT || 8082;
await app.listen(port);

Expand Down
Loading

0 comments on commit 4bb70b2

Please sign in to comment.