Compare commits

..

22 Commits

Author SHA1 Message Date
3ee46a31f7 1.2.6 2021-01-28 01:39:24 +00:00
d72310ce10 fix(core): update 2021-01-28 01:39:23 +00:00
1e14166ddb 1.2.5 2021-01-28 01:31:43 +00:00
be38e91548 fix(core): update 2021-01-28 01:31:42 +00:00
6c2057b119 1.2.4 2021-01-28 01:30:28 +00:00
08d7224016 fix(core): update 2021-01-28 01:30:27 +00:00
bfa3330eb6 1.2.3 2021-01-23 06:03:55 +00:00
644fa2a49d fix(core): update 2021-01-23 06:03:54 +00:00
c0dad3a977 1.2.2 2021-01-23 05:50:02 +00:00
a921033cc4 fix(core): update 2021-01-23 05:50:02 +00:00
21e4712b04 1.2.1 2021-01-23 04:12:56 +00:00
df43bc2974 fix(core): update 2021-01-23 04:12:55 +00:00
564988185d 1.2.0 2020-12-26 18:06:23 +00:00
8442f3570f feat(SmartsocketClient): socket client can now be stopped with .stop() addiditionally to .reconnect(), which will still try to re 2020-12-26 18:06:22 +00:00
196357c878 1.1.71 2020-12-26 17:43:20 +00:00
bc187b7e41 fix(core): update 2020-12-26 17:43:19 +00:00
0e54bf889f 1.1.70 2020-12-22 00:19:00 +00:00
4c211bc82e fix(test): use @pushrocks/isohash instead of @pushrocks/smarthash in tests 2020-12-22 00:18:59 +00:00
a1be281670 1.1.69 2020-12-16 02:20:28 +00:00
1a44d2027c fix(core): update 2020-12-16 02:20:28 +00:00
4bf5456a1d 1.1.68 2020-12-16 01:38:58 +00:00
57c748657a fix(core): update 2020-12-16 01:38:57 +00:00
11 changed files with 1421 additions and 1581 deletions

2781
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{ {
"name": "@pushrocks/smartsocket", "name": "@pushrocks/smartsocket",
"version": "1.1.67", "version": "1.2.6",
"description": "easy and secure websocket communication", "description": "easy and secure websocket communication",
"main": "dist_ts/index.js", "main": "dist_ts/index.js",
"typings": "dist_ts/index.d.ts", "typings": "dist_ts/index.d.ts",
@ -22,25 +22,26 @@
"@apiglobal/typedrequest-interfaces": "^1.0.15", "@apiglobal/typedrequest-interfaces": "^1.0.15",
"@pushrocks/isohash": "^1.0.2", "@pushrocks/isohash": "^1.0.2",
"@pushrocks/isounique": "^1.0.4", "@pushrocks/isounique": "^1.0.4",
"@pushrocks/lik": "^4.0.17", "@pushrocks/lik": "^4.0.20",
"@pushrocks/smartdelay": "^2.0.10", "@pushrocks/smartdelay": "^2.0.10",
"@pushrocks/smartenv": "^4.0.15", "@pushrocks/smartenv": "^4.0.16",
"@pushrocks/smartexpress": "^3.0.76", "@pushrocks/smartexpress": "^3.0.100",
"@pushrocks/smartjson": "^4.0.5",
"@pushrocks/smartlog": "^2.0.39", "@pushrocks/smartlog": "^2.0.39",
"@pushrocks/smartpromise": "^3.0.6", "@pushrocks/smartpromise": "^3.1.3",
"@pushrocks/smartrx": "^2.0.19", "@pushrocks/smartrx": "^2.0.19",
"@pushrocks/smarttime": "^3.0.35", "@pushrocks/smarttime": "^3.0.38",
"@types/socket.io": "^2.1.11", "@types/socket.io": "^2.1.13",
"@types/socket.io-client": "^1.4.33", "@types/socket.io-client": "^1.4.35",
"socket.io": "^2.3.0", "socket.io": "^3.1.0",
"socket.io-client": "^2.3.0" "socket.io-client": "^3.1.0"
}, },
"devDependencies": { "devDependencies": {
"@gitzone/tsbuild": "^2.1.25", "@gitzone/tsbuild": "^2.1.25",
"@gitzone/tsrun": "^1.2.12", "@gitzone/tsrun": "^1.2.12",
"@gitzone/tstest": "^1.0.48", "@gitzone/tstest": "^1.0.52",
"@pushrocks/tapbundle": "^3.2.9", "@pushrocks/tapbundle": "^3.2.10",
"@types/node": "^14.11.2", "@types/node": "^14.14.22",
"tslint": "^6.1.3", "tslint": "^6.1.3",
"tslint-config-prettier": "^1.18.0" "tslint-config-prettier": "^1.18.0"
}, },

