fix: 채널 중복 생성 근본 수정 - 글로벌 락 + 이름 기반 검색 + API 새로고침
This commit is contained in:
44
bot.py
44
bot.py
@@ -125,7 +125,7 @@ class GravityBot(commands.Bot):
|
||||
self.session_channels: dict[str, discord.TextChannel] = {}
|
||||
self.session_status_messages: dict[str, int] = {}
|
||||
self.session_names: dict[str, str] = {}
|
||||
self._channel_locks: dict[str, asyncio.Lock] = {}
|
||||
self._channel_create_lock = asyncio.Lock() # SINGLE global lock
|
||||
self.bridge = BridgeProtocol()
|
||||
self.session_category: discord.CategoryChannel | None = None
|
||||
self.guild: discord.Guild | None = None
|
||||
@@ -156,23 +156,20 @@ class GravityBot(commands.Bot):
|
||||
logger.error("No permission to create category!")
|
||||
return
|
||||
|
||||
# ONLY reconnect to existing Discord channels (NO new channel creation)
|
||||
# ONLY reconnect to existing Discord channels (NO new creation)
|
||||
await self._reconnect_existing_channels()
|
||||
|
||||
async def _reconnect_existing_channels(self):
|
||||
"""Scan existing Discord channels and map them to conversation IDs.
|
||||
Does NOT create any new channels."""
|
||||
"""Scan existing Discord channels and map them to conversation IDs."""
|
||||
if not self.session_category:
|
||||
return
|
||||
|
||||
count = 0
|
||||
for ch in self.session_category.text_channels:
|
||||
if ch.topic and "Antigravity Session:" in ch.topic:
|
||||
# Extract conversation ID from topic
|
||||
conv_id = ch.topic.replace("Antigravity Session:", "").strip()
|
||||
if conv_id:
|
||||
self.session_channels[conv_id] = ch
|
||||
# Recover last task embed
|
||||
await self._recover_task_message(ch, conv_id)
|
||||
count += 1
|
||||
|
||||
@@ -181,7 +178,6 @@ class GravityBot(commands.Bot):
|
||||
async def _recover_task_message(
|
||||
self, channel: discord.TextChannel, conversation_id: str
|
||||
):
|
||||
"""Find last task embed in channel to reuse for editing."""
|
||||
if conversation_id in self.session_status_messages:
|
||||
return
|
||||
try:
|
||||
@@ -199,43 +195,37 @@ class GravityBot(commands.Bot):
|
||||
async def _ensure_channel(
|
||||
self, conversation_id: str, project_name: str
|
||||
) -> discord.TextChannel:
|
||||
"""Get or create a channel (thread-safe, single creation per session)."""
|
||||
"""Get or create a channel. Uses GLOBAL lock and NAME-based lookup."""
|
||||
# Fast path: already mapped
|
||||
if conversation_id in self.session_channels:
|
||||
ch = self.session_channels[conversation_id]
|
||||
# Rename back from "closed-" if needed
|
||||
expected = f"{Config.CHANNEL_PREFIX}-{project_name}".lower()
|
||||
if ch.name.startswith("closed-") and ch.name != expected:
|
||||
try:
|
||||
await ch.edit(name=f"{Config.CHANNEL_PREFIX}-{project_name}")
|
||||
except discord.errors.Forbidden:
|
||||
pass
|
||||
return ch
|
||||
return self.session_channels[conversation_id]
|
||||
|
||||
# Lock per conversation to prevent duplicates
|
||||
if conversation_id not in self._channel_locks:
|
||||
self._channel_locks[conversation_id] = asyncio.Lock()
|
||||
|
||||
async with self._channel_locks[conversation_id]:
|
||||
# Double-check
|
||||
async with self._channel_create_lock:
|
||||
# Double-check after lock
|
||||
if conversation_id in self.session_channels:
|
||||
return self.session_channels[conversation_id]
|
||||
|
||||
channel_name = f"{Config.CHANNEL_PREFIX}-{project_name}"
|
||||
target_name = channel_name.lower().replace(" ", "-")
|
||||
|
||||
# Check if channel exists but wasn't mapped yet
|
||||
# Fetch FRESH channel list from Discord API (not cached)
|
||||
if self.session_category:
|
||||
for ch in self.session_category.text_channels:
|
||||
if ch.topic and conversation_id in ch.topic:
|
||||
category = await self.guild.fetch_channel(self.session_category.id)
|
||||
for ch in category.text_channels:
|
||||
# Match by NAME (handles different conv IDs → same project)
|
||||
if ch.name == target_name or (ch.topic and conversation_id in ch.topic):
|
||||
self.session_channels[conversation_id] = ch
|
||||
self.session_names[conversation_id] = project_name
|
||||
# Rename from closed- if needed
|
||||
if ch.name.startswith("closed-"):
|
||||
try:
|
||||
await ch.edit(name=channel_name)
|
||||
except discord.errors.Forbidden:
|
||||
pass
|
||||
logger.info(f"Reusing existing channel #{ch.name}")
|
||||
return ch
|
||||
|
||||
# Create new channel
|
||||
# Create new channel (only if truly no match found)
|
||||
try:
|
||||
channel = await self.guild.create_text_channel(
|
||||
name=channel_name,
|
||||
|
||||
Reference in New Issue
Block a user