微信企业会话存档SDK接口封装(Python示例)

Windows

  • 平台

    • win10
    • vs2019
    • sdk_win_v1.1
  • export.cpp

    extern "C"
    {
    #include <malloc.h>
    #include <string.h>
    #include <stdio.h>
    #include  "WeWorkFinanceSdk_C.h"
    
    	WeWorkFinanceSdk_t* sdk = NewSdk();
    
    	__declspec(dllexport) void free_p(void* p)
    	{
    		if (p) {
    			free(p);
    			p = 0;
    		}
    	}
    
    	__declspec(dllexport) int  init_sdk(char* corpid, char* key)
    	{
    		int ret = Init(sdk, corpid, key);
    		if (ret != 0)
    		{
    			DestroySdk(sdk);
    			printf("Init SDK failed.");
    		}
    		return ret;
    	}
    
    	__declspec(dllexport) char* get_chat_data(int seq, int limit, char* proxy, char* passwd, int timeout, int* datalen)
    	{
    		char* retData = 0;
    		*datalen = 0;
    
    
    		Slice_t* chatDatas = NewSlice();
    		int ret = GetChatData(sdk, seq, limit, proxy, passwd, timeout, chatDatas);
    		if (ret != 0) {
    			FreeSlice(chatDatas);
    			printf("Get data failed, return code: %d.", ret);
    			return retData;
    		}
    		retData = (char*)malloc(chatDatas->len * sizeof(char));
    		memcpy(retData, chatDatas->buf, chatDatas->len);
    		*datalen = chatDatas->len;
    		FreeSlice(chatDatas);
    		return retData;
    	}
    
    	__declspec(dllexport) char* pull_media_file(char* fileid, char* proxy, char* passwd, int timeout, int datalen)
    	{
    		char index[512*1024] = { 0 };
    		char* file_buff = (char*)malloc(datalen * sizeof(char));
    		char* fbidx = file_buff;
    		int total_len = 0;
    		int isfinish = 0;
    		while (isfinish == 0) {
    			//每次使用GetMediaData拉取存档前需要调用NewMediaData获取一个mediaData,在使用完mediaData中数据后,还需要调用FreeMediaData释放。
    			printf("index:%s\n", index);
    			MediaData_t* mediaData = NewMediaData();
    			int ret = GetMediaData(sdk, index, fileid, proxy, passwd, timeout, mediaData);
    			if (ret != 0) {
    				//单个分片拉取失败建议重试拉取该分片,避免从头开始拉取。
    				FreeMediaData(mediaData);
    				printf("GetMediaData err ret:%d\n", ret);
    				free_p(file_buff);
    				return file_buff;
    			}
    
    			memcpy(fbidx, mediaData->data, mediaData->data_len);
    			fbidx += mediaData->data_len;
    			total_len += mediaData->data_len;
    
    			//获取下次拉取需要使用的indexbuf
    			memset(index, 0, 512*1024);
    			memcpy(index, mediaData->outindexbuf, mediaData->out_len);
    			isfinish = mediaData->is_finish;
    			FreeMediaData(mediaData);
    		}
    
    		return file_buff;
    
    	}
    
    	__declspec(dllexport) char* decrypt_data(char* encrypt_key, char* encrypt_chat_msg, int* datalen)
    	{
    		char* retData = 0;
    		*datalen = 0;
    		Slice_t* msgs = NewSlice();
    		int ret = DecryptData(encrypt_key, encrypt_chat_msg, msgs);
    		retData = (char*)malloc(msgs->len * sizeof(char));
    		memcpy(retData, msgs->buf, msgs->len);
    		*datalen = msgs->len;
    		FreeSlice(msgs);
    
    		return retData;
    	}
    
    	__declspec(dllexport) void destory_sdk()
    	{
    		DestroySdk(sdk);
    	}
    
    }
    
    
  • 使用vs编译此cpp文件为dll

Linux

  • 平台

    • ubuntu 18.04
    • gcc
    • sdk_20201116
  • export.cpp

    tofix
    
  • gcc export.cpp -fPIC -shared -ldl -o libpywechat.so

Python调用方式 (windows)

import base64
from ctypes import *
import json
import sys

from Crypto import Random
from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5
from Crypto.PublicKey import RSA

pysdk = cdll.LoadLibrary('./pywechat.dll')

