Skip to content
This repository was archived by the owner on May 6, 2025. It is now read-only.

Commit 4b132a5

Browse files
committed
feat: support login api and function path config
1 parent 711f997 commit 4b132a5

18 files changed

Lines changed: 329 additions & 132 deletions

File tree

bin/tcb.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#!/usr/bin/env node
2+
const ora = require('ora')
23
const program = require('commander')
34
const chalk = require('chalk')
45
const logSymbols = require('log-symbols')
@@ -57,6 +58,7 @@ if (process.argv.length < 3) {
5758
program.parse(process.argv)
5859

5960
function errorHandler(err) {
61+
ora.stop()
6062
const stackIngoreErrors = ['TencentCloudSDKHttpException', 'TcbError']
6163
// 忽略自定义错误的错误栈
6264
if (err.stack && !stackIngoreErrors.includes(err.name)) {

lib/auth/login.js

Lines changed: 50 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,102 @@
11
"use strict";
2-
var __importDefault = (this && this.__importDefault) || function (mod) {
3-
return (mod && mod.__esModule) ? mod : { "default": mod };
4-
};
52
Object.defineProperty(exports, "__esModule", { value: true });
6-
const ora_1 = __importDefault(require("ora"));
7-
const logger_1 = __importDefault(require("../logger"));
83
const auth_1 = require("./auth");
94
const utils_1 = require("../utils");
105
const constant_1 = require("../constant");
116
const configstore_1 = require("../utils/configstore");
12-
const error_1 = require("../error");
137
const tcbService = new utils_1.CloudService('tcb', '2018-06-08');
14-
const logger = new logger_1.default('Login');
158
async function checkAuth(credential) {
169
const { tmpSecretId, tmpSecretKey, tmpToken } = credential;
1710
tcbService.setCredential(tmpSecretId, tmpSecretKey, tmpToken);
1811
return await tcbService.request('DescribeEnvs');
1912
}
20-
async function authLogin() {
13+
const LoginRes = {
14+
SUCCESS: {
15+
code: 'SUCCESS',
16+
msg: '登录成功!'
17+
},
18+
INVALID_TOKEN: {
19+
code: 'INVALID_TOKEN',
20+
msg: '无效的身份信息!'
21+
},
22+
CHECK_LOGIN_FAILED: {
23+
code: 'CHECK_LOGIN_FAILED',
24+
msg: '检查登录态失败'
25+
},
26+
INVALID_PARAM(msg) {
27+
return {
28+
code: 'INVALID_PARAM',
29+
msg: `参数无效:${msg}`
30+
};
31+
},
32+
UNKNOWN_ERROR(msg) {
33+
return {
34+
code: 'UNKNOWN_ERROR',
35+
msg: `未知错误:${msg}`
36+
};
37+
}
38+
};
39+
async function loginWithToken() {
2140
const tcbrc = utils_1.getCredentialConfig();
2241
if (tcbrc.secretId && tcbrc.secretKey) {
23-
logger.log('您已登录,无需再次登录!');
24-
return;
42+
return LoginRes.SUCCESS;
2543
}
2644
const tmpExpired = Number(tcbrc.tmpExpired) || 0;
2745
let refreshExpired = Number(tcbrc.expired) || 0;
2846
const now = Date.now();
2947
if (now < tmpExpired) {
30-
logger.log('您已登录,无需再次登录!');
31-
return;
48+
return LoginRes.SUCCESS;
3249
}
3350
let credential;
34-
const authSpinner = ora_1.default('获取授权中');
3551
try {
3652
if (now < refreshExpired) {
37-
authSpinner.start();
3853
credential = await auth_1.refreshTmpToken(tcbrc);
3954
}
4055
else {
41-
authSpinner.start();
4256
credential = await auth_1.getAuthTokenFromWeb();
4357
}
44-
authSpinner.succeed('获取授权成功');
4558
}
46-
catch (error) {
47-
authSpinner.fail(`获取授权失败 ${error}`);
48-
throw new error_1.TcbError(error);
59+
catch (e) {
60+
return LoginRes.UNKNOWN_ERROR(e.message);
4961
}
5062
if (!credential.refreshToken || !credential.uin) {
51-
logger.error('授权信息无效');
52-
return;
63+
return LoginRes.INVALID_TOKEN;
5364
}
54-
const scfCheckSpinner = ora_1.default('验证密匙权限').start();
5565
try {
5666
await checkAuth(credential);
57-
scfCheckSpinner.succeed('密钥权限验证成功');
5867
}
5968
catch (e) {
60-
throw new error_1.TcbError(e.message);
69+
return LoginRes.UNKNOWN_ERROR(e.message);
6170
}
6271
configstore_1.configStore.set(constant_1.ConfigItems.credentail, credential);
63-
logger.success('登录成功!');
72+
return LoginRes.SUCCESS;
6473
}
65-
exports.authLogin = authLogin;
66-
async function login() {
74+
exports.loginWithToken = loginWithToken;
75+
async function loginWithKey(secretId, secretKey) {
6776
const tcbrc = await utils_1.getCredentialConfig();
6877
if (tcbrc.secretId && tcbrc.secretKey) {
69-
logger.log('您已登录,无需再次登录!');
70-
return;
78+
return LoginRes.SUCCESS;
7179
}
72-
const secretId = (await utils_1.askForInput('请输入腾讯云 SecretID:'));
73-
const secretKey = (await utils_1.askForInput('请输入腾讯云 SecretKey:'));
74-
const skey = (await utils_1.askForInput('请输入腾讯云 SKey:'));
7580
if (!secretId || !secretKey) {
76-
logger.error('SecretID 或 SecretKey 不能为空');
77-
return;
81+
return LoginRes.INVALID_PARAM('SecretID 或 SecretKey 不能为空');
7882
}
79-
const cloudSpinner = ora_1.default('正在验证腾讯云密钥...').start();
8083
try {
8184
await checkAuth({ tmpSecretId: secretId, tmpSecretKey: secretKey });
82-
cloudSpinner.succeed('腾讯云密钥验证成功');
8385
}
8486
catch (e) {
85-
cloudSpinner.fail('腾讯云密钥验证失败,请检查密钥是否正确或本机网络代理有问题');
86-
return;
87+
return LoginRes.CHECK_LOGIN_FAILED;
8788
}
8889
configstore_1.configStore.set(constant_1.ConfigItems.credentail, { secretId, secretKey });
89-
logger.success('登录成功!');
90-
return skey;
90+
return LoginRes.SUCCESS;
91+
}
92+
exports.loginWithKey = loginWithKey;
93+
async function login(options) {
94+
if (options && options.key) {
95+
const { secretId, secretKey } = options;
96+
return await loginWithKey(secretId, secretKey);
97+
}
98+
else {
99+
return await loginWithToken();
100+
}
91101
}
92102
exports.login = login;

lib/commands/functions.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
44
};
55
Object.defineProperty(exports, "__esModule", { value: true });
66
const ora_1 = __importDefault(require("ora"));
7+
const path_1 = __importDefault(require("path"));
78
const commander_1 = __importDefault(require("commander"));
89
const inquirer_1 = __importDefault(require("inquirer"));
910
const chalk_1 = __importDefault(require("chalk"));
@@ -48,6 +49,7 @@ commander_1.default
4849
.description('创建云函数')
4950
.action(async function (name, envId, options) {
5051
const assignEnvId = await utils_1.getEnvId(envId);
52+
const config = await utils_1.resolveTcbrcConfig();
5153
const functions = await getConfigFunctions();
5254
const { force } = options;
5355
let isBatchCreating = false;
@@ -66,7 +68,7 @@ commander_1.default
6668
if (isBatchCreating) {
6769
return await function_1.batchCreateFunctions({
6870
functions,
69-
root: process.cwd(),
71+
functionRootPath: path_1.default.join(process.cwd(), config.functionRoot),
7072
envId: assignEnvId,
7173
force,
7274
log: true
@@ -80,7 +82,7 @@ commander_1.default
8082
try {
8183
await function_1.createFunction({
8284
func: newFunction,
83-
root: process.cwd(),
85+
functionRootPath: path_1.default.join(process.cwd(), config.functionRoot),
8486
envId: assignEnvId,
8587
force
8688
});
@@ -100,7 +102,7 @@ commander_1.default
100102
try {
101103
await function_1.createFunction({
102104
func: newFunction,
103-
root: process.cwd(),
105+
functionRootPath: path_1.default.join(process.cwd(), config.functionRoot),
104106
envId: assignEnvId,
105107
force: true
106108
});
@@ -121,6 +123,7 @@ commander_1.default
121123
.description('创建云函数')
122124
.action(async function (name, envId) {
123125
const assignEnvId = await utils_1.getEnvId(envId);
126+
const config = await utils_1.resolveTcbrcConfig();
124127
const functions = await getConfigFunctions();
125128
if (!name) {
126129
throw new error_1.TcbError('请指定函数名称!');
@@ -133,7 +136,7 @@ commander_1.default
133136
try {
134137
await function_1.updateFunctionCode({
135138
func,
136-
root: process.cwd(),
139+
functionRootPath: path_1.default.join(process.cwd(), config.functionRoot),
137140
envId: assignEnvId
138141
});
139142
spinner.succeed(`[${func.name}] 函数代码更新成功!`);

lib/commands/login.js

Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,95 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
44
};
55
Object.defineProperty(exports, "__esModule", { value: true });
66
const commander_1 = __importDefault(require("commander"));
7+
const inquirer_1 = __importDefault(require("inquirer"));
8+
const ora_1 = __importDefault(require("ora"));
79
const auth_1 = require("../auth");
810
const env_1 = require("../env");
11+
const error_1 = require("../error");
12+
const utils_1 = require("../utils");
13+
const logger_1 = require("../logger");
14+
async function checkLogin() {
15+
const tcbrc = utils_1.getCredentialConfig();
16+
if (tcbrc.secretId && tcbrc.secretKey) {
17+
return true;
18+
}
19+
const tmpExpired = Number(tcbrc.tmpExpired) || 0;
20+
const now = Date.now();
21+
if (now < tmpExpired) {
22+
return true;
23+
}
24+
return false;
25+
}
926
commander_1.default
1027
.command('login')
11-
.option('-k, --key', '使用永久密钥登录(不建议!)')
28+
.option('-k, --key', '使用永久密钥登录')
29+
.option('--skey', '使用永久密钥 + skey 登录')
1230
.description('登录腾讯云账号')
1331
.action(async function (options) {
32+
const checkSpin = ora_1.default('检验登录状态').start();
33+
const hasLogin = await checkLogin();
34+
checkSpin.succeed('您已登录,无需再次登录!');
35+
if (hasLogin)
36+
return;
1437
let skey;
15-
if (options.key) {
16-
skey = await auth_1.login();
38+
if (options.key || options.skey) {
39+
const { secretId } = await inquirer_1.default.prompt({
40+
type: 'input',
41+
name: 'secretId',
42+
message: '请输入腾讯云 SecretID:'
43+
});
44+
const { secretKey } = await inquirer_1.default.prompt({
45+
type: 'input',
46+
name: 'secretKey',
47+
message: '请输入腾讯云 SecretKey:'
48+
});
49+
if (options.skey) {
50+
const { skey: _skey } = await inquirer_1.default.prompt({
51+
type: 'input',
52+
name: 'skey',
53+
message: '请输入腾讯云 skey(选填):'
54+
});
55+
skey = _skey;
56+
}
57+
if (!secretId || !secretKey) {
58+
throw new error_1.TcbError('SecretID 或 SecretKey 不能为空');
59+
}
60+
const cloudSpinner = ora_1.default('正在验证腾讯云密钥...').start();
61+
const res = await auth_1.login({
62+
key: true,
63+
secretId,
64+
secretKey
65+
});
66+
if (res.code === 'SUCCESS') {
67+
cloudSpinner.succeed('登录成功!');
68+
}
69+
else {
70+
cloudSpinner.fail('腾讯云密钥验证失败,请检查密钥是否正确或终端网络是否可用!');
71+
return;
72+
}
1773
}
1874
else {
19-
await auth_1.authLogin();
75+
const authSpinner = ora_1.default('获取授权中!');
76+
const res = await auth_1.login();
77+
if (res.code === 'SUCCESS') {
78+
authSpinner.succeed('登录成功!');
79+
}
80+
else {
81+
authSpinner.fail(res.msg);
82+
return;
83+
}
2084
}
2185
try {
2286
const envs = await env_1.listEnvs();
2387
if (!envs.length) {
24-
console.log('你还没有可用的环境,请使用 tcb env:create alias 创建环境');
88+
logger_1.warnLog('你还没有可用的环境,请使用 tcb env:create alias 创建环境');
2589
}
2690
}
2791
catch (e) {
2892
if (e.code === 'ResourceNotFound.UserNotExists') {
29-
console.log('初始化 TCB 服务');
93+
const initSpin = ora_1.default('初始化 TCB 服务').start();
3094
await env_1.initTcb(skey);
31-
console.log('初始化成功');
95+
initSpin.succeed('初始化成功');
3296
}
3397
else {
3498
throw e;

lib/function/_packer.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class FunctionPacker {
1818
constructor(root, name) {
1919
this.name = name;
2020
this.root = root;
21-
this.funcPath = path_1.default.join(root, 'functions', name);
21+
this.funcPath = path_1.default.join(root, name);
2222
}
2323
validPath(path) {
2424
if (!fs_1.default.existsSync(path)) {

lib/function/create.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const scfService = new utils_1.CloudService('scf', '2018-04-16', {
1313
Stamp: 'MINI_QCBASE'
1414
});
1515
async function createFunction(options) {
16-
const { func, root = '', envId, force = false, base64Code = '' } = options;
16+
const { func, functionRootPath = '', envId, force = false, base64Code = '' } = options;
1717
let base64;
1818
let packer;
1919
const funcName = func.name;
@@ -22,7 +22,7 @@ async function createFunction(options) {
2222
throw new error_1.TcbError(`${funcName} Invalid runtime value:${func.config.runtime}. Now only support: ${validRuntime.join(', ')}`);
2323
}
2424
if (!base64Code) {
25-
packer = new _packer_1.FunctionPacker(root, funcName);
25+
packer = new _packer_1.FunctionPacker(functionRootPath, funcName);
2626
const type = func.config.runtime === 'Java8' ? _packer_1.CodeType.JavaFile : _packer_1.CodeType.File;
2727
base64 = await packer.build(type);
2828
if (!base64) {
@@ -83,14 +83,14 @@ async function createFunction(options) {
8383
}
8484
exports.createFunction = createFunction;
8585
async function batchCreateFunctions(options) {
86-
const { functions, root, envId, force, log = false } = options;
86+
const { functions, functionRootPath = '', envId, force, log = false } = options;
8787
const promises = functions.map(func => (async () => {
8888
const spinner = ora_1.default(`[${func.name}] 函数部署中...`);
8989
try {
9090
log && spinner.start();
9191
await createFunction({
9292
func,
93-
root,
93+
functionRootPath,
9494
envId,
9595
force
9696
});
@@ -105,7 +105,7 @@ async function batchCreateFunctions(options) {
105105
}
106106
exports.batchCreateFunctions = batchCreateFunctions;
107107
async function updateFunctionCode(options) {
108-
const { func, root = '', envId, base64Code = '' } = options;
108+
const { func, functionRootPath = '', envId, base64Code = '' } = options;
109109
let base64;
110110
let packer;
111111
const funcName = func.name;
@@ -114,7 +114,7 @@ async function updateFunctionCode(options) {
114114
throw new error_1.TcbError(`${funcName} 非法的运行环境:${func.config.runtime},当前支持环境:${validRuntime.join(', ')}`);
115115
}
116116
if (!base64Code) {
117-
packer = new _packer_1.FunctionPacker(root, funcName);
117+
packer = new _packer_1.FunctionPacker(functionRootPath, funcName);
118118
const type = func.config.runtime === 'Java8' ? _packer_1.CodeType.JavaFile : _packer_1.CodeType.File;
119119
base64 = await packer.build(type);
120120
if (!base64) {

lib/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
"use strict";
22
require("./commands");
3+
const auth_1 = require("./auth");
34
const env_1 = require("./env");
45
const function_1 = require("./function");
56
const configstore_1 = require("./utils/configstore");
67
module.exports = class Client {
78
constructor(secretId, secretKey) {
9+
this.login = auth_1.login;
810
this.env = {
911
list: env_1.listEnvs,
1012
create: env_1.createEnv,

0 commit comments

Comments
 (0)