You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

319 lines
12KB

  1. import logging, copy, pickle
  2. from weakref import ref
  3. from ..returnvalues import ReturnValue
  4. from ..utils import update_info_dict
  5. logger = logging.getLogger('itchat')
  6. class AttributeDict(dict):
  7. def __getattr__(self, value):
  8. keyName = value[0].upper() + value[1:]
  9. try:
  10. return self[keyName]
  11. except KeyError:
  12. raise AttributeError("'%s' object has no attribute '%s'" % (
  13. self.__class__.__name__.split('.')[-1], keyName))
  14. def get(self, v, d=None):
  15. try:
  16. return self[v]
  17. except KeyError:
  18. return d
  19. class UnInitializedItchat(object):
  20. def _raise_error(self, *args, **kwargs):
  21. logger.warning('An itchat instance is called before initialized')
  22. def __getattr__(self, value):
  23. return self._raise_error
  24. class ContactList(list):
  25. ''' when a dict is append, init function will be called to format that dict '''
  26. def __init__(self, *args, **kwargs):
  27. super(ContactList, self).__init__(*args, **kwargs)
  28. self.__setstate__(None)
  29. @property
  30. def core(self):
  31. return getattr(self, '_core', lambda: fakeItchat)() or fakeItchat
  32. @core.setter
  33. def core(self, value):
  34. self._core = ref(value)
  35. def set_default_value(self, initFunction=None, contactClass=None):
  36. if hasattr(initFunction, '__call__'):
  37. self.contactInitFn = initFunction
  38. if hasattr(contactClass, '__call__'):
  39. self.contactClass = contactClass
  40. def append(self, value):
  41. contact = self.contactClass(value)
  42. contact.core = self.core
  43. if self.contactInitFn is not None:
  44. contact = self.contactInitFn(self, contact) or contact
  45. super(ContactList, self).append(contact)
  46. def __deepcopy__(self, memo):
  47. r = self.__class__([copy.deepcopy(v) for v in self])
  48. r.contactInitFn = self.contactInitFn
  49. r.contactClass = self.contactClass
  50. r.core = self.core
  51. return r
  52. def __getstate__(self):
  53. return 1
  54. def __setstate__(self, state):
  55. self.contactInitFn = None
  56. self.contactClass = User
  57. def __str__(self):
  58. return '[%s]' % ', '.join([repr(v) for v in self])
  59. def __repr__(self):
  60. return '<%s: %s>' % (self.__class__.__name__.split('.')[-1],
  61. self.__str__())
  62. class AbstractUserDict(AttributeDict):
  63. def __init__(self, *args, **kwargs):
  64. super(AbstractUserDict, self).__init__(*args, **kwargs)
  65. @property
  66. def core(self):
  67. return getattr(self, '_core', lambda: fakeItchat)() or fakeItchat
  68. @core.setter
  69. def core(self, value):
  70. self._core = ref(value)
  71. def update(self):
  72. return ReturnValue({'BaseResponse': {
  73. 'Ret': -1006,
  74. 'ErrMsg': '%s can not be updated' % \
  75. self.__class__.__name__, }, })
  76. def set_alias(self, alias):
  77. return ReturnValue({'BaseResponse': {
  78. 'Ret': -1006,
  79. 'ErrMsg': '%s can not set alias' % \
  80. self.__class__.__name__, }, })
  81. def set_pinned(self, isPinned=True):
  82. return ReturnValue({'BaseResponse': {
  83. 'Ret': -1006,
  84. 'ErrMsg': '%s can not be pinned' % \
  85. self.__class__.__name__, }, })
  86. def verify(self):
  87. return ReturnValue({'BaseResponse': {
  88. 'Ret': -1006,
  89. 'ErrMsg': '%s do not need verify' % \
  90. self.__class__.__name__, }, })
  91. def get_head_image(self, imageDir=None):
  92. return self.core.get_head_img(self.userName, picDir=imageDir)
  93. def delete_member(self, userName):
  94. return ReturnValue({'BaseResponse': {
  95. 'Ret': -1006,
  96. 'ErrMsg': '%s can not delete member' % \
  97. self.__class__.__name__, }, })
  98. def add_member(self, userName):
  99. return ReturnValue({'BaseResponse': {
  100. 'Ret': -1006,
  101. 'ErrMsg': '%s can not add member' % \
  102. self.__class__.__name__, }, })
  103. def send_raw_msg(self, msgType, content):
  104. return self.core.send_raw_msg(msgType, content, self.userName)
  105. def send_msg(self, msg='Test Message'):
  106. return self.core.send_msg(msg, self.userName)
  107. def send_file(self, fileDir, mediaId=None):
  108. return self.core.send_file(fileDir, self.userName, mediaId)
  109. def send_image(self, fileDir, mediaId=None):
  110. return self.core.send_image(fileDir, self.userName, mediaId)
  111. def send_video(self, fileDir=None, mediaId=None):
  112. return self.core.send_video(fileDir, self.userName, mediaId)
  113. def send(self, msg, mediaId=None):
  114. return self.core.send(msg, self.userName, mediaId)
  115. def search_member(self, name=None, userName=None, remarkName=None, nickName=None,
  116. wechatAccount=None):
  117. return ReturnValue({'BaseResponse': {
  118. 'Ret': -1006,
  119. 'ErrMsg': '%s do not have members' % \
  120. self.__class__.__name__, }, })
  121. def __deepcopy__(self, memo):
  122. r = self.__class__()
  123. for k, v in self.items():
  124. r[copy.deepcopy(k)] = copy.deepcopy(v)
  125. r.core = self.core
  126. return r
  127. def __str__(self):
  128. return '{%s}' % ', '.join(
  129. ['%s: %s' % (repr(k),repr(v)) for k,v in self.items()])
  130. def __repr__(self):
  131. return '<%s: %s>' % (self.__class__.__name__.split('.')[-1],
  132. self.__str__())
  133. def __getstate__(self):
  134. return 1
  135. def __setstate__(self, state):
  136. pass
  137. class User(AbstractUserDict):
  138. def __init__(self, *args, **kwargs):
  139. super(User, self).__init__(*args, **kwargs)
  140. self.__setstate__(None)
  141. def update(self):
  142. r = self.core.update_friend(self.userName)
  143. if r:
  144. update_info_dict(self, r)
  145. return r
  146. def set_alias(self, alias):
  147. return self.core.set_alias(self.userName, alias)
  148. def set_pinned(self, isPinned=True):
  149. return self.core.set_pinned(self.userName, isPinned)
  150. def verify(self):
  151. return self.core.add_friend(**self.verifyDict)
  152. def __deepcopy__(self, memo):
  153. r = super(User, self).__deepcopy__(memo)
  154. r.verifyDict = copy.deepcopy(self.verifyDict)
  155. return r
  156. def __setstate__(self, state):
  157. super(User, self).__setstate__(state)
  158. self.verifyDict = {}
  159. self['MemberList'] = fakeContactList
  160. class MassivePlatform(AbstractUserDict):
  161. def __init__(self, *args, **kwargs):
  162. super(MassivePlatform, self).__init__(*args, **kwargs)
  163. self.__setstate__(None)
  164. def __setstate__(self, state):
  165. super(MassivePlatform, self).__setstate__(state)
  166. self['MemberList'] = fakeContactList
  167. class Chatroom(AbstractUserDict):
  168. def __init__(self, *args, **kwargs):
  169. super(Chatroom, self).__init__(*args, **kwargs)
  170. memberList = ContactList()
  171. userName = self.get('UserName', '')
  172. refSelf = ref(self)
  173. def init_fn(parentList, d):
  174. d.chatroom = refSelf() or \
  175. parentList.core.search_chatrooms(userName=userName)
  176. memberList.set_default_value(init_fn, ChatroomMember)
  177. if 'MemberList' in self:
  178. for member in self.memberList:
  179. memberList.append(member)
  180. self['MemberList'] = memberList
  181. @property
  182. def core(self):
  183. return getattr(self, '_core', lambda: fakeItchat)() or fakeItchat
  184. @core.setter
  185. def core(self, value):
  186. self._core = ref(value)
  187. self.memberList.core = value
  188. for member in self.memberList:
  189. member.core = value
  190. def update(self, detailedMember=False):
  191. r = self.core.update_chatroom(self.userName, detailedMember)
  192. if r:
  193. update_info_dict(self, r)
  194. self['MemberList'] = r['MemberList']
  195. return r
  196. def set_alias(self, alias):
  197. return self.core.set_chatroom_name(self.userName, alias)
  198. def set_pinned(self, isPinned=True):
  199. return self.core.set_pinned(self.userName, isPinned)
  200. def delete_member(self, userName):
  201. return self.core.delete_member_from_chatroom(self.userName, userName)
  202. def add_member(self, userName):
  203. return self.core.add_member_into_chatroom(self.userName, userName)
  204. def search_member(self, name=None, userName=None, remarkName=None, nickName=None,
  205. wechatAccount=None):
  206. with self.core.storageClass.updateLock:
  207. if (name or userName or remarkName or nickName or wechatAccount) is None:
  208. return None
  209. elif userName: # return the only userName match
  210. for m in self.memberList:
  211. if m.userName == userName:
  212. return copy.deepcopy(m)
  213. else:
  214. matchDict = {
  215. 'RemarkName' : remarkName,
  216. 'NickName' : nickName,
  217. 'Alias' : wechatAccount, }
  218. for k in ('RemarkName', 'NickName', 'Alias'):
  219. if matchDict[k] is None:
  220. del matchDict[k]
  221. if name: # select based on name
  222. contact = []
  223. for m in self.memberList:
  224. if any([m.get(k) == name for k in ('RemarkName', 'NickName', 'Alias')]):
  225. contact.append(m)
  226. else:
  227. contact = self.memberList[:]
  228. if matchDict: # select again based on matchDict
  229. friendList = []
  230. for m in contact:
  231. if all([m.get(k) == v for k, v in matchDict.items()]):
  232. friendList.append(m)
  233. return copy.deepcopy(friendList)
  234. else:
  235. return copy.deepcopy(contact)
  236. def __setstate__(self, state):
  237. super(Chatroom, self).__setstate__(state)
  238. if not 'MemberList' in self:
  239. self['MemberList'] = fakeContactList
  240. class ChatroomMember(AbstractUserDict):
  241. def __init__(self, *args, **kwargs):
  242. super(AbstractUserDict, self).__init__(*args, **kwargs)
  243. self.__setstate__(None)
  244. @property
  245. def chatroom(self):
  246. r = getattr(self, '_chatroom', lambda: fakeChatroom)()
  247. if r is None:
  248. userName = getattr(self, '_chatroomUserName', '')
  249. r = self.core.search_chatrooms(userName=userName)
  250. if isinstance(r, dict):
  251. self.chatroom = r
  252. return r or fakeChatroom
  253. @chatroom.setter
  254. def chatroom(self, value):
  255. if isinstance(value, dict) and 'UserName' in value:
  256. self._chatroom = ref(value)
  257. self._chatroomUserName = value['UserName']
  258. def get_head_image(self, imageDir=None):
  259. return self.core.get_head_img(self.userName, self.chatroom.userName, picDir=imageDir)
  260. def delete_member(self, userName):
  261. return self.core.delete_member_from_chatroom(self.chatroom.userName, self.userName)
  262. def send_raw_msg(self, msgType, content):
  263. return ReturnValue({'BaseResponse': {
  264. 'Ret': -1006,
  265. 'ErrMsg': '%s can not send message directly' % \
  266. self.__class__.__name__, }, })
  267. def send_msg(self, msg='Test Message'):
  268. return ReturnValue({'BaseResponse': {
  269. 'Ret': -1006,
  270. 'ErrMsg': '%s can not send message directly' % \
  271. self.__class__.__name__, }, })
  272. def send_file(self, fileDir, mediaId=None):
  273. return ReturnValue({'BaseResponse': {
  274. 'Ret': -1006,
  275. 'ErrMsg': '%s can not send message directly' % \
  276. self.__class__.__name__, }, })
  277. def send_image(self, fileDir, mediaId=None):
  278. return ReturnValue({'BaseResponse': {
  279. 'Ret': -1006,
  280. 'ErrMsg': '%s can not send message directly' % \
  281. self.__class__.__name__, }, })
  282. def send_video(self, fileDir=None, mediaId=None):
  283. return ReturnValue({'BaseResponse': {
  284. 'Ret': -1006,
  285. 'ErrMsg': '%s can not send message directly' % \
  286. self.__class__.__name__, }, })
  287. def send(self, msg, mediaId=None):
  288. return ReturnValue({'BaseResponse': {
  289. 'Ret': -1006,
  290. 'ErrMsg': '%s can not send message directly' % \
  291. self.__class__.__name__, }, })
  292. def __setstate__(self, state):
  293. super(ChatroomMember, self).__setstate__(state)
  294. self['MemberList'] = fakeContactList
  295. def wrap_user_dict(d):
  296. userName = d.get('UserName')
  297. if '@@' in userName:
  298. r = Chatroom(d)
  299. elif d.get('VerifyFlag', 8) & 8 == 0:
  300. r = User(d)
  301. else:
  302. r = MassivePlatform(d)
  303. return r
  304. fakeItchat = UnInitializedItchat()
  305. fakeContactList = ContactList()
  306. fakeChatroom = Chatroom()