refactor: remove patch_detector and use gameVersion field in match_collector
All checks were successful
pipeline / lint-and-format (push) Successful in 4m20s
pipeline / build-and-push-images (push) Successful in 1m20s

This commit is contained in:
2026-04-30 10:37:42 +02:00
parent e1ab81854a
commit 7051ace13f
16 changed files with 379 additions and 2617 deletions

View File

@@ -20,39 +20,69 @@ async function setupDatabase() {
// Check if data directory exists and has files
const dataDir = path.join(__dirname, '../data');
const patchFile = path.join(dataDir, "patches.json");
if(!fs.existsSync(dataDir) || !fs.existsSync(patchFile)) {
fs.mkdirSync(dataDir, { recursive: true });
console.log('🚫 No data files found. Downloading latest snapshot...');
// Try to get latest patch version from existing data files or database
let latestPatch = await getLatestPatchVersion();
// If no patch found, download snapshot
if (!latestPatch) {
if (!fs.existsSync(dataDir)) {
fs.mkdirSync(dataDir, { recursive: true });
}
console.log('🚫 No match data found. Downloading latest snapshot...');
await downloadAndExtractSnapshot();
// Try again after download
latestPatch = await getLatestPatchVersion();
}
// Get latest patch version
const latestPatch = await getLatestPatchVersion();
if (!latestPatch) {
console.error('❌ Could not determine latest patch version');
console.log('💡 Make sure you have match data files in the data directory');
process.exit(1);
}
console.log(`🎯 Latest patch version: ${latestPatch}`);
// Check if data directory exists and has files
// Support both old format (patch_matches.json) and new platform-specific format (patch_PLATFORM_matches.json)
// Also support both "XX.Y" and "XX.Y.Z" patch formats in filenames
console.log('🔍 Checking for data files...');
const platforms = ['EUW1', 'EUN1', 'NA1', 'KR'];
const dataFiles = [
{ path: 'patches.json', required: true, description: 'Patches data' }
];
const dataFiles = [];
// Check for platform-specific match files
// Files may be named with either "16.8" or "16.8.1" format
let foundPlatformFiles = [];
for (const platform of platforms) {
const platformFile = `${latestPatch}_${platform}.json`;
const fullPath = path.join(dataDir, platformFile);
if (fs.existsSync(fullPath)) {
// Try both formats: "16.8_PLATFORM.json" and "16.8.1_PLATFORM.json"
const files = fs.readdirSync(dataDir);
const matchFile = files.find(f => {
const match = f.match(/^(\d+\.\d+(?:\.\d+)?)_([A-Z0-9]+)\.json$/);
const patchFromName = match ? match[1].split('.').slice(0, 2).join('.') : null;
return match && patchFromName === latestPatch && match[2] === platform;
});
if (matchFile) {
foundPlatformFiles.push(platform);
dataFiles.push({ path: platformFile, required: false, description: `Match data for ${platform}` });
dataFiles.push({ path: matchFile, required: false, description: `Match data for ${platform}` });
}
}
// If no platform-specific files found, look for old format
if (foundPlatformFiles.length === 0) {
dataFiles.push({ path: `${latestPatch}_matches.json`, required: true, description: 'Match data' });
// Try to find any match file for this patch
const files = fs.readdirSync(dataDir);
const matchFile = files.find(f => {
const match = f.match(/^(\d+\.\d+(?:\.\d+)?)(?:_matches)?\.json$/);
const patchFromName = match ? match[1].split('.').slice(0, 2).join('.') : null;
return match && patchFromName === latestPatch;
});
if (matchFile) {
dataFiles.push({ path: matchFile, required: true, description: 'Match data' });
} else {
dataFiles.push({ path: `${latestPatch}_matches.json`, required: true, description: 'Match data' });
}
}
let filesExist = true;
@@ -91,11 +121,7 @@ async function setupDatabase() {
// 4. Wait for MongoDB to be ready
await waitForMongoDB();
// 5. Import patches data
console.log('📦 Importing patches data...');
await importPatchesData();
// 6. Check existing matches count and import if needed
// 5. Check existing matches count and import if needed
console.log('Checking existing matches count...');
// Check for platform-specific collections or fall back to old format
@@ -129,11 +155,7 @@ async function setupDatabase() {
}
}
// 7. Fetch CDragon data for the current patch
console.log('🎮 Fetching CDragon data...');
await fetchCDragonData();
// 8. Run match collector to generate stats
// 7. Run match collector to generate stats (this also handles CDragon caching)
console.log('📊 Generating champion stats...');
await generateChampionStats();
@@ -148,48 +170,70 @@ async function setupDatabase() {
}
async function getLatestPatchVersion() {
try {
const filePath = path.join(__dirname, '../data/patches.json');
if(!fs.existsSync(filePath)) {
return null;
}
const fileContent = fs.readFileSync(filePath, 'utf8');
// Check if it's line-delimited JSON or array format
let patchesData;
if (fileContent.trim().startsWith('[')) {
// Array format
patchesData = JSON.parse(fileContent);
if (!Array.isArray(patchesData)) {
throw new Error('Patches data should be an array');
}
} else {
// Line-delimited JSON format
patchesData = fileContent.split('\n')
.filter(line => line.trim() !== '')
.map(line => JSON.parse(line));
}
// Convert dates to Date objects for proper sorting
patchesData = patchesData.map(patch => ({
...patch,
date: new Date(patch.date.$date || patch.date)
}));
// Sort patches by date (newest first) and get the latest
const sortedPatches = patchesData.sort((a, b) => b.date - a.date);
const latestPatch = sortedPatches[0];
const dataDir = path.join(__dirname, '../data');
// First, try to get patch from match data files (format: PATCH_PLATFORM.json or PATCH_matches.json)
if (fs.existsSync(dataDir)) {
const files = fs.readdirSync(dataDir);
const patches = new Set();
if (!latestPatch || !latestPatch.patch) {
throw new Error('Could not find patch version in patches data');
for (const file of files) {
// Match patterns like "16.8.1_EUW1.json" or "15.1_EUW1.json" or "15.1_matches.json" or "15.1.json"
// Patch version can be either "XX.Y" or "XX.Y.Z" format
const match = file.match(/^(\d+\.\d+(?:\.\d+)?)(?:_[A-Z0-9]+)?(?:_matches)?\.json$/);
if (match) {
// Normalize to "XX.Y" format (strip the third part if present)
const patch = match[1].split('.').slice(0, 2).join('.');
patches.add(patch);
}
}
if (patches.size > 0) {
// Sort patches and return the latest (highest version number)
const sortedPatches = Array.from(patches).sort((a, b) => {
const [aMajor, aMinor] = a.split('.').map(Number);
const [bMajor, bMinor] = b.split('.').map(Number);
if (aMajor !== bMajor) return bMajor - aMajor;
return bMinor - aMinor;
});
return sortedPatches[0];
}
return latestPatch.patch;
} catch (error) {
console.error('❌ Failed to get latest patch version:', error);
throw error;
}
// Fallback: try to get from database collections
try {
const client = new MongoClient(getMongoUri());
await client.connect();
const db = client.db('matches');
const collections = await db.listCollections().toArray();
const collectionNames = collections.map(c => c.name);
const patches = new Set();
for (const name of collectionNames) {
// Collection names are either "patch_platform" or just "patch"
const patch = name.split('_')[0];
if (patch && /^\d+\.\d+$/.test(patch)) {
patches.add(patch);
}
}
await client.close();
if (patches.size > 0) {
const sortedPatches = Array.from(patches).sort((a, b) => {
const [aMajor, aMinor] = a.split('.').map(Number);
const [bMajor, bMinor] = b.split('.').map(Number);
if (aMajor !== bMajor) return bMajor - aMajor;
return bMinor - aMinor;
});
return sortedPatches[0];
}
} catch (error) {
// Database not available, continue with other methods
}
return null;
}
async function downloadAndExtractSnapshot() {
@@ -256,83 +300,25 @@ async function waitForMongoDB() {
}
}
async function importPatchesData() {
const client = new MongoClient(getMongoUri());
await client.connect();
try {
const filePath = path.join(__dirname, '../data/patches.json');
const fileContent = fs.readFileSync(filePath, 'utf8');
// Check if it's line-delimited JSON or array format
let patchesData;
if (fileContent.trim().startsWith('[')) {
// Array format
patchesData = JSON.parse(fileContent);
if (!Array.isArray(patchesData)) {
throw new Error('Patches data should be an array');
}
} else {
// Line-delimited JSON format
patchesData = fileContent.split('\n')
.filter(line => line.trim() !== '')
.map(line => {
const doc = JSON.parse(line);
return convertMongoExtendedJson(doc);
});
}
// Convert any extended JSON in array format too
if (Array.isArray(patchesData)) {
patchesData = patchesData.map(doc => convertMongoExtendedJson(doc));
}
// Sort patches by date (newest first)
patchesData.sort((a, b) => {
const dateA = new Date(a.date || a.date.$date || 0);
const dateB = new Date(b.date || b.date.$date || 0);
return dateB - dateA; // Descending order (newest first)
});
const db = client.db('patches');
const collection = db.collection('patches');
// Clear existing data
await collection.deleteMany({});
// Insert sorted data
const result = await collection.insertMany(patchesData);
console.log(`✅ Imported ${result.insertedCount} patches (sorted by date)`);
// Create index
await collection.createIndex({ date: -1 });
console.log('✅ Created patches index');
} catch (error) {
console.error('❌ Failed to import patches:', error);
throw error;
} finally {
await client.close();
}
}
async function importMatchesData(patchVersion, foundPlatformFiles = []) {
const dataDir = path.join(__dirname, '../data');
const files = fs.readdirSync(dataDir);
try {
// If platform-specific files were found, import each one
if (foundPlatformFiles.length > 0) {
for (const platform of foundPlatformFiles) {
// Try both formats: patch_PLATFORM.json and patch_PLATFORM_matches.json
let matchesFile = path.join(dataDir, `${patchVersion}_${platform}.json`);
const collectionName = `${patchVersion}_${platform}`;
// Find the actual file for this platform (could be "16.8_PLATFORM.json" or "16.8.1_PLATFORM.json")
const matchFile = files.find(f => {
const match = f.match(/^(\d+\.\d+(?:\.\d+)?)_([A-Z0-9]+)\.json$/);
const patchFromName = match ? match[1].split('.').slice(0, 2).join('.') : null;
return match && patchFromName === patchVersion && match[2] === platform;
});
// Fallback to _matches.json suffix if the direct file doesn't exist
if (!fs.existsSync(matchesFile)) {
matchesFile = path.join(dataDir, `${patchVersion}_${platform}_matches.json`);
}
if (fs.existsSync(matchesFile)) {
if (matchFile) {
const matchesFile = path.join(dataDir, matchFile);
const collectionName = `${patchVersion}_${platform}`;
console.log(`📥 Importing matches for ${platform}...`);
execSync(
`node ${path.join(__dirname, 'process-matches.js')} ${matchesFile} ${collectionName} 1000`,
@@ -348,15 +334,16 @@ async function importMatchesData(patchVersion, foundPlatformFiles = []) {
}
} else {
// Fall back to old format (single file without platform suffix)
// Try both formats: patch_matches.json and patch.json
let matchesFile = path.join(dataDir, `${patchVersion}_matches.json`);
const collectionName = patchVersion;
// Find any match file for this patch
const matchFile = files.find(f => {
const match = f.match(/^(\d+\.\d+(?:\.\d+)?)(?:_matches)?\.json$/);
const patchFromName = match ? match[1].split('.').slice(0, 2).join('.') : null;
return match && patchFromName === patchVersion;
});
if (!fs.existsSync(matchesFile)) {
matchesFile = path.join(dataDir, `${patchVersion}.json`);
}
if (fs.existsSync(matchesFile)) {
if (matchFile) {
const matchesFile = path.join(dataDir, matchFile);
const collectionName = patchVersion;
execSync(
`node ${path.join(__dirname, 'process-matches.js')} ${matchesFile} ${collectionName} 1000`,
{
@@ -404,24 +391,6 @@ async function generateChampionStats() {
}
}
async function fetchCDragonData() {
try {
console.log('🔄 Running CDragon fetcher...');
// Run the fetch-cdragon script
const fetchCDragonPath = path.join(__dirname, 'fetch-cdragon.js');
execSync(`node ${fetchCDragonPath}`, {
stdio: 'inherit',
cwd: path.join(__dirname, '..')
});
console.log('✅ CDragon data fetched');
} catch (error) {
console.error('❌ Failed to fetch CDragon data:', error);
throw error;
}
}
async function getMatchCount(patchVersion, platform = null) {
const client = new MongoClient(getMongoUri());
await client.connect();
@@ -582,9 +551,6 @@ if (import.meta.url === `file://${process.argv[1]}`) {
case 'generate-stats':
generateChampionStats().catch(console.error);
break;
case 'import-patches':
importPatchesData().catch(console.error);
break;
case 'match-count':
if (args[1]) {
getMatchCount(args[1]).then(count => console.log(`Match count: ${count}`)).catch(console.error);
@@ -605,7 +571,6 @@ if (import.meta.url === `file://${process.argv[1]}`) {
export {
setupDatabase,
importPatchesData,
importMatchesData,
generateChampionStats,
checkDatabaseStatus,