Compare commits

...

14 Commits

Author SHA1 Message Date
67f4e33ca0 1.0.55 2019-08-12 15:10:40 +02:00
8a8277ae9f fix(core): update 2019-08-12 15:10:40 +02:00
ff9cb9132c 1.0.54 2019-08-12 14:59:38 +02:00
f4ce784a59 fix(core): update 2019-08-12 14:59:37 +02:00
b34be4dcba 1.0.53 2019-07-30 10:31:36 +02:00
6cc69efe2d fix(core): update 2019-07-30 10:31:35 +02:00
8c30f294bc 1.0.52 2019-06-11 03:06:18 +02:00
228eb791b7 fix(core): update 2019-06-11 03:06:17 +02:00
057476ae66 1.0.51 2019-06-10 17:46:07 +02:00
cb80e4dc2e fix(core): update 2019-06-10 17:46:06 +02:00
8410e09a4d 1.0.50 2019-06-07 11:49:10 +02:00
eb04abddbf fix(core): update 2019-06-07 11:49:10 +02:00
57809d9b53 1.0.49 2019-06-06 23:23:37 +02:00
bee5231d47 fix(core): update 2019-06-06 23:23:37 +02:00
17 changed files with 763 additions and 512 deletions

20
.gitignore vendored
View File

@ -1,6 +1,22 @@
.nogit/ .nogit/
node_modules/
dist/ # artifacts
coverage/ coverage/
public/ public/
pages/ pages/
# installs
node_modules/
# caches
.yarn/
.cache/
.rpt2_cache
# builds
dist/
dist_web/
dist_serve/
dist_ts_web/
# custom

View File

@ -1,5 +1,5 @@
# gitzone standard # gitzone ci_default
image: hosttoday/ht-docker-node:npmci image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
cache: cache:
paths: paths:
@ -50,13 +50,13 @@ testLTS:
- docker - docker
- notpriv - notpriv
testSTABLE: testBuild:
stage: test stage: test
script: script:
- npmci npm prepare - npmci npm prepare
- npmci node install stable - npmci node install lts
- npmci npm install - npmci npm install
- npmci npm test - npmci command npm run build
coverage: /\d+.?\d+?\%\s*coverage/ coverage: /\d+.?\d+?\%\s*coverage/
tags: tags:
- docker - docker
@ -65,7 +65,7 @@ testSTABLE:
release: release:
stage: release stage: release
script: script:
- npmci node install stable - npmci node install lts
- npmci npm publish - npmci npm publish
only: only:
- tags - tags
@ -78,19 +78,11 @@ release:
# ==================== # ====================
codequality: codequality:
stage: metadata stage: metadata
image: docker:stable
allow_failure: true allow_failure: true
services:
- docker:stable-dind
script: script:
- export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/') - npmci command npm install -g tslint typescript
- docker run - npmci npm install
--env SOURCE_CODE="$PWD" - npmci command "tslint -c tslint.json ./ts/**/*.ts"
--volume "$PWD":/code
--volume /var/run/docker.sock:/var/run/docker.sock
"registry.gitlab.com/gitlab-org/security-products/codequality:$SP_VERSION" /code
artifacts:
paths: [codeclimate.json]
tags: tags:
- docker - docker
- priv - priv
@ -106,13 +98,15 @@ trigger:
- notpriv - notpriv
pages: pages:
image: hosttoday/ht-docker-node:npmci image: hosttoday/ht-docker-dbase:npmci
services:
- docker:18-dind
stage: metadata stage: metadata
script: script:
- npmci command npm install -g typedoc typescript - npmci command npm install -g @gitzone/tsdoc
- npmci npm prepare - npmci npm prepare
- npmci npm install - npmci npm install
- npmci command typedoc --module "commonjs" --target "ES2016" --out public/ ts/ - npmci command tsdoc
tags: tags:
- docker - docker
- notpriv - notpriv

