refactor: pipeline edit view

pull/9/head^2
xiaojunnuo 2022-10-26 23:29:10 +08:00
parent 370a28c10e
commit e1466737e3
20 changed files with 89 additions and 94 deletions

View File

@ -15,7 +15,7 @@
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/ban-ts-ignore": "off",
"@typescript-eslint/no-explicit-any": "off",
"no-unused-expressions": "off",
// "no-unused-expressions": "off",
"max-len": [0, 160, 2, { "ignoreUrls": true }]
}
}

View File

@ -3,7 +3,7 @@
"private": true,
"version": "0.3.0",
"main": "./dist/pipeline.umd.js",
"module": "./dist/fast-crud.mjs",
"module": "./dist/pipeline.mjs",
"types": "./dist/es/index.d.ts",
"scripts": {
"dev": "vite",
@ -19,6 +19,7 @@
"node-forge": "^0.10.0"
},
"devDependencies": {
"vue-tsc": "^0.38.9",
"@alicloud/cs20151215": "^3.0.3",
"@alicloud/openapi-client": "^0.4.0",
"@alicloud/pop-core": "^1.7.10",

View File

@ -1,3 +1,4 @@
import { AbstractRegistrable } from "../registry";
import { AccessDefine } from "./api";
export abstract class AbstractAccess extends AbstractRegistrable {}
export abstract class AbstractAccess extends AbstractRegistrable<AccessDefine> {}

View File

@ -8,6 +8,6 @@ export type AccessDefine = Registrable & {
};
export function IsAccess(define: AccessDefine) {
return function (target: any) {
target.define = define;
target.prototype.define = define;
};
}

View File

@ -1,4 +1,4 @@
import { IStorage } from "./storage";
import { IStorage, MemoryStorage } from "./storage";
export interface IContext {
get(key: string): Promise<any>;
@ -7,14 +7,20 @@ export interface IContext {
export class ContextFactory {
storage: IStorage;
memoryStorage: IStorage;
constructor(storage: IStorage) {
this.storage = storage;
this.memoryStorage = new MemoryStorage();
}
getContext(scope: string, namespace: string): IContext {
return new StorageContext(scope, namespace, this.storage);
}
getMemoryContext(scope: string, namespace: string): IContext {
return new StorageContext(scope, namespace, this.memoryStorage);
}
}
export class StorageContext implements IContext {

View File

@ -3,10 +3,9 @@ import _ from "lodash";
import { RunHistory } from "./run-history";
import { pluginRegistry, TaskPlugin } from "../plugin";
import { IAccessService } from "../access/access-service";
import { ContextFactory, StorageContext } from "./context";
import { IStorage, MemoryStorage } from "./storage";
import { ContextFactory } from "./context";
import { IStorage } from "./storage";
import { logger } from "../utils/util.log";
import { use } from "chai";
export class Executor {
userId: any;
@ -16,7 +15,14 @@ export class Executor {
accessService: IAccessService;
contextFactory: ContextFactory;
onChanged: (history: RunHistory) => void;
constructor(options: { userId: any; pipeline: Pipeline; storage: IStorage; onChanged: (history: RunHistory) => void; lastSuccessHistory?: RunHistory; accessService: IAccessService }) {
constructor(options: {
userId: any;
pipeline: Pipeline;
storage: IStorage;
onChanged: (history: RunHistory) => void;
lastSuccessHistory?: RunHistory;
accessService: IAccessService;
}) {
this.pipeline = options.pipeline;
this.lastSuccessHistory = options.lastSuccessHistory ?? new RunHistory();
this.onChanged = options.onChanged;
@ -82,13 +88,29 @@ export class Executor {
private async runStep(step: Step) {
//执行任务
const taskPlugin: TaskPlugin = await this.getPlugin(step.type);
const define = taskPlugin.getDefine();
//从outputContext读取输入参数
_.forEach(define.input, (item, key) => {
if (item.component?.name === "output-selector") {
const contextKey = step.input[key];
if (contextKey != null) {
step.input[key] = this.runtime.context[contextKey];
}
}
});
const res = await taskPlugin.execute(step.input);
_.merge(this.runtime.context, res);
//输出到output context
_.forEach(define.output, (item, key) => {
const contextKey = `step.${step.id}.${key}`;
this.runtime.context[contextKey] = res[key];
});
}
private async getPlugin(type: string): Promise<TaskPlugin> {
const pluginClass = pluginRegistry.get(type);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const plugin = new pluginClass();
await plugin.doInit({

View File

@ -1,18 +1,7 @@
import { AbstractRegistrable } from "../registry";
import {
CreateRecordOptions,
IDnsProvider,
DnsProviderDefine,
RemoveRecordOptions,
} from "./api";
import { CreateRecordOptions, IDnsProvider, DnsProviderDefine, RemoveRecordOptions } from "./api";
import { AbstractAccess } from "../access";
export abstract class AbstractDnsProvider
extends AbstractRegistrable
implements IDnsProvider
{
static define: DnsProviderDefine;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
export abstract class AbstractDnsProvider extends AbstractRegistrable<DnsProviderDefine> implements IDnsProvider {
// @ts-ignore
access: AbstractAccess;

View File

@ -15,6 +15,7 @@ export type RemoveRecordOptions = CreateRecordOptions & {
};
export interface IDnsProvider {
getDefine(): DnsProviderDefine;
createRecord(options: CreateRecordOptions): Promise<any>;
removeRecord(options: RemoveRecordOptions): Promise<any>;
@ -22,7 +23,7 @@ export interface IDnsProvider {
export function IsDnsProvider(define: DnsProviderDefine) {
return function (target: any) {
target.define = define;
target.prototype.define = define;
dnsProviderRegistry.install(target);
};
}

View File

@ -1,12 +1,7 @@
import { AbstractDnsProvider } from "../abstract-dns-provider";
import Core from "@alicloud/pop-core";
import _ from "lodash";
import {
CreateRecordOptions,
IDnsProvider,
IsDnsProvider,
RemoveRecordOptions,
} from "../api";
import { CreateRecordOptions, IDnsProvider, IsDnsProvider, RemoveRecordOptions } from "../api";
@IsDnsProvider({
name: "aliyun",
@ -14,10 +9,7 @@ import {
desc: "阿里云DNS解析提供商",
accessType: "aliyun",
})
export class AliyunDnsProvider
extends AbstractDnsProvider
implements IDnsProvider
{
export class AliyunDnsProvider extends AbstractDnsProvider implements IDnsProvider {
client: any;
constructor() {
super();
@ -42,11 +34,7 @@ export class AliyunDnsProvider
method: "POST",
};
const ret = await this.client.request(
"DescribeDomains",
params,
requestOption
);
const ret = await this.client.request("DescribeDomains", params, requestOption);
return ret.Domains.Domain;
}
@ -80,11 +68,7 @@ export class AliyunDnsProvider
method: "POST",
};
const ret = await this.client.request(
"DescribeDomainRecords",
params,
requestOption
);
const ret = await this.client.request("DescribeDomainRecords", params, requestOption);
return ret.DomainRecords.Record;
}
@ -108,11 +92,7 @@ export class AliyunDnsProvider
};
try {
const ret = await this.client.request(
"AddDomainRecord",
params,
requestOption
);
const ret = await this.client.request("AddDomainRecord", params, requestOption);
this.logger.info("添加域名解析成功:", value, value, ret.RecordId);
return ret.RecordId;
} catch (e: any) {
@ -124,7 +104,7 @@ export class AliyunDnsProvider
}
}
async removeRecord(options: RemoveRecordOptions): Promise<any> {
const { fullRecord, value, type, record } = options;
const { fullRecord, value, record } = options;
const params = {
RegionId: "cn-hangzhou",
RecordId: record,
@ -134,11 +114,7 @@ export class AliyunDnsProvider
method: "POST",
};
const ret = await this.client.request(
"DeleteDomainRecord",
params,
requestOption
);
const ret = await this.client.request("DeleteDomainRecord", params, requestOption);
this.logger.info("删除域名解析成功:", fullRecord, value, ret.RecordId);
return ret.RecordId;
}

View File

@ -1,4 +1,5 @@
import { Registry } from "../registry";
import { AbstractDnsProvider } from "./abstract-dns-provider";
// @ts-ignore
export const dnsProviderRegistry = new Registry<typeof AbstractDnsProvider>();

View File

@ -1,12 +1,11 @@
import { AbstractRegistrable } from "../registry";
import { PluginDefine } from "./api";
import { Logger } from "log4js";
import { logger } from "../utils/util.log";
import { IAccessService } from "../access/access-service";
import { IContext } from "../core/context";
import { PluginDefine, TaskInput, TaskOutput, TaskPlugin } from "./api";
export abstract class AbstractPlugin extends AbstractRegistrable {
static define: PluginDefine;
export abstract class AbstractPlugin extends AbstractRegistrable<PluginDefine> implements TaskPlugin {
logger: Logger = logger;
// @ts-ignore
accessService: IAccessService;
@ -25,4 +24,6 @@ export abstract class AbstractPlugin extends AbstractRegistrable {
protected async onInit(): Promise<void> {
//
}
abstract execute(input: TaskInput): Promise<TaskOutput>;
}

View File

@ -22,7 +22,6 @@ export type Storage = {
export type TaskOutputDefine = {
title: string;
key: string;
value?: any;
storage?: Storage;
};
@ -38,6 +37,7 @@ export type PluginDefine = Registrable & {
};
export interface TaskPlugin {
getDefine(): PluginDefine;
execute(input: TaskInput): Promise<TaskOutput>;
}
@ -50,9 +50,9 @@ export type OutputVO = {
export function IsTask(define: (() => PluginDefine) | PluginDefine) {
return function (target: any) {
if (define instanceof Function) {
target.define = define();
target.prototype.define = define();
} else {
target.define = define;
target.prototype.define = define;
}
pluginRegistry.install(target);

View File

@ -1,12 +1,12 @@
// @ts-ignore
import acme, { Authorization } from "@certd/acme-client";
import * as acme from "@certd/acme-client";
import _ from "lodash";
import { logger } from "../../../utils/util.log";
import { AbstractDnsProvider } from "../../../dns-provider/abstract-dns-provider";
import { IContext } from "../../../core/context";
import { IDnsProvider } from "../../../dns-provider";
import { Challenge } from "@certd/acme-client/types/rfc8555";
console.log("acme", acme);
export class AcmeService {
userContext: IContext;
constructor(options: { userContext: IContext }) {
@ -155,10 +155,10 @@ export class AcmeService {
email: email,
termsOfServiceAgreed: true,
challengePriority: ["dns-01"],
challengeCreateFn: async (authz: Authorization, challenge: Challenge, keyAuthorization: string): Promise<any> => {
challengeCreateFn: async (authz: acme.Authorization, challenge: Challenge, keyAuthorization: string): Promise<any> => {
return await this.challengeCreateFn(authz, challenge, keyAuthorization, dnsProvider);
},
challengeRemoveFn: async (authz: Authorization, challenge: Challenge, keyAuthorization: string, recordItem: any): Promise<any> => {
challengeRemoveFn: async (authz: acme.Authorization, challenge: Challenge, keyAuthorization: string, recordItem: any): Promise<any> => {
return await this.challengeRemoveFn(authz, challenge, keyAuthorization, recordItem, dnsProvider);
},
});

View File

@ -17,6 +17,7 @@ export type CertInfo = {
title: "证书申请",
input: {
domains: {
title: "域名",
component: {
name: "a-select",
vModel: "value",
@ -28,6 +29,7 @@ export type CertInfo = {
helper: "请输入域名",
},
email: {
title: "邮箱",
component: {
name: "a-input",
vModel: "value",
@ -35,12 +37,14 @@ export type CertInfo = {
helper: "请输入邮箱",
},
dnsProviderType: {
title: "DNS提供商",
component: {
name: "a-select",
},
helper: "请选择dns解析提供商",
},
dnsProviderAccess: {
title: "DNS解析授权",
component: {
name: "access-selector",
},
@ -49,7 +53,7 @@ export type CertInfo = {
renewDays: {
title: "更新天数",
component: {
name: "a-number",
name: "a-input-number",
value: 20,
},
helper: "到期前多少天后更新证书",

View File

@ -69,18 +69,17 @@ export class DeployCertToAliyunCDN extends AbstractPlugin implements TaskPlugin
}
async buildParams(input: TaskInput) {
const { certName, domainName, cert } = input;
const { certName, domainName } = input;
const CertName = certName + "-" + dayjs().format("YYYYMMDDHHmmss");
const newCert = (await this.pipelineContext.get(cert)) as CertInfo;
const cert = input.cert as CertInfo;
return {
RegionId: "cn-hangzhou",
DomainName: domainName,
ServerCertificateStatus: "on",
CertName: CertName,
CertType: "upload",
ServerCertificate: newCert.crt,
PrivateKey: newCert.key,
ServerCertificate: cert.crt,
PrivateKey: cert.key,
};
}
@ -95,7 +94,7 @@ export class DeployCertToAliyunCDN extends AbstractPlugin implements TaskPlugin
checkRet(ret: any) {
if (ret.code != null) {
throw new Error("执行失败:", ret.Message);
throw new Error("执行失败:" + ret.Message);
}
}
}

View File

@ -7,6 +7,7 @@ import { IsTask, TaskInput, TaskOutput, TaskPlugin } from "../api";
title: "测试插件回声",
input: {
cert: {
title: "cert",
component: {
name: "output-selector",
},

View File

@ -1,4 +1,5 @@
import { Registry } from "../registry";
import { AbstractPlugin } from "./abstract-plugin";
// @ts-ignore
export const pluginRegistry = new Registry<typeof AbstractPlugin>();

View File

@ -7,9 +7,14 @@ export type Registrable = {
desc?: string;
};
export abstract class AbstractRegistrable {
static define: Registrable;
export abstract class AbstractRegistrable<T extends Registrable> {
logger: Logger = logger;
// @ts-ignore
define: T;
getDefine(): T {
return this.define;
}
}
export class Registry<T extends typeof AbstractRegistrable> {
storage: {
@ -20,7 +25,9 @@ export class Registry<T extends typeof AbstractRegistrable> {
if (target == null) {
return;
}
let defineName = target.define.name;
// @ts-ignore
const define = new target().define;
let defineName = define.name;
if (defineName == null) {
defineName = target.name;
}

View File

@ -1,16 +0,0 @@
export interface ServiceContext {
get(name: string): any;
register(name: string, service: any): void;
}
export class ServiceContextImpl implements ServiceContext {
register(name: string, service: any): void {}
storage: {
[key: string]: any;
} = {};
get(name: string): any {
return this.storage[name];
}
}
export const serviceContext = new ServiceContextImpl();

View File

@ -3,8 +3,9 @@ import "mocha";
import { EchoPlugin } from "../src/plugin/plugins";
describe("task_plugin", function () {
it("#taskplugin", function () {
const define = EchoPlugin.define;
new EchoPlugin().execute({ context: {}, props: { test: 111 } });
const echoPlugin = new EchoPlugin();
const define = echoPlugin.define;
echoPlugin.execute({ context: {}, props: { test: 111 } });
expect(define.name).eq("EchoPlugin");
});
});