probe-jimeng-cloud.mjs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. const FN_URL = process.env.FMODE_FUNCTIONS_URL || 'https://server.fmode.cn/api/functions';
  2. const APP_ID = process.env.PARSE_APP_ID || 'ncloudmaster';
  3. const JIMENG_FN_ID = process.env.JIMENG_FN_ID || 'WUkf74lVE5';
  4. const args = parseArgs(process.argv.slice(2));
  5. async function main() {
  6. const checks = [];
  7. if (!args.baseProbe) {
  8. checks.push(['diagnose', { action: 'diagnose' }]);
  9. }
  10. if (!args.skipUnknown) {
  11. checks.unshift(['unknownAction', { action: 'unknown' }]);
  12. }
  13. if (args.workId) {
  14. checks.push(['diagnose.work', { action: 'diagnose', workId: args.workId }]);
  15. }
  16. if (args.assetUrl) {
  17. checks.push(['diagnose.asset', { action: 'diagnose', assetUrl: args.assetUrl }]);
  18. }
  19. if (args.connectivity) {
  20. checks.push([
  21. 'diagnose.connectivity.getOhDateByTask',
  22. {
  23. action: 'diagnose',
  24. probeEndpoint: 'getOhDateByTask',
  25. allowCharge: '1',
  26. payload: {
  27. workId: 'codex-connectivity-probe',
  28. routerName: 'getOhIdentifyMain',
  29. },
  30. },
  31. ]);
  32. }
  33. if (args.baseProbe) {
  34. checks.push([
  35. 'diagnoseBase.getOhDateByTask',
  36. {
  37. action: 'diagnoseBase',
  38. endpoint: args.endpoint || 'getOhDateByTask',
  39. payload: parsePayload(args.payload) || {
  40. workId: 'codex-connectivity-probe',
  41. routerName: 'getOhIdentifyMain',
  42. },
  43. },
  44. ]);
  45. }
  46. if (args.candidateBases) {
  47. checks.push([
  48. 'diagnose.candidateBases',
  49. {
  50. action: 'diagnose',
  51. probeCandidates: '1',
  52. payload: {
  53. workId: 'codex-connectivity-probe',
  54. routerName: 'getOhIdentifyMain',
  55. },
  56. },
  57. ]);
  58. }
  59. if (args.endpoint) {
  60. checks.push([
  61. `diagnose.${args.endpoint}`,
  62. {
  63. action: 'diagnose',
  64. probeEndpoint: args.endpoint,
  65. allowCharge: args.allowCharge ? '1' : '0',
  66. payload: parsePayload(args.payload),
  67. },
  68. ]);
  69. }
  70. let failed = 0;
  71. for (const [name, body] of checks) {
  72. const startedAt = Date.now();
  73. try {
  74. const result = await call(body);
  75. const ok = name === 'unknownAction'
  76. ? result?.success === false || Number(result?.code || 0) >= 400
  77. : result?.success !== false && Number(result?.code || 200) < 400;
  78. if (!ok) failed += 1;
  79. console.log(`${ok ? 'OK' : 'FAIL'} ${name} ${Date.now() - startedAt}ms`);
  80. console.log(JSON.stringify(redact(result), null, 2));
  81. } catch (error) {
  82. failed += 1;
  83. console.log(`FAIL ${name} ${Date.now() - startedAt}ms`);
  84. console.log(error?.message || error);
  85. }
  86. }
  87. if (failed) process.exitCode = 1;
  88. }
  89. async function call(body) {
  90. const response = await fetch(FN_URL, {
  91. method: 'POST',
  92. headers: {
  93. 'Content-Type': 'application/json',
  94. 'X-Parse-Application-Id': APP_ID,
  95. },
  96. body: JSON.stringify({
  97. id: JIMENG_FN_ID,
  98. _ApplicationId: APP_ID,
  99. ...body,
  100. }),
  101. });
  102. const text = await response.text();
  103. try {
  104. return JSON.parse(text);
  105. } catch {
  106. return { code: response.status, success: false, error: text };
  107. }
  108. }
  109. function parseArgs(argv) {
  110. const out = {};
  111. const booleanFlags = new Set(['allow-charge', 'skip-unknown', 'connectivity', 'candidate-bases', 'base-probe']);
  112. for (let i = 0; i < argv.length; i += 1) {
  113. const arg = argv[i];
  114. if (arg.startsWith('--')) {
  115. const key = arg.slice(2).replace(/-([a-z])/g, (_, c) => c.toUpperCase());
  116. if (booleanFlags.has(arg.slice(2))) {
  117. out[key] = true;
  118. continue;
  119. }
  120. out[key] = argv[i + 1] || '';
  121. i += 1;
  122. }
  123. }
  124. return out;
  125. }
  126. function parsePayload(value) {
  127. if (!value) return {};
  128. try {
  129. return JSON.parse(value);
  130. } catch {
  131. throw new Error('--payload 必须是合法 JSON 字符串');
  132. }
  133. }
  134. function redact(value) {
  135. if (Array.isArray(value)) return value.map(redact);
  136. if (!value || typeof value !== 'object') return value;
  137. const out = {};
  138. for (const [key, raw] of Object.entries(value)) {
  139. if (isSecretField(key, raw)) {
  140. out[key] = typeof raw === 'boolean' ? raw : '[redacted]';
  141. } else {
  142. out[key] = redact(raw);
  143. }
  144. }
  145. return out;
  146. }
  147. function isSecretField(key, value) {
  148. if (typeof value === 'boolean' || typeof value === 'number') return false;
  149. if (/tokenSource|tokenConfigured|allowedEndpoints|jimengBaseUrl|parseBaseUrl/i.test(key)) return false;
  150. return /authorization|secret|password|accessKey|secretKey/i.test(key)
  151. || (/token/i.test(key) && !/Source|Configured|Format/i.test(key));
  152. }
  153. main().catch((error) => {
  154. console.error(error?.message || error);
  155. process.exitCode = 1;
  156. });