mirror of
https://gitflic.ru/project/maks1ms/ocab.git
synced 2025-01-12 01:31:05 +03:00
wip
This commit is contained in:
parent
abf8f8047c
commit
e8b5f79d99
998
poetry.lock
generated
998
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,4 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
package-mode = false
|
|
||||||
name = "ocab"
|
name = "ocab"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
description = "OCAB is a modular Telegram bot"
|
description = "OCAB is a modular Telegram bot"
|
||||||
@ -13,7 +12,11 @@ maintainers = [
|
|||||||
]
|
]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
repository = "https://gitflic.ru/project/armatik/ocab"
|
repository = "https://gitflic.ru/project/armatik/ocab"
|
||||||
packages = [{include = "scripts"}]
|
packages = [
|
||||||
|
{ include = "scripts" },
|
||||||
|
{ include = "ocab_core", from = "src" },
|
||||||
|
{ include = "ocab_modules", from = "src" }
|
||||||
|
]
|
||||||
|
|
||||||
[tool.poetry.urls]
|
[tool.poetry.urls]
|
||||||
"Bug Tracker" = "https://gitflic.ru/project/armatik/ocab/issue?status=OPEN"
|
"Bug Tracker" = "https://gitflic.ru/project/armatik/ocab/issue?status=OPEN"
|
||||||
@ -32,6 +35,9 @@ requests = "^2.32.3"
|
|||||||
restrictedpython = "^7.1"
|
restrictedpython = "^7.1"
|
||||||
dataclasses-json = "^0.6.7"
|
dataclasses-json = "^0.6.7"
|
||||||
semver = "^3.0.2"
|
semver = "^3.0.2"
|
||||||
|
hypercorn = "^0.17.3"
|
||||||
|
flet = "^0.23.2"
|
||||||
|
fastapi = "^0.111.1"
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
flake8 = "^7.1.0"
|
flake8 = "^7.1.0"
|
||||||
|
5
src/ocab_core/__main__.py
Normal file
5
src/ocab_core/__main__.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import asyncio
|
||||||
|
|
||||||
|
from ocab_core.main import main
|
||||||
|
|
||||||
|
asyncio.run(main())
|
31
src/ocab_core/lib.py
Normal file
31
src/ocab_core/lib.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import importlib
|
||||||
|
import os
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from aiogram import Bot, Dispatcher
|
||||||
|
from aiogram.types import Update
|
||||||
|
from fastapi import FastAPI, Request
|
||||||
|
|
||||||
|
|
||||||
|
def get_module_directory(module_name):
|
||||||
|
spec = importlib.util.find_spec(module_name)
|
||||||
|
if spec is None:
|
||||||
|
raise ImportError(f"Module {module_name} not found")
|
||||||
|
module_path = spec.origin
|
||||||
|
if module_path is None:
|
||||||
|
raise ImportError(f"Module {module_name} has no origin path")
|
||||||
|
return os.path.dirname(module_path)
|
||||||
|
|
||||||
|
|
||||||
|
async def register_bot_webhook(app: FastAPI, bot: Bot, dp: Dispatcher):
|
||||||
|
async def handle_webhook(request: Request):
|
||||||
|
try:
|
||||||
|
update = Update.model_validate(await request.json(), context={"bot": bot})
|
||||||
|
await dp.feed_update(bot, update)
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc()
|
||||||
|
return {"ok": False}
|
||||||
|
|
||||||
|
return {"ok": True}
|
||||||
|
|
||||||
|
app.post("/webhook")(handle_webhook)
|
@ -2,59 +2,92 @@ import asyncio
|
|||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from aiogram import Bot, Dispatcher
|
from aiogram import Bot, Dispatcher
|
||||||
|
from fastapi import FastAPI
|
||||||
|
from hypercorn.asyncio import serve
|
||||||
|
from hypercorn.config import Config as HyperConfig
|
||||||
|
|
||||||
|
from ocab_core.lib import get_module_directory, register_bot_webhook
|
||||||
from ocab_core.logger import log, setup_logger
|
from ocab_core.logger import log, setup_logger
|
||||||
from ocab_core.modules_system import ModulesManager
|
from ocab_core.modules_system import ModulesManager
|
||||||
from ocab_core.modules_system.loaders import FSLoader
|
from ocab_core.modules_system.loaders import FSLoader, UnsafeFSLoader
|
||||||
from ocab_core.modules_system.loaders.unsafe_fs_loader import UnsafeFSLoader
|
|
||||||
from ocab_core.singleton import Singleton
|
from ocab_core.singleton import Singleton
|
||||||
from ocab_modules.standard.config.config import get_telegram_token
|
from ocab_modules.standard.config.config import get_telegram_token
|
||||||
from service import paths
|
|
||||||
|
ocab_modules_path = get_module_directory("ocab_modules")
|
||||||
|
|
||||||
|
|
||||||
|
def ocab_modules_loader(namespace: str, module_name: str, safe=True):
|
||||||
|
if not safe:
|
||||||
|
return UnsafeFSLoader(f"{ocab_modules_path}/{namespace}/{module_name}")
|
||||||
|
else:
|
||||||
|
return FSLoader(f"{ocab_modules_path}/{namespace}/{module_name}")
|
||||||
|
|
||||||
|
|
||||||
bot_modules = [
|
bot_modules = [
|
||||||
UnsafeFSLoader(f"{paths.modules_standard}/config"),
|
ocab_modules_loader("standard", "config", safe=False),
|
||||||
UnsafeFSLoader(f"{paths.modules_standard}/database"),
|
ocab_modules_loader("standard", "database", safe=False),
|
||||||
UnsafeFSLoader(f"{paths.modules_standard}/fsm_database_storage"),
|
ocab_modules_loader("standard", "fsm_database_storage", safe=False),
|
||||||
UnsafeFSLoader(f"{paths.modules_standard}/roles"),
|
ocab_modules_loader("standard", "roles", safe=False),
|
||||||
UnsafeFSLoader(f"{paths.modules_external}/yandexgpt"),
|
ocab_modules_loader("external", "yandexgpt", safe=False),
|
||||||
FSLoader(f"{paths.modules_standard}/command_helper"),
|
ocab_modules_loader("standard", "miniapp", safe=False),
|
||||||
FSLoader(f"{paths.modules_standard}/info"),
|
ocab_modules_loader("standard", "command_helper"),
|
||||||
FSLoader(f"{paths.modules_standard}/filters"),
|
ocab_modules_loader("standard", "info"),
|
||||||
FSLoader(f"{paths.modules_external}/create_report_apps"),
|
ocab_modules_loader("standard", "filters"),
|
||||||
FSLoader(f"{paths.modules_standard}/admin"),
|
ocab_modules_loader("external", "create_report_apps"),
|
||||||
FSLoader(f"{paths.modules_standard}/message_processing"),
|
ocab_modules_loader("standard", "admin"),
|
||||||
|
ocab_modules_loader("standard", "message_processing"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
async def long_polling_mode():
|
||||||
bot = None
|
singleton = Singleton()
|
||||||
setup_logger()
|
await singleton.bot.delete_webhook()
|
||||||
|
await singleton.dp.start_polling(singleton.bot)
|
||||||
|
|
||||||
app = Singleton()
|
|
||||||
|
async def webhook_mode():
|
||||||
|
singleton = Singleton()
|
||||||
|
app = FastAPI()
|
||||||
|
await register_bot_webhook(app, singleton.bot, singleton.dp)
|
||||||
|
await singleton.bot.set_webhook(
|
||||||
|
"https://mackerel-pumped-foal.ngrok-free.app/webhook"
|
||||||
|
)
|
||||||
|
config = HyperConfig()
|
||||||
|
config.bind = ["0.0.0.0:9000"]
|
||||||
|
await serve(app, config)
|
||||||
|
|
||||||
|
|
||||||
|
async def init_app():
|
||||||
|
setup_logger()
|
||||||
|
singleton = Singleton()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
app.bot = Bot(token=get_telegram_token())
|
singleton.bot = Bot(token=get_telegram_token())
|
||||||
app.modules_manager = ModulesManager()
|
singleton.modules_manager = ModulesManager()
|
||||||
|
|
||||||
for module_loader in bot_modules:
|
for module_loader in bot_modules:
|
||||||
info = module_loader.info()
|
info = module_loader.info()
|
||||||
log(f"Loading {info.name} ({info.id}) module")
|
log(f"Loading {info.name} ({info.id}) module")
|
||||||
await app.modules_manager.load(module_loader)
|
await singleton.modules_manager.load(module_loader)
|
||||||
|
|
||||||
app.dp = Dispatcher(storage=app.storage["_fsm_storage"])
|
singleton.dp = Dispatcher(storage=singleton.storage["_fsm_storage"])
|
||||||
|
|
||||||
app.dp.include_routers(*app.storage["_routers"])
|
singleton.dp.include_routers(*singleton.storage["_routers"])
|
||||||
|
|
||||||
for middleware in app.storage["_outer_message_middlewares"]:
|
for middleware in singleton.storage["_outer_message_middlewares"]:
|
||||||
app.dp.message.outer_middleware.register(middleware)
|
singleton.dp.message.outer_middleware.register(middleware)
|
||||||
|
|
||||||
|
await singleton.modules_manager.late_init()
|
||||||
|
|
||||||
await app.modules_manager.late_init()
|
|
||||||
await app.dp.start_polling(app.bot)
|
|
||||||
except Exception:
|
except Exception:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
finally:
|
raise
|
||||||
if bot is not None:
|
|
||||||
await app.bot.session.close()
|
|
||||||
|
async def main():
|
||||||
|
await init_app()
|
||||||
|
await webhook_mode()
|
||||||
|
# await long_polling_mode()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -1 +1,2 @@
|
|||||||
from .fs_loader import FSLoader
|
from .fs_loader import FSLoader
|
||||||
|
from .unsafe_fs_loader import UnsafeFSLoader
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import inspect
|
||||||
|
|
||||||
import semver
|
import semver
|
||||||
|
|
||||||
from ocab_core.modules_system.loaders.base import AbstractLoader
|
from ocab_core.modules_system.loaders.base import AbstractLoader
|
||||||
@ -21,6 +23,15 @@ def is_version_compatible(version, requirement):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
async def await_if_async(module, method_name):
|
||||||
|
if hasattr(module, method_name):
|
||||||
|
method = getattr(module, method_name)
|
||||||
|
if inspect.iscoroutinefunction(method):
|
||||||
|
await method()
|
||||||
|
else:
|
||||||
|
method()
|
||||||
|
|
||||||
|
|
||||||
class ModulesManager:
|
class ModulesManager:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.modules = []
|
self.modules = []
|
||||||
@ -57,14 +68,12 @@ class ModulesManager:
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
if hasattr(module, "module_init"):
|
await await_if_async(module, "module_init")
|
||||||
await module.module_init()
|
|
||||||
|
|
||||||
async def late_init(self):
|
async def late_init(self):
|
||||||
for m in self.modules:
|
for m in self.modules:
|
||||||
module = m["module"]
|
module = m["module"]
|
||||||
if hasattr(module, "module_late_init"):
|
await await_if_async(module, "module_late_init")
|
||||||
await module.module_late_init()
|
|
||||||
|
|
||||||
def get_by_id(self, module_id: str):
|
def get_by_id(self, module_id: str):
|
||||||
module = next(
|
module = next(
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
|
from ocab_core.logger import log
|
||||||
|
|
||||||
from .public_api import (
|
from .public_api import (
|
||||||
Storage,
|
Storage,
|
||||||
get_fsm_context,
|
get_fsm_context,
|
||||||
get_module,
|
get_module,
|
||||||
log,
|
|
||||||
register_outer_message_middleware,
|
register_outer_message_middleware,
|
||||||
register_router,
|
register_router,
|
||||||
set_my_commands,
|
set_my_commands,
|
||||||
|
@ -5,7 +5,6 @@ from aiogram import BaseMiddleware, Router
|
|||||||
from aiogram.fsm.context import FSMContext
|
from aiogram.fsm.context import FSMContext
|
||||||
from aiogram.fsm.storage.base import StorageKey
|
from aiogram.fsm.storage.base import StorageKey
|
||||||
|
|
||||||
from ocab_core.logger import log
|
|
||||||
from ocab_core.singleton import Singleton
|
from ocab_core.singleton import Singleton
|
||||||
|
|
||||||
|
|
||||||
@ -40,7 +39,6 @@ async def get_fsm_context(chat_id: int, user_id: int) -> FSMContext:
|
|||||||
|
|
||||||
def set_fsm(storage):
|
def set_fsm(storage):
|
||||||
app = Singleton()
|
app = Singleton()
|
||||||
log(storage)
|
|
||||||
app.storage["_fsm_storage"] = storage
|
app.storage["_fsm_storage"] = storage
|
||||||
|
|
||||||
|
|
||||||
|
1
src/ocab_modules/standard/miniapp/__init__.py
Normal file
1
src/ocab_modules/standard/miniapp/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
from .main import module_init
|
9
src/ocab_modules/standard/miniapp/info.json
Normal file
9
src/ocab_modules/standard/miniapp/info.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"id": "standard.miniapp",
|
||||||
|
"name": "Miniapp",
|
||||||
|
"description": "Очень полезный модуль",
|
||||||
|
"author": "OCAB Team",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"privileged": false,
|
||||||
|
"dependencies": {}
|
||||||
|
}
|
2
src/ocab_modules/standard/miniapp/main.py
Normal file
2
src/ocab_modules/standard/miniapp/main.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
def module_init():
|
||||||
|
pass
|
Loading…
Reference in New Issue
Block a user