From 23fabbd65bb0d676efdf603c0075b8e437d8d691 Mon Sep 17 00:00:00 2001 From: Lighting-Jack <574637316@qq.com> Date: Thu, 14 Nov 2019 14:39:14 +0800 Subject: [PATCH] feat(invoke): support keep-alive --- .gitignore | 3 +- .npmignore | 3 +- README.md | 20 ++++++++- __tests__/invoke.test.js | 95 ++++++++++++++++++++++++--------------- dist/helper/types.d.ts | 3 ++ dist/helper/utils.d.ts | 1 + dist/helper/utils.js | 1 + dist/index.d.ts | 5 ++- dist/index.js | 48 ++++++++++++++++++-- dist/services/invoke.d.ts | 4 +- dist/services/invoke.js | 7 +-- package.json | 4 +- src/helper/types.ts | 5 +++ src/helper/utils.ts | 3 +- src/index.ts | 72 +++++++++++++++++++++++++++-- src/services/invoke.ts | 26 +++++++---- 16 files changed, 235 insertions(+), 65 deletions(-) diff --git a/.gitignore b/.gitignore index f195ae7a..c33d6102 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ package-lock.json yarn.lock coverage secret.json -.vscode \ No newline at end of file +.vscode +*.log \ No newline at end of file diff --git a/.npmignore b/.npmignore index f195ae7a..c33d6102 100644 --- a/.npmignore +++ b/.npmignore @@ -3,4 +3,5 @@ package-lock.json yarn.lock coverage secret.json -.vscode \ No newline at end of file +.vscode +*.log \ No newline at end of file diff --git a/README.md b/README.md index ffaec2fc..9a965744 100644 --- a/README.md +++ b/README.md @@ -32,10 +32,13 @@ sdk.invoke({ ``` ## API Reference -- [Init](#Init) +- [Init](#Init) - [Invoke](#Invoke) ### Init + +**init(Params, ExtraParams)** + 使用SDK前,可以选择初始化SDK,这个并不是强制要求的操作,只是为了方便调用API接口时,复用初始化的配置。参数中undefined的值会被忽略。 **Params:** @@ -47,7 +50,16 @@ sdk.invoke({ | secretKey | 否 | string | 默认会取process.env.TENCENTCLOUD_SECRETKEY | | token | 否 | string | 默认会取process.env.TENCENTCLOUD_SESSIONTOKEN | +**ExtraParams:** +| 参数名 | 是否必填 | 类型 | 描述 | +| :-------- | :------: | :----: | -----------------------------------------: | +| forever | 否 | boolean | 是否开启keep-alive | +| time | 否 | boolean | 是否打印请求耗时统计 | + ### Invoke + +**invoke(Params, ExtraParams)** + 调用函数。暂时只支持同步调用。参数中undefined的值会被忽略。 **Params:** @@ -63,6 +75,12 @@ sdk.invoke({ | secretKey | 否 | string | 默认会取process.env.TENCENTCLOUD_SECRETKEY | | token | 否 | string | 默认会取process.env.TENCENTCLOUD_SESSIONTOKEN | +**ExtraParams:** +| 参数名 | 是否必填 | 类型 | 描述 | +| :-------- | :------: | :----: | -----------------------------------------: | +| forever | 否 | boolean | 是否开启keep-alive | +| time | 否 | boolean | 是否打印请求耗时统计 | + **Return:** 正常调用的返回结果为**被调用**的云函数的返回值。 diff --git a/__tests__/invoke.test.js b/__tests__/invoke.test.js index 938b5844..ef1391ab 100644 --- a/__tests__/invoke.test.js +++ b/__tests__/invoke.test.js @@ -2,6 +2,12 @@ const LabelResourceNotFound = String('ResourceNotFound.FunctionName') const sdk = require('../dist/index') +const extraParams = { + forever: true, + time: true, + strictSSL: false +} + let secret = { secretId: process.env.TENCENTCLOUD_SECRETID, secretKey: process.env.TENCENTCLOUD_SECRETKEY @@ -36,11 +42,14 @@ const functionReturnError = { } describe('Test Api With Init', () => { - sdk.init({ - region, - secretId: secret.secretId, - secretKey: secret.secretKey - }) + sdk.init( + { + region, + secretId: secret.secretId, + secretKey: secret.secretKey + }, + extraParams + ) test( 'Test Invoke Correct', async () => { @@ -78,16 +87,19 @@ describe('Test Api Without Init', () => { test( 'Test Invoke Correct With secret dominantly', async () => { - const res = await sdk.invoke({ - region, - secretId: secret.secretId, - secretKey: secret.secretKey, - token: undefined, - functionName: functionReturnCorrect.functionName, - version: functionReturnCorrect.version, - data: JSON.stringify(functionReturnCorrect.clientContext), - namespace: functionReturnCorrect.namespace - }) + const res = await sdk.invoke( + { + region, + secretId: secret.secretId, + secretKey: secret.secretKey, + token: undefined, + functionName: functionReturnCorrect.functionName, + version: functionReturnCorrect.version, + data: JSON.stringify(functionReturnCorrect.clientContext), + namespace: functionReturnCorrect.namespace + }, + extraParams + ) expect(res).toBe(JSON.stringify('test')) }, 10 * 1000 @@ -95,12 +107,15 @@ describe('Test Api Without Init', () => { test( 'Test Invoke Correct With secret implicitly', async () => { - const res = await sdk.invoke({ - functionName: functionReturnCorrect.functionName, - version: functionReturnCorrect.version, - data: JSON.stringify(functionReturnCorrect.clientContext), - namespace: functionReturnCorrect.namespace - }) + const res = await sdk.invoke( + { + functionName: functionReturnCorrect.functionName, + version: functionReturnCorrect.version, + data: JSON.stringify(functionReturnCorrect.clientContext), + namespace: functionReturnCorrect.namespace + }, + extraParams + ) expect(res).toBe(JSON.stringify('test')) }, 10 * 1000 @@ -109,16 +124,19 @@ describe('Test Api Without Init', () => { test( 'Test Invoke Error With secret dominantly', async () => { - const res = await sdk.invoke({ - region, - secretId: secret.secretId, - secretKey: secret.secretKey, - token: undefined, - functionName: functionReturnError.functionName, - version: functionReturnError.version, - data: JSON.stringify(functionReturnError.clientContext), - namespace: functionReturnError.namespace - }) + const res = await sdk.invoke( + { + region, + secretId: secret.secretId, + secretKey: secret.secretKey, + token: undefined, + functionName: functionReturnError.functionName, + version: functionReturnError.version, + data: JSON.stringify(functionReturnError.clientContext), + namespace: functionReturnError.namespace + }, + extraParams + ) expect(res.error.code).toBe(LabelResourceNotFound) }, 10 * 1000 @@ -126,12 +144,15 @@ describe('Test Api Without Init', () => { test( 'Test Invoke Error With secret implicitly', async () => { - const res = await sdk.invoke({ - functionName: functionReturnError.functionName, - version: functionReturnError.version, - data: JSON.stringify(functionReturnError.clientContext), - namespace: functionReturnError.namespace - }) + const res = await sdk.invoke( + { + functionName: functionReturnError.functionName, + version: functionReturnError.version, + data: JSON.stringify(functionReturnError.clientContext), + namespace: functionReturnError.namespace + }, + extraParams + ) expect(res.error.code).toBe(LabelResourceNotFound) }, 10 * 1000 diff --git a/dist/helper/types.d.ts b/dist/helper/types.d.ts index c3cbc3de..1db785ff 100644 --- a/dist/helper/types.d.ts +++ b/dist/helper/types.d.ts @@ -17,3 +17,6 @@ export interface InitConfig { token?: string; region?: string; } +export interface ExtraParams { + forever?: boolean; +} diff --git a/dist/helper/utils.d.ts b/dist/helper/utils.d.ts index d61ed1c8..14e052d4 100644 --- a/dist/helper/utils.d.ts +++ b/dist/helper/utils.d.ts @@ -1,3 +1,4 @@ +export declare const emptyOp: () => void; export declare const clone: (obj: object) => object; export declare const isType: (type: string) => (obj: any) => boolean; export declare const caseFormat: (type: 'lower' | 'upper') => (string: string) => string; diff --git a/dist/helper/utils.js b/dist/helper/utils.js index ed3ab9c5..a600cf18 100644 --- a/dist/helper/utils.js +++ b/dist/helper/utils.js @@ -1,5 +1,6 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); +exports.emptyOp = () => { }; exports.clone = function (obj) { try { return JSON.parse(JSON.stringify(obj, (key, value) => { diff --git a/dist/index.d.ts b/dist/index.d.ts index 55e5c952..73801793 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -1,9 +1,10 @@ import * as services from './services'; -import { InitConfig } from './helper/types'; +import { InitConfig, ExtraParams } from './helper/types'; declare class SDK { config: InitConfig; requestHelper: any; - init(config?: InitConfig): void; + extraParams: ExtraParams; + init(config?: InitConfig, extraParams?: ExtraParams): void; _reset(): void; invoke: typeof services.invoke; } diff --git a/dist/index.js b/dist/index.js index 3fd3dcb6..f2c4a038 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1,23 +1,55 @@ "use strict"; const services = require("./services"); const Capi = require("qcloudapi-sdk"); -const util = require("util"); const error_1 = require("./helper/error"); +const assign = require("object-assign"); +const qs = require("querystring"); +const request = require("request"); const _ = require("lodash"); +Capi.prototype.request = function (data, opts, callback, extra) { + if (typeof opts === 'function') { + callback = opts; + opts = this.defaults; + } + opts = opts || this.defaults; + callback = callback || Function.prototype; + var url = this.generateUrl(opts); + var method = (opts.method || this.defaults.method).toUpperCase(); + var dataStr = this.generateQueryString(data, opts); + var option = { url: url, method: method, json: true, strictSSL: false }; + var maxKeys = opts.maxKeys === undefined ? this.defaults.maxKeys : opts.maxKeys; + if (method === 'POST') { + option['form'] = qs.parse(dataStr, null, null, { + maxKeys: maxKeys + }); + } + else { + option.url += '?' + dataStr; + } + assign(option, extra); + request(option, function (error, response, body) { + callback(error, response, body); + }); +}; class SDK { constructor() { this.invoke = services.invoke; } - init(config) { + init(config, extraParams) { const defaultConfig = { secretId: process.env.TENCENTCLOUD_SECRETID, secretKey: process.env.TENCENTCLOUD_SECRETKEY, token: process.env.TENCENTCLOUD_SESSIONTOKEN, region: 'ap-guangzhou' }; + const defaultExtraParams = { + forever: true + }; const __config = _.omitBy(_.merge({}, defaultConfig, config), _.isUndefined); + const __extraParams = _.omitBy(_.merge({}, defaultExtraParams, extraParams), _.isUndefined); if (!__config.secretId || !__config.secretKey) return console.warn(error_1.ERR_MISSING_SECRET); + this.extraParams = __extraParams; this.config = __config; const capi = new Capi({ SecretId: __config.secretId, @@ -27,7 +59,17 @@ class SDK { baseHost: 'tencentcloudapi.com', protocol: 'https' }); - this.requestHelper = util.promisify(capi.request.bind(capi)); + this.requestHelper = (data, opts, extra) => { + return new Promise((res, rej) => { + capi.request(data, opts, (err, response, body) => { + if (err) + return rej(err); + if (__extraParams.time && response) + console.log(response.timingPhases); + res(body); + }, extra); + }); + }; } _reset() { this.config = null; diff --git a/dist/services/invoke.d.ts b/dist/services/invoke.d.ts index bbb158dc..093d6b29 100644 --- a/dist/services/invoke.d.ts +++ b/dist/services/invoke.d.ts @@ -1,4 +1,4 @@ -import { APIV3Res, APIV3Error, InitConfig } from '../helper/types'; +import { APIV3Res, APIV3Error, InitConfig, ExtraParams } from '../helper/types'; interface Params { functionName: string; qualifier?: string; @@ -17,5 +17,5 @@ declare type Res = APIV3Res<{ Log: string; }; }> & APIV3Error; -export default function (params: Params & InitConfig): Promise; +export default function (params: Params & InitConfig, extraParams?: ExtraParams): Promise; export {}; diff --git a/dist/services/invoke.js b/dist/services/invoke.js index 6a19ef0d..57776551 100644 --- a/dist/services/invoke.js +++ b/dist/services/invoke.js @@ -2,14 +2,14 @@ Object.defineProperty(exports, "__esModule", { value: true }); const utils_1 = require("../helper/utils"); const _ = require("lodash"); -async function default_1(params) { +async function default_1(params, extraParams) { if (!this.config) this.init({ secretId: params.secretId, secretKey: params.secretKey, token: params.token, region: params.region - }); + }, extraParams); const requestHelper = this.requestHelper; const region = this.config.region; let __params = _.omitBy(_.merge({ @@ -35,7 +35,8 @@ async function default_1(params) { { serviceType: 'scf', secretKey: params.secretKey || this.config.secretKey - } + }, + this.extraParams || extraParams ], 'Response.Result.RetMsg'); } exports.default = default_1; diff --git a/package.json b/package.json index 82af9cd8..4c66d80b 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,8 @@ "dependencies": { "lodash": "^4.17.15", "lodash.merge": "^4.6.2", - "qcloudapi-sdk": "^0.2.1" + "object-assign": "3.0.0", + "qcloudapi-sdk": "^0.2.1", + "request": "^2.88.0" } } diff --git a/src/helper/types.ts b/src/helper/types.ts index 8338bd9c..c6fcd84c 100644 --- a/src/helper/types.ts +++ b/src/helper/types.ts @@ -19,3 +19,8 @@ export interface InitConfig { token?: string region?: string } + +export interface ExtraParams { + forever?: boolean + time?: boolean +} diff --git a/src/helper/utils.ts b/src/helper/utils.ts index ee5b98fd..ef3809d4 100644 --- a/src/helper/utils.ts +++ b/src/helper/utils.ts @@ -1,3 +1,5 @@ +export const emptyOp = () => {} + /** * 复制一个对象,会抛弃继承属性 * @param obj @@ -134,7 +136,6 @@ export async function uniteRes(fn, scope, args, returnKey) { if (res.Response.Error) { throw res.Response } - return caseForObject(getValue(res)(returnKey), 'lower') as any } catch (e) { return caseForObject(e, 'lower') as { diff --git a/src/index.ts b/src/index.ts index f9cf1abc..dc05b485 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,25 +1,75 @@ import * as services from './services' import * as Capi from 'qcloudapi-sdk' -import * as util from 'util' -import { InitConfig } from './helper/types' +import { InitConfig, ExtraParams } from './helper/types' import { ERR_MISSING_SECRET } from './helper/error' +import * as assign from 'object-assign' +import * as qs from 'querystring' +import * as request from 'request' import * as _ from 'lodash' +/////////////////////////////////////////////// +/** + * request 重写 + * - 原始的方法只往外传body,而不传response,像状态码等详细信息获取不到 + */ +////////////////////////////////////////////// +Capi.prototype.request = function(data, opts, callback, extra) { + if (typeof opts === 'function') { + callback = opts + opts = this.defaults + } + opts = opts || this.defaults + callback = callback || Function.prototype + + var url = this.generateUrl(opts) + var method = (opts.method || this.defaults.method).toUpperCase() + var dataStr = this.generateQueryString(data, opts) + var option = { url: url, method: method, json: true, strictSSL: false } + var maxKeys = + opts.maxKeys === undefined ? this.defaults.maxKeys : opts.maxKeys + + if (method === 'POST') { + option['form'] = qs.parse(dataStr, null, null, { + maxKeys: maxKeys + }) + } else { + option.url += '?' + dataStr + } + + assign(option, extra) + + request(option, function(error, response, body) { + callback(error, response, body) + }) +} + class SDK { public config: InitConfig public requestHelper + public extraParams: ExtraParams - init(config?: InitConfig) { + init(config?: InitConfig, extraParams?: ExtraParams) { const defaultConfig = { secretId: process.env.TENCENTCLOUD_SECRETID, secretKey: process.env.TENCENTCLOUD_SECRETKEY, token: process.env.TENCENTCLOUD_SESSIONTOKEN, region: 'ap-guangzhou' } + + const defaultExtraParams = { + forever: true + } + const __config = _.omitBy(_.merge({}, defaultConfig, config), _.isUndefined) + const __extraParams = _.omitBy( + _.merge({}, defaultExtraParams, extraParams), + _.isUndefined + ) + if (!__config.secretId || !__config.secretKey) return console.warn(ERR_MISSING_SECRET) + this.extraParams = __extraParams this.config = __config const capi = new Capi({ SecretId: __config.secretId, @@ -29,7 +79,21 @@ class SDK { baseHost: 'tencentcloudapi.com', protocol: 'https' }) - this.requestHelper = util.promisify(capi.request.bind(capi)) + this.requestHelper = (data, opts, extra) => { + return new Promise((res, rej) => { + capi.request( + data, + opts, + (err, response, body) => { + if (err) return rej(err) + if (__extraParams.time && response) + console.log(response.timingPhases) + res(body) + }, + extra + ) + }) + } } _reset() { diff --git a/src/services/invoke.ts b/src/services/invoke.ts index d553cdad..f8b0713b 100644 --- a/src/services/invoke.ts +++ b/src/services/invoke.ts @@ -1,5 +1,5 @@ import { caseForObject, uniteRes } from '../helper/utils' -import { APIV3Res, APIV3Error, InitConfig } from '../helper/types' +import { APIV3Res, APIV3Error, InitConfig, ExtraParams } from '../helper/types' import * as _ from 'lodash' interface Params { @@ -31,14 +31,20 @@ type Res = APIV3Res<{ * 第一期只支持同步调用 * @param params */ -export default async function(params: Params & InitConfig): Promise { +export default async function( + params: Params & InitConfig, + extraParams?: ExtraParams +): Promise { if (!this.config) - this.init({ - secretId: params.secretId, - secretKey: params.secretKey, - token: params.token, - region: params.region - }) + this.init( + { + secretId: params.secretId, + secretKey: params.secretKey, + token: params.token, + region: params.region + }, + extraParams + ) const requestHelper = this.requestHelper const region = this.config.region @@ -69,6 +75,7 @@ export default async function(params: Params & InitConfig): Promise { ), _.isUndefined ) + return await uniteRes( requestHelper, this, @@ -77,7 +84,8 @@ export default async function(params: Params & InitConfig): Promise { { serviceType: 'scf', secretKey: params.secretKey || this.config.secretKey - } + }, + this.extraParams || extraParams ], 'Response.Result.RetMsg' )