"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.FunctionService = void 0;
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const packer_1 = require("./packer");
const error_1 = require("../error");
const utils_1 = require("../utils");
const constant_1 = require("../constant");
// 是否为 Node 函数
function isNodeFunction(runtime) {
    // 不严格限制
    return runtime === 'Nodejs10.15' || runtime === 'Nodejs8.9' || (runtime === null || runtime === void 0 ? void 0 : runtime.includes('Nodejs'));
}
// 解析函数配置，换成请求参数
function configToParams(options) {
    var _a, _b, _c, _d, _e;
    const { func, codeSecret, baseParams } = options;
    let installDependency;
    // Node 函数默认安装依赖
    installDependency = isNodeFunction(func.runtime) ? 'TRUE' : 'FALSE';
    // 是否安装依赖，选项可以覆盖
    if (typeof func.installDependency !== 'undefined') {
        installDependency = func.installDependency ? 'TRUE' : 'FALSE';
    }
    // 转换环境变量
    const envVariables = Object.keys(func.envVariables || {}).map(key => ({
        Key: key,
        Value: func.envVariables[key]
    }));
    // 当不存在 L5 配置时，不修改 L5 状态，否则根据 true/false 进行修改
    const l5Enable = typeof (func === null || func === void 0 ? void 0 : func.l5) === 'undefined' ? null : (func === null || func === void 0 ? void 0 : func.l5) ? 'TRUE' : 'FALSE';
    const params = Object.assign(Object.assign({}, baseParams), { FunctionName: func.name, 
        // 不可选择
        L5Enable: l5Enable });
    // 函数绑定的角色
    params.Role = func.role || params.Role;
    // 修复参数存在 undefined 字段时，会出现鉴权失败的情况
    // Environment 为覆盖式修改，不保留已有字段
    envVariables.length && (params.Environment = { Variables: envVariables });
    // 处理入口
    params.Handler = func.handler || 'index.main';
    // 默认超时时间为 10S
    params.Timeout = Number(func.timeout) || 10;
    // 默认运行环境 Nodejs8.9
    params.Runtime = func.runtime || 'Nodejs8.9';
    if (((_a = func === null || func === void 0 ? void 0 : func.vpc) === null || _a === void 0 ? void 0 : _a.subnetId) !== undefined && ((_b = func === null || func === void 0 ? void 0 : func.vpc) === null || _b === void 0 ? void 0 : _b.vpcId) !== undefined) {
        // VPC 网络
        params.VpcConfig = {
            SubnetId: (_c = func === null || func === void 0 ? void 0 : func.vpc) === null || _c === void 0 ? void 0 : _c.subnetId,
            VpcId: (_d = func === null || func === void 0 ? void 0 : func.vpc) === null || _d === void 0 ? void 0 : _d.vpcId
        };
    }
    // 运行内存
    params.MemorySize = func.memorySize || 256;
    // 自动安装依赖
    params.InstallDependency = installDependency;
    // 代码保护
    if (codeSecret || func.codeSecret) {
        params.CodeSecret = codeSecret || func.codeSecret;
    }
    // 函数层
    if ((_e = func === null || func === void 0 ? void 0 : func.layers) === null || _e === void 0 ? void 0 : _e.length) {
        const transformLayers = func.layers.map(item => ({
            LayerName: item.name,
            LayerVersion: item.version
        }));
        params.Layers = transformLayers;
    }
    return params;
}
class FunctionService {
    constructor(environment) {
        this.environment = environment;
        this.scfService = new utils_1.CloudService(environment.cloudBaseContext, 'scf', '2018-04-16');
        this.vpcService = new utils_1.CloudService(environment.cloudBaseContext, 'vpc', '2017-03-12');
    }
    /**
     * 增量更新函数代码
     * @param {IUpdateFunctionIncrementalCodeParam} funcParam
     * @returns {Promise<void>}
     * @memberof FunctionService
     */
    async updateFunctionIncrementalCode(funcParam) {
        const { namespace } = this.getFunctionConfig();
        const { functionRootPath, func, deleteFiles, addFiles } = funcParam;
        const { name, runtime } = func;
        const params = {
            FunctionName: name,
            Namespace: namespace
        };
        let packer;
        let base64;
        if (deleteFiles) {
            params.DeleteFiles = deleteFiles;
        }
        if (addFiles) {
            // 将选中的增量文件或增量文件夹  转base64
            const codeType = runtime === 'Java8' ? packer_1.CodeType.JavaFile : packer_1.CodeType.File;
            packer = new packer_1.FunctionPacker({
                codeType,
                name,
                root: functionRootPath,
                ignore: [],
                incrementalPath: addFiles
            });
            await packer.build();
            base64 = await packer.getBase64Code();
            if (!base64) {
                throw new error_1.CloudBaseError('函数不存在！');
            }
            params.AddFiles = base64;
        }
        return this.scfService.request('UpdateFunctionIncrementalCode', params);
    }
    /**
     * 创建云函数
     * @param {ICreateFunctionParam} funcParam
     * @returns {(Promise<IResponseInfo | ICreateFunctionRes>)}
     */
    async createFunction(funcParam) {
        const { namespace } = this.getFunctionConfig();
        const { func, functionRootPath, force = false, base64Code, codeSecret, functionPath } = funcParam;
        const funcName = func.name;
        const params = configToParams({
            func,
            codeSecret,
            baseParams: {
                Namespace: namespace,
                Role: 'TCB_QcsRole',
                Stamp: 'MINI_QCBASE'
            }
        });
        params.Code = await this.getCodeParams({
            func,
            base64Code,
            functionPath,
            functionRootPath
        }, params.InstallDependency);
        const { TopicId, LogsetId } = this.getClsServiceConfig();
        params.ClsTopicId = TopicId;
        params.ClsLogsetId = LogsetId;
        try {
            // 创建云函数
            const res = await this.scfService.request('CreateFunction', params);
            // 等待函数状态正常
            await this.waitFunctionActive(funcName, codeSecret);
            // 创建函数触发器、失败自动重试
            await this.retryCreateTrigger(funcName, func.triggers);
            // 设置路径，创建云接入路径
            if (func.path) {
                await this.createAccessPath(funcName, func.path);
            }
            // 检查函数状态
            await this.waitFunctionActive(funcName, codeSecret);
            return res;
        }
        catch (e) {
            // 函数存在
            const functionExist = e.code === 'ResourceInUse.FunctionName' || e.code === 'ResourceInUse.Function';
            // 已存在同名函数，强制更新
            if (functionExist && force) {
                // 1. 更新函数配置和代码，同名函数可能存在 codeSecret，先修改代码，清除 codeSecret
                const codeRes = await this.updateFunctionCode({
                    func,
                    base64Code,
                    functionPath,
                    functionRootPath,
                    codeSecret: codeSecret
                });
                // 等待函数状态正常
                await this.waitFunctionActive(funcName, codeSecret);
                // 2. 更新函数配置
                const configRes = await this.updateFunctionConfig(func);
                // 等待函数状态正常
                await this.waitFunctionActive(funcName, codeSecret);
                // 3. 创建函数触发器
                const triggerRes = await this.retryCreateTrigger(funcName, func.triggers);
                // 设置路径，创建云接入路径
                if (func.path) {
                    await this.createAccessPath(funcName, func.path);
                }
                // 检查函数状态
                await this.waitFunctionActive(funcName, codeSecret);
                // 返回全部操作的响应值
                return {
                    triggerRes,
                    configRes,
                    codeRes
                };
            }
            // 不强制覆盖，抛出错误
            if (e.message && !force) {
                throw new error_1.CloudBaseError(`[${funcName}] 部署失败：\n${e.message}`, {
                    code: e.code,
                    requestId: e.requestId
                });
            }
            throw e;
        }
    }
    /**
     * @param {number} [limit=20]
     * @param {number} [offset=0]
     * @returns {Promise<{
     *         Functions: Record<string, string>[]
     *         RequestId: string
     *         TotalCount: number
     *     }>}
     * @memberof FunctionService
     */
    async getFunctionList(limit = 20, offset = 0) {
        // 获取Function 环境配置
        const { namespace } = this.getFunctionConfig();
        const res = await this.scfService.request('ListFunctions', {
            Namespace: namespace,
            Limit: limit,
            Offset: offset
        });
        return res;
    }
    /**
     * 列出函数
     * @param {number} [limit=20]
     * @param {number} [offset=0]
     * @returns {Promise<Record<string, string>[]>}
     */
    async listFunctions(limit = 20, offset = 0) {
        // 获取Function 环境配置
        const { namespace } = this.getFunctionConfig();
        const res = await this.scfService.request('ListFunctions', {
            Namespace: namespace,
            Limit: limit,
            Offset: offset
        });
        const { Functions = [] } = res;
        const data = [];
        Functions.forEach(func => {
            const { FunctionId, FunctionName, Runtime, AddTime, ModTime, Status } = func;
            data.push({
                FunctionId,
                FunctionName,
                Runtime,
                AddTime,
                ModTime,
                Status
            });
        });
        return data;
    }
    /**
     * 删除云函数
     * @param {string} name 云函数名称
     * @param {string} qualifier 需要删除的版本号，不填默认删除函数下全部版本。
     * @returns {Promise<IResponseInfo>}
     */
    async deleteFunction(name, qualifier) {
        const { namespace } = this.getFunctionConfig();
        return this.scfService.request('DeleteFunction', {
            FunctionName: name,
            Namespace: namespace,
            Qualifier: qualifier
        });
    }
    /**
     * 获取云函数详细信息
     * @param {string} name 云函数名称
     * @returns {Promise<Record<string, string>>}
     */
    async getFunctionDetail(name, codeSecret) {
        const { namespace } = this.getFunctionConfig();
        const params = {
            FunctionName: name,
            Namespace: namespace,
            ShowCode: 'TRUE'
        };
        if (codeSecret) {
            params.CodeSecret = codeSecret;
        }
        const data = await this.scfService.request('GetFunction', params);
        // 解析 VPC 配置
        const { VpcId = '', SubnetId = '' } = data.VpcConfig || {};
        if (VpcId && SubnetId) {
            try {
                const vpcs = await this.getVpcs();
                const subnets = await this.getSubnets(VpcId);
                const vpc = vpcs.find(item => item.VpcId === VpcId);
                const subnet = subnets.find(item => item.SubnetId === SubnetId);
                // FIXME: 这里的 vpc 和 subnet 不应该是 string 吧，它是 vpcs 和 subnets 的项啊
                data.VpcConfig = {
                    // @ts-ignore
                    vpc,
                    // @ts-ignore
                    subnet
                };
            }
            catch (e) {
                data.VpcConfig = {
                    vpc: '',
                    subnet: ''
                };
            }
        }
        return data;
    }
    /**
     * 获取函数日志
     * @param {{
     *         name: string
     *         offset: number
     *         limit: number
     *         order: string
     *         orderBy: string
     *         startTime: string
     *         endTime: string
     *         requestId: string
     *     }} options
     * @returns {Promise<IFunctionLogRes>}
     */
    async getFunctionLogs(options) {
        const { name, offset = 0, limit = 10, order, orderBy, startTime, endTime, requestId } = options;
        const { namespace } = this.getFunctionConfig();
        const params = {
            Namespace: namespace,
            FunctionName: name,
            Offset: offset,
            Limit: limit,
            Order: order,
            OrderBy: orderBy,
            StartTime: startTime,
            EndTime: endTime,
            FunctionRequestId: requestId
        };
        const res = await this.scfService.request('GetFunctionLogs', params);
        return res;
    }
    /**
     * 更新云函数配置
     * @param {ICloudFunction} func 云函数配置
     * @returns {Promise<IResponseInfo>}
     */
    async updateFunctionConfig(func) {
        var _a, _b, _c, _d, _e;
        const { namespace } = this.getFunctionConfig();
        const envVariables = Object.keys(func.envVariables || {}).map(key => ({
            Key: key,
            Value: func.envVariables[key]
        }));
        // 当不存在 L5 配置时，不修改 L5 状态，否则根据 true/false 进行修改
        const l5Enable = typeof func.l5 === 'undefined' ? null : func.l5 ? 'TRUE' : 'FALSE';
        const params = {
            FunctionName: func.name,
            Namespace: namespace,
            L5Enable: l5Enable
        };
        // 修复参数存在 undefined 字段时，会出现鉴权失败的情况
        // Environment 为覆盖式修改，不保留已有字段
        envVariables.length && (params.Environment = { Variables: envVariables });
        // 不设默认超时时间，防止覆盖已有配置
        func.timeout && (params.Timeout = func.timeout);
        // 运行时
        func.runtime && (params.Runtime = func.runtime);
        if (((_a = func === null || func === void 0 ? void 0 : func.vpc) === null || _a === void 0 ? void 0 : _a.subnetId) !== undefined && ((_b = func === null || func === void 0 ? void 0 : func.vpc) === null || _b === void 0 ? void 0 : _b.vpcId) !== undefined) {
            // VPC 网络
            params.VpcConfig = {
                SubnetId: (_c = func === null || func === void 0 ? void 0 : func.vpc) === null || _c === void 0 ? void 0 : _c.subnetId,
                VpcId: (_d = func === null || func === void 0 ? void 0 : func.vpc) === null || _d === void 0 ? void 0 : _d.vpcId
            };
        }
        // 内存
        func.memorySize && (params.MemorySize = func.memorySize);
        // Node 函数默认安装依赖
        isNodeFunction(func.runtime) && (params.InstallDependency = 'TRUE');
        // 是否安装依赖，选项可以覆盖
        if (typeof func.installDependency !== 'undefined') {
            params.InstallDependency = func.installDependency ? 'TRUE' : 'FALSE';
        }
        // 函数层
        if ((_e = func === null || func === void 0 ? void 0 : func.layers) === null || _e === void 0 ? void 0 : _e.length) {
            const transformLayers = func.layers.map(item => ({
                LayerName: item.name,
                LayerVersion: item.version
            }));
            params.Layers = transformLayers;
        }
        return this.scfService.request('UpdateFunctionConfiguration', params);
    }
    /**
     *
     * @param {IUpdateFunctionCodeParam} funcParam
     * @returns {Promise<IResponseInfo>}
     * @memberof FunctionService
     */
    async updateFunctionCode(funcParam) {
        const { func, functionRootPath, base64Code, codeSecret, functionPath } = funcParam;
        const funcName = func.name;
        const { namespace } = this.getFunctionConfig();
        let installDependency;
        // Node 函数默认安装依赖
        installDependency = isNodeFunction(func.runtime) ? 'TRUE' : 'FALSE';
        // 是否安装依赖，选项可以覆盖
        if (typeof func.installDependency !== 'undefined') {
            installDependency = func.installDependency ? 'TRUE' : 'FALSE';
        }
        const codeParams = await this.getCodeParams({
            func,
            functionPath,
            functionRootPath,
            base64Code
        }, installDependency);
        const params = Object.assign({ FunctionName: funcName, Namespace: namespace, Handler: func.handler || 'index.main', InstallDependency: installDependency }, codeParams);
        if (codeSecret) {
            params.CodeSecret = codeSecret;
        }
        try {
            // 等待函数状态正常
            await this.waitFunctionActive(funcName, codeSecret);
            // 更新云函数代码
            const res = await this.scfService.request('UpdateFunctionCode', params);
            if (installDependency && func.isWaitInstall === true) {
                await this.waitFunctionActive(funcName, codeSecret);
            }
            return res;
        }
        catch (e) {
            throw new error_1.CloudBaseError(`[${funcName}] 函数代码更新失败： ${e.message}`, {
                code: e.code
            });
        }
    }
    /**
     * 调用云函数
     * @param {string} name 云函数名称
     * @param {Record<string, any>} params 调用函数传入参数
     * @returns {Promise<IFunctionInvokeRes>}
     */
    async invokeFunction(name, params) {
        const { namespace } = this.getFunctionConfig();
        const _params = {
            FunctionName: name,
            Namespace: namespace,
            LogType: 'Tail'
        };
        if (params) {
            _params.ClientContext = JSON.stringify(params);
        }
        try {
            const { RequestId, Result } = await this.scfService.request('Invoke', _params);
            return Object.assign({ RequestId }, Result);
        }
        catch (e) {
            throw new error_1.CloudBaseError(`[${name}] 调用失败：\n${e.message}`);
        }
    }
    /**
     * 复制云函数
     * @param {string} name 云函数名称
     * @param {string} newFunctionName 新的云函数名称
     * @param {string} targetEnvId 目标环境 Id
     * @param {boolean} [force=false] 是否覆盖同名云函数
     * @returns {Promise<IResponseInfo>}
     */
    /* eslint-disable-next-line */
    async copyFunction(name, newFunctionName, targetEnvId, force = false) {
        const { namespace } = this.getFunctionConfig();
        if (!namespace || !name || !newFunctionName) {
            throw new error_1.CloudBaseError('参数缺失');
        }
        return this.scfService.request('CopyFunction', {
            FunctionName: name,
            NewFunctionName: newFunctionName,
            Namespace: namespace,
            TargetNamespace: targetEnvId || namespace,
            Override: force ? true : false
        });
    }
    /**
     * 创建云函数触发器
     * @param {string} name 云函数名称
     * @param {ICloudFunctionTrigger[]} triggers 云函数触发器配置
     * @returns {Promise<IResponseInfo>}
     */
    async createFunctionTriggers(name, triggers = []) {
        if (!triggers || !triggers.length)
            return null;
        const { namespace } = this.getFunctionConfig();
        const parsedTriggers = triggers.map(item => {
            if (item.type !== 'timer') {
                throw new error_1.CloudBaseError(`不支持的触发器类型 [${item.type}]，目前仅支持定时触发器（timer）！`);
            }
            return {
                TriggerName: item.name,
                Type: item.type,
                TriggerDesc: item.config
            };
        });
        return this.scfService.request('BatchCreateTrigger', {
            FunctionName: name,
            Namespace: namespace,
            Triggers: JSON.stringify(parsedTriggers),
            Count: parsedTriggers.length
        });
    }
    /**
     * 删除云函数触发器
     * @param {string} name 云函数名称
     * @param {string} triggerName 云函数触发器名称
     * @returns {Promise<IResponseInfo>}
     */
    async deleteFunctionTrigger(name, triggerName) {
        const { namespace } = this.getFunctionConfig();
        return this.scfService.request('DeleteTrigger', {
            FunctionName: name,
            Namespace: namespace,
            TriggerName: triggerName,
            Type: 'timer'
        });
    }
    /**
     * 获取云函数代码下载 链接
     * @param {string} functionName
     * @param {string} [codeSecret]
     * @returns {Promise<IFunctionDownloadUrlRes>}
     * @memberof FunctionService
     */
    async getFunctionDownloadUrl(functionName, codeSecret) {
        const { namespace } = this.getFunctionConfig();
        const params = {
            FunctionName: functionName,
            Namespace: namespace
        };
        if (codeSecret) {
            params.CodeSecret = codeSecret;
        }
        try {
            const { Url, CodeSha256, RequestId } = await this.scfService.request('GetFunctionAddress', params);
            return { Url, RequestId, CodeSha256 };
        }
        catch (e) {
            throw new error_1.CloudBaseError(`[${functionName}] 获取函数代码下载链接失败：\n${e.message}`);
        }
    }
    // 创建文件层版本
    async createLayer(options) {
        const { env } = this.getFunctionConfig();
        const { contentPath = '', name, base64Content = '', runtimes = [], description = '', licenseInfo = '' } = options;
        let base64;
        if (base64Content) {
            base64 = base64Content;
        }
        else if ((0, utils_1.isDirectory)(contentPath)) {
            // 压缩文件夹
            const dirName = path_1.default.parse(contentPath).name;
            const dest = path_1.default.join(process.cwd(), `temp-${dirName}.zip`);
            // ZIP 文件存在，删除 ZIP 文件
            if ((0, utils_1.checkFullAccess)(dest)) {
                (0, utils_1.delSync)(dest);
            }
            await (0, utils_1.compressToZip)({
                dirPath: contentPath,
                outputPath: dest
            });
            // 转换成 base64
            const fileBuffer = await fs_1.default.promises.readFile(dest);
            base64 = fileBuffer.toString('base64');
            (0, utils_1.delSync)(dest);
        }
        else {
            const fileType = path_1.default.extname(contentPath);
            if (fileType !== '.zip') {
                throw new error_1.CloudBaseError('文件类型不正确，目前只支持 ZIP 文件！');
            }
            const fileBuffer = await fs_1.default.promises.readFile(contentPath);
            base64 = fileBuffer.toString('base64');
        }
        return this.scfService.request('PublishLayerVersion', {
            LayerName: name,
            CompatibleRuntimes: runtimes,
            Content: {
                // 最大支持 20M
                ZipFile: base64
            },
            Description: description,
            LicenseInfo: licenseInfo,
            Src: `TCB_${env}`
        });
    }
    // 删除文件层版本
    async deleteLayerVersion(options) {
        const { name, version } = options;
        return this.scfService.request('DeleteLayerVersion', {
            LayerName: name,
            LayerVersion: version
        });
    }
    // 获取层版本列表
    async listLayerVersions(options) {
        const { name, runtimes } = options;
        let param = {
            LayerName: name
        };
        if (runtimes === null || runtimes === void 0 ? void 0 : runtimes.length) {
            param.CompatibleRuntime = runtimes;
        }
        return this.scfService.request('ListLayerVersions', param);
    }
    // 获取文件层列表
    async listLayers(options) {
        const { env } = this.getFunctionConfig();
        const { limit = 20, offset = 0, runtime, searchKey } = options;
        let param = {
            Limit: limit,
            Offset: offset,
            SearchKey: searchKey,
            SearchSrc: `TCB_${env}`
        };
        if (runtime) {
            param.CompatibleRuntime = runtime;
        }
        return this.scfService.request('ListLayers', param);
    }
    // 获取层版本详细信息
    async getLayerVersion(options) {
        const { name, version } = options;
        return this.scfService.request('GetLayerVersion', {
            LayerName: name,
            LayerVersion: version
        });
    }
    /**
     * 设置预置并发
     * @private
     * @param {IProvisionedConcurrencyConfig} concurrencyConfig
     * @returns
     * @memberof FunctionService
     */
    async setProvisionedConcurrencyConfig(concurrencyConfig) {
        const { namespace } = this.getFunctionConfig();
        const { functionName: FunctionName, qualifier: Qualifier, versionProvisionedConcurrencyNum: VersionProvisionedConcurrencyNum } = concurrencyConfig;
        return this.scfService.request('PutProvisionedConcurrencyConfig', {
            FunctionName,
            Qualifier,
            VersionProvisionedConcurrencyNum,
            Namespace: namespace
        });
    }
    /**
     * 获取函数预置并发详情
     * @private
     * @param {IGetProvisionedConcurrencyConfig} concurrencyConfig
     * @returns {Promise<IGetProvisionedConcurrencyRes>}
     * @memberof FunctionService
     */
    async getProvisionedConcurrencyConfig(concurrencyConfig) {
        const { namespace } = this.getFunctionConfig();
        const { functionName: FunctionName, qualifier: Qualifier } = concurrencyConfig;
        return this.scfService.request('GetProvisionedConcurrencyConfig', {
            FunctionName,
            Qualifier,
            Namespace: namespace
        });
    }
    /**
     * 删除预置并发
     * @private
     * @param {IGetProvisionedConcurrencyConfig} concurrencyConfig
     * @returns {Promise<IResponseInfo>}
     * @memberof FunctionService
     */
    async deleteProvisionedConcurrencyConfig(concurrencyConfig) {
        const { namespace } = this.getFunctionConfig();
        const { functionName: FunctionName, qualifier: Qualifier } = concurrencyConfig;
        return this.scfService.request('DeleteProvisionedConcurrencyConfig', {
            FunctionName,
            Qualifier,
            Namespace: namespace
        });
    }
    /**
     * 发布新版本
     * @param {IPublishVersionParams} publishParams
     * @returns {Promise<IPublishVersionRes>}
     * @memberof FunctionService
     */
    async publishVersion(publishParams) {
        const { namespace } = this.getFunctionConfig();
        const { functionName: FunctionName, description: Description } = publishParams;
        return this.scfService.request('PublishVersion', {
            FunctionName,
            Description,
            Namespace: namespace
        });
    }
    /**
     * 查询函数版本详情
     * @param {IListFunctionVersionParams} listVersionParams
     * @returns {Promise<IFunctionVersionsRes>}
     * @memberof FunctionService
     */
    async listVersionByFunction(listVersionParams) {
        const { namespace } = this.getFunctionConfig();
        const { functionName: FunctionName, offset: Offset, limit: Limit, order: Order, orderBy: OrderBy } = listVersionParams;
        return this.scfService.request('ListVersionByFunction', {
            FunctionName,
            Namespace: namespace,
            Offset,
            Limit,
            Order,
            OrderBy
        });
    }
    /**
     *
     * @param {IUpdateFunctionAliasConfig} updateVersionConfigParams
     * @returns {Promise<IResponseInfo>}
     * @memberof FunctionService
     */
    async updateFunctionAliasConfig(updateVersionConfigParams) {
        const { namespace } = this.getFunctionConfig();
        const { functionName: FunctionName, name: Name, functionVersion: FunctionVersion, routingConfig: RoutingConfig, description: Description } = updateVersionConfigParams;
        return this.scfService.request('UpdateAlias', {
            FunctionName,
            Name,
            Namespace: namespace,
            FunctionVersion,
            RoutingConfig,
            Description
        });
    }
    /**
     * 查询函数别名详情
     * @param {IGetFunctionAlias} params
     * @returns {Promise<IGetFunctionAliasRes>}
     * @memberof FunctionService
     */
    async getFunctionAlias(params) {
        const { namespace } = this.getFunctionConfig();
        const { functionName: FunctionName, name: Name } = params;
        return this.scfService.request('GetAlias', {
            FunctionName,
            Name,
            Namespace: namespace
        });
    }
    async createAccessPath(name, path) {
        const access = this.environment.getAccessService();
        try {
            await access.createAccess({
                name,
                path
            });
        }
        catch (e) {
            // 当 Path 存在时，校验 Path 绑定的函数是不是当前函数
            if (e.code === 'InvalidParameter.APICreated') {
                const { APISet } = await access.getAccessList({
                    name
                });
                if ((APISet === null || APISet === void 0 ? void 0 : APISet[0].Name) !== name || (APISet === null || APISet === void 0 ? void 0 : APISet[0].Type) !== 1) {
                    throw e;
                }
            }
            else {
                throw e;
            }
        }
    }
    async getCodeParams(options, installDependency) {
        const { func, functionPath, functionRootPath, base64Code } = options;
        // 20MB
        const BIG_LENGTH = 167772160;
        if ((base64Code === null || base64Code === void 0 ? void 0 : base64Code.length) > BIG_LENGTH) {
            throw new error_1.CloudBaseError('base64 不能大于 20 MB');
        }
        if (base64Code === null || base64Code === void 0 ? void 0 : base64Code.length) {
            return {
                ZipFile: base64Code
            };
        }
        const codeType = func.runtime === 'Java8' ? packer_1.CodeType.JavaFile : packer_1.CodeType.File;
        // 云端安装依赖，自动忽略 node_modules 目录
        const ignore = installDependency === 'TRUE'
            ? ['node_modules/**/*', 'node_modules', ...(func.ignore || [])]
            : [...(func.ignore || [])];
        const packer = new packer_1.FunctionPacker({
            ignore,
            codeType,
            functionPath,
            name: func.name,
            root: functionRootPath
        });
        await packer.build();
        // 通过云 API 传输的代码大小不能超过 50MB
        const reachMax = await packer.isReachMaxSize();
        if (reachMax) {
            throw new error_1.CloudBaseError('函数代码不能大于 50MB');
        }
        const base64 = await packer.getBase64Code();
        if (!(base64 === null || base64 === void 0 ? void 0 : base64.length)) {
            throw new error_1.CloudBaseError('文件不能为空');
        }
        return {
            ZipFile: base64
        };
    }
    // 获取 COS 临时信息
    async getTempCosInfo(name) {
        const { env, appId } = await this.getFunctionConfig();
        /**
         * Response:
         * Date: "2020-03-18"
         * RequestId: "91876f56-7cd3-42bb-bc32-b74df5d0516e"
         * Sign: "Gc8QvXD50dx7yBfsl2yEYFwIL45hPTEyNTM2NjU4MTkm
         */
        return this.scfService.request('GetTempCosInfo', {
            ObjectPath: `${appId}/${env}/${name}.zip"`
        });
    }
    async retryCreateTrigger(name, triggers, count = 0) {
        try {
            const res = await this.createFunctionTriggers(name, triggers);
            return res;
        }
        catch (e) {
            if (count < 3) {
                await (0, utils_1.sleep)(500);
                const res = await this.retryCreateTrigger(name, triggers, count + 1);
                return res;
            }
            else {
                throw e;
            }
        }
    }
    /**
     * 获取函数配置信息
     * @private
     * @returns
     * @memberof FunctionService
     */
    getFunctionConfig() {
        var _a;
        const envConfig = this.environment.lazyEnvironmentConfig;
        const namespace = envConfig.Functions[0].Namespace;
        const appId = (_a = envConfig.Storages[0]) === null || _a === void 0 ? void 0 : _a.AppId;
        const { proxy } = this.environment.cloudBaseContext;
        return {
            proxy,
            appId,
            namespace,
            env: envConfig.EnvId
        };
    }
    /**
     * 获取日志cls配置信息
     */
    getClsServiceConfig() {
        var _a, _b;
        const currentEnv = this.environment.lazyEnvironmentConfig;
        const customLogServices = (_a = currentEnv === null || currentEnv === void 0 ? void 0 : currentEnv.CustomLogServices) === null || _a === void 0 ? void 0 : _a[0];
        const logServices = (_b = currentEnv === null || currentEnv === void 0 ? void 0 : currentEnv.LogServices) === null || _b === void 0 ? void 0 : _b[0];
        return {
            TopicId: (customLogServices === null || customLogServices === void 0 ? void 0 : customLogServices.ClsTopicId) || (logServices === null || logServices === void 0 ? void 0 : logServices.TopicId),
            LogsetId: (customLogServices === null || customLogServices === void 0 ? void 0 : customLogServices.ClsLogsetId) || (logServices === null || logServices === void 0 ? void 0 : logServices.LogsetId)
        };
    }
    /**
     * 获取 vpc 信息
     * @returns
     */
    async getVpcs() {
        const { VpcSet } = await this.vpcService.request('DescribeVpcs');
        return VpcSet;
    }
    /**
     * 获取子网
     * @param {string} vpcId
     * @returns
     */
    async getSubnets(vpcId) {
        const { SubnetSet } = await this.vpcService.request('DescribeSubnets', {
            Filters: [
                {
                    Name: 'vpc-id',
                    Values: [vpcId]
                }
            ]
        });
        return SubnetSet;
    }
    // 检查函数状态，部分操作在函数更新中时不可进行
    async waitFunctionActive(funcName, codeSecret) {
        let ticker;
        let timer;
        let resolved;
        return new Promise((resolve, reject) => {
            // 超时时间 5 分钟
            timer = setTimeout(() => {
                clearInterval(ticker);
                if (!resolved) {
                    reject(new error_1.CloudBaseError('函数状态异常，检查超时'));
                }
            }, 300000);
            ticker = setInterval(async () => {
                try {
                    const { Status } = await this.getFunctionDetail(funcName, codeSecret);
                    // 更新中
                    if (Status === constant_1.SCF_STATUS.CREATING || Status === constant_1.SCF_STATUS.UPDATING)
                        return;
                    // 创建失败
                    if (Status === constant_1.SCF_STATUS.CREATE_FAILED) {
                        throw new error_1.CloudBaseError('云函数创建失败');
                    }
                    // 函数状态正常
                    clearInterval(ticker);
                    clearTimeout(timer);
                    resolve();
                }
                catch (e) {
                    clearInterval(ticker);
                    clearTimeout(timer);
                    reject(e);
                }
                resolved = true;
            }, 1000);
        });
    }
}
exports.FunctionService = FunctionService;
__decorate([
    (0, utils_1.preLazy)()
], FunctionService.prototype, "updateFunctionIncrementalCode", null);
__decorate([
    (0, utils_1.preLazy)()
], FunctionService.prototype, "createFunction", null);
__decorate([
    (0, utils_1.preLazy)()
], FunctionService.prototype, "getFunctionList", null);
__decorate([
    (0, utils_1.preLazy)()
], FunctionService.prototype, "listFunctions", null);
__decorate([
    (0, utils_1.preLazy)()
], FunctionService.prototype, "deleteFunction", null);
__decorate([
    (0, utils_1.preLazy)()
], FunctionService.prototype, "getFunctionDetail", null);
__decorate([
    (0, utils_1.preLazy)()
], FunctionService.prototype, "getFunctionLogs", null);
__decorate([
    (0, utils_1.preLazy)()
], FunctionService.prototype, "updateFunctionConfig", null);
__decorate([
    (0, utils_1.preLazy)()
], FunctionService.prototype, "updateFunctionCode", null);
__decorate([
    (0, utils_1.preLazy)()
], FunctionService.prototype, "invokeFunction", null);
__decorate([
    (0, utils_1.preLazy)()
], FunctionService.prototype, "copyFunction", null);
__decorate([
    (0, utils_1.preLazy)()
], FunctionService.prototype, "createFunctionTriggers", null);
__decorate([
    (0, utils_1.preLazy)()
], FunctionService.prototype, "deleteFunctionTrigger", null);
__decorate([
    (0, utils_1.preLazy)()
], FunctionService.prototype, "getFunctionDownloadUrl", null);
__decorate([
    (0, utils_1.preLazy)()
], FunctionService.prototype, "createLayer", null);
__decorate([
    (0, utils_1.preLazy)()
], FunctionService.prototype, "deleteLayerVersion", null);
__decorate([
    (0, utils_1.preLazy)()
], FunctionService.prototype, "listLayerVersions", null);
__decorate([
    (0, utils_1.preLazy)()
], FunctionService.prototype, "listLayers", null);
__decorate([
    (0, utils_1.preLazy)()
], FunctionService.prototype, "getLayerVersion", null);
__decorate([
    (0, utils_1.preLazy)()
], FunctionService.prototype, "setProvisionedConcurrencyConfig", null);
__decorate([
    (0, utils_1.preLazy)()
], FunctionService.prototype, "getProvisionedConcurrencyConfig", null);
__decorate([
    (0, utils_1.preLazy)()
], FunctionService.prototype, "deleteProvisionedConcurrencyConfig", null);
__decorate([
    (0, utils_1.preLazy)()
], FunctionService.prototype, "publishVersion", null);
__decorate([
    (0, utils_1.preLazy)()
], FunctionService.prototype, "listVersionByFunction", null);
__decorate([
    (0, utils_1.preLazy)()
], FunctionService.prototype, "updateFunctionAliasConfig", null);
__decorate([
    (0, utils_1.preLazy)()
], FunctionService.prototype, "getFunctionAlias", null);
__decorate([
    (0, utils_1.preLazy)()
], FunctionService.prototype, "createAccessPath", null);
__decorate([
    (0, utils_1.preLazy)()
], FunctionService.prototype, "getCodeParams", null);
__decorate([
    (0, utils_1.preLazy)()
], FunctionService.prototype, "getTempCosInfo", null);
