作者 lemon

更新部分接口

@@ -11,7 +11,6 @@ from fbchat import ThreadType, Message, \ @@ -11,7 +11,6 @@ from fbchat import ThreadType, Message, \
11 ShareAttachment, FileAttachment, AudioAttachment, VideoAttachment, ImageAttachment, Sticker, LocationAttachment 11 ShareAttachment, FileAttachment, AudioAttachment, VideoAttachment, ImageAttachment, Sticker, LocationAttachment
12 12
13 from lib import common 13 from lib import common
14 -from lib.common import TaskStatus  
15 from lib.facebook import FacebookClient 14 from lib.facebook import FacebookClient
16 from lib.sqlhelper import UserList, Status 15 from lib.sqlhelper import UserList, Status
17 from munch import Munch 16 from munch import Munch
@@ -20,14 +19,6 @@ log = logging.getLogger(__name__) @@ -20,14 +19,6 @@ log = logging.getLogger(__name__)
20 19
21 20
22 class CallBack(): 21 class CallBack():
23 - def __init__(self):  
24 - self._socket = None  
25 -  
26 - @classmethod  
27 - def bind(cls, socket):  
28 - self = cls()  
29 - self._socket = socket  
30 - return self  
31 22
32 def _notify_(self, type_, client, body: dict): 23 def _notify_(self, type_, client, body: dict):
33 print('【%s】' % type_, body) 24 print('【%s】' % type_, body)
@@ -53,7 +44,7 @@ class CallBack(): @@ -53,7 +44,7 @@ class CallBack():
53 client=client, 44 client=client,
54 body={'event': 'onUpdateMyInfo', 'info': client.info()} 45 body={'event': 'onUpdateMyInfo', 'info': client.info()}
55 ) 46 )
56 - t = Thread(target=client.listen, name=client.email,args=(True,)) 47 + t = Thread(target=client.listen, name=client.email, args=(True,))
57 t.setDaemon(True) 48 t.setDaemon(True)
58 t.start() 49 t.start()
59 50
@@ -177,8 +168,8 @@ class CallBack(): @@ -177,8 +168,8 @@ class CallBack():
177 'adminText': msg['messageMetadata']['adminText'], 168 'adminText': msg['messageMetadata']['adminText'],
178 'type': msg['type'], 169 'type': msg['type'],
179 'class': msg['class'], 170 'class': msg['class'],
180 - 'thread_id':thread_id,  
181 - 'thread_type':thread_type.name, 171 + 'thread_id': thread_id,
  172 + 'thread_type': thread_type.name,
