smartuniverse/ts/smartuniverse.classes.client.universe.ts

187 lines
6.0 KiB
TypeScript
Raw Permalink Normal View History

2023-07-25 09:33:13 +00:00
import * as plugins from './smartuniverse.plugins.js';
import { Smartsocket, SmartsocketClient } from '@push.rocks/smartsocket';
2018-03-13 05:15:40 +00:00
2023-07-25 09:33:13 +00:00
import * as interfaces from './interfaces/index.js';
2018-03-20 07:16:54 +00:00
2023-07-25 09:33:13 +00:00
import { ClientUniverseChannel, ClientUniverseMessage } from './index.js';
import { ClientUniverseCache } from './smartuniverse.classes.client.universecache.js';
import { logger } from './smartuniverse.logging.js';
2018-03-13 05:15:40 +00:00
2018-03-15 00:05:13 +00:00
export interface IClientOptions {
2018-03-20 07:16:54 +00:00
serverAddress: string;
2019-11-09 11:59:51 +00:00
autoReconnect: boolean;
2018-03-15 00:05:13 +00:00
}
2018-04-13 13:45:48 +00:00
/**
* this class is for client side only!!!
* allows connecting to a universe server
*/
export class ClientUniverse {
2019-11-09 11:23:33 +00:00
public options: IClientOptions;
2019-04-24 21:27:57 +00:00
public smartsocketClient: plugins.smartsocket.SmartsocketClient;
2019-11-03 19:23:22 +00:00
public messageRxjsSubject = new plugins.smartrx.rxjs.Subject<ClientUniverseMessage<any>>();
2019-04-28 10:42:08 +00:00
public clientUniverseCache = new ClientUniverseCache();
2018-03-13 05:15:40 +00:00
2019-11-09 17:44:33 +00:00
public autoReconnectStatus: 'on' | 'off' = 'off';
2018-03-15 00:05:13 +00:00
constructor(optionsArg: IClientOptions) {
this.options = optionsArg;
}
2018-03-20 07:16:54 +00:00
2019-04-22 11:06:01 +00:00
/**
* adds a channel to the channelcache
* TODO: verify channel before adding it to the channel cache
*/
2019-08-13 16:41:27 +00:00
public addChannel(channelNameArg: string, passphraseArg: string) {
const existingChannel = this.getChannel(channelNameArg);
2019-04-22 20:04:52 +00:00
if (existingChannel) {
throw new Error('channel exists');
}
2019-04-22 21:11:51 +00:00
// lets create the channel
2019-09-01 15:04:25 +00:00
const clientUniverseChannel = ClientUniverseChannel.createClientUniverseChannel(
this,
channelNameArg,
passphraseArg
);
2019-08-13 16:41:27 +00:00
return clientUniverseChannel;
2019-04-22 11:06:01 +00:00
}
/**
* gets a channel from the channelcache
* @param channelName
2019-04-22 22:28:57 +00:00
* @param passphraseArg
2019-04-22 11:06:01 +00:00
*/
2019-08-13 16:41:27 +00:00
public getChannel(channelName: string): ClientUniverseChannel {
2023-07-25 09:33:13 +00:00
const clientUniverseChannel = this.clientUniverseCache.channelMap.findSync((channel) => {
2019-04-22 20:04:52 +00:00
return channel.name === channelName;
2019-04-22 22:28:57 +00:00
});
2019-04-22 11:06:01 +00:00
return clientUniverseChannel;
}
2019-04-28 10:42:08 +00:00
/**
* remove a a achannel
* @param messageArg
*/
public removeChannel(channelNameArg, notifyServer = true) {
2023-07-25 09:33:13 +00:00
const clientUniverseChannel = this.clientUniverseCache.channelMap.findOneAndRemoveSync(
2020-09-24 18:17:52 +00:00
(channelItemArg) => {
2019-09-01 15:04:25 +00:00
return channelItemArg.name === channelNameArg;
}
);
2019-04-28 10:42:08 +00:00
}
2019-08-13 13:48:20 +00:00
public async start() {
2019-11-09 17:44:33 +00:00
if (this.options.autoReconnect) {
this.autoReconnectStatus = 'on';
}
2019-08-13 13:48:20 +00:00
await this.checkConnection();
}
2019-09-09 22:39:18 +00:00
public async stop() {
2019-11-09 17:44:33 +00:00
this.autoReconnectStatus = 'off';
2019-11-09 11:23:33 +00:00
await this.disconnect('triggered');
}
2019-04-22 11:06:01 +00:00
/**
* checks the connection towards a universe server
* since password validation is done through other means, a connection should always be possible
*/
2019-11-09 17:44:33 +00:00
private async checkConnection(): Promise<void> {
2019-11-03 19:23:22 +00:00
if (!this.smartsocketClient) {
2023-07-25 09:33:13 +00:00
const parsedURL = plugins.smarturl.Smarturl.createFromUrl(this.options.serverAddress);
2019-04-24 16:20:31 +00:00
const socketConfig: plugins.smartsocket.ISmartsocketClientOptions = {
2019-09-01 19:34:01 +00:00
alias: 'universeclient',
2018-03-20 07:16:54 +00:00
port: parseInt(parsedURL.port, 10),
2020-09-24 18:17:52 +00:00
url: parsedURL.protocol + '//' + parsedURL.hostname,
2019-04-24 16:20:31 +00:00
};
2019-04-24 21:27:57 +00:00
this.smartsocketClient = new SmartsocketClient(socketConfig);
2020-09-24 18:17:52 +00:00
this.smartsocketClient.eventSubject.subscribe(async (eventArg) => {
2019-11-09 12:00:30 +00:00
switch (eventArg) {
2019-11-09 11:23:33 +00:00
case 'disconnected':
this.disconnect('upstreamEvent');
}
});
2019-04-24 21:27:57 +00:00
// lets define some basic actions
/**
* should handle a forced unsubscription by the server
*/
2019-08-13 13:48:20 +00:00
const socketFunctionUnsubscribe = new plugins.smartsocket.SocketFunction({
2019-04-24 21:27:57 +00:00
funcName: 'unsubscribe',
2019-11-03 19:23:22 +00:00
funcDef: async (dataArg: interfaces.IServerUnsubscribeActionPayload) => {
2023-07-25 09:33:13 +00:00
const channel = this.clientUniverseCache.channelMap.findSync((channelArg) => {
2019-11-03 19:23:22 +00:00
return channelArg.name === dataArg.name;
});
if (channel) {
channel.unsubscribe();
}
return {};
2020-09-24 18:17:52 +00:00
},
2019-04-24 21:27:57 +00:00
});
/**
2019-08-13 13:48:20 +00:00
* handles message reception
2019-04-24 21:27:57 +00:00
*/
2023-07-25 09:33:13 +00:00
const socketFunctionProcessMessage =
new plugins.smartsocket.SocketFunction<interfaces.ISocketRequest_ProcessMessage>({
funcName: 'processMessage',
funcDef: async (messageDescriptorArg) => {
logger.log('info', 'Got message from server');
const clientUniverseMessage =
ClientUniverseMessage.createMessageFromMessageDescriptor(messageDescriptorArg);
this.messageRxjsSubject.next(clientUniverseMessage);
// lets find the corresponding channel
const targetChannel = this.getChannel(clientUniverseMessage.targetChannelName);
if (targetChannel) {
await targetChannel.emitMessageLocally(clientUniverseMessage);
return {
messageStatus: 'ok',
};
} else {
return {
messageStatus: 'channel not found',
};
}
},
});
2019-04-24 21:27:57 +00:00
2019-08-13 13:48:20 +00:00
// add functions
this.smartsocketClient.addSocketFunction(socketFunctionUnsubscribe);
this.smartsocketClient.addSocketFunction(socketFunctionProcessMessage);
2019-04-24 21:27:57 +00:00
await this.smartsocketClient.connect();
2020-09-24 18:13:48 +00:00
logger.log('info', 'universe client connected successfully');
2020-09-24 18:17:52 +00:00
await this.clientUniverseCache.channelMap.forEach(async (clientUniverseChannelArg) => {
2019-09-10 17:36:10 +00:00
await clientUniverseChannelArg.populateSubscriptionToServer();
2019-08-13 13:48:20 +00:00
});
2018-03-20 07:16:54 +00:00
}
}
2019-11-09 11:23:33 +00:00
2019-11-09 17:44:33 +00:00
private async disconnect(
2019-11-09 12:00:30 +00:00
reason: 'upstreamEvent' | 'triggered' = 'triggered',
tryReconnect = false
) {
2019-11-09 17:44:33 +00:00
const instructDisconnect = async () => {
if (this.smartsocketClient) {
const smartsocketToDisconnect = this.smartsocketClient;
this.smartsocketClient = null; // making sure the upstreamEvent does not interfere
await smartsocketToDisconnect.disconnect();
}
};
if (reason === 'triggered' && this.smartsocketClient) {
await instructDisconnect();
2019-11-09 11:23:33 +00:00
}
2019-11-09 17:44:33 +00:00
if (this.autoReconnectStatus === 'on' && reason === 'upstreamEvent') {
await instructDisconnect();
2019-11-09 11:23:33 +00:00
await plugins.smartdelay.delayForRandom(5000, 20000);
2019-11-09 17:44:33 +00:00
await this.checkConnection();
2019-11-09 11:23:33 +00:00
}
}
2018-03-15 00:05:13 +00:00
}