Improve a lot

This commit is contained in:
Richard Chien 2018-06-27 22:05:12 +08:00
parent 6d95c16f5e
commit ae2d177d5a
11 changed files with 163 additions and 59 deletions

View File

@ -1,5 +1,4 @@
import os
import sys
import importlib
import logging
import re
@ -9,15 +8,9 @@ from typing import Any
from aiocqhttp import CQHttp
from aiocqhttp.message import Message
logger = logging.getLogger('none')
default_handler = logging.StreamHandler(sys.stdout)
default_handler.setFormatter(logging.Formatter(
'[%(asctime)s] %(levelname)s: %(message)s'
))
logger.addHandler(default_handler)
from . import plugin
from .plugin import *
from .message import handle_message
from .notice import handle_notice
from .logger import logger
def create_bot(config_object: Any = None):
@ -37,15 +30,16 @@ def create_bot(config_object: Any = None):
@bot.on_message
async def _(ctx):
asyncio.ensure_future(plugin.handle_message(bot, ctx))
asyncio.ensure_future(handle_message(bot, ctx))
@bot.on_notice
async def _(ctx):
asyncio.ensure_future(plugin.handle_notice(bot, ctx))
asyncio.ensure_future(handle_notice(bot, ctx))
@bot.on_request
async def _(ctx):
asyncio.ensure_future(plugin.handle_request(bot, ctx))
pass
# asyncio.ensure_future(plugin.handle_request(bot, ctx))
return bot
@ -79,3 +73,7 @@ def load_plugins(plugin_dir: str, module_prefix: str):
def load_builtin_plugins():
plugin_dir = os.path.join(os.path.dirname(__file__), 'plugins')
load_plugins(plugin_dir, 'none.plugins')
from .command import on_command
from .notice import on_notice

View File