182 } 173 }
183 body.update(msg['untypedData']) 174 body.update(msg['untypedData'])
184 self._notify_(type_="colorChange", client=client, body=body) 175 self._notify_(type_="colorChange", client=client, body=body)
@@ -196,13 +187,13 @@ class CallBack(): @@ -196,13 +187,13 @@ class CallBack():
196 msg=None, 187 msg=None,
197 ): 188 ):
198 body = { 189 body = {
199 - 'new_emoji':new_emoji, 190 + 'new_emoji': new_emoji,
200 'actorFbId': msg['messageMetadata']['actorFbId'], 191 'actorFbId': msg['messageMetadata']['actorFbId'],
201 'adminText': msg['messageMetadata']['adminText'], 192 'adminText': msg['messageMetadata']['adminText'],
202 'type': msg['type'], 193 'type': msg['type'],
203 'class': msg['class'], 194 'class': msg['class'],
204 - 'thread_id':thread_id,  
205 - 'thread_type':thread_type.name, 195 + 'thread_id': thread_id,
  196 + 'thread_type': thread_type.name,
206 } 197 }
207 body.update(msg['untypedData']) 198 body.update(msg['untypedData'])
208 self._notify_(type_="emojiChange", client=client, body=body) 199 self._notify_(type_="emojiChange", client=client, body=body)
@@ -220,13 +211,13 @@ class CallBack(): @@ -220,13 +211,13 @@ class CallBack():
220 msg=None, 211 msg=None,
221 ): 212 ):
222 body = { 213 body = {
223 - 'new_title':new_title, 214 + 'new_title': new_title,
224 'actorFbId': msg['messageMetadata']['actorFbId'], 215 'actorFbId': msg['messageMetadata']['actorFbId'],
225 'adminText': msg['messageMetadata']['adminText'], 216 'adminText': msg['messageMetadata']['adminText'],
226 'type': msg['type'], 217 'type': msg['type'],
227 'class': msg['class'], 218 'class': msg['class'],
228 - 'thread_id':thread_id,  
229 - 'thread_type':thread_type.name, 219 + 'thread_id': thread_id,
  220 + 'thread_type': thread_type.name,
230 } 221 }
231 body.update(msg['untypedData']) 222 body.update(msg['untypedData'])
232 self._notify_(type_="nicknameChange", client=client, body=body) 223 self._notify_(type_="nicknameChange", client=client, body=body)
@@ -258,13 +249,13 @@ class CallBack(): @@ -258,13 +249,13 @@ class CallBack():
258 msg=None, 249 msg=None,
259 ): 250 ):
260 body = { 251 body = {
261 - 'new_nickname':new_nickname, 252 + 'new_nickname': new_nickname,
262 'actorFbId': msg['messageMetadata']['actorFbId'], 253 'actorFbId': msg['messageMetadata']['actorFbId'],
263 'adminText': msg['messageMetadata']['adminText'], 254 'adminText': msg['messageMetadata']['adminText'],
264 'type': msg['type'], 255 'type': msg['type'],
265 'class': msg['class'], 256 'class': msg['class'],
266 - 'thread_id':thread_id,  
267 - 'thread_type':thread_type.name, 257 + 'thread_id': thread_id,
  258 + 'thread_type': thread_type.name,
268 } 259 }
269 body.update(msg['untypedData']) 260 body.update(msg['untypedData'])
270 self._notify_(type_="nicknameChange", client=client, body=body) 261 self._notify_(type_="nicknameChange", client=client, body=body)
@@ -523,7 +514,6 @@ class CallBack(): @@ -523,7 +514,6 @@ class CallBack():
523 """ 514 """
524 print("onTyping") 515 print("onTyping")
525 516
526 -  
527 def onGamePlayed( 517 def onGamePlayed(
528 self, 518 self,
529 client: FacebookClient, 519 client: FacebookClient,
@@ -589,7 +579,7 @@ class CallBack(): @@ -589,7 +579,7 @@ class CallBack():
589 'author_id': author_id, 579 'author_id': author_id,
590 'mid': mid, 580 'mid': mid,
591 'action': 'add', 581 'action': 'add',
592 - 'reaction':reaction.value 582 + 'reaction': reaction.value
593 } 583 }
594 self._notify_('reactionMsg', client, body=body) 584 self._notify_('reactionMsg', client, body=body)
595 585
@@ -622,7 +612,6 @@ class CallBack(): @@ -622,7 +612,6 @@ class CallBack():
622 } 612 }
623 self._notify_('reactionMsg', client, body=body) 613 self._notify_('reactionMsg', client, body=body)
624 614
625 -  
626 def onBlock( 615 def onBlock(
627 self, client: FacebookClient, author_id=None, thread_id=None, thread_type=None, ts=None, msg=None 616 self, client: FacebookClient, author_id=None, thread_id=None, thread_type=None, ts=None, msg=None
628 ): 617 ):
  1 +#!/usr/bin/env python
  2 +# -*- coding: utf-8 -*-
  3 +# @Time : 2020-02-13 09:25
  4 +# @Author : Lemon
  5 +# @File : command.py
  6 +# @Software: PyCharm
  7 +import os
  8 +
  9 +from fbchat import ThreadType, EmojiSize
  10 +
  11 +from lib import common
  12 +from lib.facebook import FacebookClient
  13 +import uuid
  14 +from base64 import b64decode
  15 +
  16 +
  17 +def _send_msg(local_func, remote_func, to, content, thread_type, suffix):
  18 + _type = getattr(ThreadType, thread_type.upper())
  19 + if content.startswith('http'):
  20 + res = remote_func(content, thread_id=to, thread_type=_type)
  21 + else:
  22 + _temp = b64decode(content.encode('utf-8'))
  23 + _temp_path = 'filecache'
  24 + if not os.path.exists(_temp_path): os.mkdir(_temp_path)
  25 + filename = os.path.join(_temp_path, '%s.%s' % (uuid.uuid1().hex, suffix))
  26 + with open(filename, 'wb') as f:
  27 + f.write(_temp)
  28 + try:
  29 + res = local_func(filename, thread_id=to, thread_type=_type)
  30 + except BaseException as err:
  31 + os.remove(filename)
  32 + raise err
  33 + return res
  34 +
  35 +
  36 +class Executor():
  37 +
  38 + def __init__(self, client):
  39 + self.client = client
  40 +
  41 + def textMsg(self, to, content, thread_type="USER"):
  42 + _type = getattr(ThreadType, thread_type.upper())
  43 + res = self.client.sendMessage(message=content, thread_id=to, thread_type=_type)
  44 + return res
  45 +
  46 + def imageMsg(self, to, image, thread_type="USER", suffix='jpg'):
  47 + return _send_msg(self.client.sendLocalImage,
  48 + self.client.sendRemoteImage,
  49 + to,
  50 + image,
  51 + thread_type,
  52 + suffix)
  53 +
  54 + def voiceMsg(self, to, voice, thread_type='USER', suffix='mp3'):
  55 + return _send_msg(self.client.sendLocalVoiceClips,
  56 + self.client.sendRemoteVoiceClips,
  57 + to,
  58 + voice,
  59 + thread_type,
  60 + suffix)
  61 +
  62 + def fileMsg(self, to, link, thread_type="USER"):
  63 + _type = getattr(ThreadType, thread_type.upper())
  64 + return self.client.sendRemoteFiles(link, thread_id=to, thread_type=_type)
  65 +
  66 + def stickerMsg(self, to, sticker_id, thread_type="USER"):
  67 + _type = getattr(ThreadType, thread_type.upper())
  68 + return self.client.sendSticker(sticker_id, thread_id=to, thread_type=_type)
  69 +
  70 + def emojiMsg(self, to, emoji, size='small', thread_type="USER"):
  71 + _type = getattr(ThreadType, thread_type.upper())
  72 + _size = getattr(EmojiSize, size.upper())
  73 + return self.client.sendEmoji(emoji=emoji, size=_size, thread_id=to, thread_type=_type)
  74 +
  75 + def linkMsg(self, to, link, thread_type='USER'):
  76 + _type = getattr(ThreadType, thread_type.upper())
  77 + return self.client.sendPictureLink(link, thread_id=to, thread_type=_type)
  78 +
  79 + def searchForUsers(self, name, limit=5):
  80 + users = self.client.searchForUsers(name, limit)
  81 + keys = ['type', 'gender', 'is_friend', 'name', 'photo', 'uid', 'url']
  82 + result=[]
  83 + for u in users:
  84 + info = common.todict(u, keys)
  85 + info['type'] = info.get('type').name
  86 + result.append(info)
  87 + return result
