dns-auto-checker.js 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. import { listDomainsForDnsAutoCheck, saveDomainStatus } from './db.js';
  2. import { buildDnsGuide } from './dns-guide.js';
  3. const defaultIntervalMs = 60000;
  4. const defaultLimit = 25;
  5. export function shouldAutoCheckDomain(domain, { now = new Date(), minIntervalMs = defaultIntervalMs } = {}) {
  6. const status = domain?.status || {};
  7. if (status.verified === true) return false;
  8. const checkedAt = Date.parse(status.checkedAt || '');
  9. if (!Number.isFinite(checkedAt)) return true;
  10. return now.getTime() - checkedAt >= minIntervalMs;
  11. }
  12. export async function runDnsAutoCheck({
  13. listDomains = listDomainsForDnsAutoCheck,
  14. buildGuide = buildDnsGuide,
  15. saveStatus = saveDomainStatus,
  16. logger = console,
  17. now = () => new Date(),
  18. minIntervalMs = defaultIntervalMs,
  19. limit = defaultLimit
  20. } = {}) {
  21. const referenceTime = typeof now === 'function' ? now() : now;
  22. const domains = listDomains();
  23. const candidates = domains
  24. .filter((domain) => shouldAutoCheckDomain(domain, { now: referenceTime, minIntervalMs }))
  25. .slice(0, safePositiveInt(limit, defaultLimit));
  26. let checked = 0;
  27. let failed = 0;
  28. for (const domain of candidates) {
  29. try {
  30. const guide = await buildGuide(domain);
  31. saveStatus(domain.id, domain.userId, guide);
  32. checked += 1;
  33. } catch (error) {
  34. failed += 1;
  35. logger.warn?.(`DNS auto-check failed for ${domain.domain}: ${error.message}`);
  36. }
  37. }
  38. return {
  39. checked,
  40. failed,
  41. skipped: domains.length - candidates.length
  42. };
  43. }
  44. export function startDnsAutoChecker({
  45. enabled = true,
  46. intervalMs = defaultIntervalMs,
  47. limit = defaultLimit,
  48. logger = console
  49. } = {}) {
  50. if (!enabled) return null;
  51. const state = {
  52. stopped: false,
  53. checking: false
  54. };
  55. const checkIntervalMs = safePositiveInt(intervalMs, defaultIntervalMs);
  56. async function poll() {
  57. if (state.stopped || state.checking) return;
  58. state.checking = true;
  59. try {
  60. await runDnsAutoCheck({
  61. minIntervalMs: checkIntervalMs,
  62. limit,
  63. logger
  64. });
  65. } finally {
  66. state.checking = false;
  67. }
  68. }
  69. const timer = setInterval(poll, checkIntervalMs);
  70. timer.unref?.();
  71. setTimeout(poll, 5000).unref?.();
  72. return {
  73. stop() {
  74. state.stopped = true;
  75. clearInterval(timer);
  76. },
  77. poll
  78. };
  79. }
  80. function safePositiveInt(value, fallback) {
  81. const number = Number(value);
  82. return Number.isFinite(number) && number > 0 ? Math.floor(number) : fallback;
  83. }