Jofthomas's picture
Jofthomas HF staff
Upload 4781 files
5c2ed06 verified
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var roomlogs_exports = {};
__export(roomlogs_exports, {
Roomlog: () => Roomlog,
Roomlogs: () => Roomlogs,
roomlogDB: () => roomlogDB,
roomlogTable: () => roomlogTable
});
module.exports = __toCommonJS(roomlogs_exports);
var import_lib = require("../lib");
var import_database = require("../lib/database");
/**
* Roomlogs
* Pokemon Showdown - http://pokemonshowdown.com/
*
* This handles data storage for rooms.
*
* @license MIT
*/
const roomlogDB = (() => {
if (!global.Config || !Config.replaysdb || Config.disableroomlogdb)
return null;
return new import_database.PGDatabase(Config.replaysdb);
})();
const roomlogTable = roomlogDB?.getTable("roomlogs");
class Roomlog {
constructor(room, options = {}) {
this.visibleMessageCount = 0;
this.roomid = room.roomid;
this.isMultichannel = !!options.isMultichannel;
this.noAutoTruncate = !!options.noAutoTruncate;
this.noLogTimes = !!options.noLogTimes;
this.log = [];
this.broadcastBuffer = [];
this.roomlogStream = void 0;
this.roomlogFilename = "";
this.numTruncatedLines = 0;
this.setupRoomlogStream();
}
getScrollback(channel = 0) {
let log = this.log;
if (!this.noLogTimes)
log = [`|:|${~~(Date.now() / 1e3)}`].concat(log);
if (!this.isMultichannel) {
return log.join("\n") + "\n";
}
log = [];
for (let i = 0; i < this.log.length; ++i) {
const line = this.log[i];
const split = /\|split\|p(\d)/g.exec(line);
if (split) {
const canSeePrivileged = channel === Number(split[1]) || channel === -1;
const ownLine = this.log[i + (canSeePrivileged ? 1 : 2)];
if (ownLine)
log.push(ownLine);
i += 2;
} else {
log.push(line);
}
}
return log.join("\n") + "\n";
}
setupRoomlogStream() {
if (this.roomlogStream === null)
return;
if (!Config.logchat || this.roomid.startsWith("battle-") || this.roomid.startsWith("game-")) {
this.roomlogStream = null;
return;
}
if (roomlogTable) {
this.roomlogTable = roomlogTable;
this.roomlogStream = null;
return;
}
const date = new Date();
const dateString = Chat.toTimestamp(date).split(" ")[0];
const monthString = dateString.split("-", 2).join("-");
const basepath = `chat/${this.roomid}/`;
const relpath = `${monthString}/${dateString}.txt`;
if (relpath === this.roomlogFilename)
return;
Monitor.logPath(basepath + monthString).mkdirpSync();
this.roomlogFilename = relpath;
if (this.roomlogStream)
void this.roomlogStream.writeEnd();
this.roomlogStream = Monitor.logPath(basepath + relpath).createAppendStream();
const link0 = basepath + "today.txt.0";
Monitor.logPath(link0).unlinkIfExistsSync();
try {
Monitor.logPath(link0).symlinkToSync(relpath);
Monitor.logPath(link0).renameSync(basepath + "today.txt");
} catch {
}
if (!Roomlogs.rollLogTimer)
Roomlogs.rollLogs();
}
add(message) {
this.roomlog(message);
if (["|c|", "|c:|", "|raw|", "|html|", "|uhtml"].some((k) => message.startsWith(k))) {
this.visibleMessageCount++;
}
message = this.withTimestamp(message);
this.log.push(message);
this.broadcastBuffer.push(message);
return this;
}
withTimestamp(message) {
if (!this.noLogTimes && message.startsWith("|c|")) {
return `|c:|${Math.trunc(Date.now() / 1e3)}|${message.slice(3)}`;
} else {
return message;
}
}
hasUsername(username) {
const userid = toID(username);
for (const line of this.log) {
if (line.startsWith("|c:|")) {
const curUserid = toID(line.split("|", 4)[3]);
if (curUserid === userid)
return true;
} else if (line.startsWith("|c|")) {
const curUserid = toID(line.split("|", 3)[2]);
if (curUserid === userid)
return true;
}
}
return false;
}
clearText(userids, lineCount = 0) {
const cleared = [];
const clearAll = lineCount === 0;
this.log = this.log.reverse().filter((line) => {
const parsed = this.parseChatLine(line);
if (parsed) {
const userid = toID(parsed.user);
if (userids.includes(userid)) {
if (!cleared.includes(userid))
cleared.push(userid);
if (!this.roomlogStream && !this.roomlogTable)
return true;
if (clearAll)
return false;
if (lineCount > 0) {
lineCount--;
return false;
}
return true;
}
}
return true;
}).reverse();
return cleared;
}
uhtmlchange(name, message) {
const originalStart = "|uhtml|" + name + "|";
const fullMessage = originalStart + message;
for (const [i, line] of this.log.entries()) {
if (line.startsWith(originalStart)) {
this.log[i] = fullMessage;
break;
}
}
this.broadcastBuffer.push(fullMessage);
}
attributedUhtmlchange(user, name, message) {
const start = `/uhtmlchange ${name},`;
const fullMessage = this.withTimestamp(`|c|${user.getIdentity()}|${start}${message}`);
let matched = false;
for (const [i, line] of this.log.entries()) {
if (this.parseChatLine(line)?.message.startsWith(start)) {
this.log[i] = fullMessage;
matched = true;
break;
}
}
if (!matched)
this.log.push(fullMessage);
this.broadcastBuffer.push(fullMessage);
}
parseChatLine(line) {
const prefixes = [["|c:|", 4], ["|c|", 3]];
for (const [messageStart, section] of prefixes) {
if (line.startsWith(messageStart)) {
const parts = import_lib.Utils.splitFirst(line, "|", section);
return { user: parts[section - 1], message: parts[section] };
}
}
}
roomlog(message, date = new Date()) {
if (!Config.logchat)
return;
message = message.replace(/<img[^>]* src="data:image\/png;base64,[^">]+"[^>]*>/g, "[img]");
if (this.roomlogTable) {
const chatData = this.parseChatLine(message);
const type = message.split("|")[1] || "";
void this.insertLog(import_database.SQL`INSERT INTO roomlogs (${{
type,
roomid: this.roomid,
userid: toID(chatData?.user) || null,
time: import_database.SQL`now()`,
log: message
}})`);
const dateStr = Chat.toTimestamp(date).split(" ")[0];
void this.insertLog(import_database.SQL`INSERT INTO roomlog_dates (${{
roomid: this.roomid,
month: dateStr.slice(0, -3),
date: dateStr
}}) ON CONFLICT (roomid, date) DO NOTHING;`);
} else if (this.roomlogStream) {
const timestamp = Chat.toTimestamp(date).split(" ")[1] + " ";
void this.roomlogStream.write(timestamp + message + "\n");
}
}
async insertLog(query, ignoreFailure = false, retries = 3) {
try {
await this.roomlogTable?.query(query);
} catch (e) {
if (e?.code === "42P01") {
await roomlogDB._query((0, import_lib.FS)("databases/schemas/roomlogs.sql").readSync(), []);
return this.insertLog(query, ignoreFailure, retries);
}
if (!ignoreFailure && retries > 0 && e.message?.includes("Connection terminated unexpectedly")) {
await new Promise((resolve) => {
setTimeout(resolve, 2e3);
});
return this.insertLog(query, ignoreFailure, retries - 1);
}
const [q, vals] = roomlogDB._resolveSQL(query);
Monitor.crashlog(e, "a roomlog database query", {
query: q,
values: vals
});
}
}
modlog(entry, overrideID) {
void Rooms.Modlog.write(this.roomid, entry, overrideID);
}
async rename(newID) {
await Rooms.Modlog.rename(this.roomid, newID);
const roomlogStreamExisted = this.roomlogStream !== null;
await this.destroy();
if (this.roomlogTable) {
await this.roomlogTable.updateAll({ roomid: newID })`WHERE roomid = ${this.roomid}`;
} else {
const roomlogPath = `chat`;
const [roomlogExists, newRoomlogExists] = await Promise.all([
Monitor.logPath(roomlogPath + `/${this.roomid}`).exists(),
Monitor.logPath(roomlogPath + `/${newID}`).exists()
]);
if (roomlogExists && !newRoomlogExists) {
await Monitor.logPath(roomlogPath + `/${this.roomid}`).rename(Monitor.logPath(roomlogPath + `/${newID}`).path);
}
if (roomlogStreamExisted) {
this.roomlogStream = void 0;
this.roomlogFilename = "";
this.setupRoomlogStream();
}
}
Roomlogs.roomlogs.set(newID, this);
this.roomid = newID;
return true;
}
static rollLogs() {
if (Roomlogs.rollLogTimer === true)
return;
if (Roomlogs.rollLogTimer) {
clearTimeout(Roomlogs.rollLogTimer);
}
Roomlogs.rollLogTimer = true;
for (const log of Roomlogs.roomlogs.values()) {
log.setupRoomlogStream();
}
const time = Date.now();
const nextMidnight = new Date();
nextMidnight.setHours(24, 0, 0, 0);
Roomlogs.rollLogTimer = setTimeout(() => Roomlog.rollLogs(), nextMidnight.getTime() - time);
}
truncate() {
if (this.noAutoTruncate)
return;
if (this.log.length > 100) {
const truncationLength = this.log.length - 100;
this.log.splice(0, truncationLength);
this.numTruncatedLines += truncationLength;
}
}
/**
* Returns the total number of lines in the roomlog, including truncated lines.
*/
getLineCount(onlyVisible = true) {
return (onlyVisible ? this.visibleMessageCount : this.log.length) + this.numTruncatedLines;
}
destroy() {
const promises = [];
if (this.roomlogStream) {
promises.push(this.roomlogStream.writeEnd());
this.roomlogStream = null;
}
Roomlogs.roomlogs.delete(this.roomid);
return Promise.all(promises);
}
}
const roomlogs = /* @__PURE__ */ new Map();
function createRoomlog(room, options = {}) {
let roomlog = Roomlogs.roomlogs.get(room.roomid);
if (roomlog)
throw new Error(`Roomlog ${room.roomid} already exists`);
roomlog = new Roomlog(room, options);
Roomlogs.roomlogs.set(room.roomid, roomlog);
return roomlog;
}
const Roomlogs = {
create: createRoomlog,
Roomlog,
roomlogs,
db: roomlogDB,
table: roomlogTable,
rollLogs: Roomlog.rollLogs,
rollLogTimer: null
};
//# sourceMappingURL=roomlogs.js.map