@firestone-hs/bgs-global-stats 1.0.43 → 1.0.45

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 (66) hide show
  1. package/dist/duos/aggregate-hourly/config.d.ts +1 -0
  2. package/dist/duos/aggregate-hourly/config.js +2 -1
  3. package/dist/duos/aggregate-hourly/config.js.map +1 -1
  4. package/dist/duos/aggregate-hourly/heroes/s3-saver.js +1 -0
  5. package/dist/duos/aggregate-hourly/heroes/s3-saver.js.map +1 -1
  6. package/dist/duos/aggregate-hourly/heroes/stats-merger.js +3 -1
  7. package/dist/duos/aggregate-hourly/heroes/stats-merger.js.map +1 -1
  8. package/dist/duos/hourly/_build-battlegrounds-hero-stats.d.ts +2 -4
  9. package/dist/duos/hourly/_build-battlegrounds-hero-stats.js +118 -12
  10. package/dist/duos/hourly/_build-battlegrounds-hero-stats.js.map +1 -1
  11. package/dist/duos/hourly/hero-stats-buikder.js +4 -4
  12. package/dist/duos/hourly/hero-stats-buikder.js.map +1 -1
  13. package/dist/duos/hourly/rows.js +1 -1
  14. package/dist/duos/hourly/rows.js.map +1 -1
  15. package/dist/duos/hourly/trinkets/trinket-stats.d.ts +0 -0
  16. package/dist/duos/hourly/trinkets/trinket-stats.js +1 -0
  17. package/dist/duos/hourly/trinkets/trinket-stats.js.map +1 -0
  18. package/dist/duos/hourly/utils.js +1 -1
  19. package/dist/duos/hourly/utils.js.map +1 -1
  20. package/dist/internal-model.d.ts +22 -1
  21. package/dist/internal-model.js.map +1 -1
  22. package/dist/model-trinkets.d.ts +21 -0
  23. package/dist/model-trinkets.js +3 -0
  24. package/dist/model-trinkets.js.map +1 -0
  25. package/dist/public-api.d.ts +1 -0
  26. package/dist/public-api.js +1 -0
  27. package/dist/public-api.js.map +1 -1
  28. package/dist/solo/aggregate-hourly/config.d.ts +2 -0
  29. package/dist/solo/aggregate-hourly/config.js +3 -1
  30. package/dist/solo/aggregate-hourly/config.js.map +1 -1
  31. package/dist/solo/aggregate-hourly/heroes/s3-saver.js +1 -0
  32. package/dist/solo/aggregate-hourly/heroes/s3-saver.js.map +1 -1
  33. package/dist/solo/aggregate-hourly/heroes/stats-merger.js +3 -1
  34. package/dist/solo/aggregate-hourly/heroes/stats-merger.js.map +1 -1
  35. package/dist/solo/aggregate-hourly/s3-loader.d.ts +3 -2
  36. package/dist/solo/aggregate-hourly/s3-loader.js +1 -1
  37. package/dist/solo/aggregate-hourly/s3-loader.js.map +1 -1
  38. package/dist/solo/aggregate-hourly/trinkets/_build-aggregated-stats.d.ts +7 -0
  39. package/dist/solo/aggregate-hourly/trinkets/_build-aggregated-stats.js +62 -0
  40. package/dist/solo/aggregate-hourly/trinkets/_build-aggregated-stats.js.map +1 -0
  41. package/dist/solo/aggregate-hourly/trinkets/s3-saver.d.ts +3 -0
  42. package/dist/solo/aggregate-hourly/trinkets/s3-saver.js +18 -0
  43. package/dist/solo/aggregate-hourly/trinkets/s3-saver.js.map +1 -0
  44. package/dist/solo/aggregate-hourly/trinkets/stats-builder.d.ts +4 -0
  45. package/dist/solo/aggregate-hourly/trinkets/stats-builder.js +45 -0
  46. package/dist/solo/aggregate-hourly/trinkets/stats-builder.js.map +1 -0
  47. package/dist/solo/hourly/_build-battlegrounds-hero-stats.d.ts +1 -0
  48. package/dist/solo/hourly/_build-battlegrounds-hero-stats.js +33 -2
  49. package/dist/solo/hourly/_build-battlegrounds-hero-stats.js.map +1 -1
  50. package/dist/solo/hourly/builders.js +2 -2
  51. package/dist/solo/hourly/builders.js.map +1 -1
  52. package/dist/solo/hourly/hero-stats-buikder.js +4 -4
  53. package/dist/solo/hourly/hero-stats-buikder.js.map +1 -1
  54. package/dist/solo/hourly/quests/reward-stats-builder.js +3 -3
  55. package/dist/solo/hourly/quests/reward-stats-builder.js.map +1 -1
  56. package/dist/solo/hourly/rows.js +1 -1
  57. package/dist/solo/hourly/rows.js.map +1 -1
  58. package/dist/solo/hourly/trinkets/trinket-stats-builder.d.ts +3 -0
  59. package/dist/solo/hourly/trinkets/trinket-stats-builder.js +49 -0
  60. package/dist/solo/hourly/trinkets/trinket-stats-builder.js.map +1 -0
  61. package/dist/solo/hourly/trinkets/trinket-stats.d.ts +4 -0
  62. package/dist/solo/hourly/trinkets/trinket-stats.js +27 -0
  63. package/dist/solo/hourly/trinkets/trinket-stats.js.map +1 -0
  64. package/dist/solo/hourly/utils.js +1 -1
  65. package/dist/solo/hourly/utils.js.map +1 -1
  66. package/package.json +2 -2
@@ -1,2 +1,3 @@
1
1
  export declare const STAT_KEY_HERO: string;
2
+ export declare const STAT_KEY_PERCENTILE: string;
2
3
  export declare const STAT_KEY_QUEST: string;
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.STAT_KEY_QUEST = exports.STAT_KEY_HERO = void 0;
3
+ 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
+ exports.STAT_KEY_PERCENTILE = `${_build_battlegrounds_hero_stats_1.STATS_KEY_PREFIX}/hero-stats/%timePeriod%/mmr-percentiles.gz.json`;
6
7
  exports.STAT_KEY_QUEST = `${_build_battlegrounds_hero_stats_1.STATS_KEY_PREFIX}/quest-stats/mmr-%mmrPercentile%/%timePeriod%/overview-from-hourly.gz.json`;
7
8
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/duos/aggregate-hourly/config.ts"],"names":[],"mappings":";;;AAAA,+FAA6E;AAEhE,QAAA,aAAa,GAAG,GAAG,kDAAgB,2EAA2E,CAAC;AAC/G,QAAA,cAAc,GAAG,GAAG,kDAAgB,4EAA4E,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_QUEST = `${STATS_KEY_PREFIX}/quest-stats/mmr-%mmrPercentile%/%timePeriod%/overview-from-hourly.gz.json`;\r\n"]}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/duos/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","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\n"]}
@@ -17,6 +17,7 @@ const persistData = async (mergedStats, mmrPercentiles, lastUpdate, timePeriod,
17
17
  mmrPercentiles: mmrPercentiles,
18
18
  };
19
19
  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_HERO.replace('%mmrPercentile%', `${mmrPercentile}`).replace('%timePeriod%', timePeriod), 'application/json', 'gzip');
20
+ await _build_aggregated_stats_1.s3.writeFile((0, zlib_1.gzipSync)(JSON.stringify(mmrPercentiles)), _build_battlegrounds_hero_stats_1.STATS_BUCKET, config_1.STAT_KEY_PERCENTILE.replace('%timePeriod%', timePeriod), 'application/json', 'gzip');
20
21
  };
21
22
  exports.persistData = persistData;
22
23
  //# sourceMappingURL=s3-saver.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"s3-saver.js","sourceRoot":"","sources":["../../../../src/duos/aggregate-hourly/heroes/s3-saver.ts"],"names":[],"mappings":";;;AAAA,+BAAgC;AAEhC,kGAA4E;AAC5E,sCAA0C;AAC1C,uEAA+C;AAExC,MAAM,WAAW,GAAG,KAAK,EAC/B,WAAyC,EACzC,cAAwC,EACxC,UAAgB,EAChB,UAAsB,EACtB,aAAkC,EACjC,EAAE;IACH,MAAM,IAAI,GAAmB;QAC5B,SAAS,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACrC,GAAG,IAAI;YACP,aAAa,EAAE,aAAa;YAC5B,UAAU,EAAE,UAAU;SACtB,CAAC,CAAC;QACH,cAAc,EAAE,UAAU;QAC1B,UAAU,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC3E,cAAc,EAAE,cAAc;KAC9B,CAAC;IAEF,MAAM,4BAAE,CAAC,SAAS,CACjB,IAAA,eAAQ,EAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,EAC9B,8CAAY,EACZ,sBAAa,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,cAAc,EAAE,UAAU,CAAC,EAChG,kBAAkB,EAClB,MAAM,CACN,CAAC;AACH,CAAC,CAAC;AAzBW,QAAA,WAAW,eAyBtB","sourcesContent":["import { gzipSync } from 'zlib';\r\nimport { BgsGlobalHeroStat, BgsHeroStatsV2, MmrPercentile, MmrPercentileFilter, TimePeriod } from '../../../models';\r\nimport { STATS_BUCKET } from '../../hourly/_build-battlegrounds-hero-stats';\r\nimport { STAT_KEY_HERO } from '../config';\r\nimport { s3 } from './_build-aggregated-stats';\r\n\r\nexport const persistData = async (\r\n\tmergedStats: readonly BgsGlobalHeroStat[],\r\n\tmmrPercentiles: readonly MmrPercentile[],\r\n\tlastUpdate: Date,\r\n\ttimePeriod: TimePeriod,\r\n\tmmrPercentile: MmrPercentileFilter,\r\n) => {\r\n\tconst stat: BgsHeroStatsV2 = {\r\n\t\theroStats: mergedStats.map((stat) => ({\r\n\t\t\t...stat,\r\n\t\t\tmmrPercentile: mmrPercentile,\r\n\t\t\ttimePeriod: timePeriod,\r\n\t\t})),\r\n\t\tlastUpdateDate: lastUpdate,\r\n\t\tdataPoints: mergedStats.map((s) => s.dataPoints).reduce((a, b) => a + b, 0),\r\n\t\tmmrPercentiles: mmrPercentiles,\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_HERO.replace('%mmrPercentile%', `${mmrPercentile}`).replace('%timePeriod%', timePeriod),\r\n\t\t'application/json',\r\n\t\t'gzip',\r\n\t);\r\n};\r\n"]}