@@ -5,11 +5,13 @@ @@ -5,11 +5,13 @@
5 # @File : core.py 5 # @File : core.py
6 # @Software: PyCharm 6 # @Software: PyCharm
7 import json 7 import json
  8 +import threading
8 9
9 from tornado import ioloop 10 from tornado import ioloop
10 11
11 from conf import settings 12 from conf import settings
12 from core.monitor import Monitor 13 from core.monitor import Monitor
  14 +from lib.common import Exchange
13 from lib.socket_ import MessageSocketClient 15 from lib.socket_ import MessageSocketClient
14 16
15 socket = MessageSocketClient() 17 socket = MessageSocketClient()
@@ -20,36 +22,23 @@ def message_receive(message): @@ -20,36 +22,23 @@ def message_receive(message):
20 print("收到消息", message) 22 print("收到消息", message)
21 if message == 'login1': 23 if message == 'login1':
22 monitor.login("[email protected]", "nantian888") 24 monitor.login("[email protected]", "nantian888")
23 - elif message == 'login2':  
24 - monitor.login('[email protected]', 'nantian888')  
25 elif message == 'exit1': 25 elif message == 'exit1':
26 monitor.logout('100047151842270') 26 monitor.logout('100047151842270')
27 - elif message == 'exit2':  
28 - monitor.logout('100046875247681')  
29 - elif message == 'size':  
30 - len = monitor.size()  
31 - socket.send({"size": len})  
32 elif message == 'uid': 27 elif message == 'uid':
33 socket.send({"keys": monitor.members()}) 28 socket.send({"keys": monitor.members()})
34 - elif message == 'info1':  
35 - monitor.cmd('100047151842270', 'info')  
36 - elif message == 'info2':  
37 - monitor.cmd('100046875247681', 'info')  
38 else: 29 else:
39 try: 30 try:
40 req = json.loads(message) 31 req = json.loads(message)
41 type_ = req.get('type') 32 type_ = req.get('type')
42 data_ = req.get('data') 33 data_ = req.get('data')
43 if type_ == 'task': 34 if type_ == 'task':
44 - commands = json.loads(data_) # list[Dict] 35 + commands = json.loads(data_)
45 for cmd in commands: 36 for cmd in commands:
46 monitor.execute(cmd) 37 monitor.execute(cmd)
47 elif type_ == 'initialize': 38 elif type_ == 'initialize':
48 commands = json.loads(data_) 39 commands = json.loads(data_)
49 - disable_sync = commands.get('disableSync')  
50 - print(disable_sync)  
51 -  
52 - except BaseException as e: 40 + monitor.init_config = commands
  41 + except:
