This commit is contained in:
crusader 2018-03-25 18:54:06 +09:00
parent 19621ef090
commit 6edb85aa07
13 changed files with 148 additions and 31 deletions

View File

@ -0,0 +1,6 @@
export class SubscriberParameterError extends Error {
public constructor(message?: string) {
super(message);
Object.setPrototypeOf(this, new.target.prototype);
}
}

View File

@ -1 +1,2 @@
export * from './error';
export * from './token';

View File

@ -3,12 +3,14 @@ import { Store, select } from '@ngrx/store';
import {
Type,
PropertyKeyType,
} from '@loafer/core';
import { TypeUtil } from '@loafer/core/util/TypeUtil';
import {
Class,
Method,
Metadata,
} from '@loafer/core/reflect';
@ -17,14 +19,26 @@ import { RPCSubscriberDecorator } from '../decorator';
import {
RPCClientNotificationCodec,
} from '../protocol';
import { SubscriberParameterError } from '../core';
export interface SubscriberMethod {
className: PropertyKeyType;
methodName: PropertyKeyType;
parameterTypes: string[];
method: Method;
instance: any;
}
@Injectable()
export class RPCSubscribeService {
private subscribers: Set<any>;
private subscriberMethodMap: Map<string, SubscriberMethod[]>;
constructor(
) {
this.subscribers = new Set();
this.subscriberMethodMap = new Map();
}
public addSubscriber(subscriber: Type<any>): void {
@ -46,11 +60,100 @@ export class RPCSubscribeService {
const methods = clazz.getMethods();
methods.forEach((method, propertyKey) => {
const annon = method.getAnnotation(RPCSubscriberDecorator);
console.log(`subscriber method[${annon.attribute.method}]`);
if (undefined === annon) {
return;
}
const subscriberMethodName = annon.attribute.method;
let subscriberMethods: SubscriberMethod[] = this.subscriberMethodMap.get(subscriberMethodName);
if (undefined === subscriberMethods) {
subscriberMethods = [];
this.subscriberMethodMap.set(subscriberMethodName, subscriberMethods);
}
const paramTypes = this.getParamTypes(method);
const subscriberMethod: SubscriberMethod = {
className: clazz.getName(),
methodName: method.getName(),
parameterTypes: paramTypes,
method: method,
instance: subscriber,
};
subscriberMethods.push(subscriberMethod);
});
}
public notify(codec: RPCClientNotificationCodec): void {
console.log(`notify method[${codec.method()}] params[${codec.params()}]`);
const method = codec.method();
const params = codec.params();
const subscriberMethods: SubscriberMethod[] = this.subscriberMethodMap.get(method);
if (undefined === subscriberMethods) {
console.warn(`Subscriber for method[${method}] is not exist`);
return;
}
subscriberMethods.forEach((subscriberMethod) => {
try {
const args = this.converParams(params, subscriberMethod.parameterTypes);
subscriberMethod.method.invoke(subscriberMethod.instance, ...args);
} catch (error) {
console.error(error);
}
});
}
private getParamTypes(method: Method): string[] {
if (undefined === method || null === method || 0 === method.getParameterCount()) {
return [];
}
const parameters = method.getParameters();
const results: string[] = [];
for (let indexI = 0; indexI < parameters.length; indexI++) {
const paramType = parameters[indexI].getType();
results.push(paramType.name);
}
return results;
}
private converParams(params: string[], paramTypes: string[]): any[] {
const results: any[] = [];
if (undefined === params || null === params || 0 === params.length) {
return results;
}
if (undefined === paramTypes || null === paramTypes || 0 === paramTypes.length) {
return results;
}
if (params.length !== paramTypes.length) {
throw new SubscriberParameterError(`Count is not same from server[${params.length}] and method[${paramTypes.length}]`);
}
for (let indexI = 0; indexI < params.length; indexI++) {
const param = params[indexI];
const type = paramTypes[indexI];
switch (type) {
case 'Object':
case 'Array':
case 'Map':
results.push(JSON.parse(param));
break;
case 'String':
results.push(param);
break;
case 'Number':
results.push(Number(param));
break;
case 'Boolean':
results.push(Boolean(param));
break;
case 'Function':
throw new SubscriberParameterError(`Function type [${indexI}] is not allowed`);
default:
throw new SubscriberParameterError(`${type} type parameter[${indexI}] is not allowed`);
}
}
return results;
}
}

View File

@ -9,9 +9,9 @@ import {
} from '../../model';
import * as CIDR from 'ip-cidr';
import * as DiscoveredStore from '../../store/setting';
import * as DiscoverStore from '../../store/notification';
import * as DiscoverStore from '../../store/discover';
import { SettingSelector, NotificationSelector } from '../../store';
import { SettingSelector, DiscoverSelector } from '../../store';
@Component({
selector: 'of-setting',
@ -21,7 +21,7 @@ import { SettingSelector, NotificationSelector } from '../../store';
export class SettingComponent implements OnInit, AfterContentInit {
settingSucceed$ = this.discoverdstore.pipe(select(SettingSelector.select('isStart')));
discoveryResult$ = this.discoverstore.pipe(select(NotificationSelector.select('getDiscoveryResult')));
discoveryResult$ = this.discoverstore.pipe(select(DiscoverSelector.select('getDiscoveryResult')));
started = false;

View File

@ -16,10 +16,11 @@ import {
DiscoverHost = '[discovery.discovery] discoverHost',
DiscoverPort = '[discovery.discovery] discoverPort',
DiscoverService = '[discovery.discovery] discoverService',
DiscoveredZone = '[@@NOTIFICATION] DiscoveryService.discoveredZone',
DiscoveredHost = '[@@NOTIFICATION] DiscoveryService.discoveredHost',
DiscoveredPort = '[@@NOTIFICATION] DiscoveryService.discoveredPort',
DiscoveredService = '[@@NOTIFICATION] DiscoveryService.discoveredService',
DiscoveredZone = '[discovery.discovery] DiscoveryService.discoveredZone',
DiscoveredHost = '[discovery.discovery] DiscoveryService.discoveredHost',
DiscoveredPort = '[discovery.discovery] DiscoveryService.discoveredPort',
DiscoveredService = '[discovery.discovery] DiscoveryService.discoveredService',
}
export class DiscoverZone implements Action {

View File

@ -1,8 +1,8 @@
import { TestBed, inject } from '@angular/core/testing';
import { Effects } from './notification.effect';
import { Effects } from './discover.effect';
describe('Notification.Effects', () => {
describe('Discover.Effects', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [Effects]

View File

@ -20,7 +20,7 @@ import {
DiscoverPort,
DiscoverService,
ActionType
} from './notification.action';
} from './discover.action';
import {DiscoveryService} from '../../service/discovery.service';

View File

@ -1,12 +1,12 @@
import {
Actions,
ActionType,
} from './notification.action';
} from './discover.action';
import {
State,
initialState,
} from './notification.state';
} from './discover.state';
import {
Zone,
@ -19,7 +19,9 @@ export function reducer(state = initialState, action: Actions): State {
switch (action.type) {
case ActionType.DiscoveredZone: {
const zone: Zone = <Zone>action.payload;
state.zones.set(zone.network, zone);
const zones: Map<string, Zone> = null === state.zones ? new Map() : state.zones;
zones.set(zone.network, zone);
return state;
}

View File

@ -0,0 +1,4 @@
export * from './discover.action';
export * from './discover.reducer';
export * from './discover.state';
export * from './discover.effect';

View File

@ -10,30 +10,30 @@ import { StateSelector } from 'packages/core/ngrx/store';
import { MODULE } from '../discovery.constant';
import * as NotificationStore from './notification';
import * as DiscoverStore from './discover';
import * as SettingStore from './setting';
export interface State {
notification: NotificationStore.State;
discover: DiscoverStore.State;
setting: SettingStore.State;
}
export const REDUCERS = {
notification: NotificationStore.reducer,
discover: DiscoverStore.reducer,
setting: SettingStore.reducer,
};
export const EFFECTS = [
SettingStore.Effects,
NotificationStore.Effects,
DiscoverStore.Effects,
];
export const selectDiscoveryState = createFeatureSelector<State>(MODULE.name);
export const NotificationSelector = new StateSelector<NotificationStore.State>(createSelector(
export const DiscoverSelector = new StateSelector<DiscoverStore.State>(createSelector(
selectDiscoveryState,
(state: State) => state.notification
(state: State) => state.discover
));
export const SettingSelector = new StateSelector<SettingStore.State>(createSelector(

View File

@ -1,4 +0,0 @@
export * from './notification.action';
export * from './notification.reducer';
export * from './notification.state';
export * from './notification.effect';

View File

@ -3,7 +3,7 @@ import { Store, select } from '@ngrx/store';
import { RPCSubscriber } from '@loafer/ng-rpc/decorator';
import * as DiscoveryStore from '../store/notification';
import * as DiscoverStore from '../store/discover';
import {
Zone,
@ -16,24 +16,28 @@ import {
export class DiscoverySubscriber {
public constructor(
private store: Store<DiscoveryStore.State>,
private store: Store<DiscoverStore.State>,
) {
}
@RPCSubscriber({method: 'DiscoveryService.discoveredZone'})
public discoveredZone(zone: Zone): void {
this.store.dispatch(new DiscoveryStore.DiscoveredZone(zone));
console.log(`DiscoverySubscriber.discoveredZone zone:${zone}`);
this.store.dispatch(new DiscoverStore.DiscoveredZone(zone));
}
@RPCSubscriber({method: 'DiscoveryService.discoveredHost'})
public discoveredHost(host: Host): void {
this.store.dispatch(new DiscoveryStore.DiscoveredHost(host));
console.log(`DiscoverySubscriber.discoveredHost host:${host}`);
this.store.dispatch(new DiscoverStore.DiscoveredHost(host));
}
@RPCSubscriber({method: 'DiscoveryService.discoveredPort'})
public discoveredPort(port: Port): void {
this.store.dispatch(new DiscoveryStore.DiscoveredPort(port));
this.store.dispatch(new DiscoverStore.DiscoveredPort(port));
}
@RPCSubscriber({method: 'DiscoveryService.discoveredService'})
public discoveredService(service: Service): void {
this.store.dispatch(new DiscoveryStore.DiscoveredService(service));
this.store.dispatch(new DiscoverStore.DiscoveredService(service));
}
}