由outputManager管理整个输出类及解析消息、分流消息功能,debug部分配置对接、xml导出部分配置对接
This commit is contained in:
parent
9fe1384b5d
commit
49a0715191
@ -9,9 +9,19 @@ webdriver:
|
|||||||
edge:
|
edge:
|
||||||
bin: msedgedriver.exe
|
bin: msedgedriver.exe
|
||||||
|
|
||||||
rooms:
|
output:
|
||||||
- 19829678666
|
use:
|
||||||
- https://live.douyin.com/579197336883
|
- print
|
||||||
|
- xml
|
||||||
|
- debug
|
||||||
|
xml:
|
||||||
|
save_path: "./"
|
||||||
|
file_pattern: "{room_id}_{ts}.xml"
|
||||||
|
debug:
|
||||||
|
save_path:
|
||||||
|
error: "./error"
|
||||||
|
unknown: "./debug"
|
||||||
|
known: False
|
||||||
|
|
||||||
http:
|
http:
|
||||||
host: 127.0.0.1
|
host: 127.0.0.1
|
||||||
|
@ -1,73 +0,0 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
from handler.common import MESSAGE_QUEUE
|
|
||||||
from messages.control import ControlMessage
|
|
||||||
from protobuf import message_pb2
|
|
||||||
from protobuf import wss_pb2
|
|
||||||
import gzip
|
|
||||||
from messages.member import MemberMessage
|
|
||||||
from messages.like import LikeMessage
|
|
||||||
from messages.roomuserseq import RoomUserSeqMessage
|
|
||||||
from messages.gift import GiftMessage
|
|
||||||
from messages.social import SocialMessage
|
|
||||||
from messages.chat import ChatMessage
|
|
||||||
from output import OUTPUTER
|
|
||||||
|
|
||||||
def loop_queue():
|
|
||||||
while True:
|
|
||||||
message = MESSAGE_QUEUE.get()
|
|
||||||
try:
|
|
||||||
response = message_pb2.Response()
|
|
||||||
wss = wss_pb2.WssResponse()
|
|
||||||
wss.ParseFromString(message.body)
|
|
||||||
decompressed = gzip.decompress(wss.data)
|
|
||||||
response.ParseFromString(decompressed)
|
|
||||||
decodeMsg(response.messages)
|
|
||||||
except Exception as e:
|
|
||||||
for output in OUTPUTER:
|
|
||||||
output.error_output("ParseError", message.body, e)
|
|
||||||
|
|
||||||
def decodeMsg(messages):
|
|
||||||
for message in messages:
|
|
||||||
try:
|
|
||||||
if message.method == 'WebcastMemberMessage':
|
|
||||||
member_message = MemberMessage()
|
|
||||||
member_message.set_payload(message.payload)
|
|
||||||
for output in OUTPUTER:
|
|
||||||
output.member_output(member_message)
|
|
||||||
elif message.method == 'WebcastSocialMessage':
|
|
||||||
social_message = SocialMessage()
|
|
||||||
social_message.set_payload(message.payload)
|
|
||||||
for output in OUTPUTER:
|
|
||||||
output.social_output(social_message)
|
|
||||||
elif message.method == 'WebcastChatMessage':
|
|
||||||
chat_message = ChatMessage()
|
|
||||||
chat_message.set_payload(message.payload)
|
|
||||||
for output in OUTPUTER:
|
|
||||||
output.chat_output(chat_message)
|
|
||||||
elif message.method == 'WebcastLikeMessage':
|
|
||||||
like_message = LikeMessage()
|
|
||||||
like_message.set_payload(message.payload)
|
|
||||||
for output in OUTPUTER:
|
|
||||||
output.like_output(like_message)
|
|
||||||
elif message.method == 'WebcastGiftMessage':
|
|
||||||
gift_message = GiftMessage()
|
|
||||||
gift_message.set_payload(message.payload)
|
|
||||||
for output in OUTPUTER:
|
|
||||||
output.gift_output(gift_message)
|
|
||||||
elif message.method == 'WebcastRoomUserSeqMessage':
|
|
||||||
room_user_seq_message = RoomUserSeqMessage()
|
|
||||||
room_user_seq_message.set_payload(message.payload)
|
|
||||||
for output in OUTPUTER:
|
|
||||||
output.userseq_output(room_user_seq_message)
|
|
||||||
elif message.method == 'WebcastControlMessage':
|
|
||||||
control_message = ControlMessage()
|
|
||||||
control_message.set_payload(message.payload)
|
|
||||||
for output in OUTPUTER:
|
|
||||||
output.control_output(control_message)
|
|
||||||
else:
|
|
||||||
for output in OUTPUTER:
|
|
||||||
output.other_output(message.method, message.payload)
|
|
||||||
except Exception as e:
|
|
||||||
for output in OUTPUTER:
|
|
||||||
output.error_output(message.method, message.payload, e)
|
|
10
main.py
10
main.py
@ -3,8 +3,8 @@ import subprocess
|
|||||||
|
|
||||||
from config.helper import config
|
from config.helper import config
|
||||||
from handler.http_server import app
|
from handler.http_server import app
|
||||||
from handler.utils import loop_queue
|
|
||||||
from browser.manager import BrowserManager
|
from browser.manager import BrowserManager
|
||||||
|
from output.manager import OutputManager
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
mitmproxy_process = subprocess.Popen([
|
mitmproxy_process = subprocess.Popen([
|
||||||
@ -13,9 +13,9 @@ if __name__ == '__main__':
|
|||||||
])
|
])
|
||||||
api_thread = threading.Thread(target=app.run, args=(config()["http"]["host"], config()["http"]["port"],))
|
api_thread = threading.Thread(target=app.run, args=(config()["http"]["host"], config()["http"]["port"],))
|
||||||
api_thread.start()
|
api_thread.start()
|
||||||
manager = BrowserManager()
|
browser_manager = BrowserManager()
|
||||||
queue_thread = threading.Thread(target=loop_queue)
|
output_manager = OutputManager()
|
||||||
queue_thread.start()
|
output_manager.start_loop()
|
||||||
queue_thread.join()
|
api_thread.join()
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
from output.print import Print
|
|
||||||
from output.debug import DebugWriter
|
|
||||||
from output.xml import XMLWriter
|
|
||||||
from typing import TYPE_CHECKING
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from output.IOutput import IOutput
|
|
||||||
|
|
||||||
OUTPUTER: "list[IOutput]" = [
|
|
||||||
Print(),
|
|
||||||
XMLWriter(),
|
|
||||||
DebugWriter()
|
|
||||||
]
|
|
@ -1,26 +1,33 @@
|
|||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
|
from config.helper import config
|
||||||
from output.IOutput import IOutput
|
from output.IOutput import IOutput
|
||||||
|
|
||||||
|
|
||||||
class DebugWriter(IOutput):
|
class DebugWriter(IOutput):
|
||||||
|
def __init__(self):
|
||||||
|
# 获取对应配置文件
|
||||||
|
self.unknown_output_dir = config()['output']['debug']['save_path']['unknown']
|
||||||
|
if not os.path.isdir(self.unknown_output_dir):
|
||||||
|
os.makedirs(self.unknown_output_dir)
|
||||||
|
self.error_output_dir = config()['output']['debug']['save_path']['error']
|
||||||
|
if not os.path.isdir(self.error_output_dir):
|
||||||
|
os.makedirs(self.error_output_dir)
|
||||||
|
|
||||||
def other_output(self, message_type: str, message_raw: bytes):
|
def other_output(self, message_type: str, message_raw: bytes):
|
||||||
if not os.path.isdir(os.path.join("", "debug")):
|
if not os.path.isdir(os.path.join(self.unknown_output_dir, message_type)):
|
||||||
os.makedirs(os.path.join("", "debug"))
|
os.makedirs(os.path.join(self.unknown_output_dir, message_type))
|
||||||
if not os.path.isdir(os.path.join("", "debug", message_type)):
|
with open(os.path.join(self.unknown_output_dir, message_type, str(time.time())), "wb") as f:
|
||||||
os.makedirs(os.path.join("", "debug", message_type))
|
|
||||||
with open(os.path.join("", "debug", message_type, str(time.time())), "wb") as f:
|
|
||||||
f.write(message_raw)
|
f.write(message_raw)
|
||||||
|
|
||||||
def error_output(self, message_type: str, message_raw: bytes, exception: Exception):
|
def error_output(self, message_type: str, message_raw: bytes, exception: Exception):
|
||||||
if not os.path.isdir(os.path.join("", "error")):
|
if not os.path.isdir(os.path.join(self.error_output_dir, message_type)):
|
||||||
os.makedirs(os.path.join("", "error"))
|
os.makedirs(os.path.join(self.error_output_dir, message_type))
|
||||||
if not os.path.isdir(os.path.join("", "error", message_type)):
|
|
||||||
os.makedirs(os.path.join("", "error", message_type))
|
|
||||||
ts = time.time()
|
ts = time.time()
|
||||||
with open(os.path.join("", "error", message_type, str(ts)), "wb") as f:
|
with open(os.path.join(self.error_output_dir, message_type, str(ts)), "wb") as f:
|
||||||
f.write(message_raw)
|
f.write(message_raw)
|
||||||
traceback.print_exc(file=open(os.path.join("", "error", message_type, str(ts)) + ".exc", "w", encoding="UTF-8"))
|
traceback.print_exc(file=open(os.path.join(self.error_output_dir, message_type, str(ts)) + ".exc", "w", encoding="UTF-8"))
|
||||||
|
|
||||||
|
|
||||||
|
109
output/manager.py
Normal file
109
output/manager.py
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
import gzip
|
||||||
|
import threading
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from config.helper import config
|
||||||
|
from handler.common import MessagePayload, MESSAGE_QUEUE
|
||||||
|
from messages.chat import ChatMessage
|
||||||
|
from messages.control import ControlMessage
|
||||||
|
from messages.gift import GiftMessage
|
||||||
|
from messages.like import LikeMessage
|
||||||
|
from messages.member import MemberMessage
|
||||||
|
from messages.roomuserseq import RoomUserSeqMessage
|
||||||
|
from messages.social import SocialMessage
|
||||||
|
from output.print import Print
|
||||||
|
from output.xml import XMLWriter
|
||||||
|
from output.debug import DebugWriter
|
||||||
|
from protobuf import message_pb2, wss_pb2
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from typing import Type, Optional
|
||||||
|
from output.IOutput import IOutput
|
||||||
|
|
||||||
|
|
||||||
|
class OutputManager():
|
||||||
|
_mapping: "dict[str, Type[IOutput]]" = {
|
||||||
|
"print": Print,
|
||||||
|
"xml": XMLWriter,
|
||||||
|
"debug": DebugWriter,
|
||||||
|
}
|
||||||
|
_writer: "list[IOutput]" = []
|
||||||
|
_thread: "Optional[threading.Thread]"= None
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
_config = config()['output']['use']
|
||||||
|
if type(_config) != list:
|
||||||
|
_config = [_config]
|
||||||
|
for _c in _config:
|
||||||
|
if _c not in self._mapping:
|
||||||
|
raise Exception("不支持的输出方式")
|
||||||
|
self._writer.append(self._mapping[_c]())
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
def decode_payload(self, message: MessagePayload):
|
||||||
|
try:
|
||||||
|
response = message_pb2.Response()
|
||||||
|
wss = wss_pb2.WssResponse()
|
||||||
|
wss.ParseFromString(message.body)
|
||||||
|
decompressed = gzip.decompress(wss.data)
|
||||||
|
response.ParseFromString(decompressed)
|
||||||
|
self.decode_message(response.messages)
|
||||||
|
except Exception as e:
|
||||||
|
for writer in self._writer:
|
||||||
|
writer.error_output("ParseError", message.body, e)
|
||||||
|
|
||||||
|
def decode_message(self, message_list: list[message_pb2.Message]):
|
||||||
|
for message in message_list:
|
||||||
|
try:
|
||||||
|
if message.method == 'WebcastMemberMessage':
|
||||||
|
member_message = MemberMessage()
|
||||||
|
member_message.set_payload(message.payload)
|
||||||
|
for writer in self._writer:
|
||||||
|
writer.member_output(member_message)
|
||||||
|
elif message.method == 'WebcastSocialMessage':
|
||||||
|
social_message = SocialMessage()
|
||||||
|
social_message.set_payload(message.payload)
|
||||||
|
for writer in self._writer:
|
||||||
|
writer.social_output(social_message)
|
||||||
|
elif message.method == 'WebcastChatMessage':
|
||||||
|
chat_message = ChatMessage()
|
||||||
|
chat_message.set_payload(message.payload)
|
||||||
|
for writer in self._writer:
|
||||||
|
writer.chat_output(chat_message)
|
||||||
|
elif message.method == 'WebcastLikeMessage':
|
||||||
|
like_message = LikeMessage()
|
||||||
|
like_message.set_payload(message.payload)
|
||||||
|
for writer in self._writer:
|
||||||
|
writer.like_output(like_message)
|
||||||
|
elif message.method == 'WebcastGiftMessage':
|
||||||
|
gift_message = GiftMessage()
|
||||||
|
gift_message.set_payload(message.payload)
|
||||||
|
for writer in self._writer:
|
||||||
|
writer.gift_output(gift_message)
|
||||||
|
elif message.method == 'WebcastRoomUserSeqMessage':
|
||||||
|
room_user_seq_message = RoomUserSeqMessage()
|
||||||
|
room_user_seq_message.set_payload(message.payload)
|
||||||
|
for writer in self._writer:
|
||||||
|
writer.userseq_output(room_user_seq_message)
|
||||||
|
elif message.method == 'WebcastControlMessage':
|
||||||
|
control_message = ControlMessage()
|
||||||
|
control_message.set_payload(message.payload)
|
||||||
|
for writer in self._writer:
|
||||||
|
writer.control_output(control_message)
|
||||||
|
else:
|
||||||
|
for writer in self._writer:
|
||||||
|
writer.other_output(message.method, message.payload)
|
||||||
|
except Exception as e:
|
||||||
|
for writer in self._writer:
|
||||||
|
writer.error_output(message.method, message.payload, e)
|
||||||
|
|
||||||
|
def start_loop(self):
|
||||||
|
self._thread = threading.Thread(target=self._handle)
|
||||||
|
self._thread.start()
|
||||||
|
|
||||||
|
def _handle(self):
|
||||||
|
while True:
|
||||||
|
message = MESSAGE_QUEUE.get()
|
||||||
|
self.decode_payload(message)
|
@ -1,3 +1,4 @@
|
|||||||
|
from config.helper import config
|
||||||
from output.IOutput import IOutput
|
from output.IOutput import IOutput
|
||||||
from typing import IO
|
from typing import IO
|
||||||
import time
|
import time
|
||||||
@ -10,13 +11,18 @@ class XMLWriter(IOutput):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.file_mappings: "dict[str, IO[str]]" = {}
|
self.file_mappings: "dict[str, IO[str]]" = {}
|
||||||
self.time_mappings: "dict[str, float]" = {}
|
self.time_mappings: "dict[str, float]" = {}
|
||||||
|
self._file_name_pattern: "str" = config()['output']['xml']['file_pattern']
|
||||||
|
|
||||||
def _get_fd_by_room_id(self, room_id: str) -> IO[str]:
|
def _get_fd_by_room_id(self, room_id: str) -> IO[str]:
|
||||||
if room_id in self.file_mappings:
|
if room_id in self.file_mappings:
|
||||||
return self.file_mappings[room_id]
|
return self.file_mappings[room_id]
|
||||||
fd = open(f"{room_id}_{time.time()}.xml", "w", encoding="UTF-8")
|
cur_ts = time.time()
|
||||||
|
fd = open(self._file_name_pattern.format_map({
|
||||||
|
"room_id": room_id,
|
||||||
|
"ts": cur_ts
|
||||||
|
}), "w", encoding="UTF-8")
|
||||||
self.file_mappings[room_id] = fd
|
self.file_mappings[room_id] = fd
|
||||||
self.time_mappings[room_id] = time.time()
|
self.time_mappings[room_id] = cur_ts
|
||||||
return fd
|
return fd
|
||||||
|
|
||||||
def _close_fd_by_room_id(self, room_id: str):
|
def _close_fd_by_room_id(self, room_id: str):
|
||||||
|
Reference in New Issue
Block a user