# Conflicts: # sop-admin/sop-admin-server/src/main/resources/public/index.html # sop-gateway/pom.xml # sop-website/pom.xml # sop-website/src/main/resources/application-dev.propertieseureka
commit
7f368be0b5
@ -0,0 +1,54 @@ |
||||
package com.gitee.sop.adminserver.api.service; |
||||
|
||||
import com.gitee.easyopen.annotation.Api; |
||||
import com.gitee.easyopen.annotation.ApiService; |
||||
import com.gitee.sop.adminserver.api.system.param.IspPageParam; |
||||
import com.gitee.sop.adminserver.api.system.param.IspResourceParam; |
||||
import com.gitee.sop.adminserver.common.CopyUtil; |
||||
import com.gitee.sop.adminserver.entity.IspResource; |
||||
import com.gitee.sop.adminserver.mapper.IspResourceMapper; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
||||
import javax.validation.constraints.NotNull; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* @author tanghc |
||||
*/ |
||||
@ApiService |
||||
public class ResourceApi { |
||||
|
||||
public static final byte RESOURCE_TYPE_SDK = (byte) 0; |
||||
|
||||
@Autowired |
||||
private IspResourceMapper ispResourceMapper; |
||||
|
||||
|
||||
@Api(name = "isp.sdk.list") |
||||
List<IspResource> list(IspPageParam param) { |
||||
return ispResourceMapper.list(param.toQuery()); |
||||
} |
||||
|
||||
@Api(name = "isp.sdk.add") |
||||
void addSdk(IspResourceParam param) { |
||||
IspResource ispResource = CopyUtil.copyBean(param, IspResource::new); |
||||
ispResource.setType(RESOURCE_TYPE_SDK); |
||||
ispResourceMapper.saveIgnoreNull(ispResource); |
||||
} |
||||
|
||||
@Api(name = "isp.sdk.update") |
||||
void updateSdk(IspResourceParam param) { |
||||
IspResource resource = ispResourceMapper.getById(param.getId()); |
||||
CopyUtil.copyProperties(param, resource); |
||||
ispResourceMapper.update(resource); |
||||
} |
||||
|
||||
@Api(name = "isp.sdk.delete") |
||||
void deleteSdk(@NotNull Long id) { |
||||
IspResource resource = ispResourceMapper.getById(id); |
||||
if (resource != null) { |
||||
ispResourceMapper.deleteById(id); |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,9 @@ |
||||
package com.gitee.sop.adminserver.api.system.param; |
||||
|
||||
import com.gitee.fastmybatis.core.query.param.PageParam; |
||||
|
||||
/** |
||||
* @author tanghc |
||||
*/ |
||||
public class IspPageParam extends PageParam { |
||||
} |
@ -0,0 +1,27 @@ |
||||
package com.gitee.sop.adminserver.api.system.param; |
||||
|
||||
import lombok.Data; |
||||
|
||||
|
||||
/** |
||||
* 表名:isp_resource |
||||
* 备注:ISP资源表 |
||||
* |
||||
* @author tanghc |
||||
*/ |
||||
@Data |
||||
public class IspResourceParam { |
||||
|
||||
private Long id; |
||||
|
||||
/** 资源名称, 数据库字段:name */ |
||||
private String name; |
||||
|
||||
private String version; |
||||
|
||||
/** 资源内容(URL), 数据库字段:content */ |
||||
private String content; |
||||
|
||||
private String extContent; |
||||
|
||||
} |
@ -0,0 +1,27 @@ |
||||
package com.gitee.sop.adminserver.api.system.result; |
||||
|
||||
import lombok.Data; |
||||
|
||||
|
||||
/** |
||||
* 表名:isp_resource |
||||
* 备注:ISP资源表 |
||||
* |
||||
* @author tanghc |
||||
*/ |
||||
@Data |
||||
public class IspResourceResult { |
||||
|
||||
private Long id; |
||||
|
||||
/** 资源名称, 数据库字段:name */ |
||||
private String name; |
||||
|
||||
private String version; |
||||
|
||||
/** 资源内容(URL), 数据库字段:content */ |
||||
private String content; |
||||
|
||||
private String extContent; |
||||
|
||||
} |
@ -0,0 +1,50 @@ |
||||
package com.gitee.sop.adminserver.entity; |
||||
|
||||
import lombok.Data; |
||||
|
||||
import javax.persistence.Column; |
||||
import javax.persistence.GeneratedValue; |
||||
import javax.persistence.GenerationType; |
||||
import javax.persistence.Id; |
||||
import javax.persistence.Table; |
||||
import java.util.Date; |
||||
|
||||
|
||||
/** |
||||
* 表名:isp_resource |
||||
* 备注:ISP资源表 |
||||
* |
||||
* @author tanghc |
||||
*/ |
||||
@Table(name = "isp_resource") |
||||
@Data |
||||
public class IspResource { |
||||
/** 数据库字段:id */ |
||||
@Id |
||||
@Column(name = "id") |
||||
@GeneratedValue(strategy = GenerationType.IDENTITY) |
||||
private Long id; |
||||
|
||||
/** 资源名称, 数据库字段:name */ |
||||
private String name; |
||||
|
||||
private String version; |
||||
|
||||
/** 资源内容(URL), 数据库字段:content */ |
||||
private String content; |
||||
|
||||
private String extContent; |
||||
|
||||
/** 资源类型:0:SDK链接, 数据库字段:type */ |
||||
private Byte type; |
||||
|
||||
/** 数据库字段:is_deleted */ |
||||
@com.gitee.fastmybatis.core.annotation.LogicDelete |
||||
private Byte isDeleted; |
||||
|
||||
/** 数据库字段:gmt_create */ |
||||
private Date gmtCreate; |
||||
|
||||
/** 数据库字段:gmt_modified */ |
||||
private Date gmtModified; |
||||
} |
@ -0,0 +1,11 @@ |
||||
package com.gitee.sop.adminserver.mapper; |
||||
|
||||
import com.gitee.fastmybatis.core.mapper.CrudMapper; |
||||
import com.gitee.sop.adminserver.entity.IspResource; |
||||
|
||||
|
||||
/** |
||||
* @author tanghc |
||||
*/ |
||||
public interface IspResourceMapper extends CrudMapper<IspResource, Long> { |
||||
} |
@ -1 +1 @@ |
||||
<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><link rel=icon href=favicon.ico><title>SOP Admin</title><link href=static/css/chunk-elementUI.81cf475c.css rel=stylesheet><link href=static/css/chunk-libs.3dfb7769.css rel=stylesheet><link href=static/css/app.5c572c03.css rel=stylesheet></head><body><noscript><strong>We're sorry but SOP Admin doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script>(function(e){function n(n){for(var r,c,a=n[0],f=n[1],i=n[2],d=0,l=[];d<a.length;d++)c=a[d],u[c]&&l.push(u[c][0]),u[c]=0;for(r in f)Object.prototype.hasOwnProperty.call(f,r)&&(e[r]=f[r]);h&&h(n);while(l.length)l.shift()();return o.push.apply(o,i||[]),t()}function t(){for(var e,n=0;n<o.length;n++){for(var t=o[n],r=!0,c=1;c<t.length;c++){var a=t[c];0!==u[a]&&(r=!1)}r&&(o.splice(n--,1),e=f(f.s=t[0]))}return e}var r={},c={runtime:0},u={runtime:0},o=[];function a(e){return f.p+"static/js/"+({}[e]||e)+"."+{"chunk-25908fca":"eac43cde","chunk-2c1f2e8f":"f092c0a0","chunk-2d0d32e7":"e7c489be","chunk-2d2085ef":"91d75f3c","chunk-2d221c34":"20057287","chunk-30c6c34f":"b288bbf5","chunk-4de1c2b6":"e74e3d03","chunk-73b2dcec":"60c5d8e9","chunk-9b31c83a":"494fc338","chunk-9f479afe":"2093f9d0","chunk-c3ce42fe":"9517b588"}[e]+".js"}function f(n){if(r[n])return r[n].exports;var t=r[n]={i:n,l:!1,exports:{}};return e[n].call(t.exports,t,t.exports,f),t.l=!0,t.exports}f.e=function(e){var n=[],t={"chunk-25908fca":1,"chunk-2c1f2e8f":1,"chunk-30c6c34f":1,"chunk-4de1c2b6":1,"chunk-73b2dcec":1,"chunk-9b31c83a":1,"chunk-c3ce42fe":1};c[e]?n.push(c[e]):0!==c[e]&&t[e]&&n.push(c[e]=new Promise(function(n,t){for(var r="static/css/"+({}[e]||e)+"."+{"chunk-25908fca":"a66354ec","chunk-2c1f2e8f":"0314067f","chunk-2d0d32e7":"31d6cfe0","chunk-2d2085ef":"31d6cfe0","chunk-2d221c34":"31d6cfe0","chunk-30c6c34f":"3b12267b","chunk-4de1c2b6":"a37cd815","chunk-73b2dcec":"ed391cc5","chunk-9b31c83a":"c4612b4a","chunk-9f479afe":"31d6cfe0","chunk-c3ce42fe":"6b789903"}[e]+".css",u=f.p+r,o=document.getElementsByTagName("link"),a=0;a<o.length;a++){var i=o[a],d=i.getAttribute("data-href")||i.getAttribute("href");if("stylesheet"===i.rel&&(d===r||d===u))return n()}var l=document.getElementsByTagName("style");for(a=0;a<l.length;a++){i=l[a],d=i.getAttribute("data-href");if(d===r||d===u)return n()}var h=document.createElement("link");h.rel="stylesheet",h.type="text/css",h.onload=n,h.onerror=function(n){var r=n&&n.target&&n.target.src||u,o=new Error("Loading CSS chunk "+e+" failed.\n("+r+")");o.code="CSS_CHUNK_LOAD_FAILED",o.request=r,delete c[e],h.parentNode.removeChild(h),t(o)},h.href=u;var s=document.getElementsByTagName("head")[0];s.appendChild(h)}).then(function(){c[e]=0}));var r=u[e];if(0!==r)if(r)n.push(r[2]);else{var o=new Promise(function(n,t){r=u[e]=[n,t]});n.push(r[2]=o);var i,d=document.createElement("script");d.charset="utf-8",d.timeout=120,f.nc&&d.setAttribute("nonce",f.nc),d.src=a(e),i=function(n){d.onerror=d.onload=null,clearTimeout(l);var t=u[e];if(0!==t){if(t){var r=n&&("load"===n.type?"missing":n.type),c=n&&n.target&&n.target.src,o=new Error("Loading chunk "+e+" failed.\n("+r+": "+c+")");o.type=r,o.request=c,t[1](o)}u[e]=void 0}};var l=setTimeout(function(){i({type:"timeout",target:d})},12e4);d.onerror=d.onload=i,document.head.appendChild(d)}return Promise.all(n)},f.m=e,f.c=r,f.d=function(e,n,t){f.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:t})},f.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(e,n){if(1&n&&(e=f(e)),8&n)return e;if(4&n&&"object"===typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var r in e)f.d(t,r,function(n){return e[n]}.bind(null,r));return t},f.n=function(e){var n=e&&e.__esModule?function(){return e["default"]}:function(){return e};return f.d(n,"a",n),n},f.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},f.p="",f.oe=function(e){throw console.error(e),e};var i=window["webpackJsonp"]=window["webpackJsonp"]||[],d=i.push.bind(i);i.push=n,i=i.slice();for(var l=0;l<i.length;l++)n(i[l]);var h=d;t()})([]);</script><script src=static/js/chunk-elementUI.298ac98c.js></script><script src=static/js/chunk-libs.75deb05f.js></script><script src=static/js/app.f323bdd7.js></script></body></html> |
||||
<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><link rel=icon href=favicon.ico><title>SOP Admin</title><link href=static/css/chunk-elementUI.81cf475c.css rel=stylesheet><link href=static/css/chunk-libs.3dfb7769.css rel=stylesheet><link href=static/css/app.6095bfbf.css rel=stylesheet></head><body><noscript><strong>We're sorry but SOP Admin doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script>(function(e){function n(n){for(var c,r,f=n[0],a=n[1],i=n[2],d=0,h=[];d<f.length;d++)r=f[d],u[r]&&h.push(u[r][0]),u[r]=0;for(c in a)Object.prototype.hasOwnProperty.call(a,c)&&(e[c]=a[c]);l&&l(n);while(h.length)h.shift()();return o.push.apply(o,i||[]),t()}function t(){for(var e,n=0;n<o.length;n++){for(var t=o[n],c=!0,r=1;r<t.length;r++){var f=t[r];0!==u[f]&&(c=!1)}c&&(o.splice(n--,1),e=a(a.s=t[0]))}return e}var c={},r={runtime:0},u={runtime:0},o=[];function f(e){return a.p+"static/js/"+({}[e]||e)+"."+{"chunk-25908fca":"f16786b7","chunk-2c1f2e8f":"f092c0a0","chunk-2d0d6219":"113d6c0f","chunk-2d2085ef":"91d75f3c","chunk-2d221c34":"20057287","chunk-2d238661":"5eefcb02","chunk-30c6c34f":"b288bbf5","chunk-4de1c2b6":"e74e3d03","chunk-73b2dcec":"60c5d8e9","chunk-9b31c83a":"494fc338","chunk-9f479afe":"2093f9d0","chunk-c3ce42fe":"9517b588"}[e]+".js"}function a(n){if(c[n])return c[n].exports;var t=c[n]={i:n,l:!1,exports:{}};return e[n].call(t.exports,t,t.exports,a),t.l=!0,t.exports}a.e=function(e){var n=[],t={"chunk-25908fca":1,"chunk-2c1f2e8f":1,"chunk-30c6c34f":1,"chunk-4de1c2b6":1,"chunk-73b2dcec":1,"chunk-9b31c83a":1,"chunk-c3ce42fe":1};r[e]?n.push(r[e]):0!==r[e]&&t[e]&&n.push(r[e]=new Promise(function(n,t){for(var c="static/css/"+({}[e]||e)+"."+{"chunk-25908fca":"a66354ec","chunk-2c1f2e8f":"0314067f","chunk-2d0d6219":"31d6cfe0","chunk-2d2085ef":"31d6cfe0","chunk-2d221c34":"31d6cfe0","chunk-2d238661":"31d6cfe0","chunk-30c6c34f":"3b12267b","chunk-4de1c2b6":"a37cd815","chunk-73b2dcec":"ed391cc5","chunk-9b31c83a":"c4612b4a","chunk-9f479afe":"31d6cfe0","chunk-c3ce42fe":"6b789903"}[e]+".css",u=a.p+c,o=document.getElementsByTagName("link"),f=0;f<o.length;f++){var i=o[f],d=i.getAttribute("data-href")||i.getAttribute("href");if("stylesheet"===i.rel&&(d===c||d===u))return n()}var h=document.getElementsByTagName("style");for(f=0;f<h.length;f++){i=h[f],d=i.getAttribute("data-href");if(d===c||d===u)return n()}var l=document.createElement("link");l.rel="stylesheet",l.type="text/css",l.onload=n,l.onerror=function(n){var c=n&&n.target&&n.target.src||u,o=new Error("Loading CSS chunk "+e+" failed.\n("+c+")");o.code="CSS_CHUNK_LOAD_FAILED",o.request=c,delete r[e],l.parentNode.removeChild(l),t(o)},l.href=u;var s=document.getElementsByTagName("head")[0];s.appendChild(l)}).then(function(){r[e]=0}));var c=u[e];if(0!==c)if(c)n.push(c[2]);else{var o=new Promise(function(n,t){c=u[e]=[n,t]});n.push(c[2]=o);var i,d=document.createElement("script");d.charset="utf-8",d.timeout=120,a.nc&&d.setAttribute("nonce",a.nc),d.src=f(e),i=function(n){d.onerror=d.onload=null,clearTimeout(h);var t=u[e];if(0!==t){if(t){var c=n&&("load"===n.type?"missing":n.type),r=n&&n.target&&n.target.src,o=new Error("Loading chunk "+e+" failed.\n("+c+": "+r+")");o.type=c,o.request=r,t[1](o)}u[e]=void 0}};var h=setTimeout(function(){i({type:"timeout",target:d})},12e4);d.onerror=d.onload=i,document.head.appendChild(d)}return Promise.all(n)},a.m=e,a.c=c,a.d=function(e,n,t){a.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:t})},a.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,n){if(1&n&&(e=a(e)),8&n)return e;if(4&n&&"object"===typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(a.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var c in e)a.d(t,c,function(n){return e[n]}.bind(null,c));return t},a.n=function(e){var n=e&&e.__esModule?function(){return e["default"]}:function(){return e};return a.d(n,"a",n),n},a.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},a.p="",a.oe=function(e){throw console.error(e),e};var i=window["webpackJsonp"]=window["webpackJsonp"]||[],d=i.push.bind(i);i.push=n,i=i.slice();for(var h=0;h<i.length;h++)n(i[h]);var l=d;t()})([]);</script><script src=static/js/chunk-elementUI.298ac98c.js></script><script src=static/js/chunk-libs.75deb05f.js></script><script src=static/js/app.3f83e9e2.js></script></body></html> |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1 +0,0 @@ |
||||
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d0d32e7"],{"5c58":function(t,e,a){"use strict";a.r(e);var l=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("div",{staticClass:"app-container"},[a("el-form",{staticClass:"demo-form-inline",attrs:{inline:!0,model:t.searchFormData,size:"mini"}},[a("el-form-item",{attrs:{label:"接口名"}},[a("el-input",{staticStyle:{width:"250px"},attrs:{clearable:!0,placeholder:"输入接口名或版本号"},model:{value:t.searchFormData.routeId,callback:function(e){t.$set(t.searchFormData,"routeId",e)},expression:"searchFormData.routeId"}})],1),t._v(" "),a("el-form-item",[a("el-button",{attrs:{type:"primary",icon:"el-icon-search"},on:{click:t.loadTable}},[t._v("搜索")])],1)],1),t._v(" "),a("el-alert",{staticStyle:{"margin-bottom":"10px"},attrs:{title:"监控数据保存在网关服务器,重启网关数据会清空。",type:"info",closable:!1}}),t._v(" "),a("el-table",{attrs:{data:t.tableData,border:"","default-expand-all":!1,"row-key":"id",height:"500","empty-text":"无数据"}},[a("el-table-column",{attrs:{fixed:"",prop:"instanceId",label:"网关实例",width:"200"},scopedSlots:t._u([{key:"default",fn:function(e){return[e.row.children?t._e():a("span",[t._v(t._s(e.row.instanceId))])]}}])}),t._v(" "),a("el-table-column",{attrs:{fixed:"",prop:"name",label:"接口名 (版本号)",width:"280"},scopedSlots:t._u([{key:"default",fn:function(e){return[t._v("\n "+t._s(e.row.name+(e.row.version?" ("+e.row.version+")":""))+"\n ")]}}])}),t._v(" "),a("el-table-column",{attrs:{prop:"serviceId",label:"serviceId",width:"170"}}),t._v(" "),a("el-table-column",{attrs:{prop:"maxTime",label:"最大耗时(ms)",width:"125"}},[a("template",{slot:"header"},[t._v("\n 最大耗时(ms)\n "),a("el-tooltip",{attrs:{effect:"dark",content:"耗时计算:签名验证成功后开始,微服务返回结果后结束",placement:"top"}},[a("i",{staticClass:"el-icon-question",staticStyle:{cursor:"pointer"}})])],1)],2),t._v(" "),a("el-table-column",{attrs:{prop:"minTime",label:"最小耗时(ms)",width:"120"}}),t._v(" "),a("el-table-column",{attrs:{prop:"avgTime",label:"平均耗时(ms)",width:"120"}}),t._v(" "),a("el-table-column",{attrs:{prop:"totalCount",label:"总调用次数",width:"100"}}),t._v(" "),a("el-table-column",{attrs:{prop:"successCount",label:"成功次数",width:"100"}}),t._v(" "),a("el-table-column",{attrs:{prop:"errorCount",label:"失败次数",width:"100"},scopedSlots:t._u([{key:"default",fn:function(e){return[e.row.errorCount>0?a("el-link",{staticStyle:{"text-decoration":"underline"},attrs:{underline:!1,type:"danger"},on:{click:function(a){return t.onShowErrorDetail(e.row)}}},[t._v("\n "+t._s(e.row.errorCount)+"\n ")]):t._e(),t._v(" "),0===e.row.errorCount?a("span",[t._v("0")]):t._e()]}}])},[a("template",{slot:"header"},[t._v("\n 失败次数\n "),a("el-tooltip",{attrs:{effect:"dark",content:"只统计微服务返回的未知错误,JSR-303验证错误算作成功",placement:"top-end"}},[a("i",{staticClass:"el-icon-question",staticStyle:{cursor:"pointer"}})])],1)],2)],1),t._v(" "),a("el-dialog",{attrs:{title:"错误详情",visible:t.logDetailVisible,width:"60%"},on:{"update:visible":function(e){t.logDetailVisible=e}}},[a("div",{staticStyle:{"overflow-x":"auto"},domProps:{innerHTML:t._s(t.errorMsgDetail)}}),t._v(" "),a("div",{staticClass:"dialog-footer",attrs:{slot:"footer"},slot:"footer"},[a("el-button",{attrs:{type:"primary"},on:{click:function(e){t.logDetailVisible=!1}}},[t._v("关 闭")])],1)])],1)},o=[],r={data:function(){return{searchFormData:{routeId:""},tableData:[],logDetailVisible:!1,errorMsgDetail:""}},created:function(){this.loadTable()},methods:{loadTable:function(){this.post("monitor.data.list",this.searchFormData,function(t){var e=t.data;this.tableData=e.monitorInfoData})},onShowErrorDetail:function(t){var e=t.errorMsgList;this.errorMsgDetail=e.length>0?e.join("<br>"):"无内容",this.logDetailVisible=!0}}},i=r,n=a("2877"),s=Object(n["a"])(i,l,o,!1,null,null,null);e["default"]=s.exports}}]); |
@ -0,0 +1 @@ |
||||
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d0d6219"],{"70f0":function(t,e,o){"use strict";o.r(e);var a=function(){var t=this,e=t.$createElement,o=t._self._c||e;return o("div",{staticClass:"app-container"},[o("el-form",{attrs:{size:"mini"}},[o("el-form-item",[o("el-button",{attrs:{type:"primary",icon:"el-icon-upload"},on:{click:t.onAddSdk}},[t._v("发布SDK")])],1)],1),t._v(" "),o("el-table",{attrs:{data:t.list,border:""}},[o("el-table-column",{attrs:{prop:"name",label:"SDK",width:"120"}}),t._v(" "),o("el-table-column",{attrs:{prop:"version",label:"版本",width:"120"}}),t._v(" "),o("el-table-column",{attrs:{prop:"content",label:"下载地址"},scopedSlots:t._u([{key:"default",fn:function(e){return[o("el-link",{attrs:{type:"primary",href:e.row.content,target:"_blank"}},[t._v(t._s(e.row.content))])]}}])}),t._v(" "),o("el-table-column",{attrs:{label:"操作",width:"150",align:"center"},scopedSlots:t._u([{key:"default",fn:function(e){return[o("el-button",{attrs:{type:"text",size:"mini"},on:{click:function(o){return t.onSdkUpdate(e.row)}}},[t._v("编辑")]),t._v(" "),o("el-button",{attrs:{type:"text",size:"mini"},on:{click:function(o){return t.onSdkDelete(e.row)}}},[t._v("删除")])]}}])})],1),t._v(" "),o("el-dialog",{attrs:{title:t.sdkDlgTitle,visible:t.sdkDlgAddShow,"close-on-click-modal":!1},on:{"update:visible":function(e){t.sdkDlgAddShow=e},close:function(e){return t.resetForm("sdkAddForm")}}},[o("el-form",{ref:"sdkAddForm",attrs:{model:t.sdkFormAddData,rules:t.sdkFormRule,"label-width":"100px"}},[o("el-form-item",{attrs:{prop:"name",label:"选择语言"}},[o("el-select",{attrs:{placeholder:"请选择"},model:{value:t.sdkFormAddData.name,callback:function(e){t.$set(t.sdkFormAddData,"name",e)},expression:"sdkFormAddData.name"}},t._l(t.sdkConfigs,function(t){return o("el-option",{key:t.name,attrs:{label:t.name,value:t.name}})}),1)],1),t._v(" "),o("el-form-item",{attrs:{prop:"version",label:"版本"}},[o("el-input",{attrs:{maxlength:"30","show-word-limit":"",placeholder:"如:1.0"},model:{value:t.sdkFormAddData.version,callback:function(e){t.$set(t.sdkFormAddData,"version",e)},expression:"sdkFormAddData.version"}})],1),t._v(" "),o("el-form-item",{attrs:{prop:"content",label:"下载地址"}},[o("el-input",{attrs:{maxlength:"100","show-word-limit":""},model:{value:t.sdkFormAddData.content,callback:function(e){t.$set(t.sdkFormAddData,"content",e)},expression:"sdkFormAddData.content"}})],1),t._v(" "),o("el-form-item",{attrs:{prop:"extContent",label:"调用示例"}},[o("el-input",{attrs:{type:"textarea",rows:12,placeholder:"填写SDK调用示例代码,支持markdown语法"},model:{value:t.sdkFormAddData.extContent,callback:function(e){t.$set(t.sdkFormAddData,"extContent",e)},expression:"sdkFormAddData.extContent"}})],1)],1),t._v(" "),o("div",{staticClass:"dialog-footer",attrs:{slot:"footer"},slot:"footer"},[o("el-button",{on:{click:function(e){t.sdkDlgAddShow=!1}}},[t._v("取 消")]),t._v(" "),o("el-button",{attrs:{type:"primary"},on:{click:t.onSubmitForm}},[t._v("保 存")])],1)],1)],1)},n=[],d=(o("7f7f"),function(){return{id:0,name:"",version:"",content:"",extContent:""}}),s={data:function(){return{searchFormData:{},sdkDownloadConfig:[],sdkConfigs:[],sdkDlgTitle:"",sdkDlgAddShow:!1,sdkFormUpdateData:d(),sdkFormAddData:d(),sdkFormLoading:!1,sdkFormRule:{name:[{required:!0,message:"请填名称",trigger:"blur"}],version:[{required:!0,message:"请填版本",trigger:"blur"}],content:[{required:!0,message:"请填写URL",trigger:"blur"}],extContent:[{required:!0,message:"请填写调用示例",trigger:"blur"}]},downloadUrl:"",list:[]}},created:function(){this.loadLangSelector(),this.loadTable()},methods:{loadLangSelector:function(){var t=this;this.getFile("static/sdkConfig.json?q=".concat((new Date).getTime()),function(e){t.sdkConfigs=e.langList})},loadTable:function(){var t=this;this.post("isp.sdk.list",this.searchFormData,function(e){t.list=e.data})},onSizeChange:function(t){this.searchFormData.pageSize=t,this.loadTable()},onPageIndexChange:function(t){this.searchFormData.pageIndex=t,this.loadTable()},onAddSdk:function(){this.sdkDlgTitle="添加SDK",this.sdkFormAddData=d(),this.sdkDlgAddShow=!0},onSdkUpdate:function(t){this.sdkDlgTitle="修改SDK",this.sdkFormAddData=d(),Object.assign(this.sdkFormAddData,t),this.sdkDlgAddShow=!0},onSdkDelete:function(t){var e=this;this.confirm("确认要删除【".concat(t.name,"】吗?"),function(o){e.post("isp.sdk.delete",{id:t.id},function(t){o(),e.tip("删除成功"),e.loadTable()})})},onSubmitForm:function(){var t=this;this.$refs.sdkAddForm.validate(function(e){if(e){var o=t.sdkFormAddData.id?"isp.sdk.update":"isp.sdk.add";t.post(o,t.sdkFormAddData,function(){this.sdkDlgAddShow=!1,this.loadTable()})}})}}},l=s,r=o("2877"),i=Object(r["a"])(l,a,n,!1,null,null,null);e["default"]=i.exports}}]); |
@ -0,0 +1,24 @@ |
||||
{ |
||||
"langList": [ |
||||
{ |
||||
"name": "Java" |
||||
}, |
||||
{ |
||||
"name": "C#" |
||||
}, |
||||
{ |
||||
"name": "C++" |
||||
}, |
||||
{ |
||||
"name": "Go" |
||||
},{ |
||||
"name": "NodeJS" |
||||
}, |
||||
{ |
||||
"name": "Python" |
||||
}, |
||||
{ |
||||
"name": "Rust" |
||||
} |
||||
] |
||||
} |
@ -0,0 +1,179 @@ |
||||
<template> |
||||
<div class="app-container"> |
||||
<el-form size="mini"> |
||||
<el-form-item> |
||||
<el-button type="primary" icon="el-icon-upload" @click="onAddSdk">发布SDK</el-button> |
||||
</el-form-item> |
||||
</el-form> |
||||
<el-table |
||||
:data="list" |
||||
border |
||||
> |
||||
<el-table-column |
||||
prop="name" |
||||
label="SDK" |
||||
width="120" |
||||
/> |
||||
<el-table-column |
||||
prop="version" |
||||
label="版本" |
||||
width="120" |
||||
/> |
||||
<el-table-column |
||||
prop="content" |
||||
label="下载地址" |
||||
> |
||||
<template slot-scope="scope"> |
||||
<el-link type="primary" :href="scope.row.content" target="_blank">{{ scope.row.content }}</el-link> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column |
||||
label="操作" |
||||
width="150" |
||||
align="center" |
||||
> |
||||
<template slot-scope="scope"> |
||||
<el-button type="text" size="mini" @click="onSdkUpdate(scope.row)">编辑</el-button> |
||||
<el-button type="text" size="mini" @click="onSdkDelete(scope.row)">删除</el-button> |
||||
</template> |
||||
</el-table-column> |
||||
</el-table> |
||||
<!--dialog--> |
||||
<el-dialog |
||||
:title="sdkDlgTitle" |
||||
:visible.sync="sdkDlgAddShow" |
||||
:close-on-click-modal="false" |
||||
@close="resetForm('sdkAddForm')" |
||||
> |
||||
<el-form |
||||
ref="sdkAddForm" |
||||
:model="sdkFormAddData" |
||||
:rules="sdkFormRule" |
||||
label-width="100px" |
||||
> |
||||
<el-form-item prop="name" label="选择语言"> |
||||
<el-select |
||||
v-model="sdkFormAddData.name" |
||||
placeholder="请选择" |
||||
> |
||||
<el-option |
||||
v-for="item in sdkConfigs" |
||||
:key="item.name" |
||||
:label="item.name" |
||||
:value="item.name" |
||||
/> |
||||
</el-select> |
||||
</el-form-item> |
||||
<el-form-item prop="version" label="版本"> |
||||
<el-input v-model="sdkFormAddData.version" maxlength="30" show-word-limit placeholder="如:1.0" /> |
||||
</el-form-item> |
||||
<el-form-item prop="content" label="下载地址"> |
||||
<el-input v-model="sdkFormAddData.content" maxlength="100" show-word-limit /> |
||||
</el-form-item> |
||||
<el-form-item prop="extContent" label="调用示例"> |
||||
<el-input v-model="sdkFormAddData.extContent" type="textarea" :rows="12" placeholder="填写SDK调用示例代码,支持markdown语法" /> |
||||
</el-form-item> |
||||
</el-form> |
||||
<div slot="footer" class="dialog-footer"> |
||||
<el-button @click="sdkDlgAddShow = false">取 消</el-button> |
||||
<el-button type="primary" @click="onSubmitForm">保 存</el-button> |
||||
</div> |
||||
</el-dialog> |
||||
</div> |
||||
</template> |
||||
<script> |
||||
const appFormDataInit = function() { |
||||
return { |
||||
id: 0, |
||||
name: '', |
||||
version: '', |
||||
content: '', |
||||
extContent: '' |
||||
} |
||||
} |
||||
export default { |
||||
data() { |
||||
return { |
||||
searchFormData: {}, |
||||
sdkDownloadConfig: [], |
||||
sdkConfigs: [], |
||||
sdkDlgTitle: '', |
||||
sdkDlgAddShow: false, |
||||
sdkFormUpdateData: appFormDataInit(), |
||||
sdkFormAddData: appFormDataInit(), |
||||
sdkFormLoading: false, |
||||
sdkFormRule: { |
||||
name: [ |
||||
{ required: true, message: '请填名称', trigger: 'blur' } |
||||
], |
||||
version: [ |
||||
{ required: true, message: '请填版本', trigger: 'blur' } |
||||
], |
||||
content: [ |
||||
{ required: true, message: '请填写URL', trigger: 'blur' } |
||||
], |
||||
extContent: [ |
||||
{ required: true, message: '请填写调用示例', trigger: 'blur' } |
||||
] |
||||
}, |
||||
downloadUrl: '', |
||||
list: [] |
||||
} |
||||
}, |
||||
created() { |
||||
this.loadLangSelector() |
||||
this.loadTable() |
||||
}, |
||||
methods: { |
||||
loadLangSelector: function() { |
||||
this.getFile(`static/sdkConfig.json?q=${new Date().getTime()}`, (content) => { |
||||
this.sdkConfigs = content.langList |
||||
}) |
||||
}, |
||||
loadTable: function() { |
||||
this.post('isp.sdk.list', this.searchFormData, resp => { |
||||
this.list = resp.data |
||||
}) |
||||
}, |
||||
onSizeChange: function(size) { |
||||
this.searchFormData.pageSize = size |
||||
this.loadTable() |
||||
}, |
||||
onPageIndexChange: function(pageIndex) { |
||||
this.searchFormData.pageIndex = pageIndex |
||||
this.loadTable() |
||||
}, |
||||
onAddSdk: function() { |
||||
this.sdkDlgTitle = '添加SDK' |
||||
this.sdkFormAddData = appFormDataInit() |
||||
this.sdkDlgAddShow = true |
||||
}, |
||||
onSdkUpdate: function(row) { |
||||
this.sdkDlgTitle = '修改SDK' |
||||
this.sdkFormAddData = appFormDataInit() |
||||
Object.assign(this.sdkFormAddData, row) |
||||
this.sdkDlgAddShow = true |
||||
}, |
||||
onSdkDelete: function(row) { |
||||
this.confirm(`确认要删除【${row.name}】吗?`, (done) => { |
||||
this.post('isp.sdk.delete', { id: row.id }, resp => { |
||||
done() |
||||
this.tip('删除成功') |
||||
this.loadTable() |
||||
}) |
||||
}) |
||||
}, |
||||
onSubmitForm: function() { |
||||
this.$refs.sdkAddForm.validate((valid) => { |
||||
if (valid) { |
||||
const uri = this.sdkFormAddData.id ? 'isp.sdk.update' : 'isp.sdk.add' |
||||
this.post(uri, this.sdkFormAddData, function() { |
||||
this.sdkDlgAddShow = false |
||||
this.loadTable() |
||||
}) |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
} |
||||
</script> |
@ -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/ |
||||
|
@ -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) |
@ -0,0 +1 @@ |
||||
hello你好123 |
@ -0,0 +1 @@ |
||||
文件bb的内容 |
@ -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; |
||||
} |
@ -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
|
@ -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; |
||||
} |
@ -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); |
@ -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
|
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
||||
|
@ -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
|
@ -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; |
||||
} |
||||
} |
||||
|
@ -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
|
@ -0,0 +1,2 @@ |
||||
|
||||
#include "stdafx.h" |
@ -0,0 +1,6 @@ |
||||
#pragma once |
||||
|
||||
#include "targetver.h" |
||||
|
||||
|
||||
|
@ -0,0 +1 @@ |
||||
|
@ -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; |
||||
} |
||||
|
||||
} |
@ -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
|
@ -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; |
||||
} |
||||
|
@ -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----- |
@ -0,0 +1,3 @@ |
||||
# SDK for C++ |
||||
|
||||
使用方式见:main.cpp |
@ -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); |
||||
} |
@ -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
|
@ -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
|
File diff suppressed because it is too large
Load Diff
@ -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_ */ |
File diff suppressed because it is too large
Load Diff
@ -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 |
@ -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; |
||||
} |
||||
|
@ -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 */ |
@ -0,0 +1,5 @@ |
||||
# sdk for rust |
||||
|
||||
使用方式见:`sdk-test/src/main.rs` |
||||
|
||||
封装步骤参考 `sdk/src/request/memberinfoget.rs` 和 `sdk/src/response/memberinfoget.rs` |
@ -0,0 +1 @@ |
||||
/target |
File diff suppressed because it is too large
Load Diff
@ -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"} |
@ -0,0 +1 @@ |
||||
hello你好123 |
@ -0,0 +1 @@ |
||||
文件bb的内容 |
@ -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); |
||||
} |
||||
|
||||
} |
@ -0,0 +1 @@ |
||||
/target |
File diff suppressed because it is too large
Load Diff
@ -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" |
@ -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 |
||||
} |
||||
} |
@ -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 |
||||
} |
||||
} |
@ -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); |
||||
} |
||||
}*/ |
@ -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 |
||||
} |
||||
} |
@ -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> |
||||
} |
@ -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 |
||||
} |
@ -0,0 +1 @@ |
||||
pub mod memberinfoget; |
@ -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("&") |
||||
} |
||||
} |
@ -0,0 +1,30 @@ |
||||
use sop; |
||||
|
||||
ALTER TABLE `sop`.`isv_info` ADD COLUMN `user_id` BIGINT NULL DEFAULT 0 COMMENT 'user_account.id' AFTER `remark`; |
||||
|
||||
CREATE INDEX `idx_userid` USING BTREE ON `sop`.`isv_info` (`user_id`); |
||||
|
||||
|
||||
CREATE TABLE `user_account` ( |
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, |
||||
`username` varchar(128) NOT NULL DEFAULT '' COMMENT '用户名(邮箱)', |
||||
`password` varchar(128) NOT NULL DEFAULT '' COMMENT '密码', |
||||
`status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '2:邮箱未验证,1:启用,0:禁用', |
||||
`gmt_create` datetime DEFAULT CURRENT_TIMESTAMP, |
||||
`gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, |
||||
PRIMARY KEY (`id`), |
||||
UNIQUE KEY `uk_username` (`username`) USING BTREE |
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户信息'; |
||||
|
||||
CREATE TABLE `isp_resource` ( |
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, |
||||
`name` varchar(64) NOT NULL DEFAULT '' COMMENT '资源名称', |
||||
`content` varchar(128) NOT NULL DEFAULT '' COMMENT '资源内容(URL)', |
||||
`ext_content` text, |
||||
`version` varchar(32) NOT NULL DEFAULT '' COMMENT '版本', |
||||
`type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '资源类型:0:SDK链接', |
||||
`is_deleted` tinyint(4) NOT NULL DEFAULT '0', |
||||
`gmt_create` datetime DEFAULT CURRENT_TIMESTAMP, |
||||
`gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, |
||||
PRIMARY KEY (`id`) |
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='ISP资源表'; |
@ -1,77 +1,21 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
|
||||
<parent> |
||||
<groupId>com.gitee.sop</groupId> |
||||
<artifactId>sop-parent</artifactId> |
||||
<version>4.1.0-SNAPSHOT</version> |
||||
<version>4.2.0-SNAPSHOT</version> |
||||
<relativePath>../pom.xml</relativePath> <!-- lookup parent from repository --> |
||||
</parent> |
||||
|
||||
<modelVersion>4.0.0</modelVersion> |
||||
<artifactId>sop-website</artifactId> |
||||
<version>4.2.0-SNAPSHOT</version> |
||||
<packaging>pom</packaging> |
||||
|
||||
<properties> |
||||
<java.version>1.8</java.version> |
||||
</properties> |
||||
|
||||
<dependencies> |
||||
<!-- |
||||
<artifactId>sop-bridge-nacos</artifactId> : 使用nacos注册中心 |
||||
<artifactId>sop-bridge-eureka</artifactId> : 使用eureka注册中心 |
||||
--> |
||||
<dependency> |
||||
<groupId>com.gitee.sop</groupId> |
||||
<!-- <artifactId>sop-bridge-nacos</artifactId>--> |
||||
<artifactId>sop-bridge-eureka</artifactId> |
||||
<version>4.0.3-SNAPSHOT</version> |
||||
</dependency> |
||||
|
||||
<dependency> |
||||
<groupId>org.springframework.boot</groupId> |
||||
<artifactId>spring-boot-starter-web</artifactId> |
||||
</dependency> |
||||
|
||||
<dependency> |
||||
<groupId>org.apache.commons</groupId> |
||||
<artifactId>commons-lang3</artifactId> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>com.squareup.okhttp3</groupId> |
||||
<artifactId>okhttp</artifactId> |
||||
</dependency> |
||||
|
||||
<dependency> |
||||
<groupId>com.alibaba</groupId> |
||||
<artifactId>fastjson</artifactId> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.apache.httpcomponents</groupId> |
||||
<artifactId>httpclient</artifactId> |
||||
</dependency> |
||||
|
||||
<dependency> |
||||
<groupId>org.projectlombok</groupId> |
||||
<artifactId>lombok</artifactId> |
||||
<version>1.18.4</version> |
||||
<scope>provided</scope> |
||||
</dependency> |
||||
|
||||
<dependency> |
||||
<groupId>org.springframework.boot</groupId> |
||||
<artifactId>spring-boot-starter-test</artifactId> |
||||
<scope>test</scope> |
||||
</dependency> |
||||
</dependencies> |
||||
|
||||
<build> |
||||
<plugins> |
||||
<plugin> |
||||
<groupId>org.springframework.boot</groupId> |
||||
<artifactId>spring-boot-maven-plugin</artifactId> |
||||
</plugin> |
||||
</plugins> |
||||
</build> |
||||
|
||||
</project> |
||||
<modules> |
||||
<module>sop-website-server</module> |
||||
</modules> |
||||
</project> |
@ -0,0 +1,22 @@ |
||||
{ |
||||
"plugins": [ |
||||
"transform-decorators-legacy", |
||||
"transform-class-properties", |
||||
"transform-object-rest-spread", |
||||
"transform-object-assign", |
||||
[ |
||||
"transform-runtime", |
||||
{ |
||||
"helpers": false, |
||||
"polyfill": false, |
||||
"regenerator": true, |
||||
"moduleName": "babel-runtime" |
||||
} |
||||
] |
||||
], |
||||
"presets": [ |
||||
"react", |
||||
"stage-0", |
||||
"es2015" |
||||
] |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue