Compare commits
61 Commits
Author | SHA1 | Date | |
---|---|---|---|
736240b978 | |||
73f4600c2a | |||
40beec1166 | |||
f8690fef50 | |||
972ddbf327 | |||
80aacd17a6 | |||
e67b3e50cc | |||
a4a8959b74 | |||
bab0f062f7 | |||
3bdfe4dcb4 | |||
fca960ad0d | |||
e43ed3951c | |||
23df304535 | |||
9a142175aa | |||
09b593e192 | |||
c27fc147b5 | |||
ddde21925a | |||
bd849d347d | |||
f2a85d4719 | |||
4e7c28ac83 | |||
243f1a70e9 | |||
b5a6517756 | |||
e12b128619 | |||
03fbab5265 | |||
1d13bf5bcc | |||
c2052f16a8 | |||
ff7cdc908c | |||
f3d41b8719 | |||
f9f0fc45e2 | |||
da6b7724b8 | |||
be7ca29e4b | |||
f401d78c4b | |||
6ceec0201f | |||
16ce4e09a9 | |||
2868ab686d | |||
5dab36382f | |||
02a32eb8c7 | |||
b258979b5a | |||
166e29bbf6 | |||
870f37d403 | |||
64c4b91678 | |||
f3e13292d8 | |||
7e1c405cb1 | |||
d1b4672eff | |||
0dd9fee52b | |||
37e1ee7970 | |||
bd0bb3acf5 | |||
f60497474e | |||
1d84cefa84 | |||
6792acd533 | |||
9397d89cf5 | |||
37cf4a91f4 | |||
52db86c929 | |||
e8f09c1b7a | |||
79edea873f | |||
97666a623d | |||
ef61ea9ad7 | |||
9c1504ef02 | |||
e8f2e04d1c | |||
e12aa7e961 | |||
857b7cd010 |
@ -38,17 +38,17 @@ snyk:
|
||||
# test stage
|
||||
# ====================
|
||||
|
||||
testLTS:
|
||||
testStable:
|
||||
stage: test
|
||||
script:
|
||||
- npmci npm prepare
|
||||
- npmci node install lts
|
||||
- npmci node install stable
|
||||
- npmci npm install
|
||||
- npmci npm test
|
||||
coverage: /\d+.?\d+?\%\s*coverage/
|
||||
tags:
|
||||
- docker
|
||||
- notpriv
|
||||
- priv
|
||||
|
||||
testBuild:
|
||||
stage: test
|
||||
@ -100,7 +100,7 @@ trigger:
|
||||
pages:
|
||||
image: hosttoday/ht-docker-dbase:npmci
|
||||
services:
|
||||
- docker:18-dind
|
||||
- docker:stable-dind
|
||||
stage: metadata
|
||||
script:
|
||||
- npmci command npm install -g @gitzone/tsdoc
|
||||
|
912
package-lock.json
generated
912
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
31
package.json
31
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@pushrocks/smartuniverse",
|
||||
"version": "1.0.62",
|
||||
"version": "1.0.93",
|
||||
"private": false,
|
||||
"description": "messaging service for your micro services",
|
||||
"main": "dist/index.js",
|
||||
@ -14,27 +14,28 @@
|
||||
"format": "(gitzone format)"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@gitzone/tsbuild": "^2.1.11",
|
||||
"@gitzone/tstest": "^1.0.24",
|
||||
"@pushrocks/tapbundle": "^3.0.11",
|
||||
"@types/node": "^12.7.1",
|
||||
"tslint": "^5.18.0",
|
||||
"@gitzone/tsbuild": "^2.1.17",
|
||||
"@gitzone/tstest": "^1.0.28",
|
||||
"@pushrocks/tapbundle": "^3.0.13",
|
||||
"@types/node": "^12.12.6",
|
||||
"tslint": "^5.20.1",
|
||||
"tslint-config-prettier": "^1.18.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"rxjs": "*"
|
||||
},
|
||||
"dependencies": {
|
||||
"@pushrocks/lik": "^3.0.10",
|
||||
"@pushrocks/smartdelay": "^2.0.3",
|
||||
"@pushrocks/smartexpress": "^3.0.38",
|
||||
"@pushrocks/smartfile": "^7.0.4",
|
||||
"@apiglobal/typedrequest-interfaces": "^1.0.7",
|
||||
"@pushrocks/lik": "^3.0.11",
|
||||
"@pushrocks/smartdelay": "^2.0.6",
|
||||
"@pushrocks/smartexpress": "^3.0.52",
|
||||
"@pushrocks/smartfile": "^7.0.6",
|
||||
"@pushrocks/smarthash": "^2.0.6",
|
||||
"@pushrocks/smartlog": "^2.0.19",
|
||||
"@pushrocks/smartpromise": "^3.0.2",
|
||||
"@pushrocks/smartrequest": "^1.1.16",
|
||||
"@pushrocks/smartrx": "^2.0.3",
|
||||
"@pushrocks/smartsocket": "^1.1.44",
|
||||
"@pushrocks/smartlog": "^2.0.21",
|
||||
"@pushrocks/smartpromise": "^3.0.6",
|
||||
"@pushrocks/smartrequest": "^1.1.42",
|
||||
"@pushrocks/smartrx": "^2.0.5",
|
||||
"@pushrocks/smartsocket": "^1.1.58",
|
||||
"@pushrocks/smarttime": "^3.0.12",
|
||||
"@pushrocks/smartunique": "^3.0.1"
|
||||
},
|
||||
|
@ -50,6 +50,6 @@ All your microservices represents clients in the universe that may talk to each
|
||||
For further information read the linked docs at the top of this readme.
|
||||
|
||||
> MIT licensed | **©** [Lossless GmbH](https://lossless.gmbh)
|
||||
| By using this npm module you agree to our [privacy policy](https://lossless.gmbH/privacy.html)
|
||||
| By using this npm module you agree to our [privacy policy](https://lossless.gmbH/privacy)
|
||||
|
||||
[](https://maintainedby.lossless.com)
|
||||
[](https://maintainedby.lossless.com)
|
||||
|
67
test/test.ts
67
test/test.ts
@ -37,24 +37,24 @@ tap.test('create smartuniverse client', async () => {
|
||||
});
|
||||
|
||||
tap.test('should add a channel to the universe', async () => {
|
||||
await testUniverse.addChannel(testChannelData.channelName, testChannelData.channelPass);
|
||||
testUniverse.addChannel(testChannelData.channelName, testChannelData.channelPass);
|
||||
});
|
||||
|
||||
tap.test('should add the same channel to the client universe in the same way', async () => {
|
||||
await testClientUniverse.addChannel(testChannelData.channelName, testChannelData.channelPass);
|
||||
testClientUniverse.addChannel(testChannelData.channelName, testChannelData.channelPass);
|
||||
});
|
||||
|
||||
tap.test('should start the ClientUniverse', async () => {
|
||||
await testClientUniverse.start();
|
||||
})
|
||||
});
|
||||
|
||||
tap.test('should get a observable correctly', async () => {
|
||||
testClientChannel = await testClientUniverse.getChannel(testChannelData.channelName);
|
||||
testClientChannel = testClientUniverse.getChannel(testChannelData.channelName);
|
||||
expect(testClientChannel).to.be.instanceof(smartuniverse.ClientUniverseChannel);
|
||||
});
|
||||
|
||||
tap.test('should send a message correctly', async () => {
|
||||
await (await testClientUniverse.getChannel(testChannelData.channelName)).sendMessage({
|
||||
await testClientUniverse.getChannel(testChannelData.channelName).sendMessage({
|
||||
messageText: 'hello'
|
||||
});
|
||||
});
|
||||
@ -69,15 +69,62 @@ tap.test('a second client should be able to subscibe', async () => {
|
||||
});
|
||||
|
||||
testClientUniverse2.addChannel(testChannelData.channelName, testChannelData.channelPass);
|
||||
await testClientUniverse2.start();
|
||||
});
|
||||
|
||||
tap.test('should receive a message correctly', async () => {});
|
||||
|
||||
tap.test('should disconnect the client correctly', async () => {
|
||||
testClientUniverse.stop();
|
||||
tap.test('should receive a message correctly', async (tools) => {
|
||||
const done = tools.defer();
|
||||
const testChannel = testClientUniverse.getChannel(testChannelData.channelName);
|
||||
const testChannel2 = testClientUniverse2.getChannel(testChannelData.channelName);
|
||||
const subscription = testChannel2.subscribe(messageArg => {
|
||||
if (messageArg.messageText === 'hellothere') {
|
||||
console.log('Yay##########');
|
||||
done.resolve();
|
||||
}
|
||||
});
|
||||
await testChannel.sendMessage({
|
||||
messageText: 'hellothere'
|
||||
});
|
||||
await done.promise;
|
||||
});
|
||||
|
||||
tap.test('should end the server correctly', async tools => {
|
||||
interface IDemoReqRes {
|
||||
method: 'demo',
|
||||
request: {
|
||||
wowso: string;
|
||||
};
|
||||
response: {
|
||||
hereso: string;
|
||||
};
|
||||
}
|
||||
|
||||
tap.test('ReactionRequest and ReactionResponse should work', async () => {
|
||||
const reactionResponse = new smartuniverse.ReactionResponse<IDemoReqRes>({
|
||||
channels: [testUniverse.getChannel(testChannelData.channelName)],
|
||||
funcDef: async reqData => {
|
||||
console.log(reqData);
|
||||
return {
|
||||
hereso: 'Hello there'
|
||||
};
|
||||
},
|
||||
method: 'demo'
|
||||
});
|
||||
const reactionRequest = new smartuniverse.ReactionRequest<IDemoReqRes>({
|
||||
method: 'demo'
|
||||
});
|
||||
const reactionResult = await reactionRequest.fire([testClientUniverse2.getChannel(testChannelData.channelName)], {
|
||||
wowso: 'wowza'
|
||||
});
|
||||
const result = await reactionResult.getFirstResult();
|
||||
console.log(result);
|
||||
});
|
||||
|
||||
tap.test('should disconnect the client correctly', async (tools) => {
|
||||
await testClientUniverse.stop();
|
||||
await testClientUniverse2.stop();
|
||||
});
|
||||
|
||||
tap.test('should end the server correctly', async (tools) => {
|
||||
await testUniverse.stopServer();
|
||||
});
|
||||
|
||||
|
@ -9,4 +9,8 @@ export * from './smartuniverse.classes.universecache';
|
||||
export * from './smartuniverse.classes.universechannel';
|
||||
export * from './smartuniverse.classes.universemessage';
|
||||
|
||||
// Reaction Response
|
||||
export * from './smartuniverse.classes.reactionrequest';
|
||||
export * from './smartuniverse.classes.reactionresponse';
|
||||
|
||||
export * from './interfaces';
|
||||
|
@ -1,4 +1,5 @@
|
||||
export * from './http.interfaces';
|
||||
export * from './socketfunctionrequests';
|
||||
export * from './universechannel.interfaces';
|
||||
export * from './universemessage.interfaces';
|
||||
export * from './universeactions.interfaces';
|
||||
|
20
ts/interfaces/socketfunctionrequests.ts
Normal file
20
ts/interfaces/socketfunctionrequests.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import * as interfaces from './index';
|
||||
|
||||
export interface ISocketRequest_SubscribeChannel {
|
||||
method: 'subscribeChannel';
|
||||
request: {
|
||||
name: string;
|
||||
passphrase: string;
|
||||
};
|
||||
response: {
|
||||
subscriptionStatus: 'subscribed' | 'unsubscribed';
|
||||
};
|
||||
}
|
||||
|
||||
export interface ISocketRequest_ProcessMessage {
|
||||
method: 'processMessage';
|
||||
request: interfaces.IUniverseMessage;
|
||||
response: {
|
||||
messageStatus: 'ok' | 'channel not found';
|
||||
};
|
||||
}
|
@ -1,17 +1,3 @@
|
||||
export type IServerCallActions =
|
||||
| 'channelSubscription'
|
||||
| 'processMessage'
|
||||
| 'channelUnsubscribe'
|
||||
| 'terminateConnection';
|
||||
|
||||
/**
|
||||
* the interface for a subscription
|
||||
*/
|
||||
export interface IServerCallSubscribeActionPayload {
|
||||
name: string;
|
||||
passphrase: string;
|
||||
}
|
||||
|
||||
export interface IServerUnsubscribeActionPayload {
|
||||
name: string;
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
export interface IMessageCreator {
|
||||
messageText: string;
|
||||
payload?: string | number | any;
|
||||
payloadStringType?: 'Buffer' | 'string' | 'object';
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* A universe
|
||||
*/
|
||||
export interface IUniverseMessage extends IMessageCreator {
|
||||
id: string;
|
||||
|
10
ts/smartuniverse.classes.broadcastevent.ts
Normal file
10
ts/smartuniverse.classes.broadcastevent.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import * as plugins from './smartuniverse.plugins';
|
||||
|
||||
/**
|
||||
* broadcasts an event to multiple channels
|
||||
*/
|
||||
export class BroadcastEvent<T> {
|
||||
fire() {
|
||||
|
||||
}
|
||||
};
|
5
ts/smartuniverse.classes.broadcastsubscription.ts
Normal file
5
ts/smartuniverse.classes.broadcastsubscription.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import * as plugins from './smartuniverse.plugins';
|
||||
|
||||
export class BroadcastSUbscription {
|
||||
|
||||
}
|
@ -19,9 +19,9 @@ export interface IClientOptions {
|
||||
* allows connecting to a universe server
|
||||
*/
|
||||
export class ClientUniverse {
|
||||
public options;
|
||||
public options: IClientOptions;
|
||||
public smartsocketClient: plugins.smartsocket.SmartsocketClient;
|
||||
public observableIntake: plugins.smartrx.ObservableIntake<ClientUniverseMessage>;
|
||||
public messageRxjsSubject = new plugins.smartrx.rxjs.Subject<ClientUniverseMessage<any>>();
|
||||
public clientUniverseCache = new ClientUniverseCache();
|
||||
|
||||
constructor(optionsArg: IClientOptions) {
|
||||
@ -32,15 +32,20 @@ export class ClientUniverse {
|
||||
* adds a channel to the channelcache
|
||||
* TODO: verify channel before adding it to the channel cache
|
||||
*/
|
||||
public async addChannel(channelNameArg: string, passphraseArg: string) {
|
||||
const existingChannel = await this.getChannel(channelNameArg);
|
||||
public addChannel(channelNameArg: string, passphraseArg: string) {
|
||||
const existingChannel = this.getChannel(channelNameArg);
|
||||
|
||||
if (existingChannel) {
|
||||
throw new Error('channel exists');
|
||||
}
|
||||
|
||||
// lets create the channel
|
||||
await ClientUniverseChannel.createClientUniverseChannel(this, channelNameArg, passphraseArg);
|
||||
const clientUniverseChannel = ClientUniverseChannel.createClientUniverseChannel(
|
||||
this,
|
||||
channelNameArg,
|
||||
passphraseArg
|
||||
);
|
||||
return clientUniverseChannel;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -48,7 +53,7 @@ export class ClientUniverse {
|
||||
* @param channelName
|
||||
* @param passphraseArg
|
||||
*/
|
||||
public async getChannel(channelName: string): Promise<ClientUniverseChannel> {
|
||||
public getChannel(channelName: string): ClientUniverseChannel {
|
||||
const clientUniverseChannel = this.clientUniverseCache.channelMap.find(channel => {
|
||||
return channel.name === channelName;
|
||||
});
|
||||
@ -60,17 +65,19 @@ export class ClientUniverse {
|
||||
* @param messageArg
|
||||
*/
|
||||
public removeChannel(channelNameArg, notifyServer = true) {
|
||||
const clientUniverseChannel = this.clientUniverseCache.channelMap.findOneAndRemove(channelItemArg => {
|
||||
const clientUniverseChannel = this.clientUniverseCache.channelMap.findOneAndRemove(
|
||||
channelItemArg => {
|
||||
return channelItemArg.name === channelNameArg;
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public async start() {
|
||||
await this.checkConnection();
|
||||
}
|
||||
|
||||
public stop() {
|
||||
this.smartsocketClient.disconnect();
|
||||
public async stop() {
|
||||
await this.disconnect('triggered');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -78,17 +85,23 @@ export class ClientUniverse {
|
||||
* since password validation is done through other means, a connection should always be possible
|
||||
*/
|
||||
public async checkConnection(): Promise<void> {
|
||||
if (!this.smartsocketClient && !this.observableIntake) {
|
||||
if (!this.smartsocketClient) {
|
||||
const parsedURL = url.parse(this.options.serverAddress);
|
||||
const socketConfig: plugins.smartsocket.ISmartsocketClientOptions = {
|
||||
alias: process.env.SOCKET_ALIAS || 'someclient',
|
||||
alias: 'universeclient',
|
||||
password: 'UniverseClient',
|
||||
port: parseInt(parsedURL.port, 10),
|
||||
role: 'UniverseClient',
|
||||
url: parsedURL.protocol + '//' + parsedURL.hostname
|
||||
};
|
||||
this.smartsocketClient = new SmartsocketClient(socketConfig);
|
||||
this.observableIntake = new plugins.smartrx.ObservableIntake();
|
||||
|
||||
this.smartsocketClient.eventSubject.subscribe(async eventArg => {
|
||||
switch(eventArg) {
|
||||
case 'disconnected':
|
||||
this.disconnect('upstreamEvent');
|
||||
}
|
||||
});
|
||||
|
||||
// lets define some basic actions
|
||||
|
||||
@ -98,20 +111,44 @@ export class ClientUniverse {
|
||||
const socketFunctionUnsubscribe = new plugins.smartsocket.SocketFunction({
|
||||
funcName: 'unsubscribe',
|
||||
allowedRoles: [],
|
||||
funcDef: async (data: interfaces.IServerUnsubscribeActionPayload) => {
|
||||
throw new Error('TODO');
|
||||
funcDef: async (dataArg: interfaces.IServerUnsubscribeActionPayload) => {
|
||||
const channel = this.clientUniverseCache.channelMap.find(channelArg => {
|
||||
return channelArg.name === dataArg.name;
|
||||
});
|
||||
if (channel) {
|
||||
channel.unsubscribe();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* handles message reception
|
||||
*/
|
||||
const socketFunctionProcessMessage = new plugins.smartsocket.SocketFunction({
|
||||
const socketFunctionProcessMessage = new plugins.smartsocket.SocketFunction<
|
||||
interfaces.ISocketRequest_ProcessMessage
|
||||
>({
|
||||
funcName: 'processMessage',
|
||||
allowedRoles: [],
|
||||
funcDef: async (messageDescriptorArg: interfaces.IUniverseMessage) => {
|
||||
funcDef: async messageDescriptorArg => {
|
||||
plugins.smartlog.defaultLogger.log('info', 'Got message from server');
|
||||
this.observableIntake.push(ClientUniverseMessage.createMessageFromMessageDescriptor(messageDescriptorArg));
|
||||
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'
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -122,8 +159,19 @@ export class ClientUniverse {
|
||||
await this.smartsocketClient.connect();
|
||||
plugins.smartlog.defaultLogger.log('info', 'universe client connected successfully');
|
||||
await this.clientUniverseCache.channelMap.forEach(async clientUniverseChannelArg => {
|
||||
await clientUniverseChannelArg.subscribe();
|
||||
await clientUniverseChannelArg.populateSubscriptionToServer();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public async disconnect(reason: 'upstreamEvent' | 'triggered' = 'triggered', tryReconnect = false) {
|
||||
if ('triggered') {
|
||||
this.smartsocketClient.disconnect();
|
||||
}
|
||||
this.smartsocketClient = null;
|
||||
if (tryReconnect) {
|
||||
await plugins.smartdelay.delayForRandom(5000, 20000);
|
||||
this.checkConnection();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,9 @@ import * as plugins from './smartuniverse.plugins';
|
||||
import * as interfaces from './interfaces';
|
||||
|
||||
import { ClientUniverse } from './';
|
||||
import { ClientUniverseMessage } from './smartuniverse.classes.clientuniversemessage';
|
||||
import { ReactionRequest } from './smartuniverse.classes.reactionrequest';
|
||||
import { ReactionResponse } from './smartuniverse.classes.reactionresponse';
|
||||
|
||||
export class ClientUniverseChannel implements interfaces.IUniverseChannel {
|
||||
// ======
|
||||
@ -13,11 +16,11 @@ export class ClientUniverseChannel implements interfaces.IUniverseChannel {
|
||||
* @param channelNameArg
|
||||
* @param passphraseArg
|
||||
*/
|
||||
public static async createClientUniverseChannel(
|
||||
public static createClientUniverseChannel(
|
||||
clientUniverseArg: ClientUniverse,
|
||||
channelNameArg: string,
|
||||
passphraseArg: string
|
||||
): Promise<ClientUniverseChannel> {
|
||||
): ClientUniverseChannel {
|
||||
const clientChannel = new ClientUniverseChannel(
|
||||
clientUniverseArg,
|
||||
channelNameArg,
|
||||
@ -34,6 +37,8 @@ export class ClientUniverseChannel implements interfaces.IUniverseChannel {
|
||||
// properties
|
||||
public name: string;
|
||||
public passphrase: string;
|
||||
public status: 'subscribed' | 'unsubscribed' = 'unsubscribed';
|
||||
private subject = new plugins.smartrx.rxjs.Subject<ClientUniverseMessage<any>>();
|
||||
|
||||
// refs
|
||||
public clientUniverseRef: ClientUniverse;
|
||||
@ -48,13 +53,35 @@ export class ClientUniverseChannel implements interfaces.IUniverseChannel {
|
||||
* subscribes to a channel
|
||||
* tells the universe about this instances interest into a channel
|
||||
*/
|
||||
public async subscribe() {
|
||||
const serverCallActionName: interfaces.IServerCallActions = 'channelSubscription';
|
||||
const serverCallActionPayload: interfaces.IServerCallSubscribeActionPayload = {
|
||||
public subscribe(observingFunctionArg: (messageArg: ClientUniverseMessage<any>) => void) {
|
||||
|
||||
return this.subject.subscribe(
|
||||
messageArg => {
|
||||
observingFunctionArg(messageArg);
|
||||
},
|
||||
error => console.log(error)
|
||||
);
|
||||
}
|
||||
|
||||
public unsubscribe() {
|
||||
// TODO: unsubscribe all users
|
||||
}
|
||||
|
||||
public async populateSubscriptionToServer() {
|
||||
// lets make sure the channel is connected
|
||||
if (this.status === 'unsubscribed') {
|
||||
const response = await this.clientUniverseRef.smartsocketClient.serverCall<
|
||||
interfaces.ISocketRequest_SubscribeChannel
|
||||
>('subscribeChannel', {
|
||||
name: this.name,
|
||||
passphrase: this.passphrase
|
||||
};
|
||||
await this.clientUniverseRef.smartsocketClient.serverCall(serverCallActionName, serverCallActionPayload);
|
||||
});
|
||||
this.status = response.subscriptionStatus;
|
||||
}
|
||||
}
|
||||
|
||||
public async emitMessageLocally(messageArg: ClientUniverseMessage<any>) {
|
||||
this.subject.next(messageArg);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -69,9 +96,11 @@ export class ClientUniverseChannel implements interfaces.IUniverseChannel {
|
||||
passphrase: this.passphrase,
|
||||
targetChannelName: this.name,
|
||||
messageText: messageArg.messageText,
|
||||
payload: messageArg.payload,
|
||||
payloadStringType: messageArg.payloadStringType
|
||||
payload: messageArg.payload
|
||||
};
|
||||
await this.clientUniverseRef.smartsocketClient.serverCall('processMessage', universeMessageToSend);
|
||||
await this.clientUniverseRef.smartsocketClient.serverCall(
|
||||
'processMessage',
|
||||
universeMessageToSend
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import * as plugins from './smartuniverse.plugins';
|
||||
|
||||
import * as interfaces from './interfaces';
|
||||
|
||||
export class ClientUniverseMessage implements interfaces.IUniverseMessage {
|
||||
export class ClientUniverseMessage<T> implements interfaces.IUniverseMessage {
|
||||
// ======
|
||||
// STATIC
|
||||
// ======
|
||||
@ -22,8 +22,7 @@ export class ClientUniverseMessage implements interfaces.IUniverseMessage {
|
||||
public smartTimestamp: plugins.smarttime.TimeStamp;
|
||||
public messageText: string;
|
||||
public passphrase: string;
|
||||
public payload: any;
|
||||
public payloadStringType;
|
||||
public payload: T;
|
||||
public targetChannelName: string;
|
||||
|
||||
constructor(messageArg: interfaces.IUniverseMessage) {
|
||||
|
66
ts/smartuniverse.classes.reactionrequest.ts
Normal file
66
ts/smartuniverse.classes.reactionrequest.ts
Normal file
@ -0,0 +1,66 @@
|
||||
import * as plugins from './smartuniverse.plugins';
|
||||
import { UniverseChannel } from './smartuniverse.classes.universechannel';
|
||||
import { ClientUniverseChannel } from './smartuniverse.classes.clientuniversechannel';
|
||||
import { ReactionResult } from './smartuniverse.classes.reactionresult';
|
||||
import { UniverseMessage } from './smartuniverse.classes.universemessage';
|
||||
import { ClientUniverseMessage } from './smartuniverse.classes.clientuniversemessage';
|
||||
|
||||
export interface IReactionRequestConstructorOptions<T extends plugins.typedrequestInterfaces.ITypedRequest> {
|
||||
method: T['method'];
|
||||
}
|
||||
|
||||
export interface ICombinatorPayload<T extends plugins.typedrequestInterfaces.ITypedRequest> {
|
||||
/**
|
||||
* needed for tying responses to requests
|
||||
*/
|
||||
id: string;
|
||||
typedRequestPayload: {
|
||||
method: T['method'],
|
||||
request : T['request'],
|
||||
response: T['response']
|
||||
};
|
||||
}
|
||||
|
||||
export class ReactionRequest<T extends plugins.typedrequestInterfaces.ITypedRequest> {
|
||||
public method: T['method'];
|
||||
|
||||
constructor(optionsArg: IReactionRequestConstructorOptions<T>) {
|
||||
this.method = optionsArg.method;
|
||||
}
|
||||
|
||||
public async fire(channelsArg: Array<UniverseChannel | ClientUniverseChannel>, requestDataArg: T['request'], timeoutMillisArg=5000) {
|
||||
const subscriptionMap = new plugins.lik.Objectmap<plugins.smartrx.rxjs.Subscription>();
|
||||
const reactionResult = new ReactionResult<T>();
|
||||
const requestId = plugins.smartunique.shortId();
|
||||
for (const channel of channelsArg) {
|
||||
subscriptionMap.add(channel.subscribe((messageArg: UniverseMessage<ICombinatorPayload<T>> | ClientUniverseMessage<ICombinatorPayload<T>>) => {
|
||||
if (messageArg.messageText === 'reactionResponse' && messageArg.payload.typedRequestPayload.method === this.method) {
|
||||
const payload: ICombinatorPayload<T> = messageArg.payload;
|
||||
if (payload.id !== requestId) {
|
||||
return;
|
||||
}
|
||||
reactionResult.pushReactionResponse(payload.typedRequestPayload.response);
|
||||
}
|
||||
}));
|
||||
const payload: ICombinatorPayload<T> = {
|
||||
id: requestId,
|
||||
typedRequestPayload: {
|
||||
method: this.method,
|
||||
request: requestDataArg,
|
||||
response: null
|
||||
}
|
||||
};
|
||||
channel.sendMessage({
|
||||
messageText: 'reactionRequest',
|
||||
payload
|
||||
});
|
||||
}
|
||||
plugins.smartdelay.delayFor(timeoutMillisArg).then(async () => {
|
||||
await subscriptionMap.forEach(subscriptionArg => {
|
||||
subscriptionArg.unsubscribe();
|
||||
});
|
||||
reactionResult.complete();
|
||||
});
|
||||
return reactionResult;
|
||||
}
|
||||
}
|
59
ts/smartuniverse.classes.reactionresponse.ts
Normal file
59
ts/smartuniverse.classes.reactionresponse.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import * as plugins from './smartuniverse.plugins';
|
||||
|
||||
import { ICombinatorPayload } from './smartuniverse.classes.reactionrequest';
|
||||
import { UniverseChannel } from './smartuniverse.classes.universechannel';
|
||||
import { ClientUniverseChannel } from './smartuniverse.classes.clientuniversechannel';
|
||||
import { UniverseMessage } from './smartuniverse.classes.universemessage';
|
||||
import { ClientUniverseMessage } from './smartuniverse.classes.clientuniversemessage';
|
||||
|
||||
export type TReactionResponseFuncDef<T extends plugins.typedrequestInterfaces.ITypedRequest> = (dataArg: T['request']) => Promise<T['response']>;
|
||||
|
||||
export interface IReactionResponseConstructorOptions<
|
||||
T extends plugins.typedrequestInterfaces.ITypedRequest
|
||||
> {
|
||||
method: T['method'];
|
||||
channels: Array<UniverseChannel | ClientUniverseChannel>;
|
||||
funcDef: TReactionResponseFuncDef<T>;
|
||||
}
|
||||
|
||||
export class ReactionResponse<T extends plugins.typedrequestInterfaces.ITypedRequest> {
|
||||
public method: T['method'];
|
||||
public channels = new plugins.lik.Objectmap<UniverseChannel | ClientUniverseChannel>();
|
||||
public funcDef: TReactionResponseFuncDef<T>;
|
||||
|
||||
constructor(optionsArg: IReactionResponseConstructorOptions<T>) {
|
||||
this.method = optionsArg.method;
|
||||
this.channels.addArray(optionsArg.channels);
|
||||
this.funcDef = optionsArg.funcDef;
|
||||
for (const channel of this.channels.getArray()) {
|
||||
channel.subscribe(messageArg => {
|
||||
this.processMessageForReaction(channel, messageArg);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private async processMessageForReaction(
|
||||
channelArg: UniverseChannel | ClientUniverseChannel,
|
||||
messageArg:
|
||||
| UniverseMessage<ICombinatorPayload<T>>
|
||||
| ClientUniverseMessage<ICombinatorPayload<T>>
|
||||
) {
|
||||
if (
|
||||
messageArg.messageText === 'reactionRequest' &&
|
||||
messageArg.payload.typedRequestPayload.method === this.method
|
||||
) {
|
||||
const response: T['response'] = await this.funcDef(messageArg.payload.typedRequestPayload.request);
|
||||
const payload: ICombinatorPayload<T> = {
|
||||
...messageArg.payload,
|
||||
typedRequestPayload: {
|
||||
...messageArg.payload.typedRequestPayload,
|
||||
response
|
||||
}
|
||||
};
|
||||
channelArg.sendMessage({
|
||||
messageText: 'reactionResponse',
|
||||
payload
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
52
ts/smartuniverse.classes.reactionresult.ts
Normal file
52
ts/smartuniverse.classes.reactionresult.ts
Normal file
@ -0,0 +1,52 @@
|
||||
import * as plugins from './smartuniverse.plugins';
|
||||
import { ReactionResponse } from './smartuniverse.classes.reactionresponse';
|
||||
|
||||
export class ReactionResult<T extends plugins.typedrequestInterfaces.ITypedRequest> {
|
||||
private resultReplaySubject = new plugins.smartrx.rxjs.ReplaySubject<T['response']>();
|
||||
private endResult: Array<T['response']> = [];
|
||||
private completeDeferred = plugins.smartpromise.defer<Array<T['response']>>();
|
||||
|
||||
constructor () {
|
||||
this.resultSubscribe(responseArg => {
|
||||
this.endResult.push(responseArg);
|
||||
});
|
||||
}
|
||||
|
||||
public resultSubscribe(observerArg: (responseArg: T['response']) => void) {
|
||||
return this.resultReplaySubject.subscribe(observerArg);
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the end result as an array of all results
|
||||
*/
|
||||
public async getEndResult() {
|
||||
const result = await this.completeDeferred.promise;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* if there is a single respondant, or you are only interested in the first result
|
||||
*/
|
||||
public async getFirstResult() {
|
||||
const done = plugins.smartpromise.defer<T['response']>();
|
||||
const subscription = this.resultReplaySubject.subscribe(result => {
|
||||
done.resolve(result);
|
||||
subscription.unsubscribe();
|
||||
});
|
||||
return await done.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* push a reactionResponse
|
||||
*/
|
||||
public async pushReactionResponse(responseArg: T['response']) {
|
||||
this.resultReplaySubject.next(responseArg);
|
||||
}
|
||||
|
||||
/**
|
||||
* completes the ReactionResult
|
||||
*/
|
||||
public async complete() {
|
||||
this.completeDeferred.resolve(this.endResult);
|
||||
}
|
||||
}
|
@ -10,6 +10,7 @@ import { UniverseConnection } from './smartuniverse.classes.universeconnection';
|
||||
|
||||
export interface ISmartUniverseConstructorOptions {
|
||||
messageExpiryInMilliseconds: number;
|
||||
externalServer?: plugins.smartexpress.Server;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -59,8 +60,18 @@ export class Universe {
|
||||
/**
|
||||
* adds a channel to the Universe
|
||||
*/
|
||||
public async addChannel(nameArg: string, passphraseArg: string) {
|
||||
public addChannel(nameArg: string, passphraseArg: string) {
|
||||
const newChannel = UniverseChannel.createChannel(this, nameArg, passphraseArg);
|
||||
return newChannel;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a channel
|
||||
*/
|
||||
public getChannel(channelNameArg: string) {
|
||||
return this.universeCache.channelMap.find(channelArg => {
|
||||
return channelArg.name === channelNameArg;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -68,6 +79,7 @@ export class Universe {
|
||||
*/
|
||||
public async start(portArg: number) {
|
||||
// lets create the base smartexpress server
|
||||
if (!this.options.externalServer) {
|
||||
this.smartexpressServer = new plugins.smartexpress.Server({
|
||||
cors: true,
|
||||
defaultAnswer: async () => {
|
||||
@ -76,6 +88,10 @@ export class Universe {
|
||||
forceSsl: false,
|
||||
port: portArg
|
||||
});
|
||||
} else {
|
||||
console.log('Universe is using externally supplied server');
|
||||
this.smartexpressServer = this.options.externalServer;
|
||||
}
|
||||
|
||||
// add websocket upgrade
|
||||
this.smartsocket = new plugins.smartsocket.Smartsocket({});
|
||||
@ -89,24 +105,21 @@ export class Universe {
|
||||
// add the role to smartsocket
|
||||
this.smartsocket.addSocketRoles([ClientRole]);
|
||||
|
||||
const socketFunctionSubscription = new plugins.smartsocket.SocketFunction({
|
||||
const socketFunctionSubscription = new plugins.smartsocket.SocketFunction<
|
||||
interfaces.ISocketRequest_SubscribeChannel
|
||||
>({
|
||||
allowedRoles: [ClientRole], // there is only one client role, Authentication happens on another level
|
||||
funcName: 'channelSubscription',
|
||||
funcDef: async (
|
||||
dataArg: interfaces.IServerCallSubscribeActionPayload,
|
||||
socketConnectionArg
|
||||
) => {
|
||||
// run in "this context" of this class
|
||||
await (async () => {
|
||||
funcName: 'subscribeChannel',
|
||||
funcDef: async (dataArg, socketConnectionArg) => {
|
||||
const universeConnection = new UniverseConnection({
|
||||
universe: this,
|
||||
socketConnection: socketConnectionArg,
|
||||
authenticationRequests: [dataArg]
|
||||
});
|
||||
await UniverseConnection.addConnectionToCache(this, universeConnection);
|
||||
return {
|
||||
'subscription status': 'success'
|
||||
subscriptionStatus: 'subscribed'
|
||||
};
|
||||
})();
|
||||
}
|
||||
});
|
||||
|
||||
@ -114,21 +127,28 @@ export class Universe {
|
||||
allowedRoles: [ClientRole], // there is only one client role, Authentication happens on another level
|
||||
funcName: 'processMessage',
|
||||
funcDef: async (dataArg: interfaces.IUniverseMessage, socketConnectionArg) => {
|
||||
// run in "this" context of this class
|
||||
await (async () => {
|
||||
const universeConnection = UniverseConnection.findUniverseConnectionBySocketConnection(
|
||||
this.universeCache,
|
||||
socketConnectionArg
|
||||
);
|
||||
if (universeConnection) {
|
||||
plugins.smartlog.defaultLogger.log('ok', 'found UniverseConnection for socket for incoming message');
|
||||
plugins.smartlog.defaultLogger.log(
|
||||
'ok',
|
||||
'found UniverseConnection for socket for incoming message'
|
||||
);
|
||||
} else {
|
||||
plugins.smartlog.defaultLogger.log('warn', 'found no Authorized channel for incoming message');
|
||||
plugins.smartlog.defaultLogger.log(
|
||||
'warn',
|
||||
'found no Authorized channel for incoming message'
|
||||
);
|
||||
return {
|
||||
error: 'You need to authenticate for a channel'
|
||||
};
|
||||
}
|
||||
const unauthenticatedMessage = UniverseMessage.createMessageFromPayload(socketConnectionArg, dataArg);
|
||||
const unauthenticatedMessage = UniverseMessage.createMessageFromPayload(
|
||||
socketConnectionArg,
|
||||
dataArg
|
||||
);
|
||||
const foundChannel = await UniverseChannel.authorizeAMessageForAChannel(
|
||||
this.universeCache,
|
||||
unauthenticatedMessage
|
||||
@ -137,7 +157,6 @@ export class Universe {
|
||||
const authenticatedMessage = unauthenticatedMessage;
|
||||
await this.universeCache.addMessage(authenticatedMessage);
|
||||
}
|
||||
})();
|
||||
}
|
||||
});
|
||||
|
||||
@ -145,10 +164,13 @@ export class Universe {
|
||||
this.smartsocket.addSocketFunction(socketFunctionSubscription);
|
||||
this.smartsocket.addSocketFunction(socketFunctionProcessMessage);
|
||||
|
||||
// add smartsocket to the running smartexpress app
|
||||
this.smartsocket.setExternalServer('smartexpress', this.smartexpressServer as any);
|
||||
// start everything
|
||||
// start the server
|
||||
if (!this.options.externalServer) {
|
||||
await this.smartexpressServer.start();
|
||||
}
|
||||
|
||||
// add smartsocket to the running smartexpress app
|
||||
await this.smartsocket.setExternalServer('smartexpress', this.smartexpressServer);
|
||||
await this.smartsocket.start();
|
||||
plugins.smartlog.defaultLogger.log('success', 'started universe');
|
||||
}
|
||||
@ -158,6 +180,8 @@ export class Universe {
|
||||
*/
|
||||
public async stopServer() {
|
||||
await this.smartsocket.stop();
|
||||
if (!this.options.externalServer) {
|
||||
await this.smartexpressServer.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,12 +19,12 @@ export class UniverseCache {
|
||||
// INSTANCE
|
||||
// ========
|
||||
public standardMessageExpiry: number;
|
||||
public destructionTime: number = 60000;
|
||||
public destructionTime: number = 10000;
|
||||
|
||||
/**
|
||||
* stores messages for this instance
|
||||
*/
|
||||
public messageMap = new Objectmap<UniverseMessage>();
|
||||
public messageMap = new Objectmap<UniverseMessage<any>>();
|
||||
|
||||
/**
|
||||
* stores the channels that are available within the universe
|
||||
@ -54,12 +54,12 @@ export class UniverseCache {
|
||||
* @param messageArg
|
||||
* @param attachedPayloadArg
|
||||
*/
|
||||
public async addMessage(messageArg: UniverseMessage) {
|
||||
public async addMessage(messageArg: UniverseMessage<any>) {
|
||||
messageArg.setUniverseCache(this);
|
||||
UniverseChannel.authorizeAMessageForAChannel(this, messageArg);
|
||||
this.messageMap.add(messageArg);
|
||||
messageArg.universeChannelList.forEach(universeChannel => {
|
||||
universeChannel.pushToClients(messageArg);
|
||||
universeChannel.push(messageArg);
|
||||
});
|
||||
}
|
||||
|
||||
@ -69,7 +69,7 @@ export class UniverseCache {
|
||||
public readMessagesYoungerThan(
|
||||
unixTimeArg?: number,
|
||||
channelName?: string
|
||||
): Observable<UniverseMessage> {
|
||||
): Observable<UniverseMessage<any>> {
|
||||
const messageObservable = from(this.messageMap.getArray()).pipe(
|
||||
filter(messageArg => {
|
||||
return messageArg.smartTimestamp.isYoungerThanMilliSeconds(this.destructionTime);
|
||||
|
@ -52,7 +52,7 @@ export class UniverseChannel {
|
||||
*/
|
||||
public static authorizeAMessageForAChannel(
|
||||
universeCacheArg: UniverseCache,
|
||||
universeMessageArg: UniverseMessage
|
||||
universeMessageArg: UniverseMessage<any>
|
||||
): UniverseChannel {
|
||||
const foundChannel = universeCacheArg.channelMap.find(universeChannel => {
|
||||
const result = universeChannel.authenticate(universeMessageArg);
|
||||
@ -85,6 +85,7 @@ export class UniverseChannel {
|
||||
*/
|
||||
public name: string;
|
||||
public universeRef: Universe;
|
||||
private subject = new plugins.smartrx.rxjs.Subject<UniverseMessage<any>>();
|
||||
|
||||
/**
|
||||
* the passphrase for the channel
|
||||
@ -102,7 +103,7 @@ export class UniverseChannel {
|
||||
* # the messages channelName against the unverseChannel's name
|
||||
* # the messages password against the universeChannel's password
|
||||
*/
|
||||
public authenticate(universeMessageArg: UniverseMessage): boolean {
|
||||
public authenticate(universeMessageArg: UniverseMessage<any>): boolean {
|
||||
return (
|
||||
this.name === universeMessageArg.targetChannelName &&
|
||||
this.passphrase === universeMessageArg.passphrase
|
||||
@ -113,25 +114,55 @@ export class UniverseChannel {
|
||||
* pushes a message to clients
|
||||
* @param messageArg
|
||||
*/
|
||||
public async pushToClients(messageArg: UniverseMessage) {
|
||||
public async push(messageArg: UniverseMessage<any>) {
|
||||
this.subject.next(messageArg);
|
||||
const universeConnectionsWithChannelAccess: UniverseConnection[] = [];
|
||||
this.universeRef.universeCache.connectionMap.forEach(async socketConnection => {
|
||||
await this.universeRef.universeCache.connectionMap.forEach(async socketConnection => {
|
||||
if (socketConnection.authenticatedChannels.includes(this)) {
|
||||
universeConnectionsWithChannelAccess.push(socketConnection);
|
||||
}
|
||||
});
|
||||
for (const universeConnection of universeConnectionsWithChannelAccess) {
|
||||
const smartsocket = universeConnection.socketConnection.smartsocketRef as plugins.smartsocket.Smartsocket;
|
||||
const smartsocket = universeConnection.socketConnection
|
||||
.smartsocketRef as plugins.smartsocket.Smartsocket;
|
||||
const universeMessageToSend: interfaces.IUniverseMessage = {
|
||||
id: messageArg.id,
|
||||
timestamp: messageArg.timestamp,
|
||||
passphrase: messageArg.passphrase,
|
||||
targetChannelName: this.name,
|
||||
messageText: messageArg.messageText,
|
||||
payload: messageArg.payload,
|
||||
payloadStringType: messageArg.payloadStringType
|
||||
payload: messageArg.payload
|
||||
};
|
||||
smartsocket.clientCall('processMessage', universeMessageToSend, universeConnection.socketConnection);
|
||||
smartsocket.clientCall(
|
||||
'processMessage',
|
||||
universeMessageToSend,
|
||||
universeConnection.socketConnection
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// functions to interact with a channel locally
|
||||
public subscribe(observingFunctionArg: (messageArg: UniverseMessage<any>) => void) {
|
||||
return this.subject.subscribe(
|
||||
messageArg => {
|
||||
observingFunctionArg(messageArg);
|
||||
},
|
||||
error => console.log(error)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* sends a message to the channel
|
||||
*/
|
||||
public async sendMessage(messageDescriptor: interfaces.IMessageCreator) {
|
||||
const messageToSend = new UniverseMessage({
|
||||
id: plugins.smartunique.shortId(),
|
||||
messageText: messageDescriptor.messageText,
|
||||
payload: messageDescriptor.payload,
|
||||
targetChannelName: this.name,
|
||||
passphrase: this.passphrase,
|
||||
timestamp: Date.now()
|
||||
});
|
||||
this.universeRef.universeCache.addMessage(messageToSend);
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ export class UniverseConnection {
|
||||
universeConnection
|
||||
);
|
||||
universeRef.universeCache.connectionMap.add(universeConnection);
|
||||
console.log('hi');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -58,7 +59,10 @@ export class UniverseConnection {
|
||||
universeConnectionArg: UniverseConnection
|
||||
): Promise<UniverseConnection> {
|
||||
for (const authenticationRequest of universeConnectionArg.authenticationRequests) {
|
||||
const universeChannelToAuthenticateAgainst = UniverseChannel.getUniverseChannelByName(universeRef, authenticationRequest.name);
|
||||
const universeChannelToAuthenticateAgainst = UniverseChannel.getUniverseChannelByName(
|
||||
universeRef,
|
||||
authenticationRequest.name
|
||||
);
|
||||
if (universeChannelToAuthenticateAgainst.passphrase === authenticationRequest.passphrase) {
|
||||
universeConnectionArg.authenticatedChannels.push(universeChannelToAuthenticateAgainst);
|
||||
}
|
||||
@ -89,30 +93,42 @@ export class UniverseConnection {
|
||||
return universeConnection;
|
||||
}
|
||||
|
||||
// INSTANCE
|
||||
public universeRef: Universe;
|
||||
public terminatedDeferred = plugins.smartpromise.defer();
|
||||
|
||||
/**
|
||||
* the socketClient to ping
|
||||
*/
|
||||
public socketConnection: plugins.smartsocket.SocketConnection;
|
||||
public authenticationRequests: interfaces.IServerCallSubscribeActionPayload[] = [];
|
||||
public subscribedChannels: UniverseChannel[] = [];
|
||||
public authenticationRequests: Array<interfaces.ISocketRequest_SubscribeChannel['request']> = [];
|
||||
public authenticatedChannels: UniverseChannel[] = [];
|
||||
public failedToJoinChannels: UniverseChannel[] = [];
|
||||
|
||||
/**
|
||||
* terminates the connection
|
||||
* disconnect the connection
|
||||
*/
|
||||
public terminateConnection() {
|
||||
this.socketConnection.socket.disconnect();
|
||||
public async disconnect(reason: 'upstreamevent' | 'triggered' = 'triggered') {
|
||||
if (reason === 'triggered') {
|
||||
await this.socketConnection.disconnect();
|
||||
}
|
||||
this.universeRef.universeCache.connectionMap.remove(this);
|
||||
this.terminatedDeferred.resolve();
|
||||
}
|
||||
|
||||
constructor(optionsArg: {
|
||||
universe: Universe;
|
||||
socketConnection: plugins.smartsocket.SocketConnection;
|
||||
authenticationRequests: interfaces.IServerCallSubscribeActionPayload[];
|
||||
authenticationRequests: Array<interfaces.ISocketRequest_SubscribeChannel['request']>;
|
||||
}) {
|
||||
this.authenticationRequests = optionsArg.authenticationRequests;
|
||||
this.socketConnection = optionsArg.socketConnection;
|
||||
this.socketConnection.eventSubject.subscribe(async eventArg => {
|
||||
switch (eventArg) {
|
||||
case 'disconnected':
|
||||
await this.disconnect('upstreamevent');
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -13,8 +13,11 @@ import { SocketConnection } from '@pushrocks/smartsocket';
|
||||
* represents a message within a universe
|
||||
* acts as a container to save message states like authentication status
|
||||
*/
|
||||
export class UniverseMessage implements interfaces.IUniverseMessage {
|
||||
public static createMessageFromPayload(socketConnectionArg: SocketConnection, dataArg: interfaces.IUniverseMessage) {
|
||||
export class UniverseMessage<T> implements interfaces.IUniverseMessage {
|
||||
public static createMessageFromPayload(
|
||||
socketConnectionArg: SocketConnection,
|
||||
dataArg: interfaces.IUniverseMessage
|
||||
) {
|
||||
const universeMessageInstance = new UniverseMessage(dataArg);
|
||||
universeMessageInstance.socketConnection = socketConnectionArg;
|
||||
return universeMessageInstance;
|
||||
@ -25,8 +28,7 @@ export class UniverseMessage implements interfaces.IUniverseMessage {
|
||||
public smartTimestamp: TimeStamp;
|
||||
public messageText: string;
|
||||
public passphrase: string;
|
||||
public payload: any;
|
||||
public payloadStringType;
|
||||
public payload: T;
|
||||
public targetChannelName: string;
|
||||
public socketConnection: SocketConnection;
|
||||
|
||||
@ -62,28 +64,32 @@ export class UniverseMessage implements interfaces.IUniverseMessage {
|
||||
this.passphrase = messageDescriptor.passphrase;
|
||||
this.payload = messageDescriptor.payload;
|
||||
// prevent memory issues
|
||||
this.fallBackDestruction();
|
||||
this.setDestructionTimer();
|
||||
}
|
||||
|
||||
public setUniverseCache(universeCacheArg: UniverseCache) {
|
||||
this.universeCache = universeCacheArg;
|
||||
}
|
||||
|
||||
public setTargetChannel() {
|
||||
public setTargetChannel() {}
|
||||
|
||||
}
|
||||
|
||||
public setDestructionTimer(selfdestructAfterArg: number) {
|
||||
public setDestructionTimer(selfdestructAfterArg?: number) {
|
||||
if (selfdestructAfterArg) {
|
||||
this.destructionTimer = new Timer(selfdestructAfterArg);
|
||||
this.destructionTimer.start();
|
||||
|
||||
// set up self destruction by removing this from the parent messageCache
|
||||
this.destructionTimer.completed.then(async () => {
|
||||
this.universeCache.messageMap.remove(this);
|
||||
}).catch(err => {
|
||||
console.log(err);
|
||||
console.log(this);
|
||||
});
|
||||
} else {
|
||||
this.fallBackDestruction();
|
||||
plugins.smartdelay.delayFor(1000).then(() => {
|
||||
if (!this.destructionTimer) {
|
||||
this.setDestructionTimer(6000);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,15 +99,4 @@ export class UniverseMessage implements interfaces.IUniverseMessage {
|
||||
public handleAsBadMessage() {
|
||||
plugins.smartlog.defaultLogger.log('warn', 'received a bad message');
|
||||
}
|
||||
|
||||
/**
|
||||
* prevents memory leaks if channels have no default
|
||||
*/
|
||||
private fallBackDestruction() {
|
||||
plugins.smartdelay.delayFor(1000).then(() => {
|
||||
if (!this.destructionTimer) {
|
||||
this.setDestructionTimer(6000);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,13 @@ import * as path from 'path';
|
||||
|
||||
export { path };
|
||||
|
||||
// apiglobal scope
|
||||
import * as typedrequestInterfaces from '@apiglobal/typedrequest-interfaces';
|
||||
|
||||
export {
|
||||
typedrequestInterfaces
|
||||
};
|
||||
|
||||
// pushrocks scope
|
||||
import * as lik from '@pushrocks/lik';
|
||||
import * as smarthash from '@pushrocks/smarthash';
|
||||
|
Reference in New Issue
Block a user