import { CachedZone, DNSRecord, DNSZone, SOARecord } from "../models/interfaces"; import { readZoneFile } from "./reader"; import { DNSRecordType } from "./records"; import { writeZoneFile } from "./writer"; export class DNSCache { private cached: Record = {}; constructor(private ttl = 1600) {} has(name: string): boolean { return this.cached[name] != null; } async get(name: string): Promise { const cached = this.cached[name]; if (!cached) { return null; } if (cached.changed.getTime() < new Date().getTime() - this.ttl * 1000) { return this.load(name, cached.file); } return this.cached[name]; } async set(name: string, zone: CachedZone): Promise { this.cached[name] = zone; } async load(name: string, file: string): Promise { const zoneFile = await readZoneFile(file); const cache = { name, file, zone: zoneFile, added: new Date(), changed: new Date() } this.cached[name] = cache; return cache; } async save(name: string): Promise { const zone = await this.get(name); if (!zone) { throw new Error('No such cached zone file!'); } await writeZoneFile(zone.zone, zone.file); } async update(name: string, newZone?: CachedZone): Promise { let zone: CachedZone | null; if (newZone) { zone = newZone; } else { zone = await this.get(name); } if (!zone) { throw new Error('No such cached zone file!'); } zone.changed = new Date(); const soa = zone.zone.records.find((record) => record.type === DNSRecordType.SOA) as SOARecord; soa.serial = Math.floor(Date.now() / 1000); this.set(name, zone); return this.save(name); } }