feat: init repo
This commit is contained in:
parent
fbc7d762df
commit
9b74bd56c2
43
README.md
43
README.md
|
@ -1 +1,44 @@
|
|||
## 组件说明
|
||||
|
||||
fc-remote-invoke 组件调用 FC 函数。
|
||||
|
||||
## 带有 YAML 文件用法
|
||||
|
||||
### yaml 配置
|
||||
|
||||
````
|
||||
edition: 1.0.0 # 命令行YAML规范版本,遵循语义化版本(Semantic Versioning)规范
|
||||
name: compoent-test # 项目名称
|
||||
|
||||
services:
|
||||
component-test:
|
||||
component: devsapp/fc-remote-invoke # 这里引入的是相对路径,正式配置替换成你自己的component名称即可
|
||||
props:
|
||||
region: ${region}
|
||||
serviceName: ${serviceName}
|
||||
functionName: ${functionName}
|
||||
````
|
||||
|
||||
### 函数调用
|
||||
|
||||
|
||||
````
|
||||
$ s exec -- invoke --invocation-type sync --event ${payload}
|
||||
$ s exec -- invoke --invocation-type async --event-file ${path}
|
||||
$ s exec -- invoke --event-stdin
|
||||
````
|
||||
|
||||
## CLI 用法
|
||||
|
||||
````
|
||||
$ s cli fc-remote-invoke invoke --region * --service-name * --function-name * --invocation-type sync --event ${payload}
|
||||
$ s cli fc-remote-invoke invoke --region * --service-name * --function-name * --invocation-type async --event-file ${path}
|
||||
$ s cli fc-remote-invoke invoke --region * --service-name * --function-name * --event-stdin
|
||||
````
|
||||
|
||||
## 特别说明
|
||||
|
||||
当函数是 http 函数时,event最终获取值目前仅支持 json 字符串,[示例参考](https://github.com/devsapp/fc-remote-invoke/blob/master/example/http.json)
|
||||
|
||||
invocation-type 选填,默认 sync
|
||||
event 选填,event 函数默认为空字符串,http 函数默认 GET 请求,其他参数为空
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "fc-remote-invoke",
|
||||
"version": "0.0.1",
|
||||
"version": "0.0.6",
|
||||
"description": "This is a component demo for Serverless Devs Tool ",
|
||||
"keywords": [
|
||||
"Serverless",
|
||||
|
@ -32,8 +32,10 @@
|
|||
"dependencies": {
|
||||
"@alicloud/fc2": "^2.2.2",
|
||||
"@serverless-devs/core": "^0.0.*",
|
||||
"fs-extra": "^10.0.0",
|
||||
"i18n": "^0.13.2",
|
||||
"lodash.get": "^4.4.2"
|
||||
"lodash.get": "^4.4.2",
|
||||
"readline": "^1.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/lodash": "^4.14.168",
|
||||
|
|
|
@ -2,7 +2,7 @@ Type: Component
|
|||
Name: fc-remote-invoke
|
||||
Provider:
|
||||
- 其它
|
||||
Version: 0.0.1
|
||||
Version: 0.0.6
|
||||
Description: 初始化component模板
|
||||
HomePage: https://www.serverless-devs.com
|
||||
Tags: #标签详情
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
export default [
|
||||
{
|
||||
header: 'Description',
|
||||
content: 'Remote Invoke',
|
||||
},
|
||||
{
|
||||
header: 'Usage',
|
||||
content: '$ fc-remote-invoke invoke <options>',
|
||||
},
|
||||
{
|
||||
header: 'Options',
|
||||
optionList: [
|
||||
{
|
||||
name: 'invocation-type',
|
||||
description: 'Invocation type: optional value "async"|"sync", default value "sync" (default: "sync")',
|
||||
alias: '-t',
|
||||
type: String,
|
||||
},
|
||||
{
|
||||
name: 'event',
|
||||
description: 'Event data (strings) passed to the function during invocation (default: "")',
|
||||
alias: '-e',
|
||||
type: String,
|
||||
},
|
||||
{
|
||||
name: 'event-file',
|
||||
description: 'A file containing event data passed to the function during invoke.',
|
||||
alias: '-f',
|
||||
type: String,
|
||||
},
|
||||
{
|
||||
name: 'event-stdin',
|
||||
description: 'Read from standard input, to support script pipeline.',
|
||||
alias: '-s',
|
||||
type: Boolean,
|
||||
},
|
||||
{
|
||||
name: 'region',
|
||||
description: 'Pass in region in cli mode',
|
||||
type: String,
|
||||
},
|
||||
{
|
||||
name: 'service-name',
|
||||
description: 'Pass in service name in cli mode',
|
||||
type: String,
|
||||
},
|
||||
{
|
||||
name: 'function-name',
|
||||
description: 'Pass in function name in cli mode',
|
||||
type: String,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
header: 'Global Options',
|
||||
optionList: [
|
||||
{
|
||||
name: 'help',
|
||||
description: 'fc-remote-invoke help for command',
|
||||
alias: 'h',
|
||||
type: Boolean,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
header: 'Examples with Yaml',
|
||||
content: [
|
||||
'$ s exec -- invoke <options>',
|
||||
],
|
||||
},
|
||||
{
|
||||
header: 'Examples with Cli',
|
||||
content: [
|
||||
'$ s cli fc-remote-invoke invoke --region * --service-name * --function-name * <options>',
|
||||
],
|
||||
},
|
||||
]
|
|
@ -3,34 +3,32 @@ import i18n from './i18n';
|
|||
import { Logger } from '@serverless-devs/core';
|
||||
|
||||
export default class ComponentLogger {
|
||||
static CONTENT = 'FC-REMOTE-INVOKE';
|
||||
static setContent(content) {
|
||||
ComponentLogger.CONTENT = content;
|
||||
}
|
||||
static log(m, color?: 'black' | 'red' | 'green' | 'yellow' | 'blue' | 'magenta' | 'cyan' | 'white' | 'whiteBright' | 'gray') {
|
||||
Logger.log(i18n.__(m) || m, color);
|
||||
}
|
||||
static info(m) {
|
||||
Logger.info(ComponentLogger.CONTENT, i18n.__(m) || m);
|
||||
}
|
||||
static CONTENT = 'FC-REMOTE-INVOKE';
|
||||
static setContent(content) {
|
||||
ComponentLogger.CONTENT = content;
|
||||
}
|
||||
static log(m, color?: 'black' | 'red' | 'green' | 'yellow' | 'blue' | 'magenta' | 'cyan' | 'white' | 'whiteBright' | 'gray') {
|
||||
Logger.log(i18n.__(m) || m, color);
|
||||
}
|
||||
static info(m) {
|
||||
Logger.info(ComponentLogger.CONTENT, i18n.__(m) || m);
|
||||
}
|
||||
|
||||
static debug(m) {
|
||||
Logger.debug(ComponentLogger.CONTENT, i18n.__(m) || m);
|
||||
}
|
||||
static debug(m) {
|
||||
Logger.debug(ComponentLogger.CONTENT, i18n.__(m) || m);
|
||||
}
|
||||
|
||||
static error(m) {
|
||||
Logger.error(ComponentLogger.CONTENT, i18n.__(m) || m);
|
||||
}
|
||||
static error(m) {
|
||||
Logger.error(ComponentLogger.CONTENT, i18n.__(m) || m);
|
||||
}
|
||||
|
||||
static warning(m) {
|
||||
Logger.warn(ComponentLogger.CONTENT, i18n.__(m) || m);
|
||||
}
|
||||
|
||||
|
||||
static success(m) {
|
||||
Logger.log(i18n.__(m) || m, 'green');
|
||||
}
|
||||
static warning(m) {
|
||||
Logger.warn(ComponentLogger.CONTENT, i18n.__(m) || m);
|
||||
}
|
||||
|
||||
static success(m) {
|
||||
Logger.log(i18n.__(m) || m, 'green');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
133
src/index.ts
133
src/index.ts
|
@ -1,45 +1,93 @@
|
|||
import logger from './common/logger';
|
||||
import _ from 'lodash';
|
||||
import * as core from '@serverless-devs/core';
|
||||
import logger from './common/logger';
|
||||
import help from './common/help';
|
||||
import { InputProps, ICredentials, isProperties, IProperties } from './interface/entity';
|
||||
import RemoteInvoke from './lib/remote-invoke';
|
||||
|
||||
export default class FcRemoteInvoke {
|
||||
async report(componentName: string, command: string, accountID?: string, access?: string): Promise<void> {
|
||||
let uid: string = accountID;
|
||||
if (_.isEmpty(accountID)) {
|
||||
const credentials = await core.getCredential(access);
|
||||
uid = credentials.AccountID;
|
||||
}
|
||||
|
||||
async report(componentName: string, command: string, accountID: string): Promise<void> {
|
||||
core.reportComponent(componentName, {
|
||||
command,
|
||||
uid,
|
||||
uid: accountID,
|
||||
});
|
||||
}
|
||||
|
||||
async handlerInputs(inputs): Promise<any> {
|
||||
const project = inputs?.project;
|
||||
const properties = inputs?.props;
|
||||
const access: string = project?.access;
|
||||
const appName: string = inputs?.appName;
|
||||
const credentials = await core.getCredential(access);
|
||||
// 去除 args 的行首以及行尾的空格
|
||||
const args: string = inputs?.args.replace(/(^\s*)|(\s*$)/g, '');
|
||||
const curPath: any = inputs?.path;
|
||||
const projectName: string = project?.projectName;
|
||||
const { region } = properties;
|
||||
async handlerInputs(inputs: InputProps): Promise<any> {
|
||||
const credentials: ICredentials = await core.getCredential(inputs?.project?.access);
|
||||
|
||||
if (args?.includes('help')) {
|
||||
// 去除 args 的行首以及行尾的空格
|
||||
const args: string = (inputs?.args || '').replace(/(^\s*)|(\s*$)/g, '');
|
||||
logger.debug(`input args: ${args}`);
|
||||
|
||||
const parsedArgs: {[key: string]: any} = core.commandParse({ args }, {
|
||||
boolean: ['help', 'event-stdin'],
|
||||
string: ['invocation-type', 'event', 'event-file', 'region', 'service-name', 'function-name', 'qualifier'],
|
||||
alias: {
|
||||
'help': 'h',
|
||||
'event': 'e',
|
||||
'invocation-type': 't',
|
||||
'event-file': 'f',
|
||||
'event-stdin': 's',
|
||||
}
|
||||
});
|
||||
|
||||
const argsData: any = parsedArgs?.data || {};
|
||||
logger.debug(`command parse: ${JSON.stringify(argsData)}`);
|
||||
if (argsData.help) {
|
||||
return {
|
||||
region,
|
||||
credentials,
|
||||
curPath,
|
||||
args,
|
||||
access,
|
||||
isHelp: true,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
return {};
|
||||
const {
|
||||
e: event,
|
||||
f: eventFile,
|
||||
s: eventStdin,
|
||||
t: invocationType = 'sync',
|
||||
} = argsData;
|
||||
const eventPayload = { event, eventFile, eventStdin };
|
||||
// @ts-ignore: 判断三个值有几个真
|
||||
const eventFlag = !!event + !!eventFile + !!eventStdin;
|
||||
|
||||
if (eventFlag > 1) {
|
||||
throw new Error('event | event-file | event-stdin must choose one.');
|
||||
} else if (eventFlag === 0) {
|
||||
eventPayload.event = '';
|
||||
}
|
||||
|
||||
if (!['sync', 'async'].includes(invocationType)) {
|
||||
throw new Error('invocation-type enum value sync, async.');
|
||||
}
|
||||
|
||||
logger.debug(`input props: ${JSON.stringify(inputs.props)}`);
|
||||
|
||||
let props: IProperties = {
|
||||
region: argsData.region,
|
||||
serviceName: argsData['service-name'],
|
||||
functionName: argsData['function-name'],
|
||||
};
|
||||
logger.debug(`input args props: ${JSON.stringify(props)}`);
|
||||
|
||||
if (!isProperties(props)) {
|
||||
props = inputs.props;
|
||||
}
|
||||
logger.debug(`props: ${JSON.stringify(props)}`);
|
||||
|
||||
if (!isProperties(props)) {
|
||||
throw new Error('region/serviceName(service-name)/functionName(function-name) can not be empty.');
|
||||
}
|
||||
|
||||
props.qualifier = argsData.qualifier || inputs.props?.qualifier;
|
||||
|
||||
return {
|
||||
props,
|
||||
credentials,
|
||||
eventPayload,
|
||||
isHelp: false,
|
||||
invocationType: _.upperFirst(invocationType),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -47,29 +95,22 @@ export default class FcRemoteInvoke {
|
|||
* @param inputs
|
||||
* @returns
|
||||
*/
|
||||
public async invoke(inputs): Promise<any> {
|
||||
public async invoke(inputs: InputProps): Promise<any> {
|
||||
const {
|
||||
args,
|
||||
credentials
|
||||
props,
|
||||
eventPayload,
|
||||
credentials,
|
||||
isHelp,
|
||||
invocationType,
|
||||
} = await this.handlerInputs(inputs);
|
||||
await this.report('fc-remote-invoke', 'invoke', credentials?.AccountID);
|
||||
const parsedArgs: {[key: string]: any} = core.commandParse({ args }, {
|
||||
boolean: ['debug'],
|
||||
alias: { 'help': 'h',
|
||||
'config': 'c',
|
||||
'mode': 'm',
|
||||
'event': 'e',
|
||||
'event-file': 'f',
|
||||
'event-stdin': 's',
|
||||
'debug-port': 'd'
|
||||
}
|
||||
});
|
||||
const argsData: any = parsedArgs?.data || {};
|
||||
if (argsData.help) {
|
||||
// TODO: help info
|
||||
// await this.report('fc-remote-invoke', 'invoke', credentials?.AccountID);
|
||||
|
||||
if (isHelp) {
|
||||
core.help(help)
|
||||
return;
|
||||
}
|
||||
|
||||
return {};
|
||||
const remoteInvoke = new RemoteInvoke(props.region, credentials);
|
||||
await remoteInvoke.invoke(props, eventPayload, { invocationType });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
export interface ICredentials {
|
||||
AccountID?: string,
|
||||
AccessKeyID?: string,
|
||||
AccessKeySecret?: string,
|
||||
SecurityToken?: string,
|
||||
}
|
||||
|
||||
export interface InputProps {
|
||||
props?: IProperties, // 用户自定义输入
|
||||
credentials: ICredentials, // 用户秘钥
|
||||
appName: string, //
|
||||
project: {
|
||||
component: string, // 组件名(支持本地绝对路径)
|
||||
access: string, // 访问秘钥名
|
||||
projectName: string, // 项目名
|
||||
},
|
||||
command: string, // 执行指令
|
||||
args: string, // 命令行 扩展参数
|
||||
path: {
|
||||
configPath: string // 配置路径
|
||||
}
|
||||
}
|
||||
|
||||
export interface IProperties {
|
||||
region: string;
|
||||
serviceName: string;
|
||||
functionName: string;
|
||||
qualifier?: string;
|
||||
}
|
||||
export function isProperties(args: any): args is IProperties {
|
||||
return args && args.region && args.serviceName && args.functionName;
|
||||
}
|
||||
|
||||
export interface IEventPayload {
|
||||
event?: string,
|
||||
eventFile?: string,
|
||||
eventStdin?: boolean,
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
import FC from '@alicloud/fc2';
|
||||
import { ICredentials } from '../interface/entity';
|
||||
|
||||
export default class Client {
|
||||
static buildFcClient(region: string, credentials: ICredentials) {
|
||||
return new FC(credentials.AccountID, {
|
||||
accessKeyID: credentials.AccessKeyID,
|
||||
accessKeySecret: credentials.AccessKeySecret,
|
||||
securityToken: credentials.SecurityToken,
|
||||
region,
|
||||
timeout: 6000000,
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
import path from 'path';
|
||||
import fs from 'fs-extra';
|
||||
import { isString } from 'lodash';
|
||||
import readline from 'readline';
|
||||
import logger from '../common/logger';
|
||||
import { getStdin } from './stdin';
|
||||
|
||||
export default class File {
|
||||
|
||||
static async getEvent(eventFile) {
|
||||
let event = await getStdin(); // read from pipes
|
||||
|
||||
if (!eventFile) return event;
|
||||
|
||||
return await new Promise((resolve, reject) => {
|
||||
let input;
|
||||
|
||||
if (eventFile === '-') { // read from stdin
|
||||
logger.log('Reading event data from stdin, which can be ended with Enter then Ctrl+D')
|
||||
input = process.stdin;
|
||||
} else {
|
||||
input = fs.createReadStream(eventFile, {
|
||||
encoding: 'utf-8'
|
||||
})
|
||||
}
|
||||
const rl = readline.createInterface({
|
||||
input,
|
||||
output: process.stdout
|
||||
})
|
||||
|
||||
event = '';
|
||||
rl.on('line', (line) => {
|
||||
event += line
|
||||
})
|
||||
rl.on('close', () => resolve(event))
|
||||
|
||||
rl.on('SIGINT', () => reject(new Error('^C')))
|
||||
})
|
||||
}
|
||||
|
||||
static async eventPriority(eventPriority) {
|
||||
let eventFile: string;
|
||||
|
||||
if (isString(eventPriority.event)) {
|
||||
return eventPriority.event;
|
||||
} else if (eventPriority.eventStdin) {
|
||||
eventFile = '-';
|
||||
} else if (eventPriority.eventFile) {
|
||||
eventFile = path.resolve(process.cwd(), eventPriority.eventFile);
|
||||
}
|
||||
|
||||
return await this.getEvent(eventFile)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
import _ from 'lodash';
|
||||
import Client from './client';
|
||||
import { IProperties, IEventPayload } from '../interface/entity';
|
||||
import Event from './event';
|
||||
import logger from '../common/logger';
|
||||
|
||||
export default class RemoteInvoke {
|
||||
fcClient: any;
|
||||
accountId: string;
|
||||
|
||||
constructor(region: string, credentials) {
|
||||
this.accountId = credentials.AccountID;
|
||||
this.fcClient = Client.buildFcClient(region, credentials);
|
||||
}
|
||||
|
||||
async invoke (props: IProperties, eventPayload: IEventPayload, { invocationType }) {
|
||||
const event = await Event.eventPriority(eventPayload);
|
||||
logger.debug(`event: ${event}`);
|
||||
|
||||
const {
|
||||
region,
|
||||
serviceName,
|
||||
functionName,
|
||||
qualifier,
|
||||
} = props;
|
||||
const httpTriggers = await this.getHttpTrigger(serviceName, functionName)
|
||||
|
||||
const payload: any = { event, serviceName, functionName, qualifier };
|
||||
if (_.isEmpty(httpTriggers)) {
|
||||
payload.invocationType = invocationType;
|
||||
payload.event = event;
|
||||
await this.eventInvoke(payload);
|
||||
} else {
|
||||
payload.region = region;
|
||||
try {
|
||||
payload.event = event ? JSON.parse(event) : {};
|
||||
} catch (ex) {
|
||||
logger.debug(ex);
|
||||
throw new Error('handler event error. Example: https://github.com/devsapp/fc-remote-invoke/blob/master/example/http.json');
|
||||
}
|
||||
|
||||
await this.httpInvoke(payload);
|
||||
}
|
||||
}
|
||||
|
||||
async getHttpTrigger(serviceName, functionName) {
|
||||
const { data } = await this.fcClient.listTriggers(serviceName, functionName);
|
||||
logger.debug(`get listTriggers: ${JSON.stringify(data)}`);
|
||||
|
||||
if (_.isEmpty(data.triggers)) { return [] }
|
||||
|
||||
const httpTrigger = data.triggers.filter(t => t.triggerType === 'http' || t.triggerType === 'https')
|
||||
if (_.isEmpty(httpTrigger)) { return [] }
|
||||
|
||||
return httpTrigger;
|
||||
}
|
||||
|
||||
async eventInvoke({
|
||||
serviceName,
|
||||
functionName,
|
||||
event,
|
||||
qualifier = 'LATEST',
|
||||
invocationType
|
||||
}) {
|
||||
|
||||
if (invocationType === 'Sync') {
|
||||
const rs = await this.fcClient.invokeFunction(serviceName, functionName, event, {
|
||||
'X-Fc-Log-Type': 'Tail',
|
||||
'X-Fc-Invocation-Type': invocationType
|
||||
}, qualifier);
|
||||
|
||||
const log = rs.headers['x-fc-log-result'];
|
||||
|
||||
if (log) {
|
||||
logger.log('========= FC invoke Logs begin =========', 'yellow');
|
||||
const decodedLog = Buffer.from(log, 'base64');
|
||||
logger.log(decodedLog.toString());
|
||||
logger.log('========= FC invoke Logs end =========', 'yellow');
|
||||
|
||||
logger.log('\nFC Invoke Result:', 'green');
|
||||
console.log(rs.data);
|
||||
console.log('\n');
|
||||
}
|
||||
} else {
|
||||
await this.fcClient.invokeFunction(serviceName, functionName, event, {
|
||||
'X-Fc-Invocation-Type': invocationType
|
||||
}, qualifier);
|
||||
|
||||
logger.log('`${serviceName}/${functionName} async invoke success.\n`', 'green');
|
||||
}
|
||||
}
|
||||
|
||||
async httpInvoke({ region, serviceName, functionName, event, qualifier }) {
|
||||
const q = qualifier ? `.${qualifier}` : '';
|
||||
event.path = `/proxy/${serviceName}${q}/${functionName}/${event.path || ''}`;
|
||||
|
||||
logger.log(`https://${this.accountId}.${region}.fc.aliyuncs.com/2016-08-15/proxy/${serviceName}${q}/${functionName}/`);
|
||||
await this.request(event)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param event: { body, headers, method, queries, path }
|
||||
* path 组装后的路径 /proxy/serviceName/functionName/path ,
|
||||
*/
|
||||
async request (event) {
|
||||
const { headers, queries, method, path: p, body } = this.handlerHttpParmase(event);
|
||||
|
||||
let resp;
|
||||
try {
|
||||
const mt = method.toLocaleUpperCase();
|
||||
logger.debug(`method is ${mt}.`);
|
||||
logger.debug(`start invoke.`);
|
||||
if (mt === 'GET') {
|
||||
resp = await this.fcClient.get(p, queries, headers);
|
||||
} else if (mt === 'POST') {
|
||||
resp = await this.fcClient.post(p, body, headers, queries);
|
||||
} else if (mt === 'PUT') {
|
||||
resp = await this.fcClient.put(p, body, headers);
|
||||
} else if (mt === 'DELETE') {
|
||||
resp = await this.fcClient.request('DELETE', p, queries, null, headers);
|
||||
/* else if (method.toLocaleUpperCase() === 'PATCH') {
|
||||
resp = await this.fcClient.request('PATCH', p, queries, body, headers);
|
||||
} else if (method.toLocaleUpperCase() === 'HEAD') {
|
||||
resp = await this.fcClient.request('HEAD', p, queries, body, headers);
|
||||
} */
|
||||
} else {
|
||||
logger.log(`Does not support ${method} requests temporarily.`);
|
||||
}
|
||||
} catch (e) {
|
||||
logger.debug(e);
|
||||
if (e.message === 'Unexpected token r in JSON at position 0' && e.stack.includes('/fc2/lib/client.js') && e.stack.includes('at Client.request')) {
|
||||
throw new Error('The body in http responss is not in json format, but the content-type in response header is application/json. We recommend that you make the format of the response body be consistent with the content-type in response header.');
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
logger.debug(`end invoke.`);
|
||||
|
||||
if (resp) {
|
||||
const log = resp.headers['x-fc-log-result'];
|
||||
if (log) {
|
||||
logger.log('\n========= FC invoke Logs begin =========', 'yellow');
|
||||
const decodedLog = Buffer.from(log, 'base64')
|
||||
logger.log(decodedLog.toString())
|
||||
logger.log('========= FC invoke Logs end =========', 'yellow');
|
||||
}
|
||||
logger.log('\nFC Invoke Result:', 'green');
|
||||
console.log(resp.data);
|
||||
console.log('\n');
|
||||
}
|
||||
}
|
||||
|
||||
handlerHttpParmase (event) {
|
||||
const { body = '', headers = {}, method = 'GET', queries = '', path: p = '' } = event;
|
||||
|
||||
let postBody;
|
||||
if (body) {
|
||||
let buff = null;
|
||||
if (Buffer.isBuffer(body)) {
|
||||
buff = body;
|
||||
headers['content-type'] = 'application/octet-stream';
|
||||
} else if (typeof body === 'string') {
|
||||
buff = Buffer.from(body, 'utf8');
|
||||
headers['content-type'] = 'application/octet-stream';
|
||||
} else if (typeof body.pipe === 'function') {
|
||||
buff = body;
|
||||
headers['content-type'] = 'application/octet-stream';
|
||||
} else {
|
||||
buff = Buffer.from(JSON.stringify(body), 'utf8');
|
||||
headers['content-type'] = 'application/json';
|
||||
}
|
||||
postBody = buff;
|
||||
}
|
||||
|
||||
if (!headers['X-Fc-Log-Type']) {
|
||||
headers['X-Fc-Log-Type'] = 'Tail';
|
||||
}
|
||||
|
||||
return {
|
||||
headers,
|
||||
queries,
|
||||
method,
|
||||
path: p,
|
||||
body: postBody
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
const {stdin} = process;
|
||||
|
||||
export async function getStdin() {
|
||||
let result = '';
|
||||
|
||||
if (stdin.isTTY) {
|
||||
return result;
|
||||
}
|
||||
|
||||
stdin.setEncoding('utf8');
|
||||
|
||||
for await (const chunk of stdin) {
|
||||
result += chunk;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
getStdin.buffer = async () => {
|
||||
const result = [];
|
||||
let length = 0;
|
||||
|
||||
if (stdin.isTTY) {
|
||||
return Buffer.concat([]);
|
||||
}
|
||||
|
||||
for await (const chunk of stdin) {
|
||||
result.push(chunk);
|
||||
length += chunk.length;
|
||||
}
|
||||
|
||||
return Buffer.concat(result, length);
|
||||
};
|
Loading…
Reference in New Issue