1
+ {"version":3,"file":"s3-saver.js","sourceRoot":"","sources":["../../../../src/duos/aggregate-hourly/heroes/s3-saver.ts"],"names":[],"mappings":";;;AAAA,+BAAgC;AAEhC,kGAA4E;AAC5E,sCAA+D;AAC/D,uEAA+C;AAExC,MAAM,WAAW,GAAG,KAAK,EAC/B,WAAyC,EACzC,cAAwC,EACxC,UAAgB,EAChB,UAAsB,EACtB,aAAkC,EACjC,EAAE;IACH,MAAM,IAAI,GAAmB;QAC5B,SAAS,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACrC,GAAG,IAAI;YACP,aAAa,EAAE,aAAa;YAC5B,UAAU,EAAE,UAAU;SACtB,CAAC,CAAC;QACH,cAAc,EAAE,UAAU;QAC1B,UAAU,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC3E,cAAc,EAAE,cAAc;KAC9B,CAAC;IAEF,MAAM,4BAAE,CAAC,SAAS,CACjB,IAAA,eAAQ,EAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,EAC9B,8CAAY,EACZ,sBAAa,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,cAAc,EAAE,UAAU,CAAC,EAChG,kBAAkB,EAClB,MAAM,CACN,CAAC;IACF,MAAM,4BAAE,CAAC,SAAS,CACjB,IAAA,eAAQ,EAAC,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,EACxC,8CAAY,EACZ,4BAAmB,CAAC,OAAO,CAAC,cAAc,EAAE,UAAU,CAAC,EACvD,kBAAkB,EAClB,MAAM,CACN,CAAC;AACH,CAAC,CAAC;AAhCW,QAAA,WAAW,eAgCtB","sourcesContent":["import { gzipSync } from 'zlib';\r\nimport { BgsGlobalHeroStat, BgsHeroStatsV2, MmrPercentile, MmrPercentileFilter, TimePeriod } from '../../../models';\r\nimport { STATS_BUCKET } from '../../hourly/_build-battlegrounds-hero-stats';\r\nimport { STAT_KEY_HERO, STAT_KEY_PERCENTILE } from '../config';\r\nimport { s3 } from './_build-aggregated-stats';\r\n\r\nexport const persistData = async (\r\n\tmergedStats: readonly BgsGlobalHeroStat[],\r\n\tmmrPercentiles: readonly MmrPercentile[],\r\n\tlastUpdate: Date,\r\n\ttimePeriod: TimePeriod,\r\n\tmmrPercentile: MmrPercentileFilter,\r\n) => {\r\n\tconst stat: BgsHeroStatsV2 = {\r\n\t\theroStats: mergedStats.map((stat) => ({\r\n\t\t\t...stat,\r\n\t\t\tmmrPercentile: mmrPercentile,\r\n\t\t\ttimePeriod: timePeriod,\r\n\t\t})),\r\n\t\tlastUpdateDate: lastUpdate,\r\n\t\tdataPoints: mergedStats.map((s) => s.dataPoints).reduce((a, b) => a + b, 0),\r\n\t\tmmrPercentiles: mmrPercentiles,\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_HERO.replace('%mmrPercentile%', `${mmrPercentile}`).replace('%timePeriod%', timePeriod),\r\n\t\t'application/json',\r\n\t\t'gzip',\r\n\t);\r\n\tawait s3.writeFile(\r\n\t\tgzipSync(JSON.stringify(mmrPercentiles)),\r\n\t\tSTATS_BUCKET,\r\n\t\tSTAT_KEY_PERCENTILE.replace('%timePeriod%', timePeriod),\r\n\t\t'application/json',\r\n\t\t'gzip',\r\n\t);\r\n};\r\n"]}
@@ -10,7 +10,9 @@ const mergeStats = (hourlyData, mmrPercentile, allCards) => {
10
10
  .filter((stat) => stat.heroCardId !== "TB_BaconShop_HERO_PH");
11
11
  const groupedByHero = (0, aws_lambda_utils_1.groupByFunction)((stat) => stat.heroCardId)(allStats);
12
12
  const result = Object.values(groupedByHero).map((stats) => mergeStatsForSingleHero(stats, allCards));
13
- return result;
13
+ const maxDataPoints = Math.max(...result.map((r) => r.dataPoints));
14
+ const filtered = result.filter((r) => r.dataPoints > maxDataPoints / 50);
15
+ return filtered;
14
16
  };
15
17
  exports.mergeStats = mergeStats;
