This commit is contained in:
@ -1,63 +0,0 @@
|
|||||||
import asyncio
|
|
||||||
import mcstatus
|
|
||||||
|
|
||||||
from nonebot import on_command
|
|
||||||
from nonebot.adapters import Event
|
|
||||||
from nonebot_plugin_alconna import UniMessage
|
|
||||||
from mcstatus.responses import JavaStatusResponse
|
|
||||||
|
|
||||||
from konabot.common.permsys import require_permission
|
|
||||||
|
|
||||||
|
|
||||||
cmd = on_command(
|
|
||||||
"宾几人",
|
|
||||||
aliases=set(("宾人数", "mcbingo")),
|
|
||||||
rule=require_permission("minecraft.bingo.check"),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_status(motd: str) -> str:
|
|
||||||
if "[PRE-GAME]" in motd:
|
|
||||||
return "[✨ 空闲]"
|
|
||||||
if "[IN-GAME]" in motd:
|
|
||||||
return "[🕜 游戏中]"
|
|
||||||
if "[POST-GAME]" in motd:
|
|
||||||
return "[🕜 游戏中]"
|
|
||||||
return "[✨ 开放]"
|
|
||||||
|
|
||||||
|
|
||||||
def dump_server_status(name: str, status: JavaStatusResponse | BaseException) -> str:
|
|
||||||
if isinstance(status, JavaStatusResponse):
|
|
||||||
motd = status.motd.to_plain()
|
|
||||||
# Bingo Status: [PRE-GAME], [IN-GAME], [POST-GAME]
|
|
||||||
st = parse_status(motd)
|
|
||||||
players_sample = status.players.sample or []
|
|
||||||
players_sample_suffix = ""
|
|
||||||
if len(players_sample) > 0:
|
|
||||||
player_list = [s.name for s in players_sample]
|
|
||||||
players_sample_suffix = " (" + ", ".join(player_list) + ")"
|
|
||||||
return f"{name}: {st} {status.players.online} 人在线{players_sample_suffix}"
|
|
||||||
else:
|
|
||||||
return f"{name}: 好像没开"
|
|
||||||
|
|
||||||
|
|
||||||
@cmd.handle()
|
|
||||||
async def _(evt: Event):
|
|
||||||
servers = (
|
|
||||||
(mcstatus.JavaServer("play.simpfun.cn", 11495), "小帕 Bingo"),
|
|
||||||
(mcstatus.JavaServer("bingo.mujica.tech"), "坏枪 Bingo"),
|
|
||||||
(mcstatus.JavaServer("mc.mujica.tech", 11456), "齿轮盛宴"),
|
|
||||||
)
|
|
||||||
|
|
||||||
responses = await asyncio.gather(
|
|
||||||
*map(lambda s: s[0].async_status(), servers),
|
|
||||||
return_exceptions=True,
|
|
||||||
)
|
|
||||||
messages = "\n".join(
|
|
||||||
(
|
|
||||||
dump_server_status(n, r)
|
|
||||||
for n, r in zip(map(lambda s: s[1], servers), responses)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
await UniMessage.text(messages).finish(evt, at_sender=False)
|
|
||||||
131
konabot/plugins/minecraft_servers/__init__.py
Normal file
131
konabot/plugins/minecraft_servers/__init__.py
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
import asyncio
|
||||||
|
import datetime
|
||||||
|
from typing import Literal
|
||||||
|
import mcstatus
|
||||||
|
|
||||||
|
from nonebot import on_command
|
||||||
|
from nonebot.adapters import Event
|
||||||
|
from nonebot_plugin_alconna import Alconna, Args, UniMessage, on_alconna
|
||||||
|
from mcstatus.responses import JavaStatusResponse
|
||||||
|
from nonebot_plugin_apscheduler import scheduler
|
||||||
|
|
||||||
|
from konabot.common.permsys import DepPermManager, require_permission
|
||||||
|
from konabot.plugins.minecraft_servers.simpfun_server import SimpfunServer
|
||||||
|
|
||||||
|
|
||||||
|
cmd = on_command(
|
||||||
|
"宾几人",
|
||||||
|
aliases=set(("宾人数", "mcbingo")),
|
||||||
|
rule=require_permission("minecraft.bingo.check"),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_status(motd: str) -> str:
|
||||||
|
if "[PRE-GAME]" in motd:
|
||||||
|
return "[✨ 空闲]"
|
||||||
|
if "[IN-GAME]" in motd:
|
||||||
|
return "[🕜 游戏中]"
|
||||||
|
if "[POST-GAME]" in motd:
|
||||||
|
return "[🕜 游戏中]"
|
||||||
|
return "[✨ 开放]"
|
||||||
|
|
||||||
|
|
||||||
|
def dump_server_status(name: str, status: JavaStatusResponse | BaseException) -> str:
|
||||||
|
if isinstance(status, JavaStatusResponse):
|
||||||
|
motd = status.motd.to_plain()
|
||||||
|
# Bingo Status: [PRE-GAME], [IN-GAME], [POST-GAME]
|
||||||
|
st = parse_status(motd)
|
||||||
|
players_sample = status.players.sample or []
|
||||||
|
players_sample_suffix = ""
|
||||||
|
if len(players_sample) > 0:
|
||||||
|
player_list = [s.name for s in players_sample]
|
||||||
|
players_sample_suffix = " (" + ", ".join(player_list) + ")"
|
||||||
|
return f"{name}: {st} {status.players.online} 人在线{players_sample_suffix}"
|
||||||
|
else:
|
||||||
|
return f"{name}: 好像没开"
|
||||||
|
|
||||||
|
|
||||||
|
@cmd.handle()
|
||||||
|
async def _(evt: Event, pm: DepPermManager):
|
||||||
|
servers = (
|
||||||
|
(mcstatus.JavaServer("play.simpfun.cn", 11495), "小帕 Bingo"),
|
||||||
|
(mcstatus.JavaServer("bingo.mujica.tech"), "坏枪 Bingo"),
|
||||||
|
(mcstatus.JavaServer("mc.mujica.tech", 11456), "齿轮盛宴"),
|
||||||
|
)
|
||||||
|
|
||||||
|
responses = await asyncio.gather(
|
||||||
|
*map(lambda s: s[0].async_status(), servers),
|
||||||
|
return_exceptions=True,
|
||||||
|
)
|
||||||
|
messages = "\n".join(
|
||||||
|
(
|
||||||
|
dump_server_status(n, r)
|
||||||
|
for n, r in zip(map(lambda s: s[1], servers), responses)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if await pm.check_has_permission(evt, "minecraft.bingo.manipulate"):
|
||||||
|
messages += "\n\n---\n\n你可以使用 bingoman start 开启小帕的 bingo 服,用 bingoman stop 关闭小帕的 bingo 服"
|
||||||
|
|
||||||
|
await UniMessage.text(messages).finish(evt, at_sender=False)
|
||||||
|
|
||||||
|
|
||||||
|
cmd_bingo_manipulate = on_alconna(
|
||||||
|
Alconna("bingoman", Args["action", str]),
|
||||||
|
aliases=("宾服务器", "bingo服"),
|
||||||
|
rule=require_permission("minecraft.bingo.manipulate"),
|
||||||
|
)
|
||||||
|
|
||||||
|
actions: dict[str, Literal["start", "stop", "restart", "kill"]] = {
|
||||||
|
"up": "start",
|
||||||
|
"down": "stop",
|
||||||
|
"start": "start",
|
||||||
|
"stop": "stop",
|
||||||
|
"开机": "start",
|
||||||
|
"关机": "stop",
|
||||||
|
"restart": "restart",
|
||||||
|
"kill": "kill",
|
||||||
|
"重启": "restart",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@cmd_bingo_manipulate.handle()
|
||||||
|
async def _(action: str, event: Event):
|
||||||
|
server = SimpfunServer.new() # 使用默认配置管理服务器
|
||||||
|
a = actions.get(action.lower().strip())
|
||||||
|
if a is None:
|
||||||
|
await UniMessage.text(f"操作 {action} 不存在").send(event, at_sender=True)
|
||||||
|
return
|
||||||
|
resp = await server.power(a)
|
||||||
|
if resp.code == 200:
|
||||||
|
await UniMessage.text("好了").send(event, at_sender=True)
|
||||||
|
else:
|
||||||
|
await UniMessage.text(f"不好:{resp}").send(event, at_sender=True)
|
||||||
|
|
||||||
|
|
||||||
|
@scheduler.scheduled_job("cron", hour="4,23")
|
||||||
|
async def _():
|
||||||
|
server = SimpfunServer.new()
|
||||||
|
today = datetime.datetime.now()
|
||||||
|
|
||||||
|
# 获取服务器当前状态,重试多次以保证不会误判服务器未开启
|
||||||
|
server_up = False
|
||||||
|
server_players = 0
|
||||||
|
for _ in range(3):
|
||||||
|
mcs = mcstatus.JavaServer("play.simpfun.cn", 11495)
|
||||||
|
try:
|
||||||
|
resp = await mcs.async_status()
|
||||||
|
server_up = True
|
||||||
|
server_players = resp.players.online
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if today.weekday() == 5 and today.hour < 12:
|
||||||
|
# 每周六开机一天,保证可以让服务器不被自动销毁
|
||||||
|
if not server_up:
|
||||||
|
await server.power("start")
|
||||||
|
else:
|
||||||
|
# 每用一个自然日都会计费,所以要赶在这一天结束之前关服
|
||||||
|
# 平时如果没人,也自动关上
|
||||||
|
if server_up and server_players == 0:
|
||||||
|
await server.power("stop")
|
||||||
90
konabot/plugins/minecraft_servers/simpfun_server.py
Normal file
90
konabot/plugins/minecraft_servers/simpfun_server.py
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
from dataclasses import dataclass
|
||||||
|
import datetime
|
||||||
|
from typing import Literal
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class SimpfunServerConfig(BaseModel):
|
||||||
|
plugin_simpfun_api_key: str = ""
|
||||||
|
plugin_simpfun_base_url: str = "https://api.simpfun.cn"
|
||||||
|
plugin_simpfun_instance_id: int = 0
|
||||||
|
|
||||||
|
|
||||||
|
def get_config():
|
||||||
|
from nonebot import get_plugin_config
|
||||||
|
|
||||||
|
return get_plugin_config(SimpfunServerConfig)
|
||||||
|
|
||||||
|
|
||||||
|
class PowerManageResult(BaseModel):
|
||||||
|
code: int
|
||||||
|
status: bool
|
||||||
|
msg: str
|
||||||
|
|
||||||
|
|
||||||
|
class SimpfunServerDetailUtilization(BaseModel):
|
||||||
|
memory_bytes: int
|
||||||
|
cpu_absolute: float
|
||||||
|
disk_bytes: int
|
||||||
|
network_rx_bytes: int
|
||||||
|
network_tx_bytes: int
|
||||||
|
uptime: float
|
||||||
|
disk_last_check_time: datetime.datetime
|
||||||
|
|
||||||
|
|
||||||
|
class SimpfunServerDetailData(BaseModel):
|
||||||
|
id: int
|
||||||
|
name: str
|
||||||
|
is_pro: bool
|
||||||
|
|
||||||
|
status: str
|
||||||
|
"运行中的话,是 running"
|
||||||
|
|
||||||
|
is_suspended: bool
|
||||||
|
utilization: SimpfunServerDetailUtilization
|
||||||
|
|
||||||
|
|
||||||
|
class SimpfunServerDetailResp(BaseModel):
|
||||||
|
code: int
|
||||||
|
data: SimpfunServerDetailData
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class SimpfunServer:
|
||||||
|
instance_id: int
|
||||||
|
api_key: str
|
||||||
|
base_url: str
|
||||||
|
|
||||||
|
async def power(
|
||||||
|
self, action: Literal["start", "stop", "restart", "kill"]
|
||||||
|
) -> PowerManageResult:
|
||||||
|
url = f"{self.base_url}/api/ins/{self.instance_id}/power"
|
||||||
|
|
||||||
|
async with aiohttp.ClientSession(
|
||||||
|
headers={"Authorization": self.api_key}
|
||||||
|
) as session:
|
||||||
|
async with session.get(url, params={"action": action}) as resp:
|
||||||
|
resp.raise_for_status()
|
||||||
|
return PowerManageResult.model_validate_json(await resp.read())
|
||||||
|
|
||||||
|
async def detail(self) -> SimpfunServerDetailResp:
|
||||||
|
url = f"{self.base_url}/api/ins/{self.instance_id}/power"
|
||||||
|
|
||||||
|
async with aiohttp.ClientSession(
|
||||||
|
headers={"Authorization": self.api_key}
|
||||||
|
) as session:
|
||||||
|
async with session.get(url) as resp:
|
||||||
|
resp.raise_for_status()
|
||||||
|
return SimpfunServerDetailResp.model_validate_json(await resp.read())
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def new(config: SimpfunServerConfig | None = None):
|
||||||
|
if config is None:
|
||||||
|
config = get_config()
|
||||||
|
return SimpfunServer(
|
||||||
|
instance_id=config.plugin_simpfun_instance_id,
|
||||||
|
api_key=config.plugin_simpfun_api_key,
|
||||||
|
base_url=config.plugin_simpfun_base_url,
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user