Хранилище данных
Персистентное хранилище - самая полезная возможность MandreLib. Данные автоматически сохраняются на диск и восстанавливаются при перезагрузке.
Автоматическое сохранение
После активации Mandre.use_persistent_storage(self) все настройки сохраняются автоматически:
def on_plugin_load(self):
Mandre.use_persistent_storage(self)
# Восстановится из сохранённого файла
count = self.get_setting("counter", 0)
self.set_setting("counter", count + 1)
self.log(f"Плагин загружался {count + 1} раз")Как это работает
MandreLib перехватывает вызовы set_setting() и автоматически сохраняет данные в JSON файл в директории плагина.
Работа с JSON напрямую
Для более сложных структур данных используйте MandreData:
Запись JSON
from mandre_lib import MandreData
# Создаём структуру данных
my_data = {
"users": [
{"id": 1, "name": "Alice", "score": 100},
{"id": 2, "name": "Bob", "score": 85}
],
"settings": {
"theme": "dark",
"notifications": True
},
"version": "1.0"
}
# Сохраняем в файл
MandreData.write_persistent_json(self.id, "database.json", my_data)Чтение JSON
# Читаем с дефолтным значением
loaded_data = MandreData.read_persistent_json(
self.id,
"database.json",
default={"users": [], "settings": {}}
)
# Используем данные
users = loaded_data.get("users", [])
for user in users:
self.log(f"User: {user['name']}, Score: {user['score']}")Список файлов плагина
# Получить все файлы, созданные плагином
files = MandreData.list_files_for_plugin(self.id)
self.log(f"Файлы плагина: {files}")
# Пример вывода: ['config.json', 'database.json', 'cache.json']Примеры использования
Счётчик сообщений
def on_send_message_hook(self, params):
# Увеличиваем счётчик
count = self.get_setting("message_count", 0)
self.set_setting("message_count", count + 1)
# Каждое 10-е сообщение показываем статистику
if count % 10 == 0:
BulletinHelper.show_info(f"Отправлено {count} сообщений")
return HookResult()База данных пользователей
def add_user(self, user_id, username):
# Загружаем базу
db = MandreData.read_persistent_json(self.id, "users.json", {"users": []})
# Добавляем пользователя
db["users"].append({
"id": user_id,
"username": username,
"added_at": time.time()
})
# Сохраняем
MandreData.write_persistent_json(self.id, "users.json", db)
def get_user(self, user_id):
db = MandreData.read_persistent_json(self.id, "users.json", {"users": []})
for user in db["users"]:
if user["id"] == user_id:
return user
return NoneКэш данных
import time
def get_cached_data(self, key, fetch_func, ttl=3600):
"""Получить данные с кэшированием
Args:
key: ключ кэша
fetch_func: функция для получения данных
ttl: время жизни кэша в секундах
"""
cache = MandreData.read_persistent_json(self.id, "cache.json", {})
# Проверяем кэш
if key in cache:
cached_item = cache[key]
if time.time() - cached_item["timestamp"] < ttl:
return cached_item["data"]
# Получаем свежие данные
data = fetch_func()
# Сохраняем в кэш
cache[key] = {
"data": data,
"timestamp": time.time()
}
MandreData.write_persistent_json(self.id, "cache.json", cache)
return dataИстория действий
def add_to_history(self, action, details):
"""Добавить запись в историю"""
history = MandreData.read_persistent_json(self.id, "history.json", [])
history.append({
"action": action,
"details": details,
"timestamp": time.time()
})
# Ограничиваем размер истории
if len(history) > 100:
history = history[-100:]
MandreData.write_persistent_json(self.id, "history.json", history)
def get_recent_history(self, limit=10):
"""Получить последние записи"""
history = MandreData.read_persistent_json(self.id, "history.json", [])
return history[-limit:]Экспорт и импорт настроек
Экспорт
import json
def export_settings(self):
"""Экспортировать настройки в JSON строку"""
settings = MandreData.read_persistent_json(self.id, "config.json", {})
json_export = json.dumps(settings, ensure_ascii=False, indent=2)
# Показываем пользователю или сохраняем в файл
self.log(f"Экспорт настроек:\n{json_export}")
return json_exportИмпорт
def import_settings(self, json_string):
"""Импортировать настройки из JSON строки"""
try:
imported_settings = json.loads(json_string)
MandreData.write_persistent_json(self.id, "config.json", imported_settings)
BulletinHelper.show_success("Настройки импортированы")
return True
except Exception as e:
BulletinHelper.show_error(f"Ошибка импорта: {e}")
return FalseПотокобезопасность
Безопасность
Все операции с MandreData потокобезопасны. Можно безопасно читать и писать из фоновых потоков:
from threading import Thread
def background_task(self):
# Безопасно из фонового потока
data = MandreData.read_persistent_json(self.id, "data.json", {})
data["updated"] = time.time()
MandreData.write_persistent_json(self.id, "data.json", data)
Thread(target=lambda: background_task(self)).start()Расположение файлов
Все файлы плагина сохраняются в:
/storage/emulated/0/Android/data/org.telegram.messenger/files/exteraGram/plugins_data/<plugin_id>/Лучшие практики
Используйте осмысленные имена файлов
python# ✅ Хорошо MandreData.write_persistent_json(self.id, "user_database.json", data) # ❌ Плохо MandreData.write_persistent_json(self.id, "data.json", data)Всегда указывайте default значения
python# ✅ Хорошо data = MandreData.read_persistent_json(self.id, "config.json", {}) # ❌ Плохо (может вызвать ошибку) data = MandreData.read_persistent_json(self.id, "config.json")Ограничивайте размер данных
python# Не храните бесконечно растущие списки if len(history) > 1000: history = history[-1000:] # Оставляем последние 1000
Экспорт и импорт данных плагина (ZIP)
Экспортируйте все файлы плагина в ZIP-архив и импортируйте их обратно при необходимости (резервное копирование/перенос).
from datetime import datetime
import zipfile, os
from android.os import Environment
def export_plugin_data(self):
downloads = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
ts = datetime.now().strftime("%Y%m%d_%H%M%S")
zip_name = f"mandrelib_data_{self.id}_{ts}.zip"
zip_path = os.path.join(downloads.getAbsolutePath(), zip_name)
with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zf:
for filename in MandreData.list_files_for_plugin(self.id):
file_path = MandreData.get_persistent_path(self.id, filename)
zf.write(file_path, arcname=filename)
BulletinHelper.show_success(f"Данные экспортированы в Downloads/{zip_name}")
def import_plugin_data(self, zip_path):
# Полная очистка данных плагина
MandreData.delete_persistent_plugin_data(self.id)
# Целевая директория хранения данных плагина
target_dir = File(MandreData._get_base_data_dir(), self.id)
if not target_dir.exists():
target_dir.mkdirs()
with zipfile.ZipFile(zip_path, 'r') as zf:
zf.extractall(target_dir.getAbsolutePath())
BulletinHelper.show_success("Данные импортированы")Важно
- Перед импортом убедитесь, что архив доверенный.
- Импорт перезапишет текущие данные плагина.
Следующие шаги
- UI компоненты - создание интерфейса
- Команды - обработка команд
- Примеры - готовые примеры