cool-admin-midway/packages/rpc/src/rpc.ts

275 lines
6.7 KiB
TypeScript
Raw Normal View History

2023-04-04 09:15:48 +08:00
import { ILogger, IMidwayApplication, Inject } from '@midwayjs/core';
import {
App,
Config,
getClassMetadata,
listModule,
Logger,
Provide,
Scope,
ScopeEnum,
} from '@midwayjs/decorator';
import { ServiceBroker } from 'moleculer';
import { CoolRpcConfig } from '.';
import { CoolCoreException, CoolValidateException } from '@cool-midway/core';
import { v1 as uuid } from 'uuid';
import { BaseRpcService } from './service/base';
import { CurdOption, MOLECYLER_KEY } from './decorator/rpc';
import { COOL_RPC_EVENT_KEY } from './decorator/event/event';
import { COOL_RPC_EVENT_HANDLER_KEY } from './decorator/event/handler';
import * as _ from 'lodash';
import { TypeORMDataSourceManager } from '@midwayjs/typeorm';
// import { AgentService } from '@moleculer/lab';
/**
*
*/
@Provide()
@Scope(ScopeEnum.Singleton)
export class CoolRpc {
broker: ServiceBroker;
@Inject()
typeORMDataSourceManager: TypeORMDataSourceManager;
@Logger()
coreLogger: ILogger;
@Config('cool.rpc')
rpcConfig: CoolRpcConfig;
@Config('cool')
coolConfig;
@App()
app: IMidwayApplication;
cruds;
async init() {
if (!this.rpcConfig?.name) {
throw new CoolCoreException(
'cool.rpc.name config is require and every service name must be unique'
);
}
let redisConfig;
if (!this.rpcConfig?.redis && !this.coolConfig?.redis) {
throw new CoolCoreException('cool.rpc.redis or cool.redis is require');
}
redisConfig = this.rpcConfig?.redis
? this.rpcConfig?.redis
: this.coolConfig?.redis;
const transporter = {
type: 'Redis',
options: {},
};
if (redisConfig instanceof Array) {
transporter.options = {
cluster: {
nodes: redisConfig,
},
};
} else {
transporter.options = redisConfig;
}
this.broker = new ServiceBroker({
nodeID: `${this.rpcConfig.name}-${uuid()}`,
transporter,
// metrics: {
// enabled: true,
// reporter: 'Laboratory',
// },
// tracing: {
// enabled: true,
// exporter: 'Laboratory',
// },
...this.rpcConfig,
});
// this.broker.createService({
// name: this.rpcConfig.name,
// mixins: [],
// // settings: {
// // name: 'test',
// // port: 3210,
// // token: '123123',
// // apiKey: '92C18ZR-ERM45EG-HT8GQGQ-4MHCXAT',
// // },
// });
global['moleculer:broker'] = this.broker;
await this.initService();
await this.createService();
}
/**
*
* @returns
*/
async getEvents() {
const allEvents = {};
const modules = listModule(COOL_RPC_EVENT_KEY);
for (const module of modules) {
const moduleInstance = await this.app
.getApplicationContext()
.getAsync(module);
moduleInstance['broker'] = this.broker;
const events = getClassMetadata(COOL_RPC_EVENT_HANDLER_KEY, module);
for (const event of events) {
allEvents[event.eventName ? event.eventName : event.propertyKey] = {
handler(ctx) {
moduleInstance[event.propertyKey](ctx.params);
},
};
}
}
return allEvents;
}
/**
*
*/
async createService() {
const _this = this;
this.broker.createService({
name: this.rpcConfig.name,
events: await this.getEvents(),
actions: {
async call(ctx) {
const { service, method, params } = ctx.params;
const targetName = _.upperFirst(service);
const target = _.find(_this.cruds, { name: targetName });
if (!target) {
throw new CoolValidateException('找不到服务');
}
const curdOption: CurdOption = getClassMetadata(
MOLECYLER_KEY,
target
);
const cls = await _this.app
.getApplicationContext()
.getAsync(_.lowerFirst(service));
const serviceInstance: BaseRpcService = new target();
Object.assign(serviceInstance, cls);
serviceInstance.setModel(_this.getModel(curdOption));
serviceInstance.setApp(_this.app);
serviceInstance.init();
// 如果是通用crud方法 注入参数
if (
['add', 'delete', 'update', 'page', 'info', 'list'].includes(method)
) {
if (!curdOption.method.includes(method)) {
throw new CoolValidateException('方法不存在');
}
}
return serviceInstance[method](params);
},
},
});
this.broker.start();
}
/**
* serviceentity
*/
async initService() {
// 获得所有的service
this.cruds = listModule(MOLECYLER_KEY);
for (const crud of this.cruds) {
const curdOption: CurdOption = getClassMetadata(MOLECYLER_KEY, crud);
const serviceInstance: BaseRpcService = await this.app
.getApplicationContext()
.getAsync(crud);
serviceInstance.setModel(this.getModel(curdOption));
serviceInstance.setCurdOption(curdOption);
}
}
/**
* Model
* @param curdOption
*/
getModel(curdOption) {
// 获得到model
let entityModel;
const { entity } = curdOption || {};
if (entity) {
const dataSourceName =
this.typeORMDataSourceManager.getDataSourceNameByModel(entity);
entityModel = this.typeORMDataSourceManager
.getDataSource(dataSourceName)
.getRepository(entity);
}
return entityModel;
}
/**
*
* @param name
* @param controller
* @param method
* @param params
* @returns
*/
async call(name: string, service: string, method: string, params?: {}) {
return this.broker.call(`${name}.call`, { service, method, params });
}
/**
*
* @param name
* @param params
* @param node
*/
async event(name: string, params: any, node?: string | string[]) {
this.broker.emit(name, params);
}
/**
* 广
* @param name
* @param params
* @param node
*/
async broadcastEvent(name: string, params: any, node?: string | string[]) {
this.broker.broadcast(name, params);
}
/**
* 广
* @param name
* @param params
* @param node
*/
async broadcastLocalEvent(
name: string,
params: any,
node?: string | string[]
) {
this.broker.broadcastLocal(name, params);
}
/**
* broker对象
* @returns
*/
getBroker() {
return this.broker;
}
/**
*
*/
stop() {
this.broker.stop();
}
}