29
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,29 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "current file",
"type": "node",
"request": "launch",
"args": [
"${relativeFile}"
],
"runtimeArgs": ["-r", "@gitzone/tsrun"],
"cwd": "${workspaceRoot}",
"protocol": "inspector",
"internalConsoleOptions": "openOnSessionStart"
},
{
"name": "test.ts",
"type": "node",
"request": "launch",
"args": [
"test/test.ts"
],
"runtimeArgs": ["-r", "@gitzone/tsrun"],
"cwd": "${workspaceRoot}",
"protocol": "inspector",
"internalConsoleOptions": "openOnSessionStart"
}
]
}

889
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{ {
"name": "@pushrocks/smartuniverse", "name": "@pushrocks/smartuniverse",
"version": "1.0.48", "version": "1.0.55",
"private": false, "private": false,
"description": "messaging service for your micro services", "description": "messaging service for your micro services",
"main": "dist/index.js", "main": "dist/index.js",
@ -14,11 +14,11 @@
"format": "(gitzone format)" "format": "(gitzone format)"
}, },
"devDependencies": { "devDependencies": {
"@gitzone/tsbuild": "^2.1.8", "@gitzone/tsbuild": "^2.1.11",
"@gitzone/tstest": "^1.0.20", "@gitzone/tstest": "^1.0.24",
"@pushrocks/tapbundle": "^3.0.9", "@pushrocks/tapbundle": "^3.0.11",
"@types/node": "^11.13.7", "@types/node": "^12.6.8",
"tslint": "^5.16.0", "tslint": "^5.18.0",
"tslint-config-prettier": "^1.18.0" "tslint-config-prettier": "^1.18.0"
}, },
"peerDependencies": { "peerDependencies": {
@ -27,14 +27,25 @@
"dependencies": { "dependencies": {
"@pushrocks/lik": "^3.0.5", "@pushrocks/lik": "^3.0.5",
"@pushrocks/smartdelay": "^2.0.3", "@pushrocks/smartdelay": "^2.0.3",
"@pushrocks/smartexpress": "^3.0.19", "@pushrocks/smartexpress": "^3.0.35",
"@pushrocks/smartfile": "^7.0.2", "@pushrocks/smartfile": "^7.0.4",
"@pushrocks/smarthash": "^2.0.4", "@pushrocks/smarthash": "^2.0.6",
"@pushrocks/smartpromise": "^3.0.2", "@pushrocks/smartpromise": "^3.0.2",
"@pushrocks/smartrequest": "^1.1.15", "@pushrocks/smartrequest": "^1.1.16",
"@pushrocks/smartrx": "^2.0.3", "@pushrocks/smartrx": "^2.0.3",
"@pushrocks/smartsocket": "^1.1.35", "@pushrocks/smartsocket": "^1.1.38",
"@pushrocks/smarttime": "^3.0.7", "@pushrocks/smarttime": "^3.0.12",
"@pushrocks/smartunique": "^3.0.1" "@pushrocks/smartunique": "^3.0.1"
} },
"files": [
"ts/*",
"ts_web/*",
"dist/*",
"dist_web/*",
"dist_ts_web/*",
"assets/*",
"cli.js",
"npmextra.json",
"readme.md"
]
} }

View File

