import { Injectable } from '@angular/core'; import { Client, ClientNotificationCodec, WebSocketClientRWC, WebSocketClientRWCConfig, JSONClientCodec } from '@overflow/rpc-js'; import { Subscription } from 'rxjs'; import { TypeUtil, Class, Annotation, PropertyKeyType, Method, ReflectionUtil, Decorator } from '@overflow/core-js'; import { RPCSubscriberDecoratorAttribute, RPCSubscriberDecorator } from '@overflow/commons/ui/decorator/RPCSubscriber'; export const requesterID = 'scannerUser'; export interface SubscriberMethod { className: PropertyKeyType; methodName: PropertyKeyType; parameterTypes: string[]; method: Method; instance: any; } export class SubscriberParameterError extends Error { public constructor(message?: string) { super(message); Object.setPrototypeOf(this, new.target.prototype); } } export class SubscriberExistError extends Error { public constructor(message?: string) { super(message); Object.setPrototypeOf(this, new.target.prototype); } } const config: WebSocketClientRWCConfig = { url: 'ws://localhost:60000/scanner?requesterID=' + requesterID }; const rwc = new WebSocketClientRWC(config); const codec = new JSONClientCodec(); @Injectable({ providedIn: 'root' }) export class ProbeService extends Client { private notiSubscription: Subscription; private subscriberMap: Map; private subscriberMethodMap: Map; public constructor() { super(codec, rwc); this.subscriberMap = new Map(); this.subscriberMethodMap = new Map(); this.connect(); this.notiSubscription = this.notification() .subscribe((notiCodec: ClientNotificationCodec) => { const method = notiCodec.method(); const params = notiCodec.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.converNotificationParams(params, subscriberMethod.parameterTypes); subscriberMethod.method.invoke(subscriberMethod.instance, ...args); } catch (error) { console.error(error); } }); }); this.connectionStatus().subscribe(isConnected => { if (!isConnected) { console.log('disconnected'); } else { console.log('connected'); } }); } /** * subscribeNotification */ public subscribeNotification(subscriber: any) { if (this.subscriberMap.has(subscriber)) { throw new SubscriberExistError(); } const type = TypeUtil.getType(subscriber); const clazz = Class.forType(type); if (undefined === clazz) { console.log(`Type[${subscriber.name}] is not decorated type`); return; } const subscriberMethodNames: string[] = []; this.subscriberMap.set(subscriber, subscriberMethodNames); const methods = clazz.getMethods(); methods.forEach((method, propertyKey) => { const annon = method.getAnnotation(RPCSubscriberDecorator); if (undefined === annon) { return; } const subscriberMethodName = annon.attribute.method; subscriberMethodNames.push(subscriberMethodName); let subscriberMethods: SubscriberMethod[] = this.subscriberMethodMap.get(subscriberMethodName); if (undefined === subscriberMethods) { subscriberMethods = []; this.subscriberMethodMap.set(subscriberMethodName, subscriberMethods); } const paramTypes = ReflectionUtil.getParamTypeStrings(method); const subscriberMethod: SubscriberMethod = { className: clazz.getName(), methodName: method.getName(), parameterTypes: paramTypes, method: method, instance: subscriber, }; subscriberMethods.push(subscriberMethod); }); } /** * subscribeNotification */ public unsubscribeNotification(subscriber: any) { if (!this.subscriberMap.has(subscriber)) { return; } const subscriberMethodNames = this.subscriberMap.get(subscriber); this.subscriberMap.delete(subscriber); subscriberMethodNames.forEach(methodName => { if (!this.subscriberMethodMap.has(methodName)) { return; } const subscriberMethods = this.subscriberMethodMap.get(methodName); subscriberMethods.some((subscriberMethod, index): boolean => { if (subscriberMethod.instance === subscriber) { delete subscriberMethods[index]; } return false; }); }); } }