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-comment": "off",
"@typescript-eslint/ban-ts-ignore": "off", "@typescript-eslint/ban-ts-ignore": "off",
"@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-explicit-any": "off",
"no-unused-expressions": "off", // "no-unused-expressions": "off",
"max-len": [0, 160, 2, { "ignoreUrls": true }] "max-len": [0, 160, 2, { "ignoreUrls": true }]
} }
} }

View File

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

View File

@ -1,3 +1,4 @@
import { AbstractRegistrable } from "../registry"; 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) { export function IsAccess(define: AccessDefine) {
return function (target: any) { 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 { export interface IContext {
get(key: string): Promise<any>; get(key: string): Promise<any>;
@ -7,14 +7,20 @@ export interface IContext {
export class ContextFactory { export class ContextFactory {
storage: IStorage; storage: IStorage;
memoryStorage: IStorage;
constructor(storage: IStorage) { constructor(storage: IStorage) {
this.storage = storage; this.storage = storage;
this.memoryStorage = new MemoryStorage();
} }
getContext(scope: string, namespace: string): IContext { getContext(scope: string, namespace: string): IContext {
return new StorageContext(scope, namespace, this.storage); 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 { export class StorageContext implements IContext {

View File

@ -3,10 +3,9 @@ import _ from "lodash";
import { RunHistory } from "./run-history"; import { RunHistory } from "./run-history";
import { pluginRegistry, TaskPlugin } from "../plugin"; import { pluginRegistry, TaskPlugin } from "../plugin";
import { IAccessService } from "../access/access-service"; import { IAccessService } from "../access/access-service";
import { ContextFactory, StorageContext } from "./context"; import { ContextFactory } from "./context";
import { IStorage, MemoryStorage } from "./storage"; import { IStorage } from "./storage";
import { logger } from "../utils/util.log"; import { logger } from "../utils/util.log";
import { use } from "chai";
export class Executor { export class Executor {
userId: any; userId: any;
@ -16,7 +15,14 @@ export class Executor {
accessService: IAccessService; accessService: IAccessService;
contextFactory: ContextFactory; contextFactory: ContextFactory;
onChanged: (history: RunHistory) => void; 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.pipeline = options.pipeline;
this.lastSuccessHistory = options.lastSuccessHistory ?? new RunHistory(); this.lastSuccessHistory = options.lastSuccessHistory ?? new RunHistory();
this.onChanged = options.onChanged; this.onChanged = options.onChanged;
@ -82,13 +88,29 @@ export class Executor {
private async runStep(step: Step) { private async runStep(step: Step) {
//执行任务 //执行任务
const taskPlugin: TaskPlugin = await this.getPlugin(step.type); 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); 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> { private async getPlugin(type: string): Promise<TaskPlugin> {
const pluginClass = pluginRegistry.get(type); const pluginClass = pluginRegistry.get(type);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
const plugin = new pluginClass(); const plugin = new pluginClass();
await plugin.doInit({ await plugin.doInit({

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -69,18 +69,17 @@ export class DeployCertToAliyunCDN extends AbstractPlugin implements TaskPlugin
} }
async buildParams(input: TaskInput) { async buildParams(input: TaskInput) {
const { certName, domainName, cert } = input; const { certName, domainName } = input;
const CertName = certName + "-" + dayjs().format("YYYYMMDDHHmmss"); const CertName = certName + "-" + dayjs().format("YYYYMMDDHHmmss");
const cert = input.cert as CertInfo;
const newCert = (await this.pipelineContext.get(cert)) as CertInfo;
return { return {
RegionId: "cn-hangzhou", RegionId: "cn-hangzhou",
DomainName: domainName, DomainName: domainName,
ServerCertificateStatus: "on", ServerCertificateStatus: "on",
CertName: CertName, CertName: CertName,
CertType: "upload", CertType: "upload",
ServerCertificate: newCert.crt, ServerCertificate: cert.crt,
PrivateKey: newCert.key, PrivateKey: cert.key,
}; };
} }
@ -95,7 +94,7 @@ export class DeployCertToAliyunCDN extends AbstractPlugin implements TaskPlugin
checkRet(ret: any) { checkRet(ret: any) {
if (ret.code != null) { 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: "测试插件回声", title: "测试插件回声",
input: { input: {
cert: { cert: {
title: "cert",
component: { component: {
name: "output-selector", name: "output-selector",
}, },

View File

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

View File

@ -7,9 +7,14 @@ export type Registrable = {
desc?: string; desc?: string;
}; };
export abstract class AbstractRegistrable { export abstract class AbstractRegistrable<T extends Registrable> {
static define: Registrable;
logger: Logger = logger; logger: Logger = logger;
// @ts-ignore
define: T;
getDefine(): T {
return this.define;
}
} }
export class Registry<T extends typeof AbstractRegistrable> { export class Registry<T extends typeof AbstractRegistrable> {
storage: { storage: {
@ -20,7 +25,9 @@ export class Registry<T extends typeof AbstractRegistrable> {
if (target == null) { if (target == null) {
return; return;
} }
let defineName = target.define.name; // @ts-ignore
const define = new target().define;
let defineName = define.name;
if (defineName == null) { if (defineName == null) {
defineName = target.name; 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"; import { EchoPlugin } from "../src/plugin/plugins";
describe("task_plugin", function () { describe("task_plugin", function () {
it("#taskplugin", function () { it("#taskplugin", function () {
const define = EchoPlugin.define; const echoPlugin = new EchoPlugin();
new EchoPlugin().execute({ context: {}, props: { test: 111 } }); const define = echoPlugin.define;
echoPlugin.execute({ context: {}, props: { test: 111 } });
expect(define.name).eq("EchoPlugin"); expect(define.name).eq("EchoPlugin");
}); });
}); });