| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
- #!/usr/bin/env node
- 'use strict';
- const crypto = require('crypto');
- const path = require('path');
- const { pathToFileURL } = require('url');
- const { readQiweiGuid } = require('../mcp/src/core/credentials');
- const {
- getRelayBaseUrl,
- getTenantApiSecret,
- getRelayPrivateKey,
- getTenantId,
- getRelayDeviceGuid,
- } = require('../mcp/src/core/relay-config');
- function runtimeModuleUrl(relativePath) {
- return pathToFileURL(path.join(__dirname, '..', 'runtime', 'callback-service', 'src', relativePath)).href;
- }
- function decryptPayload(encryptedPayload, privateKeyPem) {
- const key = privateKeyPem && typeof privateKeyPem === 'object' && privateKeyPem.type === 'private'
- ? privateKeyPem
- : crypto.createPrivateKey(privateKeyPem);
- if (String(encryptedPayload).startsWith('v2:')) {
- const envelope = JSON.parse(Buffer.from(String(encryptedPayload).slice(3), 'base64').toString('utf8'));
- const aesKey = crypto.privateDecrypt(
- { key, oaepHash: 'sha256' },
- Buffer.from(envelope.key, 'base64'),
- );
- const decipher = crypto.createDecipheriv('aes-256-gcm', aesKey, Buffer.from(envelope.iv, 'base64'));
- decipher.setAuthTag(Buffer.from(envelope.tag, 'base64'));
- return Buffer.concat([
- decipher.update(Buffer.from(envelope.ciphertext, 'base64')),
- decipher.final(),
- ]).toString('utf8');
- }
- return crypto.privateDecrypt(
- { key, oaepHash: 'sha256' },
- Buffer.from(encryptedPayload, 'base64'),
- ).toString('utf8');
- }
- async function ackEvents(baseUrl, apiSecret, guid, eventIds) {
- if (!eventIds.length) return 0;
- const response = await fetch(`${String(baseUrl).replace(/\/$/, '')}/api/relay/ack`, {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- Authorization: `Bearer ${apiSecret}`,
- },
- body: JSON.stringify({ guid, eventIds }),
- });
- if (!response.ok) throw new Error(`ACK failed: ${response.status} ${await response.text()}`);
- const data = await response.json();
- return Number(data.ackedCount) || eventIds.length;
- }
- function resolveGuid() {
- return process.argv[2] || process.env.RELAY_DEVICE_GUID || getRelayDeviceGuid() || readQiweiGuid() || '';
- }
- function resolveRuntimeConfig() {
- return {
- baseUrl: getRelayBaseUrl(),
- apiSecret: getTenantApiSecret(),
- privateKey: getRelayPrivateKey(),
- tenantId: getTenantId(),
- guid: resolveGuid(),
- };
- }
- async function runPollOnce(baseUrl, apiSecret, guid, privateKey) {
- const { EnterpriseRelayRuntime } = await import(runtimeModuleUrl('enterprise-relay-client.mjs'));
- const runtime = new EnterpriseRelayRuntime({
- config: {
- batchSize: 100,
- waitMs: 30000,
- retryMinMs: 1000,
- retryMaxMs: 60000,
- },
- });
- const result = await runtime.pollOnce({ baseUrl, apiSecret, guid, privateKey, tenantId: 'compat' }, {
- throwOnFailure: false,
- });
- return {
- received: result.received,
- acked: result.acked,
- failed: result.failed,
- };
- }
- async function main() {
- const { startRuntime } = await import(runtimeModuleUrl('index.mjs'));
- const runtime = await startRuntime({
- forceMode: 'enterprise',
- guid: process.argv[2] || '',
- dashboard: false,
- });
- process.stdout.write(`[RelayClient] ESM runtime started. pid=${process.pid}, mode=${runtime.mode}\n`);
- let shuttingDown = false;
- const shutdown = signal => {
- if (shuttingDown) return;
- shuttingDown = true;
- runtime.stop(signal).finally(() => process.exit(0));
- };
- process.once('SIGINT', () => shutdown('SIGINT'));
- process.once('SIGTERM', () => shutdown('SIGTERM'));
- }
- if (require.main === module) {
- main().catch(error => {
- process.stderr.write(`[RelayClient] ${error.message}\n`);
- process.exit(1);
- });
- }
- module.exports = {
- decryptPayload,
- ackEvents,
- runPollOnce,
- resolveGuid,
- resolveRuntimeConfig,
- };
|