mirror of
https://github.com/cool-team-official/cool-admin-midway.git
synced 2024-11-01 22:20:30 +08:00
275 lines
6.7 KiB
TypeScript
275 lines
6.7 KiB
TypeScript
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();
|
||
}
|
||
|
||
/**
|
||
* 初始化service,设置entity
|
||
*/
|
||
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();
|
||
}
|
||
}
|