@ -2,7 +2,7 @@ import re
import asyncio
from datetime import datetime
from typing import (
Tuple, Union, Callable, Iterable, Dict, Any, Optional, List, Sequence
Tuple, Union, Callable, Iterable, Dict, Any, Optional, Sequence
)
from aiocqhttp import CQHttp, Error as CQHttpError
@ -11,6 +11,7 @@ from aiocqhttp.message import Message
from . import permissions as perm
from .helpers import context_source
from .expression import render
from .session import BaseSession
# Key: str (one segment of command name)
# Value: subtree or a leaf Command object
@ -148,16 +149,14 @@ class _FurtherInteractionNeeded(Exception):
pass
class Session:
__slots__ = ('bot', 'cmd', 'ctx',
'current_key', 'current_arg', 'current_arg_text',
class CommandSession(BaseSession):
__slots__ = ('cmd', 'current_key', 'current_arg', 'current_arg_text',
'images', 'args', 'last_interaction')
def __init__(self, bot: CQHttp, cmd: Command, ctx: Dict[str, Any], *,
def __init__(self, bot: CQHttp, ctx: Dict[str, Any], cmd: Command, *,
current_arg: str = '', args: Dict[str, Any] = None):
self.bot = bot
super().__init__(bot, ctx)
self.cmd = cmd
self.ctx = ctx
self.current_key = None
self.current_arg = current_arg
self.current_arg_text = Message(current_arg).extract_plain_text()
@ -218,23 +217,9 @@ class Session:
asyncio.ensure_future(self.send(prompt))
raise _FurtherInteractionNeeded
async def send(self,
message: Union[str, Dict[str, Any], List[Dict[str, Any]]],
*, ignore_failure: bool = True) -> None:
try:
await self.bot.send(self.ctx, message)
except CQHttpError:
if not ignore_failure:
raise
async def send_expr(self,
expr: Union[str, Sequence[str], Callable],
**kwargs):
return await self.send(render(expr, **kwargs))
def _new_command_session(bot: CQHttp,
ctx: Dict[str, Any]) -> Optional[Session]:
ctx: Dict[str, Any]) -> Optional[CommandSession]:
"""
Create a new session for a command.
@ -245,7 +230,7 @@ def _new_command_session(bot: CQHttp,
:param bot: CQHttp instance
:param ctx: message context
:return: Session object or None
:return: CommandSession object or None
"""
msg_text = str(ctx['message']).lstrip()
@ -285,7 +270,7 @@ def _new_command_session(bot: CQHttp,
if not cmd:
return None
return Session(bot, cmd, ctx, current_arg=''.join(cmd_remained))
return CommandSession(bot, ctx, cmd, current_arg=''.join(cmd_remained))
async def handle_command(bot: CQHttp, ctx: Dict[str, Any]) -> bool:

View File

@ -1,4 +1,9 @@
from typing import Dict, Any
from typing import Dict, Any, Union, List, Sequence, Callable, Optional
from aiocqhttp import CQHttp, Error as CQHttpError
from aiocqhttp.bus import EventBus
from . import expression
def context_source(ctx: Dict[str, Any]) -> str:
@ -10,3 +15,48 @@ def context_source(ctx: Dict[str, Any]) -> str:
if ctx.get('user_id'):
src += f'/user/{ctx["user_id"]}'
return src
async def send(bot: CQHttp, ctx: Dict[str, Any],
message: Union[str, Dict[str, Any], List[Dict[str, Any]]],
*, ignore_failure: bool = True) -> None:
try:
if ctx.get('post_type') == 'message':
await bot.send(ctx, message)
else:
ctx = ctx.copy()
if 'message' in ctx:
del ctx['message']
if 'group_id' in ctx:
await bot.send_group_msg(**ctx, message=message)
elif 'discuss_id' in ctx:
await bot.send_discuss_msg(**ctx, message=message)
elif 'user_id' in ctx:
await bot.send_private_msg(**ctx, message=message)
except CQHttpError:
if not ignore_failure:
raise
async def send_expr(bot: CQHttp, ctx: Dict[str, Any],
expr: Union[str, Sequence[str], Callable],
**kwargs):
return await send(bot, ctx, expression.render(expr, **kwargs))
def make_event_deco(post_type: str, bus: EventBus) -> Callable:
def deco_deco(arg: Optional[Union[str, Callable]] = None,
*events: str) -> Callable:
def deco(func: Callable) -> Callable:
if isinstance(arg, str):
for e in [arg] + list(events):
bus.subscribe(f'{post_type}.{e}', func)
else:
bus.subscribe(post_type, func)
return func
if isinstance(arg, Callable):
return deco(arg)
return deco
return deco_deco

9
none/logger.py Normal file
View File

@ -0,0 +1,9 @@
import sys
import logging
logger = logging.getLogger('none')
default_handler = logging.StreamHandler(sys.stdout)
default_handler.setFormatter(logging.Formatter(
'[%(asctime)s] %(levelname)s: %(message)s'
))
logger.addHandler(default_handler)

View File

@ -3,12 +3,8 @@ from typing import Dict, Any
from aiocqhttp import CQHttp
from aiocqhttp.message import MessageSegment
from . import logger
from .command import on_command, handle_command
__all__ = [
'on_command',
]
from .command import handle_command
from .logger import logger
async def handle_message(bot: CQHttp, ctx: Dict[str, Any]) -> None:
@ -27,11 +23,3 @@ async def handle_message(bot: CQHttp, ctx: Dict[str, Any]) -> None:
return
else:
await bot.send(ctx, '你在说什么我看不懂诶')
async def handle_notice(bot: CQHttp, ctx: Dict[str, Any]) -> None:
pass
async def handle_request(bot: CQHttp, ctx: Dict[str, Any]) -> None:
pass

28
none/notice.py Normal file
View File

@ -0,0 +1,28 @@
from typing import Dict, Any
from aiocqhttp import CQHttp
from aiocqhttp.bus import EventBus
from .session import BaseSession
from .helpers import make_event_deco
from .logger import logger
_bus = EventBus()
on_notice = make_event_deco('notice', _bus)
class NoticeSession(BaseSession):
__slots__ = ()
def __init__(self, bot: CQHttp, ctx: Dict[str, Any]):
super().__init__(bot, ctx)
async def handle_notice(bot: CQHttp, ctx: Dict[str, Any]) -> None:
event = f'notice.{ctx["notice_type"]}'
if ctx.get('sub_type'):
event += f'.{ctx["sub_type"]}'
session = NoticeSession(bot, ctx)
logger.debug(f'Emitting event: {event}')
await _bus.emit(event, session)

View File

@ -2,14 +2,14 @@ from aiocqhttp.message import unescape
import none
from none import permissions as perm
from none.command import Session
from none.command import CommandSession
@none.on_command('echo')
async def echo(session: Session):
async def echo(session: CommandSession):
await session.send(session.current_arg)
@none.on_command('say', permission=perm.SUPERUSER)
async def _(session: Session):
async def _(session: CommandSession):
await session.send(unescape(session.current_arg))

24
none/session.py Normal file
View File

@ -0,0 +1,24 @@
from typing import Union, Callable, Dict, Any, List, Sequence
from aiocqhttp import CQHttp
from .helpers import send, send_expr
class BaseSession:
__slots__ = ('bot', 'ctx')
def __init__(self, bot: CQHttp, ctx: Dict[str, Any]):
self.bot = bot
self.ctx = ctx
async def send(self,
message: Union[str, Dict[str, Any], List[Dict[str, Any]]],
*, ignore_failure: bool = True) -> None:
return await send(self.bot, self.ctx, message,
ignore_failure=ignore_failure)
async def send_expr(self,
expr: Union[str, Sequence[str], Callable],
**kwargs):
return await send_expr(self.bot, self.ctx, expr, **kwargs)

View File

@ -0,0 +1,22 @@
from aiocqhttp import Error as CQHttpError
import none
from none.notice import NoticeSession
GROUP_GREETING = (
'欢迎新同学 {name}[][CQ:face,id=63][CQ:face,id=63][CQ:face,id=63]',
'[CQ:face,id=99]欢迎新成员~',
'欢迎 {name}👏👏~',
'[CQ:at,qq={user_id}] 欢迎欢迎👏',
)
@none.on_notice('group_increase')
async def _(session: NoticeSession):
try:
info = await session.bot.get_group_member_info(**session.ctx,
no_cache=True)
name = info['card'] or info['nickname'] or '新成员'
await session.send_expr(GROUP_GREETING, name=name, **session.ctx)
except CQHttpError:
pass

View File

@ -1,4 +1,4 @@
from none.command import Session, CommandGroup
from none.command import CommandSession, CommandGroup
from . import expressions as expr
@ -6,17 +6,17 @@ w = CommandGroup('weather')
@w.command('weather', aliases=('天气', '天气预报'))
async def weather(session: Session):
async def weather(session: CommandSession):
city = session.require_arg('city', prompt_expr=expr.WHICH_CITY)
await session.send_expr(expr.REPORT, city=city)
@weather.args_parser
async def _(session: Session):
async def _(session: CommandSession):
if session.current_key:
session.args[session.current_key] = session.current_arg_text.strip()
@w.command('suggestion', aliases=('生活指数', '生活建议', '生活提示'))
async def suggestion(session: Session):
async def suggestion(session: CommandSession):
await session.send('suggestion')