53 import traceback 42 import traceback
54 print(traceback.format_exc()) 43 print(traceback.format_exc())
55 44
@@ -6,7 +6,6 @@ @@ -6,7 +6,6 @@
6 # @Software: PyCharm 6 # @Software: PyCharm
7 import time 7 import time
8 import uuid 8 import uuid
9 -from threading import Thread, currentThread, Timer  
10 import functools 9 import functools
11 import logging 10 import logging
12 from concurrent.futures import ThreadPoolExecutor 11 from concurrent.futures import ThreadPoolExecutor
@@ -29,10 +28,18 @@ class Monitor(callback.CallBack): @@ -29,10 +28,18 @@ class Monitor(callback.CallBack):
29 28
30 def __init__(self): 29 def __init__(self):
31 super().__init__() 30 super().__init__()
  31 + self._socket = None
32 self._listenlist = dict() 32 self._listenlist = dict()
33 self._imei = Config.get('imei', lambda: uuid.uuid1().hex) 33 self._imei = Config.get('imei', lambda: uuid.uuid1().hex)
34 self._name = Config.get('name', lambda: 'DEV') 34 self._name = Config.get('name', lambda: 'DEV')
35 self.executor = ThreadPoolExecutor(50, 'task_thread') 35 self.executor = ThreadPoolExecutor(50, 'task_thread')
  36 + self.init_config = {}
  37 +
  38 + @classmethod
  39 + def bind(cls, socket):
  40 + self = cls()
  41 + self._socket = socket
  42 + return self
36 43
37 def _auto_login(self): 44 def _auto_login(self):
38 user_list = UserList.query(status=Status.ONLINE) 45 user_list = UserList.query(status=Status.ONLINE)
@@ -97,15 +104,9 @@ class Monitor(callback.CallBack): @@ -97,15 +104,9 @@ class Monitor(callback.CallBack):
97 def members(self): 104 def members(self):
98 return list(self._listenlist.keys()) 105 return list(self._listenlist.keys())
99 106
100 - def cmd(self, email, action):  
101 - client = self._get_member(email)  
102 - if not client:  
103 - return False  
104 -  
105 - if action == 'info':  
106 - self._socket.send(client.info())  
107 -  
108 def _heartbeat(self): 107 def _heartbeat(self):
  108 + if self.init_config.get("disableSync"):
  109 + return None
