@firestone-hs/bgs-global-stats 1.0.47 → 1.0.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/internal-model.d.ts +29 -0
  2. package/dist/internal-model.js.map +1 -1
  3. package/dist/model-cards.d.ts +37 -0
  4. package/dist/model-cards.js +3 -0
  5. package/dist/model-cards.js.map +1 -0
  6. package/dist/public-api.d.ts +1 -0
  7. package/dist/public-api.js +1 -0
  8. package/dist/public-api.js.map +1 -1
  9. package/dist/solo/aggregate-hourly/cards/_build-aggregated-stats.d.ts +7 -0
  10. package/dist/solo/aggregate-hourly/cards/_build-aggregated-stats.js +62 -0
  11. package/dist/solo/aggregate-hourly/cards/_build-aggregated-stats.js.map +1 -0
  12. package/dist/solo/aggregate-hourly/cards/s3-saver.d.ts +3 -0
  13. package/dist/solo/aggregate-hourly/cards/s3-saver.js +18 -0
  14. package/dist/solo/aggregate-hourly/cards/s3-saver.js.map +1 -0
  15. package/dist/solo/aggregate-hourly/cards/stats-builder.d.ts +4 -0
  16. package/dist/solo/aggregate-hourly/cards/stats-builder.js +86 -0
  17. package/dist/solo/aggregate-hourly/cards/stats-builder.js.map +1 -0
  18. package/dist/solo/aggregate-hourly/config.d.ts +1 -0
  19. package/dist/solo/aggregate-hourly/config.js +2 -1
  20. package/dist/solo/aggregate-hourly/config.js.map +1 -1
  21. package/dist/solo/aggregate-hourly/s3-loader.d.ts +3 -3
  22. package/dist/solo/aggregate-hourly/s3-loader.js +9 -1
  23. package/dist/solo/aggregate-hourly/s3-loader.js.map +1 -1
  24. package/dist/solo/hourly/_build-battlegrounds-hero-stats.d.ts +1 -0
  25. package/dist/solo/hourly/_build-battlegrounds-hero-stats.js +33 -2
  26. package/dist/solo/hourly/_build-battlegrounds-hero-stats.js.map +1 -1
  27. package/dist/solo/hourly/cards/card-stats-builder.d.ts +3 -0
  28. package/dist/solo/hourly/cards/card-stats-builder.js +64 -0
  29. package/dist/solo/hourly/cards/card-stats-builder.js.map +1 -0
  30. package/dist/solo/hourly/cards/card-stats.d.ts +4 -0
  31. package/dist/solo/hourly/cards/card-stats.js +27 -0
  32. package/dist/solo/hourly/cards/card-stats.js.map +1 -0
  33. package/dist/solo/hourly/rows.js +2 -0
  34. package/dist/solo/hourly/rows.js.map +1 -1
  35. package/package.json +1 -1
@@ -22,6 +22,11 @@ export interface InternalBgsRow {
22
22
  readonly bgsTrinketsOptions: string;
23
23
  readonly heroesOptions: string;
24
24
  readonly heroesOptionsExpanded: readonly string[];
25
+ readonly playedCards: string;
26
+ readonly playedCardsExpanded: readonly {
27
+ cardId: string;
28
+ turn: number;
29
+ }[];
25
30
  }
26
31
  import { MmrPercentile, WithMmrAndTimePeriod } from './models';
