goat
command
update
No description
0
views
0
likes
0
installs
Aliases: gitupdate, selfupdate
raw source
const fs = require("fs-extra");
const path = require("path");
const {
checkAndSelfUpdate,
getPendingUpdate,
applyPendingUpdate
} = require("../../includes/rX/autoUpdate.js");
const { startBackgroundUpdateChecker, CONFIRM_EMOJIS } = require("../../includes/rX/updateNotifier.js");
module.exports = {
config: {
name: "update",
aliases: ["gitupdate", "selfupdate"],
version: "2.0",
author: "EryXenX",
countDown: 10,
role: 1,
category: "owner",
description: {
vi: "Kiểm tra và tự động cập nhật bot từ GitHub repo (config.json > gitUpdate)",
en: "Check config.json > gitUpdate.url on GitHub and self-update the bot if a newer version exists"
},
guide: {
vi: " {pn}: Áp dụng bản cập nhật đã tải sẵn (nếu có), hoặc kiểm tra + cập nhật ngay",
en: " {pn}: Applies an already-downloaded update if one is staged, otherwise checks for and applies the latest update right away"
}
},
langs: {
vi: {
notAdmin: "🚫 | Chỉ admin bot mới có thể dùng lệnh này.",
checking: "🔍 | Đang kiểm tra bản cập nhật...",
applyingStaged: "📦 | Đã có bản cập nhật v%1 tải sẵn. Đang áp dụng...",
upToDate: "✅ | Bot đã ở phiên bản mới nhất (v%1).",
noRepo: "⚠ | Chưa cấu hình repo GitHub. Vui lòng đặt config.json > gitUpdate.url.",
error: "💥 | Kiểm tra cập nhật thất bại:\n%1",
reactionApplying: "📦 | Đã xác nhận! Đang áp dụng bản cập nhật v%1...",
reactionNotAdmin: "🚫 | Chỉ admin bot mới có thể xác nhận cập nhật.",
},
en: {
notAdmin: "🚫 | This command is restricted to bot admins only.",
checking: "🔍 | Checking for updates...",
applyingStaged: "📦 | Version v%1 was already downloaded in the background. Applying it now...",
upToDate: "✅ | Bot is already up to date (v%1).",
noRepo: "⚠ | No GitHub repo configured. Set config.json > gitUpdate.url first.",
error: "💥 | Update check failed:\n%1",
reactionApplying: "📦 | Confirmed! Applying update v%1 now...",
reactionNotAdmin: "🚫 | Only bot admins can confirm an update.",
}
},
onLoad({ api }) {
const tmpDir = path.join(__dirname, "tmp");
if (!fs.existsSync(tmpDir)) fs.mkdirSync(tmpDir);
const pathFile = path.join(tmpDir, "update.txt");
if (fs.existsSync(pathFile)) {
setTimeout(() => {
try {
const [tid, , fromVersion, toVersion] = fs.readFileSync(pathFile, "utf-8").split(" ");
api.sendMessage(`✅ | Update applied: v${fromVersion} → v${toVersion}.\n🔄 | Bot restarted successfully and is back online.`, tid);
fs.unlinkSync(pathFile);
} catch (e) {
console.error("Update notify error:", e);
}
}, 2000);
}
// Kick off the silent background update checker. This is fire-and-forget
// (setTimeout/setInterval only) so it never delays bot boot/login.
startBackgroundUpdateChecker({ api });
},
onStart: async function ({ message, event, getLang }) {
const admins = global.GoatBot?.config?.adminBot || [];
if (!admins.includes(event.senderID)) return message.reply(getLang("notAdmin"));
// Fast path: a version was already silently downloaded in the
// background — apply it directly instead of re-downloading.
const pending = getPendingUpdate(process.cwd());
if (pending) {
await message.reply(getLang("applyingStaged", pending.remoteVersion));
const result = await applyPendingUpdate(process.cwd(), { notifyThreadID: event.threadID });
// If applyPendingUpdate succeeded it already called process.exit(2);
// this line only runs if something went wrong.
if (!result?.applied) return message.reply(getLang("error", "Failed to apply the staged update."));
return;
}
await message.reply(getLang("checking"));
const result = await checkAndSelfUpdate(process.cwd(), {
notifyThreadID: event.threadID
});
// If an update was found and applied, checkAndSelfUpdate already wrote
// the restart marker and called process.exit(2) — this line is never
// reached in that case, the onLoad hook above reports back instead.
if (result?.error) return message.reply(getLang("error", result.error));
if (result?.noRepo) return message.reply(getLang("noRepo"));
return message.reply(getLang("upToDate", result?.localVersion || "?"));
},
// Fired when someone reacts to the "new version available" DM sent by the
// background checker (includes/rX/updateNotifier.js). Reacting ✅ (or a
// similar thumbs-up/confirm emoji) applies the already-staged update.
onReaction: async function ({ message, event, Reaction, getLang }) {
if (!Reaction || Reaction.type !== "confirmStagedUpdate") return;
const admins = global.GoatBot?.config?.adminBot || [];
if (!admins.includes(event.userID)) return message.reply(getLang("reactionNotAdmin"));
if (!CONFIRM_EMOJIS.includes(event.reaction)) {
// Any other reaction (e.g. ❌) is treated as "not now" — just drop it.
global.GoatBot.onReaction?.delete(event.messageID);
return;
}
global.GoatBot.onReaction?.delete(event.messageID);
const pending = getPendingUpdate(process.cwd());
if (!pending) return; // Nothing staged anymore (already applied or cleared)
await message.reply(getLang("reactionApplying", pending.remoteVersion));
await applyPendingUpdate(process.cwd(), { notifyThreadID: event.threadID });
}
};