Some big changes

This commit is contained in:
Richard Chien 2017-01-13 21:03:44 +08:00
parent 92b467b934
commit d01924a00c
8 changed files with 265 additions and 70 deletions

View File

@ -292,14 +292,33 @@ class CommandHub:
hub = CommandHub() hub = CommandHub()
def split_args(maxsplit=0): class CommandArgumentError(Exception):
pass
def split_arguments(maxsplit=0):
"""
To use this decorator, you should add a parameter exactly named 'argv' to the function of the command,
which will be set to the split argument list when called.
However, the first parameter, typically 'args_text', will remain to be the whole argument string, like before.
:param maxsplit: max split time
"""
def decorator(func): def decorator(func):
@functools.wraps(func)
def wrapper(argument, *args, **kwargs): def wrapper(argument, *args, **kwargs):
if isinstance(argument, (list, tuple)): if argument is None:
args_list = list(argument) raise CommandArgumentError
if kwargs.get('argv') is not None:
argv = kwargs['argv']
del kwargs['argv']
elif isinstance(argument, (list, tuple)):
argv = list(argument)
else: else:
args_list = list(filter(lambda arg: arg, re.split('|'.join(_command_args_seps), argument, maxsplit))) argv = list(filter(lambda arg: arg, re.split('|'.join(_command_args_seps), argument, maxsplit)))
return func(args_list, *args, **kwargs) return func(argument, argv=argv, *args, **kwargs)
return wrapper return wrapper

View File

@ -1,5 +1,4 @@
import sqlite3 import sqlite3
from functools import wraps
from datetime import datetime from datetime import datetime
import pytz import pytz
@ -7,7 +6,7 @@ import pytz
from command import CommandRegistry from command import CommandRegistry
from commands import core from commands import core
from interactive import * from interactive import *
from little_shit import get_default_db_path, get_source, get_target from little_shit import get_default_db_path, get_source, get_target, check_target
__registry__ = cr = CommandRegistry() __registry__ = cr = CommandRegistry()
@ -26,19 +25,6 @@ def _open_db_conn():
return conn return conn
def _check_target(func):
@wraps(func)
def wrapper(args_text, ctx_msg, *args, **kwargs):
target = get_target(ctx_msg)
if not target:
core.echo('似乎出错了,请稍后再试吧~', ctx_msg)
return
else:
return func(args_text, ctx_msg, *args, **kwargs)
return wrapper
_cmd_take = 'note.take' _cmd_take = 'note.take'
_cmd_remove = 'note.remove' _cmd_remove = 'note.remove'
@ -46,7 +32,7 @@ _cmd_remove = 'note.remove'
@cr.register('记笔记', '添加笔记') @cr.register('记笔记', '添加笔记')
@cr.register('take', 'add', hidden=True) @cr.register('take', 'add', hidden=True)
@cr.restrict(group_admin_only=True) @cr.restrict(group_admin_only=True)
@_check_target @check_target
def take(args_text, ctx_msg, allow_interactive=True): def take(args_text, ctx_msg, allow_interactive=True):
source = get_source(ctx_msg) source = get_source(ctx_msg)
if allow_interactive and (not args_text or has_session(source, _cmd_take)): if allow_interactive and (not args_text or has_session(source, _cmd_take)):
@ -67,7 +53,7 @@ def take(args_text, ctx_msg, allow_interactive=True):
@cr.register('列出所有笔记', '查看所有笔记', '所有笔记') @cr.register('列出所有笔记', '查看所有笔记', '所有笔记')
@cr.register('list', hidden=True) @cr.register('list', hidden=True)
@_check_target @check_target
def list_all(_, ctx_msg): def list_all(_, ctx_msg):
conn = _open_db_conn() conn = _open_db_conn()
target = get_target(ctx_msg) target = get_target(ctx_msg)
@ -90,7 +76,7 @@ def list_all(_, ctx_msg):
@cr.register('删除笔记') @cr.register('删除笔记')
@cr.register('remove', 'delete', hidden=True) @cr.register('remove', 'delete', hidden=True)
@cr.restrict(group_admin_only=True) @cr.restrict(group_admin_only=True)
@_check_target @check_target
def remove(args_text, ctx_msg, allow_interactive=True): def remove(args_text, ctx_msg, allow_interactive=True):
source = get_source(ctx_msg) source = get_source(ctx_msg)
if allow_interactive and (not args_text or has_session(source, _cmd_remove)): if allow_interactive and (not args_text or has_session(source, _cmd_remove)):
@ -118,7 +104,7 @@ def remove(args_text, ctx_msg, allow_interactive=True):
@cr.register('清空笔记', '清空所有笔记', '删除所有笔记') @cr.register('清空笔记', '清空所有笔记', '删除所有笔记')
@cr.register('clear', hidden=True) @cr.register('clear', hidden=True)
@cr.restrict(group_admin_only=True) @cr.restrict(group_admin_only=True)
@_check_target @check_target
def clear(_, ctx_msg): def clear(_, ctx_msg):
conn = _open_db_conn() conn = _open_db_conn()
target = get_target(ctx_msg) target = get_target(ctx_msg)