16
18
  const mergeStatsForSingleHero = (stats, allCards) => {
@@ -1 +1 @@
1
- {"version":3,"file":"stats-merger.js","sourceRoot":"","sources":["../../../../src/duos/aggregate-hourly/heroes/stats-merger.ts"],"names":[],"mappings":"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","sourcesContent":["import { groupByFunction } from '@firestone-hs/aws-lambda-utils';\r\nimport { AllCardsService, CardIds } from '@firestone-hs/reference-data';\r\nimport { round } from '../../../common/util-functions';\r\nimport { BgsGlobalHeroStat, BgsHeroStatsV2, BgsHeroTribeStat, MmrPercentileFilter } from '../../../models';\r\n\r\nexport const mergeStats = (\r\n\thourlyData: readonly BgsHeroStatsV2[],\r\n\tmmrPercentile: MmrPercentileFilter,\r\n\tallCards: AllCardsService,\r\n): readonly BgsGlobalHeroStat[] => {\r\n\tconst allStats: readonly BgsGlobalHeroStat[] = hourlyData\r\n\t\t.flatMap((data) => data.heroStats)\r\n\t\t.filter((stat) => stat.mmrPercentile === mmrPercentile)\r\n\t\t.filter((stat) => stat.heroCardId !== CardIds.BaconphheroHeroic);\r\n\t// console.debug('allStats', mmrPercentile, allStats.length, '/', hourlyData.length);\r\n\tconst groupedByHero: {\r\n\t\t[heroCardId: string]: readonly BgsGlobalHeroStat[];\r\n\t} = groupByFunction((stat: BgsGlobalHeroStat) => stat.heroCardId)(allStats);\r\n\tconst result: readonly BgsGlobalHeroStat[] = Object.values(groupedByHero).map((stats) =>\r\n\t\tmergeStatsForSingleHero(stats, allCards),\r\n\t);\r\n\treturn result;\r\n};\r\n\r\nconst mergeStatsForSingleHero = (stats: readonly BgsGlobalHeroStat[], allCards: AllCardsService): BgsGlobalHeroStat => {\r\n\tconst ref = stats[0];\r\n\tconst debug = ref.heroCardId === 'BG21_HERO_010';\r\n\r\n\tconst totalWeightedAverage = stats.map((s) => s.averagePosition * s.dataPoints).reduce((a, b) => a + b, 0);\r\n\tconst totalDataPoints = stats.map((s) => s.dataPoints).reduce((a, b) => a + b, 0);\r\n\tconst averagePosition = totalWeightedAverage / totalDataPoints;\r\n\r\n\tconst totalWeightedVariance = stats\r\n\t\t.map((s) => s.standardDeviation * s.standardDeviation * s.dataPoints)\r\n\t\t.reduce((a, b) => a + b, 0);\r\n\tconst overallVariance = totalWeightedVariance / totalDataPoints;\r\n\tconst standardDeviation = Math.sqrt(overallVariance);\r\n\tconst standardDeviationOfTheMean = standardDeviation / Math.sqrt(totalDataPoints);\r\n\r\n\tconst result: BgsGlobalHeroStat = {\r\n\t\theroCardId: ref.heroCardId,\r\n\t\tdataPoints: stats.map((stat) => stat.dataPoints).reduce((a, b) => a + b, 0),\r\n\t\taveragePosition: round(averagePosition),\r\n\t\tstandardDeviation: round(standardDeviation),\r\n\t\tstandardDeviationOfTheMean: round(standardDeviationOfTheMean),\r\n\t\tconservativePositionEstimate: round(averagePosition + 3 * standardDeviationOfTheMean),\r\n\t\tplacementDistribution: mergePlacementDistributions(stats),\r\n\t\twarbandStats: mergeWarbandStats(stats),\r\n\t\tcombatWinrate: mergeCombatWinrate(stats, debug),\r\n\t\ttribeStats: mergeTribeStats(stats, averagePosition).filter(\r\n\t\t\t(s) => s.dataPointsOnMissingTribe > s.dataPoints / 20,\r\n\t\t),\r\n\t\tanomalyStats: [], // mergeAnomalyStats(stats),\r\n\t};\r\n\treturn result;\r\n};\r\n\r\nconst mergeTribeStats = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n\trefAveragePosition: number,\r\n): readonly BgsHeroTribeStat[] => {\r\n\tconst allTribeStats = stats.flatMap((stat) => stat.tribeStats);\r\n\tconst uniqueTribes = new Set(allTribeStats.map((tribe) => tribe.tribe));\r\n\tconst result: BgsHeroTribeStat[] = [...uniqueTribes].map((tribe) => {\r\n\t\tconst tribeStats = allTribeStats.filter((stat) => stat.tribe === tribe);\r\n\t\tconst totalStatDataPoints = tribeStats.map((stat) => stat.dataPoints).reduce((a, b) => a + b, 0);\r\n\t\tconst averagePosition =\r\n\t\t\ttribeStats.map((stat) => stat.averagePosition * stat.dataPoints).reduce((a, b) => a + b, 0) /\r\n\t\t\ttotalStatDataPoints;\r\n\t\tconst averagePositionWithoutTribe =\r\n\t\t\ttribeStats\r\n\t\t\t\t.map((stat) => stat.averagePositionWithoutTribe * stat.dataPointsOnMissingTribe)\r\n\t\t\t\t.reduce((a, b) => a + b, 0) /\r\n\t\t\ttribeStats.map((stat) => stat.dataPointsOnMissingTribe).reduce((a, b) => a + b, 0);\r\n\t\t// const impactAveragePosition =\r\n\t\t// \ttribeStats.map((stat) => stat.impactAveragePosition * stat.dataPoints).reduce((a, b) => a + b, 0) /\r\n\t\t// \ttotalStatDataPoints;\r\n\t\t// const impactAveragePositionVsMissingTribe =\r\n\t\t// \ttribeStats\r\n\t\t// \t\t.map((stat) => stat.impactAveragePositionVsMissingTribe * stat.dataPoints)\r\n\t\t// \t\t.reduce((a, b) => a + b, 0) / totalStatDataPoints;\r\n\t\treturn {\r\n\t\t\ttribe: tribe,\r\n\t\t\tdataPoints: totalStatDataPoints,\r\n\t\t\tdataPointsOnMissingTribe: tribeStats\r\n\t\t\t\t.map((stat) => stat.dataPointsOnMissingTribe)\r\n\t\t\t\t.reduce((a, b) => a + b, 0),\r\n\t\t\taveragePosition: round(averagePosition),\r\n\t\t\taveragePositionWithoutTribe: round(averagePositionWithoutTribe),\r\n\t\t\trefAveragePosition: refAveragePosition,\r\n\t\t\timpactAveragePosition: round(averagePosition - refAveragePosition),\r\n\t\t\t// impactAveragePositionDebug: round(impactAveragePosition),\r\n\t\t\timpactAveragePositionVsMissingTribe: round(averagePositionWithoutTribe - refAveragePosition),\r\n\t\t};\r\n\t});\r\n\treturn result;\r\n};\r\n\r\nconst mergePlacementDistributions = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n): readonly { rank: number; percentage: number }[] => {\r\n\tconst rawMerge = mergePlacementDistributionsRaw(stats);\r\n\tconst result: { rank: number; percentage: number }[] = [];\r\n\tconst totalDataPoints = rawMerge.map((s) => s.totalMatches).reduce((a, b) => a + b, 0);\r\n\tfor (let i = 1; i <= 8; i++) {\r\n\t\tconst total: number = rawMerge.find((d) => d.rank === i)?.totalMatches ?? 0;\r\n\t\tresult.push({ rank: i, percentage: round((100 * total) / totalDataPoints) });\r\n\t}\r\n\treturn result;\r\n};\r\n\r\nconst mergePlacementDistributionsRaw = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n): readonly { rank: number; totalMatches: number }[] => {\r\n\tconst rawStats = stats.map((stat) => stat.placementDistributionRaw);\r\n\t// console.debug(\r\n\t// \t'will merge placement distributions',\r\n\t// \tstats[0].heroCardId,\r\n\t// \tstats[0],\r\n\t// \trawStats.length,\r\n\t// \trawStats.filter((s) => !!s).length,\r\n\t// );\r\n\t// Legacy, can be removed after 2024-01-31\r\n\t// const pStats = stats\r\n\t// \t.filter((stat) => stat.placementDistribution?.length)\r\n\t// \t.map((stat) =>\r\n\t// \t\tstat.placementDistribution.map((s) => ({\r\n\t// \t\t\trank: s.rank,\r\n\t// \t\t\ttotalMatches: s.percentage * stat.dataPoints,\r\n\t// \t\t})),\r\n\t// \t);\r\n\t// const allRawStats = [...rawStats, ...pStats].filter((s) => !!s);\r\n\tconst result: { rank: number; totalMatches: number }[] = [];\r\n\tfor (let i = 1; i <= 8; i++) {\r\n\t\tconst total: number = rawStats\r\n\t\t\t.map((d) => d?.find((info) => info.rank === i)?.totalMatches ?? 0)\r\n\t\t\t.reduce((a, b) => a + b, 0);\r\n\t\tresult.push({ rank: i, totalMatches: total });\r\n\t}\r\n\treturn result;\r\n};\r\n\r\nconst mergeWarbandStats = (stats: readonly BgsGlobalHeroStat[]): readonly { turn: number; averageStats: number }[] => {\r\n\tconst { rawMerge, maxTurn } = mergeWarbandStatsRaw(stats);\r\n\tconst result: { turn: number; averageStats: number }[] = [];\r\n\tfor (let i = 1; i <= maxTurn; i++) {\r\n\t\tconst statsForTurn = rawMerge.find((d) => d.turn === i);\r\n\t\tresult.push({ turn: i, averageStats: round(statsForTurn.totalStats / statsForTurn.dataPoints) });\r\n\t}\r\n\treturn result;\r\n};\r\n\r\nconst mergeWarbandStatsRaw = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n): { rawMerge: readonly { turn: number; dataPoints: number; totalStats: number }[]; maxTurn: number } => {\r\n\tconst rawStats = stats.map((stat) => stat.warbandStatsRaw).filter((s) => !!s?.length);\r\n\tconst result: { turn: number; dataPoints: number; totalStats: number }[] = [];\r\n\tconst maxTurn = Math.min(20, Math.max(...rawStats.map((stat) => getMaxTurn(stat))));\r\n\tfor (let i = 1; i <= maxTurn; i++) {\r\n\t\tconst rawStatsForTurn = rawStats.map((stat) => stat.find((info) => info.turn === i));\r\n\t\tconst totalStats: number = rawStatsForTurn.map((d) => d?.totalStats ?? 0).reduce((a, b) => a + b, 0);\r\n\t\tconst totalDataPoints = rawStatsForTurn.map((d) => d?.dataPoints ?? 0).reduce((a, b) => a + b, 0);\r\n\t\tresult.push({ turn: i, totalStats: totalStats, dataPoints: totalDataPoints });\r\n\t}\r\n\treturn { rawMerge: result, maxTurn: maxTurn };\r\n};\r\n\r\nconst mergeCombatWinrate = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n\tdebug = false,\r\n): readonly { turn: number; winrate: number }[] => {\r\n\tconst { rawMerge, maxTurn } = mergeCombatWinrateRaw(stats, debug);\r\n\tconst result: { turn: number; winrate: number }[] = [];\r\n\tfor (let i = 1; i <= maxTurn; i++) {\r\n\t\tconst statForTurn = rawMerge.find((d) => d.turn === i);\r\n\t\tresult.push({ turn: i, winrate: round(statForTurn.totalWinrate / statForTurn.dataPoints) });\r\n\t}\r\n\treturn result;\r\n};\r\n\r\nconst mergeCombatWinrateRaw = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n\tdebug = false,\r\n): { rawMerge: readonly { turn: number; dataPoints: number; totalWinrate: number }[]; maxTurn: number } => {\r\n\tconst rawStats = stats.map((stat) => stat.combatWinrateRaw).filter((stat) => !!stat?.length);\r\n\t// debug && console.log('rawStats', rawStats?.length, rawStats);\r\n\tconst result: { turn: number; dataPoints: number; totalWinrate: number }[] = [];\r\n\tconst maxTurn = Math.min(20, Math.max(...rawStats.map((stat) => getMaxTurn(stat))));\r\n\t// debug && console.log('maxTurn', maxTurn);\r\n\tfor (let i = 0; i <= maxTurn; i++) {\r\n\t\tconst rawStatsForTurn = rawStats.map((stat) => stat.find((info) => info.turn === i));\r\n\t\tconst totalWinrate: number = rawStatsForTurn.map((d) => d?.totalWinrate ?? 0).reduce((a, b) => a + b, 0);\r\n\t\tconst totalDataPoints = rawStatsForTurn.map((d) => d?.dataPoints ?? 0).reduce((a, b) => a + b, 0);\r\n\t\tresult.push({ turn: i, totalWinrate: totalWinrate, dataPoints: totalDataPoints });\r\n\t}\r\n\t// debug && console.log('result', result);\r\n\treturn { rawMerge: result, maxTurn: maxTurn };\r\n};\r\n\r\nconst getMaxTurn = (rawStats: readonly { turn: number }[]): number => {\r\n\tif (!rawStats?.length) {\r\n\t\treturn 0;\r\n\t}\r\n\treturn Math.max(...rawStats.map((stat) => stat.turn));\r\n};\r\n"]}
1
+ {"version":3,"file":"stats-merger.js","sourceRoot":"","sources":["../../../../src/duos/aggregate-hourly/heroes/stats-merger.ts"],"names":[],"mappings":"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","sourcesContent":["import { groupByFunction } from '@firestone-hs/aws-lambda-utils';\r\nimport { AllCardsService, CardIds } from '@firestone-hs/reference-data';\r\nimport { round } from '../../../common/util-functions';\r\nimport { BgsGlobalHeroStat, BgsHeroStatsV2, BgsHeroTribeStat, MmrPercentileFilter } from '../../../models';\r\n\r\nexport const mergeStats = (\r\n\thourlyData: readonly BgsHeroStatsV2[],\r\n\tmmrPercentile: MmrPercentileFilter,\r\n\tallCards: AllCardsService,\r\n): readonly BgsGlobalHeroStat[] => {\r\n\tconst allStats: readonly BgsGlobalHeroStat[] = hourlyData\r\n\t\t.flatMap((data) => data.heroStats)\r\n\t\t.filter((stat) => stat.mmrPercentile === mmrPercentile)\r\n\t\t.filter((stat) => stat.heroCardId !== CardIds.BaconphheroHeroic);\r\n\t// console.debug('allStats', mmrPercentile, allStats.length, '/', hourlyData.length);\r\n\tconst groupedByHero: {\r\n\t\t[heroCardId: string]: readonly BgsGlobalHeroStat[];\r\n\t} = groupByFunction((stat: BgsGlobalHeroStat) => stat.heroCardId)(allStats);\r\n\tconst result: readonly BgsGlobalHeroStat[] = Object.values(groupedByHero).map((stats) =>\r\n\t\tmergeStatsForSingleHero(stats, allCards),\r\n\t);\r\n\tconst maxDataPoints = Math.max(...result.map((r) => r.dataPoints));\r\n\tconst filtered = result.filter((r) => r.dataPoints > maxDataPoints / 50);\r\n\treturn filtered;\r\n};\r\n\r\nconst mergeStatsForSingleHero = (stats: readonly BgsGlobalHeroStat[], allCards: AllCardsService): BgsGlobalHeroStat => {\r\n\tconst ref = stats[0];\r\n\tconst debug = ref.heroCardId === 'BG21_HERO_010';\r\n\r\n\tconst totalWeightedAverage = stats.map((s) => s.averagePosition * s.dataPoints).reduce((a, b) => a + b, 0);\r\n\tconst totalDataPoints = stats.map((s) => s.dataPoints).reduce((a, b) => a + b, 0);\r\n\tconst averagePosition = totalWeightedAverage / totalDataPoints;\r\n\r\n\tconst totalWeightedVariance = stats\r\n\t\t.map((s) => s.standardDeviation * s.standardDeviation * s.dataPoints)\r\n\t\t.reduce((a, b) => a + b, 0);\r\n\tconst overallVariance = totalWeightedVariance / totalDataPoints;\r\n\tconst standardDeviation = Math.sqrt(overallVariance);\r\n\tconst standardDeviationOfTheMean = standardDeviation / Math.sqrt(totalDataPoints);\r\n\r\n\tconst result: BgsGlobalHeroStat = {\r\n\t\theroCardId: ref.heroCardId,\r\n\t\tdataPoints: stats.map((stat) => stat.dataPoints).reduce((a, b) => a + b, 0),\r\n\t\taveragePosition: round(averagePosition),\r\n\t\tstandardDeviation: round(standardDeviation),\r\n\t\tstandardDeviationOfTheMean: round(standardDeviationOfTheMean),\r\n\t\tconservativePositionEstimate: round(averagePosition + 3 * standardDeviationOfTheMean),\r\n\t\tplacementDistribution: mergePlacementDistributions(stats),\r\n\t\twarbandStats: mergeWarbandStats(stats),\r\n\t\tcombatWinrate: mergeCombatWinrate(stats, debug),\r\n\t\ttribeStats: mergeTribeStats(stats, averagePosition).filter(\r\n\t\t\t(s) => s.dataPointsOnMissingTribe > s.dataPoints / 20,\r\n\t\t),\r\n\t\tanomalyStats: [], // mergeAnomalyStats(stats),\r\n\t};\r\n\treturn result;\r\n};\r\n\r\nconst mergeTribeStats = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n\trefAveragePosition: number,\r\n): readonly BgsHeroTribeStat[] => {\r\n\tconst allTribeStats = stats.flatMap((stat) => stat.tribeStats);\r\n\tconst uniqueTribes = new Set(allTribeStats.map((tribe) => tribe.tribe));\r\n\tconst result: BgsHeroTribeStat[] = [...uniqueTribes].map((tribe) => {\r\n\t\tconst tribeStats = allTribeStats.filter((stat) => stat.tribe === tribe);\r\n\t\tconst totalStatDataPoints = tribeStats.map((stat) => stat.dataPoints).reduce((a, b) => a + b, 0);\r\n\t\tconst averagePosition =\r\n\t\t\ttribeStats.map((stat) => stat.averagePosition * stat.dataPoints).reduce((a, b) => a + b, 0) /\r\n\t\t\ttotalStatDataPoints;\r\n\t\tconst averagePositionWithoutTribe =\r\n\t\t\ttribeStats\r\n\t\t\t\t.map((stat) => stat.averagePositionWithoutTribe * stat.dataPointsOnMissingTribe)\r\n\t\t\t\t.reduce((a, b) => a + b, 0) /\r\n\t\t\ttribeStats.map((stat) => stat.dataPointsOnMissingTribe).reduce((a, b) => a + b, 0);\r\n\t\t// const impactAveragePosition =\r\n\t\t// \ttribeStats.map((stat) => stat.impactAveragePosition * stat.dataPoints).reduce((a, b) => a + b, 0) /\r\n\t\t// \ttotalStatDataPoints;\r\n\t\t// const impactAveragePositionVsMissingTribe =\r\n\t\t// \ttribeStats\r\n\t\t// \t\t.map((stat) => stat.impactAveragePositionVsMissingTribe * stat.dataPoints)\r\n\t\t// \t\t.reduce((a, b) => a + b, 0) / totalStatDataPoints;\r\n\t\treturn {\r\n\t\t\ttribe: tribe,\r\n\t\t\tdataPoints: totalStatDataPoints,\r\n\t\t\tdataPointsOnMissingTribe: tribeStats\r\n\t\t\t\t.map((stat) => stat.dataPointsOnMissingTribe)\r\n\t\t\t\t.reduce((a, b) => a + b, 0),\r\n\t\t\taveragePosition: round(averagePosition),\r\n\t\t\taveragePositionWithoutTribe: round(averagePositionWithoutTribe),\r\n\t\t\trefAveragePosition: refAveragePosition,\r\n\t\t\timpactAveragePosition: round(averagePosition - refAveragePosition),\r\n\t\t\t// impactAveragePositionDebug: round(impactAveragePosition),\r\n\t\t\timpactAveragePositionVsMissingTribe: round(averagePositionWithoutTribe - refAveragePosition),\r\n\t\t};\r\n\t});\r\n\treturn result;\r\n};\r\n\r\nconst mergePlacementDistributions = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n): readonly { rank: number; percentage: number }[] => {\r\n\tconst rawMerge = mergePlacementDistributionsRaw(stats);\r\n\tconst result: { rank: number; percentage: number }[] = [];\r\n\tconst totalDataPoints = rawMerge.map((s) => s.totalMatches).reduce((a, b) => a + b, 0);\r\n\tfor (let i = 1; i <= 8; i++) {\r\n\t\tconst total: number = rawMerge.find((d) => d.rank === i)?.totalMatches ?? 0;\r\n\t\tresult.push({ rank: i, percentage: round((100 * total) / totalDataPoints) });\r\n\t}\r\n\treturn result;\r\n};\r\n\r\nconst mergePlacementDistributionsRaw = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n): readonly { rank: number; totalMatches: number }[] => {\r\n\tconst rawStats = stats.map((stat) => stat.placementDistributionRaw);\r\n\t// console.debug(\r\n\t// \t'will merge placement distributions',\r\n\t// \tstats[0].heroCardId,\r\n\t// \tstats[0],\r\n\t// \trawStats.length,\r\n\t// \trawStats.filter((s) => !!s).length,\r\n\t// );\r\n\t// Legacy, can be removed after 2024-01-31\r\n\t// const pStats = stats\r\n\t// \t.filter((stat) => stat.placementDistribution?.length)\r\n\t// \t.map((stat) =>\r\n\t// \t\tstat.placementDistribution.map((s) => ({\r\n\t// \t\t\trank: s.rank,\r\n\t// \t\t\ttotalMatches: s.percentage * stat.dataPoints,\r\n\t// \t\t})),\r\n\t// \t);\r\n\t// const allRawStats = [...rawStats, ...pStats].filter((s) => !!s);\r\n\tconst result: { rank: number; totalMatches: number }[] = [];\r\n\tfor (let i = 1; i <= 8; i++) {\r\n\t\tconst total: number = rawStats\r\n\t\t\t.map((d) => d?.find((info) => info.rank === i)?.totalMatches ?? 0)\r\n\t\t\t.reduce((a, b) => a + b, 0);\r\n\t\tresult.push({ rank: i, totalMatches: total });\r\n\t}\r\n\treturn result;\r\n};\r\n\r\nconst mergeWarbandStats = (stats: readonly BgsGlobalHeroStat[]): readonly { turn: number; averageStats: number }[] => {\r\n\tconst { rawMerge, maxTurn } = mergeWarbandStatsRaw(stats);\r\n\tconst result: { turn: number; averageStats: number }[] = [];\r\n\tfor (let i = 1; i <= maxTurn; i++) {\r\n\t\tconst statsForTurn = rawMerge.find((d) => d.turn === i);\r\n\t\tresult.push({ turn: i, averageStats: round(statsForTurn.totalStats / statsForTurn.dataPoints) });\r\n\t}\r\n\treturn result;\r\n};\r\n\r\nconst mergeWarbandStatsRaw = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n): { rawMerge: readonly { turn: number; dataPoints: number; totalStats: number }[]; maxTurn: number } => {\r\n\tconst rawStats = stats.map((stat) => stat.warbandStatsRaw).filter((s) => !!s?.length);\r\n\tconst result: { turn: number; dataPoints: number; totalStats: number }[] = [];\r\n\tconst maxTurn = Math.min(20, Math.max(...rawStats.map((stat) => getMaxTurn(stat))));\r\n\tfor (let i = 1; i <= maxTurn; i++) {\r\n\t\tconst rawStatsForTurn = rawStats.map((stat) => stat.find((info) => info.turn === i));\r\n\t\tconst totalStats: number = rawStatsForTurn.map((d) => d?.totalStats ?? 0).reduce((a, b) => a + b, 0);\r\n\t\tconst totalDataPoints = rawStatsForTurn.map((d) => d?.dataPoints ?? 0).reduce((a, b) => a + b, 0);\r\n\t\tresult.push({ turn: i, totalStats: totalStats, dataPoints: totalDataPoints });\r\n\t}\r\n\treturn { rawMerge: result, maxTurn: maxTurn };\r\n};\r\n\r\nconst mergeCombatWinrate = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n\tdebug = false,\r\n): readonly { turn: number; winrate: number }[] => {\r\n\tconst { rawMerge, maxTurn } = mergeCombatWinrateRaw(stats, debug);\r\n\tconst result: { turn: number; winrate: number }[] = [];\r\n\tfor (let i = 1; i <= maxTurn; i++) {\r\n\t\tconst statForTurn = rawMerge.find((d) => d.turn === i);\r\n\t\tresult.push({ turn: i, winrate: round(statForTurn.totalWinrate / statForTurn.dataPoints) });\r\n\t}\r\n\treturn result;\r\n};\r\n\r\nconst mergeCombatWinrateRaw = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n\tdebug = false,\r\n): { rawMerge: readonly { turn: number; dataPoints: number; totalWinrate: number }[]; maxTurn: number } => {\r\n\tconst rawStats = stats.map((stat) => stat.combatWinrateRaw).filter((stat) => !!stat?.length);\r\n\t// debug && console.log('rawStats', rawStats?.length, rawStats);\r\n\tconst result: { turn: number; dataPoints: number; totalWinrate: number }[] = [];\r\n\tconst maxTurn = Math.min(20, Math.max(...rawStats.map((stat) => getMaxTurn(stat))));\r\n\t// debug && console.log('maxTurn', maxTurn);\r\n\tfor (let i = 0; i <= maxTurn; i++) {\r\n\t\tconst rawStatsForTurn = rawStats.map((stat) => stat.find((info) => info.turn === i));\r\n\t\tconst totalWinrate: number = rawStatsForTurn.map((d) => d?.totalWinrate ?? 0).reduce((a, b) => a + b, 0);\r\n\t\tconst totalDataPoints = rawStatsForTurn.map((d) => d?.dataPoints ?? 0).reduce((a, b) => a + b, 0);\r\n\t\tresult.push({ turn: i, totalWinrate: totalWinrate, dataPoints: totalDataPoints });\r\n\t}\r\n\t// debug && console.log('result', result);\r\n\treturn { rawMerge: result, maxTurn: maxTurn };\r\n};\r\n\r\nconst getMaxTurn = (rawStats: readonly { turn: number }[]): number => {\r\n\tif (!rawStats?.length) {\r\n\t\treturn 0;\r\n\t}\r\n\treturn Math.max(...rawStats.map((stat) => stat.turn));\r\n};\r\n"]}
@@ -6,9 +6,7 @@ export declare const STATS_KEY_PREFIX = "api/bgs/duo";
6
6
  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
+ export declare const HOURLY_KEY_TRINKET: string;
9
10
  declare const _default: (event: any, context: Context) => Promise<any>;
10
11
  export default _default;
11
- export declare const handleNewStats: (event: any, context: Context) => Promise<{
12
- statusCode: number;
13
- body: any;
14
- }>;
12
+ 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_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_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 trinket_stats_1 = require("../../solo/hourly/trinkets/trinket-stats");
10
11
  const hero_stats_1 = require("./hero-stats");
11
12
  const rows_1 = require("./rows");
12
13
  exports.s3 = new aws_lambda_utils_1.S3();
@@ -18,31 +19,102 @@ exports.STATS_KEY_PREFIX = `api/bgs/duo`;
18
19
  exports.WORKING_ROWS_FILE = `${exports.STATS_KEY_PREFIX}/working/working-rows-%time%.json`;
19
20
  exports.HOURLY_KEY_HERO = `${exports.STATS_KEY_PREFIX}/hero-stats/mmr-%mmrPercentile%/hourly/%startDate%.gz.json`;
20
21
  exports.HOURLY_KEY_QUEST = `${exports.STATS_KEY_PREFIX}/quest-stats/mmr-%mmrPercentile%/hourly/%startDate%.gz.json`;
22
+ exports.HOURLY_KEY_TRINKET = `${exports.STATS_KEY_PREFIX}/trinket-stats/mmr-%mmrPercentile%/hourly/%startDate%.gz.json`;
21
23
  exports.default = async (event, context) => {
22
24
  await (0, exports.handleNewStats)(event, context);
23
25
  };
24
26
  const handleNewStats = async (event, context) => {
25
27
  const cleanup = (0, aws_lambda_utils_1.logBeforeTimeout)(context);
26
28
  await allCards.initializeCardsDb();
29
+ if (event.catchUp) {
30
+ await dispatchCatchUpEvents(context, +event.catchUp);
31
+ cleanup();
32
+ return;
33
+ }
34
+ if (!event.statsV2 && !event.questsV2 && !event.trinkets) {
35
+ await dispatchMainEvents(context, event);
36
+ cleanup();
37
+ return;
38
+ }
27
39
  if (event.statsV2) {
28
40
  const lastHourRows = await (0, rows_1.readRowsFromS3)(event.startDate);
29
41
  await (0, hero_stats_1.buildHeroStats)(event.startDate, event.mmr, lastHourRows, allCards);
30
42
  }
31
- else {
32
- const startDate = new Date();
33
- startDate.setMinutes(0);
34
- startDate.setSeconds(0);
35
- startDate.setMilliseconds(0);
36
- startDate.setHours(startDate.getHours() - 1);
37
- const endDate = new Date(startDate);
38
- endDate.setHours(endDate.getHours() + 1);
39
- await (0, rows_1.saveRowsOnS3)(startDate, endDate, allCards);
40
- await dispatchStatsV2Lambda(context, startDate);
43
+ else if (event.trinkets) {
44
+ const lastHourRows = await (0, rows_1.readRowsFromS3)(event.startDate);
45
+ await (0, trinket_stats_1.buildTrinketStats)(event.startDate, event.mmr, lastHourRows, allCards, exports.STATS_BUCKET, exports.HOURLY_KEY_TRINKET, exports.s3);
41
46
  }
42
47
  cleanup();
43
- return { statusCode: 200, body: null };
44
48
  };
45
49
  exports.handleNewStats = handleNewStats;
50
+ const dispatchMainEvents = async (context, event) => {
51
+ const startDate = buildProcessStartDate(event);
52
+ const endDate = new Date(startDate);
53
+ endDate.setHours(endDate.getHours() + 1);
54
+ await (0, rows_1.saveRowsOnS3)(startDate, endDate, allCards);
55
+ await dispatchStatsV2Lambda(context, startDate);
56
+ await dispatchTrinketsLambda(context, startDate);
57
+ };
58
+ const buildProcessStartDate = (event) => {
59
+ if (event === null || event === void 0 ? void 0 : event.targetDate) {
60
+ const targetDate = new Date(event.targetDate);
61
+ return targetDate;
62
+ }
63
+ const processStartDate = new Date();
64
+ processStartDate.setMinutes(0);
65
+ processStartDate.setSeconds(0);
66
+ processStartDate.setMilliseconds(0);
67
+ processStartDate.setHours(processStartDate.getHours() - 1);
68
+ return processStartDate;
69
+ };
70
+ const dispatchTrinketsLambda = async (context, startDate) => {
71
+ for (const mmr of allMmrPercentiles) {
72
+ const newEvent = {
73
+ trinkets: true,
74
+ mmr: mmr,
75
+ startDate: startDate,
76
+ };
77
+ const params = {
78
+ FunctionName: context.functionName,
79
+ InvocationType: 'Event',
80
+ LogType: 'Tail',
81
+ Payload: JSON.stringify(newEvent),
82
+ };
83
+ console.log('\tinvoking lambda', params);
84
+ const result = await lambda
85
+ .invoke({
86
+ FunctionName: context.functionName,
87
+ InvocationType: 'Event',
88
+ LogType: 'Tail',
89
+ Payload: JSON.stringify(newEvent),
90
+ })
91
+ .promise();
92
+ }
93
+ };
94
+ const dispatchQuestsV2Lambda = async (context, startDate) => {
95
+ for (const mmr of allMmrPercentiles) {
96
+ const newEvent = {
97
+ questsV2: true,
98
+ mmr: mmr,
99
+ startDate: startDate,
100
+ };
101
+ const params = {
102
+ FunctionName: context.functionName,
103
+ InvocationType: 'Event',
104
+ LogType: 'Tail',
105
+ Payload: JSON.stringify(newEvent),
106
+ };
107
+ console.log('\tinvoking lambda', params);
108
+ const result = await lambda
109
+ .invoke({
110
+ FunctionName: context.functionName,
111
+ InvocationType: 'Event',
112
+ LogType: 'Tail',
113
+ Payload: JSON.stringify(newEvent),
114
+ })
115
+ .promise();
116
+ }
117
+ };
46
118
  const dispatchStatsV2Lambda = async (context, startDate) => {
47
119
  for (const mmr of allMmrPercentiles) {
48
120
  const newEvent = {
@@ -56,6 +128,39 @@ const dispatchStatsV2Lambda = async (context, startDate) => {
56
128
  LogType: 'Tail',
57
129
  Payload: JSON.stringify(newEvent),
58
130
  };
131
+ console.log('\tinvoking lambda', params);
132
+ const result = await lambda
133
+ .invoke({
134
+ FunctionName: context.functionName,
135
+ InvocationType: 'Event',
136
+ LogType: 'Tail',
137
+ Payload: JSON.stringify(newEvent),
138
+ })
139
+ .promise();
140
+ }
141
+ };
142
+ const dispatchCatchUpEvents = async (context, daysInThePast) => {
143
+ const now = new Date();
144
+ const hours = [];
145
+ for (let i = 0; i < 24 * daysInThePast; i++) {
146
+ const baseDate = new Date(now);
147
+ baseDate.setMinutes(0);
148
+ baseDate.setSeconds(0);
149
+ baseDate.setMilliseconds(0);
150
+ const hour = new Date(baseDate.getTime() - i * 60 * 60 * 1000);
151
+ hours.push(hour.toISOString());
152
+ }
153
+ for (const targetDate of hours) {
154
+ console.log('dispatching catch-up for date', targetDate);
155
+ const newEvent = {
156
+ targetDate: targetDate,
157
+ };
158
+ const params = {
159
+ FunctionName: context.functionName,
160
+ InvocationType: 'Event',
161
+ LogType: 'Tail',
162
+ Payload: JSON.stringify(newEvent),
163
+ };
59
164
  const result = await lambda
60
165
  .invoke({
61
166
  FunctionName: context.functionName,
@@ -64,6 +169,7 @@ const dispatchStatsV2Lambda = async (context, startDate) => {
64
169
  Payload: JSON.stringify(newEvent),
65
170
  })
66
171
  .promise();
172
+ await (0, aws_lambda_utils_1.sleep)(50);
67
173
  }
68
174
  };
69
175
  //# sourceMappingURL=_build-battlegrounds-hero-stats.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"_build-battlegrounds-hero-stats.js","sourceRoot":"","sources":["../../../src/duos/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 } 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\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/duo`;\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\n\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.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 {\r\n\t\tconst startDate = new Date();\r\n\t\tstartDate.setMinutes(0);\r\n\t\tstartDate.setSeconds(0);\r\n\t\tstartDate.setMilliseconds(0);\r\n\t\tstartDate.setHours(startDate.getHours() - 1);\r\n\t\t// console.log('processStartDate', startDate);\r\n\t\t// End one hour later\r\n\t\tconst endDate = new Date(startDate);\r\n\t\tendDate.setHours(endDate.getHours() + 1);\r\n\r\n\t\tawait saveRowsOnS3(startDate, endDate, allCards);\r\n\t\tawait dispatchStatsV2Lambda(context, startDate);\r\n\t}\r\n\r\n\tcleanup();\r\n\treturn { statusCode: 200, body: null };\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\t// logger.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"]}
1
+ {"version":3,"file":"_build-battlegrounds-hero-stats.js","sourceRoot":"","sources":["../../../src/duos/hourly/_build-battlegrounds-hero-stats.ts"],"names":[],"mappings":";;;;;;AACA,qEAA6E;AAC7E,iEAA+D;AAE/D,sDAA0B;AAE1B,4EAA6E;AAC7E,6CAA8C;AAC9C,iCAAsD;AAEzC,QAAA,EAAE,GAAG,IAAI,qBAAE,EAAE,CAAC;AAC3B,MAAM,QAAQ,GAAG,IAAI,gCAAe,EAAE,CAAC;AACvC,MAAM,MAAM,GAAG,IAAI,iBAAG,CAAC,MAAM,EAAE,CAAC;AAEhC,MAAM,iBAAiB,GAA+B,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;AAE9D,QAAA,YAAY,GAAG,yBAAyB,CAAC;AACzC,QAAA,gBAAgB,GAAG,aAAa,CAAC;AACjC,QAAA,iBAAiB,GAAG,GAAG,wBAAgB,mCAAmC,CAAC;AAC3E,QAAA,eAAe,GAAG,GAAG,wBAAgB,4DAA4D,CAAC;AAClG,QAAA,gBAAgB,GAAG,GAAG,wBAAgB,6DAA6D,CAAC;AACpG,QAAA,kBAAkB,GAAG,GAAG,wBAAgB,+DAA+D,CAAC;AAErH,kBAAe,KAAK,EAAE,KAAK,EAAE,OAAgB,EAAgB,EAAE;IAC9D,MAAM,IAAA,sBAAc,EAAC,KAAK,EAAE,OAAO,CAAC,CAAC;AACtC,CAAC,CAAC;AAEK,MAAM,cAAc,GAAG,KAAK,EAAE,KAAK,EAAE,OAAgB,EAAE,EAAE;IAC/D,MAAM,OAAO,GAAG,IAAA,mCAAgB,EAAC,OAAO,CAAC,CAAC;IAE1C,MAAM,QAAQ,CAAC,iBAAiB,EAAE,CAAC;IAEnC,IAAI,KAAK,CAAC,OAAO,EAAE;QAClB,MAAM,qBAAqB,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACrD,OAAO,EAAE,CAAC;QACV,OAAO;KACP;IAED,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE;QACzD,MAAM,kBAAkB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QACzC,OAAO,EAAE,CAAC;QACV,OAAO;KACP;IAOD,IAAI,KAAK,CAAC,OAAO,EAAE;QAClB,MAAM,YAAY,GAA8B,MAAM,IAAA,qBAAc,EAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAEtF,MAAM,IAAA,2BAAc,EAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,GAAG,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;KACzE;SAAM,IAAI,KAAK,CAAC,QAAQ,EAAE;QAC1B,MAAM,YAAY,GAA8B,MAAM,IAAA,qBAAc,EAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAEtF,MAAM,IAAA,iCAAiB,EACtB,KAAK,CAAC,SAAS,EACf,KAAK,CAAC,GAAG,EACT,YAAY,EACZ,QAAQ,EACR,oBAAY,EACZ,0BAAkB,EAClB,UAAE,CACF,CAAC;KACF;IAED,OAAO,EAAE,CAAC;AACX,CAAC,CAAC;AAzCW,QAAA,cAAc,kBAyCzB;AAEF,MAAM,kBAAkB,GAAG,KAAK,EAAE,OAAgB,EAAE,KAAK,EAAE,EAAE;IAC5D,MAAM,SAAS,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;IAE/C,MAAM,OAAO,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;IAEzC,MAAM,IAAA,mBAAY,EAAC,SAAS,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IAEjD,MAAM,qBAAqB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAEhD,MAAM,sBAAsB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;AAClD,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,CAAC,KAAK,EAAQ,EAAE;IAC7C,IAAI,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,UAAU,EAAE;QACtB,MAAM,UAAU,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC9C,OAAO,UAAU,CAAC;KAClB;IAGD,MAAM,gBAAgB,GAAG,IAAI,IAAI,EAAE,CAAC;IACpC,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAC/B,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAC/B,gBAAgB,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IACpC,gBAAgB,CAAC,QAAQ,CAAC,gBAAgB,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;IAC3D,OAAO,gBAAgB,CAAC;AACzB,CAAC,CAAC;AAEF,MAAM,sBAAsB,GAAG,KAAK,EAAE,OAAgB,EAAE,SAAe,EAAE,EAAE;IAC1E,KAAK,MAAM,GAAG,IAAI,iBAAiB,EAAE;QACpC,MAAM,QAAQ,GAAG;YAChB,QAAQ,EAAE,IAAI;YACd,GAAG,EAAE,GAAG;YACR,SAAS,EAAE,SAAS;SACpB,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;QACF,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC;QACzC,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;KAEZ;AACF,CAAC,CAAC;AAEF,MAAM,sBAAsB,GAAG,KAAK,EAAE,OAAgB,EAAE,SAAe,EAAE,EAAE;IAC1E,KAAK,MAAM,GAAG,IAAI,iBAAiB,EAAE;QACpC,MAAM,QAAQ,GAAG;YAChB,QAAQ,EAAE,IAAI;YACd,GAAG,EAAE,GAAG;YACR,SAAS,EAAE,SAAS;SACpB,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;QACF,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC;QACzC,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;KAEZ;AACF,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,KAAK,EAAE,OAAgB,EAAE,SAAe,EAAE,EAAE;IACzE,KAAK,MAAM,GAAG,IAAI,iBAAiB,EAAE;QACpC,MAAM,QAAQ,GAAG;YAChB,OAAO,EAAE,IAAI;YACb,GAAG,EAAE,GAAG;YACR,SAAS,EAAE,SAAS;SACpB,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;QACF,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC;QACzC,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;KAEZ;AACF,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,KAAK,EAAE,OAAgB,EAAE,aAAqB,EAAE,EAAE;IAE/E,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,MAAM,KAAK,GAAG,EAAE,CAAC;IACjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,aAAa,EAAE,CAAC,EAAE,EAAE;QAC5C,MAAM,QAAQ,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;QAC/B,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QACvB,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QACvB,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QAC5B,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QAC/D,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;KAC/B;IAED,KAAK,MAAM,UAAU,IAAI,KAAK,EAAE;QAC/B,OAAO,CAAC,GAAG,CAAC,+BAA+B,EAAE,UAAU,CAAC,CAAC;QACzD,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":["/* 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 { buildTrinketStats } from '../../solo/hourly/trinkets/trinket-stats';\r\nimport { buildHeroStats } from './hero-stats';\r\nimport { readRowsFromS3, saveRowsOnS3 } from './rows';\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/duo`;\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\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"]}
@@ -12,11 +12,11 @@ const buildHeroStatsForMmr = (rows, allCards) => {
12
12
  exports.buildHeroStatsForMmr = buildHeroStatsForMmr;
13
13
  const buildStatsForSingleHero = (rows) => {
14
14
  const ref = rows[0];
15
- const averagePosition = average(rows.map((r) => r.rank));
15
+ const averagePosition = average(rows.map((r) => r.playerRank));
16
16
  const placementDistribution = (0, utils_1.buildPlacementDistribution)(rows);
17
17
  const rawCombatWinrates = (0, builders_1.buildCombatWinrate)(rows);
18
18
  const rawWarbandStats = (0, builders_1.buildWarbandStats)(rows);
19
- const allRanks = rows.map((r) => r.rank);
19
+ const allRanks = rows.map((r) => r.playerRank);
20
20
  const allDeviations = allRanks.map((r) => averagePosition - r);
21
21
  const squareDeviations = allDeviations.map((d) => Math.pow(d, 2));
22
22
  const sumOfSquares = squareDeviations.reduce((a, b) => a + b, 0);
@@ -44,8 +44,8 @@ const buildTribeStats = (rows, refAveragePosition) => {
44
44
  return uniqueTribes.map((tribe) => {
45
45
  const rowsForTribe = rows.filter((r) => r.tribesExpanded.includes(tribe));
46
46
  const rowsWithoutTribe = rows.filter((r) => !r.tribesExpanded.includes(tribe));
47
- const averagePosition = average(rowsForTribe.map((r) => r.rank));
48
- const averagePositionWithoutTribe = average(rowsWithoutTribe.map((r) => r.rank));
47
+ const averagePosition = average(rowsForTribe.map((r) => r.playerRank));
48
+ const averagePositionWithoutTribe = average(rowsWithoutTribe.map((r) => r.playerRank));
49
49
  const result = {
50
50
  tribe: tribe,
51
51
  dataPoints: rowsForTribe.length,
@@ -1 +1 @@
1
- {"version":3,"file":"hero-stats-buikder.js","sourceRoot":"","sources":["../../../src/duos/hourly/hero-stats-buikder.ts"],"names":[],"mappings":"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","sourcesContent":["import { groupByFunction } from '@firestone-hs/aws-lambda-utils';\r\nimport { AllCardsService, Race } from '@firestone-hs/reference-data';\r\nimport { normalizeHeroCardId, round } from '../../common/util-functions';\r\nimport { InternalBgsRow } from '../../internal-model';\r\nimport { BgsGlobalHeroStat, BgsHeroTribeStat } from '../../models';\r\nimport { buildCombatWinrate, buildWarbandStats } from './builders';\r\nimport { buildPlacementDistribution } from './utils';\r\n\r\nexport const buildHeroStatsForMmr = (\r\n\trows: readonly InternalBgsRow[],\r\n\tallCards: AllCardsService,\r\n): readonly BgsGlobalHeroStat[] => {\r\n\t// This takes about 3s, so not impactful\r\n\tconst groupedByHero: {\r\n\t\t[questCardId: string]: readonly InternalBgsRow[];\r\n\t} = groupByFunction((row: InternalBgsRow) => normalizeHeroCardId(row.heroCardId, allCards))(rows);\r\n\treturn Object.values(groupedByHero).flatMap((data) => buildStatsForSingleHero(data));\r\n};\r\n\r\n// All rows here belong to a single hero\r\nconst buildStatsForSingleHero = (rows: readonly InternalBgsRow[]): BgsGlobalHeroStat => {\r\n\t// const startTime = new Date().getTime();\r\n\tconst ref = rows[0];\r\n\tconst averagePosition = average(rows.map((r) => r.rank));\r\n\t// const placementStartTime = new Date().getTime();\r\n\tconst placementDistribution = buildPlacementDistribution(rows);\r\n\t// const placementProcessTime = new Date().getTime() - placementStartTime;\r\n\t// const winrateStartTime = new Date().getTime();\r\n\tconst rawCombatWinrates = buildCombatWinrate(rows);\r\n\t// const winrateProcessTime = new Date().getTime() - winrateStartTime;\r\n\t// const combatWinrate: readonly { turn: number; winrate: number }[] = rawCombatWinrates.map((info) => ({\r\n\t// \tturn: info.turn,\r\n\t// \twinrate: round(info.totalWinrate / info.dataPoints),\r\n\t// }));\r\n\tconst rawWarbandStats = buildWarbandStats(rows);\r\n\t// const warbandStats: readonly { turn: number; averageStats: number }[] = rawWarbandStats.map((info) => ({\r\n\t// \tturn: info.turn,\r\n\t// \taverageStats: round(info.totalStats / info.dataPoints),\r\n\t// }));\r\n\r\n\tconst allRanks = rows.map((r) => r.rank);\r\n\tconst allDeviations = allRanks.map((r) => averagePosition - r);\r\n\tconst squareDeviations = allDeviations.map((d) => Math.pow(d, 2));\r\n\tconst sumOfSquares = squareDeviations.reduce((a, b) => a + b, 0);\r\n\tconst variance = sumOfSquares / rows.length;\r\n\tconst standardDeviation = Math.sqrt(variance);\r\n\tconst standardDeviationOfTheMean = standardDeviation / Math.sqrt(rows.length);\r\n\t// const tribeStartTime = new Date().getTime();\r\n\tconst tribeStats = buildTribeStats(rows, averagePosition);\r\n\t// const tribeProcessTime = new Date().getTime() - tribeStartTime;\r\n\t// const anomalyStartTime = new Date().getTime();\r\n\t// const anomalyStats = buildAnomalyStats(rows, averagePosition, placementDistribution, combatWinrate, warbandStats);\r\n\t// const anomalyProcessTime = new Date().getTime() - anomalyStartTime;\r\n\tconst result: BgsGlobalHeroStat = {\r\n\t\theroCardId: ref.heroCardId,\r\n\t\tdataPoints: rows.length,\r\n\t\taveragePosition: round(averagePosition),\r\n\t\tstandardDeviation: round(standardDeviation),\r\n\t\tstandardDeviationOfTheMean: round(standardDeviationOfTheMean),\r\n\t\tconservativePositionEstimate: round(averagePosition + 3 * standardDeviationOfTheMean),\r\n\t\tplacementDistributionRaw: placementDistribution,\r\n\t\tcombatWinrateRaw: rawCombatWinrates,\r\n\t\twarbandStatsRaw: rawWarbandStats,\r\n\t\ttribeStats: tribeStats,\r\n\t\tanomalyStats: null, //anomalyStats,\r\n\t};\r\n\t// const processTime = new Date().getTime() - startTime;\r\n\t// console.log('\\tbuilt for hero', result.heroCardId, result.dataPoints, result);\r\n\treturn result;\r\n};\r\n\r\nconst buildTribeStats = (rows: readonly InternalBgsRow[], refAveragePosition: number): readonly BgsHeroTribeStat[] => {\r\n\tconst uniqueTribes: readonly Race[] = [...new Set(rows.flatMap((r) => r.tribesExpanded))];\r\n\treturn uniqueTribes.map((tribe) => {\r\n\t\tconst rowsForTribe = rows.filter((r) => r.tribesExpanded.includes(tribe));\r\n\t\tconst rowsWithoutTribe = rows.filter((r) => !r.tribesExpanded.includes(tribe));\r\n\t\tconst averagePosition = average(rowsForTribe.map((r) => r.rank));\r\n\t\tconst averagePositionWithoutTribe = average(rowsWithoutTribe.map((r) => r.rank));\r\n\t\tconst result: BgsHeroTribeStat = {\r\n\t\t\ttribe: tribe,\r\n\t\t\tdataPoints: rowsForTribe.length,\r\n\t\t\tdataPointsOnMissingTribe: rowsWithoutTribe.length,\r\n\t\t\taveragePosition: averagePosition,\r\n\t\t\taveragePositionWithoutTribe: averagePositionWithoutTribe,\r\n\t\t\timpactAveragePosition: averagePosition - refAveragePosition,\r\n\t\t\timpactAveragePositionVsMissingTribe: averagePosition - averagePositionWithoutTribe,\r\n\t\t};\r\n\t\treturn result;\r\n\t});\r\n};\r\n\r\n// const buildAnomalyStats = (\r\n// \trows: readonly InternalBgsRow[],\r\n// \trefAveragePosition: number,\r\n// \trefPlacementDistribution: readonly { rank: number; percentage: number }[],\r\n// \trefCombatWinrate: readonly { turn: number; winrate: number }[],\r\n// \trefWarbandStats: readonly { turn: number; averageStats: number }[],\r\n// ): readonly BgsHeroAnomalyStat[] => {\r\n// \tconst rowsWithAnomalies = rows.filter((r) => !!r.bgsAnomalies?.length);\r\n// \tconst uniqueAnomalies: readonly string[] = [...new Set(rowsWithAnomalies.flatMap((r) => r.bgsAnomalies))];\r\n// \treturn uniqueAnomalies.map((anomaly) => {\r\n// \t\tconst rowsForAnomaly = rowsWithAnomalies.filter((r) => r.bgsAnomalies.includes(anomaly));\r\n// \t\tconst averagePosition = average(rowsForAnomaly.map((r) => r.rank));\r\n// \t\tconst placementDistribution = buildPlacementDistribution(rowsForAnomaly);\r\n// \t\tconst rawCombatWinrates = buildCombatWinrate(rowsForAnomaly);\r\n// \t\tconst combatWinrate = rawCombatWinrates.map((info) => ({\r\n// \t\t\tturn: info.turn,\r\n// \t\t\twinrate: round(info.totalWinrate / info.dataPoints),\r\n// \t\t}));\r\n// \t\tconst rawWarbandStats = buildWarbandStats(rowsForAnomaly);\r\n// \t\tconst warbandStats: readonly { turn: number; averageStats: number }[] = rawWarbandStats.map((info) => ({\r\n// \t\t\tturn: info.turn,\r\n// \t\t\taverageStats: round(info.totalStats / info.dataPoints),\r\n// \t\t}));\r\n// \t\tconst result: BgsHeroAnomalyStat = {\r\n// \t\t\tanomaly: anomaly,\r\n// \t\t\tdataPoints: rowsForAnomaly.length,\r\n// \t\t\taveragePosition: round(averagePosition),\r\n// \t\t\timpactAveragePosition: round(averagePosition - refAveragePosition),\r\n// \t\t\tplacementDistributionRaw: placementDistribution,\r\n// \t\t\timpactPlacementDistribution: refPlacementDistribution.map((p) => {\r\n// \t\t\t\tconst newPlacementInfo = placementDistribution.find((p2) => p2.rank === p.rank);\r\n// \t\t\t\t// Cna happen when there isn't a lot of data points, typically for high MMR\r\n// \t\t\t\tif (!newPlacementInfo) {\r\n// \t\t\t\t\t// console.log('missing placement info', placementDistribution, p);\r\n// \t\t\t\t}\r\n// \t\t\t\treturn {\r\n// \t\t\t\t\trank: p.rank,\r\n// \t\t\t\t\timpact: round((newPlacementInfo?.percentage ?? 0) - p.percentage),\r\n// \t\t\t\t};\r\n// \t\t\t}),\r\n// \t\t\tcombatWinrate: combatWinrate,\r\n// \t\t\timpactCombatWinrate: refCombatWinrate.map((c) => {\r\n// \t\t\t\tconst newCombatWinrate = combatWinrate.find((c2) => c2.turn === c.turn);\r\n// \t\t\t\tif (!newCombatWinrate) {\r\n// \t\t\t\t\t// console.debug('missing winrate info', combatWinrate);\r\n// \t\t\t\t}\r\n// \t\t\t\treturn {\r\n// \t\t\t\t\tturn: c.turn,\r\n// \t\t\t\t\timpact: round((newCombatWinrate?.winrate ?? 0) - c.winrate),\r\n// \t\t\t\t};\r\n// \t\t\t}),\r\n// \t\t\twarbandStats: warbandStats,\r\n// \t\t\timpactWarbandStats: refWarbandStats.map((c) => {\r\n// \t\t\t\tconst newWarbandStats = warbandStats.find((c2) => c2.turn === c.turn);\r\n// \t\t\t\tif (!newWarbandStats) {\r\n// \t\t\t\t\t// console.debug('missing warband info', warbandStats);\r\n// \t\t\t\t}\r\n// \t\t\t\treturn {\r\n// \t\t\t\t\tturn: c.turn,\r\n// \t\t\t\t\timpact: round((newWarbandStats?.averageStats ?? 0) - c.averageStats),\r\n// \t\t\t\t};\r\n// \t\t\t}),\r\n// \t\t};\r\n// \t\treturn result;\r\n// \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"]}
1
+ {"version":3,"file":"hero-stats-buikder.js","sourceRoot":"","sources":["../../../src/duos/hourly/hero-stats-buikder.ts"],"names":[],"mappings":"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","sourcesContent":["import { groupByFunction } from '@firestone-hs/aws-lambda-utils';\r\nimport { AllCardsService, Race } from '@firestone-hs/reference-data';\r\nimport { normalizeHeroCardId, round } from '../../common/util-functions';\r\nimport { InternalBgsRow } from '../../internal-model';\r\nimport { BgsGlobalHeroStat, BgsHeroTribeStat } from '../../models';\r\nimport { buildCombatWinrate, buildWarbandStats } from './builders';\r\nimport { buildPlacementDistribution } from './utils';\r\n\r\nexport const buildHeroStatsForMmr = (\r\n\trows: readonly InternalBgsRow[],\r\n\tallCards: AllCardsService,\r\n): readonly BgsGlobalHeroStat[] => {\r\n\t// This takes about 3s, so not impactful\r\n\tconst groupedByHero: {\r\n\t\t[questCardId: string]: readonly InternalBgsRow[];\r\n\t} = groupByFunction((row: InternalBgsRow) => normalizeHeroCardId(row.heroCardId, allCards))(rows);\r\n\treturn Object.values(groupedByHero).flatMap((data) => buildStatsForSingleHero(data));\r\n};\r\n\r\n// All rows here belong to a single hero\r\nconst buildStatsForSingleHero = (rows: readonly InternalBgsRow[]): BgsGlobalHeroStat => {\r\n\t// const startTime = new Date().getTime();\r\n\tconst ref = rows[0];\r\n\tconst averagePosition = average(rows.map((r) => r.playerRank));\r\n\t// const placementStartTime = new Date().getTime();\r\n\tconst placementDistribution = buildPlacementDistribution(rows);\r\n\t// const placementProcessTime = new Date().getTime() - placementStartTime;\r\n\t// const winrateStartTime = new Date().getTime();\r\n\tconst rawCombatWinrates = buildCombatWinrate(rows);\r\n\t// const winrateProcessTime = new Date().getTime() - winrateStartTime;\r\n\t// const combatWinrate: readonly { turn: number; winrate: number }[] = rawCombatWinrates.map((info) => ({\r\n\t// \tturn: info.turn,\r\n\t// \twinrate: round(info.totalWinrate / info.dataPoints),\r\n\t// }));\r\n\tconst rawWarbandStats = buildWarbandStats(rows);\r\n\t// const warbandStats: readonly { turn: number; averageStats: number }[] = rawWarbandStats.map((info) => ({\r\n\t// \tturn: info.turn,\r\n\t// \taverageStats: round(info.totalStats / info.dataPoints),\r\n\t// }));\r\n\r\n\tconst allRanks = rows.map((r) => r.playerRank);\r\n\tconst allDeviations = allRanks.map((r) => averagePosition - r);\r\n\tconst squareDeviations = allDeviations.map((d) => Math.pow(d, 2));\r\n\tconst sumOfSquares = squareDeviations.reduce((a, b) => a + b, 0);\r\n\tconst variance = sumOfSquares / rows.length;\r\n\tconst standardDeviation = Math.sqrt(variance);\r\n\tconst standardDeviationOfTheMean = standardDeviation / Math.sqrt(rows.length);\r\n\t// const tribeStartTime = new Date().getTime();\r\n\tconst tribeStats = buildTribeStats(rows, averagePosition);\r\n\t// const tribeProcessTime = new Date().getTime() - tribeStartTime;\r\n\t// const anomalyStartTime = new Date().getTime();\r\n\t// const anomalyStats = buildAnomalyStats(rows, averagePosition, placementDistribution, combatWinrate, warbandStats);\r\n\t// const anomalyProcessTime = new Date().getTime() - anomalyStartTime;\r\n\tconst result: BgsGlobalHeroStat = {\r\n\t\theroCardId: ref.heroCardId,\r\n\t\tdataPoints: rows.length,\r\n\t\taveragePosition: round(averagePosition),\r\n\t\tstandardDeviation: round(standardDeviation),\r\n\t\tstandardDeviationOfTheMean: round(standardDeviationOfTheMean),\r\n\t\tconservativePositionEstimate: round(averagePosition + 3 * standardDeviationOfTheMean),\r\n\t\tplacementDistributionRaw: placementDistribution,\r\n\t\tcombatWinrateRaw: rawCombatWinrates,\r\n\t\twarbandStatsRaw: rawWarbandStats,\r\n\t\ttribeStats: tribeStats,\r\n\t\tanomalyStats: null, //anomalyStats,\r\n\t};\r\n\t// const processTime = new Date().getTime() - startTime;\r\n\t// console.log('\\tbuilt for hero', result.heroCardId, result.dataPoints, result);\r\n\treturn result;\r\n};\r\n\r\nconst buildTribeStats = (rows: readonly InternalBgsRow[], refAveragePosition: number): readonly BgsHeroTribeStat[] => {\r\n\tconst uniqueTribes: readonly Race[] = [...new Set(rows.flatMap((r) => r.tribesExpanded))];\r\n\treturn uniqueTribes.map((tribe) => {\r\n\t\tconst rowsForTribe = rows.filter((r) => r.tribesExpanded.includes(tribe));\r\n\t\tconst rowsWithoutTribe = rows.filter((r) => !r.tribesExpanded.includes(tribe));\r\n\t\tconst averagePosition = average(rowsForTribe.map((r) => r.playerRank));\r\n\t\tconst averagePositionWithoutTribe = average(rowsWithoutTribe.map((r) => r.playerRank));\r\n\t\tconst result: BgsHeroTribeStat = {\r\n\t\t\ttribe: tribe,\r\n\t\t\tdataPoints: rowsForTribe.length,\r\n\t\t\tdataPointsOnMissingTribe: rowsWithoutTribe.length,\r\n\t\t\taveragePosition: averagePosition,\r\n\t\t\taveragePositionWithoutTribe: averagePositionWithoutTribe,\r\n\t\t\timpactAveragePosition: averagePosition - refAveragePosition,\r\n\t\t\timpactAveragePositionVsMissingTribe: averagePosition - averagePositionWithoutTribe,\r\n\t\t};\r\n\t\treturn result;\r\n\t});\r\n};\r\n\r\n// const buildAnomalyStats = (\r\n// \trows: readonly InternalBgsRow[],\r\n// \trefAveragePosition: number,\r\n// \trefPlacementDistribution: readonly { rank: number; percentage: number }[],\r\n// \trefCombatWinrate: readonly { turn: number; winrate: number }[],\r\n// \trefWarbandStats: readonly { turn: number; averageStats: number }[],\r\n// ): readonly BgsHeroAnomalyStat[] => {\r\n// \tconst rowsWithAnomalies = rows.filter((r) => !!r.bgsAnomalies?.length);\r\n// \tconst uniqueAnomalies: readonly string[] = [...new Set(rowsWithAnomalies.flatMap((r) => r.bgsAnomalies))];\r\n// \treturn uniqueAnomalies.map((anomaly) => {\r\n// \t\tconst rowsForAnomaly = rowsWithAnomalies.filter((r) => r.bgsAnomalies.includes(anomaly));\r\n// \t\tconst averagePosition = average(rowsForAnomaly.map((r) => r.rank));\r\n// \t\tconst placementDistribution = buildPlacementDistribution(rowsForAnomaly);\r\n// \t\tconst rawCombatWinrates = buildCombatWinrate(rowsForAnomaly);\r\n// \t\tconst combatWinrate = rawCombatWinrates.map((info) => ({\r\n// \t\t\tturn: info.turn,\r\n// \t\t\twinrate: round(info.totalWinrate / info.dataPoints),\r\n// \t\t}));\r\n// \t\tconst rawWarbandStats = buildWarbandStats(rowsForAnomaly);\r\n// \t\tconst warbandStats: readonly { turn: number; averageStats: number }[] = rawWarbandStats.map((info) => ({\r\n// \t\t\tturn: info.turn,\r\n// \t\t\taverageStats: round(info.totalStats / info.dataPoints),\r\n// \t\t}));\r\n// \t\tconst result: BgsHeroAnomalyStat = {\r\n// \t\t\tanomaly: anomaly,\r\n// \t\t\tdataPoints: rowsForAnomaly.length,\r\n// \t\t\taveragePosition: round(averagePosition),\r\n// \t\t\timpactAveragePosition: round(averagePosition - refAveragePosition),\r\n// \t\t\tplacementDistributionRaw: placementDistribution,\r\n// \t\t\timpactPlacementDistribution: refPlacementDistribution.map((p) => {\r\n// \t\t\t\tconst newPlacementInfo = placementDistribution.find((p2) => p2.rank === p.rank);\r\n// \t\t\t\t// Cna happen when there isn't a lot of data points, typically for high MMR\r\n// \t\t\t\tif (!newPlacementInfo) {\r\n// \t\t\t\t\t// console.log('missing placement info', placementDistribution, p);\r\n// \t\t\t\t}\r\n// \t\t\t\treturn {\r\n// \t\t\t\t\trank: p.rank,\r\n// \t\t\t\t\timpact: round((newPlacementInfo?.percentage ?? 0) - p.percentage),\r\n// \t\t\t\t};\r\n// \t\t\t}),\r\n// \t\t\tcombatWinrate: combatWinrate,\r\n// \t\t\timpactCombatWinrate: refCombatWinrate.map((c) => {\r\n// \t\t\t\tconst newCombatWinrate = combatWinrate.find((c2) => c2.turn === c.turn);\r\n// \t\t\t\tif (!newCombatWinrate) {\r\n// \t\t\t\t\t// console.debug('missing winrate info', combatWinrate);\r\n// \t\t\t\t}\r\n// \t\t\t\treturn {\r\n// \t\t\t\t\tturn: c.turn,\r\n// \t\t\t\t\timpact: round((newCombatWinrate?.winrate ?? 0) - c.winrate),\r\n// \t\t\t\t};\r\n// \t\t\t}),\r\n// \t\t\twarbandStats: warbandStats,\r\n// \t\t\timpactWarbandStats: refWarbandStats.map((c) => {\r\n// \t\t\t\tconst newWarbandStats = warbandStats.find((c2) => c2.turn === c.turn);\r\n// \t\t\t\tif (!newWarbandStats) {\r\n// \t\t\t\t\t// console.debug('missing warband info', warbandStats);\r\n// \t\t\t\t}\r\n// \t\t\t\treturn {\r\n// \t\t\t\t\tturn: c.turn,\r\n// \t\t\t\t\timpact: round((newWarbandStats?.averageStats ?? 0) - c.averageStats),\r\n// \t\t\t\t};\r\n// \t\t\t}),\r\n// \t\t};\r\n// \t\treturn result;\r\n// \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"]}
@@ -147,7 +147,7 @@ const processRows = async (rows, multipartUpload, allCards) => {
147
147
  const validRows = rows
148
148
  .filter((row) => row.heroCardId !== "TB_BaconShop_HERO_59t" &&
149
149
  row.heroCardId !== "BG22_HERO_007t")
150
- .filter((row) => { var _a; return !!row.rank && !!((_a = row.tribes) === null || _a === void 0 ? void 0 : _a.length); })
150
+ .filter((row) => { var _a; return !!row.playerRank && !!((_a = row.tribes) === null || _a === void 0 ? void 0 : _a.length); })
151
151
  .map((row) => {
152
152
  const result = {
153
153
  ...row,
@@ -1 +1 @@
1
- {"version":3,"file":"rows.js","sourceRoot":"","sources":["../../../src/duos/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_duo\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.rank && !!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};\r\n\t\t\tdelete (result as any).reviewId;\r\n\t\t\tdelete (result as any).tribes;\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/duos/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_duo\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};\r\n\t\t\tdelete (result as any).reviewId;\r\n\t\t\tdelete (result as any).tribes;\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"]}
File without changes
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=trinket-stats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trinket-stats.js","sourceRoot":"","sources":["../../../../src/duos/hourly/trinkets/trinket-stats.ts"],"names":[],"mappings":"","sourcesContent":[""]}
@@ -48,7 +48,7 @@ const buildMmrPercentiles = (rows) => {
48
48
  exports.buildMmrPercentiles = buildMmrPercentiles;
49
49
  const buildPlacementDistribution = (rows) => {
50
50
  const placementDistribution = [];
51
- const groupedByPlacement = (0, aws_lambda_utils_1.groupByFunction)((res) => '' + res.rank)(rows);
51
+ const groupedByPlacement = (0, aws_lambda_utils_1.groupByFunction)((res) => '' + res.playerRank)(rows);
52
52
  Object.keys(groupedByPlacement).forEach((placement) => placementDistribution.push({ rank: +placement, totalMatches: groupedByPlacement[placement].length }));
53
53
  return placementDistribution;
54
54
  };
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/duos/hourly/utils.ts"],"names":[],"mappings":"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","sourcesContent":["import { PatchInfo, groupByFunction } from '@firestone-hs/aws-lambda-utils';\r\nimport { InternalBgsRow } from '../../internal-model';\r\nimport { MmrPercentile } from '../../public-api';\r\n\r\nexport const filterRowsForTimePeriod = (\r\n\trows: readonly InternalBgsRow[],\r\n\ttimePeriod: 'all-time' | 'past-three' | 'past-seven' | 'last-patch',\r\n\tlastPatch: PatchInfo,\r\n): readonly InternalBgsRow[] => {\r\n\tswitch (timePeriod) {\r\n\t\tcase 'last-patch':\r\n\t\t\treturn rows.filter(\r\n\t\t\t\t(row) => row.buildNumber >= lastPatch.number || new Date(row.creationDate) > new Date(lastPatch.date),\r\n\t\t\t);\r\n\t\tcase 'past-three':\r\n\t\t\treturn rows.filter(\r\n\t\t\t\t(row) => new Date(row.creationDate) > new Date(new Date().getTime() - 3 * 24 * 60 * 60 * 1000),\r\n\t\t\t);\r\n\t\tcase 'past-seven':\r\n\t\t\treturn rows.filter(\r\n\t\t\t\t(row) => new Date(row.creationDate) > new Date(new Date().getTime() - 7 * 24 * 60 * 60 * 1000),\r\n\t\t\t);\r\n\t\tcase 'all-time':\r\n\t\tdefault:\r\n\t\t\treturn rows;\r\n\t}\r\n};\r\n\r\nexport const buildMmrPercentiles = (rows: readonly InternalBgsRow[]): readonly MmrPercentile[] => {\r\n\tconst sortedMmrs = rows.map((row) => row.rating).sort((a, b) => a - b);\r\n\tconst median = sortedMmrs[Math.floor(sortedMmrs.length / 2)];\r\n\tconst top25 = sortedMmrs[Math.floor((sortedMmrs.length / 4) * 3)];\r\n\tconst top10 = sortedMmrs[Math.floor((sortedMmrs.length / 10) * 9)];\r\n\tconst top1 = sortedMmrs[Math.floor((sortedMmrs.length / 100) * 99)];\r\n\t// logger.debug('percentiles', median, top25, top10, top1);\r\n\treturn [\r\n\t\t{\r\n\t\t\tpercentile: 100,\r\n\t\t\tmmr: 0,\r\n\t\t},\r\n\t\t{\r\n\t\t\tpercentile: 50,\r\n\t\t\tmmr: median,\r\n\t\t},\r\n\t\t{\r\n\t\t\tpercentile: 25,\r\n\t\t\tmmr: top25,\r\n\t\t},\r\n\t\t{\r\n\t\t\tpercentile: 10,\r\n\t\t\tmmr: top10,\r\n\t\t},\r\n\t\t{\r\n\t\t\tpercentile: 1,\r\n\t\t\tmmr: top1,\r\n\t\t},\r\n\t];\r\n};\r\n\r\nexport const buildPlacementDistribution = (\r\n\trows: readonly InternalBgsRow[],\r\n): readonly { rank: number; totalMatches: number }[] => {\r\n\tconst placementDistribution: { rank: number; totalMatches: number }[] = [];\r\n\tconst groupedByPlacement: { [placement: string]: readonly InternalBgsRow[] } = groupByFunction(\r\n\t\t(res: InternalBgsRow) => '' + res.rank,\r\n\t)(rows);\r\n\tObject.keys(groupedByPlacement).forEach((placement) =>\r\n\t\tplacementDistribution.push({ rank: +placement, totalMatches: groupedByPlacement[placement].length }),\r\n\t);\r\n\treturn placementDistribution;\r\n};\r\n"]}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/duos/hourly/utils.ts"],"names":[],"mappings":"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","sourcesContent":["import { PatchInfo, groupByFunction } from '@firestone-hs/aws-lambda-utils';\r\nimport { InternalBgsRow } from '../../internal-model';\r\nimport { MmrPercentile } from '../../public-api';\r\n\r\nexport const filterRowsForTimePeriod = (\r\n\trows: readonly InternalBgsRow[],\r\n\ttimePeriod: 'all-time' | 'past-three' | 'past-seven' | 'last-patch',\r\n\tlastPatch: PatchInfo,\r\n): readonly InternalBgsRow[] => {\r\n\tswitch (timePeriod) {\r\n\t\tcase 'last-patch':\r\n\t\t\treturn rows.filter(\r\n\t\t\t\t(row) => row.buildNumber >= lastPatch.number || new Date(row.creationDate) > new Date(lastPatch.date),\r\n\t\t\t);\r\n\t\tcase 'past-three':\r\n\t\t\treturn rows.filter(\r\n\t\t\t\t(row) => new Date(row.creationDate) > new Date(new Date().getTime() - 3 * 24 * 60 * 60 * 1000),\r\n\t\t\t);\r\n\t\tcase 'past-seven':\r\n\t\t\treturn rows.filter(\r\n\t\t\t\t(row) => new Date(row.creationDate) > new Date(new Date().getTime() - 7 * 24 * 60 * 60 * 1000),\r\n\t\t\t);\r\n\t\tcase 'all-time':\r\n\t\tdefault:\r\n\t\t\treturn rows;\r\n\t}\r\n};\r\n\r\nexport const buildMmrPercentiles = (rows: readonly InternalBgsRow[]): readonly MmrPercentile[] => {\r\n\tconst sortedMmrs = rows.map((row) => row.rating).sort((a, b) => a - b);\r\n\tconst median = sortedMmrs[Math.floor(sortedMmrs.length / 2)];\r\n\tconst top25 = sortedMmrs[Math.floor((sortedMmrs.length / 4) * 3)];\r\n\tconst top10 = sortedMmrs[Math.floor((sortedMmrs.length / 10) * 9)];\r\n\tconst top1 = sortedMmrs[Math.floor((sortedMmrs.length / 100) * 99)];\r\n\t// logger.debug('percentiles', median, top25, top10, top1);\r\n\treturn [\r\n\t\t{\r\n\t\t\tpercentile: 100,\r\n\t\t\tmmr: 0,\r\n\t\t},\r\n\t\t{\r\n\t\t\tpercentile: 50,\r\n\t\t\tmmr: median,\r\n\t\t},\r\n\t\t{\r\n\t\t\tpercentile: 25,\r\n\t\t\tmmr: top25,\r\n\t\t},\r\n\t\t{\r\n\t\t\tpercentile: 10,\r\n\t\t\tmmr: top10,\r\n\t\t},\r\n\t\t{\r\n\t\t\tpercentile: 1,\r\n\t\t\tmmr: top1,\r\n\t\t},\r\n\t];\r\n};\r\n\r\nexport const buildPlacementDistribution = (\r\n\trows: readonly InternalBgsRow[],\r\n): readonly { rank: number; totalMatches: number }[] => {\r\n\tconst placementDistribution: { rank: number; totalMatches: number }[] = [];\r\n\tconst groupedByPlacement: { [placement: string]: readonly InternalBgsRow[] } = groupByFunction(\r\n\t\t(res: InternalBgsRow) => '' + res.playerRank,\r\n\t)(rows);\r\n\tObject.keys(groupedByPlacement).forEach((placement) =>\r\n\t\tplacementDistribution.push({ rank: +placement, totalMatches: groupedByPlacement[placement].length }),\r\n\t);\r\n\treturn placementDistribution;\r\n};\r\n"]}