@ -1,4 +1,8 @@
export type IServerCallActions = 'subscribe' | 'sendmessage' | 'unsubscribe'; export type IServerCallActions =
| 'channelSubscription'
| 'processMessage'
| 'channelUnsubscribe'
| 'terminateConnection';
/** /**
* the interface for a subscription * the interface for a subscription

View File

@ -0,0 +1,4 @@
export interface IAuthenticationRequest {
channelName: string;
password: string;
}

View File

@ -8,9 +8,7 @@ import * as url from 'url';
import * as interfaces from './interfaces'; import * as interfaces from './interfaces';
import { ClientUniverseChannel, UniverseMessage } from './'; import { ClientUniverseChannel, UniverseMessage } from './';
import { import { ClientUniverseCache } from './smartuniverse.classes.clientuniversecache';
ClientUniverseCache
} from './smartuniverse.classes.clientuniversecache';
export interface IClientOptions { export interface IClientOptions {
serverAddress: string; serverAddress: string;
@ -70,20 +68,19 @@ export class ClientUniverse {
}); });
} }
/** /**
* sends a message towards the server * sends a message towards the server
* @param messageArg * @param messageArg
*/ */
public async sendMessage(messageArg: interfaces.IMessageCreator) { public async sendMessage(messageArg: interfaces.IMessageCreator) {
await this.checkConnection(); await this.checkConnection();
const requestBody: interfaces.IUniverseMessage = { const universeMessageToSend: interfaces.IUniverseMessage = {
id: plugins.smartunique.shortId(), id: plugins.smartunique.shortId(),
timestamp: Date.now(), timestamp: Date.now(),
passphrase: (await this.getChannel(messageArg.targetChannelName)).passphrase, passphrase: (await this.getChannel(messageArg.targetChannelName)).passphrase,
...messageArg ...messageArg
}; };
// TODO: User websocket connection if available await this.smartsocketClient.serverCall('processMessage', universeMessageToSend);
} }
public close() { public close() {
@ -117,18 +114,20 @@ export class ClientUniverse {
funcName: 'unsubscribe', funcName: 'unsubscribe',
allowedRoles: [], allowedRoles: [],
funcDef: async (data: interfaces.IServerUnsubscribeActionPayload) => { funcDef: async (data: interfaces.IServerUnsubscribeActionPayload) => {
throw new Error('TODO');
}, }
}); });
/** /**
* should handle a message reception * should handle a message reception
*/ */
const receiveMessage = async () => { const processMessageSocketFunction = new plugins.smartsocket.SocketFunction({
funcName: 'processMessage',
}; allowedRoles: [],
funcDef: async (data: interfaces.IServerUnsubscribeActionPayload) => {
throw new Error('TODO');
}
});
await this.smartsocketClient.connect(); await this.smartsocketClient.connect();
} }

View File

@ -5,6 +5,4 @@ import * as plugins from './smartuniverse.plugins';
* keeps track of which messages have already been received * keeps track of which messages have already been received
* good for deduplication in mesh environments * good for deduplication in mesh environments
*/ */
export class ClientUniverseCache { export class ClientUniverseCache {}
}

View File

