UNPKG

@ones-open/node-host

Version:
488 lines (487 loc) 21.5 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.HttpHandler = void 0; const config_1 = require("../config"); const logger_1 = require("../logger"); const plugin_1 = require("../plugin"); const protocol_1 = require("../protocol"); const node_utils_1 = require("@ones-op/node-utils"); const node_utils_2 = require("@ones-op/node-utils"); const utils_1 = require("../utils"); const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); const plugin_func_type = 'ones-plugin-function-type'; const plugin_instance_id = 'ones-plugin-instance-id'; class HttpHandler { static async handlePBPluginCall(ctx) { logger_1.logger.debug(`[plugin-func]request body length ${ctx.request.body.length}`); // as Buffer let requestMesage; try { //requestMesage = JSON.parse(ctx.request.body as string) requestMesage = protocol_1.protocol.PlatformMessage.decode(ctx.request.body); } catch (err) { logger_1.logger.error('decode error', err); logger_1.logger.error(`decode error bodylen: ${ctx.request.body.length} body: [${ctx.request.body}]`); } const instanceId = ctx.headers[plugin_instance_id] || ''; try { const funcType = ctx.headers[plugin_func_type] || ''; if (requestMesage) { switch (funcType) { case 'plugin-func': { const pluginHttpResponse = await HttpHandler.callPluginFunc(instanceId, requestMesage.Plugin?.Http?.Request); const responseMessage = { Plugin: { Http: { Response: pluginHttpResponse, }, }, }; const msg = protocol_1.protocol.PlatformMessage.fromObject(responseMessage); ctx.response.body = protocol_1.protocol.PlatformMessage.encode(msg).finish(); //JSON.stringify(responseMessage) } break; case 'lifecycle': { const controlMessage = requestMesage.Control; controlMessage.Headers = controlMessage.Headers || {}; const response = await HttpHandler.callPluginLifecycle(instanceId, controlMessage.Headers || {}, controlMessage.LifeCycleRequest); const responseMessage = { Control: { LifeCycleResponse: response, }, }; const msg = protocol_1.protocol.PlatformMessage.fromObject(responseMessage); ctx.response.body = protocol_1.protocol.PlatformMessage.encode(msg).finish(); //JSON.stringify(responseMessage) } break; case 'readfile': { const response = await HttpHandler.callPluginReadFile(instanceId, requestMesage.Plugin?.ReadFile); const responseMessage = { Plugin: { ReadFile: response, }, }; const msg = protocol_1.protocol.PlatformMessage.fromObject(responseMessage); ctx.response.body = protocol_1.protocol.PlatformMessage.encode(msg).finish(); //JSON.stringify(responseMessage) } break; case 'timer-task': { const result = await HttpHandler.callPluginTimerTask(instanceId, requestMesage.Ability?.TimerTask); const responseMessage = { Ability: { TimerTask: { Response: { Result: result, }, }, }, }; const msg = protocol_1.protocol.PlatformMessage.fromObject(responseMessage); ctx.response.body = protocol_1.protocol.PlatformMessage.encode(msg).finish(); //JSON.stringify(responseMessage) } break; default: throw new Error(`Not found plugin call type: [${funcType}]`); } logger_1.logger.debug(`[${funcType}] execute success`); } } catch (err) { logger_1.logger.error('handlePBPluginCall error', err, err.stack); } } static async callPluginFunc(instanceId, message) { HttpHandler.debugRequest(message); const { abilityFunc: functionName, ...request } = (0, node_utils_1.parseRequest)(message); const instance = plugin_1.pluginManager.getPlugin(); if (!instance) { throw new Error(`Not found plugin instance: ${instanceId}`); } if (!functionName) { throw new Error(`Not found AbilityFunc!`); } let response = {}; try { if (!message.IsEvent) { const result = (await instance.runMethod(functionName, request)); if (!result) { response = { StatusCode: 500, Headers: null, Body: null, Error: { Code: 500, Error: `Plugin function [${functionName}] execute empty response!`, }, }; } else { response = { StatusCode: result.statusCode || 200, Headers: result.headers ? (0, node_utils_1.formatHeaders)(result.headers) : {}, Body: result.body ? (0, node_utils_1.formatBody)(result.body) : null, }; } } else { instance.runMethod(functionName, request); response = { StatusCode: 200, Headers: null, Body: null, }; } } catch (error) { const errorType = error?.errType || ''; let statusCode; let Err; if (errorType == 'pluginError') { statusCode = error?.code || 500; Err = HttpHandler.handlePluginErr(error); } else if (errorType == 'abilityError') { statusCode = error?.statusCode || 500; Err = HttpHandler.handleAbilityErr(error); } else { if (error?.message === 'Reference is not a function') { statusCode = 404; Err = { Code: 404, Msg: `Can not find function[${functionName}]!`, Error: error?.stack, }; } else { statusCode = 500; Err = { Code: 500, Msg: `Plugin function [${functionName}] execute failed!`, Error: error?.stack, }; } } response = { StatusCode: statusCode, Headers: null, Body: null, Error: Err, }; logger_1.logger.error(`Plugin function [${functionName}] execute error: `, response); } HttpHandler.debugResponse(response); return response; } static handlePluginErr(pluginErr) { return { Code: pluginErr?.code || 500, Msg: pluginErr?.reason || '', Level: pluginErr?.type || 'error', Model: 'plugin.Err', }; } static handleAbilityErr(abilityErr) { const err = { Code: abilityErr?.statusCode || 500, Msg: abilityErr?.reason || '', Level: abilityErr?.level || 'error', Model: 'plugin.Err', }; if (err.Code == 500) { err.Msg = 'Service unavailable. Try again later.'; } return err; } static debugRequest(request) { if (config_1.config.host.debug_mode) { logger_1.logger.info(`[debug RequestMessage]: `, request); } } static debugResponse(response) { if (config_1.config.host.debug_mode) { logger_1.logger.info(`[debug ResponseMessage]: `, response); } } static async callPluginLifecycle(instanceId, headers, requestMessage) { HttpHandler.debugRequest(requestMessage); const Action = requestMessage.Action || 0; const Forced = requestMessage.Forced || false; const teamUUIDList = requestMessage.TeamUUID || []; const orgUUID = requestMessage.OrgUUID || ''; const firstInstall = requestMessage.FirstInstall || false; const responseMessage = { Result: true, Error: null, FailedTeamUUID: [], }; try { const pluginRequest = { headers: {}, parsedHeaders: (0, protocol_1.parseHeaders)(headers), method: '', body: {}, }; const instance = plugin_1.pluginManager.findPlugin(instanceId); if (!instance) { throw new Error(`Not found plugin instance: ${instanceId}`); } switch (Action) { case protocol_1.protocol.ControlMessage.PluginActionType['Install']: { await instance.Install(pluginRequest); break; } case protocol_1.protocol.ControlMessage.PluginActionType['OrgInstall']: { if (config_1.config.host.serve_mode == config_1.serveModeSaas) { await instance.SaasOrgInstall(pluginRequest); } else { await instance.OrgInstall(pluginRequest, teamUUIDList, firstInstall); } break; } case protocol_1.protocol.ControlMessage.PluginActionType['UnInstall']: { await instance.Uninstall(pluginRequest); break; } case protocol_1.protocol.ControlMessage.PluginActionType['OrgUnInstall']: { if (config_1.config.host.serve_mode == config_1.serveModeSaas) { await instance.SaasOrgUninstall(pluginRequest); } else { await instance.OrgUninstall(pluginRequest, teamUUIDList); } break; } case protocol_1.protocol.ControlMessage.PluginActionType['Enable']: { if (config_1.config.host.serve_mode == config_1.serveModeSaas) { await instance.SaasEnable(pluginRequest, teamUUIDList); } else { await instance.Enable(pluginRequest); } break; } case protocol_1.protocol.ControlMessage.PluginActionType['OrgEnable']: { if (config_1.config.host.serve_mode == config_1.serveModeSaas) { const resp = await instance.SaasOrgEnable(pluginRequest, orgUUID, teamUUIDList); responseMessage.FailedTeamUUID = resp; } else { const resp = await instance.OrgEnable(pluginRequest, teamUUIDList); responseMessage.FailedTeamUUID = resp; } break; } case protocol_1.protocol.ControlMessage.PluginActionType['Disable']: { if (config_1.config.host.serve_mode == config_1.serveModeSaas) { await instance.SaasDisable(pluginRequest, teamUUIDList, Forced); } else { await instance.Disable(pluginRequest, Forced); } break; } case protocol_1.protocol.ControlMessage.PluginActionType['OrgDisable']: { if (config_1.config.host.serve_mode == config_1.serveModeSaas) { const resp = await instance.SaasOrgDisable(pluginRequest, orgUUID, teamUUIDList, Forced); responseMessage.FailedTeamUUID = resp; } else { const resp = await instance.OrgDisable(pluginRequest, teamUUIDList, Forced); responseMessage.FailedTeamUUID = resp; } break; } case protocol_1.protocol.ControlMessage.PluginActionType['Upgrade']: { const oldPluginInfo = { version: (0, node_utils_1.parseVersion)(requestMessage.OldVersion), }; await instance?.Upgrade(oldPluginInfo, pluginRequest); break; } case protocol_1.protocol.ControlMessage.PluginActionType['OrgUpgrade']: { const oldPluginInfo = { version: (0, node_utils_1.parseVersion)(requestMessage.OldVersion), }; if (config_1.config.host.serve_mode == config_1.serveModeSaas) { await instance?.SaasOrgUpgrade(oldPluginInfo, pluginRequest); } else { await instance?.OrgUpgrade(oldPluginInfo, pluginRequest, teamUUIDList); } break; } default: logger_1.logger.error(`Lifecycle action not found: ${Action}`); break; } } catch (error) { responseMessage.Result = false; const ErrorMessage = (0, node_utils_2.formatError)(error, 500); responseMessage.Error = ErrorMessage; logger_1.logger.error(`Lifecycle execute error: `, error); } HttpHandler.debugResponse(responseMessage); return responseMessage; } static async callPluginReadFile(instanceId, message) { const request = message?.Request; if (!instanceId || !request || !request.Path || !request.Name) { return; } request.Type = request.Type || 0; const response = { Error: null, Md5Response: null, ContentResponse: null, }; try { const instance = plugin_1.pluginManager.findPlugin(instanceId); if (!instance) { throw new Error(`Not found plugin instance: ${instanceId}`); } let file = path_1.default.join(request.Path, request.Name); if (config_1.config.cli.debug_mode) { file = path_1.default.join(config_1.config.plugin.workspace_path, request.Name); } if (request.Type == protocol_1.protocol.ReadFileMessageRequest.MessageType.Md5) { //const md5 = await instance.runMethod(getFileMd5,request.Name) const stat = await fs_1.default.promises.stat(file); const md5 = await (0, protocol_1.getFileMd5)(file); response.Md5Response = { Name: request.Name, Md5: md5, Size: stat.size, }; } else if (request.Type == protocol_1.protocol.ReadFileMessageRequest.MessageType.Content) { request.StartPos = request.StartPos || 0; if (!request.EndPos) { throw new Error(`Invalid EndPos!`); } //proto定义为int64,通过protbuf到node.js这边变成了string。。。 const startPos = (0, utils_1.toNumber)(request.StartPos); const endPos = (0, utils_1.toNumber)(request.EndPos); const len = endPos - startPos; if (len < 0) { throw new Error(`Invalid StartPos:[${request.StartPos}] and EndPos:[${request.EndPos}!`); } const content = await (0, utils_1.readPartialFile)(file, startPos, len); response.ContentResponse = { Name: request.Name, Content: content, }; } else { throw new Error(`Invalid requestType: [${request.Type}]`); } } catch (err) { logger_1.logger.error(`read file handler err: `, err); const ErrorMessage = (0, node_utils_2.formatError)(err, 500); response.Error = ErrorMessage; } return { Response: response, }; } static async callPluginTimerTask(instanceId, message) { const request = message?.Request; let result = true; try { const instance = plugin_1.pluginManager.findPlugin(instanceId); if (!instance) { throw new Error(`[callPluginTimerTask] Not found plugin instance: ${instanceId}`); } // 异步调用插件方法 const functionName = request?.AbilityFunc || ''; if (functionName == '' || !functionName) { throw new Error(`[callPluginTimerTask] Not found AbilityFunc!`); } instance.runMethod(functionName); } catch (err) { logger_1.logger.error(`Ability timer-task handle error: `, err); result = false; } // 发送收到确认消息 return result; } static async extensionFuncHandler(ctx, extensionFuncPath, funcName) { try { logger_1.logger.debug(`Received request at ${extensionFuncPath}`); const instance = plugin_1.pluginManager.getPlugin(); const instanceID = instance?.plugin.InstanceID; if (!instance) { throw new Error(`Not found plugin instance: ${instanceID}`); } const result = (await instance.runMethod(funcName, ctx.request.body)); if (!result) { ctx.response.body = { StatusCode: 500, Headers: null, Body: null, Error: { Code: 500, Error: `Plugin function [${funcName}] execute empty response!`, }, }; } else { ctx.response.body = { StatusCode: result.statusCode || 200, Headers: result.headers ? (0, node_utils_1.formatHeaders)(result.headers) : {}, Body: JSON.stringify(result.body), }; } } catch (error) { const errorType = error?.errType || ''; let statusCode; let Err; switch (true) { case errorType === 'pluginError': statusCode = error?.code || 500; Err = HttpHandler.handlePluginErr(error); break; case errorType === 'abilityError': statusCode = error?.statusCode || 500; Err = HttpHandler.handleAbilityErr(error); break; case error?.message === 'Reference is not a function': statusCode = 404; Err = { Code: 404, Msg: `Can not find function[${funcName}]!`, Error: error?.stack, }; break; default: statusCode = 500; Err = { Code: 500, Msg: `Plugin function [${funcName}] execute failed!`, Error: error?.stack, }; } ctx.response.body = { StatusCode: statusCode, Headers: null, Body: null, Error: Err, }; logger_1.logger.error(`Plugin function [${funcName}] execute error: `, ctx.response.body); } } } exports.HttpHandler = HttpHandler;