修正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 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
|
||||
from lib.noawait import NoAwaitPool
|
||||
from libs.noawait import NoAwaitPool
|
||||
|
||||
debug = False
|
||||
loop = asyncio.new_event_loop()
|
||||
|
Loading…
Reference in New Issue