logging-status.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. (function attachBackgroundLoggingStatus(root, factory) {
  2. root.MultiPageBackgroundLoggingStatus = factory();
  3. })(typeof self !== 'undefined' ? self : globalThis, function createBackgroundLoggingStatusModule() {
  4. function createLoggingStatus(deps = {}) {
  5. const {
  6. chrome,
  7. DEFAULT_STATE,
  8. getState,
  9. isRecoverableStep9AuthFailure,
  10. LOG_PREFIX,
  11. setState,
  12. STOP_ERROR_MESSAGE,
  13. } = deps;
  14. function getSourceLabel(source) {
  15. const labels = {
  16. 'gmail-mail': 'Gmail 邮箱',
  17. 'sidepanel': '侧边栏',
  18. 'signup-page': '认证页',
  19. 'vps-panel': 'CPA 面板',
  20. 'sub2api-panel': 'SUB2API 后台',
  21. 'qq-mail': 'QQ 邮箱',
  22. 'mail-163': '163 邮箱',
  23. 'mail-2925': '2925 邮箱',
  24. 'inbucket-mail': 'Inbucket 邮箱',
  25. 'duck-mail': 'Duck 邮箱',
  26. 'hotmail-api': 'Hotmail(API对接/本地助手)',
  27. 'luckmail-api': 'LuckMail(API 购邮)',
  28. 'cloudflare-temp-email': 'Cloudflare Temp Email',
  29. };
  30. return labels[source] || source || '未知来源';
  31. }
  32. async function addLog(message, level = 'info') {
  33. const state = await getState();
  34. const logs = state.logs || [];
  35. const entry = { message, level, timestamp: Date.now() };
  36. logs.push(entry);
  37. if (logs.length > 500) logs.splice(0, logs.length - 500);
  38. await setState({ logs });
  39. chrome.runtime.sendMessage({ type: 'LOG_ENTRY', payload: entry }).catch(() => { });
  40. }
  41. async function setStepStatus(step, status) {
  42. const state = await getState();
  43. const statuses = { ...state.stepStatuses };
  44. statuses[step] = status;
  45. await setState({ stepStatuses: statuses, currentStep: step });
  46. chrome.runtime.sendMessage({
  47. type: 'STEP_STATUS_CHANGED',
  48. payload: { step, status },
  49. }).catch(() => { });
  50. }
  51. function getErrorMessage(error) {
  52. return String(typeof error === 'string' ? error : error?.message || '');
  53. }
  54. function isVerificationMailPollingError(error) {
  55. const message = getErrorMessage(error);
  56. return /未在 .*邮箱中找到新的匹配邮件|未在 Hotmail 收件箱中找到新的匹配验证码|邮箱轮询结束,但未获取到验证码|无法获取新的(?:注册|登录)验证码|页面未能重新就绪|页面通信异常|did not respond in \d+s/i.test(message);
  57. }
  58. function getLoginAuthStateLabel(state) {
  59. state = state === 'oauth_consent_page' ? 'unknown' : state;
  60. switch (state) {
  61. case 'verification_page':
  62. return '登录验证码页';
  63. case 'password_page':
  64. return '密码页';
  65. case 'email_page':
  66. return '邮箱输入页';
  67. case 'login_timeout_error_page':
  68. return '登录超时报错页';
  69. case 'oauth_consent_page':
  70. return 'OAuth 授权页';
  71. case 'add_phone_page':
  72. return '手机号页';
  73. default:
  74. return '未知页面';
  75. }
  76. }
  77. function isRestartCurrentAttemptError(error) {
  78. const message = String(typeof error === 'string' ? error : error?.message || '');
  79. return /当前邮箱已存在,需要重新开始新一轮/.test(message);
  80. }
  81. function isStep9RecoverableAuthError(error) {
  82. const message = String(typeof error === 'string' ? error : error?.message || '');
  83. return /STEP9_OAUTH_RETRY::/i.test(message)
  84. || isRecoverableStep9AuthFailure(message);
  85. }
  86. function isLegacyStep9RecoverableAuthError(error) {
  87. const message = String(typeof error === 'string' ? error : error?.message || '');
  88. return /STEP9_OAUTH_TIMEOUT::|认证失败:\s*(?:Timeout waiting for OAuth callback|timeout of \d+ms exceeded)/i.test(message);
  89. }
  90. function isStepDoneStatus(status) {
  91. return status === 'completed' || status === 'manual_completed' || status === 'skipped';
  92. }
  93. function getFirstUnfinishedStep(statuses = {}) {
  94. for (let step = 1; step <= 9; step++) {
  95. if (!isStepDoneStatus(statuses[step] || 'pending')) {
  96. return step;
  97. }
  98. }
  99. return null;
  100. }
  101. function hasSavedProgress(statuses = {}) {
  102. return Object.values({ ...DEFAULT_STATE.stepStatuses, ...statuses }).some((status) => status !== 'pending');
  103. }
  104. function getRunningSteps(statuses = {}) {
  105. return Object.entries({ ...DEFAULT_STATE.stepStatuses, ...statuses })
  106. .filter(([, status]) => status === 'running')
  107. .map(([step]) => Number(step))
  108. .sort((a, b) => a - b);
  109. }
  110. function getAutoRunStatusPayload(phase, payload = {}) {
  111. return {
  112. autoRunning: phase === 'scheduled'
  113. || phase === 'running'
  114. || phase === 'waiting_step'
  115. || phase === 'waiting_email'
  116. || phase === 'retrying'
  117. || phase === 'waiting_interval',
  118. autoRunPhase: phase,
  119. autoRunCurrentRun: payload.currentRun ?? 0,
  120. autoRunTotalRuns: payload.totalRuns ?? 1,
  121. autoRunAttemptRun: payload.attemptRun ?? 0,
  122. scheduledAutoRunAt: Number.isFinite(Number(payload.scheduledAt)) ? Number(payload.scheduledAt) : null,
  123. autoRunCountdownAt: Number.isFinite(Number(payload.countdownAt)) ? Number(payload.countdownAt) : null,
  124. autoRunCountdownTitle: payload.countdownTitle === undefined ? '' : String(payload.countdownTitle || ''),
  125. autoRunCountdownNote: payload.countdownNote === undefined ? '' : String(payload.countdownNote || ''),
  126. };
  127. }
  128. return {
  129. addLog,
  130. getAutoRunStatusPayload,
  131. getErrorMessage,
  132. getFirstUnfinishedStep,
  133. getLoginAuthStateLabel,
  134. getRunningSteps,
  135. getSourceLabel,
  136. hasSavedProgress,
  137. isLegacyStep9RecoverableAuthError,
  138. isRestartCurrentAttemptError,
  139. isStep9RecoverableAuthError,
  140. isStepDoneStatus,
  141. isVerificationMailPollingError,
  142. setStepStatus,
  143. };
  144. }
  145. return {
  146. createLoggingStatus,
  147. };
  148. });