395 lines
8.8 KiB
JavaScript
395 lines
8.8 KiB
JavaScript
import fs from 'fs';
|
|
import readline from 'readline';
|
|
|
|
import { PIXELLOGGER_PREFIX } from './logger';
|
|
import { getNamesToIds } from '../data/sql/RegUser';
|
|
import {
|
|
getIdsToIps,
|
|
getInfoToIps,
|
|
getIPofIID,
|
|
} from '../data/sql/IPInfo';
|
|
import { getIPv6Subnet } from '../utils/ip';
|
|
|
|
|
|
function parseFile(cb) {
|
|
const date = new Date();
|
|
const year = date.getUTCFullYear();
|
|
let month = date.getUTCMonth() + 1;
|
|
let day = date.getUTCDate();
|
|
if (day < 10) day = `0${day}`;
|
|
if (month < 10) month = `0${month}`;
|
|
const filename = `${PIXELLOGGER_PREFIX}${year}-${month}-${day}.log`;
|
|
|
|
return new Promise((resolve, reject) => {
|
|
const fileStream = fs.createReadStream(filename);
|
|
|
|
const rl = readline.createInterface({
|
|
input: fileStream,
|
|
});
|
|
|
|
rl.on('line', (line) => cb(line.split(' ')));
|
|
|
|
rl.on('error', (err) => {
|
|
reject(err);
|
|
});
|
|
|
|
rl.on('close', () => {
|
|
resolve();
|
|
});
|
|
});
|
|
}
|
|
|
|
/*
|
|
* Get summary of pixels per canvas placed by iid
|
|
* @param iid Limit on one user (optional)
|
|
* @param time timestamp of when to start
|
|
* @return array of parsed pixel log lines
|
|
* string if error
|
|
*/
|
|
export async function getIIDSummary(
|
|
iid,
|
|
time,
|
|
) {
|
|
const filterIP = await getIPofIID(iid);
|
|
if (!filterIP) {
|
|
return 'Could not resolve IID to IP';
|
|
}
|
|
const cids = {};
|
|
|
|
try {
|
|
await parseFile((parts) => {
|
|
const [tsStr, ipFull,, cid, x, y,, clrStr] = parts;
|
|
const ts = parseInt(tsStr, 10);
|
|
if (ts >= time) {
|
|
const ip = getIPv6Subnet(ipFull);
|
|
if (ip === filterIP) {
|
|
const clr = parseInt(clrStr, 10);
|
|
let curVals = cids[cid];
|
|
if (!curVals) {
|
|
curVals = [0, 0, 0, 0, 0];
|
|
cids[cid] = curVals;
|
|
}
|
|
curVals[0] += 1;
|
|
curVals[1] = x;
|
|
curVals[2] = y;
|
|
curVals[3] = clr;
|
|
curVals[4] = ts;
|
|
}
|
|
}
|
|
});
|
|
} catch (err) {
|
|
return `Could not parse logfile: ${err.message}`;
|
|
}
|
|
|
|
const columns = ['rid', '#', 'canvas', 'last', 'clr', 'time'];
|
|
const types = ['number', 'number', 'cid', 'coord', 'clr', 'ts'];
|
|
const rows = [];
|
|
const cidKeys = Object.keys(cids);
|
|
for (let i = 0; i < cidKeys.length; i += 1) {
|
|
const cid = cidKeys[i];
|
|
const [pxls, x, y, clr, ts] = cids[cid];
|
|
rows.push([
|
|
i,
|
|
pxls,
|
|
cid,
|
|
`${x},${y}`,
|
|
clr,
|
|
ts,
|
|
]);
|
|
}
|
|
|
|
return {
|
|
columns,
|
|
types,
|
|
rows,
|
|
};
|
|
}
|
|
|
|
/*
|
|
* Get pixels by iid
|
|
* @param iid Limit on one user (optional)
|
|
* @param time timestamp of when to start
|
|
* @return array of parsed pixel log lines
|
|
* string if error
|
|
*/
|
|
export async function getIIDPixels(
|
|
iid,
|
|
time,
|
|
maxRows = 300,
|
|
) {
|
|
const filterIP = await getIPofIID(iid);
|
|
if (!filterIP) {
|
|
return 'Could not resolve IID to IP';
|
|
}
|
|
const pixels = [];
|
|
|
|
try {
|
|
await parseFile((parts) => {
|
|
const [tsStr, ipFull,, cid, x, y,, clrStr] = parts;
|
|
const ts = parseInt(tsStr, 10);
|
|
if (ts >= time) {
|
|
const ip = getIPv6Subnet(ipFull);
|
|
if (ip === filterIP) {
|
|
const clr = parseInt(clrStr, 10);
|
|
pixels.push([
|
|
cid,
|
|
x,
|
|
y,
|
|
clr,
|
|
ts,
|
|
]);
|
|
}
|
|
}
|
|
});
|
|
} catch (err) {
|
|
return `Could not parse logfile: ${err.message}`;
|
|
}
|
|
|
|
const pixelF = (pixels.length > maxRows)
|
|
? pixels.slice(maxRows * -1)
|
|
: pixels;
|
|
|
|
const columns = ['rid', 'canvas', 'coord', 'clr', 'time'];
|
|
const types = ['number', 'cid', 'coord', 'clr', 'ts'];
|
|
const rows = [];
|
|
for (let i = 0; i < pixelF.length; i += 1) {
|
|
const [cid, x, y, clr, ts] = pixelF[i];
|
|
rows.push([
|
|
i,
|
|
cid,
|
|
`${x},${y}`,
|
|
clr,
|
|
ts,
|
|
]);
|
|
}
|
|
|
|
return {
|
|
columns,
|
|
types,
|
|
rows,
|
|
};
|
|
}
|
|
|
|
/*
|
|
* Get summary of users placing in area of current day
|
|
* @param canvasId id of canvas
|
|
* @param xUL, yUL, xBR, yBR area of canvas
|
|
* @param time timestamp of when to start
|
|
* @param iid Limit on one user (optional)
|
|
* @return array of parsed pixel log lines
|
|
* string if error
|
|
*/
|
|
export async function getSummaryFromArea(
|
|
canvasId,
|
|
xUL,
|
|
yUL,
|
|
xBR,
|
|
yBR,
|
|
time,
|
|
iid,
|
|
) {
|
|
const ips = {};
|
|
const uids = [];
|
|
let filterIP = null;
|
|
if (iid) {
|
|
filterIP = await getIPofIID(iid);
|
|
if (!filterIP) {
|
|
return 'Could not resolve IID to IP';
|
|
}
|
|
}
|
|
try {
|
|
await parseFile((parts) => {
|
|
const [tsStr, ipFull, uidStr, cid, x, y,, clrStr] = parts;
|
|
const ts = parseInt(tsStr, 10);
|
|
if (ts >= time
|
|
// eslint-disable-next-line eqeqeq
|
|
&& canvasId == cid
|
|
&& x >= xUL
|
|
&& x <= xBR
|
|
&& y >= yUL
|
|
&& y <= yBR
|
|
) {
|
|
const ip = getIPv6Subnet(ipFull);
|
|
if (filterIP && ip !== filterIP) {
|
|
return;
|
|
}
|
|
const clr = parseInt(clrStr, 10);
|
|
const uid = parseInt(uidStr, 10);
|
|
let curVals = ips[ip];
|
|
if (!curVals) {
|
|
curVals = [0, uid, 0, 0, 0, 0];
|
|
ips[ip] = curVals;
|
|
uids.push(uid);
|
|
}
|
|
curVals[0] += 1;
|
|
curVals[2] = x;
|
|
curVals[3] = y;
|
|
curVals[4] = clr;
|
|
curVals[5] = ts;
|
|
}
|
|
});
|
|
} catch (err) {
|
|
return `Could not parse logfile: ${err.message}`;
|
|
}
|
|
|
|
const uid2Name = await getNamesToIds(uids);
|
|
|
|
const ipKeys = Object.keys(ips);
|
|
const ip2Info = await getInfoToIps(ipKeys);
|
|
|
|
let printIIDs = false;
|
|
let printUsers = false;
|
|
const columns = ['rid', '#'];
|
|
const types = ['number', 'number'];
|
|
if (ip2Info.size > 0) {
|
|
printIIDs = true;
|
|
columns.push('IID', 'ct', 'cidr', 'org', 'pc');
|
|
types.push('uuid', 'flag', 'cidr', 'string', 'string');
|
|
}
|
|
if (uid2Name.size > 0) {
|
|
printUsers = true;
|
|
columns.push('User');
|
|
types.push('user');
|
|
}
|
|
columns.push('last', 'clr', 'time');
|
|
types.push('coord', 'clr', 'ts');
|
|
|
|
const rows = [];
|
|
for (let i = 0; i < ipKeys.length; i += 1) {
|
|
const ip = ipKeys[i];
|
|
const [pxls, uid, x, y, clr, ts] = ips[ip];
|
|
const row = [i, pxls];
|
|
if (printIIDs) {
|
|
const ipInfo = ip2Info.get(ip);
|
|
if (!ipInfo) {
|
|
row.push('N/A', 'xx', 'N/A', 'N/A', 'N/A');
|
|
} else {
|
|
let { pcheck } = ipInfo;
|
|
if (pcheck) {
|
|
const separator = pcheck.indexOf(',');
|
|
if (separator !== -1) {
|
|
pcheck = pcheck.slice(0, separator);
|
|
}
|
|
}
|
|
row.push(
|
|
ipInfo.uuid,
|
|
ipInfo.country,
|
|
ipInfo.cidr,
|
|
ipInfo.org || 'N/A',
|
|
pcheck || 'N/A',
|
|
);
|
|
}
|
|
}
|
|
if (printUsers) {
|
|
const userMd = (uid && uid2Name.has(uid))
|
|
? `${uid2Name.get(uid)},${uid}` : 'N/A';
|
|
row.push(userMd);
|
|
}
|
|
row.push(`${x},${y}`, clr, ts);
|
|
rows.push(row);
|
|
}
|
|
|
|
return {
|
|
columns,
|
|
types,
|
|
rows,
|
|
};
|
|
}
|
|
|
|
|
|
export async function getPixelsFromArea(
|
|
canvasId,
|
|
xUL,
|
|
yUL,
|
|
xBR,
|
|
yBR,
|
|
time,
|
|
iid,
|
|
maxRows = 300,
|
|
) {
|
|
const pixels = [];
|
|
const uids = [];
|
|
const ips = [];
|
|
let filterIP = null;
|
|
if (iid) {
|
|
filterIP = await getIPofIID(iid);
|
|
if (!filterIP) {
|
|
return 'Could not resolve IID to IP';
|
|
}
|
|
}
|
|
try {
|
|
await parseFile((parts) => {
|
|
const [tsStr, ipFull, uidStr, cid, x, y,, clrStr] = parts;
|
|
const ts = parseInt(tsStr, 10);
|
|
if (ts >= time
|
|
// eslint-disable-next-line eqeqeq
|
|
&& canvasId == cid
|
|
&& x >= xUL
|
|
&& x <= xBR
|
|
&& y >= yUL
|
|
&& y <= yBR
|
|
) {
|
|
const ip = getIPv6Subnet(ipFull);
|
|
if (filterIP && ip !== filterIP) {
|
|
return;
|
|
}
|
|
const clr = parseInt(clrStr, 10);
|
|
const uid = parseInt(uidStr, 10);
|
|
pixels.push([ip, uid, x, y, clr, ts]);
|
|
if (!ips.includes(ip)) {
|
|
ips.push(ip);
|
|
uids.push(uid);
|
|
}
|
|
}
|
|
});
|
|
} catch (err) {
|
|
return `Could not parse logfile: ${err.message}`;
|
|
}
|
|
|
|
const uid2Name = await getNamesToIds(uids);
|
|
const ip2Id = await getIdsToIps(ips);
|
|
|
|
const pixelF = (pixels.length > maxRows)
|
|
? pixels.slice(maxRows * -1)
|
|
: pixels;
|
|
|
|
let printIIDs = false;
|
|
let printUsers = false;
|
|
const columns = ['rid'];
|
|
const types = ['number'];
|
|
if (!filterIP && ip2Id.size > 0) {
|
|
printIIDs = true;
|
|
columns.push('IID');
|
|
types.push('uuid');
|
|
}
|
|
if (!filterIP && uid2Name.size > 0) {
|
|
printUsers = true;
|
|
columns.push('User');
|
|
types.push('user');
|
|
}
|
|
columns.push('coord', 'clr', 'time');
|
|
types.push('coord', 'clr', 'ts');
|
|
|
|
const rows = [];
|
|
for (let i = 0; i < pixelF.length; i += 1) {
|
|
const [ip, uid, x, y, clr, ts] = pixelF[i];
|
|
const row = [i];
|
|
if (printIIDs) {
|
|
row.push(ip2Id.get(ip) || 'N/A');
|
|
}
|
|
if (printUsers) {
|
|
const userMd = (uid && uid2Name.has(uid))
|
|
? `${uid2Name.get(uid)},${uid}` : 'N/A';
|
|
row.push(userMd);
|
|
}
|
|
row.push(`${x},${y}`, clr, ts);
|
|
rows.push(row);
|
|
}
|
|
|
|
return {
|
|
columns,
|
|
types,
|
|
rows,
|
|
};
|
|
}
|