27
32
  export interface InternalBgsTrinketStats {
@@ -30,6 +35,30 @@ export interface InternalBgsTrinketStats {
30
35
  readonly dataPoints: number;
31
36
  readonly trinketStats: readonly WithMmrAndTimePeriod<InternalBgsGlobalTrinketStat>[];
32
37
  }
38
+ export interface InternalBgsCardStats {
39
+ readonly lastUpdateDate: Date;
40
+ readonly mmrPercentiles: readonly MmrPercentile[];
41
+ readonly dataPoints: number;
42
+ readonly cardStats: readonly WithMmrAndTimePeriod<InternalBgsCardStat>[];
43
+ }
44
+ export interface InternalBgsCardStat {
45
+ readonly cardId: string;
46
+ readonly totalPlayed: number;
47
+ readonly averagePlacement: number;
48
+ readonly turnStats: readonly InternalBgsCardTurnStat[];
49
+ readonly heroStats: readonly InternalBgsCardHeroStat[];
50
+ }
51
+ export interface InternalBgsCardHeroStat {
52
+ readonly heroCardId: string;
53
+ readonly totalPlayedWithHero: number;
54
+ readonly averagePlacement: number;
55
+ readonly turnStats: readonly InternalBgsCardTurnStat[];
56
+ }
57
+ export interface InternalBgsCardTurnStat {
58
+ readonly turn: number;
59
+ readonly totalPlayedAtTurn: number;
60
+ readonly averagePlacement: number;
61
+ }
33
62
  export interface InternalBgsGlobalTrinketStat {
34
63
  readonly trinketCardId: string;
35
64
  readonly dataPoints: number;
@@ -1 +1 @@
1
- {"version":3,"file":"internal-model.js","sourceRoot":"","sources":["../src/internal-model.ts"],"names":[],"mappings":"","sourcesContent":["import { Race } from '@firestone-hs/reference-data';\r\n\r\n// bgs_run_stats and bgs_run_stats_duo\r\nexport interface InternalBgsRow {\r\n\treadonly id: number;\r\n\treadonly reviewId: string;\r\n\treadonly creationDate: Date;\r\n\treadonly buildNumber: number;\r\n\treadonly rating: number;\r\n\t// Normalized once it goes out of the \"rows.ts\" process\r\n\treadonly heroCardId: string;\r\n\treadonly playerRank: number;\r\n\t/** @deprecated */\r\n\treadonly tribes: string;\r\n\treadonly tribesExpanded: readonly Race[];\r\n\t/** @deprecated */\r\n\treadonly combatWinrate: string;\r\n\t// readonly combatWinrateExpanded: readonly { turn: number; winrate: number }[];\r\n\t/** @deprecated */\r\n\treadonly warbandStats: string;\r\n\t// readonly warbandStatsExpanded: readonly { turn: number; totalStats: number }[];\r\n\treadonly darkmoonPrizes: boolean;\r\n\treadonly quests: boolean;\r\n\treadonly bgsHeroQuests: string;\r\n\treadonly bgsQuestsCompletedTimings: string;\r\n\treadonly bgsQuestsDifficulties: string;\r\n\treadonly bgsHeroQuestRewards: string;\r\n\treadonly bgsAnomalies: string;\r\n\treadonly bgsTrinkets: string;\r\n\treadonly bgsTrinketsOptions: string;\r\n\t/** @deprecated */\r\n\treadonly heroesOptions: string;\r\n\treadonly heroesOptionsExpanded: readonly string[];\r\n}\r\n\r\nimport { MmrPercentile, WithMmrAndTimePeriod } from './models';\r\n\r\nexport interface InternalBgsTrinketStats {\r\n\treadonly lastUpdateDate: Date;\r\n\treadonly mmrPercentiles: readonly MmrPercentile[];\r\n\treadonly dataPoints: number;\r\n\treadonly trinketStats: readonly WithMmrAndTimePeriod<InternalBgsGlobalTrinketStat>[];\r\n}\r\n\r\nexport interface InternalBgsGlobalTrinketStat {\r\n\treadonly trinketCardId: string;\r\n\treadonly dataPoints: number;\r\n\treadonly totalOffered: number;\r\n\treadonly averagePlacement: number;\r\n\treadonly heroStats: readonly InternalBgsTrinketHeroStat[];\r\n}\r\n\r\nexport interface InternalBgsTrinketHeroStat {\r\n\treadonly heroCardId: string;\r\n\treadonly dataPoints: number;\r\n\treadonly averagePlacement: number;\r\n}\r\n"]}
1
+ {"version":3,"file":"internal-model.js","sourceRoot":"","sources":["../src/internal-model.ts"],"names":[],"mappings":"","sourcesContent":["import { Race } from '@firestone-hs/reference-data';\r\n\r\n// bgs_run_stats and bgs_run_stats_duo\r\nexport interface InternalBgsRow {\r\n\treadonly id: number;\r\n\treadonly reviewId: string;\r\n\treadonly creationDate: Date;\r\n\treadonly buildNumber: number;\r\n\treadonly rating: number;\r\n\t// Normalized once it goes out of the \"rows.ts\" process\r\n\treadonly heroCardId: string;\r\n\treadonly playerRank: number;\r\n\t/** @deprecated */\r\n\treadonly tribes: string;\r\n\treadonly tribesExpanded: readonly Race[];\r\n\t/** @deprecated */\r\n\treadonly combatWinrate: string;\r\n\t// readonly combatWinrateExpanded: readonly { turn: number; winrate: number }[];\r\n\t/** @deprecated */\r\n\treadonly warbandStats: string;\r\n\t// readonly warbandStatsExpanded: readonly { turn: number; totalStats: number }[];\r\n\treadonly darkmoonPrizes: boolean;\r\n\treadonly quests: boolean;\r\n\treadonly bgsHeroQuests: string;\r\n\treadonly bgsQuestsCompletedTimings: string;\r\n\treadonly bgsQuestsDifficulties: string;\r\n\treadonly bgsHeroQuestRewards: string;\r\n\treadonly bgsAnomalies: string;\r\n\treadonly bgsTrinkets: string;\r\n\treadonly bgsTrinketsOptions: string;\r\n\t/** @deprecated */\r\n\treadonly heroesOptions: string;\r\n\treadonly heroesOptionsExpanded: readonly string[];\r\n\treadonly playedCards: string;\r\n\treadonly playedCardsExpanded: readonly { cardId: string; turn: number }[];\r\n}\r\n\r\nimport { MmrPercentile, WithMmrAndTimePeriod } from './models';\r\n\r\nexport interface InternalBgsTrinketStats {\r\n\treadonly lastUpdateDate: Date;\r\n\treadonly mmrPercentiles: readonly MmrPercentile[];\r\n\treadonly dataPoints: number;\r\n\treadonly trinketStats: readonly WithMmrAndTimePeriod<InternalBgsGlobalTrinketStat>[];\r\n}\r\n\r\nexport interface InternalBgsCardStats {\r\n\treadonly lastUpdateDate: Date;\r\n\treadonly mmrPercentiles: readonly MmrPercentile[];\r\n\treadonly dataPoints: number;\r\n\treadonly cardStats: readonly WithMmrAndTimePeriod<InternalBgsCardStat>[];\r\n}\r\n\r\nexport interface InternalBgsCardStat {\r\n\treadonly cardId: string;\r\n\treadonly totalPlayed: number;\r\n\treadonly averagePlacement: number;\r\n\treadonly turnStats: readonly InternalBgsCardTurnStat[];\r\n\treadonly heroStats: readonly InternalBgsCardHeroStat[];\r\n}\r\n\r\nexport interface InternalBgsCardHeroStat {\r\n\treadonly heroCardId: string;\r\n\treadonly totalPlayedWithHero: number;\r\n\treadonly averagePlacement: number;\r\n\treadonly turnStats: readonly InternalBgsCardTurnStat[];\r\n}\r\n\r\nexport interface InternalBgsCardTurnStat {\r\n\treadonly turn: number;\r\n\treadonly totalPlayedAtTurn: number;\r\n\treadonly averagePlacement: number;\r\n}\r\n\r\nexport interface InternalBgsGlobalTrinketStat {\r\n\treadonly trinketCardId: string;\r\n\treadonly dataPoints: number;\r\n\treadonly totalOffered: number;\r\n\treadonly averagePlacement: number;\r\n\treadonly heroStats: readonly InternalBgsTrinketHeroStat[];\r\n}\r\n\r\nexport interface InternalBgsTrinketHeroStat {\r\n\treadonly heroCardId: string;\r\n\treadonly dataPoints: number;\r\n\treadonly averagePlacement: number;\r\n}\r\n"]}
@@ -0,0 +1,37 @@
1
+ import { TimePeriod } from './models';
2
+ export interface BgsCardStats {
3
+ readonly lastUpdateDate: Date;
4
+ readonly dataPoints: number;
5
+ readonly timePeriod: TimePeriod;
6
+ readonly cardStats: readonly BgsCardStat[];
7
+ }
8
+ export interface BgsCardStat {
9
+ readonly cardId: string;
10
+ readonly totalPlayed: number;
11
+ readonly averagePlacement: number;
12
+ readonly averagePlacementAtMmr: readonly {
13
+ mmr: number;
14
+ placement: number;
15
+ }[];
16
+ readonly turnStats: readonly BgsCardTurnStat[];
17
+ readonly heroStats: readonly BgsCardHeroStat[];
18
+ }
19
+ export interface BgsCardHeroStat {
20
+ readonly heroCardId: string;
21
+ readonly totalPlayedWithHero: number;
22
+ readonly averagePlacement: number;
23
+ readonly averagePlacementAtMmr: readonly {
24
+ mmr: number;
25
+ placement: number;
26
+ }[];
27
+ readonly turnStats: readonly BgsCardTurnStat[];
28
+ }
29
+ export interface BgsCardTurnStat {
30
+ readonly turn: number;
31
+ readonly totalPlayedAtTurn: number;
32
+ readonly averagePlacement: number;
33
+ readonly averagePlacementAtMmr: readonly {
34
+ mmr: number;
35
+ placement: number;
36
+ }[];
37
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=model-cards.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-cards.js","sourceRoot":"","sources":["../src/model-cards.ts"],"names":[],"mappings":"","sourcesContent":["import { TimePeriod } from './models';\r\n\r\nexport interface BgsCardStats {\r\n\treadonly lastUpdateDate: Date;\r\n\treadonly dataPoints: number;\r\n\treadonly timePeriod: TimePeriod;\r\n\treadonly cardStats: readonly BgsCardStat[];\r\n}\r\n\r\nexport interface BgsCardStat {\r\n\treadonly cardId: string;\r\n\treadonly totalPlayed: number;\r\n\treadonly averagePlacement: number;\r\n\treadonly averagePlacementAtMmr: readonly {\r\n\t\tmmr: number;\r\n\t\tplacement: number;\r\n\t}[];\r\n\treadonly turnStats: readonly BgsCardTurnStat[];\r\n\treadonly heroStats: readonly BgsCardHeroStat[];\r\n}\r\n\r\nexport interface BgsCardHeroStat {\r\n\treadonly heroCardId: string;\r\n\treadonly totalPlayedWithHero: number;\r\n\treadonly averagePlacement: number;\r\n\treadonly averagePlacementAtMmr: readonly {\r\n\t\tmmr: number;\r\n\t\tplacement: number;\r\n\t}[];\r\n\treadonly turnStats: readonly BgsCardTurnStat[];\r\n}\r\n\r\nexport interface BgsCardTurnStat {\r\n\treadonly turn: number;\r\n\treadonly totalPlayedAtTurn: number;\r\n\treadonly averagePlacement: number;\r\n\treadonly averagePlacementAtMmr: readonly {\r\n\t\tmmr: number;\r\n\t\tplacement: number;\r\n\t}[];\r\n}\r\n"]}
@@ -1,3 +1,4 @@
1
+ export * from './model-cards';
1
2
  export * from './model-quests';
2
3
  export * from './model-trinkets';
3
4
  export * from './models';
@@ -14,6 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./model-cards"), exports);
17
18
  __exportStar(require("./model-quests"), exports);
18
19
  __exportStar(require("./model-trinkets"), exports);
19
20
  __exportStar(require("./models"), exports);
@@ -1 +1 @@
1
- {"version":3,"file":"public-api.js","sourceRoot":"","sources":["../src/public-api.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,iDAA+B;AAC/B,mDAAiC;AACjC,2CAAyB","sourcesContent":["export * from './model-quests';\r\nexport * from './model-trinkets';\r\nexport * from './models';\r\n"]}
1
+ {"version":3,"file":"public-api.js","sourceRoot":"","sources":["../src/public-api.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,gDAA8B;AAC9B,iDAA+B;AAC/B,mDAAiC;AACjC,2CAAyB","sourcesContent":["export * from './model-cards';\r\nexport * from './model-quests';\r\nexport * from './model-trinkets';\r\nexport * from './models';\r\n"]}
@@ -0,0 +1,7 @@
1
+ import { S3 } from '@firestone-hs/aws-lambda-utils';
2
+ import { Context } from 'aws-lambda';
3
+ import { MmrPercentileFilter } from '../../../models';
4
+ export declare const s3: S3;
5
+ export declare const mmrPercentiles: readonly MmrPercentileFilter[];
6
+ declare const _default: (event: any, context: Context) => Promise<any>;
7
+ export default _default;
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.mmrPercentiles = exports.s3 = void 0;
7
+ const aws_lambda_utils_1 = require("@firestone-hs/aws-lambda-utils");
8
+ const reference_data_1 = require("@firestone-hs/reference-data");
9
+ const aws_sdk_1 = __importDefault(require("aws-sdk"));
10
+ const s3_loader_1 = require("../s3-loader");
11
+ const s3_saver_1 = require("./s3-saver");
12
+ const stats_builder_1 = require("./stats-builder");
13
+ const allCards = new reference_data_1.AllCardsService();
14
+ exports.s3 = new aws_lambda_utils_1.S3();
15
+ const lambda = new aws_sdk_1.default.Lambda();
16
+ const allTimePeriod = ['all-time', 'past-three', 'past-seven', 'last-patch'];
17
+ exports.mmrPercentiles = [100, 50, 25, 10, 1];
18
+ exports.default = async (event, context) => {
19
+ await allCards.initializeCardsDb();
20
+ if (!event.timePeriod) {
21
+ await dispatchEvents(context);
22
+ return;
23
+ }
24
+ const cleanup = (0, aws_lambda_utils_1.logBeforeTimeout)(context);
25
+ const timePeriod = event.timePeriod;
26
+ const patchInfo = await (0, aws_lambda_utils_1.getLastBattlegroundsPatch)();
27
+ const hourlyData = (await Promise.all(exports.mmrPercentiles.map((mmrPercentile) => (0, s3_loader_1.loadHourlyDataFromS3)('card', timePeriod, mmrPercentile, patchInfo)))).flat();
28
+ const lastUpdate = hourlyData
29
+ .map((d) => ({
30
+ date: new Date(d.lastUpdateDate),
31
+ dateStr: d.lastUpdateDate,
32
+ time: new Date(d.lastUpdateDate).getTime(),
33
+ }))
34
+ .sort((a, b) => b.time - a.time)[0].date;
35
+ const mergedStats = (0, stats_builder_1.buildCardStats)(hourlyData, allCards);
36
+ await (0, s3_saver_1.persistData)(mergedStats, timePeriod, lastUpdate);
37
+ cleanup();
38
+ };
39
+ const dispatchEvents = async (context) => {
40
+ console.log('dispatching events');
41
+ for (const timePeriod of allTimePeriod) {
42
+ const newEvent = {
43
+ timePeriod: timePeriod,
44
+ };
45
+ const params = {
46
+ FunctionName: context.functionName,
47
+ InvocationType: 'Event',
48
+ LogType: 'Tail',
49
+ Payload: JSON.stringify(newEvent),
50
+ };
51
+ const result = await lambda
52
+ .invoke({
53
+ FunctionName: context.functionName,
54
+ InvocationType: 'Event',
55
+ LogType: 'Tail',
56
+ Payload: JSON.stringify(newEvent),
57
+ })
58
+ .promise();
59
+ await (0, aws_lambda_utils_1.sleep)(50);
60
+ }
61
+ };
62
+ //# sourceMappingURL=_build-aggregated-stats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_build-aggregated-stats.js","sourceRoot":"","sources":["../../../../src/solo/aggregate-hourly/cards/_build-aggregated-stats.ts"],"names":[],"mappings":";;;;;;AAAA,qEAAwG;AACxG,iEAA+D;AAE/D,sDAA0B;AAI1B,4CAAoD;AACpD,yCAAyC;AACzC,mDAAiD;AAEjD,MAAM,QAAQ,GAAG,IAAI,gCAAe,EAAE,CAAC;AAC1B,QAAA,EAAE,GAAG,IAAI,qBAAE,EAAE,CAAC;AAC3B,MAAM,MAAM,GAAG,IAAI,iBAAG,CAAC,MAAM,EAAE,CAAC;AAEhC,MAAM,aAAa,GAA0B,CAAC,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,CAAC,CAAC;AACvF,QAAA,cAAc,GAAmC,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;AAEnF,kBAAe,KAAK,EAAE,KAAK,EAAE,OAAgB,EAAgB,EAAE;IAC9D,MAAM,QAAQ,CAAC,iBAAiB,EAAE,CAAC;IAEnC,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE;QACtB,MAAM,cAAc,CAAC,OAAO,CAAC,CAAC;QAC9B,OAAO;KACP;IAED,MAAM,OAAO,GAAG,IAAA,mCAAgB,EAAC,OAAO,CAAC,CAAC;IAC1C,MAAM,UAAU,GAAe,KAAK,CAAC,UAAU,CAAC;IAIhD,MAAM,SAAS,GAAG,MAAM,IAAA,4CAAyB,GAAE,CAAC;IACpD,MAAM,UAAU,GAAoC,CACnD,MAAM,OAAO,CAAC,GAAG,CAChB,sBAAc,CAAC,GAAG,CAAC,CAAC,aAAa,EAAE,EAAE,CAAC,IAAA,gCAAoB,EAAC,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS,CAAC,CAAC,CACzG,CACD,CAAC,IAAI,EAAE,CAAC;IAET,MAAM,UAAU,GAAG,UAAU;SAC3B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACZ,IAAI,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC;QAChC,OAAO,EAAE,CAAC,CAAC,cAAc;QACzB,IAAI,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,OAAO,EAAE;KAC1C,CAAC,CAAC;SACF,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAE1C,MAAM,WAAW,GAA2B,IAAA,8BAAc,EAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAEjF,MAAM,IAAA,sBAAW,EAAC,WAAW,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;IACvD,OAAO,EAAE,CAAC;AACX,CAAC,CAAC;AAEF,MAAM,cAAc,GAAG,KAAK,EAAE,OAAgB,EAAE,EAAE;IACjD,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IAClC,KAAK,MAAM,UAAU,IAAI,aAAa,EAAE;QACvC,MAAM,QAAQ,GAAG;YAChB,UAAU,EAAE,UAAU;SACtB,CAAC;QACF,MAAM,MAAM,GAAG;YACd,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,cAAc,EAAE,OAAO;YACvB,OAAO,EAAE,MAAM;YACf,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;SACjC,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,MAAM;aACzB,MAAM,CAAC;YACP,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,cAAc,EAAE,OAAO;YACvB,OAAO,EAAE,MAAM;YACf,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;SACjC,CAAC;aACD,OAAO,EAAE,CAAC;QAEZ,MAAM,IAAA,wBAAK,EAAC,EAAE,CAAC,CAAC;KAChB;AACF,CAAC,CAAC","sourcesContent":["import { S3, getLastBattlegroundsPatch, logBeforeTimeout, sleep } from '@firestone-hs/aws-lambda-utils';\r\nimport { AllCardsService } from '@firestone-hs/reference-data';\r\nimport { Context } from 'aws-lambda';\r\nimport AWS from 'aws-sdk';\r\nimport { InternalBgsCardStats } from '../../../internal-model';\r\nimport { BgsCardStat } from '../../../model-cards';\r\nimport { MmrPercentileFilter, TimePeriod } from '../../../models';\r\nimport { loadHourlyDataFromS3 } from '../s3-loader';\r\nimport { persistData } from './s3-saver';\r\nimport { buildCardStats } from './stats-builder';\r\n\r\nconst allCards = new AllCardsService();\r\nexport const s3 = new S3();\r\nconst lambda = new AWS.Lambda();\r\n\r\nconst allTimePeriod: readonly TimePeriod[] = ['all-time', 'past-three', 'past-seven', 'last-patch'];\r\nexport const mmrPercentiles: readonly MmrPercentileFilter[] = [100, 50, 25, 10, 1];\r\n\r\nexport default async (event, context: Context): Promise<any> => {\r\n\tawait allCards.initializeCardsDb();\r\n\r\n\tif (!event.timePeriod) {\r\n\t\tawait dispatchEvents(context);\r\n\t\treturn;\r\n\t}\r\n\r\n\tconst cleanup = logBeforeTimeout(context);\r\n\tconst timePeriod: TimePeriod = event.timePeriod;\r\n\r\n\t// console.log('aggregating data', timePeriod, mmrPercentile);\r\n\t// Build the list of files based on the timeframe, and load all of these\r\n\tconst patchInfo = await getLastBattlegroundsPatch();\r\n\tconst hourlyData: readonly InternalBgsCardStats[] = (\r\n\t\tawait Promise.all(\r\n\t\t\tmmrPercentiles.map((mmrPercentile) => loadHourlyDataFromS3('card', timePeriod, mmrPercentile, patchInfo)),\r\n\t\t)\r\n\t).flat();\r\n\r\n\tconst lastUpdate = hourlyData\r\n\t\t.map((d) => ({\r\n\t\t\tdate: new Date(d.lastUpdateDate),\r\n\t\t\tdateStr: d.lastUpdateDate,\r\n\t\t\ttime: new Date(d.lastUpdateDate).getTime(),\r\n\t\t}))\r\n\t\t.sort((a, b) => b.time - a.time)[0].date;\r\n\r\n\tconst mergedStats: readonly BgsCardStat[] = buildCardStats(hourlyData, allCards);\r\n\r\n\tawait persistData(mergedStats, timePeriod, lastUpdate);\r\n\tcleanup();\r\n};\r\n\r\nconst dispatchEvents = async (context: Context) => {\r\n\tconsole.log('dispatching events');\r\n\tfor (const timePeriod of allTimePeriod) {\r\n\t\tconst newEvent = {\r\n\t\t\ttimePeriod: timePeriod,\r\n\t\t};\r\n\t\tconst params = {\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t};\r\n\t\t// console.log('\\tinvoking lambda', params);\r\n\t\tconst result = await lambda\r\n\t\t\t.invoke({\r\n\t\t\t\tFunctionName: context.functionName,\r\n\t\t\t\tInvocationType: 'Event',\r\n\t\t\t\tLogType: 'Tail',\r\n\t\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t\t})\r\n\t\t\t.promise();\r\n\t\t// console.log('\\tinvocation result', result);\r\n\t\tawait sleep(50);\r\n\t}\r\n};\r\n"]}
@@ -0,0 +1,3 @@
1
+ import { BgsCardStat } from '../../../model-cards';
2
+ import { TimePeriod } from '../../../models';
3
+ export declare const persistData: (mergedStats: readonly BgsCardStat[], timePeriod: TimePeriod, lastUpdate: Date) => Promise<void>;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.persistData = void 0;
4
+ const zlib_1 = require("zlib");
5
+ const _build_battlegrounds_hero_stats_1 = require("../../hourly/_build-battlegrounds-hero-stats");
6
+ const config_1 = require("../config");
7
+ const _build_aggregated_stats_1 = require("./_build-aggregated-stats");
8
+ const persistData = async (mergedStats, timePeriod, lastUpdate) => {
9
+ const stat = {
10
+ cardStats: mergedStats,
11
+ lastUpdateDate: lastUpdate,
12
+ dataPoints: mergedStats.map((s) => s.totalPlayed).reduce((a, b) => a + b, 0),
13
+ timePeriod: timePeriod,
14
+ };
15
+ await _build_aggregated_stats_1.s3.writeFile((0, zlib_1.gzipSync)(JSON.stringify(stat)), _build_battlegrounds_hero_stats_1.STATS_BUCKET, config_1.STAT_KEY_CARD.replace('%timePeriod%', timePeriod), 'application/json', 'gzip');
16
+ };
17
+ exports.persistData = persistData;
18
+ //# sourceMappingURL=s3-saver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"s3-saver.js","sourceRoot":"","sources":["../../../../src/solo/aggregate-hourly/cards/s3-saver.ts"],"names":[],"mappings":";;;AAAA,+BAAgC;AAGhC,kGAA4E;AAC5E,sCAA0C;AAC1C,uEAA+C;AAExC,MAAM,WAAW,GAAG,KAAK,EAAE,WAAmC,EAAE,UAAsB,EAAE,UAAgB,EAAE,EAAE;IAClH,MAAM,IAAI,GAAiB;QAC1B,SAAS,EAAE,WAAW;QACtB,cAAc,EAAE,UAAU;QAC1B,UAAU,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC5E,UAAU,EAAE,UAAU;KACtB,CAAC;IAEF,MAAM,4BAAE,CAAC,SAAS,CACjB,IAAA,eAAQ,EAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,EAC9B,8CAAY,EACZ,sBAAa,CAAC,OAAO,CAAC,cAAc,EAAE,UAAU,CAAC,EACjD,kBAAkB,EAClB,MAAM,CACN,CAAC;AACH,CAAC,CAAC;AAfW,QAAA,WAAW,eAetB","sourcesContent":["import { gzipSync } from 'zlib';\r\nimport { BgsCardStat, BgsCardStats } from '../../../model-cards';\r\nimport { TimePeriod } from '../../../models';\r\nimport { STATS_BUCKET } from '../../hourly/_build-battlegrounds-hero-stats';\r\nimport { STAT_KEY_CARD } from '../config';\r\nimport { s3 } from './_build-aggregated-stats';\r\n\r\nexport const persistData = async (mergedStats: readonly BgsCardStat[], timePeriod: TimePeriod, lastUpdate: Date) => {\r\n\tconst stat: BgsCardStats = {\r\n\t\tcardStats: mergedStats,\r\n\t\tlastUpdateDate: lastUpdate,\r\n\t\tdataPoints: mergedStats.map((s) => s.totalPlayed).reduce((a, b) => a + b, 0),\r\n\t\ttimePeriod: timePeriod,\r\n\t};\r\n\t// console.log('persisting data', stat.dataPoints, stat.heroStats?.length);\r\n\tawait s3.writeFile(\r\n\t\tgzipSync(JSON.stringify(stat)),\r\n\t\tSTATS_BUCKET,\r\n\t\tSTAT_KEY_CARD.replace('%timePeriod%', timePeriod),\r\n\t\t'application/json',\r\n\t\t'gzip',\r\n\t);\r\n};\r\n"]}
@@ -0,0 +1,4 @@
1
+ import { AllCardsService } from '@firestone-hs/reference-data';
2
+ import { InternalBgsCardStats } from '../../../internal-model';
3
+ import { BgsCardStat } from '../../../model-cards';
4
+ export declare const buildCardStats: (hourlyData: readonly InternalBgsCardStats[], allCards: AllCardsService) => readonly BgsCardStat[];
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildCardStats = void 0;
4
+ const aws_lambda_utils_1 = require("@firestone-hs/aws-lambda-utils");
5
+ const buildCardStats = (hourlyData, allCards) => {
6
+ const allCardStats = hourlyData.flatMap((data) => data.cardStats);
7
+ const groupedByCard = (0, aws_lambda_utils_1.groupByFunction)((data) => data.cardId)(allCardStats);
8
+ return Object.keys(groupedByCard).map((cardId) => buildSingleCardStat(groupedByCard[cardId], allCards));
9
+ };
10
+ exports.buildCardStats = buildCardStats;
11
+ const buildSingleCardStat = (data, allCards) => {
12
+ const ref = data[0];
13
+ const totalPlayed = data.map((d) => d.totalPlayed).reduce((a, b) => a + b, 0);
14
+ const totalPlacement = data.map((d) => d.totalPlayed * d.averagePlacement).reduce((a, b) => a + b, 0);
15
+ const averagePlacement = totalPlacement / totalPlayed;
16
+ const averagePlacementAtMmr = buildAveragePlacementAtMmr(data);
17
+ const turnStats = buildTurnStats(data);
18
+ const heroStats = buildHeroStats(data);
19
+ const result = {
20
+ cardId: ref.cardId,
21
+ totalPlayed: totalPlayed,
22
+ averagePlacement: averagePlacement,
23
+ averagePlacementAtMmr: averagePlacementAtMmr,
24
+ turnStats: turnStats,
25
+ heroStats: heroStats,
26
+ };
27
+ return result;
28
+ };
29
+ const buildHeroStats = (data) => {
30
+ const allHeroStats = data.flatMap((d) => d.heroStats);
31
+ const groupedByHero = (0, aws_lambda_utils_1.groupByFunction)((data) => data.heroCardId)(allHeroStats);
32
+ return Object.keys(groupedByHero).map((heroCardId) => {
33
+ const relevantData = groupedByHero[heroCardId];
34
+ const totalPlayed = relevantData.map((d) => d.totalPlayedWithHero).reduce((a, b) => a + b, 0);
35
+ const totalPlacement = relevantData
36
+ .map((d) => d.totalPlayedWithHero * d.averagePlacement)
37
+ .reduce((a, b) => a + b, 0);
38
+ const averagePlacement = totalPlacement / totalPlayed;
39
+ const averagePlacementAtMmr = [];
40
+ const turnStats = buildTurnStats(relevantData);
41
+ const heroResult = {
42
+ heroCardId: heroCardId,
43
+ totalPlayedWithHero: totalPlayed,
44
+ averagePlacement: averagePlacement,
45
+ averagePlacementAtMmr: averagePlacementAtMmr,
46
+ turnStats: turnStats,
47
+ };
48
+ return heroResult;
49
+ });
50
+ };
51
+ const buildTurnStats = (data) => {
52
+ const allTurnStats = data.flatMap((d) => d.turnStats);
53
+ const groupedByTurn = (0, aws_lambda_utils_1.groupByFunction)((data) => data.turn)(allTurnStats);
54
+ return Object.keys(groupedByTurn).map((turn) => {
55
+ const relevantData = groupedByTurn[turn];
56
+ const totalPlayed = relevantData.map((d) => d.totalPlayedAtTurn).reduce((a, b) => a + b, 0);
57
+ const totalPlacement = relevantData
58
+ .map((d) => d.totalPlayedAtTurn * d.averagePlacement)
59
+ .reduce((a, b) => a + b, 0);
60
+ const averagePlacement = totalPlacement / totalPlayed;
61
+ const averagePlacementAtMmr = [];
62
+ const turnResult = {
63
+ turn: parseInt(turn),
64
+ totalPlayedAtTurn: totalPlayed,
65
+ averagePlacement: averagePlacement,
66
+ averagePlacementAtMmr: averagePlacementAtMmr,
67
+ };
68
+ return turnResult;
69
+ });
70
+ };
71
+ const buildAveragePlacementAtMmr = (data) => {
72
+ const groupedByMmr = (0, aws_lambda_utils_1.groupByFunction)((data) => data.mmrPercentile)(data);
73
+ const result = Object.keys(groupedByMmr).map((mmr) => {
74
+ const relevantData = groupedByMmr[mmr];
75
+ const totalPlayed = relevantData.map((d) => d.totalPlayed).reduce((a, b) => a + b, 0);
76
+ const totalPlacement = relevantData.map((d) => d.totalPlayed * d.averagePlacement).reduce((a, b) => a + b, 0);
77
+ const averagePlacement = totalPlacement / totalPlayed;
78
+ const mmrResult = {
79
+ mmr: parseInt(mmr),
80
+ placement: averagePlacement,
81
+ };
82
+ return mmrResult;
83
+ });
84
+ return result;
85
+ };
86
+ //# sourceMappingURL=stats-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats-builder.js","sourceRoot":"","sources":["../../../../src/solo/aggregate-hourly/cards/stats-builder.ts"],"names":[],"mappings":"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","sourcesContent":["import { groupByFunction } from '@firestone-hs/aws-lambda-utils';\r\nimport { AllCardsService } from '@firestone-hs/reference-data';\r\nimport {\r\n\tInternalBgsCardHeroStat,\r\n\tInternalBgsCardStat,\r\n\tInternalBgsCardStats,\r\n\tInternalBgsCardTurnStat,\r\n} from '../../../internal-model';\r\nimport { BgsCardHeroStat, BgsCardStat, BgsCardTurnStat } from '../../../model-cards';\r\nimport { WithMmrAndTimePeriod } from '../../../models';\r\n\r\n// These should all be for a single MMR\r\nexport const buildCardStats = (\r\n\thourlyData: readonly InternalBgsCardStats[],\r\n\tallCards: AllCardsService,\r\n): readonly BgsCardStat[] => {\r\n\tconst allCardStats: readonly WithMmrAndTimePeriod<InternalBgsCardStat>[] = hourlyData.flatMap(\r\n\t\t(data) => data.cardStats,\r\n\t);\r\n\tconst groupedByCard = groupByFunction((data: WithMmrAndTimePeriod<InternalBgsCardStat>) => data.cardId)(\r\n\t\tallCardStats,\r\n\t);\r\n\treturn Object.keys(groupedByCard).map((cardId) => buildSingleCardStat(groupedByCard[cardId], allCards));\r\n};\r\n\r\nconst buildSingleCardStat = (\r\n\tdata: readonly WithMmrAndTimePeriod<InternalBgsCardStat>[],\r\n\tallCards: AllCardsService,\r\n): BgsCardStat => {\r\n\tconst ref = data[0];\r\n\tconst totalPlayed = data.map((d) => d.totalPlayed).reduce((a, b) => a + b, 0);\r\n\tconst totalPlacement = data.map((d) => d.totalPlayed * d.averagePlacement).reduce((a, b) => a + b, 0);\r\n\tconst averagePlacement = totalPlacement / totalPlayed;\r\n\tconst averagePlacementAtMmr: BgsCardStat['averagePlacementAtMmr'] = buildAveragePlacementAtMmr(data);\r\n\tconst turnStats: readonly BgsCardTurnStat[] = buildTurnStats(data);\r\n\tconst heroStats: readonly BgsCardHeroStat[] = buildHeroStats(data);\r\n\r\n\tconst result: BgsCardStat = {\r\n\t\tcardId: ref.cardId,\r\n\t\ttotalPlayed: totalPlayed,\r\n\t\taveragePlacement: averagePlacement,\r\n\t\taveragePlacementAtMmr: averagePlacementAtMmr,\r\n\t\tturnStats: turnStats,\r\n\t\theroStats: heroStats,\r\n\t};\r\n\treturn result;\r\n};\r\n\r\nconst buildHeroStats = (data: readonly WithMmrAndTimePeriod<InternalBgsCardStat>[]): readonly BgsCardHeroStat[] => {\r\n\tconst allHeroStats = data.flatMap((d) => d.heroStats);\r\n\tconst groupedByHero = groupByFunction((data: InternalBgsCardHeroStat) => data.heroCardId)(allHeroStats);\r\n\treturn Object.keys(groupedByHero).map((heroCardId) => {\r\n\t\tconst relevantData = groupedByHero[heroCardId];\r\n\t\tconst totalPlayed = relevantData.map((d) => d.totalPlayedWithHero).reduce((a, b) => a + b, 0);\r\n\t\tconst totalPlacement = relevantData\r\n\t\t\t.map((d) => d.totalPlayedWithHero * d.averagePlacement)\r\n\t\t\t.reduce((a, b) => a + b, 0);\r\n\t\tconst averagePlacement = totalPlacement / totalPlayed;\r\n\t\tconst averagePlacementAtMmr = [];\r\n\t\tconst turnStats = buildTurnStats(relevantData);\r\n\t\tconst heroResult: BgsCardHeroStat = {\r\n\t\t\theroCardId: heroCardId,\r\n\t\t\ttotalPlayedWithHero: totalPlayed,\r\n\t\t\taveragePlacement: averagePlacement,\r\n\t\t\taveragePlacementAtMmr: averagePlacementAtMmr,\r\n\t\t\tturnStats: turnStats,\r\n\t\t};\r\n\t\treturn heroResult;\r\n\t});\r\n};\r\n\r\nconst buildTurnStats = (\r\n\tdata: readonly { turnStats: readonly InternalBgsCardTurnStat[] }[],\r\n): readonly BgsCardTurnStat[] => {\r\n\tconst allTurnStats = data.flatMap((d) => d.turnStats);\r\n\tconst groupedByTurn = groupByFunction((data: InternalBgsCardTurnStat) => data.turn)(allTurnStats);\r\n\treturn Object.keys(groupedByTurn).map((turn) => {\r\n\t\tconst relevantData = groupedByTurn[turn];\r\n\t\tconst totalPlayed = relevantData.map((d) => d.totalPlayedAtTurn).reduce((a, b) => a + b, 0);\r\n\t\tconst totalPlacement = relevantData\r\n\t\t\t.map((d) => d.totalPlayedAtTurn * d.averagePlacement)\r\n\t\t\t.reduce((a, b) => a + b, 0);\r\n\t\tconst averagePlacement = totalPlacement / totalPlayed;\r\n\t\tconst averagePlacementAtMmr = [];\r\n\t\tconst turnResult: BgsCardTurnStat = {\r\n\t\t\tturn: parseInt(turn),\r\n\t\t\ttotalPlayedAtTurn: totalPlayed,\r\n\t\t\taveragePlacement: averagePlacement,\r\n\t\t\taveragePlacementAtMmr: averagePlacementAtMmr,\r\n\t\t};\r\n\t\treturn turnResult;\r\n\t});\r\n};\r\n\r\nconst buildAveragePlacementAtMmr = (\r\n\tdata: readonly WithMmrAndTimePeriod<InternalBgsCardStat>[],\r\n): BgsCardStat['averagePlacementAtMmr'] => {\r\n\tconst groupedByMmr = groupByFunction((data: WithMmrAndTimePeriod<InternalBgsCardStat>) => data.mmrPercentile)(data);\r\n\tconst result: BgsCardStat['averagePlacementAtMmr'] = Object.keys(groupedByMmr).map((mmr) => {\r\n\t\tconst relevantData = groupedByMmr[mmr];\r\n\t\tconst totalPlayed = relevantData.map((d) => d.totalPlayed).reduce((a, b) => a + b, 0);\r\n\t\tconst totalPlacement = relevantData.map((d) => d.totalPlayed * d.averagePlacement).reduce((a, b) => a + b, 0);\r\n\t\tconst averagePlacement = totalPlacement / totalPlayed;\r\n\t\tconst mmrResult: { mmr: number; placement: number } = {\r\n\t\t\tmmr: parseInt(mmr),\r\n\t\t\tplacement: averagePlacement,\r\n\t\t};\r\n\t\treturn mmrResult;\r\n\t});\r\n\treturn result;\r\n};\r\n"]}
@@ -2,3 +2,4 @@ export declare const STAT_KEY_HERO: string;
2
2
  export declare const STAT_KEY_PERCENTILE: string;
3
3
  export declare const STAT_KEY_QUEST: string;
4
4
  export declare const STAT_KEY_TRINKET: string;
5
+ export declare const STAT_KEY_CARD: string;
@@ -1,9 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.STAT_KEY_TRINKET = exports.STAT_KEY_QUEST = exports.STAT_KEY_PERCENTILE = exports.STAT_KEY_HERO = void 0;
3
+ exports.STAT_KEY_CARD = exports.STAT_KEY_TRINKET = exports.STAT_KEY_QUEST = exports.STAT_KEY_PERCENTILE = exports.STAT_KEY_HERO = void 0;
4
4
  const _build_battlegrounds_hero_stats_1 = require("../hourly/_build-battlegrounds-hero-stats");
5
5
  exports.STAT_KEY_HERO = `${_build_battlegrounds_hero_stats_1.STATS_KEY_PREFIX}/hero-stats/mmr-%mmrPercentile%/%timePeriod%/overview-from-hourly.gz.json`;
6
6
  exports.STAT_KEY_PERCENTILE = `${_build_battlegrounds_hero_stats_1.STATS_KEY_PREFIX}/hero-stats/%timePeriod%/mmr-percentiles.gz.json`;
7
7
  exports.STAT_KEY_QUEST = `${_build_battlegrounds_hero_stats_1.STATS_KEY_PREFIX}/quest-stats/mmr-%mmrPercentile%/%timePeriod%/overview-from-hourly.gz.json`;
8
8
  exports.STAT_KEY_TRINKET = `${_build_battlegrounds_hero_stats_1.STATS_KEY_PREFIX}/trinket-stats/%timePeriod%/overview-from-hourly.gz.json`;
9
+ exports.STAT_KEY_CARD = `${_build_battlegrounds_hero_stats_1.STATS_KEY_PREFIX}/card-stats/%timePeriod%/overview-from-hourly.gz.json`;
9
10
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/solo/aggregate-hourly/config.ts"],"names":[],"mappings":";;;AAAA,+FAA6E;AAEhE,QAAA,aAAa,GAAG,GAAG,kDAAgB,2EAA2E,CAAC;AAC/G,QAAA,mBAAmB,GAAG,GAAG,kDAAgB,kDAAkD,CAAC;AAC5F,QAAA,cAAc,GAAG,GAAG,kDAAgB,4EAA4E,CAAC;AACjH,QAAA,gBAAgB,GAAG,GAAG,kDAAgB,0DAA0D,CAAC","sourcesContent":["import { STATS_KEY_PREFIX } from '../hourly/_build-battlegrounds-hero-stats';\r\n\r\nexport const STAT_KEY_HERO = `${STATS_KEY_PREFIX}/hero-stats/mmr-%mmrPercentile%/%timePeriod%/overview-from-hourly.gz.json`;\r\nexport const STAT_KEY_PERCENTILE = `${STATS_KEY_PREFIX}/hero-stats/%timePeriod%/mmr-percentiles.gz.json`;\r\nexport const STAT_KEY_QUEST = `${STATS_KEY_PREFIX}/quest-stats/mmr-%mmrPercentile%/%timePeriod%/overview-from-hourly.gz.json`;\r\nexport const STAT_KEY_TRINKET = `${STATS_KEY_PREFIX}/trinket-stats/%timePeriod%/overview-from-hourly.gz.json`;\r\n"]}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/solo/aggregate-hourly/config.ts"],"names":[],"mappings":";;;AAAA,+FAA6E;AAEhE,QAAA,aAAa,GAAG,GAAG,kDAAgB,2EAA2E,CAAC;AAC/G,QAAA,mBAAmB,GAAG,GAAG,kDAAgB,kDAAkD,CAAC;AAC5F,QAAA,cAAc,GAAG,GAAG,kDAAgB,4EAA4E,CAAC;AACjH,QAAA,gBAAgB,GAAG,GAAG,kDAAgB,0DAA0D,CAAC;AACjG,QAAA,aAAa,GAAG,GAAG,kDAAgB,uDAAuD,CAAC","sourcesContent":["import { STATS_KEY_PREFIX } from '../hourly/_build-battlegrounds-hero-stats';\r\n\r\nexport const STAT_KEY_HERO = `${STATS_KEY_PREFIX}/hero-stats/mmr-%mmrPercentile%/%timePeriod%/overview-from-hourly.gz.json`;\r\nexport const STAT_KEY_PERCENTILE = `${STATS_KEY_PREFIX}/hero-stats/%timePeriod%/mmr-percentiles.gz.json`;\r\nexport const STAT_KEY_QUEST = `${STATS_KEY_PREFIX}/quest-stats/mmr-%mmrPercentile%/%timePeriod%/overview-from-hourly.gz.json`;\r\nexport const STAT_KEY_TRINKET = `${STATS_KEY_PREFIX}/trinket-stats/%timePeriod%/overview-from-hourly.gz.json`;\r\nexport const STAT_KEY_CARD = `${STATS_KEY_PREFIX}/card-stats/%timePeriod%/overview-from-hourly.gz.json`;\r\n"]}
@@ -1,7 +1,7 @@
1
1
  import { PatchInfo } from '@firestone-hs/aws-lambda-utils';
2
- import { InternalBgsTrinketStats } from '../../internal-model';
2
+ import { InternalBgsCardStats, InternalBgsTrinketStats } from '../../internal-model';
3
3
  import { BgsQuestStats } from '../../model-quests';
4
4
  import { BgsHeroStatsV2, MmrPercentileFilter, TimePeriod } from '../../models';
5
- export type DataType = 'hero' | 'quest' | 'trinket';
6
- export type DataResult<T extends DataType> = T extends 'hero' ? BgsHeroStatsV2 : T extends 'trinket' ? InternalBgsTrinketStats : BgsQuestStats;
5
+ export type DataType = 'hero' | 'quest' | 'trinket' | 'card';
6
+ export type DataResult<T extends DataType> = T extends 'hero' ? BgsHeroStatsV2 : T extends 'trinket' ? InternalBgsTrinketStats : T extends 'card' ? InternalBgsCardStats : T extends 'quest' ? BgsQuestStats : null;
7
7
  export declare const loadHourlyDataFromS3: <T extends DataType>(type: T, timePeriod: TimePeriod, mmrPercentile: MmrPercentileFilter, patchInfo: PatchInfo) => Promise<readonly DataResult<T>[]>;
@@ -12,7 +12,15 @@ const loadHourlyDataFromS3 = async (type, timePeriod, mmrPercentile, patchInfo)
12
12
  };
13
13
  exports.loadHourlyDataFromS3 = loadHourlyDataFromS3;
14
14
  const loadHourlyDeckStatFromS3 = async (type, mmrPercentile, fileName) => {
15
- const mainKey = type === 'hero' ? _build_battlegrounds_hero_stats_1.HOURLY_KEY_HERO : type === 'trinket' ? _build_battlegrounds_hero_stats_1.HOURLY_KEY_TRINKET : _build_battlegrounds_hero_stats_1.HOURLY_KEY_QUEST;
15
+ const mainKey = type === 'hero'
16
+ ? _build_battlegrounds_hero_stats_1.HOURLY_KEY_HERO
17
+ : type === 'trinket'
18
+ ? _build_battlegrounds_hero_stats_1.HOURLY_KEY_TRINKET
19
+ : type === 'quest'
20
+ ? _build_battlegrounds_hero_stats_1.HOURLY_KEY_QUEST
21
+ : type === 'card'
22
+ ? _build_battlegrounds_hero_stats_1.HOURLY_KEY_CARD
23
+ : null;
16
24
  const fileKey = mainKey.replace('%mmrPercentile%', `${mmrPercentile}`).replace('%startDate%', fileName);
17
25
  const data = await _build_aggregated_stats_1.s3.readGzipContent(_build_battlegrounds_hero_stats_1.STATS_BUCKET, fileKey, 1, false);
18
26
  const result = JSON.parse(data);
@@ -1 +1 @@
1
- {"version":3,"file":"s3-loader.js","sourceRoot":"","sources":["../../../src/solo/aggregate-hourly/s3-loader.ts"],"names":[],"mappings":";;;AAIA,+FAKmD;AACnD,8EAAsD;AACtD,iDAAyE;AASlE,MAAM,oBAAoB,GAAG,KAAK,EACxC,IAAO,EACP,UAAsB,EACtB,aAAkC,EAClC,SAAoB,EACgB,EAAE;IACtC,MAAM,SAAS,GAAW,IAAA,sCAAuB,EAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IACzE,MAAM,SAAS,GAAsB,IAAA,6BAAc,EAAC,SAAS,CAAC,CAAC;IAE/D,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,GAAG,CACpC,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,wBAAwB,CAAC,IAAI,EAAE,aAAa,EAAE,QAAQ,CAAC,CAAC,CACpF,CAAC;IACF,OAAO,WAAW,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AACjD,CAAC,CAAC;AAbW,QAAA,oBAAoB,wBAa/B;AAEF,MAAM,wBAAwB,GAAG,KAAK,EACrC,IAAO,EACP,aAAkC,EAClC,QAAgB,EACS,EAAE;IAC3B,MAAM,OAAO,GAAG,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,iDAAe,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,oDAAkB,CAAC,CAAC,CAAC,kDAAgB,CAAC;IAC/G,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;IACxG,MAAM,IAAI,GAAG,MAAM,4BAAE,CAAC,eAAe,CAAC,8CAAY,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;IACvE,MAAM,MAAM,GAAkB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/C,OAAO,MAAM,CAAC;AACf,CAAC,CAAC","sourcesContent":["import { PatchInfo } from '@firestone-hs/aws-lambda-utils';\r\nimport { InternalBgsTrinketStats } from '../../internal-model';\r\nimport { BgsQuestStats } from '../../model-quests';\r\nimport { BgsHeroStatsV2, MmrPercentileFilter, TimePeriod } from '../../models';\r\nimport {\r\n\tHOURLY_KEY_HERO,\r\n\tHOURLY_KEY_QUEST,\r\n\tHOURLY_KEY_TRINKET,\r\n\tSTATS_BUCKET,\r\n} from '../hourly/_build-battlegrounds-hero-stats';\r\nimport { s3 } from './heroes/_build-aggregated-stats';\r\nimport { buildFileNames, computeHoursBackFromNow } from './hourly-utils';\r\n\r\nexport type DataType = 'hero' | 'quest' | 'trinket';\r\nexport type DataResult<T extends DataType> = T extends 'hero'\r\n\t? BgsHeroStatsV2\r\n\t: T extends 'trinket'\r\n\t? InternalBgsTrinketStats\r\n\t: BgsQuestStats;\r\n\r\nexport const loadHourlyDataFromS3 = async <T extends DataType>(\r\n\ttype: T,\r\n\ttimePeriod: TimePeriod,\r\n\tmmrPercentile: MmrPercentileFilter,\r\n\tpatchInfo: PatchInfo,\r\n): Promise<readonly DataResult<T>[]> => {\r\n\tconst hoursBack: number = computeHoursBackFromNow(timePeriod, patchInfo);\r\n\tconst fileNames: readonly string[] = buildFileNames(hoursBack);\r\n\t// console.debug('fileNames', timePeriod, mmrPercentile, fileNames);\r\n\tconst fileResults = await Promise.all(\r\n\t\tfileNames.map((fileName) => loadHourlyDeckStatFromS3(type, mmrPercentile, fileName)),\r\n\t);\r\n\treturn fileResults.filter((result) => !!result);\r\n};\r\n\r\nconst loadHourlyDeckStatFromS3 = async <T extends DataType>(\r\n\ttype: T,\r\n\tmmrPercentile: MmrPercentileFilter,\r\n\tfileName: string,\r\n): Promise<DataResult<T>> => {\r\n\tconst mainKey = type === 'hero' ? HOURLY_KEY_HERO : type === 'trinket' ? HOURLY_KEY_TRINKET : HOURLY_KEY_QUEST;\r\n\tconst fileKey = mainKey.replace('%mmrPercentile%', `${mmrPercentile}`).replace('%startDate%', fileName);\r\n\tconst data = await s3.readGzipContent(STATS_BUCKET, fileKey, 1, false);\r\n\tconst result: DataResult<T> = JSON.parse(data);\r\n\treturn result;\r\n};\r\n"]}
1
+ {"version":3,"file":"s3-loader.js","sourceRoot":"","sources":["../../../src/solo/aggregate-hourly/s3-loader.ts"],"names":[],"mappings":";;;AAIA,+FAMmD;AACnD,8EAAsD;AACtD,iDAAyE;AAalE,MAAM,oBAAoB,GAAG,KAAK,EACxC,IAAO,EACP,UAAsB,EACtB,aAAkC,EAClC,SAAoB,EACgB,EAAE;IACtC,MAAM,SAAS,GAAW,IAAA,sCAAuB,EAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IACzE,MAAM,SAAS,GAAsB,IAAA,6BAAc,EAAC,SAAS,CAAC,CAAC;IAE/D,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,GAAG,CACpC,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,wBAAwB,CAAC,IAAI,EAAE,aAAa,EAAE,QAAQ,CAAC,CAAC,CACpF,CAAC;IACF,OAAO,WAAW,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AACjD,CAAC,CAAC;AAbW,QAAA,oBAAoB,wBAa/B;AAEF,MAAM,wBAAwB,GAAG,KAAK,EACrC,IAAO,EACP,aAAkC,EAClC,QAAgB,EACS,EAAE;IAC3B,MAAM,OAAO,GACZ,IAAI,KAAK,MAAM;QACd,CAAC,CAAC,iDAAe;QACjB,CAAC,CAAC,IAAI,KAAK,SAAS;YACpB,CAAC,CAAC,oDAAkB;YACpB,CAAC,CAAC,IAAI,KAAK,OAAO;gBAClB,CAAC,CAAC,kDAAgB;gBAClB,CAAC,CAAC,IAAI,KAAK,MAAM;oBACjB,CAAC,CAAC,iDAAe;oBACjB,CAAC,CAAC,IAAI,CAAC;IACT,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;IACxG,MAAM,IAAI,GAAG,MAAM,4BAAE,CAAC,eAAe,CAAC,8CAAY,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;IACvE,MAAM,MAAM,GAAkB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/C,OAAO,MAAM,CAAC;AACf,CAAC,CAAC","sourcesContent":["import { PatchInfo } from '@firestone-hs/aws-lambda-utils';\r\nimport { InternalBgsCardStats, InternalBgsTrinketStats } from '../../internal-model';\r\nimport { BgsQuestStats } from '../../model-quests';\r\nimport { BgsHeroStatsV2, MmrPercentileFilter, TimePeriod } from '../../models';\r\nimport {\r\n\tHOURLY_KEY_CARD,\r\n\tHOURLY_KEY_HERO,\r\n\tHOURLY_KEY_QUEST,\r\n\tHOURLY_KEY_TRINKET,\r\n\tSTATS_BUCKET,\r\n} from '../hourly/_build-battlegrounds-hero-stats';\r\nimport { s3 } from './heroes/_build-aggregated-stats';\r\nimport { buildFileNames, computeHoursBackFromNow } from './hourly-utils';\r\n\r\nexport type DataType = 'hero' | 'quest' | 'trinket' | 'card';\r\nexport type DataResult<T extends DataType> = T extends 'hero'\r\n\t? BgsHeroStatsV2\r\n\t: T extends 'trinket'\r\n\t? InternalBgsTrinketStats\r\n\t: T extends 'card'\r\n\t? InternalBgsCardStats\r\n\t: T extends 'quest'\r\n\t? BgsQuestStats\r\n\t: null;\r\n\r\nexport const loadHourlyDataFromS3 = async <T extends DataType>(\r\n\ttype: T,\r\n\ttimePeriod: TimePeriod,\r\n\tmmrPercentile: MmrPercentileFilter,\r\n\tpatchInfo: PatchInfo,\r\n): Promise<readonly DataResult<T>[]> => {\r\n\tconst hoursBack: number = computeHoursBackFromNow(timePeriod, patchInfo);\r\n\tconst fileNames: readonly string[] = buildFileNames(hoursBack);\r\n\t// console.debug('fileNames', timePeriod, mmrPercentile, fileNames);\r\n\tconst fileResults = await Promise.all(\r\n\t\tfileNames.map((fileName) => loadHourlyDeckStatFromS3(type, mmrPercentile, fileName)),\r\n\t);\r\n\treturn fileResults.filter((result) => !!result);\r\n};\r\n\r\nconst loadHourlyDeckStatFromS3 = async <T extends DataType>(\r\n\ttype: T,\r\n\tmmrPercentile: MmrPercentileFilter,\r\n\tfileName: string,\r\n): Promise<DataResult<T>> => {\r\n\tconst mainKey =\r\n\t\ttype === 'hero'\r\n\t\t\t? HOURLY_KEY_HERO\r\n\t\t\t: type === 'trinket'\r\n\t\t\t? HOURLY_KEY_TRINKET\r\n\t\t\t: type === 'quest'\r\n\t\t\t? HOURLY_KEY_QUEST\r\n\t\t\t: type === 'card'\r\n\t\t\t? HOURLY_KEY_CARD\r\n\t\t\t: null;\r\n\tconst fileKey = mainKey.replace('%mmrPercentile%', `${mmrPercentile}`).replace('%startDate%', fileName);\r\n\tconst data = await s3.readGzipContent(STATS_BUCKET, fileKey, 1, false);\r\n\tconst result: DataResult<T> = JSON.parse(data);\r\n\treturn result;\r\n};\r\n"]}
@@ -7,6 +7,7 @@ export declare const WORKING_ROWS_FILE: string;
7
7
  export declare const HOURLY_KEY_HERO: string;
8
8
  export declare const HOURLY_KEY_QUEST: string;
9
9
  export declare const HOURLY_KEY_TRINKET: string;
10
+ export declare const HOURLY_KEY_CARD: string;
10
11
  declare const _default: (event: any, context: Context) => Promise<any>;
11
12
  export default _default;
12
13
  export declare const handleNewStats: (event: any, context: Context) => Promise<void>;
@@ -3,10 +3,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.handleNewStats = exports.HOURLY_KEY_TRINKET = exports.HOURLY_KEY_QUEST = exports.HOURLY_KEY_HERO = exports.WORKING_ROWS_FILE = exports.STATS_KEY_PREFIX = exports.STATS_BUCKET = exports.s3 = void 0;
6
+ exports.handleNewStats = exports.HOURLY_KEY_CARD = exports.HOURLY_KEY_TRINKET = exports.HOURLY_KEY_QUEST = exports.HOURLY_KEY_HERO = exports.WORKING_ROWS_FILE = exports.STATS_KEY_PREFIX = exports.STATS_BUCKET = exports.s3 = void 0;
7
7
  const aws_lambda_utils_1 = require("@firestone-hs/aws-lambda-utils");
8
8
  const reference_data_1 = require("@firestone-hs/reference-data");
9
9
  const aws_sdk_1 = __importDefault(require("aws-sdk"));
10
+ const card_stats_1 = require("./cards/card-stats");
10
11
  const hero_stats_1 = require("./hero-stats");
11
12
  const rows_1 = require("./rows");
12
13
  const trinket_stats_1 = require("./trinkets/trinket-stats");
@@ -20,6 +21,7 @@ exports.WORKING_ROWS_FILE = `${exports.STATS_KEY_PREFIX}/working/working-rows-%t
20
21
  exports.HOURLY_KEY_HERO = `${exports.STATS_KEY_PREFIX}/hero-stats/mmr-%mmrPercentile%/hourly/%startDate%.gz.json`;
21
22
  exports.HOURLY_KEY_QUEST = `${exports.STATS_KEY_PREFIX}/quest-stats/mmr-%mmrPercentile%/hourly/%startDate%.gz.json`;
22
23
  exports.HOURLY_KEY_TRINKET = `${exports.STATS_KEY_PREFIX}/trinket-stats/mmr-%mmrPercentile%/hourly/%startDate%.gz.json`;
24
+ exports.HOURLY_KEY_CARD = `${exports.STATS_KEY_PREFIX}/card-stats/mmr-%mmrPercentile%/hourly/%startDate%.gz.json`;
23
25
  exports.default = async (event, context) => {
24
26
  await (0, exports.handleNewStats)(event, context);
25
27
  };
@@ -31,7 +33,7 @@ const handleNewStats = async (event, context) => {
31
33
  cleanup();
32
34
  return;
33
35
  }
34
- if (!event.statsV2 && !event.questsV2 && !event.trinkets) {
36
+ if (!event.statsV2 && !event.questsV2 && !event.trinkets && !event.cards) {
35
37
  await dispatchMainEvents(context, event);
36
38
  cleanup();
37
39
  return;
@@ -44,6 +46,10 @@ const handleNewStats = async (event, context) => {
44
46
  const lastHourRows = await (0, rows_1.readRowsFromS3)(event.startDate);
45
47
  await (0, trinket_stats_1.buildTrinketStats)(event.startDate, event.mmr, lastHourRows, allCards, exports.STATS_BUCKET, exports.HOURLY_KEY_TRINKET, exports.s3);
46
48
  }
49
+ else if (event.cards) {
50
+ const lastHourRows = await (0, rows_1.readRowsFromS3)(event.startDate);
51
+ await (0, card_stats_1.buildCardStats)(event.startDate, event.mmr, lastHourRows, allCards, exports.STATS_BUCKET, exports.HOURLY_KEY_CARD, exports.s3);
52
+ }
47
53
  cleanup();
48
54
  };
49
55
  exports.handleNewStats = handleNewStats;
@@ -54,6 +60,7 @@ const dispatchMainEvents = async (context, event) => {
54
60
  await (0, rows_1.saveRowsOnS3)(startDate, endDate, allCards);
55
61
  await dispatchStatsV2Lambda(context, startDate);
56
62
  await dispatchTrinketsLambda(context, startDate);
63
+ await dispatchCardsLambda(context, startDate);
57
64
  };
58
65
  const buildProcessStartDate = (event) => {
59
66
  if (event === null || event === void 0 ? void 0 : event.targetDate) {
@@ -67,6 +74,30 @@ const buildProcessStartDate = (event) => {
67
74
  processStartDate.setHours(processStartDate.getHours() - 1);
68
75
  return processStartDate;
69
76
  };
77
+ const dispatchCardsLambda = async (context, startDate) => {
78
+ for (const mmr of allMmrPercentiles) {
79
+ const newEvent = {
80
+ cards: true,
81
+ mmr: mmr,
82
+ startDate: startDate,
83
+ };
84
+ const params = {
85
+ FunctionName: context.functionName,
86
+ InvocationType: 'Event',
87
+ LogType: 'Tail',
88
+ Payload: JSON.stringify(newEvent),
89
+ };
90
+ console.log('\tinvoking lambda', params);
91
+ const result = await lambda
92
+ .invoke({
93
+ FunctionName: context.functionName,
94
+ InvocationType: 'Event',
95
+ LogType: 'Tail',
96
+ Payload: JSON.stringify(newEvent),
97
+ })
98
+ .promise();
99
+ }
100
+ };
70
101
  const dispatchTrinketsLambda = async (context, startDate) => {
71
102
  for (const mmr of allMmrPercentiles) {
72
103
  const newEvent = {
@@ -1 +1 @@
1
- {"version":3,"file":"_build-battlegrounds-hero-stats.js","sourceRoot":"","sources":["../../../src/solo/hourly/_build-battlegrounds-hero-stats.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-use-before-define */\r\nimport { S3, logBeforeTimeout, sleep } from '@firestone-hs/aws-lambda-utils';\r\nimport { AllCardsService } from '@firestone-hs/reference-data';\r\nimport { Context } from 'aws-lambda';\r\nimport AWS from 'aws-sdk';\r\nimport { InternalBgsRow } from '../../internal-model';\r\nimport { buildHeroStats } from './hero-stats';\r\nimport { readRowsFromS3, saveRowsOnS3 } from './rows';\r\nimport { buildTrinketStats } from './trinkets/trinket-stats';\r\n\r\nexport const s3 = new S3();\r\nconst allCards = new AllCardsService();\r\nconst lambda = new AWS.Lambda();\r\n\r\nconst allMmrPercentiles: (100 | 50 | 25 | 10 | 1)[] = [100, 50, 25, 10, 1];\r\n\r\nexport const STATS_BUCKET = 'static.zerotoheroes.com';\r\nexport const STATS_KEY_PREFIX = `api/bgs`;\r\nexport const WORKING_ROWS_FILE = `${STATS_KEY_PREFIX}/working/working-rows-%time%.json`;\r\nexport const HOURLY_KEY_HERO = `${STATS_KEY_PREFIX}/hero-stats/mmr-%mmrPercentile%/hourly/%startDate%.gz.json`;\r\nexport const HOURLY_KEY_QUEST = `${STATS_KEY_PREFIX}/quest-stats/mmr-%mmrPercentile%/hourly/%startDate%.gz.json`;\r\nexport const HOURLY_KEY_TRINKET = `${STATS_KEY_PREFIX}/trinket-stats/mmr-%mmrPercentile%/hourly/%startDate%.gz.json`;\r\n\r\n// This example demonstrates a NodeJS 8.10 async handler[1], however of course you could use\r\n// the more traditional callback-style handler.\r\n// [1]: https://aws.amazon.com/blogs/compute/node-js-8-10-runtime-now-available-in-aws-lambda/\r\nexport default async (event, context: Context): Promise<any> => {\r\n\tawait handleNewStats(event, context);\r\n};\r\n\r\nexport const handleNewStats = async (event, context: Context) => {\r\n\tconst cleanup = logBeforeTimeout(context);\r\n\t// logger.log('event', event);\r\n\tawait allCards.initializeCardsDb();\r\n\r\n\tif (event.catchUp) {\r\n\t\tawait dispatchCatchUpEvents(context, +event.catchUp);\r\n\t\tcleanup();\r\n\t\treturn;\r\n\t}\r\n\r\n\tif (!event.statsV2 && !event.questsV2 && !event.trinkets) {\r\n\t\tawait dispatchMainEvents(context, event);\r\n\t\tcleanup();\r\n\t\treturn;\r\n\t}\r\n\r\n\t// if (event.questsV2) {\r\n\t// \tconst lastHourRows: readonly InternalBgsRow[] = await readRowsFromS3(event.startDate);\r\n\t// \t// logger.log('building quest stats', event.timePeriod, event.startDate, lastHourRows?.length);\r\n\t// \tawait buildQuestStats(event.startDate, event.mmr, lastHourRows, allCards, s3);\r\n\t// } else\r\n\tif (event.statsV2) {\r\n\t\tconst lastHourRows: readonly InternalBgsRow[] = await readRowsFromS3(event.startDate);\r\n\t\t// logger.log('building hero stats', event.startDate, lastHourRows?.length);\r\n\t\tawait buildHeroStats(event.startDate, event.mmr, lastHourRows, allCards);\r\n\t} else if (event.trinkets) {\r\n\t\tconst lastHourRows: readonly InternalBgsRow[] = await readRowsFromS3(event.startDate);\r\n\t\t// logger.log('building hero stats', event.startDate, lastHourRows?.length);\r\n\t\tawait buildTrinketStats(\r\n\t\t\tevent.startDate,\r\n\t\t\tevent.mmr,\r\n\t\t\tlastHourRows,\r\n\t\t\tallCards,\r\n\t\t\tSTATS_BUCKET,\r\n\t\t\tHOURLY_KEY_TRINKET,\r\n\t\t\ts3,\r\n\t\t);\r\n\t}\r\n\r\n\tcleanup();\r\n};\r\n\r\nconst dispatchMainEvents = async (context: Context, event) => {\r\n\tconst startDate = buildProcessStartDate(event);\r\n\t// End one hour later\r\n\tconst endDate = new Date(startDate);\r\n\tendDate.setHours(endDate.getHours() + 1);\r\n\r\n\tawait saveRowsOnS3(startDate, endDate, allCards);\r\n\r\n\tawait dispatchStatsV2Lambda(context, startDate);\r\n\t// await dispatchQuestsV2Lambda(context, startDate);\r\n\tawait dispatchTrinketsLambda(context, startDate);\r\n};\r\n\r\nconst buildProcessStartDate = (event): Date => {\r\n\tif (event?.targetDate) {\r\n\t\tconst targetDate = new Date(event.targetDate);\r\n\t\treturn targetDate;\r\n\t}\r\n\r\n\t// Start from the start of the current hour\r\n\tconst processStartDate = new Date();\r\n\tprocessStartDate.setMinutes(0);\r\n\tprocessStartDate.setSeconds(0);\r\n\tprocessStartDate.setMilliseconds(0);\r\n\tprocessStartDate.setHours(processStartDate.getHours() - 1);\r\n\treturn processStartDate;\r\n};\r\n\r\nconst dispatchTrinketsLambda = async (context: Context, startDate: Date) => {\r\n\tfor (const mmr of allMmrPercentiles) {\r\n\t\tconst newEvent = {\r\n\t\t\ttrinkets: true,\r\n\t\t\tmmr: mmr,\r\n\t\t\tstartDate: startDate,\r\n\t\t};\r\n\t\tconst params = {\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t};\r\n\t\tconsole.log('\\tinvoking lambda', params);\r\n\t\tconst result = await lambda\r\n\t\t\t.invoke({\r\n\t\t\t\tFunctionName: context.functionName,\r\n\t\t\t\tInvocationType: 'Event',\r\n\t\t\t\tLogType: 'Tail',\r\n\t\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t\t})\r\n\t\t\t.promise();\r\n\t\t// logger.log('\\tinvocation result', result);\r\n\t}\r\n};\r\n\r\nconst dispatchQuestsV2Lambda = async (context: Context, startDate: Date) => {\r\n\tfor (const mmr of allMmrPercentiles) {\r\n\t\tconst newEvent = {\r\n\t\t\tquestsV2: true,\r\n\t\t\tmmr: mmr,\r\n\t\t\tstartDate: startDate,\r\n\t\t};\r\n\t\tconst params = {\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t};\r\n\t\tconsole.log('\\tinvoking lambda', params);\r\n\t\tconst result = await lambda\r\n\t\t\t.invoke({\r\n\t\t\t\tFunctionName: context.functionName,\r\n\t\t\t\tInvocationType: 'Event',\r\n\t\t\t\tLogType: 'Tail',\r\n\t\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t\t})\r\n\t\t\t.promise();\r\n\t\t// logger.log('\\tinvocation result', result);\r\n\t}\r\n};\r\n\r\nconst dispatchStatsV2Lambda = async (context: Context, startDate: Date) => {\r\n\tfor (const mmr of allMmrPercentiles) {\r\n\t\tconst newEvent = {\r\n\t\t\tstatsV2: true,\r\n\t\t\tmmr: mmr,\r\n\t\t\tstartDate: startDate,\r\n\t\t};\r\n\t\tconst params = {\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t};\r\n\t\tconsole.log('\\tinvoking lambda', params);\r\n\t\tconst result = await lambda\r\n\t\t\t.invoke({\r\n\t\t\t\tFunctionName: context.functionName,\r\n\t\t\t\tInvocationType: 'Event',\r\n\t\t\t\tLogType: 'Tail',\r\n\t\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t\t})\r\n\t\t\t.promise();\r\n\t\t// logger.log('\\tinvocation result', result);\r\n\t}\r\n};\r\n\r\nconst dispatchCatchUpEvents = async (context: Context, daysInThePast: number) => {\r\n\t// Build a list of hours for the last `daysInThePast` days, in the format YYYY-MM-ddTHH:mm:ss.sssZ\r\n\tconst now = new Date();\r\n\tconst hours = [];\r\n\tfor (let i = 0; i < 24 * daysInThePast; i++) {\r\n\t\tconst baseDate = new Date(now);\r\n\t\tbaseDate.setMinutes(0);\r\n\t\tbaseDate.setSeconds(0);\r\n\t\tbaseDate.setMilliseconds(0);\r\n\t\tconst hour = new Date(baseDate.getTime() - i * 60 * 60 * 1000);\r\n\t\thours.push(hour.toISOString());\r\n\t}\r\n\r\n\tfor (const targetDate of hours) {\r\n\t\tconsole.log('dispatching catch-up for date', targetDate);\r\n\t\tconst newEvent = {\r\n\t\t\ttargetDate: targetDate,\r\n\t\t};\r\n\t\tconst params = {\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t};\r\n\t\t// console.log('\\tinvoking lambda', params);\r\n\t\tconst result = await lambda\r\n\t\t\t.invoke({\r\n\t\t\t\tFunctionName: context.functionName,\r\n\t\t\t\tInvocationType: 'Event',\r\n\t\t\t\tLogType: 'Tail',\r\n\t\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t\t})\r\n\t\t\t.promise();\r\n\t\t// console.log('\\tinvocation result', result);\r\n\t\tawait sleep(50);\r\n\t}\r\n};\r\n"]}
1
+ {"version":3,"file":"_build-battlegrounds-hero-stats.js","sourceRoot":"","sources":["../../../src/solo/hourly/_build-battlegrounds-hero-stats.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-use-before-define */\r\nimport { S3, logBeforeTimeout, sleep } from '@firestone-hs/aws-lambda-utils';\r\nimport { AllCardsService } from '@firestone-hs/reference-data';\r\nimport { Context } from 'aws-lambda';\r\nimport AWS from 'aws-sdk';\r\nimport { InternalBgsRow } from '../../internal-model';\r\nimport { buildCardStats } from './cards/card-stats';\r\nimport { buildHeroStats } from './hero-stats';\r\nimport { readRowsFromS3, saveRowsOnS3 } from './rows';\r\nimport { buildTrinketStats } from './trinkets/trinket-stats';\r\n\r\nexport const s3 = new S3();\r\nconst allCards = new AllCardsService();\r\nconst lambda = new AWS.Lambda();\r\n\r\nconst allMmrPercentiles: (100 | 50 | 25 | 10 | 1)[] = [100, 50, 25, 10, 1];\r\n\r\nexport const STATS_BUCKET = 'static.zerotoheroes.com';\r\nexport const STATS_KEY_PREFIX = `api/bgs`;\r\nexport const WORKING_ROWS_FILE = `${STATS_KEY_PREFIX}/working/working-rows-%time%.json`;\r\nexport const HOURLY_KEY_HERO = `${STATS_KEY_PREFIX}/hero-stats/mmr-%mmrPercentile%/hourly/%startDate%.gz.json`;\r\nexport const HOURLY_KEY_QUEST = `${STATS_KEY_PREFIX}/quest-stats/mmr-%mmrPercentile%/hourly/%startDate%.gz.json`;\r\nexport const HOURLY_KEY_TRINKET = `${STATS_KEY_PREFIX}/trinket-stats/mmr-%mmrPercentile%/hourly/%startDate%.gz.json`;\r\nexport const HOURLY_KEY_CARD = `${STATS_KEY_PREFIX}/card-stats/mmr-%mmrPercentile%/hourly/%startDate%.gz.json`;\r\n\r\n// This example demonstrates a NodeJS 8.10 async handler[1], however of course you could use\r\n// the more traditional callback-style handler.\r\n// [1]: https://aws.amazon.com/blogs/compute/node-js-8-10-runtime-now-available-in-aws-lambda/\r\nexport default async (event, context: Context): Promise<any> => {\r\n\tawait handleNewStats(event, context);\r\n};\r\n\r\nexport const handleNewStats = async (event, context: Context) => {\r\n\tconst cleanup = logBeforeTimeout(context);\r\n\t// logger.log('event', event);\r\n\tawait allCards.initializeCardsDb();\r\n\r\n\tif (event.catchUp) {\r\n\t\tawait dispatchCatchUpEvents(context, +event.catchUp);\r\n\t\tcleanup();\r\n\t\treturn;\r\n\t}\r\n\r\n\tif (!event.statsV2 && !event.questsV2 && !event.trinkets && !event.cards) {\r\n\t\tawait dispatchMainEvents(context, event);\r\n\t\tcleanup();\r\n\t\treturn;\r\n\t}\r\n\r\n\t// if (event.questsV2) {\r\n\t// \tconst lastHourRows: readonly InternalBgsRow[] = await readRowsFromS3(event.startDate);\r\n\t// \t// logger.log('building quest stats', event.timePeriod, event.startDate, lastHourRows?.length);\r\n\t// \tawait buildQuestStats(event.startDate, event.mmr, lastHourRows, allCards, s3);\r\n\t// } else\r\n\tif (event.statsV2) {\r\n\t\tconst lastHourRows: readonly InternalBgsRow[] = await readRowsFromS3(event.startDate);\r\n\t\t// logger.log('building hero stats', event.startDate, lastHourRows?.length);\r\n\t\tawait buildHeroStats(event.startDate, event.mmr, lastHourRows, allCards);\r\n\t} else if (event.trinkets) {\r\n\t\tconst lastHourRows: readonly InternalBgsRow[] = await readRowsFromS3(event.startDate);\r\n\t\t// logger.log('building hero stats', event.startDate, lastHourRows?.length);\r\n\t\tawait buildTrinketStats(\r\n\t\t\tevent.startDate,\r\n\t\t\tevent.mmr,\r\n\t\t\tlastHourRows,\r\n\t\t\tallCards,\r\n\t\t\tSTATS_BUCKET,\r\n\t\t\tHOURLY_KEY_TRINKET,\r\n\t\t\ts3,\r\n\t\t);\r\n\t} else if (event.cards) {\r\n\t\tconst lastHourRows: readonly InternalBgsRow[] = await readRowsFromS3(event.startDate);\r\n\t\t// logger.log('building hero stats', event.startDate, lastHourRows?.length);\r\n\t\tawait buildCardStats(event.startDate, event.mmr, lastHourRows, allCards, STATS_BUCKET, HOURLY_KEY_CARD, s3);\r\n\t}\r\n\r\n\tcleanup();\r\n};\r\n\r\nconst dispatchMainEvents = async (context: Context, event) => {\r\n\tconst startDate = buildProcessStartDate(event);\r\n\t// End one hour later\r\n\tconst endDate = new Date(startDate);\r\n\tendDate.setHours(endDate.getHours() + 1);\r\n\r\n\tawait saveRowsOnS3(startDate, endDate, allCards);\r\n\r\n\tawait dispatchStatsV2Lambda(context, startDate);\r\n\t// await dispatchQuestsV2Lambda(context, startDate);\r\n\tawait dispatchTrinketsLambda(context, startDate);\r\n\tawait dispatchCardsLambda(context, startDate);\r\n};\r\n\r\nconst buildProcessStartDate = (event): Date => {\r\n\tif (event?.targetDate) {\r\n\t\tconst targetDate = new Date(event.targetDate);\r\n\t\treturn targetDate;\r\n\t}\r\n\r\n\t// Start from the start of the current hour\r\n\tconst processStartDate = new Date();\r\n\tprocessStartDate.setMinutes(0);\r\n\tprocessStartDate.setSeconds(0);\r\n\tprocessStartDate.setMilliseconds(0);\r\n\tprocessStartDate.setHours(processStartDate.getHours() - 1);\r\n\treturn processStartDate;\r\n};\r\n\r\nconst dispatchCardsLambda = async (context: Context, startDate: Date) => {\r\n\tfor (const mmr of allMmrPercentiles) {\r\n\t\tconst newEvent = {\r\n\t\t\tcards: true,\r\n\t\t\tmmr: mmr,\r\n\t\t\tstartDate: startDate,\r\n\t\t};\r\n\t\tconst params = {\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t};\r\n\t\tconsole.log('\\tinvoking lambda', params);\r\n\t\tconst result = await lambda\r\n\t\t\t.invoke({\r\n\t\t\t\tFunctionName: context.functionName,\r\n\t\t\t\tInvocationType: 'Event',\r\n\t\t\t\tLogType: 'Tail',\r\n\t\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t\t})\r\n\t\t\t.promise();\r\n\t\t// logger.log('\\tinvocation result', result);\r\n\t}\r\n};\r\n\r\nconst dispatchTrinketsLambda = async (context: Context, startDate: Date) => {\r\n\tfor (const mmr of allMmrPercentiles) {\r\n\t\tconst newEvent = {\r\n\t\t\ttrinkets: true,\r\n\t\t\tmmr: mmr,\r\n\t\t\tstartDate: startDate,\r\n\t\t};\r\n\t\tconst params = {\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t};\r\n\t\tconsole.log('\\tinvoking lambda', params);\r\n\t\tconst result = await lambda\r\n\t\t\t.invoke({\r\n\t\t\t\tFunctionName: context.functionName,\r\n\t\t\t\tInvocationType: 'Event',\r\n\t\t\t\tLogType: 'Tail',\r\n\t\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t\t})\r\n\t\t\t.promise();\r\n\t\t// logger.log('\\tinvocation result', result);\r\n\t}\r\n};\r\n\r\nconst dispatchQuestsV2Lambda = async (context: Context, startDate: Date) => {\r\n\tfor (const mmr of allMmrPercentiles) {\r\n\t\tconst newEvent = {\r\n\t\t\tquestsV2: true,\r\n\t\t\tmmr: mmr,\r\n\t\t\tstartDate: startDate,\r\n\t\t};\r\n\t\tconst params = {\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t};\r\n\t\tconsole.log('\\tinvoking lambda', params);\r\n\t\tconst result = await lambda\r\n\t\t\t.invoke({\r\n\t\t\t\tFunctionName: context.functionName,\r\n\t\t\t\tInvocationType: 'Event',\r\n\t\t\t\tLogType: 'Tail',\r\n\t\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t\t})\r\n\t\t\t.promise();\r\n\t\t// logger.log('\\tinvocation result', result);\r\n\t}\r\n};\r\n\r\nconst dispatchStatsV2Lambda = async (context: Context, startDate: Date) => {\r\n\tfor (const mmr of allMmrPercentiles) {\r\n\t\tconst newEvent = {\r\n\t\t\tstatsV2: true,\r\n\t\t\tmmr: mmr,\r\n\t\t\tstartDate: startDate,\r\n\t\t};\r\n\t\tconst params = {\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t};\r\n\t\tconsole.log('\\tinvoking lambda', params);\r\n\t\tconst result = await lambda\r\n\t\t\t.invoke({\r\n\t\t\t\tFunctionName: context.functionName,\r\n\t\t\t\tInvocationType: 'Event',\r\n\t\t\t\tLogType: 'Tail',\r\n\t\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t\t})\r\n\t\t\t.promise();\r\n\t\t// logger.log('\\tinvocation result', result);\r\n\t}\r\n};\r\n\r\nconst dispatchCatchUpEvents = async (context: Context, daysInThePast: number) => {\r\n\t// Build a list of hours for the last `daysInThePast` days, in the format YYYY-MM-ddTHH:mm:ss.sssZ\r\n\tconst now = new Date();\r\n\tconst hours = [];\r\n\tfor (let i = 0; i < 24 * daysInThePast; i++) {\r\n\t\tconst baseDate = new Date(now);\r\n\t\tbaseDate.setMinutes(0);\r\n\t\tbaseDate.setSeconds(0);\r\n\t\tbaseDate.setMilliseconds(0);\r\n\t\tconst hour = new Date(baseDate.getTime() - i * 60 * 60 * 1000);\r\n\t\thours.push(hour.toISOString());\r\n\t}\r\n\r\n\tfor (const targetDate of hours) {\r\n\t\tconsole.log('dispatching catch-up for date', targetDate);\r\n\t\tconst newEvent = {\r\n\t\t\ttargetDate: targetDate,\r\n\t\t};\r\n\t\tconst params = {\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t};\r\n\t\t// console.log('\\tinvoking lambda', params);\r\n\t\tconst result = await lambda\r\n\t\t\t.invoke({\r\n\t\t\t\tFunctionName: context.functionName,\r\n\t\t\t\tInvocationType: 'Event',\r\n\t\t\t\tLogType: 'Tail',\r\n\t\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t\t})\r\n\t\t\t.promise();\r\n\t\t// console.log('\\tinvocation result', result);\r\n\t\tawait sleep(50);\r\n\t}\r\n};\r\n"]}
@@ -0,0 +1,3 @@
1
+ import { AllCardsService } from '@firestone-hs/reference-data';
2
+ import { InternalBgsCardStat, InternalBgsRow } from '../../../internal-model';
3
+ export declare const buildCardStatsForMmr: (rows: readonly InternalBgsRow[], allCards: AllCardsService) => readonly InternalBgsCardStat[];
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildCardStatsForMmr = void 0;
4
+ const aws_lambda_utils_1 = require("@firestone-hs/aws-lambda-utils");
5
+ const buildCardStatsForMmr = (rows, allCards) => {
6
+ console.debug('building minion stats for', rows.length, 'rows');
7
+ const denormalized = rows.flatMap((row) => {
8
+ const cards = row.playedCardsExpanded;
9
+ return [...cards.map((card) => ({ ...row, playedCardsExpanded: [card] }))];
10
+ });
11
+ const groupedByCardPlayed = (0, aws_lambda_utils_1.groupByFunction)((r) => r.playedCardsExpanded[0].cardId)(denormalized);
12
+ return Object.keys(groupedByCardPlayed)
13
+ .sort()
14
+ .map((cardId) => {
15
+ const relevantRows = groupedByCardPlayed[cardId];
16
+ return buildStatsForSingleCard(relevantRows);
17
+ });
18
+ };
19
+ exports.buildCardStatsForMmr = buildCardStatsForMmr;
20
+ const buildStatsForSingleCard = (rows) => {
21
+ const ref = rows[0];
22
+ const averagePlacement = average(rows.map((r) => r.playerRank));
23
+ const result = {
24
+ cardId: ref.playedCardsExpanded[0].cardId,
25
+ totalPlayed: rows.length,
26
+ averagePlacement: averagePlacement,
27
+ turnStats: buildTurnStats(rows),
28
+ heroStats: buildHeroStats(rows),
29
+ };
30
+ return result;
31
+ };
32
+ const buildHeroStats = (rows) => {
33
+ const groupedByHero = (0, aws_lambda_utils_1.groupByFunction)((r) => r.heroCardId)(rows);
34
+ return Object.keys(groupedByHero)
35
+ .sort()
36
+ .map((heroCardId) => {
37
+ const relevantRows = groupedByHero[heroCardId];
38
+ const result = {
39
+ heroCardId: heroCardId,
40
+ totalPlayedWithHero: relevantRows.length,
41
+ averagePlacement: average(relevantRows.map((r) => r.playerRank)),
42
+ turnStats: buildTurnStats(relevantRows),
43
+ };
44
+ return result;
45
+ });
46
+ };
47
+ const buildTurnStats = (rows) => {
48
+ const groupedByTurn = (0, aws_lambda_utils_1.groupByFunction)((r) => r.playedCardsExpanded[0].turn)(rows);
49
+ return Object.keys(groupedByTurn)
50
+ .sort()
51
+ .map((turn) => {
52
+ const relevantRows = groupedByTurn[turn];
53
+ const result = {
54
+ turn: parseInt(turn),
55
+ totalPlayedAtTurn: relevantRows.length,
56
+ averagePlacement: average(relevantRows.map((r) => r.playerRank)),
57
+ };
58
+ return result;
59
+ });
60
+ };
61
+ const average = (data) => {
62
+ return data.reduce((a, b) => a + b, 0) / data.length;
63
+ };
64
+ //# sourceMappingURL=card-stats-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"card-stats-builder.js","sourceRoot":"","sources":["../../../../src/solo/hourly/cards/card-stats-builder.ts"],"names":[],"mappings":"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","sourcesContent":["import { groupByFunction } from '@firestone-hs/aws-lambda-utils';\r\nimport { AllCardsService } from '@firestone-hs/reference-data';\r\nimport {\r\n\tInternalBgsCardHeroStat,\r\n\tInternalBgsCardStat,\r\n\tInternalBgsCardTurnStat,\r\n\tInternalBgsRow,\r\n} from '../../../internal-model';\r\n\r\nexport const buildCardStatsForMmr = (\r\n\trows: readonly InternalBgsRow[],\r\n\tallCards: AllCardsService,\r\n): readonly InternalBgsCardStat[] => {\r\n\tconsole.debug('building minion stats for', rows.length, 'rows');\r\n\tconst denormalized = rows.flatMap((row) => {\r\n\t\tconst cards = row.playedCardsExpanded;\r\n\t\treturn [...cards.map((card) => ({ ...row, playedCardsExpanded: [card] }))];\r\n\t});\r\n\tconst groupedByCardPlayed = groupByFunction((r: InternalBgsRow) => r.playedCardsExpanded[0].cardId)(denormalized);\r\n\treturn Object.keys(groupedByCardPlayed)\r\n\t\t.sort()\r\n\t\t.map((cardId) => {\r\n\t\t\tconst relevantRows = groupedByCardPlayed[cardId];\r\n\t\t\treturn buildStatsForSingleCard(relevantRows);\r\n\t\t});\r\n};\r\n\r\n// All rows here belong to a single card\r\nconst buildStatsForSingleCard = (rows: readonly InternalBgsRow[]): InternalBgsCardStat => {\r\n\tconst ref = rows[0];\r\n\tconst averagePlacement = average(rows.map((r) => r.playerRank));\r\n\r\n\tconst result: InternalBgsCardStat = {\r\n\t\tcardId: ref.playedCardsExpanded[0].cardId,\r\n\t\ttotalPlayed: rows.length,\r\n\t\taveragePlacement: averagePlacement,\r\n\t\tturnStats: buildTurnStats(rows),\r\n\t\theroStats: buildHeroStats(rows),\r\n\t};\r\n\treturn result;\r\n};\r\n\r\nconst buildHeroStats = (rows: readonly InternalBgsRow[]): readonly InternalBgsCardHeroStat[] => {\r\n\tconst groupedByHero = groupByFunction((r: InternalBgsRow) => r.heroCardId)(rows);\r\n\treturn Object.keys(groupedByHero)\r\n\t\t.sort()\r\n\t\t.map((heroCardId) => {\r\n\t\t\tconst relevantRows = groupedByHero[heroCardId];\r\n\t\t\tconst result: InternalBgsCardHeroStat = {\r\n\t\t\t\theroCardId: heroCardId,\r\n\t\t\t\ttotalPlayedWithHero: relevantRows.length,\r\n\t\t\t\taveragePlacement: average(relevantRows.map((r) => r.playerRank)),\r\n\t\t\t\tturnStats: buildTurnStats(relevantRows),\r\n\t\t\t};\r\n\t\t\treturn result;\r\n\t\t});\r\n};\r\n\r\nconst buildTurnStats = (rows: readonly InternalBgsRow[]): readonly InternalBgsCardTurnStat[] => {\r\n\tconst groupedByTurn = groupByFunction((r: InternalBgsRow) => r.playedCardsExpanded[0].turn)(rows);\r\n\treturn Object.keys(groupedByTurn)\r\n\t\t.sort()\r\n\t\t.map((turn) => {\r\n\t\t\tconst relevantRows = groupedByTurn[turn];\r\n\t\t\tconst result: InternalBgsCardTurnStat = {\r\n\t\t\t\tturn: parseInt(turn),\r\n\t\t\t\ttotalPlayedAtTurn: relevantRows.length,\r\n\t\t\t\taveragePlacement: average(relevantRows.map((r) => r.playerRank)),\r\n\t\t\t};\r\n\t\t\treturn result;\r\n\t\t});\r\n};\r\n\r\nconst average = (data: readonly number[]): number => {\r\n\treturn data.reduce((a, b) => a + b, 0) / data.length;\r\n};\r\n"]}
@@ -0,0 +1,4 @@
1
+ import { S3 } from '@firestone-hs/aws-lambda-utils';
2
+ import { AllCardsService } from '@firestone-hs/reference-data';
3
+ import { InternalBgsRow } from '../../../internal-model';
4
+ export declare const buildCardStats: (startDate: string, percentile: 100 | 50 | 25 | 10 | 1, rows: readonly InternalBgsRow[], allCards: AllCardsService, bucket: string, key: string, s3: S3) => Promise<void>;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildCardStats = void 0;
4
+ const zlib_1 = require("zlib");
5
+ const utils_1 = require("../utils");
6
+ const card_stats_builder_1 = require("./card-stats-builder");
7
+ const buildCardStats = async (startDate, percentile, rows, allCards, bucket, key, s3) => {
8
+ const rowsWithCards = rows.filter((row) => row.playedCardsExpanded.length > 0);
9
+ const mmrPercentiles = (0, utils_1.buildMmrPercentiles)(rowsWithCards);
10
+ const mmrPercentile = mmrPercentiles.find((p) => p.percentile === percentile);
11
+ const mmrRows = rowsWithCards.filter((row) => mmrPercentile.percentile === 100 || row.rating >= mmrPercentile.mmr);
12
+ const minionStats = (0, card_stats_builder_1.buildCardStatsForMmr)(mmrRows, allCards);
13
+ const result = {
14
+ lastUpdateDate: new Date(),
15
+ mmrPercentiles: mmrPercentiles,
16
+ dataPoints: rowsWithCards.length,
17
+ cardStats: minionStats.map((stat) => ({
18
+ ...stat,
19
+ mmrPercentile: percentile,
20
+ timePeriod: null,
21
+ })),
22
+ };
23
+ const destination = key.replace('%mmrPercentile%', `${percentile}`).replace('%startDate%', startDate);
24
+ await s3.writeFile((0, zlib_1.gzipSync)(JSON.stringify(result)), bucket, destination, 'application/json', 'gzip');
25
+ };
26
+ exports.buildCardStats = buildCardStats;
27
+ //# sourceMappingURL=card-stats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"card-stats.js","sourceRoot":"","sources":["../../../../src/solo/hourly/cards/card-stats.ts"],"names":[],"mappings":";;;AAEA,+BAAgC;AAGhC,oCAA+C;AAC/C,6DAA4D;AAErD,MAAM,cAAc,GAAG,KAAK,EAClC,SAAiB,EACjB,UAAkC,EAClC,IAA+B,EAC/B,QAAyB,EACzB,MAAc,EACd,GAAW,EACX,EAAM,EACL,EAAE;IACH,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,mBAAmB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC/E,MAAM,cAAc,GAA6B,IAAA,2BAAmB,EAAC,aAAa,CAAC,CAAC;IACpF,MAAM,aAAa,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,UAAU,CAAC,CAAC;IAC9E,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,aAAa,CAAC,UAAU,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,IAAI,aAAa,CAAC,GAAG,CAAC,CAAC;IAEnH,MAAM,WAAW,GAAmC,IAAA,yCAAoB,EAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC5F,MAAM,MAAM,GAAyB;QACpC,cAAc,EAAE,IAAI,IAAI,EAAE;QAC1B,cAAc,EAAE,cAAc;QAC9B,UAAU,EAAE,aAAa,CAAC,MAAM;QAChC,SAAS,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACrC,GAAG,IAAI;YACP,aAAa,EAAE,UAAU;YACzB,UAAU,EAAE,IAAI;SAChB,CAAC,CAAC;KACH,CAAC;IAEF,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,UAAU,EAAE,CAAC,CAAC,OAAO,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;IACtG,MAAM,EAAE,CAAC,SAAS,CAAC,IAAA,eAAQ,EAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,CAAC,CAAC;AAEvG,CAAC,CAAC;AA7BW,QAAA,cAAc,kBA6BzB","sourcesContent":["import { S3 } from '@firestone-hs/aws-lambda-utils';\r\nimport { AllCardsService } from '@firestone-hs/reference-data';\r\nimport { gzipSync } from 'zlib';\r\nimport { InternalBgsCardStat, InternalBgsCardStats, InternalBgsRow } from '../../../internal-model';\r\nimport { MmrPercentile } from '../../../models';\r\nimport { buildMmrPercentiles } from '../utils';\r\nimport { buildCardStatsForMmr } from './card-stats-builder';\r\n\r\nexport const buildCardStats = async (\r\n\tstartDate: string,\r\n\tpercentile: 100 | 50 | 25 | 10 | 1,\r\n\trows: readonly InternalBgsRow[],\r\n\tallCards: AllCardsService,\r\n\tbucket: string,\r\n\tkey: string,\r\n\ts3: S3,\r\n) => {\r\n\tconst rowsWithCards = rows.filter((row) => row.playedCardsExpanded.length > 0);\r\n\tconst mmrPercentiles: readonly MmrPercentile[] = buildMmrPercentiles(rowsWithCards);\r\n\tconst mmrPercentile = mmrPercentiles.find((p) => p.percentile === percentile);\r\n\tconst mmrRows = rowsWithCards.filter((row) => mmrPercentile.percentile === 100 || row.rating >= mmrPercentile.mmr);\r\n\r\n\tconst minionStats: readonly InternalBgsCardStat[] = buildCardStatsForMmr(mmrRows, allCards);\r\n\tconst result: InternalBgsCardStats = {\r\n\t\tlastUpdateDate: new Date(),\r\n\t\tmmrPercentiles: mmrPercentiles,\r\n\t\tdataPoints: rowsWithCards.length,\r\n\t\tcardStats: minionStats.map((stat) => ({\r\n\t\t\t...stat,\r\n\t\t\tmmrPercentile: percentile,\r\n\t\t\ttimePeriod: null,\r\n\t\t})),\r\n\t};\r\n\t// logger.log('\\tbuilt stats', statsV2.dataPoints, statsV2.heroStats?.length);\r\n\tconst destination = key.replace('%mmrPercentile%', `${percentile}`).replace('%startDate%', startDate);\r\n\tawait s3.writeFile(gzipSync(JSON.stringify(result)), bucket, destination, 'application/json', 'gzip');\r\n\t// console.log('written file', destination);\r\n};\r\n"]}
@@ -155,10 +155,12 @@ const processRows = async (rows, multipartUpload, allCards) => {
155
155
  heroCardId: (0, util_functions_1.normalizeHeroCardId)(row.heroCardId, allCards),
156
156
  tribesExpanded: row.tribes.split(',').map((tribe) => parseInt(tribe)),
157
157
  heroesOptionsExpanded: (_b = (_a = row.heroesOptions) === null || _a === void 0 ? void 0 : _a.split(',').map((hero) => (0, util_functions_1.normalizeHeroCardId)(hero, allCards))) !== null && _b !== void 0 ? _b : [],
158
+ playedCardsExpanded: row.playedCards != null ? JSON.parse(row.playedCards) : [],
158
159
  };
159
160
  delete result.reviewId;
160
161
  delete result.tribes;
161
162
  delete result.heroesOptions;
163
+ delete result.playedCards;
162
164
  return result;
163
165
  });
164
166
  if (validRows.length > 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"rows.js","sourceRoot":"","sources":["../../../src/solo/hourly/rows.ts"],"names":[],"mappings":"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","sourcesContent":["import { S3Multipart } from '@firestone-hs/aws-lambda-utils';\r\nimport { AllCardsService, CardIds } from '@firestone-hs/reference-data';\r\nimport { S3 as S3AWS } from 'aws-sdk';\r\nimport SecretsManager, { GetSecretValueRequest, GetSecretValueResponse } from 'aws-sdk/clients/secretsmanager';\r\nimport { Connection, createPool } from 'mysql';\r\nimport { Readable } from 'stream';\r\nimport { normalizeHeroCardId } from '../../common/util-functions';\r\nimport { InternalBgsRow } from '../../internal-model';\r\nimport { STATS_BUCKET, WORKING_ROWS_FILE, s3 } from './_build-battlegrounds-hero-stats';\r\n\r\nexport const readRowsFromS3 = async (startDate: string): Promise<readonly InternalBgsRow[]> => {\r\n\treturn new Promise<readonly InternalBgsRow[]>((resolve, reject) => {\r\n\t\tconst workingRowsFile = `${WORKING_ROWS_FILE.replace('%time%', startDate)}`;\r\n\t\tconsole.debug('reading rows from s3', workingRowsFile);\r\n\t\tlet parseErrors = 0;\r\n\t\tlet totalParsed = 0;\r\n\t\tconst stream: Readable = s3.readStream(STATS_BUCKET, workingRowsFile);\r\n\t\tconst result: InternalBgsRow[] = [];\r\n\t\tlet previousString = '';\r\n\t\tlet emptyRowsInARow = 0;\r\n\t\tstream\r\n\t\t\t.on('data', (chunk) => {\r\n\t\t\t\tconst str = Buffer.from(chunk).toString('utf-8');\r\n\t\t\t\tconst newStr = previousString + str;\r\n\t\t\t\tconst split = newStr.split('\\n');\r\n\t\t\t\tconst rows: readonly InternalBgsRow[] = split.slice(0, split.length - 1).map((row) => {\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tconst result: InternalBgsRow = JSON.parse(row);\r\n\t\t\t\t\t\ttotalParsed++;\r\n\t\t\t\t\t\treturn result;\r\n\t\t\t\t\t} catch (e) {\r\n\t\t\t\t\t\t// logger.warn('could not parse row', row);\r\n\t\t\t\t\t\tparseErrors++;\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\t\t\t\tpreviousString = split[split.length - 1];\r\n\t\t\t\tresult.push(...rows);\r\n\r\n\t\t\t\t// Do this to avoid errors in case the chunks are small compared to the row sizes\r\n\t\t\t\tif (result.length === 0 && rows.length === 0) {\r\n\t\t\t\t\temptyRowsInARow++;\r\n\t\t\t\t} else {\r\n\t\t\t\t\temptyRowsInARow = 0;\r\n\t\t\t\t}\r\n\t\t\t\tif (emptyRowsInARow > 50) {\r\n\t\t\t\t\tconsole.error(newStr);\r\n\t\t\t\t\tconsole.error(split);\r\n\t\t\t\t\tthrow new Error('Could not parse any row');\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t\t.on('end', () => {\r\n\t\t\t\tconst finalResult = result.filter((row) => !!row);\r\n\t\t\t\tconsole.log('stream end', result.length, finalResult.length);\r\n\t\t\t\tconsole.log('parsing errors', parseErrors, 'and successes', totalParsed);\r\n\t\t\t\tresolve(finalResult);\r\n\t\t\t});\r\n\t});\r\n};\r\n\r\nexport const saveRowsOnS3 = async (startDate: Date, endDate: Date, allCards: AllCardsService) => {\r\n\tconsole.log('will export rows to S3', startDate, endDate);\r\n\tconst secretRequest: GetSecretValueRequest = {\r\n\t\tSecretId: 'rds-connection',\r\n\t};\r\n\tconst secret: SecretInfo = await getSecret(secretRequest);\r\n\tconst pool = createPool({\r\n\t\tconnectionLimit: 1,\r\n\t\thost: secret.hostReadOnly,\r\n\t\tuser: secret.username,\r\n\t\tpassword: secret.password,\r\n\t\tdatabase: 'replay_summary',\r\n\t\tport: secret.port,\r\n\t});\r\n\r\n\ttry {\r\n\t\tawait performRowProcessIngPool(pool, startDate, endDate, allCards);\r\n\t} finally {\r\n\t\tpool.end((err) => {\r\n\t\t\tconsole.log('ending pool', err);\r\n\t\t});\r\n\t}\r\n};\r\n\r\nconst performRowProcessIngPool = async (pool: any, startDate: Date, endDate: Date, allCards: AllCardsService) => {\r\n\treturn new Promise<void>((resolve) => {\r\n\t\tpool.getConnection(async (err, connection) => {\r\n\t\t\tif (err) {\r\n\t\t\t\tconsole.log('error with connection', err);\r\n\t\t\t\tthrow new Error('Could not connect to DB');\r\n\t\t\t} else {\r\n\t\t\t\tawait performRowsProcessing(connection, startDate, endDate, allCards);\r\n\t\t\t\tconnection.release();\r\n\t\t\t}\r\n\t\t\tresolve();\r\n\t\t});\r\n\t});\r\n};\r\n\r\nconst performRowsProcessing = async (\r\n\tconnection: Connection,\r\n\tstartDate: Date,\r\n\tendDate: Date,\r\n\tallCards: AllCardsService,\r\n) => {\r\n\tconst multipartUpload = new S3Multipart(new S3AWS());\r\n\tconst workingRowsFile = `${WORKING_ROWS_FILE.replace('%time%', startDate.toISOString())}`;\r\n\tawait multipartUpload.initMultipart('static.zerotoheroes.com', workingRowsFile, 'application/json');\r\n\tconsole.log('multipart upload init', workingRowsFile);\r\n\r\n\treturn new Promise<void>((resolve) => {\r\n\t\tconst queryStr = `\r\n\t\t\tSELECT * FROM bgs_run_stats\r\n\t\t\tWHERE creationDate >= ?\r\n\t\t\tAND creationDate < ?\r\n\t\t`;\r\n\t\tconsole.log('running query', queryStr);\r\n\t\tconst query = connection.query(queryStr, [startDate, endDate]);\r\n\r\n\t\tlet rowsToProcess = [];\r\n\t\tlet rowCount = 0;\r\n\t\tquery\r\n\t\t\t.on('error', (err) => {\r\n\t\t\t\tconsole.error('error while fetching rows', err);\r\n\t\t\t})\r\n\t\t\t.on('fields', (fields) => {\r\n\t\t\t\tconsole.log('fields', fields);\r\n\t\t\t})\r\n\t\t\t.on('result', async (row) => {\r\n\t\t\t\trowsToProcess.push(row);\r\n\t\t\t\tif (rowsToProcess.length > 20000 && !multipartUpload.processing) {\r\n\t\t\t\t\tconnection.pause();\r\n\t\t\t\t\t// console.log('before upload', rowsToProcess.length);\r\n\t\t\t\t\tconst toUpload = rowsToProcess;\r\n\t\t\t\t\trowsToProcess = [];\r\n\t\t\t\t\t// console.log('will upload', toUpload.length, 'rows');\r\n\t\t\t\t\tconst uploaded = await processRows(toUpload, multipartUpload, allCards);\r\n\t\t\t\t\trowCount += uploaded;\r\n\t\t\t\t\tconsole.log('processed rows', uploaded, '/', toUpload.length, rowCount);\r\n\t\t\t\t\tconnection.resume();\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t\t.on('end', async () => {\r\n\t\t\t\tconsole.log('end');\r\n\t\t\t\tconst toUpload = rowsToProcess;\r\n\t\t\t\trowsToProcess = [];\r\n\t\t\t\t// console.log('will upload', toUpload.length, 'rows');\r\n\t\t\t\tconst uploaded = await processRows(toUpload, multipartUpload, allCards);\r\n\t\t\t\trowCount += uploaded;\r\n\t\t\t\tconsole.log('processed rows', uploaded, rowCount);\r\n\t\t\t\t// connection.resume();\r\n\t\t\t\tawait multipartUpload.completeMultipart();\r\n\t\t\t\tresolve();\r\n\t\t\t});\r\n\t});\r\n};\r\n\r\nconst processRows = async (\r\n\trows: readonly InternalBgsRow[],\r\n\tmultipartUpload: S3Multipart,\r\n\tallCards: AllCardsService,\r\n) => {\r\n\tconst validRows = rows\r\n\t\t// .filter((row) => row.heroCardId.startsWith('TB_BaconShop_') || row.heroCardId.startsWith('BG'))\r\n\t\t.filter(\r\n\t\t\t(row) =>\r\n\t\t\t\trow.heroCardId !== CardIds.ArannaStarseeker_ArannaUnleashedToken &&\r\n\t\t\t\trow.heroCardId !== CardIds.QueenAzshara_NagaQueenAzsharaToken,\r\n\t\t)\r\n\t\t.filter((row) => !!row.playerRank && !!row.tribes?.length)\r\n\t\t.map((row) => {\r\n\t\t\tconst result: InternalBgsRow = {\r\n\t\t\t\t...row,\r\n\t\t\t\theroCardId: normalizeHeroCardId(row.heroCardId, allCards),\r\n\t\t\t\ttribesExpanded: row.tribes.split(',').map((tribe) => parseInt(tribe)),\r\n\t\t\t\theroesOptionsExpanded:\r\n\t\t\t\t\trow.heroesOptions?.split(',').map((hero) => normalizeHeroCardId(hero, allCards)) ?? [],\r\n\t\t\t};\r\n\t\t\tdelete (result as any).reviewId;\r\n\t\t\tdelete (result as any).tribes;\r\n\t\t\tdelete (result as any).heroesOptions;\r\n\t\t\treturn result;\r\n\t\t});\r\n\tif (validRows.length > 0) {\r\n\t\t// console.log('\\t', 'uploading', validRows.length, 'rows');\r\n\t\tawait multipartUpload.uploadPart(validRows.map((r) => JSON.stringify(r)).join('\\n'));\r\n\t}\r\n\treturn validRows.length;\r\n};\r\n\r\nconst getSecret = (secretRequest: GetSecretValueRequest) => {\r\n\tconst secretsManager = new SecretsManager({ region: 'us-west-2' });\r\n\treturn new Promise<SecretInfo>((resolve) => {\r\n\t\tsecretsManager.getSecretValue(secretRequest, (err, data: GetSecretValueResponse) => {\r\n\t\t\tconst secretInfo: SecretInfo = JSON.parse(data.SecretString);\r\n\t\t\tresolve(secretInfo);\r\n\t\t});\r\n\t});\r\n};\r\n\r\ninterface SecretInfo {\r\n\treadonly username: string;\r\n\treadonly password: string;\r\n\treadonly host: string;\r\n\treadonly hostReadOnly: string;\r\n\treadonly port: number;\r\n\treadonly dbClusterIdentifier: string;\r\n}\r\n"]}
1
+ {"version":3,"file":"rows.js","sourceRoot":"","sources":["../../../src/solo/hourly/rows.ts"],"names":[],"mappings":"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","sourcesContent":["import { S3Multipart } from '@firestone-hs/aws-lambda-utils';\r\nimport { AllCardsService, CardIds } from '@firestone-hs/reference-data';\r\nimport { S3 as S3AWS } from 'aws-sdk';\r\nimport SecretsManager, { GetSecretValueRequest, GetSecretValueResponse } from 'aws-sdk/clients/secretsmanager';\r\nimport { Connection, createPool } from 'mysql';\r\nimport { Readable } from 'stream';\r\nimport { normalizeHeroCardId } from '../../common/util-functions';\r\nimport { InternalBgsRow } from '../../internal-model';\r\nimport { STATS_BUCKET, WORKING_ROWS_FILE, s3 } from './_build-battlegrounds-hero-stats';\r\n\r\nexport const readRowsFromS3 = async (startDate: string): Promise<readonly InternalBgsRow[]> => {\r\n\treturn new Promise<readonly InternalBgsRow[]>((resolve, reject) => {\r\n\t\tconst workingRowsFile = `${WORKING_ROWS_FILE.replace('%time%', startDate)}`;\r\n\t\tconsole.debug('reading rows from s3', workingRowsFile);\r\n\t\tlet parseErrors = 0;\r\n\t\tlet totalParsed = 0;\r\n\t\tconst stream: Readable = s3.readStream(STATS_BUCKET, workingRowsFile);\r\n\t\tconst result: InternalBgsRow[] = [];\r\n\t\tlet previousString = '';\r\n\t\tlet emptyRowsInARow = 0;\r\n\t\tstream\r\n\t\t\t.on('data', (chunk) => {\r\n\t\t\t\tconst str = Buffer.from(chunk).toString('utf-8');\r\n\t\t\t\tconst newStr = previousString + str;\r\n\t\t\t\tconst split = newStr.split('\\n');\r\n\t\t\t\tconst rows: readonly InternalBgsRow[] = split.slice(0, split.length - 1).map((row) => {\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tconst result: InternalBgsRow = JSON.parse(row);\r\n\t\t\t\t\t\ttotalParsed++;\r\n\t\t\t\t\t\treturn result;\r\n\t\t\t\t\t} catch (e) {\r\n\t\t\t\t\t\t// logger.warn('could not parse row', row);\r\n\t\t\t\t\t\tparseErrors++;\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\t\t\t\tpreviousString = split[split.length - 1];\r\n\t\t\t\tresult.push(...rows);\r\n\r\n\t\t\t\t// Do this to avoid errors in case the chunks are small compared to the row sizes\r\n\t\t\t\tif (result.length === 0 && rows.length === 0) {\r\n\t\t\t\t\temptyRowsInARow++;\r\n\t\t\t\t} else {\r\n\t\t\t\t\temptyRowsInARow = 0;\r\n\t\t\t\t}\r\n\t\t\t\tif (emptyRowsInARow > 50) {\r\n\t\t\t\t\tconsole.error(newStr);\r\n\t\t\t\t\tconsole.error(split);\r\n\t\t\t\t\tthrow new Error('Could not parse any row');\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t\t.on('end', () => {\r\n\t\t\t\tconst finalResult = result.filter((row) => !!row);\r\n\t\t\t\tconsole.log('stream end', result.length, finalResult.length);\r\n\t\t\t\tconsole.log('parsing errors', parseErrors, 'and successes', totalParsed);\r\n\t\t\t\tresolve(finalResult);\r\n\t\t\t});\r\n\t});\r\n};\r\n\r\nexport const saveRowsOnS3 = async (startDate: Date, endDate: Date, allCards: AllCardsService) => {\r\n\tconsole.log('will export rows to S3', startDate, endDate);\r\n\tconst secretRequest: GetSecretValueRequest = {\r\n\t\tSecretId: 'rds-connection',\r\n\t};\r\n\tconst secret: SecretInfo = await getSecret(secretRequest);\r\n\tconst pool = createPool({\r\n\t\tconnectionLimit: 1,\r\n\t\thost: secret.hostReadOnly,\r\n\t\tuser: secret.username,\r\n\t\tpassword: secret.password,\r\n\t\tdatabase: 'replay_summary',\r\n\t\tport: secret.port,\r\n\t});\r\n\r\n\ttry {\r\n\t\tawait performRowProcessIngPool(pool, startDate, endDate, allCards);\r\n\t} finally {\r\n\t\tpool.end((err) => {\r\n\t\t\tconsole.log('ending pool', err);\r\n\t\t});\r\n\t}\r\n};\r\n\r\nconst performRowProcessIngPool = async (pool: any, startDate: Date, endDate: Date, allCards: AllCardsService) => {\r\n\treturn new Promise<void>((resolve) => {\r\n\t\tpool.getConnection(async (err, connection) => {\r\n\t\t\tif (err) {\r\n\t\t\t\tconsole.log('error with connection', err);\r\n\t\t\t\tthrow new Error('Could not connect to DB');\r\n\t\t\t} else {\r\n\t\t\t\tawait performRowsProcessing(connection, startDate, endDate, allCards);\r\n\t\t\t\tconnection.release();\r\n\t\t\t}\r\n\t\t\tresolve();\r\n\t\t});\r\n\t});\r\n};\r\n\r\nconst performRowsProcessing = async (\r\n\tconnection: Connection,\r\n\tstartDate: Date,\r\n\tendDate: Date,\r\n\tallCards: AllCardsService,\r\n) => {\r\n\tconst multipartUpload = new S3Multipart(new S3AWS());\r\n\tconst workingRowsFile = `${WORKING_ROWS_FILE.replace('%time%', startDate.toISOString())}`;\r\n\tawait multipartUpload.initMultipart('static.zerotoheroes.com', workingRowsFile, 'application/json');\r\n\tconsole.log('multipart upload init', workingRowsFile);\r\n\r\n\treturn new Promise<void>((resolve) => {\r\n\t\tconst queryStr = `\r\n\t\t\tSELECT * FROM bgs_run_stats\r\n\t\t\tWHERE creationDate >= ?\r\n\t\t\tAND creationDate < ?\r\n\t\t`;\r\n\t\tconsole.log('running query', queryStr);\r\n\t\tconst query = connection.query(queryStr, [startDate, endDate]);\r\n\r\n\t\tlet rowsToProcess = [];\r\n\t\tlet rowCount = 0;\r\n\t\tquery\r\n\t\t\t.on('error', (err) => {\r\n\t\t\t\tconsole.error('error while fetching rows', err);\r\n\t\t\t})\r\n\t\t\t.on('fields', (fields) => {\r\n\t\t\t\tconsole.log('fields', fields);\r\n\t\t\t})\r\n\t\t\t.on('result', async (row) => {\r\n\t\t\t\trowsToProcess.push(row);\r\n\t\t\t\tif (rowsToProcess.length > 20000 && !multipartUpload.processing) {\r\n\t\t\t\t\tconnection.pause();\r\n\t\t\t\t\t// console.log('before upload', rowsToProcess.length);\r\n\t\t\t\t\tconst toUpload = rowsToProcess;\r\n\t\t\t\t\trowsToProcess = [];\r\n\t\t\t\t\t// console.log('will upload', toUpload.length, 'rows');\r\n\t\t\t\t\tconst uploaded = await processRows(toUpload, multipartUpload, allCards);\r\n\t\t\t\t\trowCount += uploaded;\r\n\t\t\t\t\tconsole.log('processed rows', uploaded, '/', toUpload.length, rowCount);\r\n\t\t\t\t\tconnection.resume();\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t\t.on('end', async () => {\r\n\t\t\t\tconsole.log('end');\r\n\t\t\t\tconst toUpload = rowsToProcess;\r\n\t\t\t\trowsToProcess = [];\r\n\t\t\t\t// console.log('will upload', toUpload.length, 'rows');\r\n\t\t\t\tconst uploaded = await processRows(toUpload, multipartUpload, allCards);\r\n\t\t\t\trowCount += uploaded;\r\n\t\t\t\tconsole.log('processed rows', uploaded, rowCount);\r\n\t\t\t\t// connection.resume();\r\n\t\t\t\tawait multipartUpload.completeMultipart();\r\n\t\t\t\tresolve();\r\n\t\t\t});\r\n\t});\r\n};\r\n\r\nconst processRows = async (\r\n\trows: readonly InternalBgsRow[],\r\n\tmultipartUpload: S3Multipart,\r\n\tallCards: AllCardsService,\r\n) => {\r\n\tconst validRows = rows\r\n\t\t// .filter((row) => row.heroCardId.startsWith('TB_BaconShop_') || row.heroCardId.startsWith('BG'))\r\n\t\t.filter(\r\n\t\t\t(row) =>\r\n\t\t\t\trow.heroCardId !== CardIds.ArannaStarseeker_ArannaUnleashedToken &&\r\n\t\t\t\trow.heroCardId !== CardIds.QueenAzshara_NagaQueenAzsharaToken,\r\n\t\t)\r\n\t\t.filter((row) => !!row.playerRank && !!row.tribes?.length)\r\n\t\t.map((row) => {\r\n\t\t\tconst result: InternalBgsRow = {\r\n\t\t\t\t...row,\r\n\t\t\t\theroCardId: normalizeHeroCardId(row.heroCardId, allCards),\r\n\t\t\t\ttribesExpanded: row.tribes.split(',').map((tribe) => parseInt(tribe)),\r\n\t\t\t\theroesOptionsExpanded:\r\n\t\t\t\t\trow.heroesOptions?.split(',').map((hero) => normalizeHeroCardId(hero, allCards)) ?? [],\r\n\t\t\t\tplayedCardsExpanded: row.playedCards != null ? JSON.parse(row.playedCards) : [],\r\n\t\t\t};\r\n\t\t\tdelete (result as any).reviewId;\r\n\t\t\tdelete (result as any).tribes;\r\n\t\t\tdelete (result as any).heroesOptions;\r\n\t\t\tdelete (result as any).playedCards;\r\n\t\t\treturn result;\r\n\t\t});\r\n\tif (validRows.length > 0) {\r\n\t\t// console.log('\\t', 'uploading', validRows.length, 'rows');\r\n\t\tawait multipartUpload.uploadPart(validRows.map((r) => JSON.stringify(r)).join('\\n'));\r\n\t}\r\n\treturn validRows.length;\r\n};\r\n\r\nconst getSecret = (secretRequest: GetSecretValueRequest) => {\r\n\tconst secretsManager = new SecretsManager({ region: 'us-west-2' });\r\n\treturn new Promise<SecretInfo>((resolve) => {\r\n\t\tsecretsManager.getSecretValue(secretRequest, (err, data: GetSecretValueResponse) => {\r\n\t\t\tconst secretInfo: SecretInfo = JSON.parse(data.SecretString);\r\n\t\t\tresolve(secretInfo);\r\n\t\t});\r\n\t});\r\n};\r\n\r\ninterface SecretInfo {\r\n\treadonly username: string;\r\n\treadonly password: string;\r\n\treadonly host: string;\r\n\treadonly hostReadOnly: string;\r\n\treadonly port: number;\r\n\treadonly dbClusterIdentifier: string;\r\n}\r\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@firestone-hs/bgs-global-stats",
3
- "version": "1.0.47",
3
+ "version": "1.0.48",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "lint": "eslint --color --fix --ext .ts .",