chore: 域名自动同步初步

This commit is contained in:
xiaojunnuo
2026-01-16 18:18:39 +08:00
parent 8685aa371a
commit be1a70299f
22 changed files with 248 additions and 10 deletions
@@ -4,12 +4,20 @@ import {In, Not, Repository} from 'typeorm';
import {AccessService, BaseService} from '@certd/lib-server';
import {DomainEntity} from '../entity/domain.js';
import {SubDomainService} from "../../pipeline/service/sub-domain-service.js";
import {DomainParser} from "@certd/plugin-cert";
import {createDnsProvider, DomainParser} from "@certd/plugin-lib";
import {DomainVerifiers} from "@certd/plugin-cert";
import { SubDomainsGetter } from '../../pipeline/service/getter/sub-domain-getter.js';
import { CnameRecordService } from '../../cname/service/cname-record-service.js';
import { CnameRecordEntity } from "../../cname/entity/cname-record.js";
import { http, logger, utils } from '@certd/basic';
import { TaskServiceBuilder } from '../../pipeline/service/getter/task-service-getter.js';
import { Pager } from '@certd/pipeline';
export interface SyncFromProviderReq {
userId: number;
dnsProviderType: string;
dnsProviderAccessId: string;
}
/**
*
@@ -28,6 +36,9 @@ export class DomainService extends BaseService<DomainEntity> {
@Inject()
cnameRecordService: CnameRecordService;
@Inject()
taskServiceBuilder: TaskServiceBuilder;
//@ts-ignore
getRepository() {
return this.repository;
@@ -187,4 +198,79 @@ export class DomainService extends BaseService<DomainEntity> {
return domainVerifiers;
}
async syncFromProvider(req: SyncFromProviderReq) {
const { userId, dnsProviderType, dnsProviderAccessId } = req;
const subDomainGetter = new SubDomainsGetter(userId, this.subDomainService)
const domainParser = new DomainParser(subDomainGetter)
const serviceGetter = this.taskServiceBuilder.create({ userId });
const access = await this.accessService.getById(dnsProviderAccessId, userId);
const context = { access, logger, http, utils, domainParser, serviceGetter };
// 翻页查询dns的记录
const dnsProvider = await createDnsProvider({dnsProviderType,context})
const pager = new Pager({
pageNo: 1,
pageSize: 100,
})
const challengeType = "dns"
const importDomain = async(domainRecord: any) =>{
const domain = domainRecord.domain
const old = await this.findOne({
where: {
domain,
userId,
}
})
if (old) {
//更新
await this.update({
id: old.id,
dnsProviderType,
dnsProviderAccess: dnsProviderAccessId,
challengeType,
})
} else {
//添加
await this.add({
userId,
domain,
dnsProviderType,
dnsProviderAccess: dnsProviderAccessId,
challengeType,
})
}
}
const start = async ()=>{
let count = 0
while(true){
const pageRes = await dnsProvider.getDomainListPage(pager)
if(!pageRes || !pageRes.list || pageRes.list.length === 0){
//遍历完成
break
}
//处理
for (const domainRecord of pageRes.list) {
if (domainRecord.thirdDns) {
//域名由第三方dns解析,不导入
continue
}
await importDomain(domainRecord)
}
count += pageRes.list.length
if(pageRes.total>0 && count >= pageRes.total){
//遍历完成
break
}
pager.pageNo++
}
}
start()
}
}
@@ -0,0 +1,88 @@
import { logger } from "@certd/basic"
export class BackTaskExecutor{
tasks :Record<string,Record<string,BackTask>> = {}
add(type:string,task: BackTask){
if (!this.tasks[type]) {
this.tasks[type] = {}
}
this.tasks[type][task.key] = task
}
get(type: string,key: string){
return this.tasks[type][key]
}
removeIsEnd(type: string,key: string){
const task = this.tasks[type]?.[key]
if (task && task.status !== "running") {
this.clear(type,key);
}
}
clear(type: string,key: string){
const task = this.tasks[type]?.[key]
if (task) {
task.clearTimeout();
delete this.tasks[type][key]
}
}
async run(type:string,key: string){
const task = this.tasks[type]?.[key]
if (!task) {
throw new Error(`任务 ${key} 不存在`)
}
task.startTime = Date.now();
task.clearTimeout();
try{
task.status = "running";
return await task.run();
}catch(e){
logger.error(`任务 ${task.title}[${task.key}] 执行失败`, e.message);
task.status = "failed";
task.error = e.message;
}finally{
task.endTime = Date.now();
task.status = "done";
task.timeoutId = setTimeout(() => {
this.clear(type,task.key);
}, 60*60*1000);
}
}
}
export class BackTask{
key:string;
title: string;
total: number = 0;
current: number = 0;
startTime: number;
endTime: number;
status: string = "pending";
error?: string;
timeoutId?: NodeJS.Timeout;
run: () => Promise<void>;
constructor(key:string,title: string,run: () => Promise<void>){
this.key = key;
this.title = title;
Object.defineProperty(this, 'run', {
value: run,
writable: true,
enumerable: false, // 设置为false使其不可遍历
configurable: true
});
}
clearTimeout(){
if (this.timeoutId) {
clearTimeout(this.timeoutId);
this.timeoutId = null;
}
}
}