Archived
1
0
Fork 0
This repository has been archived on 2024-04-26. You can view files and clone it, but cannot push or open issues or pull requests.
akari-bot/modules/calc/__init__.py

133 lines
6 KiB
Python
Raw Normal View History

2023-05-10 15:26:04 +00:00
import asyncio
import os
import subprocess
import sys
import time
2023-05-11 15:19:55 +00:00
import ujson as json
2023-05-10 15:26:04 +00:00
from core.builtins import Bot
from core.component import module
from core.exceptions import NoReportException
from core.logger import Logger
2023-05-10 15:48:59 +00:00
calc_dir = os.path.dirname(os.path.abspath(__file__))
2023-05-10 15:26:04 +00:00
c = module('calc', developers=[
'Dianliang233'], desc='{calc.calc.help.desc}')
@c.command('<math_expression>', options_desc={'+': '{calc.calc.help.plus}',
'-': '{calc.calc.help.minus}',
'/': '{calc.calc.help.multiply}',
'*': '{calc.calc.help.divide}',
'**': '{calc.calc.help.power}',
'%': '{calc.calc.help.modulo}',
'==': '{calc.calc.help.equal}',
'<=': '{calc.calc.help.less_equal}',
'>=': '{calc.calc.help.greater_equal}',
'>>': '{calc.calc.help.move_right}',
'<<': '{calc.calc.help.move_left}',
'^': '{calc.calc.help.xor}',
'not': '{calc.calc.help.not}',
'is': '{calc.calc.help.is}',
'randint(x)': '{calc.calc.help.randint}',
'rand()': '{calc.calc.help.rand}',
'int()': '{calc.calc.help.int}',
'float()': '{calc.calc.help.float}',
'str()': '{calc.calc.help.str}',
'complex()': '{calc.calc.help.complex}',
'bool()': '{calc.calc.help.bool}',
'bin()': '{calc.calc.help.bin}',
'oct()': '{calc.calc.help.oct}',
'hex()': '{calc.calc.help.hex}',
'{calc.calc.help.more}': 'https://bot.teahouse.team/-/340',
})
async def _(msg: Bot.MessageSession):
expr = msg.asDisplay().split(' ', 1)[1]
2023-05-11 15:19:55 +00:00
start = time.perf_counter_ns()
res = await spawn_subprocess('/calc.py', expr, msg)
stop = time.perf_counter_ns()
delta = (stop - start) / 1000000
if res[:6] == 'Result':
if msg.target.senderFrom == "Discord|Client":
m = f'`{(expr)}` = {res[7:]}'
else:
m = f'{(expr)} = {res[7:]}'
if msg.checkSuperUser():
m += '\n' + msg.locale.t("calc.message.running_time", time=delta)
await msg.finish(m)
else:
await msg.finish(msg.locale.t("calc.calc.message.invalid", expr={res[7:]}))
2023-05-11 15:31:12 +00:00
factor = module('factor', developers=['DoroWolf, Light-Beacon', 'Dianliang233'])
2023-05-11 15:19:55 +00:00
@factor.handle('prime <number> {{calc.factor.prime.help}}')
async def prime(msg: Bot.MessageSession):
try:
2023-05-11 15:31:12 +00:00
num_str = msg.parsed_msg.get('<number>')
if num_str is None:
raise ValueError
2023-05-11 15:37:45 +00:00
num = int(num_str)
2023-05-11 15:19:55 +00:00
if num <= 1:
return await msg.finish(msg.locale.t('calc.factor.prime.message.error'))
except ValueError:
return await msg.finish(msg.locale.t('calc.factor.prime.message.error'))
start = time.perf_counter_ns()
res = await spawn_subprocess('/factor.py', str(num), msg)
stop = time.perf_counter_ns()
delta = (stop - start) / 1000000
2023-05-11 15:31:12 +00:00
if res[:6] != 'Result':
2023-05-11 15:19:55 +00:00
raise ValueError(res)
2023-05-11 15:31:12 +00:00
primes = json.loads(res[7:])
prime = "*".join(primes)
if len(primes) == 1:
m = msg.locale.t("calc.factor.prime.message.is_prime", num=num)
2023-05-12 10:58:03 +00:00
else:
m = (
f'{num} = `{prime}`'
if msg.target.senderFrom == "Discord|Client"
else f'{num} = {prime}'
)
2023-05-11 15:31:12 +00:00
if msg.checkSuperUser():
m += '\n' + msg.locale.t("calc.message.running_time", time=delta)
await msg.finish(m)
2023-05-11 15:19:55 +00:00
2023-05-12 10:58:03 +00:00
async def spawn_subprocess(file: str, arg: str, msg: Bot.MessageSession) -> str:
2023-05-11 17:18:00 +00:00
envs = os.environ.copy()
2023-05-10 15:26:04 +00:00
if sys.platform == 'win32' and sys.version_info.minor < 10:
try:
2023-05-11 15:19:55 +00:00
return subprocess.check_output(
2023-05-12 10:58:03 +00:00
[sys.executable, calc_dir + file, arg], timeout=10, shell=False,
2023-05-11 17:18:00 +00:00
cwd=os.path.abspath('.'), env=envs) \
2023-05-10 15:26:04 +00:00
.decode('utf-8')
2023-05-11 15:31:12 +00:00
except subprocess.TimeoutExpired as e:
2023-05-14 01:18:23 +00:00
raise NoReportException(msg.locale.t("calc.message.time_out")) from e
2023-05-10 15:26:04 +00:00
else:
try:
2023-05-11 15:19:55 +00:00
p = await asyncio.create_subprocess_exec(sys.executable, calc_dir + file,
2023-05-12 10:58:03 +00:00
arg,
2023-05-10 15:26:04 +00:00
stdout=asyncio.subprocess.PIPE,
2023-05-11 17:18:00 +00:00
stderr=asyncio.subprocess.PIPE,
cwd=os.path.abspath('.'), env=envs
2023-05-10 15:26:04 +00:00
)
try:
await asyncio.wait_for(p.wait(), timeout=10)
2023-05-11 15:31:12 +00:00
except asyncio.TimeoutError as e:
2023-05-10 15:26:04 +00:00
p.kill()
2023-05-11 15:31:12 +00:00
raise NoReportException(msg.locale.t("calc.message.time_out")) from e
2023-05-10 15:26:04 +00:00
stdout_data, stderr_data = await p.communicate()
2023-05-11 15:19:55 +00:00
if p.returncode != 0:
2023-05-11 15:31:12 +00:00
Logger.error(f'{file} exited with code {p.returncode}')
2023-05-10 15:26:04 +00:00
try:
Logger.error(
2023-05-11 15:31:12 +00:00
f'{file} stderr: {stderr_data.decode("utf-8")}')
2023-05-10 15:26:04 +00:00
except UnicodeDecodeError:
Logger.error(
2023-05-11 15:31:12 +00:00
f'{file} stderr: {stderr_data.decode("gbk")}')
2023-05-11 15:19:55 +00:00
return stdout_data.decode('utf-8')
2023-05-10 15:26:04 +00:00
except Exception as e:
2023-05-11 15:31:12 +00:00
raise NoReportException(e) from e