chore: 雨云支持

pull/436/head
xiaojunnuo 2025-06-10 18:41:25 +08:00
parent 1e863382d3
commit 12ed79ca60
4 changed files with 180 additions and 0 deletions

View File

@ -0,0 +1,90 @@
import {AccessInput, BaseAccess, IsAccess} from "@certd/pipeline";
import {HttpRequestConfig} from "@certd/basic";
/**
*/
@IsAccess({
name: "rainyun",
title: "雨云授权",
desc: "https://app.rainyun.com/",
icon: "svg:icon-lucky"
})
export class RainyunAccess extends BaseAccess {
@AccessInput({
title: "ApiKey",
component: {
placeholder: "api-key",
component: {
name: "a-input",
vModel: "value"
}
},
encrypt: true,
required: true
})
apiKey!: string;
@AccessInput({
title: "测试",
component: {
name: "api-test",
action: "TestRequest"
},
helper: "点击测试接口是否正常"
})
testRequest = true;
async onTestRequest() {
await this.getDomainList({});
return "ok"
}
// {"columnFilters":{"domains.Domain":"domain"},"sort":[],"page":1,"perPage":20}
async getDomainList(req:{offset?:number,size?:number,query?:string}){
const size = req.size ?? 20;
const offset = req.offset ?? 0;
const page = offset % size === 0 ? offset / size : Math.floor(offset / size) + 1;
const options ={
page: page,
perPage: size,
columnFilters: {
"domains.Domain": req.query??""
},
}
return await this.doRequest({
url: "/product/domain/",
method: "GET",
params: {
options: JSON.stringify(options)
}
});
}
async doRequest(req:HttpRequestConfig){
const res = await this.ctx.http.request({
url: req.url,
baseURL:"https://api.v2.rainyun.com",
method: req.method|| "POST",
data: req.data,
params: req.params,
headers:{
"x-api-key": this.apiKey
},
// httpProxy: this.httpProxy||undefined,
});
if (res.code === 200) {
return res.data;
}
throw new Error(res.message || res);
}
}
new RainyunAccess();

View File

@ -0,0 +1,88 @@
import {AbstractDnsProvider, CreateRecordOptions, IsDnsProvider, RemoveRecordOptions} from '@certd/plugin-cert';
import {RainyunAccess} from "./access.js";
@IsDnsProvider({
name: 'rainyun',
title: '雨云',
desc: '雨云DNS解析提供商',
accessType: 'rainyun',
icon: 'svg:icon-lucky',
order:0,
})
export class RainyunDnsProvider extends AbstractDnsProvider {
client: any;
async onInstance() {
}
async createRecord(options: CreateRecordOptions): Promise<any> {
const access: RainyunAccess = this.ctx.access as RainyunAccess
console.log(access)
const { fullRecord,hostRecord, value, type, domain } = options;
this.logger.info('添加域名解析:', fullRecord, value, domain);
// const domain = await this.matchDomain(fullRecord);
const params = {
RegionId: 'cn-hangzhou',
DomainName: domain,
RR: hostRecord,
Type: type,
Value: value,
// Line: 'oversea' // 海外
};
const requestOption = {
method: 'POST',
};
try {
const ret = await this.client.request('AddDomainRecord', params, requestOption);
this.logger.info('添加域名解析成功:', JSON.stringify(options), ret.RecordId);
return ret.RecordId;
} catch (e: any) {
if (e.code === 'DomainRecordDuplicate') {
return;
}
if(e.code === "LastOperationNotFinished"){
this.logger.info('上一个操作还未完成5s后重试')
await this.ctx.utils.sleep(5000)
return this.createRecord(options)
}
this.logger.info('添加域名解析出错', e);
this.resolveError(e, options);
}
}
resolveError(e: any, req: CreateRecordOptions) {
if (e.message?.indexOf('The specified domain name does not exist') > -1) {
throw new Error(`阿里云账号中不存在此域名:${req.domain}`);
}
throw e;
}
async removeRecord(options: RemoveRecordOptions<any>): Promise<any> {
const { fullRecord, value } = options.recordReq;
const record = options.recordRes;
const params = {
RegionId: 'cn-hangzhou',
RecordId: record,
};
const requestOption = {
method: 'POST',
};
try{
const ret = await this.client.request('DeleteDomainRecord', params, requestOption);
this.logger.info('删除域名解析成功:', fullRecord, value, ret.RecordId);
return ret.RecordId;
}catch (e) {
if(e.code === "LastOperationNotFinished"){
this.logger.info('上一个操作还未完成5s后重试')
await this.ctx.utils.sleep(5000)
return this.removeRecord(options)
}
throw e
}
}
}
new RainyunDnsProvider();

View File

@ -0,0 +1,2 @@
export * from "./plugins/index.js";
export * from "./access.js";