mirror of
https://gitee.com/durcframework/SOP.git
synced 2025-08-11 12:56:28 +08:00
- 新增ISV用户平台
- 新增门户网站(portal) - 新增`C++`,`Rust`语言SDK
This commit is contained in:
27
sop-sdk/sdk-c++/.gitignore
vendored
Normal file
27
sop-sdk/sdk-c++/.gitignore
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
/target/
|
||||
/cmake-build-debug/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
/build/
|
||||
|
42
sop-sdk/sdk-c++/CMakeLists.txt
Normal file
42
sop-sdk/sdk-c++/CMakeLists.txt
Normal file
@@ -0,0 +1,42 @@
|
||||
# cmake和CMakeLists.txt教程
|
||||
# https://www.jianshu.com/p/cb4f8136a265
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(sdk_cxx)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(LIB_SRC
|
||||
common/OpenClient.cpp
|
||||
common/OpenClient.h
|
||||
common/RequestType.h
|
||||
common/tool.h
|
||||
common/sign.h
|
||||
common/RSASign.h
|
||||
common/RSASign.cpp
|
||||
common/sha256.hpp
|
||||
request/BaseRequest.h
|
||||
request/MemberInfoGetRequest.hpp
|
||||
thirdparty/base64/base64.h
|
||||
thirdparty/base64/base64.cpp
|
||||
thirdparty/CJsonObject/cJSON.c
|
||||
thirdparty/CJsonObject/cJSON.h
|
||||
thirdparty/CJsonObject/CJsonObject.hpp
|
||||
thirdparty/CJsonObject/CJsonObject.cpp
|
||||
thirdparty/x2struct/x2struct.hpp
|
||||
common/sign.cpp common/tool.cpp common/sha256.cpp
|
||||
request/BaseRequest.cpp response/BaseResponse.h response/MemberInfoGetResponse.h)
|
||||
|
||||
# openssl安装路径
|
||||
set(OPENSSL_INC_DIR /usr/local/opt/openssl/include)
|
||||
set(OPENSSL_LINK_DIR /usr/local/opt/openssl/lib)
|
||||
|
||||
include_directories(${OPENSSL_INC_DIR})
|
||||
link_directories(${OPENSSL_LINK_DIR})
|
||||
link_libraries(ssl crypto)
|
||||
|
||||
# 添加类库
|
||||
add_library(lib ${LIB_SRC})
|
||||
# 添加可执行文件
|
||||
add_executable(sdk_cxx main.cpp)
|
||||
|
||||
# 可执行文件依赖lib库
|
||||
target_link_libraries(sdk_cxx lib ssl)
|
1
sop-sdk/sdk-c++/aa.txt
Normal file
1
sop-sdk/sdk-c++/aa.txt
Normal file
@@ -0,0 +1 @@
|
||||
hello你好123
|
1
sop-sdk/sdk-c++/bb.txt
Normal file
1
sop-sdk/sdk-c++/bb.txt
Normal file
@@ -0,0 +1 @@
|
||||
文件bb的内容
|
133
sop-sdk/sdk-c++/common/OpenClient.cpp
Normal file
133
sop-sdk/sdk-c++/common/OpenClient.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
#include "OpenClient.h"
|
||||
#include "httplib.h"
|
||||
#include "tool.h"
|
||||
#include "sign.h"
|
||||
|
||||
#include "../thirdparty/CJsonObject/CJsonObject.hpp"
|
||||
|
||||
httplib::Headers headers = {
|
||||
{"Accept-Encoding", "identity"}
|
||||
};
|
||||
|
||||
const string ERROR_NODE = "error_response";
|
||||
|
||||
OpenClient::OpenClient(const string &appId, const string &privateKeyFilePath, const string &url) {
|
||||
this->appId = appId;
|
||||
this->privateKeyFilePath = privateKeyFilePath;
|
||||
|
||||
char *_url = const_cast<char *>(url.c_str());
|
||||
char *host;
|
||||
int port;
|
||||
char *path;
|
||||
tool::parse_url(_url, &host, &port, &path);
|
||||
this->hostInfo = HostInfo{
|
||||
host = host,
|
||||
port = port,
|
||||
path = path
|
||||
};
|
||||
}
|
||||
|
||||
neb::CJsonObject OpenClient::execute(BaseRequest *request) {
|
||||
return this->execute(request, "");
|
||||
}
|
||||
|
||||
neb::CJsonObject OpenClient::execute(BaseRequest *request, const string &token) {
|
||||
string method = request->getMethod();
|
||||
string version = request->getVersion();
|
||||
RequestType requestType = request->getRequestType();
|
||||
map<string, string> bizModel = request->bizModel;
|
||||
// 创建HTTP请求客户端
|
||||
httplib::Client cli(this->hostInfo.host, this->hostInfo.port);
|
||||
// 构建请求参数
|
||||
map<string, string> allParams = this->buildParams(request, token);
|
||||
char *path = this->hostInfo.path;
|
||||
string responseBody;
|
||||
// 如果有文件上传
|
||||
if (!request->getFiles().empty()) {
|
||||
httplib::MultipartFormDataItems items = OpenClient::getMultipartFormDataItems(
|
||||
allParams, request->getFiles());
|
||||
responseBody = cli.Post(path, headers, items)->body;
|
||||
} else {
|
||||
switch (requestType) {
|
||||
case GET: {
|
||||
responseBody = cli.Get(path, allParams, headers)->body;
|
||||
break;
|
||||
}
|
||||
case POST_FORM: {
|
||||
responseBody = cli.Post(path, headers, OpenClient::getParams(allParams))->body;
|
||||
break;
|
||||
}
|
||||
case POST_JSON: {
|
||||
string json = tool::mapToJson(allParams);
|
||||
responseBody = cli.Post(path, json, "application/json")->body;
|
||||
break;
|
||||
}
|
||||
case POST_FILE: {
|
||||
httplib::MultipartFormDataItems items = OpenClient::getMultipartFormDataItems(
|
||||
allParams, request->getFiles());
|
||||
responseBody = cli.Post(path, headers, items)->body;
|
||||
}
|
||||
}
|
||||
}
|
||||
return OpenClient::parseResponse(responseBody, request);
|
||||
}
|
||||
|
||||
|
||||
httplib::Params OpenClient::getParams(map<string, string> allParams) {
|
||||
httplib::Params params;
|
||||
map<string, string>::iterator it;
|
||||
for (it = allParams.begin(); it != allParams.end(); ++it) {
|
||||
params.emplace(it->first, it->second);
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
map<string, string> OpenClient::buildParams(BaseRequest *request, const string &token) {
|
||||
map<string, string> allParams;
|
||||
allParams["app_id"] = this->appId;
|
||||
allParams["method"] = request->getMethod();
|
||||
allParams["charset"] = "UTF-8";
|
||||
allParams["sign_type"] = "RSA2";
|
||||
allParams["timestamp"] = tool::getTime();
|
||||
allParams["version"] = request->getVersion();
|
||||
|
||||
if (!token.empty()) {
|
||||
allParams["app_auth_token"] = token;
|
||||
}
|
||||
|
||||
map<string, string> bizModel = request->bizModel;
|
||||
|
||||
allParams.insert(bizModel.begin(), bizModel.end());
|
||||
|
||||
// 生成签名
|
||||
string sign = signutil::createSign(allParams, this->privateKeyFilePath, "RSA2");
|
||||
allParams["sign"] = sign;
|
||||
return allParams;
|
||||
}
|
||||
|
||||
httplib::MultipartFormDataItems
|
||||
OpenClient::getMultipartFormDataItems(map<string, string> allParams, vector<FileInfo> fileInfoList) {
|
||||
httplib::MultipartFormDataItems items = {};
|
||||
map<string, string>::iterator it;
|
||||
for (it = allParams.begin(); it != allParams.end(); ++it) {
|
||||
items.push_back({it->first, it->second, "", ""});
|
||||
}
|
||||
// 添加上传文件
|
||||
vector<FileInfo>::iterator vit;
|
||||
for (vit = fileInfoList.begin(); vit != fileInfoList.end(); vit++) {
|
||||
string content = tool::getFileContent(vit->filepath);
|
||||
items.push_back({vit->name, content, tool::getFilename(vit->filepath), "application/octet-stream"});
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
neb::CJsonObject OpenClient::parseResponse(const string& responseBody, BaseRequest *request) {
|
||||
neb::CJsonObject oJson(responseBody);
|
||||
neb::CJsonObject data = oJson[ERROR_NODE];
|
||||
if (data.IsEmpty()) {
|
||||
string method = request->getMethod();
|
||||
string nodeName = tool::replace(method.c_str(),".","_") + "_response";
|
||||
data = oJson[nodeName];
|
||||
}
|
||||
return data;
|
||||
}
|
66
sop-sdk/sdk-c++/common/OpenClient.h
Normal file
66
sop-sdk/sdk-c++/common/OpenClient.h
Normal file
@@ -0,0 +1,66 @@
|
||||
#ifndef SDK_CXX_OPENCLIENT_H
|
||||
#define SDK_CXX_OPENCLIENT_H
|
||||
|
||||
#include <string>
|
||||
#include "httplib.h"
|
||||
#include "../request/BaseRequest.h"
|
||||
#include "../thirdparty/CJsonObject/CJsonObject.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct HostInfo {
|
||||
string host;
|
||||
int port;
|
||||
char *path;
|
||||
};
|
||||
|
||||
/**
|
||||
* 请求客户端
|
||||
*/
|
||||
class OpenClient {
|
||||
private:
|
||||
/** 应用id */
|
||||
string appId;
|
||||
/** 私钥文件路径 */
|
||||
string privateKeyFilePath;
|
||||
|
||||
public:
|
||||
/**
|
||||
* 创建客户端对象
|
||||
* @param appId 应用ID
|
||||
* @param privateKeyFilePath 应用私钥路径
|
||||
* @param url 请求URL
|
||||
*/
|
||||
OpenClient(const string &appId, const string &privateKeyFilePath, const string &url);
|
||||
|
||||
/**
|
||||
* 发送请求
|
||||
* @param request 请求对象,BaseRequest的子类
|
||||
* @param token token
|
||||
* @return 返回响应结果
|
||||
*/
|
||||
neb::CJsonObject execute(BaseRequest *request, const string& token);
|
||||
|
||||
/**
|
||||
* 发送请求
|
||||
* @param request 请求对象,BaseRequest的子类
|
||||
* @return 返回响应结果
|
||||
*/
|
||||
neb::CJsonObject execute(BaseRequest *request);
|
||||
|
||||
private:
|
||||
|
||||
HostInfo hostInfo;
|
||||
|
||||
map<string, string> buildParams(BaseRequest *request, const string& token);
|
||||
|
||||
static httplib::MultipartFormDataItems
|
||||
getMultipartFormDataItems(map<string, string> allParams, vector<FileInfo> fileInfoList);
|
||||
|
||||
static httplib::Params getParams(map<string, string> params);
|
||||
|
||||
static neb::CJsonObject parseResponse(const string& responseBody,BaseRequest *request);
|
||||
};
|
||||
|
||||
|
||||
#endif //SDK_CXX_OPENCLIENT_H
|
94
sop-sdk/sdk-c++/common/RSASign.cpp
Normal file
94
sop-sdk/sdk-c++/common/RSASign.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
#include "stdafx.h"
|
||||
#include "RSASign.h"
|
||||
#include "../thirdparty/base64/base64.h"
|
||||
|
||||
RSA* GetPublicKeyEx(char* szPath)
|
||||
{
|
||||
RSA *pubkey = RSA_new();
|
||||
|
||||
BIO *pubio;
|
||||
|
||||
pubio = BIO_new_file(szPath, "rb");
|
||||
pubkey = PEM_read_bio_RSAPublicKey(pubio, &pubkey, NULL, NULL);
|
||||
|
||||
BIO_free(pubio);
|
||||
|
||||
return pubkey;
|
||||
}
|
||||
|
||||
RSA* GetPrivateKeyEx(char* szPath)
|
||||
{
|
||||
RSA *prikey = RSA_new();
|
||||
|
||||
BIO *priio;
|
||||
|
||||
priio = BIO_new_file(szPath, "rb");
|
||||
prikey = PEM_read_bio_RSAPrivateKey(priio, &prikey, NULL, NULL);
|
||||
|
||||
BIO_free(priio);
|
||||
|
||||
return prikey;
|
||||
}
|
||||
|
||||
bool RSASignAction(const string& strEnData, char *privateKeyFilePath, string &strSigned)
|
||||
{
|
||||
int nlen = strEnData.length();
|
||||
RSA *prsa = NULL;
|
||||
if (NULL == (prsa = GetPrivateKeyEx(privateKeyFilePath)))
|
||||
{
|
||||
RSA_free(prsa);
|
||||
printf("获取私钥失败\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
char szTmp[1024] = { 0 };
|
||||
//对待签名数据做SHA1摘要
|
||||
SHA256((const unsigned char*)strEnData.c_str(), nlen, (unsigned char*)szTmp);
|
||||
int nLength;
|
||||
unsigned int nLengthRet;
|
||||
char szTmp1[1024] = { 0 }; //位数一定不能小于等于RSA的128位,没有‘\0’,数据会增加后面位数
|
||||
// unsigned char *szTmp1 = {0};
|
||||
nLength = RSA_sign(NID_sha256, (unsigned char *)szTmp, 32, (unsigned char *)szTmp1, &nLengthRet, prsa);
|
||||
if (nLength != 1)
|
||||
{
|
||||
RSA_free(prsa);
|
||||
return false;
|
||||
}
|
||||
strSigned = base64_encode((unsigned char *)szTmp1, strlen((const char *)szTmp1));
|
||||
RSA_free(prsa);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RSAVerifyAction(string strEnData, string &strSigned)
|
||||
{
|
||||
int nlen = strEnData.length();
|
||||
printf("验签的原始数据:[%s]\n", strEnData.c_str());
|
||||
|
||||
RSA *prsa = NULL;
|
||||
if (NULL == (prsa = GetPublicKeyEx(PUBLIC_KEY_FILE_EX)))
|
||||
{
|
||||
RSA_free(prsa);
|
||||
printf("获取公钥失败\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
//对待签名数据做SHA1摘要
|
||||
char szTmp[1024] = { 0 };
|
||||
int nLen = strEnData.length();
|
||||
SHA256((const unsigned char*)strEnData.c_str(), nLen, (unsigned char*)szTmp);
|
||||
|
||||
int nLength;
|
||||
unsigned int nLengthRet = strSigned.length();
|
||||
printf("nLengthRet2 = %d\n", nLengthRet);
|
||||
nLength = RSA_verify(NID_sha256, (unsigned char *)szTmp, 32, (unsigned char*)strSigned.c_str(), nLengthRet, prsa);
|
||||
if (nLength != 1)
|
||||
{
|
||||
RSA_free(prsa);
|
||||
return false;
|
||||
}
|
||||
|
||||
RSA_free(prsa);
|
||||
|
||||
return true;
|
||||
}
|
19
sop-sdk/sdk-c++/common/RSASign.h
Normal file
19
sop-sdk/sdk-c++/common/RSASign.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/err.h>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define PUBLIC_KEY_FILE_EX "publicEx.pem" //公钥文件
|
||||
#define PRIVATE_KEY_FILE_EX "privateEx.pem" //私钥文件
|
||||
|
||||
RSA* GetPublicKeyEx(char* szPath);
|
||||
RSA* GetPrivateKeyEx(char* szPath);
|
||||
|
||||
bool RSASignAction(const string& strEnData,char *privateKeyFilePath, string &strSigned);
|
||||
bool RSAVerifyAction(string strEnData, string &strSigned);
|
11
sop-sdk/sdk-c++/common/RequestType.h
Normal file
11
sop-sdk/sdk-c++/common/RequestType.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef SDK_CXX_REQUESTTYPE_H
|
||||
#define SDK_CXX_REQUESTTYPE_H
|
||||
|
||||
enum RequestType {
|
||||
GET,
|
||||
POST_FORM,
|
||||
POST_JSON,
|
||||
POST_FILE
|
||||
};
|
||||
|
||||
#endif //SDK_CXX_REQUESTTYPE_H
|
5741
sop-sdk/sdk-c++/common/httplib.h
Normal file
5741
sop-sdk/sdk-c++/common/httplib.h
Normal file
File diff suppressed because it is too large
Load Diff
270
sop-sdk/sdk-c++/common/sha256.cpp
Normal file
270
sop-sdk/sdk-c++/common/sha256.cpp
Normal file
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* Filename: sha256.cpp
|
||||
* Author: L.Y.
|
||||
* Brief: SHA256算法实现
|
||||
* Version: V1.0.0
|
||||
* Update log:
|
||||
* 1)20191108-20191113 V1.0.0
|
||||
* 1、初次版本。
|
||||
* TODO:
|
||||
* Attention:
|
||||
* 1)输入信息中有中文时,得到的数字指纹与使用SHA256在线加密工具得到数字指纹可能不相同。
|
||||
* 原因是中文的编码方式不同。
|
||||
*/
|
||||
|
||||
#include "sha256.hpp"
|
||||
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace digest
|
||||
{
|
||||
|
||||
//////////////////////////////// 静态数据成员初始化 //////////////////////////////////////////
|
||||
|
||||
std::vector<uint32_t> Sha256::initial_message_digest_ =
|
||||
{
|
||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372,
|
||||
0xa54ff53a, 0x510e527f, 0x9b05688c,
|
||||
0x1f83d9ab, 0x5be0cd19
|
||||
};
|
||||
|
||||
std::vector<uint32_t> Sha256::add_constant_ =
|
||||
{
|
||||
0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
|
||||
0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
|
||||
0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
|
||||
0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
|
||||
0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
|
||||
0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
|
||||
0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
|
||||
0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////// 成员函数的定义 //////////////////////////////////////////
|
||||
|
||||
bool Sha256::encrypt(const std::vector<uint8_t>& input_message,
|
||||
std::vector<uint8_t>* _digest)
|
||||
{
|
||||
if (!input_message.empty() && _digest)
|
||||
{
|
||||
//! 文本预处理
|
||||
std::vector<uint8_t> message = input_message;
|
||||
preprocessing(&message);
|
||||
|
||||
//! 将文本分解成连续的64Byte大小的数据块
|
||||
std::vector<std::vector<uint8_t>> chunks;
|
||||
breakTextInto64ByteChunks(message, &chunks);
|
||||
|
||||
//! 由64Byte大小的数据块,构造出64个4Byte大小的字。然后进行循环迭代。
|
||||
std::vector<uint32_t> message_digest(initial_message_digest_); // 初始化信息摘要
|
||||
|
||||
std::vector<uint32_t> words;
|
||||
for (const auto& chunk : chunks)
|
||||
{
|
||||
structureWords(chunk, &words);
|
||||
transform(words, &message_digest);
|
||||
}
|
||||
|
||||
//! 获取最终结果
|
||||
produceFinalHashValue(message_digest, _digest);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Sha256::getHexMessageDigest(const std::string& message)
|
||||
{
|
||||
if (!message.empty())
|
||||
{
|
||||
std::vector<uint8_t> __message;
|
||||
for (auto it = message.begin(); it != message.end(); ++it)
|
||||
{
|
||||
__message.push_back(static_cast<uint8_t>(*it));
|
||||
}
|
||||
|
||||
std::vector<uint8_t> digest;
|
||||
encrypt(__message, &digest);
|
||||
|
||||
std::ostringstream o_s;
|
||||
o_s << std::hex << std::setiosflags(std::ios::uppercase);
|
||||
for (auto it = digest.begin(); it != digest.end(); ++it)
|
||||
{
|
||||
o_s << std::setw(2) << std::setfill('0')
|
||||
<< static_cast<unsigned short>(*it);
|
||||
}
|
||||
|
||||
return o_s.str();
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
bool Sha256::preprocessing(std::vector<uint8_t>* _message) const
|
||||
{
|
||||
if (_message)
|
||||
{
|
||||
const uint64_t original_bit_size = _message->size() * 8;
|
||||
|
||||
//! 附加填充比特
|
||||
size_t remainder = _message->size() % 64;
|
||||
if (remainder < 56)
|
||||
{
|
||||
_message->push_back(0x80); // ox80 == 10000000
|
||||
for (size_t i = 1; i < 56 - remainder; ++i)
|
||||
{
|
||||
_message->push_back(0x00);
|
||||
}
|
||||
}
|
||||
else if (remainder == 56)
|
||||
{
|
||||
_message->push_back(0x80);
|
||||
for (size_t i = 1; i < 64; ++i)
|
||||
{
|
||||
_message->push_back(0x00);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_message->push_back(0x80);
|
||||
for (size_t i = 1; i < 64 - remainder + 56; ++i)
|
||||
{
|
||||
_message->push_back(0x00);
|
||||
}
|
||||
}
|
||||
|
||||
//! 附加原始文本的长度值
|
||||
for (int i = 1; i <= 8; ++i)
|
||||
{
|
||||
uint8_t c = static_cast<uint8_t>(original_bit_size >> (64 - 8 * i));
|
||||
_message->push_back(c);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Sha256::breakTextInto64ByteChunks(const std::vector<uint8_t>& message,
|
||||
std::vector<std::vector<uint8_t>>* _chunks) const
|
||||
{
|
||||
if (_chunks && 0 == message.size() % 64)
|
||||
{
|
||||
_chunks->clear(); // 清空输出buffer
|
||||
|
||||
size_t quotient = message.size() / 64;
|
||||
for (size_t i = 0; i < quotient; ++i)
|
||||
{
|
||||
std::vector<uint8_t> temp(message.begin() + i * 64, message.begin() + (i + 1) * 64);
|
||||
_chunks->push_back(temp);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Sha256::structureWords(const std::vector<uint8_t>& chunk,
|
||||
std::vector<uint32_t>* _words) const
|
||||
{
|
||||
if (_words && 64 == chunk.size())
|
||||
{
|
||||
_words->resize(64);
|
||||
|
||||
auto& words = *_words;
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
words[i] = (static_cast<uint32_t>(chunk[i * 4]) << 24)
|
||||
| (static_cast<uint32_t>(chunk[i * 4 + 1]) << 16)
|
||||
| (static_cast<uint32_t>(chunk[i * 4 + 2]) << 8)
|
||||
| static_cast<uint32_t>(chunk[i * 4 + 3]);
|
||||
}
|
||||
for (int i = 16; i < 64; ++i)
|
||||
{
|
||||
words[i] = small_sigma1(words[i - 2])
|
||||
+ words[i - 7]
|
||||
+ small_sigma0(words[i - 15])
|
||||
+ words[i - 16];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Sha256::transform(const std::vector<uint32_t>& words,
|
||||
std::vector<uint32_t>* _message_digest) const
|
||||
{
|
||||
if (_message_digest && 8 == _message_digest->size() && 64 == words.size())
|
||||
{
|
||||
std::vector<uint32_t> d = *_message_digest;
|
||||
|
||||
for (int i = 0; i < 64; ++i)
|
||||
{
|
||||
uint32_t temp1 = d[7] + big_sigma1(d[4]) + ch(d[4], d[5], d[6]) + add_constant_[i] + words[i];
|
||||
uint32_t temp2 = big_sigma0(d[0]) + maj(d[0], d[1], d[2]);
|
||||
|
||||
d[7] = d[6];
|
||||
d[6] = d[5];
|
||||
d[5] = d[4];
|
||||
d[4] = d[3] + temp1;
|
||||
d[3] = d[2];
|
||||
d[2] = d[1];
|
||||
d[1] = d[0];
|
||||
d[0] = temp1 + temp2;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
(*_message_digest)[i] += d[i];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Sha256::produceFinalHashValue(const std::vector<uint32_t>& input,
|
||||
std::vector<uint8_t>* _output) const
|
||||
{
|
||||
if (_output)
|
||||
{
|
||||
_output->clear();
|
||||
|
||||
for (auto it = input.begin(); it != input.end(); ++it)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
_output->push_back(static_cast<uint8_t>((*it) >> (24 - 8 * i)));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ly
|
||||
|
||||
|
144
sop-sdk/sdk-c++/common/sha256.hpp
Normal file
144
sop-sdk/sdk-c++/common/sha256.hpp
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Filename: sha256.hpp
|
||||
* Author: L.Y.
|
||||
* Brief: SHA256算法实现
|
||||
* Version: V1.0.0
|
||||
* Update log:
|
||||
* 1)20191108-20191113 V1.0.0
|
||||
* 1、初次版本。
|
||||
* TODO:
|
||||
* Attention:
|
||||
* 1)输入信息中有中文时,得到的数字指纹与使用SHA256在线加密工具得到数字指纹可能不相同。
|
||||
* 原因是中文的编码方式不同。
|
||||
*/
|
||||
|
||||
#ifndef SHA256_HPP
|
||||
#define SHA256_HPP
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace digest
|
||||
{
|
||||
|
||||
//
|
||||
// \brief: SHA256算法实现
|
||||
//
|
||||
class Sha256
|
||||
{
|
||||
public:
|
||||
//! 默认构造函数
|
||||
Sha256() {}
|
||||
|
||||
//! 析构函数
|
||||
virtual ~Sha256() {}
|
||||
|
||||
/** @brief: 使用SHA256算法,获取输入信息的摘要(数字指纹)
|
||||
@param[in] message: 输入信息
|
||||
@param[out] _digest: 摘要(数字指纹)
|
||||
@return: 是否成功
|
||||
*/
|
||||
bool encrypt(const std::vector<uint8_t>& message,
|
||||
std::vector<uint8_t>* _digest);
|
||||
|
||||
/** @brief: 获取十六进制表示的信息摘要(数字指纹)
|
||||
@param[in] message: 输入信息
|
||||
@return: 十六进制表示的信息摘要(数字指纹)
|
||||
*/
|
||||
std::string getHexMessageDigest(const std::string& message);
|
||||
|
||||
protected:
|
||||
/////// SHA256算法中定义的6种逻辑运算 ///////
|
||||
inline uint32_t ch(uint32_t x, uint32_t y, uint32_t z) const;
|
||||
inline uint32_t maj(uint32_t x, uint32_t y, uint32_t z) const;
|
||||
inline uint32_t big_sigma0(uint32_t x) const;
|
||||
inline uint32_t big_sigma1(uint32_t x) const;
|
||||
inline uint32_t small_sigma0(uint32_t x) const;
|
||||
inline uint32_t small_sigma1(uint32_t x) const;
|
||||
|
||||
/** @brief: SHA256算法对输入信息的预处理,包括“附加填充比特”和“附加长度值”
|
||||
附加填充比特: 在报文末尾进行填充,先补第一个比特为1,然后都补0,直到长度满足对512取模后余数是448。需要注意的是,信息必须进行填充。
|
||||
附加长度值: 用一个64位的数据来表示原始消息(填充前的消息)的长度,并将其补到已经进行了填充操作的消息后面。
|
||||
@param[in][out] _message: 待处理的信息
|
||||
@return: 是否成功
|
||||
*/
|
||||
bool preprocessing(std::vector<uint8_t>* _message) const;
|
||||
|
||||
/** @brief: 将信息分解成连续的64Byte大小的数据块
|
||||
@param[in] message: 输入信息,长度为64Byte的倍数
|
||||
@param[out] _chunks: 输出数据块
|
||||
@return: 是否成功
|
||||
*/
|
||||
bool breakTextInto64ByteChunks(const std::vector<uint8_t>& message,
|
||||
std::vector<std::vector<uint8_t>>* _chunks) const;
|
||||
|
||||
/** @brief: 由64Byte大小的数据块,构造出64个4Byte大小的字。
|
||||
构造算法:前16个字直接由数据块分解得到,其余的字由如下迭代公式得到:
|
||||
W[t] = small_sigma1(W[t-2]) + W[t-7] + small_sigma0(W[t-15]) + W[t-16]
|
||||
@param[in] chunk: 输入数据块,大小为64Byte
|
||||
@param[out] _words: 输出字
|
||||
@return: 是否成功
|
||||
*/
|
||||
bool structureWords(const std::vector<uint8_t>& chunk,
|
||||
std::vector<uint32_t>* _words) const;
|
||||
|
||||
/** @breif: 基于64个4Byte大小的字,进行64次循环加密
|
||||
@param[in] words: 64个4Byte大小的字
|
||||
@param[in][out] _message_digest: 信息摘要
|
||||
@return: 是否成功
|
||||
*/
|
||||
bool transform(const std::vector<uint32_t>& words,
|
||||
std::vector<uint32_t>* _message_digest) const;
|
||||
|
||||
/** @brief: 输出最终的哈希值(数字指纹)
|
||||
@param[in] input: 步长为32bit的哈希值
|
||||
@param[out] _output: 步长为8bit的哈希值
|
||||
@return: 是否成功
|
||||
*/
|
||||
bool produceFinalHashValue(const std::vector<uint32_t>& input,
|
||||
std::vector<uint8_t>* _output) const;
|
||||
|
||||
|
||||
private:
|
||||
static std::vector<uint32_t> initial_message_digest_; // 在SHA256算法中的初始信息摘要,这些常量是对自然数中前8个质数的平方根的小数部分取前32bit而来。
|
||||
static std::vector<uint32_t> add_constant_; // 在SHA256算法中,用到64个常量,这些常量是对自然数中前64个质数的立方根的小数部分取前32bit而来。
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////// 内联函数&模版函数的定义 /////////////////////////////////////////
|
||||
|
||||
inline uint32_t Sha256::ch(uint32_t x, uint32_t y, uint32_t z) const
|
||||
{
|
||||
return (x & y) ^ ((~x) & z);
|
||||
}
|
||||
|
||||
inline uint32_t Sha256::maj(uint32_t x, uint32_t y, uint32_t z) const
|
||||
{
|
||||
return (x & y) ^ (x & z) ^ (y & z);
|
||||
}
|
||||
|
||||
inline uint32_t Sha256::big_sigma0(uint32_t x) const
|
||||
{
|
||||
return (x >> 2 | x << 30) ^ (x >> 13 | x << 19) ^ (x >> 22 | x << 10);
|
||||
}
|
||||
|
||||
inline uint32_t Sha256::big_sigma1(uint32_t x) const
|
||||
{
|
||||
return (x >> 6 | x << 26) ^ (x >> 11 | x << 21) ^ (x >> 25 | x << 7);
|
||||
}
|
||||
|
||||
inline uint32_t Sha256::small_sigma0(uint32_t x) const
|
||||
{
|
||||
return (x >> 7 | x << 25) ^ (x >> 18 | x << 14) ^ (x >> 3);
|
||||
}
|
||||
|
||||
inline uint32_t Sha256::small_sigma1(uint32_t x) const
|
||||
{
|
||||
return (x >> 17 | x << 15) ^ (x >> 19 | x << 13) ^ (x >> 10);
|
||||
}
|
||||
|
||||
} // namespace ly
|
||||
|
||||
#endif // SHA256_HPP
|
118
sop-sdk/sdk-c++/common/sign.cpp
Normal file
118
sop-sdk/sdk-c++/common/sign.cpp
Normal file
@@ -0,0 +1,118 @@
|
||||
#include <utility>
|
||||
|
||||
#include "../thirdparty/base64/base64.h"
|
||||
#include "sign.h"
|
||||
#include "RSASign.h"
|
||||
#include "tool.h"
|
||||
|
||||
namespace signutil {
|
||||
string createSign(map<string, string> params, const string& privateKeyFilepath, const string& signType) {
|
||||
string content = getSignContent(std::move(params));
|
||||
return sign(content, privateKeyFilepath, "");
|
||||
}
|
||||
|
||||
string sign(const string& content, const string& privateKeyFilepath, const string& hash) {
|
||||
BIO *bufio = NULL;
|
||||
RSA *rsa = NULL;
|
||||
EVP_PKEY *evpKey = NULL;
|
||||
bool verify = false;
|
||||
EVP_MD_CTX ctx;
|
||||
int result = 0;
|
||||
unsigned int size = 0;
|
||||
char *sign = NULL;
|
||||
std::string signStr = "";
|
||||
|
||||
//bufio = BIO_new_mem_buf((void*)private_key, -1);
|
||||
//if (bufio == NULL) {
|
||||
// ERR("BIO_new_mem_buf failed");
|
||||
// goto safe_exit;
|
||||
//}
|
||||
bufio = BIO_new(BIO_s_file());
|
||||
// 读取私钥文件
|
||||
BIO_read_filename(bufio, privateKeyFilepath.c_str());
|
||||
|
||||
// 私钥字符串转换成私钥对象
|
||||
rsa = PEM_read_bio_RSAPrivateKey(bufio, NULL, NULL, NULL);
|
||||
if (rsa == NULL) {
|
||||
ERR("PEM_read_bio_RSAPrivateKey failed");
|
||||
goto safe_exit;
|
||||
}
|
||||
|
||||
evpKey = EVP_PKEY_new();
|
||||
if (evpKey == NULL) {
|
||||
ERR("EVP_PKEY_new failed");
|
||||
goto safe_exit;
|
||||
}
|
||||
|
||||
if ((result = EVP_PKEY_set1_RSA(evpKey, rsa)) != 1) {
|
||||
ERR("EVP_PKEY_set1_RSA failed");
|
||||
goto safe_exit;
|
||||
}
|
||||
|
||||
EVP_MD_CTX_init(&ctx);
|
||||
|
||||
// SHA256签名
|
||||
if (result == 1 && (result = EVP_SignInit_ex(&ctx,
|
||||
EVP_sha256(), NULL)) != 1) {
|
||||
ERR("EVP_SignInit_ex failed");
|
||||
}
|
||||
|
||||
if (result == 1 && (result = EVP_SignUpdate(&ctx,
|
||||
content.c_str(), content.size())) != 1) {
|
||||
ERR("EVP_SignUpdate failed");
|
||||
}
|
||||
|
||||
size = EVP_PKEY_size(evpKey);
|
||||
sign = (char*)malloc(size+1);
|
||||
memset(sign, 0, size+1);
|
||||
|
||||
if (result == 1 && (result = EVP_SignFinal(&ctx,
|
||||
(unsigned char*)sign,
|
||||
&size, evpKey)) != 1) {
|
||||
ERR("EVP_SignFinal failed");
|
||||
}
|
||||
|
||||
if (result == 1) {
|
||||
verify = true;
|
||||
} else {
|
||||
ERR("verify failed");
|
||||
}
|
||||
|
||||
signStr = base64_encode((const unsigned char*)sign, size);
|
||||
EVP_MD_CTX_cleanup(&ctx);
|
||||
free(sign);
|
||||
|
||||
safe_exit:
|
||||
if (rsa != NULL) {
|
||||
RSA_free(rsa);
|
||||
rsa = NULL;
|
||||
}
|
||||
|
||||
if (evpKey != NULL) {
|
||||
EVP_PKEY_free(evpKey);
|
||||
evpKey = NULL;
|
||||
}
|
||||
|
||||
if (bufio != NULL) {
|
||||
BIO_free_all(bufio);
|
||||
bufio = NULL;
|
||||
}
|
||||
|
||||
return signStr;
|
||||
|
||||
}
|
||||
|
||||
string getSignContent(map<string, string> params){
|
||||
map<string, string>::iterator iter;
|
||||
string content;
|
||||
for(iter = params.begin(); iter != params.end(); iter++) {
|
||||
content.append("&").append(iter->first + "=" + iter->second);
|
||||
}
|
||||
return content.substr(1);
|
||||
}
|
||||
|
||||
void ERR(const string &msg) {
|
||||
throw msg;
|
||||
}
|
||||
}
|
||||
|
30
sop-sdk/sdk-c++/common/sign.h
Normal file
30
sop-sdk/sdk-c++/common/sign.h
Normal file
@@ -0,0 +1,30 @@
|
||||
|
||||
|
||||
#ifndef SDK_CXX_SIGN_H
|
||||
#define SDK_CXX_SIGN_H
|
||||
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/err.h>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace signutil {
|
||||
|
||||
string createSign(map<string, string> params, const string& privateKeyFilepath, const string& signType);
|
||||
|
||||
string sign(const string& content, const string& privateKeyFilepath, const string& hash);
|
||||
|
||||
string getSignContent(map<string, string> params);
|
||||
|
||||
void ERR(const string &msg);
|
||||
}
|
||||
|
||||
|
||||
#endif //SDK_CXX_SIGN_H
|
2
sop-sdk/sdk-c++/common/stdafx.cpp
Normal file
2
sop-sdk/sdk-c++/common/stdafx.cpp
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
#include "stdafx.h"
|
6
sop-sdk/sdk-c++/common/stdafx.h
Normal file
6
sop-sdk/sdk-c++/common/stdafx.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "targetver.h"
|
||||
|
||||
|
||||
|
1
sop-sdk/sdk-c++/common/targetver.h
Normal file
1
sop-sdk/sdk-c++/common/targetver.h
Normal file
@@ -0,0 +1 @@
|
||||
|
174
sop-sdk/sdk-c++/common/tool.cpp
Normal file
174
sop-sdk/sdk-c++/common/tool.cpp
Normal file
@@ -0,0 +1,174 @@
|
||||
#include <clocale>
|
||||
#include "tool.h"
|
||||
#include <map>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
namespace tool {
|
||||
bool endWith(const string &str, const string &tail) {
|
||||
return str.compare(str.size() - tail.size(), tail.size(), tail) == 0;
|
||||
}
|
||||
|
||||
bool startWith(const string &str, const string &head) {
|
||||
return str.compare(0, head.size(), head) == 0;
|
||||
}
|
||||
|
||||
string getTime() {
|
||||
time_t timep;
|
||||
time(&timep);
|
||||
char tmp[64];
|
||||
strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S", localtime(&timep));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
int parse_url(char *url, char **serverstrp, int *portp, char **pathstrp) {
|
||||
char buf[256];
|
||||
int serverlen, numread = 0;
|
||||
/* go through the url */
|
||||
|
||||
/* reset url to point PAST the http:// */
|
||||
|
||||
/* assume it's always 7 chars! */
|
||||
string _url = url;
|
||||
bool isHttps = startWith(_url, "https");
|
||||
int len = 7;
|
||||
if (isHttps) {
|
||||
len = 8;
|
||||
}
|
||||
url = url + len;
|
||||
/* no http:// now... server is simply up to the next / or : */
|
||||
|
||||
sscanf(url, "%255[^/:]", buf);
|
||||
serverlen = strlen(buf);
|
||||
*serverstrp = (char *) malloc(serverlen + 1);
|
||||
strcpy(*serverstrp, buf);
|
||||
if (url[serverlen] == ':') {
|
||||
/* get the port */
|
||||
|
||||
sscanf(&url[serverlen + 1], "%d%n", portp, &numread);
|
||||
/* add one to go PAST it */
|
||||
|
||||
numread++;
|
||||
|
||||
} else {
|
||||
if (isHttps) {
|
||||
*portp = 443;
|
||||
} else {
|
||||
*portp = 80;
|
||||
}
|
||||
|
||||
}
|
||||
/* the path is a pointer into the rest of url */
|
||||
|
||||
*pathstrp = &url[serverlen + numread];
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string url_encode(const std::string &str) {
|
||||
std::string strTemp = "";
|
||||
size_t length = str.length();
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
if (isalnum((unsigned char) str[i]) ||
|
||||
(str[i] == '-') ||
|
||||
(str[i] == '_') ||
|
||||
(str[i] == '.') ||
|
||||
(str[i] == '~'))
|
||||
strTemp += str[i];
|
||||
else if (str[i] == ' ')
|
||||
strTemp += "+";
|
||||
else {
|
||||
strTemp += '%';
|
||||
strTemp += ToHex((unsigned char) str[i] >> 4);
|
||||
strTemp += ToHex((unsigned char) str[i] % 16);
|
||||
}
|
||||
}
|
||||
return strTemp;
|
||||
}
|
||||
|
||||
|
||||
std::string url_decode(const std::string &str) {
|
||||
std::string strTemp = "";
|
||||
size_t length = str.length();
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
if (str[i] == '+') strTemp += ' ';
|
||||
else if (str[i] == '%') {
|
||||
assert(i + 2 < length);
|
||||
unsigned char high = FromHex((unsigned char) str[++i]);
|
||||
unsigned char low = FromHex((unsigned char) str[++i]);
|
||||
strTemp += high * 16 + low;
|
||||
} else strTemp += str[i];
|
||||
}
|
||||
return strTemp;
|
||||
}
|
||||
|
||||
|
||||
unsigned char ToHex(unsigned char x) {
|
||||
return x > 9 ? x + 55 : x + 48;
|
||||
}
|
||||
|
||||
unsigned char FromHex(unsigned char x) {
|
||||
unsigned char y;
|
||||
if (x >= 'A' && x <= 'Z') y = x - 'A' + 10;
|
||||
else if (x >= 'a' && x <= 'z') y = x - 'a' + 10;
|
||||
else if (x >= '0' && x <= '9') y = x - '0';
|
||||
else
|
||||
assert(0);
|
||||
return y;
|
||||
}
|
||||
|
||||
string mapToJson(std::map<string, string> map_info) {
|
||||
// Json::Value jObject;
|
||||
// for (map<string, string>::const_iterator iter = map_info.begin( ); iter != map_info.end( ); ++iter)
|
||||
// {
|
||||
// jObject[iter->first] = iter->second;
|
||||
// }
|
||||
// return jObject.toStyledString();
|
||||
return "{}";
|
||||
}
|
||||
|
||||
string getFilename(string filepath) {
|
||||
{
|
||||
if (filepath.empty()) {
|
||||
return "";
|
||||
}
|
||||
std::string::size_type iPos;
|
||||
#ifdef Q_OS_WIN
|
||||
iPos = strFullName.find_last_of('\\') + 1;
|
||||
#else
|
||||
iPos = filepath.find_last_of('/') + 1;
|
||||
#endif
|
||||
|
||||
return filepath.substr(iPos, filepath.length() - iPos);
|
||||
}
|
||||
}
|
||||
|
||||
string getFileContent(string filepath) {
|
||||
ifstream fin(filepath);
|
||||
stringstream buffer;
|
||||
buffer << fin.rdbuf();
|
||||
string fileContent(buffer.str());
|
||||
fin.close();
|
||||
return fileContent;
|
||||
}
|
||||
|
||||
std::string replace(const char *pszSrc, const char *pszOld, const char *pszNew)
|
||||
{
|
||||
std::string strContent, strTemp;
|
||||
strContent.assign( pszSrc );
|
||||
std::string::size_type nPos = 0;
|
||||
while( true )
|
||||
{
|
||||
nPos = strContent.find(pszOld, nPos);
|
||||
strTemp = strContent.substr(nPos+strlen(pszOld), strContent.length());
|
||||
if ( nPos == std::string::npos )
|
||||
{
|
||||
break;
|
||||
}
|
||||
strContent.replace(nPos,strContent.length(), pszNew );
|
||||
strContent.append(strTemp);
|
||||
nPos +=strlen(pszNew) - strlen(pszOld)+1; //防止重复替换 避免死循环
|
||||
}
|
||||
return strContent;
|
||||
}
|
||||
|
||||
}
|
52
sop-sdk/sdk-c++/common/tool.h
Normal file
52
sop-sdk/sdk-c++/common/tool.h
Normal file
@@ -0,0 +1,52 @@
|
||||
|
||||
|
||||
#ifndef SDK_CXX_TOOL_H
|
||||
#define SDK_CXX_TOOL_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace tool {
|
||||
|
||||
bool endWith(const string &str, const string &tail);
|
||||
|
||||
bool startWith(const string &str, const string &head);
|
||||
|
||||
string getTime();
|
||||
|
||||
int parse_url(char *url, char **serverstrp, int *portp, char **pathstrp);
|
||||
|
||||
std::string url_encode(const std::string &szToEncode);
|
||||
|
||||
std::string url_decode(const std::string &SRC);
|
||||
|
||||
unsigned char ToHex(unsigned char x);
|
||||
|
||||
unsigned char FromHex(unsigned char x);
|
||||
|
||||
string mapToJson(std::map<string, string> m);
|
||||
|
||||
string getFilename(string filepath);
|
||||
|
||||
string getFileContent(string filepath);
|
||||
|
||||
|
||||
/**
|
||||
* 函数:
|
||||
* replace(替换字符串)
|
||||
* 参数:
|
||||
* pszSrc:源字符串
|
||||
* pszOld:需要替换的字符串
|
||||
* pszNew:新字符串
|
||||
* 返回值:
|
||||
* 返回替换后的字符串
|
||||
* 备注:
|
||||
* 需要添加#include <string>头文件
|
||||
* ssdwujianhua 2017/08/30
|
||||
*/
|
||||
std::string replace(const char *pszSrc, const char *pszOld, const char *pszNew);
|
||||
}
|
||||
|
||||
#endif //SDK_CXX_TOOL_H
|
41
sop-sdk/sdk-c++/main.cpp
Normal file
41
sop-sdk/sdk-c++/main.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
#include <iostream>
|
||||
|
||||
#include "common/OpenClient.h"
|
||||
#include "request/BaseRequest.h"
|
||||
#include "request/MemberInfoGetRequest.hpp"
|
||||
|
||||
// 应用ID
|
||||
string appId = "2020051325943082302177280";
|
||||
// 存放私钥的文件路径
|
||||
string privateKeyFile = "/Users/thc/IdeaProjects/opc/opc-sdk/sdk-c++/privateEx.pem";
|
||||
// 请求接口
|
||||
string url = "http://localhost:7071/prod/gw68uy85";
|
||||
|
||||
OpenClient openClient(appId, privateKeyFile, url);
|
||||
|
||||
int main() {
|
||||
// 创建请求
|
||||
MemberInfoGetRequest request;
|
||||
|
||||
// 业务参数
|
||||
map<string, string> bizModel;
|
||||
bizModel["name"] = "jim";
|
||||
bizModel["age"] = "22";
|
||||
bizModel["address"] = "xx";
|
||||
|
||||
request.bizModel = bizModel;
|
||||
|
||||
// 添加上传文件
|
||||
// request->setFiles({
|
||||
// FileInfo{"aa", "/Users/thc/IdeaProjects/opc/opc-sdk/sdk-c++/aa.txt"},
|
||||
// FileInfo{"bb", "/Users/thc/IdeaProjects/opc/opc-sdk/sdk-c++/bb.txt"}
|
||||
// });
|
||||
|
||||
// 发送请求
|
||||
neb::CJsonObject jsonObj = openClient.execute(&request);
|
||||
std::cout << jsonObj.ToString() << std::endl;
|
||||
std::cout << "id:" << jsonObj["id"].ToString() << std::endl;
|
||||
std::cout << "is_vip:" << jsonObj["member_info"]["is_vip"].ToString() << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
15
sop-sdk/sdk-c++/privateEx.pem
Normal file
15
sop-sdk/sdk-c++/privateEx.pem
Normal file
@@ -0,0 +1,15 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICXAIBAAKBgQCHJlAPN+1dCbgc3HiahQkT2W/skecGWOCkSX4CPvEc8oIk6544
|
||||
xihEwShHnfrapiQdF2fndv5agrhg4FyOHheST42L5MnCk+4Km+mWm5GDvmFS7Sa2
|
||||
aZ5o3regY0MUoJ7D74dYjE3UYFuTujAXiXjGpAwa9qOcKotov5LCkSfUeQIDAQAB
|
||||
AoGAB1cyw8LYRQSHQCUO9Wiaq730jPNHSrJW4EGAIz/XMYjv/fCgx0lnDEX4CbzI
|
||||
UGoz/bME4R721YRyXoutJ0h14/cGrt/TEn/TMI0xnISzJHr8VSlyBkQEdfO/W3LO
|
||||
qjs/UYq2Bz4+kJROJHreM+7d5hiIWLzLBlyI8cSU92ySmHECQQDwju2SoRu88kQP
|
||||
1qr4seZyKQa8DHTVyCoa6LtPLXyJsdgWgY4KyqJHwMUumEC2Zhhu833CR0ZXbfta
|
||||
uQDmwAVJAkEAj9M225jrPasaD5vPO7thxtEqgV4F/ZyNKH0Z8bDH27KaKkQ+8GMt
|
||||
kxwKVckZXs2bMvg/6tCiDZkWAxawNrvFsQJBANmTrPWOmpQPW9gnhYRjA9gFm33C
|
||||
lno2DT9BeQloTtgL7zKMA3lnRdg4VyCJvR48waS4vupVpR228D1iT5pl22ECQF1M
|
||||
JUzkcM0rPheb+h2EW1QOgWU0Keyvbj4ykO7gv3T78dezN6TWoUzJpsapUiTWeXPh
|
||||
6AyZ1FW/1bChOiP3QLECQGAbObmsYlN0bjzPYChwWYeYjErXuv51a44GZCNWinFw
|
||||
GGiHU9ZAqF8RzmBVW4htwj0j/Yry/V1Sp0uoP0zu3uA=
|
||||
-----END RSA PRIVATE KEY-----
|
3
sop-sdk/sdk-c++/readme.md
Normal file
3
sop-sdk/sdk-c++/readme.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# SDK for C++
|
||||
|
||||
使用方式见:main.cpp
|
17
sop-sdk/sdk-c++/request/BaseRequest.cpp
Normal file
17
sop-sdk/sdk-c++/request/BaseRequest.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
#include "BaseRequest.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
|
||||
vector<FileInfo> BaseRequest::getFiles() {
|
||||
return this->files;
|
||||
}
|
||||
|
||||
void BaseRequest::addFile(const FileInfo& filepath) {
|
||||
this->files.push_back(filepath);
|
||||
}
|
||||
|
||||
void BaseRequest::setFiles(vector<FileInfo> files) {
|
||||
this->files = std::move(files);
|
||||
}
|
60
sop-sdk/sdk-c++/request/BaseRequest.h
Normal file
60
sop-sdk/sdk-c++/request/BaseRequest.h
Normal file
@@ -0,0 +1,60 @@
|
||||
#ifndef SDK_CXX_BASEREQUEST_H
|
||||
#define SDK_CXX_BASEREQUEST_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "../common/RequestType.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct FileInfo {
|
||||
/** 表单名称 */
|
||||
string name;
|
||||
/** 文件完整路径 */
|
||||
string filepath;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 请求类基类,其它请求类需要继承这个类
|
||||
*/
|
||||
class BaseRequest {
|
||||
public:
|
||||
|
||||
/**
|
||||
* 业务参数
|
||||
*/
|
||||
map<string, string> bizModel;
|
||||
|
||||
/**
|
||||
* 定义接口名称
|
||||
* @return 返回接口名称
|
||||
*/
|
||||
virtual string getMethod() = 0;
|
||||
|
||||
/**
|
||||
* 定义接口版本号
|
||||
* @return 返回版本号
|
||||
*/
|
||||
virtual string getVersion() = 0;
|
||||
|
||||
/**
|
||||
* 定义请求方式
|
||||
* @return 返回请求方式
|
||||
*/
|
||||
virtual RequestType getRequestType() = 0;
|
||||
|
||||
vector<FileInfo> getFiles();
|
||||
|
||||
void setFiles(vector<FileInfo> files);
|
||||
|
||||
private:
|
||||
vector<FileInfo> files = {};
|
||||
|
||||
void addFile(const FileInfo& filepath);
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif //SDK_CXX_BASEREQUEST_H
|
29
sop-sdk/sdk-c++/request/MemberInfoGetRequest.hpp
Normal file
29
sop-sdk/sdk-c++/request/MemberInfoGetRequest.hpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#ifndef SDK_CXX_MEMBERINFOGETREQUEST_HPP
|
||||
#define SDK_CXX_MEMBERINFOGETREQUEST_HPP
|
||||
|
||||
#include <string>
|
||||
#include "BaseRequest.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class MemberInfoGetRequest : public BaseRequest {
|
||||
|
||||
public:
|
||||
string getMethod() override;
|
||||
string getVersion() override;
|
||||
RequestType getRequestType() override;
|
||||
};
|
||||
|
||||
string MemberInfoGetRequest::getMethod() {
|
||||
return "member.info.get";
|
||||
}
|
||||
|
||||
string MemberInfoGetRequest::getVersion() {
|
||||
return "1.0";
|
||||
}
|
||||
|
||||
RequestType MemberInfoGetRequest::getRequestType() {
|
||||
return GET;
|
||||
}
|
||||
|
||||
#endif //SDK_CXX_MEMBERINFOGETREQUEST_HPP
|
3523
sop-sdk/sdk-c++/thirdparty/CJsonObject/CJsonObject.cpp
vendored
Normal file
3523
sop-sdk/sdk-c++/thirdparty/CJsonObject/CJsonObject.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
156
sop-sdk/sdk-c++/thirdparty/CJsonObject/CJsonObject.hpp
vendored
Normal file
156
sop-sdk/sdk-c++/thirdparty/CJsonObject/CJsonObject.hpp
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
/*******************************************************************************
|
||||
* Project: neb
|
||||
* @file CJsonObject.hpp
|
||||
* @brief Json
|
||||
* @author bwarliao
|
||||
* @date: 2014-7-16
|
||||
* @note
|
||||
* Modify history:
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef CJSONOBJECT_HPP_
|
||||
#define CJSONOBJECT_HPP_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include "cJSON.h"
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
namespace neb
|
||||
{
|
||||
|
||||
class CJsonObject
|
||||
{
|
||||
public: // method of ordinary json object or json array
|
||||
CJsonObject();
|
||||
CJsonObject(const std::string& strJson);
|
||||
CJsonObject(const CJsonObject* pJsonObject);
|
||||
CJsonObject(const CJsonObject& oJsonObject);
|
||||
virtual ~CJsonObject();
|
||||
|
||||
CJsonObject& operator=(const CJsonObject& oJsonObject);
|
||||
bool operator==(const CJsonObject& oJsonObject) const;
|
||||
bool Parse(const std::string& strJson);
|
||||
void Clear();
|
||||
bool IsEmpty() const;
|
||||
bool IsArray() const;
|
||||
std::string ToString() const;
|
||||
std::string ToFormattedString() const;
|
||||
const std::string& GetErrMsg() const
|
||||
{
|
||||
return(m_strErrMsg);
|
||||
}
|
||||
|
||||
public: // method of ordinary json object
|
||||
bool AddEmptySubObject(const std::string& strKey);
|
||||
bool AddEmptySubArray(const std::string& strKey);
|
||||
bool GetKey(std::string& strKey);
|
||||
void ResetTraversing();
|
||||
CJsonObject& operator[](const std::string& strKey);
|
||||
std::string operator()(const std::string& strKey) const;
|
||||
bool Get(const std::string& strKey, CJsonObject& oJsonObject) const;
|
||||
bool Get(const std::string& strKey, std::string& strValue) const;
|
||||
bool Get(const std::string& strKey, int32& iValue) const;
|
||||
bool Get(const std::string& strKey, uint32& uiValue) const;
|
||||
bool Get(const std::string& strKey, int64& llValue) const;
|
||||
bool Get(const std::string& strKey, uint64& ullValue) const;
|
||||
bool Get(const std::string& strKey, bool& bValue) const;
|
||||
bool Get(const std::string& strKey, float& fValue) const;
|
||||
bool Get(const std::string& strKey, double& dValue) const;
|
||||
bool IsNull(const std::string& strKey) const;
|
||||
bool Add(const std::string& strKey, const CJsonObject& oJsonObject);
|
||||
bool Add(const std::string& strKey, const std::string& strValue);
|
||||
bool Add(const std::string& strKey, int32 iValue);
|
||||
bool Add(const std::string& strKey, uint32 uiValue);
|
||||
bool Add(const std::string& strKey, int64 llValue);
|
||||
bool Add(const std::string& strKey, uint64 ullValue);
|
||||
bool Add(const std::string& strKey, bool bValue, bool bValueAgain);
|
||||
bool Add(const std::string& strKey, float fValue);
|
||||
bool Add(const std::string& strKey, double dValue);
|
||||
bool AddNull(const std::string& strKey); // add null like this: "key":null
|
||||
bool Delete(const std::string& strKey);
|
||||
bool Replace(const std::string& strKey, const CJsonObject& oJsonObject);
|
||||
bool Replace(const std::string& strKey, const std::string& strValue);
|
||||
bool Replace(const std::string& strKey, int32 iValue);
|
||||
bool Replace(const std::string& strKey, uint32 uiValue);
|
||||
bool Replace(const std::string& strKey, int64 llValue);
|
||||
bool Replace(const std::string& strKey, uint64 ullValue);
|
||||
bool Replace(const std::string& strKey, bool bValue, bool bValueAgain);
|
||||
bool Replace(const std::string& strKey, float fValue);
|
||||
bool Replace(const std::string& strKey, double dValue);
|
||||
bool ReplaceWithNull(const std::string& strKey); // replace value with null
|
||||
|
||||
public: // method of json array
|
||||
int GetArraySize();
|
||||
CJsonObject& operator[](unsigned int uiWhich);
|
||||
std::string operator()(unsigned int uiWhich) const;
|
||||
bool Get(int iWhich, CJsonObject& oJsonObject) const;
|
||||
bool Get(int iWhich, std::string& strValue) const;
|
||||
bool Get(int iWhich, int32& iValue) const;
|
||||
bool Get(int iWhich, uint32& uiValue) const;
|
||||
bool Get(int iWhich, int64& llValue) const;
|
||||
bool Get(int iWhich, uint64& ullValue) const;
|
||||
bool Get(int iWhich, bool& bValue) const;
|
||||
bool Get(int iWhich, float& fValue) const;
|
||||
bool Get(int iWhich, double& dValue) const;
|
||||
bool IsNull(int iWhich) const;
|
||||
bool Add(const CJsonObject& oJsonObject);
|
||||
bool Add(const std::string& strValue);
|
||||
bool Add(int32 iValue);
|
||||
bool Add(uint32 uiValue);
|
||||
bool Add(int64 llValue);
|
||||
bool Add(uint64 ullValue);
|
||||
bool Add(int iAnywhere, bool bValue);
|
||||
bool Add(float fValue);
|
||||
bool Add(double dValue);
|
||||
bool AddNull(); // add a null value
|
||||
bool AddAsFirst(const CJsonObject& oJsonObject);
|
||||
bool AddAsFirst(const std::string& strValue);
|
||||
bool AddAsFirst(int32 iValue);
|
||||
bool AddAsFirst(uint32 uiValue);
|
||||
bool AddAsFirst(int64 llValue);
|
||||
bool AddAsFirst(uint64 ullValue);
|
||||
bool AddAsFirst(int iAnywhere, bool bValue);
|
||||
bool AddAsFirst(float fValue);
|
||||
bool AddAsFirst(double dValue);
|
||||
bool AddNullAsFirst(); // add a null value
|
||||
bool Delete(int iWhich);
|
||||
bool Replace(int iWhich, const CJsonObject& oJsonObject);
|
||||
bool Replace(int iWhich, const std::string& strValue);
|
||||
bool Replace(int iWhich, int32 iValue);
|
||||
bool Replace(int iWhich, uint32 uiValue);
|
||||
bool Replace(int iWhich, int64 llValue);
|
||||
bool Replace(int iWhich, uint64 ullValue);
|
||||
bool Replace(int iWhich, bool bValue, bool bValueAgain);
|
||||
bool Replace(int iWhich, float fValue);
|
||||
bool Replace(int iWhich, double dValue);
|
||||
bool ReplaceWithNull(int iWhich); // replace with a null value
|
||||
|
||||
private:
|
||||
CJsonObject(cJSON* pJsonData);
|
||||
|
||||
private:
|
||||
cJSON* m_pJsonData;
|
||||
cJSON* m_pExternJsonDataRef;
|
||||
cJSON* m_pKeyTravers;
|
||||
std::string m_strErrMsg;
|
||||
std::map<unsigned int, CJsonObject*> m_mapJsonArrayRef;
|
||||
std::map<std::string, CJsonObject*> m_mapJsonObjectRef;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* CJSONHELPER_HPP_ */
|
1091
sop-sdk/sdk-c++/thirdparty/CJsonObject/cJSON.c
vendored
Normal file
1091
sop-sdk/sdk-c++/thirdparty/CJsonObject/cJSON.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
151
sop-sdk/sdk-c++/thirdparty/CJsonObject/cJSON.h
vendored
Normal file
151
sop-sdk/sdk-c++/thirdparty/CJsonObject/cJSON.h
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
Copyright (c) 2009 Dave Gamble
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef cJSON__h
|
||||
#define cJSON__h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef int int32;
|
||||
typedef unsigned int uint32;
|
||||
#ifndef _WIN32
|
||||
#if __WORDSIZE == 64
|
||||
typedef long int64;
|
||||
typedef unsigned long uint64;
|
||||
#endif
|
||||
#else
|
||||
typedef long long int64;
|
||||
typedef unsigned long long uint64;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* cJSON Types: */
|
||||
#define cJSON_False 0
|
||||
#define cJSON_True 1
|
||||
#define cJSON_NULL 2
|
||||
#define cJSON_Int 3
|
||||
#define cJSON_Double 4
|
||||
#define cJSON_String 5
|
||||
#define cJSON_Array 6
|
||||
#define cJSON_Object 7
|
||||
|
||||
#define cJSON_IsReference 256
|
||||
|
||||
/* The cJSON structure: */
|
||||
typedef struct cJSON
|
||||
{
|
||||
struct cJSON *next, *prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
|
||||
struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
|
||||
|
||||
int type; /* The type of the item, as above. */
|
||||
|
||||
char *valuestring; /* The item's string, if type==cJSON_String */
|
||||
int64 valueint; /* The item's number, if type==cJSON_Number */
|
||||
double valuedouble; /* The item's number, if type==cJSON_Number */
|
||||
int sign; /* sign of valueint, 1(unsigned), -1(signed) */
|
||||
|
||||
char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
|
||||
} cJSON;
|
||||
|
||||
typedef struct cJSON_Hooks
|
||||
{
|
||||
void *(*malloc_fn)(size_t sz);
|
||||
void (*free_fn)(void *ptr);
|
||||
} cJSON_Hooks;
|
||||
|
||||
/* Supply malloc, realloc and free functions to cJSON */
|
||||
extern void cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||
|
||||
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
|
||||
extern cJSON *cJSON_Parse(const char *value);
|
||||
/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
|
||||
extern char *cJSON_Print(cJSON *item);
|
||||
/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
|
||||
extern char *cJSON_PrintUnformatted(cJSON *item);
|
||||
/* Delete a cJSON entity and all subentities. */
|
||||
extern void cJSON_Delete(cJSON *c);
|
||||
|
||||
/* Returns the number of items in an array (or object). */
|
||||
extern int cJSON_GetArraySize(cJSON *array);
|
||||
/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
|
||||
extern cJSON *cJSON_GetArrayItem(cJSON *array, int item);
|
||||
/* Get item "string" from object. Case insensitive. */
|
||||
extern cJSON *cJSON_GetObjectItem(cJSON *object, const char *string);
|
||||
|
||||
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
|
||||
extern const char *cJSON_GetErrorPtr();
|
||||
|
||||
/* These calls create a cJSON item of the appropriate type. */
|
||||
extern cJSON *cJSON_CreateNull();
|
||||
extern cJSON *cJSON_CreateTrue();
|
||||
extern cJSON *cJSON_CreateFalse();
|
||||
extern cJSON *cJSON_CreateBool(int b);
|
||||
extern cJSON *cJSON_CreateDouble(double num, int sign);
|
||||
extern cJSON *cJSON_CreateInt(uint64 num, int sign);
|
||||
extern cJSON *cJSON_CreateString(const char *string);
|
||||
extern cJSON *cJSON_CreateArray();
|
||||
extern cJSON *cJSON_CreateObject();
|
||||
|
||||
/* These utilities create an Array of count items. */
|
||||
extern cJSON *cJSON_CreateIntArray(int *numbers, int sign, int count);
|
||||
extern cJSON *cJSON_CreateFloatArray(float *numbers, int count);
|
||||
extern cJSON *cJSON_CreateDoubleArray(double *numbers, int count);
|
||||
extern cJSON *cJSON_CreateStringArray(const char **strings, int count);
|
||||
|
||||
/* Append item to the specified array/object. */
|
||||
extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||
extern void cJSON_AddItemToArrayHead(cJSON *array, cJSON *item); /* add by Bwar on 2015-01-28 */
|
||||
extern void cJSON_AddItemToObject(cJSON *object, const char *string,
|
||||
cJSON *item);
|
||||
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
|
||||
extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
||||
extern void cJSON_AddItemReferenceToObject(cJSON *object, const char *string,
|
||||
cJSON *item);
|
||||
|
||||
/* Remove/Detatch items from Arrays/Objects. */
|
||||
extern cJSON *cJSON_DetachItemFromArray(cJSON *array, int which);
|
||||
extern void cJSON_DeleteItemFromArray(cJSON *array, int which);
|
||||
extern cJSON *cJSON_DetachItemFromObject(cJSON *object, const char *string);
|
||||
extern void cJSON_DeleteItemFromObject(cJSON *object, const char *string);
|
||||
|
||||
/* Update array items. */
|
||||
extern void cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
|
||||
extern void cJSON_ReplaceItemInObject(cJSON *object, const char *string,
|
||||
cJSON *newitem);
|
||||
|
||||
#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
|
||||
#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
|
||||
#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
|
||||
#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
|
||||
#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
103
sop-sdk/sdk-c++/thirdparty/base64/base64.cpp
vendored
Normal file
103
sop-sdk/sdk-c++/thirdparty/base64/base64.cpp
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
//
|
||||
// base64.cpp
|
||||
// CPPWork
|
||||
//
|
||||
// Created by cocoa on 16/8/5.
|
||||
// Copyright © 2016年 cc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "base64.h"
|
||||
|
||||
static const std::string base64_chars =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
|
||||
|
||||
static inline bool is_base64(unsigned char c) {
|
||||
return (isalnum(c) || (c == '+') || (c == '/'));
|
||||
}
|
||||
|
||||
std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
|
||||
std::string ret;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
unsigned char char_array_3[3];
|
||||
unsigned char char_array_4[4];
|
||||
|
||||
while (in_len--) {
|
||||
char_array_3[i++] = *(bytes_to_encode++);
|
||||
if (i == 3) {
|
||||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
||||
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
||||
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||
|
||||
for(i = 0; (i <4) ; i++)
|
||||
ret += base64_chars[char_array_4[i]];
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (i)
|
||||
{
|
||||
for(j = i; j < 3; j++)
|
||||
char_array_3[j] = '\0';
|
||||
|
||||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
||||
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
||||
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||
|
||||
for (j = 0; (j < i + 1); j++)
|
||||
ret += base64_chars[char_array_4[j]];
|
||||
|
||||
while((i++ < 3))
|
||||
ret += '=';
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
std::string base64_decode(std::string const& encoded_string) {
|
||||
int in_len = encoded_string.size();
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int in_ = 0;
|
||||
unsigned char char_array_4[4], char_array_3[3];
|
||||
std::string ret;
|
||||
|
||||
while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
|
||||
char_array_4[i++] = encoded_string[in_]; in_++;
|
||||
if (i ==4) {
|
||||
for (i = 0; i <4; i++)
|
||||
char_array_4[i] = base64_chars.find(char_array_4[i]);
|
||||
|
||||
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||
|
||||
for (i = 0; (i < 3); i++)
|
||||
ret += char_array_3[i];
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (i) {
|
||||
for (j = i; j <4; j++)
|
||||
char_array_4[j] = 0;
|
||||
|
||||
for (j = 0; j <4; j++)
|
||||
char_array_4[j] = base64_chars.find(char_array_4[j]);
|
||||
|
||||
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||
|
||||
for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
10
sop-sdk/sdk-c++/thirdparty/base64/base64.h
vendored
Executable file
10
sop-sdk/sdk-c++/thirdparty/base64/base64.h
vendored
Executable file
@@ -0,0 +1,10 @@
|
||||
#ifndef base64_h
|
||||
#define base64_h
|
||||
|
||||
#include <string>
|
||||
|
||||
std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len);
|
||||
std::string base64_decode(std::string const& encoded_string);
|
||||
|
||||
|
||||
#endif /* base64_h */
|
5
sop-sdk/sdk-rust/readme.md
Normal file
5
sop-sdk/sdk-rust/readme.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# sdk for rust
|
||||
|
||||
使用方式见:`sdk-test/src/main.rs`
|
||||
|
||||
封装步骤参考 `sdk/src/request/memberinfoget.rs` 和 `sdk/src/response/memberinfoget.rs`
|
1
sop-sdk/sdk-rust/sdk-test/.gitignore
vendored
Normal file
1
sop-sdk/sdk-rust/sdk-test/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
1558
sop-sdk/sdk-rust/sdk-test/Cargo.lock
generated
Normal file
1558
sop-sdk/sdk-rust/sdk-test/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
11
sop-sdk/sdk-rust/sdk-test/Cargo.toml
Normal file
11
sop-sdk/sdk-rust/sdk-test/Cargo.toml
Normal file
@@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "sdk-test"
|
||||
version = "0.1.0"
|
||||
authors = ["thc"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
# 依赖sdk模块
|
||||
sdk = { path = "../sdk"}
|
1
sop-sdk/sdk-rust/sdk-test/aa.txt
Normal file
1
sop-sdk/sdk-rust/sdk-test/aa.txt
Normal file
@@ -0,0 +1 @@
|
||||
hello你好123
|
1
sop-sdk/sdk-rust/sdk-test/bb.txt
Normal file
1
sop-sdk/sdk-rust/sdk-test/bb.txt
Normal file
@@ -0,0 +1 @@
|
||||
文件bb的内容
|
76
sop-sdk/sdk-rust/sdk-test/src/main.rs
Normal file
76
sop-sdk/sdk-rust/sdk-test/src/main.rs
Normal file
@@ -0,0 +1,76 @@
|
||||
extern crate sdk;
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use sdk::client::OpenClient;
|
||||
use sdk::http::UploadFile;
|
||||
use sdk::request::BaseRequest;
|
||||
use sdk::request::memberinfoget::MemberInfoGetRequest;
|
||||
use sdk::response::memberinfoget::MemberInfoGetResponse;
|
||||
use std::env;
|
||||
|
||||
fn main() {
|
||||
// 创建请求客户端
|
||||
let client = OpenClient {
|
||||
// 应用ID
|
||||
app_id: "2020051325943082302177280",
|
||||
// 应用私钥
|
||||
private_key: "MIICXAIBAAKBgQCHJlAPN+1dCbgc3HiahQkT2W/skecGWOCkSX4CPvEc8oIk6544\nxihEwShHnfrapiQdF2fndv5agrhg4FyOHheST42L5MnCk+4Km+mWm5GDvmFS7Sa2\naZ5o3regY0MUoJ7D74dYjE3UYFuTujAXiXjGpAwa9qOcKotov5LCkSfUeQIDAQAB\nAoGAB1cyw8LYRQSHQCUO9Wiaq730jPNHSrJW4EGAIz/XMYjv/fCgx0lnDEX4CbzI\nUGoz/bME4R721YRyXoutJ0h14/cGrt/TEn/TMI0xnISzJHr8VSlyBkQEdfO/W3LO\nqjs/UYq2Bz4+kJROJHreM+7d5hiIWLzLBlyI8cSU92ySmHECQQDwju2SoRu88kQP\n1qr4seZyKQa8DHTVyCoa6LtPLXyJsdgWgY4KyqJHwMUumEC2Zhhu833CR0ZXbfta\nuQDmwAVJAkEAj9M225jrPasaD5vPO7thxtEqgV4F/ZyNKH0Z8bDH27KaKkQ+8GMt\nkxwKVckZXs2bMvg/6tCiDZkWAxawNrvFsQJBANmTrPWOmpQPW9gnhYRjA9gFm33C\nlno2DT9BeQloTtgL7zKMA3lnRdg4VyCJvR48waS4vupVpR228D1iT5pl22ECQF1M\nJUzkcM0rPheb+h2EW1QOgWU0Keyvbj4ykO7gv3T78dezN6TWoUzJpsapUiTWeXPh\n6AyZ1FW/1bChOiP3QLECQGAbObmsYlN0bjzPYChwWYeYjErXuv51a44GZCNWinFw\nGGiHU9ZAqF8RzmBVW4htwj0j/Yry/V1Sp0uoP0zu3uA=",
|
||||
// 请求地址
|
||||
url: "http://localhost:7071/prod/gw68uy85",
|
||||
};
|
||||
// 业务参数
|
||||
let mut biz_model = HashMap::new();
|
||||
biz_model.insert("name", "jim".to_string());
|
||||
biz_model.insert("address", "xx".to_string());
|
||||
biz_model.insert("age", "22".to_string());
|
||||
|
||||
let mut files = vec![];
|
||||
|
||||
// 添加上传文件
|
||||
/*let mod_dir = env::current_dir().unwrap().display().to_string();
|
||||
files = vec![
|
||||
UploadFile { name:"file1", path: format!("{}/{}", &mod_dir, "aa.txt")},
|
||||
UploadFile { name:"file2", path: format!("{}/{}", &mod_dir, "bb.txt") },
|
||||
];*/
|
||||
|
||||
|
||||
// 创建请求,设置业务参数
|
||||
let request = MemberInfoGetRequest {
|
||||
base: BaseRequest { biz_model: biz_model, files: files }
|
||||
};
|
||||
|
||||
// 发送请求
|
||||
let response:MemberInfoGetResponse = client.execute(request);
|
||||
|
||||
// 成功
|
||||
if response.sub_code.len() == 0 {
|
||||
println!("resp:{:#?}", response)
|
||||
} else {
|
||||
println!("error:{:#?}", response)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use sdk::sign::{HashType, SignUtil};
|
||||
use sdk::http::HttpTool;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
let content = "123";
|
||||
let private_key = "MIICXAIBAAKBgQCHJlAPN+1dCbgc3HiahQkT2W/skecGWOCkSX4CPvEc8oIk6544\nxihEwShHnfrapiQdF2fndv5agrhg4FyOHheST42L5MnCk+4Km+mWm5GDvmFS7Sa2\naZ5o3regY0MUoJ7D74dYjE3UYFuTujAXiXjGpAwa9qOcKotov5LCkSfUeQIDAQAB\nAoGAB1cyw8LYRQSHQCUO9Wiaq730jPNHSrJW4EGAIz/XMYjv/fCgx0lnDEX4CbzI\nUGoz/bME4R721YRyXoutJ0h14/cGrt/TEn/TMI0xnISzJHr8VSlyBkQEdfO/W3LO\nqjs/UYq2Bz4+kJROJHreM+7d5hiIWLzLBlyI8cSU92ySmHECQQDwju2SoRu88kQP\n1qr4seZyKQa8DHTVyCoa6LtPLXyJsdgWgY4KyqJHwMUumEC2Zhhu833CR0ZXbfta\nuQDmwAVJAkEAj9M225jrPasaD5vPO7thxtEqgV4F/ZyNKH0Z8bDH27KaKkQ+8GMt\nkxwKVckZXs2bMvg/6tCiDZkWAxawNrvFsQJBANmTrPWOmpQPW9gnhYRjA9gFm33C\nlno2DT9BeQloTtgL7zKMA3lnRdg4VyCJvR48waS4vupVpR228D1iT5pl22ECQF1M\nJUzkcM0rPheb+h2EW1QOgWU0Keyvbj4ykO7gv3T78dezN6TWoUzJpsapUiTWeXPh\n6AyZ1FW/1bChOiP3QLECQGAbObmsYlN0bjzPYChwWYeYjErXuv51a44GZCNWinFw\nGGiHU9ZAqF8RzmBVW4htwj0j/Yry/V1Sp0uoP0zu3uA=";
|
||||
let sign = SignUtil::rsa_sign(content, private_key, HashType::Sha256);
|
||||
println!("sign:{}", sign);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_http() {
|
||||
let mut map = HashMap::new();
|
||||
map.insert("aaa", "bbb");
|
||||
let response = HttpTool::get("http://baidu.com", &map, &HashMap::new());
|
||||
println!("response:{:#?}", response);
|
||||
}
|
||||
|
||||
}
|
1
sop-sdk/sdk-rust/sdk/.gitignore
vendored
Normal file
1
sop-sdk/sdk-rust/sdk/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
1551
sop-sdk/sdk-rust/sdk/Cargo.lock
generated
Normal file
1551
sop-sdk/sdk-rust/sdk/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
23
sop-sdk/sdk-rust/sdk/Cargo.toml
Normal file
23
sop-sdk/sdk-rust/sdk/Cargo.toml
Normal file
@@ -0,0 +1,23 @@
|
||||
[package]
|
||||
name = "sdk"
|
||||
version = "0.1.0"
|
||||
authors = ["thc"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
# 时间api
|
||||
chrono = "0.4"
|
||||
# rsa库
|
||||
rsa = "0.3.0"
|
||||
# 加密库
|
||||
rust-crypto = "^0.2"
|
||||
# base64库
|
||||
base64 = "0.12.3"
|
||||
# HTTP客户端 https://github.com/seanmonstar/reqwest
|
||||
reqwest = { version = "0.10", features = ["blocking", "json"] }
|
||||
tokio = { version = "0.2", features = ["full"] }
|
||||
# 处理json https://serde.rs/
|
||||
serde = { version = "1.0.114", features = ["derive"] }
|
||||
serde_json = "1.0.56"
|
112
sop-sdk/sdk-rust/sdk/src/client.rs
Normal file
112
sop-sdk/sdk-rust/sdk/src/client.rs
Normal file
@@ -0,0 +1,112 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use chrono::Local;
|
||||
use serde::de::DeserializeOwned;
|
||||
|
||||
use crate::http::HttpTool;
|
||||
use crate::request::{Request, RequestType};
|
||||
use crate::sign::{SignType, SignUtil};
|
||||
use serde_json::Value;
|
||||
|
||||
pub struct OpenClient {
|
||||
/// 应用ID
|
||||
pub app_id: &'static str,
|
||||
/// 应用私钥,PKCS#1
|
||||
pub private_key: &'static str,
|
||||
/// 请求url
|
||||
pub url: &'static str,
|
||||
}
|
||||
|
||||
impl OpenClient {
|
||||
|
||||
/// 发送请求
|
||||
///
|
||||
/// - request: 请求对象
|
||||
///
|
||||
/// 返回结果
|
||||
pub fn execute<T: DeserializeOwned>(&self, request: impl Request) -> T {
|
||||
self.execute_token(request, "")
|
||||
}
|
||||
|
||||
///发送请求
|
||||
///
|
||||
/// - request: 请求对象
|
||||
/// - token:token
|
||||
///
|
||||
/// 返回结果
|
||||
pub fn execute_token<T: DeserializeOwned>(&self, request: impl Request, token: &'static str) -> T {
|
||||
let struct_obj: T;
|
||||
|
||||
let request_type = request.get_request_type();
|
||||
let headers = &OpenClient::get_default_headers();
|
||||
let all_params = &self.build_params(&request, token);
|
||||
|
||||
if request.get_base().files.len() > 0 {
|
||||
let base = request.get_base();
|
||||
let files = &base.files;
|
||||
let resp = HttpTool::post_file(self.url, all_params, files, headers);
|
||||
struct_obj = self.parse_response(resp, &request);
|
||||
} else {
|
||||
match request_type {
|
||||
RequestType::Get => {
|
||||
let resp = HttpTool::get(self.url, all_params, headers);
|
||||
struct_obj = self.parse_response(resp, &request);
|
||||
}
|
||||
RequestType::PostForm => {
|
||||
let resp = HttpTool::post_form(self.url, all_params, headers);
|
||||
struct_obj = self.parse_response(resp, &request);
|
||||
}
|
||||
RequestType::PostJson => {
|
||||
let resp = HttpTool::post_json(self.url, all_params, headers);
|
||||
struct_obj = self.parse_response(resp, &request);
|
||||
}
|
||||
RequestType::PostFile => {
|
||||
let base = request.get_base();
|
||||
let files = &base.files;
|
||||
let resp = HttpTool::post_file(self.url, all_params, files, headers);
|
||||
struct_obj = self.parse_response(resp, &request);
|
||||
}
|
||||
}
|
||||
}
|
||||
struct_obj
|
||||
}
|
||||
|
||||
fn get_default_headers() -> HashMap<&'static str, &'static str> {
|
||||
let mut headers = HashMap::new();
|
||||
headers.insert("Accept-Encoding", "identity");
|
||||
headers
|
||||
}
|
||||
|
||||
fn parse_response<T: DeserializeOwned>(&self, resp: reqwest::blocking::Response, request: &impl Request) -> T {
|
||||
let root: HashMap<String, Value> = resp.json().expect("error");
|
||||
request.parse_response(root)
|
||||
}
|
||||
|
||||
/// 构建请求参数
|
||||
fn build_params(&self, request: &impl Request, token: &str) -> HashMap<&'static str, String> {
|
||||
let method = request.get_method();
|
||||
let version = request.get_version();
|
||||
|
||||
let mut all_params = HashMap::new();
|
||||
all_params.insert("app_id", self.app_id.to_string());
|
||||
all_params.insert("method", method.to_string());
|
||||
all_params.insert("charset", "UTF-8".to_string());
|
||||
all_params.insert("timestamp", Local::now().format("%Y-%m-%d %H:%M:%S").to_string());
|
||||
all_params.insert("version", version.to_string());
|
||||
|
||||
// 添加业务参数
|
||||
for entry in &request.get_base().biz_model {
|
||||
all_params.insert(entry.0, entry.1.to_string());
|
||||
}
|
||||
|
||||
if !token.is_empty() {
|
||||
all_params.insert("app_auth_token", token.to_string());
|
||||
}
|
||||
|
||||
// 创建签名
|
||||
let sign = SignUtil::create_sign(&all_params, self.private_key, SignType::RSA2);
|
||||
all_params.insert("sign", sign);
|
||||
|
||||
all_params
|
||||
}
|
||||
}
|
158
sop-sdk/sdk-rust/sdk/src/http.rs
Normal file
158
sop-sdk/sdk-rust/sdk/src/http.rs
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
Cargo.toml:
|
||||
|
||||
[dependencies]
|
||||
reqwest = { version = "0.10", features = ["blocking", "json"] }
|
||||
tokio = { version = "0.2", features = ["full"] }
|
||||
serde = { version = "1.0.114", features = ["derive"] }
|
||||
serde_json = "1.0.56"
|
||||
*/
|
||||
use std::collections::HashMap;
|
||||
|
||||
use reqwest::blocking::Response;
|
||||
use reqwest::header::{HeaderMap, HeaderValue, HeaderName};
|
||||
use std::str::FromStr;
|
||||
use serde::Serialize;
|
||||
|
||||
/// HTTP请求工具
|
||||
pub struct HttpTool {}
|
||||
|
||||
/// 上传文件对象
|
||||
pub struct UploadFile {
|
||||
/// 上传文件表单名称
|
||||
pub name: &'static str,
|
||||
/// 文件全路径
|
||||
pub path: String,
|
||||
}
|
||||
|
||||
impl HttpTool {
|
||||
|
||||
/// get请求
|
||||
///
|
||||
/// - url:请求url
|
||||
/// - params:请求参数
|
||||
/// - headers:请求header
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// let mut params = HashMap::new();
|
||||
/// params.insert("name", "Jim");
|
||||
/// params.insert("age", "12");
|
||||
/// let resp = HttpTool::get(url, ¶ms, &HashMap::new());
|
||||
/// ```
|
||||
/// return: Response对象
|
||||
pub fn get<T: Serialize + ?Sized>(url: &str, params: &T, headers: &HashMap<&str, &str>) -> Response {
|
||||
let client = reqwest::blocking::Client::new();
|
||||
let res = client
|
||||
.get(url)
|
||||
.query(params)
|
||||
.headers(super::http::HttpTool::get_headers_map(headers))
|
||||
.send();
|
||||
let resp = res.expect("request error");
|
||||
resp
|
||||
}
|
||||
|
||||
/// post模拟表单请求
|
||||
///
|
||||
/// - url:请求url
|
||||
/// - params:请求参数
|
||||
/// - headers:请求header
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// let mut params = HashMap::new();
|
||||
/// params.insert("name", "Jim");
|
||||
/// params.insert("age", "12");
|
||||
/// let resp = HttpTool::post_form(url, ¶ms, &HashMap::new());
|
||||
/// ```
|
||||
/// return: Response对象
|
||||
pub fn post_form<T: Serialize + ?Sized>(url: &str, params: &T, headers: &HashMap<&str, &str>) -> Response {
|
||||
let client = reqwest::blocking::Client::new();
|
||||
let res = client
|
||||
.post(url)
|
||||
.form(params)
|
||||
.headers(super::http::HttpTool::get_headers_map(headers))
|
||||
.send();
|
||||
let resp = res.expect("request error");
|
||||
resp
|
||||
}
|
||||
|
||||
/// post发送json
|
||||
///
|
||||
/// - url:请求url
|
||||
/// - params:请求参数
|
||||
/// - headers:请求header
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// let mut params = HashMap::new();
|
||||
/// params.insert("name", "Jim");
|
||||
/// params.insert("age", "12");
|
||||
/// let resp = HttpTool::post_json(url, ¶ms, &HashMap::new());
|
||||
/// ```
|
||||
/// return: Response对象
|
||||
pub fn post_json<T: Serialize + ?Sized>(url: &str, params: &T, headers: &HashMap<&str, &str>) -> Response {
|
||||
let client = reqwest::blocking::Client::new();
|
||||
let res = client
|
||||
.post(url)
|
||||
.json(params)
|
||||
.headers(super::http::HttpTool::get_headers_map(headers))
|
||||
.send();
|
||||
let resp = res.expect("request error");
|
||||
resp
|
||||
}
|
||||
|
||||
/// post上传文件
|
||||
///
|
||||
/// - url:请求url
|
||||
/// - params:请求参数
|
||||
/// - files:上传文件
|
||||
/// - headers:请求header
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// let mut params = HashMap::new();
|
||||
/// params.insert("name", String::from("Jim"));
|
||||
/// params.insert("age",String::from("12"));
|
||||
///
|
||||
/// // 设置上传文件
|
||||
/// let mut files = vec![
|
||||
/// UploadFile { name:"file1", path: String::from("/User/xx/aa.txt") },
|
||||
/// UploadFile { name:"file2", path: String::from("/User/xx/bb.txt") },
|
||||
/// ];
|
||||
///
|
||||
/// let resp = HttpTool::post_file(url, ¶ms, &files, &HashMap::new());
|
||||
/// ```
|
||||
/// return: Response对象
|
||||
pub fn post_file(url: &str, params: &HashMap<&str, String>, files: &Vec<UploadFile>, headers: &HashMap<&str, &str>) -> Response {
|
||||
let client = reqwest::blocking::Client::new();
|
||||
let mut form = reqwest::blocking::multipart::Form::new();
|
||||
// 添加普通参数
|
||||
for entry in params {
|
||||
form = form.text(entry.0.to_string(), entry.1.to_string());
|
||||
}
|
||||
// 添加文件
|
||||
for file in files {
|
||||
form = form.file(file.name.to_string(), file.path.to_string()).unwrap();
|
||||
}
|
||||
let res = client
|
||||
.post(url)
|
||||
.multipart(form)
|
||||
.headers(super::http::HttpTool::get_headers_map(headers))
|
||||
.send();
|
||||
let resp = res.expect("request error");
|
||||
resp
|
||||
}
|
||||
|
||||
fn get_headers_map(headers: &HashMap<&str, &str>) -> HeaderMap {
|
||||
let mut header_map = HeaderMap::new();
|
||||
for entry in headers {
|
||||
header_map.insert(HeaderName::from_str(entry.0).unwrap(), HeaderValue::from_str(entry.1).unwrap());
|
||||
}
|
||||
header_map
|
||||
}
|
||||
}
|
14
sop-sdk/sdk-rust/sdk/src/lib.rs
Normal file
14
sop-sdk/sdk-rust/sdk/src/lib.rs
Normal file
@@ -0,0 +1,14 @@
|
||||
pub mod sign;
|
||||
pub mod client;
|
||||
pub mod request;
|
||||
pub mod response;
|
||||
pub mod http;
|
||||
extern crate chrono;
|
||||
|
||||
/*#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert_eq!(2 + 2, 4);
|
||||
}
|
||||
}*/
|
26
sop-sdk/sdk-rust/sdk/src/request/memberinfoget.rs
Normal file
26
sop-sdk/sdk-rust/sdk/src/request/memberinfoget.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
use crate::request::{BaseRequest, Request, RequestType};
|
||||
|
||||
pub struct MemberInfoGetRequest {
|
||||
// 固定这么写
|
||||
pub base: BaseRequest
|
||||
}
|
||||
|
||||
impl Request for MemberInfoGetRequest {
|
||||
|
||||
fn get_method(&self) -> &str {
|
||||
"member.info.get"
|
||||
}
|
||||
|
||||
fn get_version(&self) -> &str {
|
||||
"1.0"
|
||||
}
|
||||
|
||||
fn get_request_type(&self) -> RequestType {
|
||||
RequestType::Get
|
||||
}
|
||||
|
||||
// 固定这么写
|
||||
fn get_base(&self) -> &BaseRequest {
|
||||
&self.base
|
||||
}
|
||||
}
|
45
sop-sdk/sdk-rust/sdk/src/request/mod.rs
Normal file
45
sop-sdk/sdk-rust/sdk/src/request/mod.rs
Normal file
@@ -0,0 +1,45 @@
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::http::UploadFile;
|
||||
use serde::de::DeserializeOwned;
|
||||
|
||||
pub mod memberinfoget;
|
||||
|
||||
pub enum RequestType {
|
||||
Get,
|
||||
PostJson,
|
||||
PostForm,
|
||||
PostFile,
|
||||
}
|
||||
|
||||
pub trait Request {
|
||||
/// 返回接口名称
|
||||
fn get_method(&self) -> &str;
|
||||
|
||||
/// 返回版本号
|
||||
fn get_version(&self) -> &str;
|
||||
|
||||
/// 返回请求方式
|
||||
fn get_request_type(&self) -> RequestType;
|
||||
|
||||
/// 返回base
|
||||
fn get_base(&self) -> &BaseRequest;
|
||||
|
||||
fn parse_response<T: DeserializeOwned>(&self, root: HashMap<String, Value>) -> T {
|
||||
let mut data = root.get("error_response");
|
||||
if data.is_none() {
|
||||
let data_name = self.get_method().replace(".", "_") + "_response";
|
||||
data = root.get(data_name.as_str());
|
||||
}
|
||||
let value = serde_json::to_value(data.unwrap()).unwrap();
|
||||
serde_json::from_value(value).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BaseRequest {
|
||||
pub biz_model: HashMap<&'static str, String>,
|
||||
pub files: Vec<UploadFile>
|
||||
}
|
36
sop-sdk/sdk-rust/sdk/src/response/memberinfoget.rs
Normal file
36
sop-sdk/sdk-rust/sdk/src/response/memberinfoget.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
extern crate serde;
|
||||
|
||||
use serde::{Deserialize};
|
||||
|
||||
// 响应参数
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct MemberInfoGetResponse {
|
||||
// ~~~ 固定部分 ~~~
|
||||
pub code: String,
|
||||
pub msg: String,
|
||||
// json中可能没有sub_code属性,因此需要加上 #[serde(default)]
|
||||
// 详见:https://serde.rs/field-attrs.html
|
||||
#[serde(default)]
|
||||
pub sub_code: String,
|
||||
#[serde(default)]
|
||||
pub sub_msg: String,
|
||||
// ~~~ 固定部分 ~~~
|
||||
|
||||
// 下面是业务字段
|
||||
#[serde(default)]
|
||||
pub id: u32,
|
||||
|
||||
#[serde(default)]
|
||||
pub name: String,
|
||||
|
||||
pub member_info: MemberInfo
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct MemberInfo {
|
||||
#[serde(default)]
|
||||
pub is_vip: i8,
|
||||
|
||||
#[serde(default)]
|
||||
pub vip_endtime: String
|
||||
}
|
1
sop-sdk/sdk-rust/sdk/src/response/mod.rs
Normal file
1
sop-sdk/sdk-rust/sdk/src/response/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod memberinfoget;
|
108
sop-sdk/sdk-rust/sdk/src/sign.rs
Normal file
108
sop-sdk/sdk-rust/sdk/src/sign.rs
Normal file
@@ -0,0 +1,108 @@
|
||||
extern crate rsa;
|
||||
extern crate crypto;
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use rsa::{RSAPrivateKey, PaddingScheme};
|
||||
use rsa::Hash;
|
||||
|
||||
use crypto::sha2::Sha256;
|
||||
use crypto::digest::Digest;
|
||||
use std::iter::repeat;
|
||||
|
||||
pub struct SignUtil {}
|
||||
|
||||
pub enum SignType {
|
||||
RSA,
|
||||
RSA2,
|
||||
}
|
||||
|
||||
pub enum HashType {
|
||||
Sha1,
|
||||
Sha256
|
||||
}
|
||||
|
||||
impl SignUtil {
|
||||
|
||||
pub fn create_sign(all_params: &HashMap<&str, String>, private_key: &str, sign_type: SignType) -> String {
|
||||
let content = SignUtil::get_sign_content(all_params);
|
||||
// println!("content:{}", content);
|
||||
let hash_type;
|
||||
match sign_type {
|
||||
SignType::RSA => hash_type = HashType::Sha1,
|
||||
SignType::RSA2 => hash_type = HashType::Sha256,
|
||||
}
|
||||
|
||||
SignUtil::rsa_sign(content.as_str(), private_key, hash_type)
|
||||
}
|
||||
|
||||
/// RSA签名
|
||||
///
|
||||
/// - content: 签名内容
|
||||
/// - private_key: 私钥,PKCS#1
|
||||
/// - hash_type: hash类型
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use sdk::sign::{SignUtil, HashType};
|
||||
///
|
||||
/// let content = "123";
|
||||
/// let private_key = "your private key";
|
||||
/// let sign = SignUtil::rsa_sign(content, private_key, HashType::Sha256);
|
||||
///
|
||||
/// println!("sign:{}", sign);
|
||||
/// ```
|
||||
/// return: 返回base64字符串
|
||||
pub fn rsa_sign(content: &str, private_key: &str, hash_type: HashType) -> String {
|
||||
// 格式化私钥
|
||||
let der_encoded = private_key
|
||||
.lines()
|
||||
.filter(|line| !line.starts_with("-"))
|
||||
.fold(String::new(), |mut data, line| {
|
||||
data.push_str(&line);
|
||||
data
|
||||
});
|
||||
let der_bytes = base64::decode(der_encoded).expect("failed to decode base64 content");
|
||||
// 获取私钥对象
|
||||
let private_key = RSAPrivateKey::from_pkcs1(&der_bytes).expect("failed to parse key");
|
||||
|
||||
// 创建一个Sha256对象
|
||||
let mut hasher = Sha256::new();
|
||||
// 对内容进行摘要
|
||||
hasher.input_str(content);
|
||||
// 将摘要结果保存到buf中
|
||||
let mut buf: Vec<u8> = repeat(0).take((hasher.output_bits()+7)/8).collect();
|
||||
hasher.result(&mut buf);
|
||||
|
||||
// 对摘要进行签名
|
||||
let hash;
|
||||
match hash_type {
|
||||
HashType::Sha1 => hash = Hash::SHA1,
|
||||
HashType::Sha256 => hash = Hash::SHA2_256
|
||||
}
|
||||
let sign_result = private_key.sign(PaddingScheme::PKCS1v15Sign {hash: Option::from(hash) }, &buf);
|
||||
// 签名结果转化为base64
|
||||
let vec = sign_result.expect("create sign error for base64");
|
||||
|
||||
base64::encode(vec)
|
||||
}
|
||||
|
||||
fn get_sign_content(all_params: &HashMap<&str, String>) -> String {
|
||||
let mut content = Vec::new();
|
||||
let keys = all_params.keys();
|
||||
let mut sorted_keys = Vec::new();
|
||||
for key in keys {
|
||||
sorted_keys.push(key);
|
||||
}
|
||||
// 排序
|
||||
sorted_keys.sort();
|
||||
for key in sorted_keys {
|
||||
let val = all_params.get(key);
|
||||
if val.is_some() {
|
||||
content.push(key.to_string() + "=" + val.unwrap());
|
||||
}
|
||||
}
|
||||
content.join("&")
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user