import { createHash } from 'crypto'; import { type INodeType, type INodeTypeDescription, IExecuteFunctions, INodeExecutionData, } from 'n8n-workflow'; import { distributionDescription } from './resources/distribution'; /** * 生成 MD5 签名 * @param params 参数数组 * @returns MD5 签名字符串 */ function getSign(params: (string | number)[]): string { const paramStr = params.join(''); return createHash('md5').update(paramStr).digest('hex'); } /** * 创建认证参数 * @param distributorId 分销商 ID * @param secretKey 签名密钥 * @returns */ function createAuthParams( distributorId: string, secretKey: string, ): Record { const timeStamp = Math.floor(Date.now() / 1000); return { distributor_id: distributorId, ts: timeStamp, sign: getSign([distributorId, secretKey, timeStamp]), }; } export class GwezzChangdunovel implements INodeType { description: INodeTypeDescription = { displayName: 'Gwezz 常读分销', name: 'gwezzChangdunovel', icon: { light: 'file:../../icons/gwezz.svg', dark: 'file:../../icons/gwezz.dark.svg' }, group: ['transform'], version: 1, subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', description: 'Interact with the Changdunovel API', defaults: { name: 'Gwezz 常读分销', }, usableAsTool: true, inputs: ['main'], outputs: ['main'], credentials: [{ name: 'gwezzChangdunovelApi', required: true }], requestDefaults: { baseURL: 'https://www.changdunovel.com/novelsale/openapi', headers: { Accept: 'application/json', 'Content-Type': 'application/json', }, }, properties: [ { displayName: '资源', name: 'resource', type: 'options', noDataExpression: true, options: [ { name: '分销', value: 'distribution', }, ], default: 'distribution', }, ...distributionDescription, ], }; async execute(this: IExecuteFunctions): Promise { const items = this.getInputData(); const returnData: INodeExecutionData[] = []; const resource = this.getNodeParameter('resource', 0); const operation = this.getNodeParameter('operation', 0); const credentials = await this.getCredentials('gwezzChangdunovelApi'); const distributorId = credentials.distributor_id as string; const secretKey = credentials.secret_key as string; let responseData; for (let i = 0; i < items.length; i++) { try { if (resource === 'distribution') { if (operation === 'contentBookMetaV1') { const bookId = this.getNodeParameter('book_id', i) as string; const authParams = createAuthParams(distributorId, secretKey); const qs = { ...authParams, book_id: bookId, }; responseData = await this.helpers.httpRequest({ method: 'GET', url: '/v1/content/book/meta', qs, }); } } returnData.push({ json: responseData, itemIndex: i }); } catch (error) { if (this.continueOnFail()) { returnData.push({ json: { error: (error as Error).message, }, itemIndex: i, }); continue; } throw error; } } return [this.helpers.returnJsonArray(returnData)]; } }