View File

@ -29,6 +29,7 @@ _scheduler = BackgroundScheduler(
_command_args_start_flags = get_command_args_start_flags() _command_args_start_flags = get_command_args_start_flags()
_args_split_sep = '[ \n\t]' _args_split_sep = '[ \n\t]'
_job_id_suffix_start = '@'
def _init(): def _init():
@ -148,7 +149,7 @@ def add_job(args_text, ctx_msg, internal=False):
if len(tmp) < 2: if len(tmp) < 2:
raise _IncompleteArgsError raise _IncompleteArgsError
job_id_without_suffix, command_raw = tmp job_id_without_suffix, command_raw = tmp
job_id = job_id_without_suffix + '_' + get_target(ctx_msg) job_id = job_id_without_suffix + _job_id_suffix_start + get_target(ctx_msg)
command_list = [] command_list = []
if multi: if multi:
command_raw_list = command_raw.split('\n') command_raw_list = command_raw.split('\n')
@ -190,7 +191,7 @@ def remove_job(args_text, ctx_msg, internal=False):
if not job_id_without_suffix: if not job_id_without_suffix:
_send_text('请指定计划任务的 ID', ctx_msg, internal) _send_text('请指定计划任务的 ID', ctx_msg, internal)
return False return False
job_id = job_id_without_suffix + '_' + get_target(ctx_msg) job_id = job_id_without_suffix + _job_id_suffix_start + get_target(ctx_msg)
try: try:
_scheduler.remove_job(job_id, 'default') _scheduler.remove_job(job_id, 'default')
_send_text('成功删除计划任务 ' + job_id_without_suffix, ctx_msg, internal) _send_text('成功删除计划任务 ' + job_id_without_suffix, ctx_msg, internal)
@ -208,9 +209,11 @@ def get_job(args_text, ctx_msg, internal=False):
if not job_id_without_suffix: if not job_id_without_suffix:
_send_text('请指定计划任务的 ID', ctx_msg, internal) _send_text('请指定计划任务的 ID', ctx_msg, internal)
return None return None
job_id = job_id_without_suffix + '_' + get_target(ctx_msg) job_id = job_id_without_suffix + _job_id_suffix_start + get_target(ctx_msg)
job = _scheduler.get_job(job_id, 'default') job = _scheduler.get_job(job_id, 'default')
if internal: if internal:
if job:
job.id = job_id_without_suffix
return job return job
if not job: if not job:
core.echo('没有找到该计划任务,请指定正确的计划任务 ID', ctx_msg, internal) core.echo('没有找到该计划任务,请指定正确的计划任务 ID', ctx_msg, internal)
@ -220,7 +223,7 @@ def get_job(args_text, ctx_msg, internal=False):
reply += '下次触发时间:\n%s\n' % job.next_run_time.strftime('%Y-%m-%d %H:%M') reply += '下次触发时间:\n%s\n' % job.next_run_time.strftime('%Y-%m-%d %H:%M')
reply += '命令:\n' reply += '命令:\n'
command_list = job.kwargs['command_list'] command_list = job.kwargs['command_list']
reply += _convert_command_list_to_str(command_list) reply += convert_command_list_to_str(command_list)
_send_text(reply, ctx_msg, internal) _send_text(reply, ctx_msg, internal)
@ -229,9 +232,11 @@ def get_job(args_text, ctx_msg, internal=False):
@_check_target @_check_target
def list_jobs(_, ctx_msg, internal=False): def list_jobs(_, ctx_msg, internal=False):
target = get_target(ctx_msg) target = get_target(ctx_msg)
job_id_suffix = '_' + target job_id_suffix = _job_id_suffix_start + target
jobs = list(filter(lambda j: j.id.endswith(job_id_suffix), _scheduler.get_jobs('default'))) jobs = list(filter(lambda j: j.id.endswith(job_id_suffix), _scheduler.get_jobs('default')))
if internal: if internal:
for job in jobs:
job.id = job.id[:-len(job_id_suffix)]
return jobs return jobs
for job in jobs: for job in jobs:
@ -240,7 +245,7 @@ def list_jobs(_, ctx_msg, internal=False):
reply = 'ID' + job_id + '\n' reply = 'ID' + job_id + '\n'
reply += '下次触发时间:\n%s\n' % job.next_run_time.strftime('%Y-%m-%d %H:%M') reply += '下次触发时间:\n%s\n' % job.next_run_time.strftime('%Y-%m-%d %H:%M')
reply += '命令:\n' reply += '命令:\n'
reply += _convert_command_list_to_str(command_list) reply += convert_command_list_to_str(command_list)
_send_text(reply, ctx_msg, internal) _send_text(reply, ctx_msg, internal)
if len(jobs): if len(jobs):
_send_text('以上', ctx_msg, internal) _send_text('以上', ctx_msg, internal)
@ -256,12 +261,12 @@ def execute_job(args_text, ctx_msg, internal=False):
if not job: if not job:
core.echo('没有找到该计划任务,请指定正确的计划任务 ID', ctx_msg, internal) core.echo('没有找到该计划任务,请指定正确的计划任务 ID', ctx_msg, internal)
return return
job_id_suffix = '_' + get_target(ctx_msg) job_id_suffix = _job_id_suffix_start + get_target(ctx_msg)
job_id = job.id[:-len(job_id_suffix)] job_id = job.id[:-len(job_id_suffix)]
_call_commands(job_id, job.kwargs['command_list'], job.kwargs['ctx_msg'], internal) _call_commands(job_id, job.kwargs['command_list'], job.kwargs['ctx_msg'], internal)
def _convert_command_list_to_str(command_list): def convert_command_list_to_str(command_list):
s = '' s = ''
if len(command_list) > 1: if len(command_list) > 1:
for c in command_list: for c in command_list:

164
commands/subscribe.py Normal file
View File

@ -0,0 +1,164 @@
import re
from datetime import datetime
from command import CommandRegistry, split_arguments
from commands import core, scheduler
from interactive import *
from little_shit import get_source, check_target
__registry__ = cr = CommandRegistry()
_cmd_subscribe = 'subscribe.subscribe'
_scheduler_job_id_prefix = _cmd_subscribe + '_'
@cr.register('subscribe', '订阅')
@cr.restrict(group_admin_only=True)
@split_arguments(maxsplit=1)
@check_target
def subscribe(args_text, ctx_msg, argv=None, allow_interactive=True):
source = get_source(ctx_msg)
if allow_interactive and has_session(source, _cmd_subscribe):
# Already in a session, no need to pass in data,
# because the interactive version of this command will take care of it
return _subscribe_interactively(args_text, ctx_msg, source, None)
data = {}
if argv:
m = re.match('([0-1]\d|[2][0-3])(?::|)?([0-5]\d)', argv[0])
if not m:
# Got command but no time
data['command'] = args_text
else:
# Got time
data['hour'], data['minute'] = m.group(1), m.group(2)
if len(argv) == 2:
# Got command
data['command'] = argv[1]
if allow_interactive:
if data.keys() != {'command', 'hour', 'minute'}:
# First visit and data is not enough
return _subscribe_interactively(args_text, ctx_msg, source, data)
# Got both time and command, do the job!
hour, minute = data['hour'], data['minute']
command = data['command']
job = scheduler.add_job(
'-H %s -M %s %s %s' % (hour, minute, _scheduler_job_id_prefix + str(datetime.now().timestamp()), command),
ctx_msg, internal=True
)
if job:
# Succeeded to add a job
print('成功订阅:', hour, minute, command)
reply = '订阅成功,我会在每天 %s 推送哦~' % ':'.join((hour, minute))
else:
reply = '订阅失败,可能后台出了点小问题~'
core.echo(reply, ctx_msg)
@cr.register('subscribe_list', 'subscribe-list', '订阅列表', '查看订阅', '查看所有订阅', '所有订阅')
@cr.restrict(group_admin_only=True)
@check_target
def subscribe_list(_, ctx_msg, internal=False):
jobs = sorted(filter(
lambda j: j.id.startswith(_scheduler_job_id_prefix),
scheduler.list_jobs('', ctx_msg, internal=True)
), key=lambda j: j.id)
if internal:
return jobs
if not jobs:
core.echo('暂时还没有订阅哦~', ctx_msg)
return
for index, job in enumerate(jobs):
command_list = job.kwargs['command_list']
reply = 'ID' + str(index + 1) + '\n'
reply += '下次推送时间:\n%s\n' % job.next_run_time.strftime('%Y-%m-%d %H:%M')
reply += '命令:\n'
reply += scheduler.convert_command_list_to_str(command_list)
core.echo(reply, ctx_msg)
core.echo('以上~', ctx_msg)
@cr.register('unsubscribe', '取消订阅')
@cr.restrict(group_admin_only=True)
@split_arguments()
@check_target
def unsubscribe(_, ctx_msg, argv=None, internal=False):
if not argv:
core.echo('请在命令名后指定要取消订阅的 ID多个 ID、ID 和命令名之间用空格隔开)哦~\n\n'
'你可以通过「查看所有订阅」命令来查看所有订阅项目的 ID', ctx_msg, internal)
return
jobs = subscribe_list('', ctx_msg, internal=True)
min_id = 1
max_id = len(jobs)
if not all(map(lambda x: x.isdigit() and int(x) in range(min_id, max_id + 1), argv)):
core.echo('请输入正确的 ID 哦~\n\n'
'你可以通过「查看所有订阅」命令来查看所有订阅项目的 ID', ctx_msg, internal)
result = []
for i in argv:
result.append(scheduler.remove_job(jobs[int(i) - 1].id, ctx_msg, internal=True))
if all(result):
core.echo('取消订阅成功~', ctx_msg, internal)
else:
core.echo('出了点小问题,可能有一些订阅项目没有成功取消订阅,请使用「查看所有订阅」命令来检查哦~',
ctx_msg, internal)
def _subscribe_interactively(args_text, ctx_msg, source, data):
sess = get_session(source, _cmd_subscribe)
if data:
sess.data.update(data)
state_command = 1
state_time = 2
state_finish = -1
if sess.state == state_command:
if not args_text.strip():
core.echo('你输入的命令不正确,请重新发送订阅命令哦~', ctx_msg)
sess.state = state_finish
else:
sess.data['command'] = args_text
elif sess.state == state_time:
m = re.match('([0-1]\d|[2][0-3])(?::|)?([0-5]\d)', args_text.strip())
if not m:
core.echo('你输入的时间格式不正确,请重新发送订阅命令哦~', ctx_msg)
sess.state = state_finish
else:
sess.data['hour'], sess.data['minute'] = m.group(1), m.group(2)
if sess.state == state_finish:
remove_session(source, _cmd_subscribe)
return
if 'command' not in sess.data:
# Ask for command
core.echo(
'请输入你需要订阅的命令(包括所需的参数),不需要加开头的斜杠哦~\n\n'
'例如(序号后的):\n'
'(1) 天气 南京\n'
'(2) 知乎日报\n'
'(3) 历史上的今天',
ctx_msg
)
sess.state = state_command
return
if 'hour' not in sess.data or 'minute' not in sess.data:
# Ask for time
core.echo('请输入你需要推送的时间,格式如 22:00', ctx_msg)
sess.state = state_time
return
subscribe(
'', ctx_msg,
argv=[':'.join((sess.data['hour'], sess.data['minute'])), sess.data['command']],
allow_interactive=False
)
remove_session(source, _cmd_subscribe)

View File

@ -1,6 +1,6 @@
import sqlite3 import sqlite3
from command import CommandRegistry, split_args from command import CommandRegistry, split_arguments
from commands import core from commands import core
from little_shit import get_default_db_path, get_target from little_shit import get_default_db_path, get_target
@ -26,16 +26,16 @@ def test(_, ctx_msg):
@cr.register('block') @cr.register('block')
@cr.restrict(full_command_only=True, superuser_only=True) @cr.restrict(full_command_only=True, superuser_only=True)
@split_args(maxsplit=2) @split_arguments(maxsplit=2)
def block(args, ctx_msg): def block(_, ctx_msg, argv=None):
def _send_error_msg(): def _send_error_msg():
core.echo('参数不正确。\n\n正确使用方法:\nsudo.block wx|qq <account-to-block>', ctx_msg) core.echo('参数不正确。\n\n正确使用方法:\nsudo.block wx|qq <account-to-block>', ctx_msg)
if len(args) != 2: if len(argv) != 2:
_send_error_msg() _send_error_msg()
return return
via, account = args via, account = argv
# Get a target using a fake context message # Get a target using a fake context message
target = get_target({ target = get_target({
'via': via, 'via': via,
@ -74,16 +74,16 @@ def block_list(_, ctx_msg, internal=False):
@cr.register('unblock') @cr.register('unblock')
@cr.restrict(full_command_only=True, superuser_only=True) @cr.restrict(full_command_only=True, superuser_only=True)
@split_args(maxsplit=2) @split_arguments(maxsplit=2)
def unblock(args, ctx_msg): def unblock(_, ctx_msg, argv=None):
def _send_error_msg(): def _send_error_msg():
core.echo('参数不正确。\n\n正确使用方法:\nsudo.unblock wx|qq <account-to-unblock>', ctx_msg) core.echo('参数不正确。\n\n正确使用方法:\nsudo.unblock wx|qq <account-to-unblock>', ctx_msg)
if len(args) != 2: if len(argv) != 2:
_send_error_msg() _send_error_msg()
return return
via, account = args via, account = argv
# Get a target using a fake context message # Get a target using a fake context message
target = get_target({ target = get_target({
'via': via, 'via': via,

View File

@ -5,7 +5,7 @@ from datetime import datetime, timedelta
import requests import requests
from command import CommandRegistry, split_args from command import CommandRegistry, split_arguments
from commands import core from commands import core
from little_shit import get_source, get_db_dir, get_tmp_dir from little_shit import get_source, get_db_dir, get_tmp_dir
from interactive import * from interactive import *
@ -25,14 +25,14 @@ _weekday_string = ['周一', '周二', '周三', '周四', '周五', '周六', '
@cr.register('weather') @cr.register('weather')
@cr.register('天气', '查天气', '天气预报', '查天气预报') @cr.register('天气', '查天气', '天气预报', '查天气预报')
@split_args() @split_arguments()
def weather(args, ctx_msg, allow_interactive=True): def weather(args_text, ctx_msg, argv: list = None, allow_interactive=True):
source = get_source(ctx_msg) source = get_source(ctx_msg)
if allow_interactive and (len(args) < 1 or not args[0].startswith('CN') or has_session(source, _cmd_weather)): if allow_interactive and (not argv or not argv[0].startswith('CN') or has_session(source, _cmd_weather)):
# Be interactive # Be interactive
return _do_interactively(_cmd_weather, weather, args, ctx_msg, source) return _do_interactively(_cmd_weather, weather, args_text.strip(), ctx_msg, source)
city_id = args[0] city_id = argv[0]
text = '' text = ''
data = _get_weather(city_id) data = _get_weather(city_id)
@ -41,12 +41,13 @@ def weather(args, ctx_msg, allow_interactive=True):
now = data['now'] now = data['now']
aqi = data['aqi']['city'] aqi = data['aqi']['city']
text += '\n\n实时:\n%s,气温%s˚C体感温度%s˚C%s%s级,能见度%skm空气质量指数%s%sPM2.5%sPM10%s' \ text += '\n\n实时:\n\n%s,气温%s˚C体感温度%s˚C%s%s级,' \
'能见度%skm空气质量指数%s%sPM2.5%sPM10%s' \
% (now['cond']['txt'], now['tmp'], now['fl'], now['wind']['dir'], now['wind']['sc'], now['vis'], % (now['cond']['txt'], now['tmp'], now['fl'], now['wind']['dir'], now['wind']['sc'], now['vis'],
aqi['aqi'], aqi['qlty'], aqi['pm25'], aqi['pm10']) aqi['aqi'], aqi['qlty'], aqi['pm25'], aqi['pm10'])
daily_forecast = data['daily_forecast'] daily_forecast = data['daily_forecast']
text += '\n\n预报:\n' text += '\n\n预报:\n\n'
for forecast in daily_forecast: for forecast in daily_forecast:
d = datetime.strptime(forecast['date'], '%Y-%m-%d') d = datetime.strptime(forecast['date'], '%Y-%m-%d')
@ -59,24 +60,25 @@ def weather(args, ctx_msg, allow_interactive=True):
text += forecast['tmp']['min'] + '~' + forecast['tmp']['max'] + '°C' text += forecast['tmp']['min'] + '~' + forecast['tmp']['max'] + '°C'
text += forecast['wind']['dir'] + forecast['wind']['sc'] + '级,' text += forecast['wind']['dir'] + forecast['wind']['sc'] + '级,'
text += '降雨概率%s%%' % forecast['pop'] text += '降雨概率%s%%' % forecast['pop']
text += '\n' text += '\n\n'
text = text.rstrip()
if text: if text:
core.echo(text, ctx_msg) core.echo(text, ctx_msg)
else: else:
core.echo('查询失败了,请稍后再试哦~', ctx_msg) core.echo('查询失败了,请稍后再试哦~', ctx_msg)
@cr.register('suggestion') @cr.register('suggestion', hidden=True)
@cr.register('生活指数', '生活建议', '天气建议') @cr.register('生活指数', '生活建议', '天气建议')
@split_args() @split_arguments()
def suggestion(args, ctx_msg, allow_interactive=True): def suggestion(args_text, ctx_msg, argv: list = None, allow_interactive=True):
source = get_source(ctx_msg) source = get_source(ctx_msg)
if allow_interactive and (len(args) < 1 or not args[0].startswith('CN') or has_session(source, _cmd_suggestion)): if allow_interactive and (len(argv) < 1 or not argv[0].startswith('CN') or has_session(source, _cmd_suggestion)):
# Be interactive # Be interactive
return _do_interactively(_cmd_suggestion, suggestion, args, ctx_msg, source) return _do_interactively(_cmd_suggestion, suggestion, args_text.strip(), ctx_msg, source)
city_id = args[0] city_id = argv[0]
text = '' text = ''
data = _get_weather(city_id) data = _get_weather(city_id)
@ -101,9 +103,9 @@ def suggestion(args, ctx_msg, allow_interactive=True):
_state_machines = {} _state_machines = {}
def _do_interactively(command_name, func, args, ctx_msg, source): def _do_interactively(command_name, func, args_text, ctx_msg, source):
def ask_for_city(s, a, c): def ask_for_city(s, a, c):
if len(a) > 0: if a:
if search_city(s, a, c): if search_city(s, a, c):
return True return True
else: else:
@ -111,11 +113,11 @@ def _do_interactively(command_name, func, args, ctx_msg, source):
s.state += 1 s.state += 1
def search_city(s, a, c): def search_city(s, a, c):
if len(a) < 1: if not a:
core.echo('你输入的城市不正确哦,请重新发送命令~', c) core.echo('你输入的城市不正确哦,请重新发送命令~', c)
return True return True
city_list = _get_city_list(a[0]) city_list = _get_city_list(a)
if not city_list: if not city_list:
core.echo('没有找到你输入的城市哦,请重新发送命令~', c) core.echo('没有找到你输入的城市哦,请重新发送命令~', c)
@ -125,7 +127,7 @@ def _do_interactively(command_name, func, args, ctx_msg, source):
if len(city_list) == 1: if len(city_list) == 1:
# Directly choose the first one # Directly choose the first one
choose_city(s, ['1'], c) choose_city(s, '1', c)
return True return True
# Here comes more than one city with the same name # Here comes more than one city with the same name
@ -140,11 +142,11 @@ def _do_interactively(command_name, func, args, ctx_msg, source):
s.state += 1 s.state += 1
def choose_city(s, a, c): def choose_city(s, a, c):
if len(a) != 1 or not a[0].isdigit(): if not a or not a.isdigit():
core.echo('你输入的序号不正确哦,请重新发送命令~', c) core.echo('你输入的序号不正确哦,请重新发送命令~', c)
return True return True
choice = int(a[0]) - 1 # Should be from 0 to len(city_list) - 1 choice = int(a) - 1 # Should be from 0 to len(city_list) - 1
city_list = s.data['city_list'] city_list = s.data['city_list']
if choice < 0 or choice >= len(city_list): if choice < 0 or choice >= len(city_list):
core.echo('你输入的序号超出范围了,请重新发送命令~', c) core.echo('你输入的序号超出范围了,请重新发送命令~', c)
@ -164,7 +166,7 @@ def _do_interactively(command_name, func, args, ctx_msg, source):
sess = get_session(source, command_name) sess = get_session(source, command_name)
sess.data['func'] = func sess.data['func'] = func
if _state_machines[command_name][sess.state](sess, args, ctx_msg): if _state_machines[command_name][sess.state](sess, args_text, ctx_msg):
# Done # Done
remove_session(source, command_name) remove_session(source, command_name)

View File

@ -104,13 +104,13 @@ Source 表示命令的来源由谁发出Target 表示命令将对谁产
## 命令参数 ## 命令参数
命令的函数的第一个参数为命令参数,默认情况下,是一个字符串,即用户发送的消息中命令后面的内容,可以自行切割、分析。如果需要使用默认的命令参数分隔符,可以使用 `command.py` 中的 `split_args` 装饰器,使用之后,命令的函数接收到的第一个参数将变为命令参数列表,而不再是字符串。例如: 命令的函数的第一个参数为命令参数,默认情况下,是一个字符串,即用户发送的消息中命令后面的内容,可以自行切割、分析。如果需要使用默认的命令参数分隔符,可以使用 `command.py` 中的 `split_arguments` 装饰器,使用之后,命令的函数将接受到一个名为 `argv` 的参数,为分割后的参数列表,而原先第一个参数还保留为原字符串。例如:
```python ```python
@__registry__.register('test') @__registry__.register('test')
@__registry__.restrict(group_admin_only=True) @__registry__.restrict(group_admin_only=True)
@split_args() @split_arguments()
def test(args, ctx_msg): def test(args_text, ctx_msg, argv=None):
if len(args) > 0: if argv:
print(args[0]) print(args[0])
``` ```

View File

@ -1,9 +1,11 @@
import os import os
import hashlib import hashlib
import random import random
import functools
from datetime import datetime from datetime import datetime
from config import config from config import config
from apiclient import client as api
class SkipException(Exception): class SkipException(Exception):
@ -87,6 +89,23 @@ def get_target(ctx_msg):
return None return None
def check_target(func):
"""
This decorator checks whether there is a target value, and prevent calling the function if not.
"""
@functools.wraps(func)
def wrapper(args_text, ctx_msg, *args, **kwargs):
target = get_target(ctx_msg)
if not target:
api.send_message('当前语境无法使用这个命令,请尝试发送私聊消息或稍后再试吧~', ctx_msg)
return
else:
return func(args_text, ctx_msg, *args, **kwargs)
return wrapper
def get_command_start_flags(): def get_command_start_flags():
return tuple(sorted(config.get('command_start_flags', ('',)), reverse=True)) return tuple(sorted(config.get('command_start_flags', ('',)), reverse=True))
@ -96,11 +115,11 @@ def get_command_name_separators():
def get_command_args_start_flags(): def get_command_args_start_flags():
return tuple(sorted(('[ \t\n]',) + config.get('command_args_start_flags', ()), reverse=True)) return tuple(sorted(('[ \t\n]+',) + config.get('command_args_start_flags', ()), reverse=True))
def get_command_args_separators(): def get_command_args_separators():
return tuple(sorted(('[ \t\n]',) + config.get('command_args_separators', ()), reverse=True)) return tuple(sorted(('[ \t\n]+',) + config.get('command_args_separators', ()), reverse=True))
def get_fallback_command(): def get_fallback_command():