重构了后台启动的相关部分

This commit is contained in:
Xu Chang 2022-07-16 17:10:16 +08:00
parent 066ff597e5
commit f4b11e7fdf
16 changed files with 212 additions and 21 deletions

View File

@ -10,7 +10,7 @@ async function run(options) {
(0, tip_style_1.Success)(`${(0, tip_style_1.success)('初始化数据库中……')}`);
// ts-node scripts/build-app-domain & npm link ./app-domain
const drop = options.args.includes('drop') || false;
const result = cross_spawn_1.default.sync('ts-node', [require.resolve('../scripts/' + 'initialize-database.js'), `${drop}`], {
const result = cross_spawn_1.default.sync('ts-node', [require.resolve('../scripts/' + 'initialize-server.ts'), `${drop}`], {
stdio: 'inherit',
shell: true,
});
@ -28,6 +28,7 @@ async function run(options) {
// ts-node scripts/build-app-domain & npm link ./app-domain
const result = cross_spawn_1.default.sync(`cross-env`, [
`NODE_ENV=${options.mode}`,
'OAK_PLATFORM=server',
'ts-node',
require.resolve('../scripts/' + 'start-server.js'),
], {

3
lib/server/initialize.d.ts vendored Normal file
View File

@ -0,0 +1,3 @@
/// <reference path="../../src/typings/polyfill.d.ts" />
import { Context, EntityDict, RowStore } from 'oak-domain/lib/types';
export declare function initialize<ED extends EntityDict, Cxt extends Context<ED>>(path: string, contextBuilder: (scene?: string) => (store: RowStore<ED, Cxt>) => Cxt, dropIfExists?: boolean): Promise<void>;

13
lib/server/initialize.js Normal file
View File

@ -0,0 +1,13 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.initialize = void 0;
/// <reference path="../typings/polyfill.d.ts" />
const oak_backend_base_1 = require("oak-backend-base");
async function initialize(path, contextBuilder, dropIfExists) {
const appLoader = new oak_backend_base_1.AppLoader(path, contextBuilder);
await appLoader.mount();
await appLoader.initialize(dropIfExists);
await appLoader.unmount();
console.log('data initialized');
}
exports.initialize = initialize;

3
lib/server/polyfill.d.ts vendored Normal file
View File

@ -0,0 +1,3 @@
export declare type GenerateIdOption = {
shuffle?: boolean;
};

12
lib/server/polyfill.js Normal file
View File

@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const uuid_1 = require("uuid");
async function generateNewId(option) {
if (option?.shuffle && process.env.NODE_ENV === 'development') {
return (0, uuid_1.v4)();
}
return (0, uuid_1.v1)();
}
Object.assign(global, {
generateNewId,
});

4
lib/server/start.d.ts vendored Normal file
View File

@ -0,0 +1,4 @@
/// <reference path="../../src/typings/polyfill.d.ts" />
import './polyfill';
import { Connector, EntityDict, Context, RowStore } from 'oak-domain/lib/types';
export declare function startup<ED extends EntityDict, Cxt extends Context<ED>>(path: string, contextBuilder: (scene?: string) => (store: RowStore<ED, Cxt>) => Cxt, connector: Connector<ED, Cxt>): Promise<void>;

67
lib/server/start.js Normal file
View File

@ -0,0 +1,67 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.startup = void 0;
/// <reference path="../typings/polyfill.d.ts" />
require("./polyfill");
const koa_1 = __importDefault(require("koa"));
const koa_router_1 = __importDefault(require("koa-router"));
const koa_body_1 = __importDefault(require("koa-body"));
const oak_backend_base_1 = require("oak-backend-base");
const types_1 = require("oak-domain/lib/types");
async function startup(path, contextBuilder, connector) {
const appLoader = new oak_backend_base_1.AppLoader(path, contextBuilder);
await appLoader.mount();
const koa = new koa_1.default();
koa.use((0, koa_body_1.default)({
multipart: true,
}));
const router = new koa_router_1.default();
// 如果是开发环境允许options
if (process.env.NODE_ENV = 'development') {
koa.use(async (ctx, next) => {
ctx.set('Access-Control-Allow-Origin', '*');
ctx.set('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With, oak-cxt, oak-aspect');
ctx.set('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');
if (ctx.method == 'OPTIONS') {
ctx.body = 200;
}
else {
await next();
}
});
}
router.post(connector.getRouter(), async (ctx) => {
console.log('aspect called');
const { request } = ctx;
const { name, params, context } = connector.parseRequest(request.headers, request.body, appLoader.getStore());
await context.begin();
let result;
try {
result = await appLoader.execAspect(name, context, params);
await context.commit();
}
catch (err) {
await context.rollback();
console.error(err);
const exception = err instanceof types_1.OakException ? err : new types_1.OakException('内部不可知错误');
const { body } = connector.serializeException(exception, request.headers, request.body);
ctx.response.body = body;
return;
}
const { body, headers } = connector.serializeResult(result, context, request.headers, request.body);
ctx.response.body = body;
return;
});
koa.use(router.routes());
const serverConfig = require(`${path}/configuration/server.json`);
console.log(`server will listen on port ${serverConfig.port}`);
koa.on('error', (err) => {
console.error(err);
throw err;
});
koa.listen(serverConfig.port);
}
exports.startup = startup;

View File

@ -19,8 +19,10 @@
"devDependencies": {
"@types/cross-spawn": "^6.0.2",
"@types/inquirer": "^7.3.1",
"@types/koa-router": "^7.4.4",
"@types/node": "^12.0.27",
"@types/shelljs": "^0.8.8",
"@types/uuid": "^8.3.4",
"@xmldom/xmldom": "^0.8.2",
"stream-browserify": "^3.0.0",
"typescript": "^4.6.3"
@ -66,17 +68,15 @@
"jest": "^27.4.3",
"jest-resolve": "^27.4.2",
"jest-watch-typeahead": "^1.0.0",
"koa": "^2.13.4",
"koa-body": "^5.0.0",
"koa-router": "^11.0.1",
"less": "^4.1.2",
"less-loader": "^10.2.0",
"loader-utils": "^3.2.0",
"lodash": "^4.17.21",
"mini-css-extract-plugin": "^2.5.3",
"oak-common-aspect": "file:../oak-common-aspect",
"oak-domain": "file:../oak-domain",
"oak-external-sdk": "file:../oak-external-sdk",
"oak-frontend-base": "file:../oak-frontend-base",
"oak-general-business": "file:../oak-general-business",
"oak-memory-tree-store": "file:../oak-memory-tree-store",
"postcss": "^8.4.4",
"postcss-flexbugs-fixes": "^5.0.2",
"postcss-less": "^6.0.0",
@ -100,6 +100,7 @@
"tailwindcss": "^3.0.2",
"terser-webpack-plugin": "^5.2.5",
"ui-extract-webpack-plugin": "^1.0.0",
"uuid": "^8.3.2",
"webpack": "^5.72.0",
"webpack-dev-server": "^4.6.0",
"webpack-manifest-plugin": "^4.0.2",

View File

@ -1,9 +0,0 @@
const { initialize } = require('oak-backend-base');
const pwd = process.cwd();
const dropIfExists = process.argv[2];
initialize(pwd, dropIfExists)
.then(
() => process.exit(0)
);

View File

@ -1,4 +0,0 @@
const { startup } = require('oak-backend-base');
const pwd = process.cwd();
startup(pwd);

View File

@ -15,7 +15,7 @@ export default async function run(options: any): Promise<void> {
const drop = options.args.includes('drop') || false;
const result = spawn.sync(
'ts-node',
[require.resolve('../scripts/' + 'initialize-database.js'), `${drop}`],
[require.resolve('../scripts/' + 'initialize-server.ts'), `${drop}`],
{
stdio: 'inherit',
shell: true,
@ -37,6 +37,7 @@ export default async function run(options: any): Promise<void> {
`cross-env`,
[
`NODE_ENV=${options.mode}`,
'OAK_PLATFORM=server',
'ts-node',
require.resolve('../scripts/' + 'start-server.js'),
],

11
src/server/initialize.ts Normal file
View File

@ -0,0 +1,11 @@
/// <reference path="../typings/polyfill.d.ts" />
import { AppLoader } from 'oak-backend-base';
import { Context, EntityDict, RowStore } from 'oak-domain/lib/types';
export async function initialize<ED extends EntityDict, Cxt extends Context<ED>>(path: string, contextBuilder: (scene?: string) => (store: RowStore<ED, Cxt>) => Cxt, dropIfExists?: boolean) {
const appLoader = new AppLoader(path, contextBuilder);
await appLoader.mount();
await appLoader.initialize(dropIfExists);
await appLoader.unmount();
console.log('data initialized');
}

16
src/server/polyfill.ts Normal file
View File

@ -0,0 +1,16 @@
import { v4, v1 } from 'uuid';
export type GenerateIdOption = {
shuffle?: boolean;
};
async function generateNewId(option?: GenerateIdOption) {
if (option?.shuffle && process.env.NODE_ENV === 'development') {
return v4();
}
return v1();
}
Object.assign(global, {
generateNewId,
});

64
src/server/start.ts Normal file
View File

@ -0,0 +1,64 @@
/// <reference path="../typings/polyfill.d.ts" />
import './polyfill';
import Koa from 'koa';
import KoaRouter from 'koa-router';
import KoaBody from 'koa-body';
import { AppLoader, BackendContext } from 'oak-backend-base';
import { OakException, Connector, EntityDict, Context, RowStore } from 'oak-domain/lib/types';
export async function startup<ED extends EntityDict, Cxt extends Context<ED>>(path: string, contextBuilder: (scene?: string) => (store: RowStore<ED, Cxt>) => Cxt, connector: Connector<ED, Cxt>) {
const appLoader = new AppLoader(path, contextBuilder);
await appLoader.mount();
const koa = new Koa();
koa.use(KoaBody({
multipart: true,
}));
const router = new KoaRouter();
// 如果是开发环境允许options
if (process.env.NODE_ENV = 'development') {
koa.use(async (ctx, next) => {
ctx.set('Access-Control-Allow-Origin', '*');
ctx.set('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With, oak-cxt, oak-aspect');
ctx.set('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');
if (ctx.method == 'OPTIONS') {
ctx.body = 200;
} else {
await next();
}
});
}
router.post(connector.getRouter(), async (ctx) => {
console.log('aspect called');
const { request } = ctx;
const { name, params, context } = connector.parseRequest(request.headers, request.body, appLoader.getStore());
await context.begin();
let result: any;
try {
result = await appLoader.execAspect(name, context, params);
await context.commit();
}
catch (err: any) {
await context.rollback();
console.error(err);
const exception = err instanceof OakException ? err : new OakException('内部不可知错误');
const { body } = connector.serializeException(exception, request.headers, request.body);
ctx.response.body = body;
return;
}
const { body, headers } = connector.serializeResult(result, context, request.headers, request.body);
ctx.response.body = body;
return;
});
koa.use(router.routes());
const serverConfig = require(`${path}/configuration/server.json`);
console.log(`server will listen on port ${serverConfig.port}`);
koa.on('error', (err) => {
console.error(err);
throw err;
});
koa.listen(serverConfig.port);
}

7
src/typings/polyfill.d.ts vendored Normal file
View File

@ -0,0 +1,7 @@
import { GenerateIdOption } from "oak-backend-base/src/polyfill";
declare global {
const generateNewId: (option?: GenerateIdOption) => Promise<string>;
const __DEV__: boolean;
}
export {}

View File

@ -62,7 +62,8 @@
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
/* Advanced Options */
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true /* Disallow inconsistently-cased references to the same file. */
"resolveJsonModule": true, /* Disallow inconsistently-cased references to the same file. */
"experimentalDecorators": true
},
"include": [ "src/**/*" ],
"exclude": [