支持自定义的endpoint
This commit is contained in:
parent
b5739a4128
commit
26b02e4cca
|
|
@ -3,8 +3,9 @@ import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
|
|||
import { AppLoader as GeneralAppLoader, Trigger, EntityDict, Watcher, OpRecord, FreeTimer, OperationResult } from "oak-domain/lib/types";
|
||||
import { DbStore } from "./DbStore";
|
||||
import { BackendRuntimeContext } from 'oak-frontend-base/lib/context/BackendRuntimeContext';
|
||||
import { IncomingHttpHeaders, IncomingMessage } from 'http';
|
||||
import { IncomingHttpHeaders } from 'http';
|
||||
import { Namespace } from 'socket.io';
|
||||
import Koa from "koa";
|
||||
import DataSubscriber from './cluster/DataSubscriber';
|
||||
import Synchronizer from './Synchronizer';
|
||||
import { AsyncContext } from 'oak-domain/lib/store/AsyncRowStore';
|
||||
|
|
@ -37,7 +38,7 @@ export declare class AppLoader<ED extends EntityDict & BaseEntityDict, Cxt exten
|
|||
}>;
|
||||
initialize(): Promise<void>;
|
||||
getStore(): DbStore<ED, Cxt>;
|
||||
getEndpoints(prefix: string): [string, "post" | "get" | "put" | "delete", string, (params: Record<string, string>, headers: IncomingHttpHeaders, req: IncomingMessage, body?: any) => Promise<any>][];
|
||||
getEndpoints(prefix: string): ["rest" | "custom" | undefined, string, "post" | "get" | "put" | "delete", string, (koaCtx: Koa.ParameterizedContext) => Promise<any>][];
|
||||
protected operateInWatcher<T extends keyof ED>(entity: T, operation: ED[T]['Update'], context: Cxt, singleton?: true): Promise<OperationResult<ED>>;
|
||||
protected selectInWatcher<T extends keyof ED>(entity: T, selection: ED[T]['Selection'], context: Cxt, forUpdate?: true, singleton?: true): Promise<Partial<ED[T]["Schema"]>[]>;
|
||||
protected execWatcher(watcher: Watcher<ED, keyof ED, Cxt>): Promise<OperationResult<ED> | undefined>;
|
||||
|
|
|
|||
|
|
@ -264,7 +264,7 @@ class AppLoader extends types_1.AppLoader {
|
|||
const endPointRouters = [];
|
||||
const endPointMap = {};
|
||||
const transformEndpointItem = (key, item) => {
|
||||
const { name, method, fn, params: itemParams } = item;
|
||||
const { name, method, fn, params: itemParams, type } = item;
|
||||
const k = `${key}-${name}-${method}`;
|
||||
const makeEndpoint = async () => {
|
||||
endPointMap[k] = true;
|
||||
|
|
@ -274,19 +274,36 @@ class AppLoader extends types_1.AppLoader {
|
|||
url += `/:${p}`;
|
||||
}
|
||||
}
|
||||
endPointRouters.push([name, method, url, async (params, headers, req, body) => {
|
||||
const context = await this.makeContext(undefined, headers);
|
||||
try {
|
||||
const result = await fn(context, params, headers, req, body);
|
||||
await context.commit();
|
||||
return result;
|
||||
}
|
||||
catch (err) {
|
||||
await context.rollback();
|
||||
console.error(`endpoint「${key}」方法「${method}」出错`, err);
|
||||
throw err;
|
||||
}
|
||||
}]);
|
||||
if (type == "custom") {
|
||||
endPointRouters.push([type, name, method, url, async (koaCtx) => {
|
||||
const { request } = koaCtx;
|
||||
const { headers } = request;
|
||||
try {
|
||||
await fn(() => this.makeContext(undefined, headers), koaCtx);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(`endpoint「${key}」方法「${method}」出错`, err);
|
||||
throw err;
|
||||
}
|
||||
}]);
|
||||
}
|
||||
else {
|
||||
endPointRouters.push([type, name, method, url, async (koaCtx) => {
|
||||
const { request, params } = koaCtx;
|
||||
const { body, headers, files, req } = request;
|
||||
const context = await this.makeContext(undefined, headers);
|
||||
try {
|
||||
const result = await fn(context, params, headers, req, files ? Object.assign({}, body, files) : body);
|
||||
await context.commit();
|
||||
return result;
|
||||
}
|
||||
catch (err) {
|
||||
await context.rollback();
|
||||
console.error(`endpoint「${key}」方法「${method}」出错`, err);
|
||||
throw err;
|
||||
}
|
||||
}]);
|
||||
}
|
||||
};
|
||||
if (endPointMap[k]) {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import assert from 'assert';
|
|||
import { IncomingHttpHeaders, IncomingMessage } from 'http';
|
||||
import { Namespace } from 'socket.io';
|
||||
import { analyzeDepedency } from 'oak-domain/lib/compiler/dependencyBuilder';
|
||||
import Koa from "koa"
|
||||
|
||||
import DataSubscriber from './cluster/DataSubscriber';
|
||||
import { getClusterInfo } from './cluster/env';
|
||||
|
|
@ -114,7 +115,7 @@ export class AppLoader<ED extends EntityDict & BaseEntityDict, Cxt extends Backe
|
|||
async commit() {
|
||||
const { eventOperationMap, opRecords } = this;
|
||||
await super.commit();
|
||||
|
||||
|
||||
// 注入在提交后向dataSubscribe发送订阅的事件
|
||||
if (loaderThis.dataSubscriber) {
|
||||
Object.keys(eventOperationMap).forEach(
|
||||
|
|
@ -179,7 +180,7 @@ export class AppLoader<ED extends EntityDict & BaseEntityDict, Cxt extends Backe
|
|||
const socketFilePath = join(this.path, 'lib/socket/index');
|
||||
if (existsSync(socketFilePath)) {
|
||||
const { registerSocketEntry } = require(socketFilePath);
|
||||
assert(typeof registerSocketEntry === 'function');
|
||||
assert(typeof registerSocketEntry === 'function');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -260,7 +261,7 @@ export class AppLoader<ED extends EntityDict & BaseEntityDict, Cxt extends Backe
|
|||
const data = this.requireSth('lib/data/index')!;
|
||||
// oak-domain中只有i18n
|
||||
assert(data.i18n);
|
||||
data.i18n.push(...domainI18nData);
|
||||
data.i18n.push(...domainI18nData);
|
||||
|
||||
const context = this.contextBuilder(this.dbStore);
|
||||
context.openRootMode();
|
||||
|
|
@ -281,7 +282,7 @@ export class AppLoader<ED extends EntityDict & BaseEntityDict, Cxt extends Backe
|
|||
await context.commit();
|
||||
console.log(`data in ${entity} omitted, ${rows.length} rows passed`);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 再插入所有的行
|
||||
try {
|
||||
|
|
@ -308,7 +309,7 @@ export class AppLoader<ED extends EntityDict & BaseEntityDict, Cxt extends Backe
|
|||
catch (err) {
|
||||
await context.rollback();
|
||||
console.error(`data on ${entity} initilization failed!`);
|
||||
throw err;
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -321,11 +322,17 @@ export class AppLoader<ED extends EntityDict & BaseEntityDict, Cxt extends Backe
|
|||
|
||||
getEndpoints(prefix: string) {
|
||||
const endpoints: Record<string, Endpoint<ED, Cxt>> = this.requireSth('lib/endpoints/index');
|
||||
const endPointRouters: Array<[EndpointItem<ED, Cxt>['name'], EndpointItem<ED, Cxt>['method'], string, (params: Record<string, string>, headers: IncomingHttpHeaders, req: IncomingMessage, body?: any) => Promise<any>]> = [];
|
||||
const endPointRouters: Array<[
|
||||
EndpointItem<ED, Cxt>['type'],
|
||||
EndpointItem<ED, Cxt>['name'],
|
||||
EndpointItem<ED, Cxt>['method'],
|
||||
string,
|
||||
(koaCtx: Koa.ParameterizedContext) => Promise<any>
|
||||
]> = [];
|
||||
const endPointMap: Record<string, true> = {};
|
||||
|
||||
const transformEndpointItem = (key: string, item: EndpointItem<ED, Cxt>) => {
|
||||
const { name, method, fn, params: itemParams } = item;
|
||||
const { name, method, fn, params: itemParams, type } = item;
|
||||
const k = `${key}-${name}-${method}`;
|
||||
const makeEndpoint = async () => {
|
||||
endPointMap[k] = true;
|
||||
|
|
@ -335,22 +342,43 @@ export class AppLoader<ED extends EntityDict & BaseEntityDict, Cxt extends Backe
|
|||
url += `/:${p}`;
|
||||
}
|
||||
}
|
||||
endPointRouters.push(
|
||||
[name, method, url, async (params, headers, req, body) => {
|
||||
const context = await this.makeContext(undefined, headers);
|
||||
if (type == "custom") {
|
||||
endPointRouters.push(
|
||||
[type, name, method, url, async (koaCtx) => {
|
||||
const { request, res } = koaCtx
|
||||
const { headers } = request;
|
||||
koaCtx.respond = false
|
||||
try {
|
||||
await fn(() => this.makeContext(undefined, headers), koaCtx);
|
||||
res.statusCode = 200
|
||||
}
|
||||
catch (err) {
|
||||
console.error(`endpoint「${key}」方法「${method}」出错`, err);
|
||||
res.statusCode = 500
|
||||
throw err;
|
||||
}
|
||||
}]
|
||||
);
|
||||
} else {
|
||||
endPointRouters.push(
|
||||
[type, name, method, url, async (koaCtx) => {
|
||||
const { request, params } = koaCtx;
|
||||
const { body, headers, files, req } = request;
|
||||
const context = await this.makeContext(undefined, headers);
|
||||
|
||||
try {
|
||||
const result = await fn(context, params, headers, req, body);
|
||||
await context.commit();
|
||||
return result;
|
||||
}
|
||||
catch (err) {
|
||||
await context.rollback();
|
||||
console.error(`endpoint「${key}」方法「${method}」出错`, err);
|
||||
throw err;
|
||||
}
|
||||
}]
|
||||
);
|
||||
try {
|
||||
const result = await fn(context, params, headers, req, files ? Object.assign({}, body, files) : body);
|
||||
await context.commit();
|
||||
return result;
|
||||
}
|
||||
catch (err) {
|
||||
await context.rollback();
|
||||
console.error(`endpoint「${key}」方法「${method}」出错`, err);
|
||||
throw err;
|
||||
}
|
||||
}]
|
||||
);
|
||||
}
|
||||
}
|
||||
if (endPointMap[k]) {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
|
|
@ -401,18 +429,18 @@ export class AppLoader<ED extends EntityDict & BaseEntityDict, Cxt extends Backe
|
|||
let result: OperationResult<ED> | undefined;
|
||||
try {
|
||||
if (watcher.hasOwnProperty('actionData')) {
|
||||
const { entity, action, filter, actionData, singleton } = <BBWatcher<ED, keyof ED>>watcher;
|
||||
const { entity, action, filter, actionData, singleton } = <BBWatcher<ED, keyof ED>>watcher;
|
||||
const filter2 = typeof filter === 'function' ? await filter() : cloneDeep(filter);
|
||||
const data = typeof actionData === 'function' ? await (actionData)() : cloneDeep(actionData);
|
||||
result = await this.operateInWatcher(entity, {
|
||||
id: await generateNewIdAsync(),
|
||||
action: action as string,
|
||||
data,
|
||||
filter: filter2,
|
||||
filter: filter2,
|
||||
}, context, singleton);
|
||||
}
|
||||
else {
|
||||
const { entity, projection, fn, filter, singleton,forUpdate } = <WBWatcher<ED, keyof ED, Cxt>>watcher;
|
||||
const { entity, projection, fn, filter, singleton, forUpdate } = <WBWatcher<ED, keyof ED, Cxt>>watcher;
|
||||
const filter2 = typeof filter === 'function' ? await filter() : cloneDeep(filter);
|
||||
const projection2 = typeof projection === 'function' ? await projection() : cloneDeep(projection);
|
||||
const rows = await this.selectInWatcher(entity, {
|
||||
|
|
@ -503,7 +531,7 @@ export class AppLoader<ED extends EntityDict & BaseEntityDict, Cxt extends Backe
|
|||
const job = scheduleJob(name, cron, async (date) => {
|
||||
const start = Date.now();
|
||||
console.log(`定时器【${name}】开始执行,时间是【${date.toLocaleTimeString()}】`);
|
||||
|
||||
|
||||
if (timer.hasOwnProperty('entity')) {
|
||||
try {
|
||||
const result = await this.execWatcher(timer as Watcher<ED, keyof ED, Cxt>);
|
||||
|
|
|
|||
Loading…
Reference in New Issue