Skip to content

Commit

Permalink
✨查询机器使用状况
Browse files Browse the repository at this point in the history
  • Loading branch information
wling-art committed Jan 9, 2024
1 parent 186ef0e commit 5ad088a
Show file tree
Hide file tree
Showing 8 changed files with 446 additions and 1 deletion.
54 changes: 53 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ nonebot-plugin-eventexpiry = "^0.1.1"
imageio = "^2.33.1"
pillow = "^9.0.0"
nonebot-plugin-datastore = "^1.1.2"
humanize = "^4.9.0"
psutil = "^5.9.7"


[build-system]
Expand Down
120 changes: 120 additions & 0 deletions src/plugins/nonebot_plugin_status/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
"""
@Author : yanyongyu
@Date : 2020-09-18 00:00:13
@LastEditors : yanyongyu
@LastEditTime : 2023-12-01 10:41:28
@Description : Status plugin
@GitHub : https://github.com/yanyongyu
"""

__author__ = "yanyongyu"

import inspect
import contextlib
from typing import Any, Dict

from jinja2 import Environment
from nonebot import get_driver
from nonebot.matcher import Matcher
from nonebot.permission import SUPERUSER
from nonebot.plugin import PluginMetadata
from jinja2.meta import find_undeclared_variables

from .config import Config
from .helpers import humanize_date, relative_time, humanize_delta
from .data_source import (
get_uptime,
get_cpu_status,
get_disk_usage,
per_cpu_status,
get_swap_status,
get_memory_status,
get_bot_connect_time,
get_nonebot_run_time,
)

__plugin_meta__ = PluginMetadata(
name="服务器状态查看",
description="通过戳一戳获取服务器状态",
usage=(
"通过QQ私聊戳一戳或拍一拍头像获取机器人服务器状态\n"
"或者通过发送指令 `status/状态` 获取机器人服务器状态\n"
"可以通过配置文件修改服务器状态模板"
),
type="application",
homepage="https://github.com/cscs181/QQ-GitHub-Bot/tree/master/src/plugins/nonebot_plugin_status",
config=Config,
supported_adapters=None,
)

global_config = get_driver().config
status_config = Config.parse_obj(global_config)
status_permission = (status_config.server_status_only_superusers or None) and SUPERUSER

_ev = Environment(
trim_blocks=True, lstrip_blocks=True, autoescape=False, enable_async=True
)
_ev.globals["relative_time"] = relative_time
_ev.filters["relative_time"] = relative_time
_ev.filters["humanize_date"] = humanize_date
_ev.globals["humanize_date"] = humanize_date
_ev.filters["humanize_delta"] = humanize_delta
_ev.globals["humanize_delta"] = humanize_delta

_t_ast = _ev.parse(status_config.server_status_template)
_t_vars = find_undeclared_variables(_t_ast)
_t = _ev.from_string(_t_ast)

KNOWN_VARS = {
"cpu_usage": get_cpu_status,
"per_cpu_usage": per_cpu_status,
"memory_usage": get_memory_status,
"swap_usage": get_swap_status,
"disk_usage": get_disk_usage,
"uptime": get_uptime,
"runtime": get_nonebot_run_time,
"bot_connect_time": get_bot_connect_time,
}
"""Available variables for template rendering."""


if not set(_t_vars).issubset(KNOWN_VARS):
raise ValueError(
"Unknown variables in status template:"
f" {', '.join(set(_t_vars) - set(KNOWN_VARS))}"
)


async def _solve_required_vars() -> Dict[str, Any]:
"""Solve required variables for template rendering."""
return (
{
k: await v() if inspect.iscoroutinefunction(v) else v()
for k, v in KNOWN_VARS.items()
if k in _t_vars
}
if status_config.server_status_truncate
else {
k: await v() if inspect.iscoroutinefunction(v) else v()
for k, v in KNOWN_VARS.items()
}
)


async def render_template() -> str:
"""Render status template with required variables."""
message = await _t.render_async(**(await _solve_required_vars()))
return message.strip("\n")


async def server_status(matcher: Matcher):
"""Server status matcher handler."""
await matcher.send(message=await render_template())


from . import common as common # noqa: E402

with contextlib.suppress(ImportError):
import nonebot.adapters.onebot.v11 # noqa: F401

from . import onebot_v11 as onebot_v11
24 changes: 24 additions & 0 deletions src/plugins/nonebot_plugin_status/common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""
@Author : yanyongyu
@Date : 2020-09-18 00:00:13
@LastEditors : yanyongyu
@LastEditTime : 2023-03-30 18:26:14
@Description : Common text matcher for status plugin
@GitHub : https://github.com/yanyongyu
"""

__author__ = "yanyongyu"

from nonebot import on_command

from . import server_status, status_config, status_permission

if status_config.server_status_enabled:
command = on_command(
"status",
aliases={"状态"},
permission=status_permission,
priority=10,
handlers=[server_status],
)
"""`status`/`状态` command matcher"""
68 changes: 68 additions & 0 deletions src/plugins/nonebot_plugin_status/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
"""
@Author : yanyongyu
@Date : 2020-10-04 16:32:00
@LastEditors : yanyongyu
@LastEditTime : 2023-03-30 18:17:09
@Description : Config for status plugin
@GitHub : https://github.com/yanyongyu
"""

__author__ = "yanyongyu"


from pydantic import Extra, BaseModel

CPU_TEMPLATE = r"CPU: {{ '%02d' % cpu_usage }}%"
"""Default CPU status template."""

# PER_CPU_TEMPLATE = (
# "CPU:\n"
# "{%- for core in per_cpu_usage %}\n"
# " core{{ loop.index }}: {{ '%02d' % core }}%\n"
# "{%- endfor %}"
# )

MEMORY_TEMPLATE = r"Memory: {{ '%02d' % memory_usage.percent }}%"
"""Default memory status template."""

SWAP_TEMPLATE = (
r"{% if swap_usage.total %}Swap: {{ '%02d' % swap_usage.percent }}%{% endif +%}"
)
"""Default swap status template."""

DISK_TEMPLATE = (
"Disk:\n"
"{% for name, usage in disk_usage.items() %}\n"
" {{ name }}: {{ '%02d' % usage.percent }}%\n"
"{% endfor %}"
)
"""Default disk status template."""

UPTIME_TEMPLATE = "Uptime: {{ uptime | relative_time | humanize_delta }}"
"""Default uptime status template."""

RUNTIME_TEMPLATE = "Runtime: {{ runtime | relative_time | humanize_delta }}"
"""Default runtime status template."""


class Config(BaseModel, extra=Extra.ignore):
server_status_enabled: bool = True
"""Whether to enable the server status commands."""
server_status_truncate: bool = True
"""Whether to render the status template with used variables only."""
server_status_only_superusers: bool = True
"""Whether to allow only superusers to use the status commands."""

server_status_template: str = "\n".join(
(CPU_TEMPLATE, MEMORY_TEMPLATE, RUNTIME_TEMPLATE, SWAP_TEMPLATE, DISK_TEMPLATE)
)
"""Default server status template.
Including:
- CPU usage
- Memory usage
- Runtime
- Swap usage
- Disk usage
"""
Loading

0 comments on commit 5ad088a

Please sign in to comment.