refactor(core): 重构访问控制和插件实例化逻辑

- 修改访问控制和插件注册方式,使用异步函数统一实例化逻辑
- 更新相关组件和控制器以适应新的异步实例化方式
- 优化 DNS 提供商选择器,增加访问类型支持
pull/370/head
xiaojunnuo 2025-04-12 01:21:50 +08:00
parent c4fb138ae8
commit 3d8a5196a0
15 changed files with 79 additions and 39 deletions

View File

@ -26,7 +26,9 @@ export function IsAccess(define: AccessDefine): ClassDecorator {
target.define = define;
accessRegistry.register(define.name, {
define,
target,
target: async () => {
return target;
},
});
};
}
@ -39,13 +41,15 @@ export function AccessInput(input?: AccessInputDefine): PropertyDecorator {
};
}
export function newAccess(type: string, input: any, ctx?: AccessContext) {
export async function newAccess(type: string, input: any, ctx?: AccessContext) {
const register = accessRegistry.get(type);
if (register == null) {
throw new Error(`access ${type} not found`);
}
// @ts-ignore
const access = new register.target();
const accessCls = await register.target();
// @ts-ignore
const access = new accessCls();
for (const key in input) {
access[key] = input[key];
}

View File

@ -281,13 +281,9 @@ export class Executor {
let instance: ITaskPlugin = null;
try {
//@ts-ignore
if (plugin.target.define) {
//@ts-ignore
instance = new plugin.target();
} else {
//@ts-ignore
instance = await plugin.target();
}
const pluginCls = await plugin.target();
//@ts-ignore
instance = new pluginCls();
} catch (e: any) {
currentLogger.error(`实例化插件失败:${e.message}`);
throw new Error(`实例化插件失败`, e);

View File

@ -26,7 +26,9 @@ export function IsNotification(define: NotificationDefine): ClassDecorator {
target.define = define;
notificationRegistry.register(define.name, {
define,
target,
target: async () => {
return target;
},
});
};
}
@ -44,9 +46,10 @@ export async function newNotification(type: string, input: any, ctx: Notificatio
if (register == null) {
throw new Error(`notification ${type} not found`);
}
// @ts-ignore
const plugin = new register.target();
const pluginCls = await register.target();
// @ts-ignore
const plugin = new pluginCls();
merge(plugin, input);
if (!ctx) {
throw new Error("ctx is required");

View File

@ -65,7 +65,9 @@ export function IsTaskPlugin(define: PluginDefine): ClassDecorator {
pluginRegistry.register(define.name, {
define,
target,
target: async () => {
return target;
},
});
};
}

View File

@ -11,7 +11,7 @@ export type Registrable = {
export type TargetGetter<T> = () => Promise<T>;
export type RegistryItem<T> = {
define: Registrable;
target: T | TargetGetter<T>;
target: TargetGetter<T>;
};
export type OnRegisterContext<T> = {

View File

@ -140,7 +140,7 @@ export class AccessService extends BaseService<AccessEntity> {
id: entity.id,
...setting,
};
return newAccess(entity.type, input);
return await newAccess(entity.type, input);
}
async getById(id: any, userId: number): Promise<any> {

View File

@ -29,6 +29,7 @@ export type DomainVerifyPlanInput = {
domain: string;
type: "cname" | "dns" | "http";
dnsProviderType?: string;
dnsProviderAccessType?: string;
dnsProviderAccessId?: number;
cnameVerifyPlan?: Record<string, CnameRecordInput>;
httpVerifyPlan?: Record<string, HttpRecordInput>;
@ -99,7 +100,14 @@ HTTP文件验证不支持泛域名需要配置网站文件上传`,
return {
show: ctx.compute(({form})=>{
return form.challengeType === 'dns'
})
}),
component:{
on:{
selectedChange({form,$event}){
form.dnsProviderAccessType = $event.accessType
}
}
}
}
`,
required: true,
@ -107,6 +115,8 @@ HTTP文件验证不支持泛域名需要配置网站文件上传`,
})
dnsProviderType!: string;
dnsProviderAccessType!: string;
@TaskInput({
title: "DNS解析授权",
component: {
@ -117,7 +127,7 @@ HTTP文件验证不支持泛域名需要配置网站文件上传`,
mergeScript: `return {
component:{
type: ctx.compute(({form})=>{
return form.dnsProviderType
return form.dnsProviderAccessType || form.dnsProviderType
})
},
show: ctx.compute(({form})=>{

View File

@ -5,6 +5,6 @@ const apiPrefix = "/pi/dnsProvider";
export async function GetList() {
return await request({
url: apiPrefix + "/list",
method: "post"
method: "post",
});
}

View File

@ -11,10 +11,10 @@ export default {
props: {
modelValue: {
type: String,
default: undefined
}
default: undefined,
},
},
emits: ["update:modelValue"],
emits: ["update:modelValue", "selected-change"],
setup(props: any, ctx: any) {
const options = ref<any[]>([]);
@ -25,24 +25,36 @@ export default {
array.push({
value: item.name,
label: item.title,
icon: item.icon
icon: item.icon,
accessType: item.accessType,
});
}
options.value = array;
// if (props.modelValue == null && options.value.length > 0) {
// ctx.emit("update:modelValue", options.value[0].value);
// }
onSelectedChange(props.modelValue);
}
onCreate();
function onChanged(value: any) {
ctx.emit("update:modelValue", value);
onSelectedChange(value);
}
function onSelectedChange(value: any) {
if (value) {
const option = options.value.find(item => item.value == value);
if (option) {
ctx.emit("selected-change", option);
return;
}
}
}
return {
options,
onChanged
onChanged,
};
}
},
};
</script>

View File

@ -35,7 +35,7 @@ import { HttpRecord } from "/@/components/plugins/cert/domains-verify-plan-edito
import { dict } from "@fast-crud/fast-crud";
defineOptions({
name: "HttpVerifyPlan"
name: "HttpVerifyPlan",
});
const emit = defineEmits(["update:modelValue", "change"]);
@ -53,12 +53,12 @@ watch(
(value: any) => {
if (value) {
records.value = {
...value
...value,
};
}
},
{
immediate: true
immediate: true,
}
);
@ -75,8 +75,8 @@ const uploaderTypeDict = dict({
{ label: "阿里云OSS", value: "alioss" },
{ label: "腾讯云COS", value: "tencentcos" },
{ label: "七牛OSS", value: "qiniuoss" },
{ label: "SSH(已废弃请选择SFTP方式)", value: "ssh", disabled: true }
]
{ label: "SSH(已废弃请选择SFTP方式)", value: "ssh", disabled: true },
],
});
</script>

View File

@ -32,14 +32,21 @@
<div class="form-item">
<span class="label">DNS类型</span>
<span class="input">
<fs-dict-select v-model:value="item.dnsProviderType" size="small" :dict="dnsProviderTypeDict" placeholder="DNS提供商" @change="onPlanChanged"></fs-dict-select>
<fs-dict-select
v-model:value="item.dnsProviderType"
size="small"
:dict="dnsProviderTypeDict"
placeholder="DNS提供商"
@change="onPlanChanged"
@selected-change="onDnsProviderChange(item, $event)"
></fs-dict-select>
</span>
</div>
<a-divider type="vertical" />
<div class="form-item">
<span class="label">DNS授权</span>
<span class="input">
<access-selector v-model="item.dnsProviderAccessId" size="small" :type="item.dnsProviderType" placeholder="请选择" @change="onPlanChanged"></access-selector>
<access-selector v-model="item.dnsProviderAccessId" size="small" :type="item.dnsProviderAccessType || item.dnsProviderType" placeholder="请选择" @change="onPlanChanged"></access-selector>
</span>
</div>
</div>
@ -101,6 +108,10 @@ const emit = defineEmits<{
"update:modelValue": any;
}>();
function onDnsProviderChange(item: any, option: any) {
item.dnsProviderAccessType = option.accessType;
}
const fullscreen = ref(false);
function fullscreenExit() {
if (fullscreen.value) {

View File

@ -12,6 +12,7 @@ export type DomainVerifyPlanInput = {
domains: string[];
type: "cname" | "dns" | "http";
dnsProviderType?: string;
dnsProviderAccessType?: string;
dnsProviderAccessId?: number;
cnameVerifyPlan?: Record<string, CnameRecord>;
httpVerifyPlan?: Record<string, HttpRecord>;

View File

@ -27,6 +27,8 @@ export class DnsProviderController extends BaseController {
dict.push({
value: item.name,
label: item.title,
//@ts-ignore
accessType: item.accessType,
});
}
return this.ok(dict);

View File

@ -49,7 +49,7 @@ export class HandleController extends BaseController {
}
}
const access = newAccess(body.typeName, inputAccess);
const access = await newAccess(body.typeName, inputAccess);
const res = await access.onRequest(body);
@ -76,7 +76,7 @@ export class HandleController extends BaseController {
async pluginRequest(@Body(ALL) body: PluginRequestHandleReq) {
const userId = this.getUserId();
const pluginDefine = pluginRegistry.get(body.typeName);
const pluginCls = pluginDefine.target;
const pluginCls = await pluginDefine.target();
if (pluginCls == null) {
throw new Error(`plugin ${body.typeName} not found`);
}

View File

@ -213,10 +213,9 @@ export class PluginService extends BaseService<PluginEntity> {
// const script = await this.compile(plugin.content);
const script = plugin.content
const getPluginClass = new AsyncFunction(script);
const pluginClass = await getPluginClass({ logger: logger });
return new pluginClass();
return await getPluginClass({ logger: logger });
}catch (e) {
logger.error("实例化插件失败:",e)
logger.error("编译插件失败:",e)
throw e
}
@ -266,8 +265,8 @@ export class PluginService extends BaseService<PluginEntity> {
registry.register(item.name, {
define: item,
target: () => {
return this.getPluginTarget(item.name);
target: async () => {
return await this.getPluginTarget(item.name);
}
});
}