forked from Yinzo/SmartQQBot
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMsgHandler.py
More file actions
158 lines (125 loc) · 6.62 KB
/
MsgHandler.py
File metadata and controls
158 lines (125 loc) · 6.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# -*- coding: utf-8 -*-
# Code by Yinzo: https://github.com/Yinzo
# Origin repository: https://github.com/Yinzo/SmartQQBot
from Group import *
from Pm import *
from Sess import *
import threading
logging.basicConfig(
filename='smartqq.log',
level=logging.DEBUG,
format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
datefmt='%a, %d %b %Y %H:%M:%S',
)
class MsgHandler:
def __init__(self, operator):
if not isinstance(operator, QQ):
raise TypeError("Operator must be a logined QQ instance")
self.__operator = operator
self.process_threads = {}
self.__group_list = {}
self.__pm_list = {}
self.__sess_list = {}
def handle(self, msg_list):
assert isinstance(msg_list, list), "msg_list is NOT a LIST"
for msg in msg_list:
# 仅处理程序管理层面上的操作 Only do the operation of the program management
if not isinstance(msg, (Msg, Notify)):
logging.error("Handler received a not a Msg or Notify instance.")
raise TypeError("Handler received a not a Msg or Notify instance.")
elif isinstance(msg, MsgWithContent):
logging.info(str(self.__get_account(msg)) + ":" + msg.content)
if isinstance(msg, GroupMsg): # 群聊信息的处理
# 判断群对象是否存在,group_code实际上为群号
if msg.group_code not in self.__group_list:
self.__group_list[msg.group_code] = Group(self.__operator, msg)
# 维护一个线程队列,然后每一个线程处理各自的信息
self.process_threads[msg.group_code] = MsgHandleQueue(self.__group_list[msg.group_code])
self.process_threads[msg.group_code].start()
logging.debug("Now group list: " + str(self.__group_list))
tgt_group = self.__group_list[msg.group_code]
if len(tgt_group.msg_list) >= 1 and msg.msg_id == tgt_group.msg_list[-1].msg_id:
# 若如上一条seq重复则抛弃此条信息不处理
logging.info("消息重复,抛弃")
return
tgt_group.msg_id = msg.msg_id
self.process_threads[msg.group_code].append(msg)
elif isinstance(msg, PmMsg): # 私聊信息处理
tid = self.__get_account(msg)
if tid not in self.__pm_list:
self.__pm_list[tid] = Pm(self.__operator, msg)
# 维护一个线程队列,然后每一个线程处理各自的信息
self.process_threads[tid] = MsgHandleQueue(self.__pm_list[tid])
self.process_threads[tid].start()
logging.debug("Now pm thread list: " + str(self.__pm_list))
tgt_pm = self.__pm_list[tid]
if len(tgt_pm.msg_list) >= 1 and msg.time == tgt_pm.msg_list[-1].time \
and msg.from_uin == tgt_pm.msg_list[-1].from_uin \
and msg.content == tgt_pm.msg_list[-1].content:
# 私聊没有seq可用于判断重复,只能抛弃同一个人在同一时间戳发出的内容相同的消息。
logging.info("消息重复,抛弃")
return
tgt_pm.msg_id = msg.msg_id
self.process_threads[tid].append(msg)
elif isinstance(msg, SessMsg): # 临时会话的处理
tid = self.__get_account(msg)
if tid not in self.__sess_list:
self.__sess_list[tid] = Sess(self.__operator, msg)
self.process_threads[tid] = MsgHandleQueue(self.__sess_list[tid])
self.process_threads[tid].start()
logging.debug("Now sess thread list: " + str(self.__sess_list))
tgt_sess = self.__sess_list[tid]
if len(tgt_sess.msg_list) >= 1 and msg.time == tgt_sess.msg_list[-1].time \
and msg.from_uin == tgt_sess.msg_list[-1].from_uin \
and msg.content == tgt_sess.msg_list[-1].content:
# 私聊没有seq可用于判断重复,只能抛弃同一个人在同一时间戳发出的同一内容的消息。
logging.info("消息重复,抛弃")
return
tgt_sess.msg_id = msg.msg_id
self.process_threads[tid].append(msg)
elif isinstance(msg, InputNotify):
self.__input_notify_handler(msg)
elif isinstance(msg, BuddiesStatusChange):
self.__buddies_status_change_handler(msg)
elif isinstance(msg, KickMessage):
self.__kick_message(msg)
else:
logging.warning("Unsolved Msg type :" + str(msg.poll_type))
raise TypeError("Unsolved Msg type :" + str(msg.poll_type))
def __get_account(self, msg):
assert isinstance(msg, (Msg, Notify)), "function get_account received a not Msg or Notify parameter."
if isinstance(msg, (PmMsg, SessMsg, InputNotify)):
# 如果消息的发送者的真实QQ号码不在FriendList中,则自动去取得真实的QQ号码并保存到缓存中
tuin = msg.from_uin
account = self.__operator.get_friend_info(tuin)
return account
elif isinstance(msg, GroupMsg):
return str(msg.msg_id).join("[]") + str(self.__operator.get_friend_info(msg.send_uin))
def __input_notify_handler(self, msg):
logging.info(str(self.__get_account(msg)) + " is typing...")
def __buddies_status_change_handler(self, msg):
pass
def __kick_message(self, msg):
logging.warning(str(msg.to_uin) + " is kicked. Reason: " + str(msg.reason))
logging.warning("[{0}]{1} is kicked. Reason: {2}".format(
str(msg.to_uin),
self.__operator.username,
str(msg.reason),
))
raise KeyboardInterrupt("Kicked")
# 为了加速程序处理消息,采用了多线程技术
class MsgHandleQueue(threading.Thread):
def __init__(self, handler):
super(MsgHandleQueue, self).__init__()
self.handler = handler
self.msg_queue = []
self.setDaemon(True)
def run(self):
while 1:
if len(self.msg_queue):
self.handler.handle(self.msg_queue.pop(0))
logging.debug("queue handling.Now queue length:" + str(len(self.msg_queue)))
else:
time.sleep(1)
def append(self, msg):
self.msg_queue.append(msg)