v0.3.9.a2
Added experimental bot wrapper functionality for completely automated updates and restarts
This commit is contained in:
parent
9fcd55ec4b
commit
dee0c4a5b4
4
.gitignore
vendored
4
.gitignore
vendored
@ -10,3 +10,7 @@ data/
|
||||
data.json
|
||||
data.json.bak
|
||||
settings*.conf
|
||||
|
||||
# Tools
|
||||
wrapper/
|
||||
wrapper/tools/
|
53
bot.py
53
bot.py
@ -1,15 +1,14 @@
|
||||
import os
|
||||
import asyncio
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
from dotenv import load_dotenv
|
||||
from configparser import ConfigParser
|
||||
from data_manager import DataManager
|
||||
from modules.common.boot_notice import post_boot_notice
|
||||
import pathlib
|
||||
import os, asyncio, xml.etree.ElementTree as ET
|
||||
import os, signal, asyncio, xml.etree.ElementTree as ET
|
||||
import aiohttp
|
||||
|
||||
VERSION="0.0.9"
|
||||
VERSION="0.3.9.a2"
|
||||
|
||||
# ---------- Env & config loading ----------
|
||||
|
||||
@ -130,6 +129,33 @@ async def _fetch_latest_from_rss(url: str):
|
||||
|
||||
# ---------- boot notice ----------
|
||||
|
||||
async def _maybe_post_boot_notice(bot):
|
||||
status = os.getenv("SHAI_BOOT_STATUS", "")
|
||||
if not status:
|
||||
return
|
||||
desc = os.getenv("SHAI_BOOT_DESC", "")
|
||||
old_v = os.getenv("SHAI_BOOT_OLD", "")
|
||||
new_v = os.getenv("SHAI_BOOT_NEW", "")
|
||||
|
||||
if status == "fetched_new":
|
||||
line = f"Successfully fetched, cached, and booted new version: v{old_v or '0.0.0.0'} -> v{new_v}"
|
||||
elif status == "cached_no_update":
|
||||
line = f"Successfully booted from cached version: v{new_v}. No new update found"
|
||||
else:
|
||||
line = f"Successfully booted from cached version: v{new_v}. Program repository not accessible!"
|
||||
|
||||
ch_id = int(bot.config['DEFAULT'].get('modlog_channel_id', "0") or 0)
|
||||
ch = None
|
||||
for g in bot.guilds:
|
||||
ch = g.get_channel(ch_id)
|
||||
if ch: break
|
||||
if ch:
|
||||
try:
|
||||
msg = line if not desc else f"{line}\n_{desc}_"
|
||||
await ch.send(msg, allowed_mentions=discord.AllowedMentions.none())
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
async def _post_boot_notice():
|
||||
|
||||
msg = f"Self-update and reboot successful! (v.{VERSION})"
|
||||
@ -176,8 +202,11 @@ async def on_ready():
|
||||
except Exception as e:
|
||||
print("[Slash] Sync failed:", repr(e))
|
||||
|
||||
# Boot notice in modlog
|
||||
await _post_boot_notice()
|
||||
# Post BSM if present
|
||||
try:
|
||||
await post_boot_notice(bot)
|
||||
except Exception as e:
|
||||
print("[BootNotice] failed:", repr(e))
|
||||
|
||||
# ---------- Auto-discover extensions ----------
|
||||
|
||||
@ -190,6 +219,16 @@ for folder in modules_path.iterdir():
|
||||
continue
|
||||
extensions.append(f"modules.{folder.name}.{file.stem}")
|
||||
|
||||
def _install_signal_handlers(loop, bot):
|
||||
def _graceful(*_):
|
||||
# ask discord.py to close cleanly
|
||||
loop.create_task(bot.close())
|
||||
for s in (signal.SIGTERM, signal.SIGINT):
|
||||
try:
|
||||
loop.add_signal_handler(s, _graceful)
|
||||
except NotImplementedError:
|
||||
pass # Windows
|
||||
|
||||
async def main():
|
||||
async with bot:
|
||||
for ext in extensions:
|
||||
@ -198,6 +237,8 @@ async def main():
|
||||
print(f"[Modules] Loaded: {ext}")
|
||||
except Exception as e:
|
||||
print(f"[Modules] Failed to load {ext}:", repr(e))
|
||||
loop = asyncio.get_running_loop()
|
||||
_install_signal_handlers(loop, bot)
|
||||
await bot.start(TOKEN)
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
45
modules/common/boot_notice.py
Normal file
45
modules/common/boot_notice.py
Normal file
@ -0,0 +1,45 @@
|
||||
# modules/common/boot_notice.py
|
||||
import os
|
||||
import time
|
||||
import discord
|
||||
|
||||
async def post_boot_notice(bot: discord.Client):
|
||||
# Needs modlog_channel_id in config/env
|
||||
cfg = bot.config['DEFAULT']
|
||||
ch_raw = cfg.get('modlog_channel_id') or os.getenv('SHAI_MODLOG_CHANNEL_ID')
|
||||
if not ch_raw:
|
||||
return
|
||||
try:
|
||||
ch_id = int(ch_raw)
|
||||
except Exception:
|
||||
return
|
||||
ch = None
|
||||
for g in bot.guilds:
|
||||
ch = g.get_channel(ch_id)
|
||||
if ch:
|
||||
break
|
||||
if not ch:
|
||||
return
|
||||
|
||||
status = os.getenv("SHAI_BOOT_STATUS", "").strip()
|
||||
oldver = os.getenv("SHAI_BOOT_OLDVER", "").strip()
|
||||
newver = os.getenv("SHAI_BOOT_NEWVER", "").strip()
|
||||
commit = os.getenv("SHAI_BUILD_COMMIT", "").strip()
|
||||
subject = os.getenv("SHAI_BUILD_SUBJECT", "").strip()
|
||||
|
||||
if not status:
|
||||
return
|
||||
|
||||
parts = [f"**Boot**: {status}"]
|
||||
if oldver or newver:
|
||||
parts.append(f"**Version**: {oldver or '?'} → {newver or '?'}")
|
||||
if commit:
|
||||
parts.append(f"**Commit**: `{commit}`")
|
||||
if subject and len(subject) > 5:
|
||||
parts.append(f"**Note**: {subject}")
|
||||
|
||||
msg = " | ".join(parts) + f" — <t:{int(time.time())}:R>"
|
||||
try:
|
||||
await ch.send(msg, allowed_mentions=discord.AllowedMentions.none())
|
||||
except Exception:
|
||||
pass
|
@ -87,6 +87,10 @@ class NickNudgeCog(commands.Cog):
|
||||
"""
|
||||
if not guild:
|
||||
return
|
||||
# If a pending review already exists for this user in this guild, do nothing
|
||||
for r in self.bot.data_manager.get('nick_reviews'):
|
||||
if r.get('guild_id') == guild.id and r.get('user_id') == member.id and r.get('status') == 'pending':
|
||||
return
|
||||
mod_ch = guild.get_channel(self.mod_channel_id)
|
||||
if not mod_ch:
|
||||
return
|
||||
|
Loading…
Reference in New Issue
Block a user