Compare commits

..
12 Commits
6 changed files with 338 additions and 126 deletions
+4
View File
@@ -173,3 +173,7 @@ cython_debug/
# PyPI configuration file # PyPI configuration file
.pypirc .pypirc
.*
state.json
botpy.log*
joined_group.cfg
+3 -3
View File
@@ -70,18 +70,18 @@ class bobbySession(requests.Session):
for i in codes : for i in codes :
res.append(i.group()) res.append(i.group())
return res return res
def getInviteCode(self,step=0)->str: def getInviteCode(self,ctx:str,step=0)->str:
if step == 5: if step == 5:
raise SystemError("验证码查找失败") raise SystemError("验证码查找失败")
try : try :
codes = self.__getInvite() codes = self.__getInvite()
if codes.__len__() == 0: if codes.__len__() == 0:
self.__GenerateInvite() self.__GenerateInvite()
return self.getInviteCode(step+1) return self.getInviteCode(ctx,step+1)
rand =random.randrange(0,codes.__len__()) rand =random.randrange(0,codes.__len__())
return codes[rand] return codes[rand]
except: except:
self.Refresh() self.Refresh()
return self.getInviteCode(step+1) return self.getInviteCode(ctx,step+1)
+239 -123
View File
@@ -1,123 +1,239 @@
from typing import Any, List from typing import Any, List
import group
import botpy
from botpy.message import (Message) from botpy.connection import ConnectionSession
from botpy import logger from botpy.message import (Message,GroupMessage)
import queue from botpy.flags import (Flag,fill_with_flags)
from dotenv import load_dotenv from botpy import( logger,Intents,Client)
import os from botpy.gateway import (BotWebSocket)
import types from botpy.types.gateway import (MessagePayload)
from bobby import bobbySession import queue
from mcwatcher import watcher from botpy.types.session import Session
from threading import Thread from botpy.types.message import MarkdownPayload
import asyncio from dotenv import load_dotenv
#环境配置 import os
import types
class djtuWebsocket (botpy.Client) : from bobby import bobbySession
def __init__( from mcwatcher import watcher
self, intents: botpy.Intents, from threading import Thread
timeout: int = 5, import asyncio
is_sandbox=False, from serverGET import ServerGet
log_config: str | dict | None = None, #环境配置
log_format: str| None = None,
log_level: int |None= None, class Intents_ex(Intents):
bot_log: bool | None = True, def __init__(self, **kwargs: bool) -> None:
ext_handlers: dict | List[dict] | bool = True): arg_tmp = dict[str,bool]()
self.q = queue.Queue() arg_ex = dict[str,bool]()
super().__init__(intents, timeout, is_sandbox, log_config, log_format, log_level, bot_log, ext_handlers) for key, value in kwargs.items():
if key in ['member_event']:
async def on_group_at_message_create(self, message: Message): arg_ex[key] = value
await self.parseCommand(message) else:
arg_tmp[key] = value
async def on_group_message_create(self,message:Message):
super().__init__(**arg_tmp)
await self.parseGlobalMessage(message) for key , value in arg_ex.items() :
setattr(self, key, value)
# 触发概率不大所以可以直接提取关键字 @Flag
async def parseCommand(self,msg :Message): def member_event(self):
commands:dict[str,types.MethodType|types.FunctionType] = { return 1 << 24
r'/邀请码' : bobby.getInviteCode,
r'吃什么' : lambda :"是啊吃什么" class BotWebsocket_ex(BotWebSocket):
} def __init__(self, session: Session, _connection: ConnectionSession):
required = msg.content super().__init__(session, _connection)
reply = "" self._parser['group_member_add'] = lambda aaw:self._connection.dispatch("group_member_add",aaw)
for cmd,func in commands.items(): self._parser['group_message_create'] = lambda aaw:self._connection.dispatch("group_message_create",aaw)
if required.find(cmd) != -1:
try: class djtuWebsocket (Client) :
reply = func() def __init__(
except: self, intents: Intents,
reply = "服务异常" timeout: int = 5,
break is_sandbox=False,
if reply.__len__() == 0: log_config: str | dict | None = None,
reply = "你在发什么东西我怎么看不懂?" log_format: str| None = None,
await msg.reply(content=reply) log_level: int |None= None,
bot_log: bool | None = True,
# 触发概率大,以后要做好解析防止刷屏 ext_handlers: dict | List[dict] | bool = True):
# async def parseGlobalMessage(self,msg:Message): self.q = queue.Queue()
# await msg.reply(content="awda") super().__init__(intents, timeout, is_sandbox, log_config, log_format, log_level, bot_log, ext_handlers)
# 监听队列,接受其他线程的消息
async def mcloop(self):
while True: async def bot_connect(self, session):
if self.q.empty(): """
# time.sleep会阻塞整个线程我去 newConnect 启动一个新的连接,如果连接在监听过程中报错了,或者被远端关闭了链接,需要识别关闭的原因,能否继续 resume
await asyncio.sleep(20) 如果能够 resume,则往 sessionChan 中放入带有 sessionID 的 session
else: 如果不能,则清理掉 sessionID,将 session 放入 sessionChan 中
try : session 的启动,交给 start 中的 for 循环执行,session 不自己递归进行重连,避免递归深度过深
msg = self.q.get()
if group_open_id is None: param session: session对象
logger.error("群聊不存在") """
continue logger.info("[botpy] 会话启动中...")
asyncio.create_task(self.api.post_group_message(group_open_id,content=msg))
except Exception as e: client = BotWebsocket_ex(session, self._connection)
logger.error("MCWatcher发送群聊任务失败:\n"+str(e)) try:
await client.ws_connect()
# source except (Exception, KeyboardInterrupt, SystemExit) as e:
load_dotenv(".env") await client.on_error(e)
bbyAccount = os.getenv("BOBBY_ACCOUNT") async def on_group_at_message_create(self, message: Message):
bbyPasswd = os.getenv("BOBBY_PASSWORD") await self.parseCommand(message)
appid = os.getenv("APP_ID")
secret_bot = os.getenv("SECRET") async def on_group_message_create(self,message):
group_open_id = os.getenv("GROUP_OPEN_ID") # 检验是否有自身@消息
try:
if appid is None or secret_bot is None : msg = message['d']
raise SystemExit("未找到bot配置!") mention = msg['mentions']
logger.info("登录账号:"+appid) for m in mention :
if m['is_you'] == True:
# bobby Session return await self.parseCommand(GroupMessage(self.api,msg['id'],MessagePayload(message['d'])))
if bbyAccount is None or bbyPasswd is None : except:
raise SystemError("未找到账密配置") '没有@消息欸'
if appid is None or secret_bot is None :
raise SystemError("未找到bot配置") return await self.parseGlobalMessage(message)
bobby = bobbySession(bbyAccount,bbyPasswd)
async def main(ws:djtuWebsocket, *args: Any, **kwargs: Any) -> None: async def on_group_member_add(self,payload):
async with ws as ws: # await message.reply(content="awdwa")
logger.info("启动并发异步ing...") openid = 'null'
mcloop = ws.mcloop() memberid = 'null'
# 你*的为什么retcoro true的话会报错啊 eid ='null'
# 协程对象不会不是这个异步回话而是httpx吧? try :
bot = ws.start(*args, **kwargs,ret_coro=False) eid = payload['id']
if bot is None: data = payload['d']
logger.error("bot不给协程啊") openid = data['group_openid']
return memberid = data['member_openid']
try: except:
await asyncio.gather(bot,mcloop) logger.warning("data解析失败")
except Exception as e : return
logger.error(e) logger.info("入群信息:"+' 群: '+openid+" openid: "+memberid)
await self.api.post_group_message(openid,event_id=eid,content='欢迎加入大海啸!\n入服教程请看链接:\nhttps://hiso.wgfire.top/archives/ifnew')
# bot初始化
ws = djtuWebsocket(botpy.Intents(public_messages=True)) # 触发概率不大所以可以直接提取关键字
async def parseCommand(self,msg :GroupMessage):
# 启动mcwatcher线程 # 加入群聊
def pushQuene(cont:str): if msg.group_openid:
ws.q.put(cont) self.group_add(msg.group_openid)
Thread(target=watcher.MCWatcher,name="watcher",kwargs={ commands:dict[str,types.MethodType|types.FunctionType] = {
"hookfunction":pushQuene, r'/邀请码' : bobby.getInviteCode,
"logging":logger r'吃什么' : lambda ctx:"是啊吃什么" ,
}).start() r'/服务器' : ServerGet.GetNames,
}
# bot线程运行 required = msg.content
asyncio.run(main(ws,appid=appid,secret=secret_bot)) reply = ""
for cmd,func in commands.items():
if required.find(cmd) != -1:
try:
ctx = required.split(cmd)[1]
reply = func(ctx)
except:
reply = "服务异常"
break
if reply.__len__() == 0:
reply = "你在发什么东西我怎么看不懂?"
md = MarkdownPayload(content=reply)
await msg.reply(msg_type=2, markdown=md)
def group_add(self,gid :str):
# 加入群聊
new_group = True
if not groups is None :
for i in groups.groups :
if i.find(gid) != -1 :
new_group = False
if new_group :
groups.groups.append(gid)
groups.save()
# 触发概率大,以后要做好解析防止刷屏
async def parseGlobalMessage(self,payload):
try :
msg = payload['d']
gid = msg['group_id']
content = msg['content']
except:
return
# 群聊加入
self.group_add(gid)
# 解析指令
commands:dict[str,types.MethodType|types.FunctionType] = {
r'吃什么' : lambda :"是啊吃什么"
}
required = content
reply = ""
for cmd,func in commands.items():
if required.find(cmd) != -1:
try:
reply = func()
except:
reply = "服务异常"
break
if reply.__len__() == 0:
return
await self.api.post_group_message(gid,content=reply)
# await msg.reply(content="awda")
# 监听队列,接受其他线程的消息
async def mcloop(self):
while True:
if self.q.empty():
# time.sleep会阻塞整个线程我去
await asyncio.sleep(20)
else:
# 广播
try :
msg = self.q.get()
for i in groups.groups:
asyncio.create_task(self.api.post_group_message(i,content=msg))
except Exception as e:
logger.error("MCWatcher发送群聊任务失败:\n"+str(e))
# source
load_dotenv(".env")
bbyAccount = os.getenv("BOBBY_ACCOUNT")
bbyPasswd = os.getenv("BOBBY_PASSWORD")
appid = os.getenv("APP_ID")
secret_bot = os.getenv("SECRET")
groups = group.GroupCtl()
if appid is None or secret_bot is None :
raise SystemExit("未找到bot配置!")
logger.info("登录账号:"+appid)
# bobby Session
if bbyAccount is None or bbyPasswd is None :
raise SystemError("未找到账密配置")
if appid is None or secret_bot is None :
raise SystemError("未找到bot配置")
bobby = bobbySession(bbyAccount,bbyPasswd)
async def main(ws:djtuWebsocket, *args: Any, **kwargs: Any) -> None:
async with ws as ws:
logger.info("启动并发异步ing...")
mcloop = ws.mcloop()
# 你*的为什么retcoro true的话会报错啊
# 协程对象不会不是这个异步回话而是httpx吧?
bot = ws.start(*args, **kwargs,ret_coro=False)
if bot is None:
logger.error("bot不给协程啊")
return
try:
await asyncio.gather(bot,mcloop)
except Exception as e :
logger.error(e)
# bot初始化
ws = djtuWebsocket(Intents_ex(public_messages=True,member_event=True))
# 启动mcwatcher线程
def pushQuene(cont:str):
ws.q.put(cont)
Thread(target=watcher.MCWatcher,name="watcher",kwargs={
"hookfunction":pushQuene,
"logging":logger
}).start()
# bot线程运行
asyncio.run(main(ws,appid=appid,secret=secret_bot))
+4
View File
@@ -0,0 +1,4 @@
SECRET=""
APP_ID=""
BOBBY_PASSWORD=""
BOBBY_ACCOUNT=""
+22
View File
@@ -0,0 +1,22 @@
import os
# 记录加入的群组
class GroupCtl :
path = os.path.join(os.getcwd(),"joined_group.cfg")
groups:list[str] = []
def __init__(self) -> None:
with open(self.openfile()) as awa:
self.groups = awa.readlines()
def save(self):
# 重新加载
fd = self.openfile()
os.truncate(self.path,0)
os.write(fd,bytes('\n'.join(self.groups),'utf-8'))
os.close(fd)
def openfile(self):
return os.open(self.path,os.O_RDWR|os.O_CREAT)
+66
View File
@@ -0,0 +1,66 @@
import requests
from typing import List
class ServerGet :
url = r'https://mcserve-panel.hiso.de5.net/api/overview'
@staticmethod
def __getNames():
try:
res = requests.get(ServerGet.url,timeout=5)
data = res.json()
servers:list = data['servers']
return servers
except Exception as e :
return None
@staticmethod
def __getIndex(ind:int):
if ind <1 :
return None
try:
res = requests.get(ServerGet.url,timeout=5)
data = res.json()
servers:list = data['servers']
if ind>servers.__len__():
return None
server = servers[ind-1]
return server
except Exception as e :
return None
@staticmethod
def GetNames(ctx:str):
faultmsg = "(っ °Д °;)っ出错了呜....."
servers = ServerGet.__getNames()
if servers is None :
return faultmsg
if servers.__len__() == 0:
return "(っ °Д °;)っ好像...没有服务器呢"
# 试探是否有ctx对应的信息
try :
for s in servers:
if ctx.find(s['name']) != -1:
name = s['name']
s_id = s['id']
status = s['status']
online = s['online']
url = s['url']
addr = s['address']
msg = "{0} 信息如下:\n \nid: {1}\n状态: {2}\n在线人数: {3}\n信息页面: {4}\n地址: {5}".format(name,s_id,status,online,url,addr)
return msg
except:
'交给轮询试试'
# 服务器轮训
msg = 'mc服务器如下:\n \n'
try :
for i in servers:
msg += '' + """- <qqbot-cmd-input text="/服务器 {0}" show="{0}" reference="false" />""".format(str(i['name'])) +' ' + "状态:"+str(i['status'])
msg +='\n'
msg += ' \n点击蓝字获取详情~'
return msg
except:
return faultmsg