Skip to content

Commit 8ff0b71

Browse files
committed
support multiple file store
1 parent 4a90a89 commit 8ff0b71

12 files changed

+285
-83
lines changed

doc/qqprotocol.md

+14
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,20 @@ w.qq与手机qq能够保证都收到消息,但是手机上发送的消息不
7171
*
7272
*
7373

74+
##### long poll
75+
76+
POST
77+
http://d.web2.qq.com/channel/poll2?
78+
79+
80+
返回值:
81+
82+
{"retcode":102,"errmsg":""} poll 正常超时,再次poll即可。
83+
84+
{"retcode":121,"t":""} 掉线
85+
86+
87+
7488
##### 被迫下载
7589
您的帐号在另一地点登录,您已被迫下线。如有疑问,请登录 safe.qq.com 了解更多。
7690

requirements.txt

+1
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ pytox
33
sleekxmpp
44
qiniu
55
PyExecJS
6+
pycurl

setup.py

+8-2
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,18 @@
1010
description="A weixin agent daemon and client",
1111
author='kitech',
1212
author_email='[email protected]',
13-
url='http://contrix.tk/',
13+
url='https://github.com/kitech/wxagent',
1414
packages=find_packages(),
1515
package_data={
1616
'wxagent': ['readme.md']
1717
},
18-
install_requires=[],
18+
install_requires=[
19+
'pytox',
20+
'sleekxmpp',
21+
'qiniu',
22+
'pycurl',
23+
'PyExecJS',
24+
],
1925
entry_points="""
2026
[console_scripts]
2127
wxagent = wxagent.wxagent:main

wxagent/filestore.py

+117-30
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,124 @@
1+
import os
2+
import io
13
import hashlib
4+
import base64
5+
import pycurl
26

37
from PyQt5.QtCore import QByteArray
48

59
import qiniu
610

711

8-
# @param data bytes
9-
def md5_file(data):
10-
h = hashlib.md5()
11-
h.update(data)
12-
return h.hexdigest()
13-
14-
15-
# @param data bytes | QByteArray
16-
def upload_file(data):
17-
if type(data) == QByteArray:
18-
data = data.data()
19-
from .secfg import qiniu_acckey, qiniu_seckey, qiniu_bucket_name
20-
access_key = qiniu_acckey
21-
secret_key = qiniu_seckey
22-
bucket_name = qiniu_bucket_name
23-
24-
q = qiniu.Auth(access_key, secret_key)
25-
key = 'helloqt.png'
26-
key = md5_file(data)
27-
# data = 'hello qiniu!'
28-
# data = load_from_file(PATH)
29-
token = q.upload_token(bucket_name)
30-
ret, info = qiniu.put_data(token, key, data)
31-
if ret is not None:
32-
print('upload file All is OK', ret)
33-
else:
34-
print(ret, '=====', info) # error message in info
35-
36-
url = 'http://7xn2rb.com1.z0.glb.clouddn.com/%s' % key
37-
return url
12+
class FileStore:
13+
def __init__(self):
14+
return
15+
16+
def uploadData(data):
17+
return
18+
19+
def uploadFile(fname):
20+
return
21+
22+
def md5sum(data):
23+
h = hashlib.md5()
24+
h.update(data)
25+
return h.hexdigest()
26+
27+
28+
class QiniuFileStore(FileStore):
29+
def __init__(self):
30+
return
31+
32+
# @param data bytes | QByteArray
33+
def uploadData(data):
34+
if type(data) == QByteArray:
35+
data = data.data()
36+
37+
from .secfg import qiniu_acckey, qiniu_seckey, qiniu_bucket_name
38+
access_key = qiniu_acckey
39+
secret_key = qiniu_seckey
40+
bucket_name = qiniu_bucket_name
41+
42+
q = qiniu.Auth(access_key, secret_key)
43+
key = 'helloqt.png'
44+
key = FileStore.md5sum(data)
45+
# data = 'hello qiniu!'
46+
# data = load_from_file(PATH)
47+
token = q.upload_token(bucket_name)
48+
ret, info = qiniu.put_data(token, key, data)
49+
if ret is not None:
50+
print('upload file All is OK', ret)
51+
else:
52+
print(ret, '=====', info) # error message in info
53+
54+
url = 'http://7xn2rb.com1.z0.glb.clouddn.com/%s' % key
55+
return url
56+
57+
def uploadFile(fname):
58+
data = b''
59+
with open(fname, 'rb') as f:
60+
data = f.read()
61+
62+
return QiniuFileStore.uploadData(data)
63+
64+
65+
class ImgurFileStore(FileStore):
66+
def __init__(self):
67+
return
68+
69+
def uploadData(data):
70+
return
71+
72+
def uploadFile(fname):
73+
return
74+
75+
76+
class VnFileStore(FileStore):
77+
def __init__(self):
78+
return
79+
80+
def uploadData(data):
81+
if type(data) == QByteArray:
82+
data = data.data()
83+
84+
md5sum = FileStore.md5sum(data)
85+
fname = '/tmp/' + md5sum
86+
87+
with open(fname, 'wb') as f:
88+
f.write(data)
89+
90+
url = VnFileStore.uploadFile(fname)
91+
os.path.os.unlink(fname)
92+
return url
93+
94+
def uploadFile(fname):
95+
dest_url = b'aHR0cHM6Ly9pbWcudmltLWNuLmNvbS8=' # heihei
96+
dest_url = base64.b64decode(dest_url).decode()
97+
98+
c = pycurl.Curl()
99+
c.setopt(pycurl.URL, dest_url)
100+
c.setopt(pycurl.POST, 1)
101+
102+
filename = fname
103+
c.setopt(c.HTTPPOST, [(('file', (c.FORM_FILE, filename)))])
104+
c.setopt(pycurl.SSL_VERIFYPEER, 0)
105+
c.setopt(pycurl.SSL_VERIFYHOST, 0)
106+
c.setopt(pycurl.USERAGENT, 'curl/7.45.0')
107+
# c.setopt(pycurl.VERBOSE, 1)
108+
# c.setopt(pycurl.PROXY, '127.0.0.1:8117')
109+
# c.setopt(pycurl.PROXYTYPE_HTTP, 1)
110+
111+
outval = io.BytesIO()
112+
hdrval = io.BytesIO()
113+
c.setopt(pycurl.WRITEFUNCTION, outval.write)
114+
c.setopt(pycurl.HEADERFUNCTION, hdrval.write)
115+
c.setopt(pycurl.TIMEOUT, 107) # 这网烂成如此,不容易
116+
117+
c.perform()
118+
c.close()
119+
120+
# print(outval.getvalue().decode(), hdrval.getvalue().decode())
121+
url = outval.getvalue().decode()
122+
if not url.startswith('https://'): print('upload error: ', hdrval.getvalue())
123+
124+
return url

wxagent/imrelay.py

+2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ def __init__(self, parent=None):
2626
self.unimsgcls = UniMessage # 为foo2bar主控逻辑做消息转换时使用
2727
self.src_pname = 'WXU.or.WQU' # src proto name
2828
self.relay_tail = '' # like -- from tox/xmpp
29+
30+
self.support_file_transfer = False # 支持inline方式传递文件,而不是使用第三方存储
2931
return
3032

3133
# @return True|False

wxagent/qq2any.py

+29-8
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@
99
from PyQt5.QtNetwork import *
1010
from PyQt5.QtDBus import *
1111

12-
import wxagent.filestore as filestore
1312
from .imrelayfactory import IMRelayFactory
1413
from .qqcom import *
1514
from .qqsession import *
1615
from .unimessage import *
1716
from .wxprotocol import *
17+
from .filestore import QiniuFileStore, VnFileStore
1818

1919
# QDBUS_DEBUG
2020

@@ -117,7 +117,10 @@ def __init__(self, parent = None):
117117
return
118118

119119
def initRelay(self):
120-
relay_type = 'xmpp'
120+
from .secfg import relay_type
121+
if relay_type is None or relay_type == '' or relay_type not in ('xmpp', 'tox'):
122+
raise 'relay type not set or invalid relay type. see secfg.py.'
123+
# relay_type = 'xmpp'
121124
# relay_type = 'tox'
122125
self.peerRelay = IMRelayFactory.create(relay_type)
123126
self.peerRelay.src_pname = 'WQU'
@@ -138,7 +141,10 @@ def onRelayConnected(self):
138141

139142
if self.need_send_qrfile is True and self.peerRelay.isPeerConnected(self.peerRelay.peer_user):
140143
# from .secfg import peer_xmpp_user
141-
url = filestore.upload_file(self.qrpic.data())
144+
# url = filestore.upload_file(self.qrpic.data())
145+
url1 = QiniuFileStore.uploadData(self.qrpic.data())
146+
url2 = VnFileStore.uploadData(self.qrpic.data())
147+
url = url1 + "\n" + url2
142148
self.peerRelay.sendMessage('test qrpic url....' + url, self.peerRelay.peer_user)
143149
self.need_send_qrfile = False
144150

@@ -161,7 +167,10 @@ def onRelayPeerConnected(self):
161167

162168
if self.need_send_qrfile is True and self.peerRelay.isPeerConnected(self.peerRelay.peer_user):
163169
# from .secfg import peer_xmpp_user
164-
url = filestore.upload_file(self.qrpic.data())
170+
# url = filestore.upload_file(self.qrpic.data())
171+
url1 = QiniuFileStore.uploadData(self.qrpic.data())
172+
url2 = VnFileStore.uploadData(self.qrpic.data())
173+
url = url1 + "\n" + url2
165174
self.peerRelay.sendMessage('test qrpic url....' + url, self.peerRelay.peer_user)
166175
self.need_send_qrfile = False
167176

@@ -341,7 +350,10 @@ def startWXBot(self):
341350
tkc = False
342351
tkc = self.peerRelay.isPeerConnected(self.peerRelay.peer_user)
343352
if tkc is True:
344-
url = filestore.upload_file(self.qrpic)
353+
# url = filestore.upload_file(self.qrpic)
354+
url1 = QiniuFileStore.uploadData(self.qrpic)
355+
url2 = VnFileStore.uploadData(self.qrpic)
356+
url = url1 + "\n" + url2
345357
self.peerRelay.sendMessage('qrcode url:' + url, self.peerRelay.peer_user)
346358
else:
347359
self.need_send_qrfile = True
@@ -404,7 +416,10 @@ def onDBusGotQRCode(self, message):
404416
tkc = False
405417
tkc = self.peerRelay.isPeerConnected(self.peerRelay.peer_user)
406418
if tkc is True:
407-
url = filestore.upload_file(self.qrpic)
419+
# url = filestore.upload_file(self.qrpic)
420+
url1 = QiniuFileStore.uploadData(self.qrpic)
421+
url2 = VnFileStore.uploadData(self.qrpic)
422+
url = url1 + "\n" + url2
408423
self.peerRelay.sendMessage('qrpic url:' + url, self.peerRelay.peer_user)
409424
else:
410425
self.need_send_qrfile = True
@@ -523,7 +538,10 @@ def sendMessageToTox(self, msg, fmtcc):
523538
def sendShotPicMessageToTox(self, msg, logstr):
524539
def get_img_reply(data=None):
525540
if data is None: return
526-
url = filestore.upload_file(data)
541+
# url = filestore.upload_file(data)
542+
url1 = QiniuFileStore.uploadData(data)
543+
url2 = VnFileStore.uploadData(data)
544+
url = url1 + "\n" + url2
527545
umsg = 'pic url: ' + url
528546
self.sendMessageToTox(msg, umsg)
529547
return
@@ -538,7 +556,10 @@ def get_file_reply(data=None):
538556
umsg = 'Get file error: ' + data.data().decode()
539557
self.sendMessageToTox(msg, umsg)
540558
else:
541-
url = filestore.upload_file(data)
559+
# url = filestore.upload_file(data)
560+
url1 = QiniuFileStore.uploadData(data)
561+
url2 = VnFileStore.uploadData(data)
562+
url = url1 + "\n" + url2
542563
umsg = 'file url: ' + url
543564
self.sendMessageToTox(msg, umsg)
544565
return

wxagent/qqagent.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ def onReply(self, reply):
113113
qDebug('content-length:' + str(len(hcc)) + ',' + str(status_code) + ',' + str(error_no))
114114
self.updateCookies(reply)
115115

116+
if status_code is None and error_no in [99]:
117+
qDebug('maybe logout for timeout.')
118+
116119
# statemachine by url and response content
117120
if url.startswith('https://ui.ptlogin2.qq.com/cgi-bin/login?'):
118121

@@ -1341,7 +1344,7 @@ def dumpReply(self, reply):
13411344
qDebug("\ngggggggg===========")
13421345
qDebug(str(reply))
13431346
req = reply.request()
1344-
qDebug(str(req.url()))
1347+
qDebug(str(req.url()).encode())
13451348
stcode = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute)
13461349
qDebug(str(stcode))
13471350
cookies = reply.header(QNetworkRequest.SetCookieHeader)

wxagent/toxrelay.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from .qtoxkit import *
99

1010
from .imrelay import IMRelay
11-
from .unimessage import *
11+
from .unimessage import ToxMessage
1212

1313

1414
class ToxRelay(IMRelay):

0 commit comments

Comments
 (0)