mirror of
https://github.com/migatu/conjurer.git
synced 2026-07-14 21:38:38 +00:00
Land prototype on main (fix stacked-PR retarget gap)
PRs #10 and #11 were merged into their intermediate base branches (restructure/working-copy-root and proto-improvements) rather than main, because the stacked PRs' bases were not auto-retargeted (the branches were not deleted on merge). As a result main only received the #9 restructure and is still the plain working-copy bot. This brings the full prototype onto main as a clean delta on top of the current main tree (identical content to proto-improvements, but with main ancestry so it merges without the squash-induced rename/delete conflicts): - constants.py: env-var config, safe JSON loading, dependency guards, env->netrc tokens, API_SHARED_KEY + service_headers(), CONAN_* config - communication_subroutine.py: queue timeout/Empty, daemon threads, cooperative stop_event, inbound _authorize_request() - bot.py: asyncio event loop + load conanjurer_commands - music_functions / radio_commands / librarian_commands: X-Conjurer-Api-Key - conanjurer_commands/_functions: fixed + integrated bridge with RCON player-join notifications - requirements_bot.txt: aiomcrcon, asyncssh - conjurer_musician/.gitignore: keep runtime playlists/mp3 out of the repo Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
"""
|
||||
Module of a python bot named Conjurer - used to work on BDSM discord servers.
|
||||
"""
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
# *=========================================== Standard Library Imports
|
||||
@@ -70,6 +71,7 @@ async def on_ready():
|
||||
await client.load_extension("voice_recognition_commands")
|
||||
await client.load_extension("file_search_commands")
|
||||
await client.load_extension("latex_commands")
|
||||
await client.load_extension("conanjurer_commands")
|
||||
logger.info("Sensors: online")
|
||||
|
||||
logger.info(client.cogs)
|
||||
@@ -82,22 +84,52 @@ async def on_ready():
|
||||
logger.info("All systems: operational")
|
||||
|
||||
|
||||
# *=========================================== Runtime orchestration
|
||||
# The legacy bootstrap used two bare threads (client.run + comm_subroutine) and
|
||||
# joined them, which made a clean shutdown impossible. We now drive everything
|
||||
# from a single asyncio loop: the Flask comm layer still runs in its own
|
||||
# threads (via asyncio.to_thread) but is steered through a shared stop_event so
|
||||
# the bot can stop both halves cooperatively.
|
||||
|
||||
|
||||
async def _run_comm_subroutine(stop_event: threading.Event) -> None:
|
||||
"""Run the blocking comm subroutine in a worker thread."""
|
||||
await asyncio.to_thread(comm_subroutine, stop_event)
|
||||
|
||||
|
||||
async def _run_bot(token: str, shutdown_event: asyncio.Event) -> None:
|
||||
"""Start the Discord client and flag shutdown when it returns."""
|
||||
try:
|
||||
await client.start(token, log_handler=None)
|
||||
finally:
|
||||
shutdown_event.set()
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
if not TOKEN:
|
||||
logger.error("Discord token missing - set DISCORD_TOKEN or configure netrc")
|
||||
return
|
||||
|
||||
logger.info("Starting discord bot")
|
||||
shutdown_event = asyncio.Event()
|
||||
comm_stop_event = threading.Event()
|
||||
|
||||
comm_task = asyncio.create_task(_run_comm_subroutine(comm_stop_event))
|
||||
bot_task = asyncio.create_task(_run_bot(TOKEN, shutdown_event))
|
||||
|
||||
try:
|
||||
await shutdown_event.wait()
|
||||
except (KeyboardInterrupt, asyncio.CancelledError):
|
||||
logger.info("Shutdown signal received")
|
||||
comm_stop_event.set()
|
||||
await client.close()
|
||||
finally:
|
||||
comm_stop_event.set()
|
||||
if not client.is_closed():
|
||||
await client.close()
|
||||
await asyncio.gather(bot_task, comm_task, return_exceptions=True)
|
||||
|
||||
|
||||
# *================================== Run
|
||||
if __name__ == "__main__":
|
||||
logger.info("Starting discord bot")
|
||||
threads = []
|
||||
logger.info("Starting discord bot: Creating threads")
|
||||
threads.append(threading.Thread(target=client.run, args=(TOKEN,),kwargs={"log_handler":None}))
|
||||
threads.append(threading.Thread(target=comm_subroutine))
|
||||
logger.info("Starting discord bot: Starting threads")
|
||||
WRK_CNT = 0
|
||||
for worker in threads:
|
||||
WRK_CNT += 1
|
||||
logger.info("Starting discord bot: Starting thread %s", WRK_CNT)
|
||||
worker.start()
|
||||
logger.info("Starting discord bot: Joining threads")
|
||||
WRK_CNT = 0
|
||||
for worker in threads:
|
||||
WRK_CNT += 1
|
||||
logger.info("Starting discord bot: Joining thread %s", WRK_CNT)
|
||||
worker.join()
|
||||
asyncio.run(main())
|
||||
|
||||
Reference in New Issue
Block a user