This repository has been archived on 2024-04-14. You can view files and clone it, but cannot push or open issues or pull requests.
icydns/src/dns/cache.ts

87 lines
2.1 KiB
TypeScript

import { CachedZone, SOARecord } from '../models/interfaces';
import { readZoneFile } from './reader';
import { DNSRecordType } from './records';
import { ReloadExecutor } from './rndc';
import { ValidatorExecutor } from './validator';
export class DNSCache {
private cached: Record<string, CachedZone> = {};
constructor(
private rndc: ReloadExecutor,
private validator: ValidatorExecutor,
private ttl = 1600
) {}
has(name: string): boolean {
return this.cached[name] != null;
}
async get(name: string): Promise<CachedZone | null> {
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<void> {
this.cached[name] = zone;
}
async load(name: string, file: string): Promise<CachedZone> {
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<void> {
const zone = await this.get(name);
if (!zone) {
throw new Error('No such cached zone file!');
}
await this.validator.validateAndSave(name, zone);
}
async update(name: string, newZone?: CachedZone, skipReload = false): Promise<void> {
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);
await this.save(name);
if (!skipReload) {
try {
await this.rndc.reload(name);
} catch (e) {
console.warn('%s automatic zone reload failed:', name, e.stack);
}
}
}
}