Now index locking should be not a problem

This commit is contained in:
2026-02-06 12:27:31 +03:00
parent 44ca8633c6
commit a7b8c740b4

View File

@@ -3,10 +3,12 @@
from collections import Counter, defaultdict from collections import Counter, defaultdict
import shutil
from whoosh.index import create_in, open_dir from whoosh.index import create_in, open_dir
from whoosh.fields import Schema, TEXT, ID from whoosh.fields import Schema, TEXT, ID
from whoosh.qparser import QueryParser, OrGroup from whoosh.qparser import QueryParser, OrGroup
from whoosh.query import FuzzyTerm, Wildcard from whoosh.query import FuzzyTerm, Wildcard
from whoosh.writing import LockError
import aiohttp import aiohttp
import random import random
import logging import logging
@@ -31,7 +33,7 @@ from .. import utils, loader
from ..types import InlineCall from ..types import InlineCall
logger = logging.getLogger("Limoka") logger = logging.getLogger("Limoka")
__version__ = (1, 4, 1) __version__ = (1, 4, 2)
WEIGHTS = { WEIGHTS = {
"inline.token_obtainment": 15, "inline.token_obtainment": 15,
@@ -43,6 +45,8 @@ WEIGHTS = {
DEFAULT_WEIGHT = 1 DEFAULT_WEIGHT = 1
BASE_DIR = os.getcwd()
def _get_lang_value(data: Dict[str, Any], lang: str) -> str: def _get_lang_value(data: Dict[str, Any], lang: str) -> str:
if not isinstance(data, dict): if not isinstance(data, dict):
@@ -185,6 +189,13 @@ class Limoka(loader.Module):
"nonlongermaintained": "No Longer Maintained Repository", "nonlongermaintained": "No Longer Maintained Repository",
"newbie": "Newbie", "newbie": "Newbie",
}, },
"indexing_in_progress": (
"⚠️ Database is busy, "
"try again later. "
"If issue persists, try "
"removing limoka_index in the userbot's root folder. "
"If error persists again, report to developers"
),
} }
strings_ru = { strings_ru = {
"name": "Limoka", "name": "Limoka",
@@ -291,6 +302,13 @@ class Limoka(loader.Module):
"nonlongermaintained": "Неподдерживаемый репозиторий", "nonlongermaintained": "Неподдерживаемый репозиторий",
"newbie": "Новичок", "newbie": "Новичок",
}, },
"indexing_in_progress": (
"⚠️ База данных занята, "
"попробуйте снова через несколько секунд. "
"Если ошибка сохраняется, попробуйте "
"удалить limoka_index в корневой папке юзербота. "
"Если ошибка сохраняется снова, сообщите разработчикам"
),
"_cls_doc": "Модули теперь в одном месте с простым и удобным поиском!", "_cls_doc": "Модули теперь в одном месте с простым и удобным поиском!",
} }
@@ -323,13 +341,13 @@ class Limoka(loader.Module):
# Search session states # Search session states
self.SEARCH_STATES = { self.SEARCH_STATES = {
"no_banner": "no_banner", # 404 - Нет баннера "no_banner": "no_banner", # 404 - No banner
"global_search": "global_search", # Глобальный поиск "global_search": "global_search", # Global search
"not_found": "not_found", # Не найдено (модуль) "not_found": "not_found", # Not found (module)
"filter_select": "filter_select", # Выбор категорий (фильтров) "filter_select": "filter_select", # Select categories (filters)
} }
# State banners - placeholders for now # State banners
self.state_banners = { self.state_banners = {
"no_banner": "https://raw.githubusercontent.com/MuRuLOSE/hikka-assets/refs/heads/main/Limoka%20-%20No%20banner.png", "no_banner": "https://raw.githubusercontent.com/MuRuLOSE/hikka-assets/refs/heads/main/Limoka%20-%20No%20banner.png",
"global_search": "https://raw.githubusercontent.com/MuRuLOSE/hikka-assets/main/Limoka%20-%20Global%20Search.png", "global_search": "https://raw.githubusercontent.com/MuRuLOSE/hikka-assets/main/Limoka%20-%20Global%20Search.png",
@@ -419,7 +437,10 @@ class Limoka(loader.Module):
except Exception: except Exception:
pass pass
self._service_bot_id = (await self.client.get_entity(self._bot_username)).id self._service_bot_id = (await self.client.get_entity(self._bot_username)).id
await self._update_index()
loop = asyncio.get_running_loop()
self.ix_task = loop.run_in_executor(None, lambda: asyncio.run(self._update_index()))
if self.config["external_install_allowed"]: if self.config["external_install_allowed"]:
try: try:
message = await self.client.get_messages(self._bot_username, limit=1) message = await self.client.get_messages(self._bot_username, limit=1)
@@ -454,6 +475,7 @@ class Limoka(loader.Module):
await self._update_index() await self._update_index()
async def _update_index(self): async def _update_index(self):
try:
writer = self.ix.writer() writer = self.ix.writer()
modules_to_index = self._filter_newbies(self.modules) modules_to_index = self._filter_newbies(self.modules)
for module_path, module_data in modules_to_index.items(): for module_path, module_data in modules_to_index.items():
@@ -481,6 +503,19 @@ class Limoka(loader.Module):
content=f"{command} {description}", content=f"{command} {description}",
) )
writer.commit() writer.commit()
except LockError:
folder = os.path.join(BASE_DIR, "limoka_search")
if os.path.commonpath([folder, BASE_DIR]) == BASE_DIR and os.path.exists(folder):
shutil.rmtree(folder)
await self._update_index()
else:
logger.error(
(
f"Skipping unsafe rmtree for {folder}. Please, report this to developer. ",
f"Debug info: folder={folder}, base_dir={BASE_DIR}, common_path={os.path.commonpath([folder, BASE_DIR])}, exists={os.path.exists(folder)}",
)
)
async def _validate_url(self, url: str) -> Optional[str]: async def _validate_url(self, url: str) -> Optional[str]:
if not url or url in self._invalid_banners: if not url or url in self._invalid_banners:
@@ -509,7 +544,6 @@ class Limoka(loader.Module):
for key in keys: for key in keys:
parts = key.split(".") parts = key.split(".")
# проходим все префиксы
for i in range(1, len(parts)): for i in range(1, len(parts)):
prefix = ".".join(parts[:i]) prefix = ".".join(parts[:i])
suffix = ".".join(parts[i:]) suffix = ".".join(parts[i:])
@@ -1329,6 +1363,11 @@ class Limoka(loader.Module):
async def limokacmd(self, message: Message): async def limokacmd(self, message: Message):
"""[query / nothing] - Search modules""" """[query / nothing] - Search modules"""
args = utils.get_args_raw(message) args = utils.get_args_raw(message)
lock_path = os.path.join(BASE_DIR, "limoka_search", "index.lock")
if os.path.exists(lock_path):
await utils.answer(message, self.strings["indexing_in_progress"])
return
if not args: if not args:
markup = [ markup = [
[ [