@cloudbase/node-sdk
Version:
tencent cloud base server sdk for node.js
260 lines (259 loc) • 9.63 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AIRequestAdapter = void 0;
const openapicommonrequester = __importStar(require("../utils/tcbopenapicommonrequester"));
const web_streams_polyfill_1 = require("web-streams-polyfill");
const utils_1 = require("../utils/utils");
class AIRequestAdapter {
constructor(config, getAccessToken) {
this.config = config;
this.getAccessToken = getAccessToken;
}
async fetch(options) {
var _a, _b;
const { url, stream = false, timeout, method = 'POST', headers, body } = options;
const headersObj = {};
if (isHeaders(headers)) {
headers.forEach((value, key) => {
headersObj[key] = value;
});
}
else if (Array.isArray(headers)) {
headers.forEach(([k, v]) => (headersObj[k] = v));
}
else {
Object.assign(headersObj, headers);
}
let parsedBody;
if (typeof body === 'string') {
try {
parsedBody = JSON.parse(body);
}
catch (_c) {
parsedBody = body;
}
}
else {
parsedBody = body;
}
const token = await this.getAccessToken();
const result = await openapicommonrequester.request({
config: this.config,
data: parsedBody,
method: (method === null || method === void 0 ? void 0 : method.toUpperCase()) || 'POST',
url,
headers: Object.assign({ 'Content-Type': 'application/json' }, headersObj),
token,
opts: {
timeout: timeout || this.config.timeout,
stream
}
});
const { body: bodyData, headers: responseHeaders, statusCode } = result;
if (statusCode < 200 || statusCode >= 300) {
let errorMessage = `Request failed with status code ${statusCode}`;
let errorCode = `${statusCode}`;
let requestId = '';
let errorBody = null;
if (typeof bodyData === 'string') {
errorBody = bodyData;
}
else if (Buffer.isBuffer(bodyData)) {
errorBody = bodyData.toString('utf-8');
}
else if (bodyData && typeof bodyData === 'object' && typeof bodyData.on === 'function') {
errorBody = await readStreamToString(bodyData);
}
if (errorBody) {
try {
const errorData = JSON.parse(errorBody);
if ((_a = errorData.error) === null || _a === void 0 ? void 0 : _a.message) {
errorMessage = errorData.error.message;
}
else if (errorData.message) {
errorMessage = errorData.message;
}
if ((_b = errorData.error) === null || _b === void 0 ? void 0 : _b.code) {
errorCode = errorData.error.code;
}
else if (errorData.code) {
errorCode = errorData.code;
}
if (errorData.requestId) {
requestId = errorData.requestId;
}
}
catch (_d) {
errorMessage = errorBody || errorMessage;
}
}
// 从响应头中获取 requestId
if (!requestId && responseHeaders) {
const headerRequestId = responseHeaders['x-cloudbase-request-id'] || responseHeaders['x-request-id'] || '';
requestId = Array.isArray(headerRequestId) ? headerRequestId[0] : headerRequestId;
}
throw (0, utils_1.E)({
code: errorCode,
message: errorMessage,
requestId
});
}
if (stream) {
// 对于流式响应,将 Node.js 原生流转换为 Web ReadableStream
let readableStream;
if (bodyData && typeof bodyData === 'object' && 'on' in bodyData && typeof bodyData.on === 'function') {
const nodeStream = bodyData;
// Node 12 兼容: 使用标志位追踪 stream 状态,避免重复 close 导致异常
let streamClosed = false;
readableStream = new web_streams_polyfill_1.ReadableStream({
start(controller) {
nodeStream.on('data', (chunk) => {
if (streamClosed)
return;
controller.enqueue(new Uint8Array(chunk));
});
nodeStream.on('end', () => {
if (streamClosed)
return;
streamClosed = true;
controller.close();
});
nodeStream.on('error', (err) => {
if (streamClosed)
return;
streamClosed = true;
controller.error(err);
});
},
cancel() {
streamClosed = true;
nodeStream.destroy();
}
});
}
else if (bodyData instanceof Buffer) {
readableStream = new web_streams_polyfill_1.ReadableStream({
start(controller) {
controller.enqueue(new Uint8Array(bodyData));
controller.close();
}
});
}
else if (typeof bodyData === 'string') {
const encoder = new TextEncoder();
readableStream = new web_streams_polyfill_1.ReadableStream({
start(controller) {
controller.enqueue(encoder.encode(bodyData));
controller.close();
}
});
}
else {
readableStream = new web_streams_polyfill_1.ReadableStream({
start(controller) {
controller.close();
}
});
}
return {
data: readableStream,
statusCode,
header: responseHeaders
};
}
let responseData;
if (typeof bodyData === 'string') {
try {
responseData = JSON.parse(bodyData);
}
catch (_e) {
responseData = bodyData;
}
}
else if (bodyData instanceof Buffer) {
const bodyString = bodyData.toString('utf-8');
try {
responseData = JSON.parse(bodyString);
}
catch (_f) {
responseData = bodyString;
}
}
else {
responseData = bodyData;
}
return {
data: Promise.resolve(responseData),
statusCode,
header: responseHeaders
};
}
/**
* post 方法 - AI 模块可能不使用,但需要实现接口
*/
async post() {
throw new Error('post method is not supported in AI module');
}
/**
* upload 方法 - AI 模块可能不使用,但需要实现接口
*/
async upload() {
throw new Error('upload method is not supported in AI module');
}
/**
* download 方法 - AI 模块可能不使用,但需要实现接口
*/
async download() {
throw new Error('download method is not supported in AI module');
}
}
exports.AIRequestAdapter = AIRequestAdapter;
function isHeaders(h) {
try {
// Node.js 低版本可能没有 Headers
return h instanceof Headers;
}
catch (_) {
return false;
}
}
/**
* 从 Node.js 流中读取完整内容为字符串
*/
async function readStreamToString(stream) {
return await new Promise((resolve, reject) => {
const chunks = [];
stream.on('data', (chunk) => {
chunks.push(chunk);
});
stream.on('end', () => {
resolve(Buffer.concat(chunks).toString('utf-8'));
});
stream.on('error', (err) => {
reject(err);
});
});
}