diff --git a/app/logic/voyage_stats.ts b/app/logic/voyage_stats.ts index a2114bf..02d69eb 100644 --- a/app/logic/voyage_stats.ts +++ b/app/logic/voyage_stats.ts @@ -7,6 +7,7 @@ export interface Voyager { crewSymbol: string, seats: { seat_skill: string, seat_index: number, crewCount: number, averageDuration: number }[], averageDuration: number, + maxDuration: number, startDate: Date, endDate: Date, crewCount: number; @@ -28,9 +29,9 @@ export async function voyageRawByRange(startDate?: Date, endDate?: Date, crewMat startDate = new Date(endDate.getTime()); startDate.setDate(startDate.getDate() - 7); } - let results: Voyage[] | undefined = undefined; - if (crewMatch) { - results = await Voyage.findAll({ + let results: Voyage[] | undefined = undefined; + if (crewMatch) { + results = await Voyage.findAll({ where: { [Op.and]: [ { @@ -58,7 +59,7 @@ export async function voyageRawByRange(startDate?: Date, endDate?: Date, crewMat }); } else { - results = await Voyage.findAll({ + results = await Voyage.findAll({ where: { voyageDate: { [Op.and]: [ @@ -78,43 +79,43 @@ export async function getVoyageStats(sqlconn?: string, filename?: string) { return new Promise<{ [key: string]: Voyager[] }>((resolve, reject) => { filename ??= "snapshot.sqlite" sqlconn ??= process.env.DB_CONNECTION_STRING as string; - + let n = sqlconn.indexOf("/"); sqlconn = sqlconn.slice(n); let sqlfile = sqlconn; - + n = sqlconn.lastIndexOf("/"); - sqlconn = sqlconn.slice(0, n); + sqlconn = sqlconn.slice(0, n); let histfile = sqlconn + "/" + filename; - + sqlfile = sqlfile.replace(/\/\//g, '/'); histfile = histfile.replace(/\/\//g, '/'); - - let proc = exec(`flock ${sqlfile} cp ${sqlfile} ${histfile}`); + + let proc = exec(`flock ${sqlfile} cp ${sqlfile} ${histfile}`); proc.on('exit', async (code, signal) => { - + let sql = new Sequelize(`sqlite:${histfile}`, { models: [Historical], logging: false, repositoryMode: true }); - + if (sql) { await sql.sync(); const repo = sql.getRepository(Historical); - let results = await internalgetVoyageStats(repo); + let results = await internalgetVoyageStats(repo); resolve(results); } else { reject(new Error("Could not connect to database")); } - }); + }); }); } function parseQuipment(data: (number[] | 0)[]) { - + const quipment = [] as number[][]; for (let q of data) { @@ -143,38 +144,38 @@ function addQuipment(quipment: number[], current?: { [key: string]: number }) { return current; } -async function internalgetVoyageStats(Table: Repository) { +async function internalgetVoyageStats(Table: Repository) { const oneYearAgo = new Date(Date.now() - 365 * 24 * 60 * 60 * 1000); const seats = [ - 'command_skill', - 'command_skill', - 'diplomacy_skill', - 'diplomacy_skill', - 'security_skill', - 'security_skill', - 'engineering_skill', - 'engineering_skill', - 'science_skill', - 'science_skill', + 'command_skill', + 'command_skill', + 'diplomacy_skill', + 'diplomacy_skill', + 'security_skill', + 'security_skill', + 'engineering_skill', + 'engineering_skill', + 'science_skill', + 'science_skill', 'medicine_skill', - 'medicine_skill' + 'medicine_skill' ]; const shortNames = { - 'command_skill': 'CMD', - 'diplomacy_skill': 'DIP', - 'security_skill': 'SEC', - 'engineering_skill': 'ENG', - 'science_skill': 'SCI', + 'command_skill': 'CMD', + 'diplomacy_skill': 'DIP', + 'security_skill': 'SEC', + 'engineering_skill': 'ENG', + 'science_skill': 'SCI', 'medicine_skill': 'MED', } as { [key: string]: string }; - const records = await Table.findAll({ - where: { - voyageDate: { - [Op.gte]: oneYearAgo + const records = await Table.findAll({ + where: { + voyageDate: { + [Op.gte]: oneYearAgo } }, - lock: true + lock: true }); const output = {} as { [key: string]: Voyager[] }; @@ -202,19 +203,19 @@ async function internalgetVoyageStats(Table: Repository) { for (let dset of dsets) { let { date: d, file: fn } = dset; console.log(`From ${d} as '${fn}'...`); - + let rangeraw = records.filter(r => r.voyageDate.getTime() >= dset.date.getTime()); let dmap = {} as { [key: string]: Historical }; for (let item of rangeraw) { dmap[item.voyageDate.getTime().toString()] = item; } - + let results = Object.values(dmap); const cp = {} as { [key: string]: Voyager }; - + for (let res of results) { let seat = 0; - + let pri = res.primary_skill; let sec = res.secondary_skill; let prisec = '/'; @@ -226,8 +227,8 @@ async function internalgetVoyageStats(Table: Repository) { if (!res.estimatedDuration) continue; let quipment = [] as number[][] - - if (res.extra_stats && + + if (res.extra_stats && res.extra_stats.quipment) { quipment = parseQuipment(res.extra_stats.quipment); } @@ -244,11 +245,12 @@ async function internalgetVoyageStats(Table: Repository) { crewSymbol: c, seats: [], averageDuration: 0, + maxDuration: 0, startDate: res.voyageDate, endDate: res.voyageDate, crewCount: 0, quipmentCounts: addQuipment(currQuip), - voyageTypes: {} + voyageTypes: {} }; if (prisec !== '/') { cp[c].voyageTypes[prisec] ??= 0; @@ -259,7 +261,13 @@ async function internalgetVoyageStats(Table: Repository) { cp[c].endDate = res.voyageDate; let cseatcount = cp[c].seats.reduce((p, n) => p ? p + n.crewCount : n.crewCount, 0); cp[c].averageDuration = ((cp[c].averageDuration * cseatcount) + res.estimatedDuration) / (cseatcount + 1); + + if (cp[c].maxDuration < res.estimatedDuration) { + cp[c].maxDuration = res.estimatedDuration; + } + let currseat = cp[c].seats.find(s => s.seat_skill === seats[seat]); + if (currseat) { currseat.averageDuration = ((currseat.averageDuration * currseat.crewCount) + res.estimatedDuration) / (currseat.crewCount + 1); currseat.crewCount++;