View File

@ -110,7 +110,6 @@ mySmartsocketClient.serverCall('function', functionCallData).then((functionRespo
> `data` is always a js object that you can design for your specific needs. > `data` is always a js object that you can design for your specific needs.
> It supports buffers for large binary data network exchange. > It supports buffers for large binary data network exchange.
## Contribution ## Contribution
We are always happy for code contributions. If you are not the code contributing type that is ok. Still, maintaining Open Source repositories takes considerable time and thought. If you like the quality of what we do and our modules are useful to you we would appreciate a little monthly contribution: You can [contribute one time](https://lossless.link/contribute-onetime) or [contribute monthly](https://lossless.link/contribute). :) We are always happy for code contributions. If you are not the code contributing type that is ok. Still, maintaining Open Source repositories takes considerable time and thought. If you like the quality of what we do and our modules are useful to you we would appreciate a little monthly contribution: You can [contribute one time](https://lossless.link/contribute-onetime) or [contribute monthly](https://lossless.link/contribute). :)

View File

@ -1,11 +1,9 @@
// tslint:disable-next-line:no-implicit-dependencies // tslint:disable-next-line:no-implicit-dependencies
import { expect, tap } from '@pushrocks/tapbundle'; import { expect, tap } from '@pushrocks/tapbundle';
import * as smarthash from '@pushrocks/smarthash'; import * as isohash from '@pushrocks/isohash';
import * as smartpromise from '@pushrocks/smartpromise';
import * as smartexpress from '@pushrocks/smartexpress'; import * as smartexpress from '@pushrocks/smartexpress';
import socketIoClient = require('socket.io-client');
import smartsocket = require('../ts/index'); import smartsocket = require('../ts/index');
let testSmartsocket: smartsocket.Smartsocket; let testSmartsocket: smartsocket.Smartsocket;
@ -40,7 +38,7 @@ tap.test('Should accept an smartExpressServer as server', async () => {
tap.test('should add a socketrole', async () => { tap.test('should add a socketrole', async () => {
testSocketRole1 = new smartsocket.SocketRole({ testSocketRole1 = new smartsocket.SocketRole({
name: 'testRole1', name: 'testRole1',
passwordHash: smarthash.sha256FromStringSync('testPassword'), passwordHash: await isohash.sha256FromString('testPassword'),
}); });
testSmartsocket.addSocketRoles([testSocketRole1]); testSmartsocket.addSocketRoles([testSocketRole1]);
}); });
@ -87,10 +85,25 @@ tap.test('2 clients should connect in parallel', async () => {
}); });
tap.test('should be able to make a functionCall from client to server', async () => { tap.test('should be able to make a functionCall from client to server', async () => {
const response = await testSmartsocketClient.serverCall('testFunction1', { const totalCycles = 20000;
value1: 'hello', let counter = 0;
let startTime = Date.now();
while (counter < totalCycles) {
const randomString = `hello ${Math.random()}`;
const response: any = await testSmartsocketClient.serverCall('testFunction1', {
value1: randomString,
}); });
console.log(response); expect(response.value1).to.equal(randomString);
if (counter % 100 === 0) {
console.log(
`processed 100 more messages in ${Date.now() - startTime}ms. ${
totalCycles - counter
} messages to go.`
);
startTime = Date.now();
}
counter++;
}
}); });
tap.test('should be able to make a functionCall from server to client', async () => {}); tap.test('should be able to make a functionCall from server to client', async () => {});

View File

@ -1,11 +1,8 @@
// tslint:disable-next-line:no-implicit-dependencies // tslint:disable-next-line:no-implicit-dependencies
import { expect, tap } from '@pushrocks/tapbundle'; import { expect, tap } from '@pushrocks/tapbundle';
import * as smarthash from '@pushrocks/smarthash';
import * as smartpromise from '@pushrocks/smartpromise';
import socketIoClient = require('socket.io-client');
import smartsocket = require('../ts/index'); import smartsocket = require('../ts/index');
import * as isohash from '@pushrocks/isohash';
let testSmartsocket: smartsocket.Smartsocket; let testSmartsocket: smartsocket.Smartsocket;
let testSmartsocketClient: smartsocket.SmartsocketClient; let testSmartsocketClient: smartsocket.SmartsocketClient;
@ -48,7 +45,7 @@ tap.test('should create a new smartsocket', async () => {
tap.test('should add a socketrole', async () => { tap.test('should add a socketrole', async () => {
testSocketRole1 = new smartsocket.SocketRole({ testSocketRole1 = new smartsocket.SocketRole({
name: 'testRole1', name: 'testRole1',
passwordHash: smarthash.sha256FromStringSync('testPassword'), passwordHash: await isohash.sha256FromString('testPassword'),
}); });
testSmartsocket.addSocketRoles([testSocketRole1]); testSmartsocket.addSocketRoles([testSocketRole1]);
}); });
@ -93,6 +90,31 @@ tap.test('should react to a new websocket connection from client', async () => {
await testSmartsocketClient.connect(); await testSmartsocketClient.connect();
}); });
tap.test('should be able to tag a connection from client', async (tools) => {
await testSmartsocketClient.addTag({
id: 'awesome',
payload: 'yes',
});
const tagOnServerSide = await testSmartsocket.socketConnections
.find((socketConnection) => {
return true;
})
.getTagById('awesome');
expect(tagOnServerSide.payload).to.equal('yes');
});
tap.test('should be able to tag a connection from server', async (tools) => {
await testSmartsocket.socketConnections
.find((socketConnection) => {
return true;
}).addTag({
id: 'awesome2',
payload: 'absolutely',
});
const tagOnClientSide = await testSmartsocketClient.socketConnection.getTagById('awesome2');
expect(tagOnClientSide.payload).to.equal('absolutely');
});
tap.test('2 clients should connect in parallel', async () => { tap.test('2 clients should connect in parallel', async () => {
// TODO: implement parallel test // TODO: implement parallel test
}); });

View File

@ -1 +1,2 @@
export * from './connection'; export * from './connection';
export * from './tag';

6
ts/interfaces/tag.ts Normal file
View File

@ -0,0 +1,6 @@
export interface ITag<T = any> {
id: string;
payload: T;
}
export type TTagStore = { [key: string]: ITag };

View File

@ -45,6 +45,40 @@ export class SmartsocketClient {
public socketRequests = new plugins.lik.ObjectMap<SocketRequest<any>>(); public socketRequests = new plugins.lik.ObjectMap<SocketRequest<any>>();
public socketRoles = new plugins.lik.ObjectMap<SocketRole>(); public socketRoles = new plugins.lik.ObjectMap<SocketRole>();
// tagStore
private tagStore: { [key: string]: interfaces.ITag } = {};
private tagStoreSubscription: plugins.smartrx.rxjs.Subscription;
/**
* adds a tag to a connection
*/
public async addTag(tagArg: interfaces.ITag) {
if (this.socketConnection) {
await this.socketConnection.addTag(tagArg);
} else {
this.tagStore[tagArg.id] = tagArg;
}
}
/**
* gets a tag by id
* @param tagIdArg
*/
public async getTagById(tagIdArg: interfaces.ITag['id']) {
return this.tagStore[tagIdArg];
}
/**
* removes a tag from a connection
*/
public async removeTagById(tagIdArg: interfaces.ITag['id']) {
if (this.socketConnection) {
this.socketConnection.removeTagById(tagIdArg);
} else {
delete this.tagStore[tagIdArg];
}
}
constructor(optionsArg: ISmartsocketClientOptions) { constructor(optionsArg: ISmartsocketClientOptions) {
this.alias = optionsArg.alias; this.alias = optionsArg.alias;
this.serverUrl = optionsArg.url; this.serverUrl = optionsArg.url;
@ -85,6 +119,7 @@ export class SmartsocketClient {
socket: await socketIoClient.connect(socketUrl, { socket: await socketIoClient.connect(socketUrl, {
multiplex: false, multiplex: false,
reconnectionAttempts: 5, reconnectionAttempts: 5,
rejectUnauthorized: socketUrl.startsWith('https://localhost') ? false : true,
}), }),
}); });
@ -128,6 +163,16 @@ export class SmartsocketClient {
// handle connection // handle connection
this.socketConnection.socket.on('connect', async () => { this.socketConnection.socket.on('connect', async () => {
this.tagStoreSubscription?.unsubscribe();
for (const keyArg of Object.keys(this.tagStore)) {
this.socketConnection.addTag(this.tagStore[keyArg]);
}
this.tagStoreSubscription = this.socketConnection.tagStoreObservable.subscribe(
(tagStoreArg) => {
this.tagStore = tagStoreArg;
}
);
this.updateStatus('connected'); this.updateStatus('connected');
}); });
@ -163,6 +208,14 @@ export class SmartsocketClient {
} }
} }
/**
* stops the client completely
*/
public async stop() {
this.autoReconnect = false;
await this.disconnect();
}
/** /**
* try a reconnection * try a reconnection
*/ */

View File

@ -57,6 +57,10 @@ export class SocketConnection {
public eventSubject = new plugins.smartrx.rxjs.Subject<interfaces.TConnectionStatus>(); public eventSubject = new plugins.smartrx.rxjs.Subject<interfaces.TConnectionStatus>();
public eventStatus: interfaces.TConnectionStatus = 'new'; public eventStatus: interfaces.TConnectionStatus = 'new';
private tagStore: interfaces.TTagStore = {};
public tagStoreObservable = new plugins.smartrx.rxjs.Subject<interfaces.TTagStore>();
public remoteTagStoreObservable = new plugins.smartrx.rxjs.Subject<interfaces.TTagStore>();
constructor(optionsArg: ISocketConnectionConstructorOptions) { constructor(optionsArg: ISocketConnectionConstructorOptions) {
this.alias = optionsArg.alias; this.alias = optionsArg.alias;
this.authenticated = optionsArg.authenticated; this.authenticated = optionsArg.authenticated;
@ -82,6 +86,42 @@ export class SocketConnection {
}); });
} }
/**
* adds a tag to a connection
*/
public async addTag(tagArg: interfaces.ITag) {
const done = plugins.smartpromise.defer();
this.tagStore[tagArg.id] = tagArg;
this.tagStoreObservable.next(this.tagStore);
const remoteSubscription = this.remoteTagStoreObservable.subscribe((remoteTagStore) => {
const localTagString = plugins.smartjson.stringify(tagArg);
const remoteTagString = plugins.smartjson.stringify(remoteTagStore[tagArg.id]);
if (localTagString === remoteTagString) {
remoteSubscription.unsubscribe();
done.resolve();
}
});
this.socket.emit('updateTagStore', this.tagStore);
await done.promise;
}
/**
* gets a tag by id
* @param tagIdArg
*/
public async getTagById(tagIdArg: interfaces.ITag['id']) {
return this.tagStore[tagIdArg];
}
/**
* removes a tag from a connection
*/
public async removeTagById(tagIdArg: interfaces.ITag['id']) {
delete this.tagStore[tagIdArg];
this.tagStoreObservable.next(this.tagStore);
this.socket.emit('updateTagStore', this.tagStore);
}
// authenticating -------------------------- // authenticating --------------------------
/** /**
@ -91,7 +131,7 @@ export class SocketConnection {
const done = plugins.smartpromise.defer(); const done = plugins.smartpromise.defer();
this.socket.on('dataAuth', async (dataArg: ISocketConnectionAuthenticationObject) => { this.socket.on('dataAuth', async (dataArg: ISocketConnectionAuthenticationObject) => {
logger.log('info', 'received authentication data. now hashing and comparing...'); logger.log('info', 'received authentication data. now hashing and comparing...');
this.socket.removeListener('dataAuth', () => {}); this.socket.removeAllListeners('dataAuth');
if (await SocketRole.checkPasswordForRole(dataArg, this.smartsocketRef)) { if (await SocketRole.checkPasswordForRole(dataArg, this.smartsocketRef)) {
// TODO: authenticate password // TODO: authenticate password
this.alias = dataArg.alias; this.alias = dataArg.alias;
@ -143,13 +183,27 @@ export class SocketConnection {
} }
}); });
this.socket.on('functionResponse', (dataArg: ISocketRequestDataObject<any>) => { this.socket.on('functionResponse', (dataArg: ISocketRequestDataObject<any>) => {
logger.log('info', `received response for request with id ${dataArg.shortId}`); // logger.log('info', `received response for request with id ${dataArg.shortId}`);
const targetSocketRequest = SocketRequest.getSocketRequestById( const targetSocketRequest = SocketRequest.getSocketRequestById(
this.smartsocketRef, this.smartsocketRef,
dataArg.shortId dataArg.shortId
); );
targetSocketRequest.handleResponse(dataArg); targetSocketRequest.handleResponse(dataArg);
}); });
this.socket.on('updateTagStore', async (tagStoreArg: interfaces.TTagStore) => {
const exitingStoreString = plugins.smartjson.stringify(this.tagStore);
const newStoreString = plugins.smartjson.stringify(tagStoreArg);
console.log(exitingStoreString);
console.log(newStoreString);
if (exitingStoreString !== newStoreString) {
this.tagStore = tagStoreArg;
this.socket.emit('updateTagStore', this.tagStore);
this.tagStoreObservable.next(this.tagStore);
}
this.remoteTagStoreObservable.next(tagStoreArg);
});
logger.log('info', `now listening to function requests for ${this.alias}`); logger.log('info', `now listening to function requests for ${this.alias}`);
done.resolve(this); done.resolve(this);
} else { } else {

View File

@ -90,7 +90,7 @@ export class SocketRequest<T extends plugins.typedrequestInterfaces.ITypedReques
* handles the response that is received by the requesting side * handles the response that is received by the requesting side
*/ */
public async handleResponse(responseDataArg: ISocketRequestDataObject<T>) { public async handleResponse(responseDataArg: ISocketRequestDataObject<T>) {
logger.log('info', 'handling response!'); // logger.log('info', 'handling response!');
this.done.resolve(responseDataArg.funcCallData); this.done.resolve(responseDataArg.funcCallData);
this.smartsocketRef.socketRequests.remove(this); this.smartsocketRef.socketRequests.remove(this);
} }
@ -110,11 +110,11 @@ export class SocketRequest<T extends plugins.typedrequestInterfaces.ITypedReques
logger.log('error', `There is no SocketFunction defined for ${this.funcCallData.funcName}`); logger.log('error', `There is no SocketFunction defined for ${this.funcCallData.funcName}`);
return; return;
} }
logger.log('info', `invoking ${targetSocketFunction.name}`); // logger.log('info', `invoking ${targetSocketFunction.name}`);
targetSocketFunction targetSocketFunction
.invoke(this.funcCallData, this.originSocketConnection) .invoke(this.funcCallData, this.originSocketConnection)
.then((resultData) => { .then((resultData) => {
logger.log('info', 'got resultData. Sending it to requesting party.'); // logger.log('info', 'got resultData. Sending it to requesting party.');
const responseData: ISocketRequestDataObject<T> = { const responseData: ISocketRequestDataObject<T> = {
funcCallData: resultData, funcCallData: resultData,
shortId: this.shortid, shortId: this.shortid,

View File

@ -8,6 +8,7 @@ import * as isohash from '@pushrocks/isohash';
import * as isounique from '@pushrocks/isounique'; import * as isounique from '@pushrocks/isounique';
import * as lik from '@pushrocks/lik'; import * as lik from '@pushrocks/lik';
import * as smartenv from '@pushrocks/smartenv'; import * as smartenv from '@pushrocks/smartenv';
import * as smartjson from '@pushrocks/smartjson';
import * as smartlog from '@pushrocks/smartlog'; import * as smartlog from '@pushrocks/smartlog';
import * as smartdelay from '@pushrocks/smartdelay'; import * as smartdelay from '@pushrocks/smartdelay';
import * as smartpromise from '@pushrocks/smartpromise'; import * as smartpromise from '@pushrocks/smartpromise';
@ -19,6 +20,7 @@ export {
isounique, isounique,
lik, lik,
smartenv, smartenv,
smartjson,
smartlog, smartlog,
smartdelay, smartdelay,
smartpromise, smartpromise,