From 43c7a1984926f5d4647760cc134bb0aede3a7b7a Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Thu, 12 Jun 2025 23:51:21 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E6=94=AF=E6=8C=81=E9=9B=A8=E4=BA=91dns?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E4=BB=A5=E5=8F=8A=E9=9B=A8=E4=BA=91=E8=AF=81?= =?UTF-8?q?=E4=B9=A6=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../access/access-selector/access/crud.tsx | 54 ++++----- packages/ui/certd-server/src/plugins/index.ts | 1 + .../src/plugins/plugin-rainyun/access.ts | 65 ++++++++-- .../plugins/plugin-rainyun/dns-provider.ts | 67 +++++------ .../plugins/plugin-refresh-cert.ts | 113 ++++++++++++++++++ 5 files changed, 230 insertions(+), 70 deletions(-) create mode 100644 packages/ui/certd-server/src/plugins/plugin-rainyun/plugins/plugin-refresh-cert.ts diff --git a/packages/ui/certd-client/src/views/certd/access/access-selector/access/crud.tsx b/packages/ui/certd-client/src/views/certd/access/access-selector/access/crud.tsx index 9bcd93ec..23bbb1f8 100644 --- a/packages/ui/certd-client/src/views/certd/access/access-selector/access/crud.tsx +++ b/packages/ui/certd-client/src/views/certd/access/access-selector/access/crud.tsx @@ -49,38 +49,38 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat pageRequest, addRequest, editRequest, - delRequest + delRequest, }, toolbar: { - show: false + show: false, }, search: { - show: false + show: false, }, form: { wrapper: { - width: "1050px" - } + width: "1050px", + }, }, rowHandle: { - width: 200 + width: 200, }, table: { scroll: { - x: 800 + x: 800, }, rowSelection: { type: "radio", selectedRowKeys: selectedRowKey, - onChange: onSelectChange + onChange: onSelectChange, }, customRow: (record: any) => { return { onClick: () => { onSelectChange([record.id]); - } // 点击行 + }, // 点击行 }; - } + }, }, columns: { id: { @@ -88,25 +88,25 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat key: "id", type: "number", column: { - width: 50 + width: 50, }, form: { - show: false - } + show: false, + }, }, name: { title: "名称", search: { - show: true + show: true, }, type: ["text"], form: { rules: [{ required: true, message: "请填写名称" }], - helper: "随便填,当多个相同类型的授权时,便于区分" + helper: "随便填,当多个相同类型的授权时,便于区分", }, column: { - width: 200 - } + width: 200, + }, }, from: { title: "级别", @@ -114,29 +114,29 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat dict: dict({ data: [ { label: "系统", value: "sys" }, - { label: "用户", value: "user" } - ] + { label: "用户", value: "user" }, + ], }), search: { - show: false + show: false, }, form: { - show: false + show: false, }, column: { width: 100, align: "center", component: { - color: "auto" + color: "auto", }, - order: 10 + order: 10, }, valueBuilder: ({ row, key, value }) => { row[key] = row.userId > 0 ? "user" : "sys"; - } + }, }, - ...commonColumnsDefine - } - } + ...commonColumnsDefine, + }, + }, }; } diff --git a/packages/ui/certd-server/src/plugins/index.ts b/packages/ui/certd-server/src/plugins/index.ts index 00bdced3..485b2216 100644 --- a/packages/ui/certd-server/src/plugins/index.ts +++ b/packages/ui/certd-server/src/plugins/index.ts @@ -24,3 +24,4 @@ export * from './plugin-notification/index.js' export * from './plugin-flex/index.js' export * from './plugin-farcdn/index.js' export * from './plugin-fnos/index.js' +export * from './plugin-rainyun/index.js' diff --git a/packages/ui/certd-server/src/plugins/plugin-rainyun/access.ts b/packages/ui/certd-server/src/plugins/plugin-rainyun/access.ts index dc5c5cb6..18e44529 100644 --- a/packages/ui/certd-server/src/plugins/plugin-rainyun/access.ts +++ b/packages/ui/certd-server/src/plugins/plugin-rainyun/access.ts @@ -1,5 +1,6 @@ import {AccessInput, BaseAccess, IsAccess} from "@certd/pipeline"; import {HttpRequestConfig} from "@certd/basic"; +import { CertInfo } from "@certd/plugin-cert"; /** @@ -41,13 +42,13 @@ export class RainyunAccess extends BaseAccess { testRequest = true; async onTestRequest() { - await this.getDomainList({}); + await this.getDomainList({limit:1}); 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; + async getDomainList(req:{offset?:number,limit?:number,query?:string}){ + const size = req.limit ?? 20; const offset = req.offset ?? 0; let page = Math.floor(offset / size); if(offset % size === 0 ){ @@ -67,17 +68,63 @@ export class RainyunAccess extends BaseAccess { return { total: res.TotalRecords, - list: res.Records || [] + list: res.Records || [], + limit: size, + offset: offset } } - async getDomainId(domain:string){ - const res = await this.getDomainList({query: domain,size:1}); - if (res.list.length === 0) { - throw new Error(`域名${domain}不存在 ` ); + async getCertList(req:{offset?:number,limit?:number,query?:string}){ + const size = req.limit ?? 20; + const offset = req.offset ?? 0; + let page = Math.floor(offset / size); + if(offset % size === 0 ){ + page++ } - return res.list[0].ID; + const options ={ + columnFilters: { + Domain: req.query??"" + }, + sort:[], + page: page, + perPage: size, + + } + const res = await this.doRequest({ + url: `product/sslcenter/?options=${encodeURIComponent(JSON.stringify(options))}`, + method: "GET", + }); + + return { + total: res.TotalRecords, + list: res.Records || [], + limit: size, + offset: offset + } + } + + async doCertReplace(req:{certId:number,cert:CertInfo}){ + + // /product/sslcenter/{id} + return await this.doRequest({ + url: `product/sslcenter/${req.certId}`, + method: "PUT", + data: { + cert: req.cert.crt, + key: req.cert.key, + } + }); + + } + + + async getDomainId(domain:string){ + const res = await this.getDomainList({query: domain,limit:1}); + if (res.list.length === 0) { + throw new Error(`域名${domain}不存在` ); + } + return res.list[0].id; } async doRequest(req:HttpRequestConfig){ diff --git a/packages/ui/certd-server/src/plugins/plugin-rainyun/dns-provider.ts b/packages/ui/certd-server/src/plugins/plugin-rainyun/dns-provider.ts index ea5adc46..c37800ef 100644 --- a/packages/ui/certd-server/src/plugins/plugin-rainyun/dns-provider.ts +++ b/packages/ui/certd-server/src/plugins/plugin-rainyun/dns-provider.ts @@ -1,65 +1,64 @@ -import {AbstractDnsProvider, CreateRecordOptions, IsDnsProvider, RemoveRecordOptions} from '@certd/plugin-cert'; -import {RainyunAccess} from "./access.js"; +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, + 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 { - const access: RainyunAccess = this.ctx.access as RainyunAccess + const access: RainyunAccess = this.ctx.access as RainyunAccess; const domainId = await access.getDomainId(options.domain); if (!domainId) { throw new Error(`域名${options.domain}未找到`); } - const { fullRecord,hostRecord, value, type, domain } = options; - this.logger.info('添加域名解析:', fullRecord, value, domain); + const { fullRecord, hostRecord, value, type, domain } = options; + this.logger.info("添加域名解析:", fullRecord, value, domain); - const ret = await access.doRequest({ - url: `/product/domain/${domainId}/dns`, - method: 'POST', - data: { - host: hostRecord, - value: value, - type: type, - line: 'DEFAULT', - ttl: 360, - }, - }); - this.logger.info('添加域名解析成功:', JSON.stringify(options), ret.ID); - return { - recordId:ret.ID, - domainId: domainId - }; + const ret = await access.doRequest({ + url: `/product/domain/${domainId}/dns`, + method: "POST", + data: { + host: hostRecord, + value: value, + level: 1, + type: type, + line: "DEFAULT", + ttl: 60 + } + }); + this.logger.info("添加域名解析成功:", JSON.stringify(options), ret); + return { + recordId: ret, + domainId: domainId + }; } async removeRecord(options: RemoveRecordOptions): Promise { const { fullRecord, value } = options.recordReq; - const access: RainyunAccess = this.ctx.access as RainyunAccess + const access: RainyunAccess = this.ctx.access as RainyunAccess; const record = options.recordRes; const ret = await access.doRequest({ - url: `/product/domain/${record.domainId}/dns`, - method: 'DELETE', - data:{ - record_id: record.recordId - } + url: `/product/domain/${record.domainId}/dns?record_id=${record.recordId}`, + method: "DELETE", }); - this.logger.info('删除域名解析成功:', fullRecord, value, ret); + this.logger.info("删除域名解析成功:", fullRecord, value, ret); return ret; } } diff --git a/packages/ui/certd-server/src/plugins/plugin-rainyun/plugins/plugin-refresh-cert.ts b/packages/ui/certd-server/src/plugins/plugin-rainyun/plugins/plugin-refresh-cert.ts new file mode 100644 index 00000000..4ce5254f --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-rainyun/plugins/plugin-refresh-cert.ts @@ -0,0 +1,113 @@ +import { AbstractTaskPlugin, IsTaskPlugin, PageReq, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline"; +import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert"; +import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from "@certd/plugin-lib"; +import { RainyunAccess } from "../access.js"; + +@IsTaskPlugin({ + //命名规范,插件类型+功能(就是目录plugin-demo中的demo),大写字母开头,驼峰命名 + name: "RainyunRefreshCert", + title: "雨云-更新证书", + desc: "app.rainyun.com", + icon: "svg:icon-lucky", + //插件分组 + group: pluginGroups.cdn.key, + needPlus: false, + default: { + //默认值配置照抄即可 + strategy: { + runStrategy: RunStrategy.SkipWhenSucceed + } + } +}) +//类名规范,跟上面插件名称(name)一致 +export class RainyunRefreshCert extends AbstractTaskPlugin { + //证书选择,此项必须要有 + @TaskInput({ + title: "域名证书", + helper: "请选择前置任务输出的域名证书", + component: { + name: "output-selector", + from: [...CertApplyPluginNames] + } + // required: true, // 必填 + }) + cert!: CertInfo; + + @TaskInput(createCertDomainGetterInputDefine({ props: { required: false } })) + certDomains!: string[]; + + //授权选择框 + @TaskInput({ + title: "雨云授权", + component: { + name: "access-selector", + type: "rainyun" //固定授权类型 + }, + required: true //必填 + }) + accessId!: string; + // + + @TaskInput( + createRemoteSelectInputDefine({ + title: "证书Id", + helper: "要更新的rainyun证书id", + + action: RainyunRefreshCert.prototype.onGetCertList.name + }) + ) + certList!: number[]; + + //插件实例化时执行的方法 + async onInstance() { + } + + //插件执行方法 + async execute(): Promise { + const access = await this.getAccess(this.accessId); + + for (const item of this.certList) { + this.logger.info(`----------- 开始更新证书:${item}`); + await access.doCertReplace({ + certId: item, + cert: this.cert + }); + this.logger.info(`----------- 更新证书${item}成功`); + } + + this.logger.info("部署完成"); + } + + async onGetCertList(req: PageReq = {}) { + const access = await this.getAccess(this.accessId); + + const offset = req.offset ?? 0; + const limit = req.limit ?? 100; + const res = await access.getCertList({ + offset, + limit + }); + const total = res.total; + const list = res.list; + if (!list || list.length === 0) { + throw new Error("没有找到证书,请先在控制台上传一次证书且关联站点"); + } + + const options = list.map((item: any) => { + return { + label: `${item.Domain}<${item.ID}>`, + value: item.ID, + domain: item.Domain.split(",").map(item => item.trim()) + }; + }); + return { + list: this.ctx.utils.options.buildGroupOptions(options, this.certDomains), + total: total, + offset: offset, + limit: limit + }; + } +} + +//实例化一下,注册插件 +new RainyunRefreshCert();