mirror of
https://github.com/certd/certd.git
synced 2026-04-23 19:57:27 +08:00
chore: 域名自动同步初步
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user