109 payload = { 110 payload = {
110 "data": tostr({ 111 "data": tostr({
111 'online': self.members(), 112 'online': self.members(),
@@ -7,6 +7,7 @@ @@ -7,6 +7,7 @@
7 7
8 import datetime 8 import datetime
9 9
  10 +from enum import Enum
10 from attr import attrs, attrib 11 from attr import attrs, attrib
11 12
12 13
@@ -84,11 +85,41 @@ class TaskStatus(): @@ -84,11 +85,41 @@ class TaskStatus():
84 EXECUTE = 0 85 EXECUTE = 0
85 SUCCESS = 1 86 SUCCESS = 1
86 87
87 -def todict(obj):  
88 - keys=dir(obj)  
89 - res={} 88 +
  89 +class Exchange(Enum):
  90 + CLIENT = 0
  91 +
  92 + # SERVER = 1
  93 + # NSQ = 2
  94 + # MQTT = 3
  95 +
  96 + @classmethod
  97 + def get(cls, code) -> Enum:
  98 + if isinstance(code, str):
  99 + code = int(code)
  100 +
  101 + keys = [x for x in dir(cls) if not x.startswith('__')]
  102 + for key in keys:
  103 + member = getattr(cls, key)
  104 + if member.value == code:
  105 + return member
  106 + return None
  107 +
  108 +
  109 +def todict(obj,include:list=None):
  110 + keys = dir(obj)
  111 + res = {}
  112 + if include:
  113 + for key in include:
  114 + try:
  115 + value = getattr(obj, key)
  116 + res[key] = value
  117 + except:
  118 + pass
  119 + return res
  120 + else:
90 for key in keys: 121 for key in keys:
91 if not key.startswith('_'): 122 if not key.startswith('_'):
92 - value=getattr(obj,key)  
93 - res[key]=value 123 + value = getattr(obj, key)
  124 + res[key] = value
94 return res 125 return res
@@ -18,7 +18,7 @@ from fbchat._state import State, session_factory, is_home @@ -18,7 +18,7 @@ from fbchat._state import State, session_factory, is_home
18 18
19 from lib import google_map 19 from lib import google_map
20 from lib.common import WorkPlace, College 20 from lib.common import WorkPlace, College
21 -from utils import parse_html, share_attachment 21 +from utils import parse_html, _attachment
22 22
23 23
24 class PCState(State): 24 class PCState(State):
@@ -344,7 +344,7 @@ class FacebookClient(Client): @@ -344,7 +344,7 @@ class FacebookClient(Client):
344 if thread_type == ThreadType.USER: 344 if thread_type == ThreadType.USER:
345 data["specific_to_list[0]"] = "fbid:{}".format(thread_id) 345 data["specific_to_list[0]"] = "fbid:{}".format(thread_id)
346 data["specific_to_list[1]"] = "fbid:{}".format(self.uid) 346 data["specific_to_list[1]"] = "fbid:{}".format(self.uid)
347 - info = share_attachment.parse(self._parse_link(link)) 347 + info = _attachment.parse(self._parse_link(link))
348 data.update(info) 348 data.update(info)
349 return self._doSendRequest(data) 349 return self._doSendRequest(data)
350 350
@@ -150,7 +150,10 @@ class MessageSocketClient(WebSocketClient): @@ -150,7 +150,10 @@ class MessageSocketClient(WebSocketClient):
150 return {"type": "ping"} 150 return {"type": "ping"}
151 151
152 def sendheartbeat(self): 152 def sendheartbeat(self):
153 - if self.send(self.payload_data()): 153 + msg = self.payload_data()
  154 + bool = self.send(msg) if msg else False
  155 +
  156 + if msg is None or bool:
154 self._io_loop.call_later(self.heartbeat_interval_in_secs, 157 self._io_loop.call_later(self.heartbeat_interval_in_secs,
155 functools.partial(self.sendheartbeat)) 158 functools.partial(self.sendheartbeat))
156 159
  1 +#!/usr/bin/env python
  2 +# -*- coding: utf-8 -*-
  3 +# @Time : 2020-02-13 14:49
  4 +# @Author : Lemon
  5 +# @File : share_attachment.py
  6 +# @Software: PyCharm
  7 +
  8 +def _get_share_data(result, res, keys):
  9 + if isinstance(res, dict):
  10 + for key, value in res.items():
  11 + _handler_data(key, value, keys, result)
  12 + elif isinstance(res, list):
  13 + for i, value in enumerate(res):
  14 + _get_share_data(result, value, keys + ("[%d]" % i))
  15 + else:
  16 + result.update({keys: res})
  17 +
  18 +
  19 +def _handler_data(key, value, keys, result):
  20 + if value is None:
  21 + value = ''
  22 + if isinstance(value, dict):
  23 + _get_share_data(result, value, keys + ("[%s]" % key))
  24 + elif isinstance(value, list):
  25 + if value:
  26 + _get_share_data(result, value, keys + ("[%s]" % key))
  27 + else:
  28 + result.update({
  29 + keys + '[%s]' % key: value
  30 + })
  31 +
  32 +
  33 +def parse(t):
  34 + data = t.get('share_data')
  35 + result = dict()
  36 + _get_share_data(result, data, "shareable_attachment")
  37 + return result