@ones-op/node-host
Version:
ONES Open Platform Node.js plugin host
112 lines (111 loc) • 4.58 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.HttpServer = void 0;
const koa_1 = __importDefault(require("koa"));
const koa_router_1 = __importDefault(require("koa-router"));
const config_1 = require("../config");
const logger_1 = require("../logger");
const handler_1 = require("../handler");
const bodyParser = require("koa-bodyparser");
const lodash = require("lodash");
const api_1 = require("@opentelemetry/api");
const semantic_conventions_1 = require("@opentelemetry/semantic-conventions");
class HttpServer {
constructor(port) {
const app = new koa_1.default();
const router = new koa_router_1.default();
const tracer = api_1.trace.getTracer('http-server', '1.0.0');
// add trace
app.use(async (ctx, next) => {
let spanName = ctx.method;
const route = ctx._matchedRoute;
if (route) {
spanName = `${spanName} ${route}`;
}
const activeContext = api_1.propagation.extract(api_1.context.active(), ctx.request.headers);
await tracer.startActiveSpan(spanName, {
attributes: {
[semantic_conventions_1.ATTR_URL_FULL]: ctx.request.url,
[semantic_conventions_1.ATTR_HTTP_REQUEST_METHOD]: ctx.request.method,
},
}, activeContext, async (span) => {
try {
return await next();
}
catch (error) {
span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: String(error) });
throw error;
}
finally {
span.setAttribute(semantic_conventions_1.ATTR_HTTP_RESPONSE_STATUS_CODE, ctx.response.status);
span.end();
}
});
});
// log url
app.use(async (ctx, next) => {
logger_1.logger.debug(`Process ${ctx.request.method} ${ctx.request.url}`);
await next();
logger_1.logger.debug(`Process ${ctx.request.method} ${ctx.request.url} finished reponse with code:${ctx.response.status} bodylength:${ctx.response.length}`);
});
router.get('/healthz', (ctx) => {
ctx.response.body = {
status: 'ok',
version: config_1.config.plugin.app_version,
};
});
router.post('/plugin-call', this.copyPBBody, handler_1.HttpHandler.handlePBPluginCall);
// 遍历 pluginConfig.extension 并注册路由
config_1.pluginConfig?.extension?.forEach((extensionItem) => {
lodash.forEach(extensionItem, (providerConfig, provider) => {
providerConfig?.funcs?.forEach((func, index) => {
const routePath = `/backend/extension/${providerConfig.provider}/${func.name}`;
router.post(routePath, this.createBodyParser, async (ctx) => {
await handler_1.HttpHandler.extensionFuncHandler(ctx, routePath, func.url);
});
});
});
});
app.use(router.routes()).use(router.allowedMethods());
app.listen(port);
logger_1.logger.info(`Server is running on port ${port}`);
}
async copyPBBody(ctx, next) {
try {
ctx.request.body = await new Promise((resolve, reject) => {
const chunks = [];
ctx.req.on('data', (chunk) => {
chunks.push(chunk);
});
ctx.req.on('end', () => {
resolve(Buffer.concat(chunks));
});
ctx.req.on('error', (err) => {
reject(err);
});
});
await next();
}
catch (error) {
logger_1.logger.error('Error in copyPBBody middleware', error);
ctx.status = 500;
ctx.body = 'Internal server error';
}
}
async createBodyParser(ctx, next) {
try {
await bodyParser({
enableTypes: ['json', 'form', 'text', 'xml'],
})(ctx, next);
}
catch (error) {
logger_1.logger.error('Error in createBodyParser', error);
ctx.status = 500;
ctx.body = 'Internal server error';
}
}
}
exports.HttpServer = HttpServer;