# void free_p(void* p)
# int  init_sdk(char* corpid, char* key)
# char* get_chat_data(int seq, int limit, char* proxy, char* passwd, int timeout, int* datalen)
# char* pull_media_file(char* fileid, char* proxy, char* passwd, int timeout, int datalen)
# char* decrypt_data(char* encrypt_key, char* encrypt_chat_msg, int* datalen)
# void destory_sdk()
pysdk.get_chat_data.restype = c_int64
pysdk.pull_media_file.restype = c_int64
pysdk.decrypt_data.restype = c_int64

corpid = b'企业号'
key = b'会话存档密钥'
seq = c_int(0)
limit = c_int(100)
proxy = b''
passwd = b''
timeout = c_int(10)

corpid_buff = create_string_buffer(corpid, len(corpid)+1)
key_buff = create_string_buffer(key, len(key)+1)
proxy_buff = create_string_buffer(proxy, len(proxy)+1)
passwd_buff = create_string_buffer(passwd, len(passwd)+1)

ret_len = c_int(0)

# 初始化sdk
init_status = pysdk.init_sdk(corpid_buff, key_buff)
print("Init sdk ret_code.", init_status)
if init_status != 0:
	sys.exit(init_status)
# 获取数据
resp = pysdk.get_chat_data(seq, limit, proxy_buff, passwd_buff, timeout, byref(ret_len))

# ret_data_demo = {
# 	"errcode": 0,
# 	"errmsg": "ok",
# 	"chatdata": [{
# 		"seq": 1,
# 		"msgid": "10717693993641340428_1641865486744",
# 		"publickey_ver": 1,
# 		"encrypt_random_key": "随机加密码",
# 		"encrypt_chat_msg": "加密消息内容"
# 	}, {
# 		"seq": 2,
# 		"msgid": "13596831180950397347_1641871046891",
# 		"publickey_ver": 1,
# 		"encrypt_random_key": "随机加密码",
# 		"encrypt_chat_msg": "加密消息内容"
# 	}]
# }
ret_data = json.loads(string_at(resp, ret_len.value))

# 释放内存空间
# pysdk.free_p(resp)
#
datails_data_demo = {"msgid": "13596831180950397347_1641871046891", "action": "send", "from": "发送方",
                     "tolist": ["接收方"], "roomid": "", "msgtime": 1641871046713, "msgtype": "file",
                     "file": {"md5sum": "C328154E2E2D4879443CAF464F1F9E0D", "filename": "Visual Assist X 10.9.2210.rar",
                              "fileext": "rar", "filesize": 35341717,
                              "sdkfileid": "文件序号"}}
random_generator = Random.new().read
assert ret_data.get("errcode") == 0
for chat_data in ret_data.get("chatdata"):
	if 'external' in chat_data.get("msgid"):
		continue
	print(chat_data.get("msgid"))
	# TODO: 判断 publickey_ver
	with open("私钥文件") as f:
		key = f.read()
		rsakey = RSA.importKey(key)
		cipher = Cipher_pkcs1_v1_5.new(rsakey)
		encrypt_key = cipher.decrypt(base64.b64decode(chat_data.get("encrypt_random_key")), None)
		encrypt_msg = bytes(chat_data.get("encrypt_chat_msg"), encoding='utf-8')
		encrypt_key_buff = create_string_buffer(encrypt_key, len(encrypt_key)+1)
		encrypt_msg_buff = create_string_buffer(encrypt_msg, len(encrypt_msg)+1)
		ret_len = c_int(0)
		byte_details = pysdk.decrypt_data(encrypt_key_buff, encrypt_msg_buff, byref(ret_len))
		byte_details = string_at(byte_details, ret_len.value)
		data_details = json.loads(byte_details)
		print(data_details)
		if data_details.get("msgtype") is None:
			print("invalid type error")
			continue
		elif data_details.get("msgtype") == "file":
			fileid = bytes(data_details.get('file').get("sdkfileid"), encoding='utf-8')
			filelen = data_details.get('file').get("filesize")
			file_content = pysdk.pull_media_file(create_string_buffer(fileid, len(fileid)+1), proxy_buff, passwd_buff, timeout, c_int(filelen))
			filename = data_details.get('file').get("filename")
			with open(filename, 'wb') as dstf:
				dstf.write(string_at(file_content, filelen))
				# pysdk.free_p(file_content)
		elif data_details.get("msgtype") == "text":
			print("text message")

pysdk.destory_sdk()
print(1)
sys.exit(0)
上一篇:随机数、时间戳、猜数字游戏


下一篇:CF 741D. Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths [dsu on tree 类似点分治]