wistroni40-bnft
Version:
Benefit platform parameters publish job template
260 lines (246 loc) • 6.59 kB
text/typescript
/**
* 專案名稱: @wistroni40/bnft
* 部門代號: ML8100
* 檔案說明: API服務器
* @CREATE Mon Feb 08 2021 下午2:56:08
* @author Steve Y Lin
* @contact Steve_Y_Lin@wistron.com #1342
* -----------------------------------------------------------------------------
* @NOTE
*/
import * as bodyParser from 'body-parser';
import * as express from 'express';
import * as fs from 'fs';
import * as http from 'http';
import { BnftTemplate } from 'src/bnft';
import * as swaggerUi from 'swagger-ui-express';
import { Log4js } from './../logger';
import { SWAGGER_DOC } from './swagger';
/**
* API服務器
*/
export class Server {
/**
* 日誌
*/
private readonly logger = new Log4js('api');
/**
* API Server
*/
private readonly server = express();
/**
* API
*/
private api?: http.Server;
/**
* 效益計算Job
*/
private benefit = new Map<string, BnftTemplate>();
/**
* 單一實例
*/
public static instance = new Server();
private constructor() {
// 啟動API Server
this.start();
}
/**
* 取得效益計算Job清單
*
* @method private
* @return 回傳效益計算Job清單
*/
private getBenefitList(): BnftTemplate[] {
return Array.from(this.benefit).map(benefit => benefit[1]);
}
/**
* 取得效益Key名稱
*
* @method private
* @param req 請求
* @return 回傳效益Key名稱
*/
private getBenefitKey(req: express.Request): string {
const systemId = req.query.systemId;
const typeId = req.query.typeId;
return `${systemId}.${typeId}`;
}
/**
* 重新上拋所有效益
*
* @method private
* @param req 請求
* @param res 回應
*/
private async sendBenefit(
req: express.Request,
res: express.Response,
): Promise<void> {
const timestamp = new Date(parseInt(req.query.timestamp as string, 10));
timestamp.setDate(timestamp.getDate() + 1);
await Promise.all(
this.getBenefitList().map(benefit =>
benefit.execute(timestamp).toPromise(),
),
);
res.send(true);
}
/**
* 重新上拋特定效益
*
* @method private
* @param req 請求
* @param res 回應
*/
private async sendSpecificBenefit(
req: express.Request,
res: express.Response,
): Promise<void> {
const key = this.getBenefitKey(req);
const timestamp = new Date(parseInt(req.query.timestamp as string, 10));
timestamp.setDate(timestamp.getDate() + 1);
const benefit = this.benefit.get(key);
if (benefit) {
await benefit.execute(timestamp).toPromise();
res.send(true);
} else {
res.send(null);
}
}
/**
* 重新上拋特定時間區間內的所有效益
*
* @method private
* @param req 請求
* @param res 會應
*/
private async sendBenefitByTimeGroup(
req: express.Request,
res: express.Response,
): Promise<void> {
if (Array.isArray(req.body) && req.body.length > 0) {
await Promise.all(
req.body.map(async date => {
const timestamp = new Date(parseInt(date, 10));
timestamp.setDate(timestamp.getDate() + 1);
await Promise.all(
this.getBenefitList().map(benefit =>
benefit.execute(timestamp).toPromise(),
),
);
}),
);
res.send(true);
} else {
res.send('body format error');
}
}
/**
* 重新上拋特定時間區間內的特定效益
*
* @method private
* @param req 請求
* @param res 會應
*/
public async sendSpecificBenefitByTimeGroup(
req: express.Request,
res: express.Response,
): Promise<void> {
if (Array.isArray(req.body) && req.body.length > 0) {
const key = this.getBenefitKey(req);
await Promise.all(
req.body.map(async date => {
const timestamp = new Date(parseInt(date, 10));
timestamp.setDate(timestamp.getDate() + 1);
const benefit = await this.benefit.get(key);
if (benefit) {
await benefit.execute(timestamp).toPromise();
}
}),
);
res.send(true);
} else {
res.send('body format error');
}
}
/**
* 重拋上拋失敗的效益
*
* @method private
* @param req 請求
* @param res 會應
*/
private async sendBackupBenefit(
req: express.Request,
res: express.Response,
): Promise<void> {
const files = fs.readdirSync('backup');
await Promise.all(
files.map(file => {
const benefit = fs.readFileSync(`backup/${file}`, { encoding: 'utf8' });
try {
if (this.getBenefitList().length > 0) {
this.getBenefitList()[0].send(JSON.parse(benefit));
fs.unlinkSync(`backup/${file}`);
}
} catch (error) {
this.logger.warn('Send backup benefit failed');
this.logger.warn(benefit);
}
return JSON.parse(benefit);
}),
);
res.send(true);
}
/**
* 啟動API Server
*
* @method public
* @return 回傳物件本身
*/
public start(): Server {
const port = 3000;
this.server.use(bodyParser.json());
this.server.post('/benefit/send', this.sendBenefit.bind(this));
this.server.post(
'/specific/benefit/send',
this.sendSpecificBenefit.bind(this),
);
this.server.post(
'/benefit/send/timestamps',
this.sendBenefitByTimeGroup.bind(this),
);
this.server.post(
'/specific/benefit/send/timestamps',
this.sendSpecificBenefitByTimeGroup.bind(this),
);
this.server.post('/benefit/backup', this.sendBackupBenefit.bind(this));
this.server.use('/', swaggerUi.serve, swaggerUi.setup(SWAGGER_DOC));
this.logger.info(`Listen api port ${port}`);
this.api = this.server.listen(port);
return this;
}
/**
* 終止API Server
*
* @method public
* @return 回傳物件本身
*/
public stop(): Server {
if (this.api) {
this.api.close();
this.logger.warn('api close');
}
return this;
}
/**
* 註冊效益計算Job
*
* @method public
* @param benefit 效益計算Job
*/
public register(benefit: BnftTemplate): void {
const key = `${benefit.config.systemId}.${benefit.config.typeId}`;
this.benefit.set(key, benefit);
}
}