@ -50,7 +50,7 @@ export class ClientUniverseChannel implements interfaces.IUniverseChannel {
* tells the universe about this instances interest into a channel * tells the universe about this instances interest into a channel
*/ */
public async subscribe() { public async subscribe() {
const serverCallActionName: interfaces.IServerCallActions = 'subscribe'; const serverCallActionName: interfaces.IServerCallActions = 'channelSubscription';
const serverCallActionPayload: interfaces.IServerCallSubscribeActionPayload = { const serverCallActionPayload: interfaces.IServerCallSubscribeActionPayload = {
name: this.name, name: this.name,
passphrase: this.passphrase passphrase: this.passphrase

View File

@ -1,7 +1,6 @@
import * as plugins from './smartuniverse.plugins'; import * as plugins from './smartuniverse.plugins';
import * as interfaces from './interfaces'; import * as interfaces from './interfaces';
import { IUniverseMessage } from './interfaces';
export class ClientUniverseMessage implements interfaces.IUniverseMessage { export class ClientUniverseMessage implements interfaces.IUniverseMessage {
// ====== // ======
@ -24,11 +23,11 @@ export class ClientUniverseMessage implements interfaces.IUniverseMessage {
public payloadStringType; public payloadStringType;
public targetChannelName: string; public targetChannelName: string;
constructor(messageArg: IUniverseMessage, payloadArg) { constructor(messageArg: interfaces.IUniverseMessage, payloadArg) {
for (const key of Object.keys(messageArg)) { for (const key of Object.keys(messageArg)) {
this[key] = messageArg[key]; this[key] = messageArg[key];
} }
} }
getAsJsonForPayload() {}; getAsJsonForPayload() {}
} }

View File

@ -6,7 +6,6 @@ import { UniverseCache, UniverseChannel, UniverseMessage } from './';
import * as paths from './smartuniverse.paths'; import * as paths from './smartuniverse.paths';
import * as interfaces from './interfaces'; import * as interfaces from './interfaces';
import { UniverseConnectionManager } from './smartuniverse.classes.universeconnectionmanager';
import { UniverseConnection } from './smartuniverse.classes.universeconnection'; import { UniverseConnection } from './smartuniverse.classes.universeconnection';
export interface ISmartUniverseConstructorOptions { export interface ISmartUniverseConstructorOptions {
@ -14,12 +13,11 @@ export interface ISmartUniverseConstructorOptions {
} }
/** /**
* main class that setsup a Universe * main class that setups a Universe
*/ */
export class Universe { export class Universe {
// subinstances // subinstances
public universeCache: UniverseCache; public universeCache: UniverseCache;
public universeConnectionManager: UniverseConnectionManager;
// options // options
private options: ISmartUniverseConstructorOptions; private options: ISmartUniverseConstructorOptions;
@ -37,7 +35,6 @@ export class Universe {
constructor(optionsArg: ISmartUniverseConstructorOptions) { constructor(optionsArg: ISmartUniverseConstructorOptions) {
this.options = optionsArg; this.options = optionsArg;
this.universeCache = new UniverseCache(this.options.messageExpiryInMilliseconds); this.universeCache = new UniverseCache(this.options.messageExpiryInMilliseconds);
this.universeConnectionManager = new UniverseConnectionManager();
} }
/** /**
@ -93,12 +90,60 @@ export class Universe {
this.smartsocket.addSocketRoles([ClientRole]); this.smartsocket.addSocketRoles([ClientRole]);
const SubscriptionSocketFunction = new plugins.smartsocket.SocketFunction({ const SubscriptionSocketFunction = new plugins.smartsocket.SocketFunction({
allowedRoles: [ClientRole], allowedRoles: [ClientRole], // there is only one client role, Authentication happens on another level
funcName: 'channelSubscription', funcName: 'channelSubscription',
funcDef: (data) => { funcDef: async (
(() => { dataArg: interfaces.IServerCallSubscribeActionPayload,
// TODO: socketConnectionArg
this.universeConnectionManager.addConnection(); ) => {
// run in "this context" of this class
await (async () => {
// TODO: properly add the connection
const universeConnection = new UniverseConnection({
socketConnection: socketConnectionArg,
authenticationRequests: []
});
await UniverseConnection.addConnectionToCache(this.universeCache, universeConnection);
return {
'subscription status': 'success'
};
})();
}
});
const ProcessMessageSocketFunction = new plugins.smartsocket.SocketFunction({
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) {
console.log('found UniverseConnection for socket');
} else {
console.log('universe client not yet present');
console.log('creating one now as send only');
const universeConnectionInstance = new UniverseConnection({
socketConnection: socketConnectionArg,
authenticationRequests: []
});
await UniverseConnection.addConnectionToCache(
this.universeCache,
universeConnectionInstance
);
}
const unauthenticatedMessage = UniverseMessage.createMessageFromPayload(dataArg);
const foundChannel = await UniverseChannel.authorizeAMessageForAChannel(
this.universeCache,
unauthenticatedMessage
);
if (foundChannel) {
const authenticatedMessage = unauthenticatedMessage;
await this.universeCache.addMessage(authenticatedMessage);
}
})(); })();
} }
}); });
@ -109,7 +154,6 @@ export class Universe {
await this.smartexpressServer.start(); await this.smartexpressServer.start();
await this.smartsocket.start(); await this.smartsocket.start();
console.log('started universe'); console.log('started universe');
} }
/** /**

View File

@ -8,6 +8,7 @@ import { Objectmap } from '@pushrocks/lik';
import { Observable, from } from 'rxjs'; import { Observable, from } from 'rxjs';
import { filter } from 'rxjs/operators'; import { filter } from 'rxjs/operators';
import { rxjs } from '@pushrocks/smartrx'; import { rxjs } from '@pushrocks/smartrx';
import { UniverseConnection } from './smartuniverse.classes.universeconnection';
/** /**
* universe store handles the creation, storage and retrieval of messages. * universe store handles the creation, storage and retrieval of messages.
@ -29,6 +30,8 @@ export class UniverseCache {
*/ */
public channelMap = new Objectmap<UniverseChannel>(); public channelMap = new Objectmap<UniverseChannel>();
public connectionMap = new plugins.lik.Objectmap<UniverseConnection>();
/** /**
* allows messages to be processed in a blacklist mode for further analysis * allows messages to be processed in a blacklist mode for further analysis
*/ */
@ -52,7 +55,10 @@ export class UniverseCache {
/** /**
* Read a message from the UniverseCache * Read a message from the UniverseCache
*/ */
public readMessagesYoungerThan(unixTimeArg?: number, channelName?: string): Observable<UniverseMessage> { public readMessagesYoungerThan(
unixTimeArg?: number,
channelName?: string
): Observable<UniverseMessage> {
const messageObservable = from(this.messageMap.getArray()).pipe( const messageObservable = from(this.messageMap.getArray()).pipe(
filter(messageArg => { filter(messageArg => {
return messageArg.smartTimestamp.isYoungerThanMilliSeconds(this.destructionTime); return messageArg.smartTimestamp.isYoungerThanMilliSeconds(this.destructionTime);

View File

@ -1,6 +1,5 @@
import * as plugins from './smartuniverse.plugins'; import * as plugins from './smartuniverse.plugins';
import { Objectmap } from '@pushrocks/lik';
import { UniverseCache } from './smartuniverse.classes.universecache'; import { UniverseCache } from './smartuniverse.classes.universecache';
import { UniverseMessage } from './smartuniverse.classes.universemessage'; import { UniverseMessage } from './smartuniverse.classes.universemessage';
@ -41,10 +40,17 @@ export class UniverseChannel {
} }
} }
/**
* a static message authorization function that takes the UniverseCache
* (where messages and channels are stored and their lifetime is managed)
* and the universemessage to find a fitting channel for the message
* @param universeCacheArg
* @param universeMessageArg
*/
public static authorizeAMessageForAChannel( public static authorizeAMessageForAChannel(
universeCacheArg: UniverseCache, universeCacheArg: UniverseCache,
universeMessageArg: UniverseMessage universeMessageArg: UniverseMessage
) { ): UniverseChannel {
const foundChannel = universeCacheArg.channelMap.find(universeChannel => { const foundChannel = universeCacheArg.channelMap.find(universeChannel => {
const result = universeChannel.authenticate(universeMessageArg); const result = universeChannel.authenticate(universeMessageArg);
return result; return result;
@ -52,10 +58,13 @@ export class UniverseChannel {
if (foundChannel) { if (foundChannel) {
universeMessageArg.authenticated = true; universeMessageArg.authenticated = true;
universeMessageArg.universeChannelList.add(foundChannel); universeMessageArg.universeChannelList.add(foundChannel);
console.log('message authorized');
return foundChannel; return foundChannel;
} else { } else {
universeMessageArg.authenticated = false; universeMessageArg.authenticated = false;
universeMessageArg.universeChannelList.add(universeCacheArg.blackListChannel); universeMessageArg.universeChannelList.add(universeCacheArg.blackListChannel);
console.log('message not valid');
return null;
} }
} }
@ -79,7 +88,9 @@ export class UniverseChannel {
} }
/** /**
* authenticates a client on the server side * authenticates a client on the server side by matching
* # 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): boolean {
return ( return (
@ -88,7 +99,5 @@ export class UniverseChannel {
); );
} }
public pushToClients(messageArg: UniverseMessage) { public pushToClients(messageArg: UniverseMessage) {}
}
} }

View File

@ -1,20 +1,110 @@
import * as plugins from './smartuniverse.plugins'; import * as plugins from './smartuniverse.plugins';
import * as interfaces from './interfaces';
import { UniverseChannel } from './smartuniverse.classes.universechannel'; import { UniverseChannel } from './smartuniverse.classes.universechannel';
import { UniverseCache } from './smartuniverse.classes.universecache';
/** /**
* represents a connection to the universe * represents a connection to the universe
*/ */
export class UniverseConnection { export class UniverseConnection {
/**
*
* @param universeConnectionArg
*/
public static async addConnectionToCache(
universeCache: UniverseCache,
universeConnectionArg: UniverseConnection
) {
let universeConnection = universeConnectionArg;
universeConnection = await UniverseConnection.deduplicateUniverseConnection(
universeCache,
universeConnection
);
universeConnection = await UniverseConnection.authenticateAuthenticationRequests(
universeConnection
);
}
/**
* deduplicates UniverseConnections
*/
public static async deduplicateUniverseConnection(
universeCache: UniverseCache,
universeConnectionArg: UniverseConnection
): Promise<UniverseConnection> {
let connectionToReturn: UniverseConnection;
universeCache.connectionMap.forEach(async existingConnection => {
if (existingConnection.socketConnection === universeConnectionArg.socketConnection) {
connectionToReturn = await this.mergeUniverseConnections(
existingConnection,
universeConnectionArg
);
}
});
if (!connectionToReturn) {
connectionToReturn = universeConnectionArg;
}
return connectionToReturn;
}
/**
* authenticate AuthenticationRequests
*/
public static authenticateAuthenticationRequests(
universeConnectionArg
): Promise<UniverseConnection> {
// TODO: authenticate connections
return universeConnectionArg;
}
/**
* merges two UniverseConnections
*/
public static mergeUniverseConnections(
connectionArg1: UniverseConnection,
connectionArg2: UniverseConnection
) {
// TODO: merge connections
return connectionArg1;
}
/**
* finds a UniverseConnection by providing a socket connection
*/
public static findUniverseConnectionBySocketConnection(
universeCache: UniverseCache,
socketConnectionArg: plugins.smartsocket.SocketConnection
): UniverseConnection {
const universeConnection = universeCache.connectionMap.find(universeConnectionArg => {
return universeConnectionArg.socketConnection === socketConnectionArg;
});
return universeConnection;
}
public terminatedDeferred = plugins.smartpromise.defer();
/** /**
* the socketClient to ping * the socketClient to ping
*/ */
socketclient: plugins.smartsocket.SmartsocketClient; public socketConnection: plugins.smartsocket.SocketConnection;
subscribedChannels: UniverseChannel[] = []; public authenticationRequests = [];
authenticatedChannels: UniverseChannel[] = []; public subscribedChannels: UniverseChannel[] = [];
public authenticatedChannels: UniverseChannel[] = [];
public failedToJoinChannels: UniverseChannel[] = [];
constructor() { /**
* terminates the connection
*/
public terminateConnection() {
this.socketConnection.socket.disconnect();
this.terminatedDeferred.resolve();
}
constructor(optionsArg: {
socketConnection: plugins.smartsocket.SocketConnection;
authenticationRequests: interfaces.IServerCallSubscribeActionPayload[];
}) {
// TODO: check if this is correct
this.socketConnection = optionsArg.socketConnection;
} }
} }

View File

@ -1,11 +0,0 @@
import * as plugins from './smartuniverse.plugins';
import { UniverseConnection } from './smartuniverse.classes.universeconnection';
/**
* manages connections to a universe
*/
export class UniverseConnectionManager {
public connectionMap = new plugins.lik.Objectmap<UniverseConnection>();
public addConnection() {}
}

View File

@ -14,6 +14,10 @@ import { IUniverseMessage } from './interfaces';
* acts as a container to save message states like authentication status * acts as a container to save message states like authentication status
*/ */
export class UniverseMessage implements interfaces.IUniverseMessage { export class UniverseMessage implements interfaces.IUniverseMessage {
public static createMessageFromPayload(dataArg: interfaces.IUniverseMessage) {
return new UniverseMessage(dataArg);
}
public id: string; public id: string;
public timestamp: number; public timestamp: number;