修正gitignore排除目录问题
parent
e55c25b9e3
commit
071ab94829
@ -0,0 +1,95 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
import toml
|
||||||
|
from watchdog.events import FileSystemEventHandler
|
||||||
|
from watchdog.observers import Observer
|
||||||
|
|
||||||
|
config_observer = Observer()
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
file_name: str
|
||||||
|
values: dict = {}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def load_config(file):
|
||||||
|
global config_observer
|
||||||
|
|
||||||
|
Config.file_name = file
|
||||||
|
Config.reload()
|
||||||
|
|
||||||
|
if config_observer.is_alive():
|
||||||
|
config_observer.stop()
|
||||||
|
config_observer.join()
|
||||||
|
|
||||||
|
config_observer.schedule(Config.ConfigEventHandler(), file)
|
||||||
|
config_observer.start()
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def reload():
|
||||||
|
with open(Config.file_name, "r", encoding="utf-8") as f:
|
||||||
|
Config.values = toml.load(f)
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get(key: str, default=None, type=None, empty_is_none=False):
|
||||||
|
key_path = key.split(".")
|
||||||
|
value = Config.values
|
||||||
|
for k in key_path:
|
||||||
|
if k in value:
|
||||||
|
value = value[k]
|
||||||
|
else:
|
||||||
|
return default
|
||||||
|
|
||||||
|
if empty_is_none and value == "":
|
||||||
|
return None
|
||||||
|
|
||||||
|
if type == bool:
|
||||||
|
if isinstance(value, bool):
|
||||||
|
return value
|
||||||
|
elif isinstance(value, int) or isinstance(value, float):
|
||||||
|
return value != 0
|
||||||
|
else:
|
||||||
|
return str(value).lower() in ("yes", "true", "1")
|
||||||
|
elif type == int:
|
||||||
|
return int(value)
|
||||||
|
elif type == float:
|
||||||
|
return float(value)
|
||||||
|
elif type == str:
|
||||||
|
return str(value)
|
||||||
|
elif type == list:
|
||||||
|
if not isinstance(value, list):
|
||||||
|
return []
|
||||||
|
elif type == dict:
|
||||||
|
if not isinstance(value, dict):
|
||||||
|
return {}
|
||||||
|
else:
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def set(key: str, value):
|
||||||
|
key_path = key.split(".")
|
||||||
|
obj = Config.values
|
||||||
|
for k in key_path[:-1]:
|
||||||
|
if k not in obj:
|
||||||
|
obj[k] = {}
|
||||||
|
obj = obj[k]
|
||||||
|
obj[key_path[-1]] = value
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def unload():
|
||||||
|
global config_observer
|
||||||
|
|
||||||
|
if config_observer.is_alive():
|
||||||
|
config_observer.stop()
|
||||||
|
config_observer.join()
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigEventHandler(FileSystemEventHandler):
|
||||||
|
def on_modified(self, event):
|
||||||
|
if os.path.basename(event.src_path) == os.path.basename(Config.file_name):
|
||||||
|
print("Config file changed, reloading...")
|
||||||
|
Config.reload()
|
@ -0,0 +1,165 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
from asyncio import AbstractEventLoop, Task
|
||||||
|
import asyncio
|
||||||
|
import atexit
|
||||||
|
from functools import wraps
|
||||||
|
import random
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
|
from typing import Callable, Coroutine, Optional, TypedDict
|
||||||
|
|
||||||
|
class TimerInfo(TypedDict):
|
||||||
|
id: int
|
||||||
|
callback: Callable
|
||||||
|
interval: float
|
||||||
|
next_time: float
|
||||||
|
|
||||||
|
class NoAwaitPool:
|
||||||
|
def __init__(self, loop: AbstractEventLoop):
|
||||||
|
self.task_list: list[Task] = []
|
||||||
|
self.timer_map: dict[int, TimerInfo] = {}
|
||||||
|
self.loop = loop
|
||||||
|
self.running = True
|
||||||
|
|
||||||
|
self.should_refresh_task = False
|
||||||
|
self.next_timer_time: Optional[float] = None
|
||||||
|
|
||||||
|
self.on_error: list[Callable] = []
|
||||||
|
|
||||||
|
self.gc_task = loop.create_task(self._run_gc())
|
||||||
|
self.timer_task = loop.create_task(self._run_timer())
|
||||||
|
|
||||||
|
atexit.register(self.end_task)
|
||||||
|
|
||||||
|
async def end(self):
|
||||||
|
if self.running:
|
||||||
|
print("Stopping NoAwait Tasks...")
|
||||||
|
self.running = False
|
||||||
|
for task in self.task_list:
|
||||||
|
await self._finish_task(task)
|
||||||
|
|
||||||
|
await self.gc_task
|
||||||
|
await self.timer_task
|
||||||
|
|
||||||
|
def end_task(self):
|
||||||
|
if self.running and not self.loop.is_closed():
|
||||||
|
self.loop.run_until_complete(self.end())
|
||||||
|
|
||||||
|
async def _wrap_task(self, task: Task):
|
||||||
|
try:
|
||||||
|
await task
|
||||||
|
except Exception as e:
|
||||||
|
handled = False
|
||||||
|
for handler in self.on_error:
|
||||||
|
try:
|
||||||
|
handler_ret = handler(e)
|
||||||
|
await handler_ret
|
||||||
|
handled = True
|
||||||
|
except Exception as handler_err:
|
||||||
|
print("Exception on error handler: " + str(handler_err), file=sys.stderr)
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
if not handled:
|
||||||
|
print(e, file=sys.stderr)
|
||||||
|
traceback.print_exc()
|
||||||
|
finally:
|
||||||
|
self.should_refresh_task = True
|
||||||
|
|
||||||
|
def add_task(self, coroutine: Coroutine):
|
||||||
|
task = self.loop.create_task(coroutine)
|
||||||
|
self.task_list.append(task)
|
||||||
|
|
||||||
|
def add_timer(self, callback: Callable, interval: float) -> int:
|
||||||
|
id = random.randint(0, 1000000000)
|
||||||
|
while id in self.timer_map:
|
||||||
|
id = random.randint(0, 1000000000)
|
||||||
|
|
||||||
|
now = self.loop.time()
|
||||||
|
next_time = now + interval
|
||||||
|
self.timer_map[id] = {
|
||||||
|
"id": id,
|
||||||
|
"callback": callback,
|
||||||
|
"interval": interval,
|
||||||
|
"next_time": next_time
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.next_timer_time is None or next_time < self.next_timer_time:
|
||||||
|
self.next_timer_time = next_time
|
||||||
|
|
||||||
|
return id
|
||||||
|
|
||||||
|
def remove_timer(self, id: int):
|
||||||
|
if id in self.timer_map:
|
||||||
|
del self.timer_map[id]
|
||||||
|
|
||||||
|
def wrap(self, f):
|
||||||
|
@wraps(f)
|
||||||
|
def decorated_function(*args, **kwargs):
|
||||||
|
coroutine = f(*args, **kwargs)
|
||||||
|
self.add_task(coroutine)
|
||||||
|
|
||||||
|
return decorated_function
|
||||||
|
|
||||||
|
async def _finish_task(self, task: Task):
|
||||||
|
try:
|
||||||
|
if not task.done():
|
||||||
|
task.cancel()
|
||||||
|
await task
|
||||||
|
except Exception as e:
|
||||||
|
handled = False
|
||||||
|
for handler in self.on_error:
|
||||||
|
try:
|
||||||
|
handler_ret = handler(e)
|
||||||
|
await handler_ret
|
||||||
|
handled = True
|
||||||
|
except Exception as handler_err:
|
||||||
|
print("Exception on error handler: " + str(handler_err), file=sys.stderr)
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
if not handled:
|
||||||
|
print(e, file=sys.stderr)
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
async def _run_gc(self):
|
||||||
|
while self.running:
|
||||||
|
if self.should_refresh_task:
|
||||||
|
should_remove = []
|
||||||
|
for task in self.task_list:
|
||||||
|
if task.done():
|
||||||
|
await self._finish_task(task)
|
||||||
|
should_remove.append(task)
|
||||||
|
for task in should_remove:
|
||||||
|
self.task_list.remove(task)
|
||||||
|
|
||||||
|
await asyncio.sleep(0.1)
|
||||||
|
|
||||||
|
async def _run_timer(self):
|
||||||
|
while self.running:
|
||||||
|
now = self.loop.time()
|
||||||
|
if self.next_timer_time is not None and now >= self.next_timer_time:
|
||||||
|
self.next_timer_time = None
|
||||||
|
for timer in self.timer_map.values():
|
||||||
|
if now >= timer["next_time"]:
|
||||||
|
timer["next_time"] = now + timer["interval"]
|
||||||
|
try:
|
||||||
|
result = timer["callback"]()
|
||||||
|
self.add_task(result)
|
||||||
|
except Exception as e:
|
||||||
|
handled = False
|
||||||
|
for handler in self.on_error:
|
||||||
|
try:
|
||||||
|
handler_ret = handler(e)
|
||||||
|
self.add_task(handler_ret)
|
||||||
|
handled = True
|
||||||
|
except Exception as handler_err:
|
||||||
|
print("Exception on error handler: " + str(handler_err), file=sys.stderr)
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
if not handled:
|
||||||
|
print(e, file=sys.stderr)
|
||||||
|
traceback.print_exc()
|
||||||
|
if self.next_timer_time is None or timer["next_time"] < self.next_timer_time:
|
||||||
|
self.next_timer_time = timer["next_time"]
|
||||||
|
|
||||||
|
await asyncio.sleep(0.1)
|
@ -1,4 +1,9 @@
|
|||||||
import sys
|
import sys
|
||||||
import pathlib
|
import pathlib
|
||||||
|
|
||||||
sys.path.append(str(pathlib.Path(__file__).parent.parent))
|
root_path = pathlib.Path(__file__).parent.parent
|
||||||
|
sys.path.append(".")
|
||||||
|
|
||||||
|
from libs.config import Config
|
||||||
|
|
||||||
|
Config.load_config(str(root_path) + "/config.toml")
|
@ -1,43 +0,0 @@
|
|||||||
from __future__ import annotations
|
|
||||||
import sqlalchemy
|
|
||||||
from server.model.base import BaseHelper, BaseModel
|
|
||||||
|
|
||||||
import sqlalchemy
|
|
||||||
from sqlalchemy import select, update
|
|
||||||
from sqlalchemy.orm import mapped_column, relationship, Mapped
|
|
||||||
|
|
||||||
class BotPersonaCategoryModel(BaseModel):
|
|
||||||
__tablename__ = "chat_complete_bot_persona_category"
|
|
||||||
|
|
||||||
id: Mapped[int] = mapped_column(sqlalchemy.Integer, primary_key=True, autoincrement=True)
|
|
||||||
name: Mapped[str] = mapped_column(sqlalchemy.String(60), index=True)
|
|
||||||
description: Mapped[str] = mapped_column(sqlalchemy.String, nullable=True)
|
|
||||||
icon: Mapped[str] = mapped_column(sqlalchemy.String, nullable=True)
|
|
||||||
font_icon: Mapped[str] = mapped_column(sqlalchemy.String, nullable=True)
|
|
||||||
color: Mapped[str] = mapped_column(sqlalchemy.String(10), nullable=True)
|
|
||||||
order: Mapped[int] = mapped_column(sqlalchemy.Integer, nullable=True)
|
|
||||||
|
|
||||||
class BotPersonaHelper(BaseHelper):
|
|
||||||
async def add(self, obj: BotPersonaCategoryModel):
|
|
||||||
self.session.add(obj)
|
|
||||||
await self.session.commit()
|
|
||||||
await self.session.refresh(obj)
|
|
||||||
return obj
|
|
||||||
|
|
||||||
async def update(self, obj: BotPersonaCategoryModel):
|
|
||||||
obj = await self.session.merge(obj)
|
|
||||||
await self.session.commit()
|
|
||||||
return obj
|
|
||||||
|
|
||||||
async def remove(self, id: int):
|
|
||||||
stmt = sqlalchemy.delete(BotPersonaCategoryModel).where(BotPersonaCategoryModel.id == id)
|
|
||||||
await self.session.execute(stmt)
|
|
||||||
await self.session.commit()
|
|
||||||
|
|
||||||
async def get_list(self):
|
|
||||||
stmt = select(BotPersonaCategoryModel)
|
|
||||||
return await self.session.scalars(stmt)
|
|
||||||
|
|
||||||
async def find_by_id(self, id: int):
|
|
||||||
stmt = select(BotPersonaCategoryModel).where(BotPersonaCategoryModel.id == id)
|
|
||||||
return await self.session.scalar(stmt)
|
|
@ -1,5 +1,5 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
from lib.noawait import NoAwaitPool
|
from libs.noawait import NoAwaitPool
|
||||||
|
|
||||||
debug = False
|
debug = False
|
||||||
loop = asyncio.new_event_loop()
|
loop = asyncio.new_event_loop()
|
||||||
|
Loading…
Reference in New Issue