Compare commits
164 Commits
Author | SHA1 | Date | |
---|---|---|---|
564988185d | |||
8442f3570f | |||
196357c878 | |||
bc187b7e41 | |||
0e54bf889f | |||
4c211bc82e | |||
a1be281670 | |||
1a44d2027c | |||
4bf5456a1d | |||
57c748657a | |||
15df24bf68 | |||
ca7470eedf | |||
38f017934c | |||
1980824540 | |||
09dec2071e | |||
a1443deafe | |||
9eac5ad336 | |||
cf607a79d5 | |||
8426c976bf | |||
1086065000 | |||
72196ec383 | |||
c6ad490a6f | |||
a40a83f0bf | |||
82fa029d05 | |||
0d76e7f577 | |||
57e6f058be | |||
b0bf9d7c95 | |||
1fbc76ef30 | |||
424d9cca91 | |||
d712270946 | |||
f98c797ad8 | |||
a23e7349be | |||
c390881a4e | |||
5e64f4ca25 | |||
765bc73197 | |||
105acaf97b | |||
5139136af4 | |||
bcc4ce9a87 | |||
20e7584eb9 | |||
59cbc343cc | |||
75aa1f6f0d | |||
3f073ab9b3 | |||
08c1618ea8 | |||
eb181fa2f6 | |||
c901ab75d3 | |||
075c59ed2c | |||
8d358dd93d | |||
e576d6058a | |||
6546da2394 | |||
29597daba1 | |||
c8b647d2fd | |||
1fa4aca049 | |||
2d4695de22 | |||
a3f4dcbc2a | |||
d6e81288b4 | |||
c441d89596 | |||
85b69e487a | |||
0d94ed9345 | |||
e188b18016 | |||
33c0fa3746 | |||
52be1415ee | |||
e75d5eabdb | |||
fb99848df1 | |||
1bd39d0755 | |||
d24c5f628c | |||
33fbabdd72 | |||
9d26fff986 | |||
41151e5436 | |||
109c5197f3 | |||
c3d47c1f50 | |||
1b45fb45e9 | |||
c22adc9b57 | |||
35e87306dd | |||
1b20aa5992 | |||
a63f14da47 | |||
86cf94c5dc | |||
0d39d6f237 | |||
1856ad5cfc | |||
b5dab810e8 | |||
f145b85b1c | |||
a8c647c5c7 | |||
22472e0adf | |||
333ddb4d9c | |||
126f020bf8 | |||
7677b1bb48 | |||
114379c5b3 | |||
79ae7d2039 | |||
d2cb6a3045 | |||
963619b2ed | |||
976abaaed7 | |||
ef322c32ac | |||
475911a968 | |||
5530e29da4 | |||
5f1d2c83c6 | |||
b84dd36885 | |||
c2d64ba39a | |||
85a5d7cdaf | |||
69380a2dbc | |||
fc292d83b9 | |||
b29961df95 | |||
f774a82ad5 | |||
5a45f4750b | |||
fc6227ef96 | |||
873aba3e0b | |||
f9bed9da8a | |||
d296064bfa | |||
1b0922759a | |||
aef4f9c591 | |||
abf546eec3 | |||
483cb38175 | |||
b2bd66a6a6 | |||
cfc3e8788d | |||
23c14c032c | |||
c92dae809f | |||
7200464e4b | |||
eaa97f0598 | |||
cde8270313 | |||
1b073ac8f6 | |||
3f3857df1e | |||
02e17a52c3 | |||
287c2a73c5 | |||
dea3746bb0 | |||
fc2a55bb0d | |||
99eca912d3 | |||
0b6929af8f | |||
0aa073f2a7 | |||
7170e58457 | |||
cccee35f2c | |||
118ec84ec5 | |||
dd31eea263 | |||
477429143d | |||
ea6fa14133 | |||
02065e36a6 | |||
f34358db81 | |||
fddf54b2b1 | |||
e1dbdc1a15 | |||
f3031a1d4e | |||
47ca497d48 | |||
c7e3c4537b | |||
62b36ab859 | |||
4563aade16 | |||
47596bfa59 | |||
6543d60019 | |||
f0aba45cec | |||
f327fa2784 | |||
983b4672fd | |||
c81a41b365 | |||
abe4d22226 | |||
87cc238345 | |||
475cd12904 | |||
84f33fa447 | |||
180ae23c9a | |||
7f0fff0bf4 | |||
24310b6709 | |||
bd8697ac6e | |||
7b2b2bd151 | |||
8dfc39be75 | |||
ab2196fd5f | |||
3afede95fc | |||
da510eb87a | |||
cb3d7f4d7b | |||
19a883c641 | |||
1f8e1fc7cb | |||
5109964247 |
21
.gitignore
vendored
21
.gitignore
vendored
@ -1,3 +1,20 @@
|
||||
node_modules/
|
||||
.nogit/
|
||||
|
||||
# artifacts
|
||||
coverage/
|
||||
docs/
|
||||
public/
|
||||
pages/
|
||||
|
||||
# installs
|
||||
node_modules/
|
||||
|
||||
# caches
|
||||
.yarn/
|
||||
.cache/
|
||||
.rpt2_cache
|
||||
|
||||
# builds
|
||||
dist/
|
||||
dist_*/
|
||||
|
||||
# custom
|
129
.gitlab-ci.yml
129
.gitlab-ci.yml
@ -1,36 +1,137 @@
|
||||
image: hosttoday/ht-docker-node:npmts
|
||||
# gitzone ci_default
|
||||
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||
|
||||
cache:
|
||||
paths:
|
||||
- .npmci_cache/
|
||||
key: '$CI_BUILD_STAGE'
|
||||
|
||||
stages:
|
||||
- test
|
||||
- release
|
||||
- security
|
||||
- test
|
||||
- release
|
||||
- metadata
|
||||
|
||||
testLEGACY:
|
||||
stage: test
|
||||
# ====================
|
||||
# security stage
|
||||
# ====================
|
||||
mirror:
|
||||
stage: security
|
||||
script:
|
||||
- npmci test legacy
|
||||
- npmci git mirror
|
||||
only:
|
||||
- tags
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- notpriv
|
||||
|
||||
auditProductionDependencies:
|
||||
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||
stage: security
|
||||
script:
|
||||
- npmci npm prepare
|
||||
- npmci command npm install --production --ignore-scripts
|
||||
- npmci command npm config set registry https://registry.npmjs.org
|
||||
- npmci command npm audit --audit-level=high --only=prod --production
|
||||
tags:
|
||||
- docker
|
||||
|
||||
testLTS:
|
||||
stage: test
|
||||
auditDevDependencies:
|
||||
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||
stage: security
|
||||
script:
|
||||
- npmci test lts
|
||||
- npmci npm prepare
|
||||
- npmci command npm install --ignore-scripts
|
||||
- npmci command npm config set registry https://registry.npmjs.org
|
||||
- npmci command npm audit --audit-level=high --only=dev
|
||||
tags:
|
||||
- docker
|
||||
|
||||
testSTABLE:
|
||||
allow_failure: true
|
||||
|
||||
# ====================
|
||||
# test stage
|
||||
# ====================
|
||||
|
||||
testStable:
|
||||
stage: test
|
||||
script:
|
||||
- npmci test stable
|
||||
- npmci npm prepare
|
||||
- npmci node install stable
|
||||
- npmci npm install
|
||||
- npmci npm test
|
||||
coverage: /\d+.?\d+?\%\s*coverage/
|
||||
tags:
|
||||
- docker
|
||||
|
||||
testBuild:
|
||||
stage: test
|
||||
script:
|
||||
- npmci npm prepare
|
||||
- npmci node install stable
|
||||
- npmci npm install
|
||||
- npmci command npm run build
|
||||
coverage: /\d+.?\d+?\%\s*coverage/
|
||||
tags:
|
||||
- docker
|
||||
|
||||
release:
|
||||
stage: release
|
||||
environment: npmjs-com_registry
|
||||
script:
|
||||
- npmci publish
|
||||
- npmci node install stable
|
||||
- npmci npm publish
|
||||
only:
|
||||
- tags
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- notpriv
|
||||
|
||||
# ====================
|
||||
# metadata stage
|
||||
# ====================
|
||||
codequality:
|
||||
stage: metadata
|
||||
allow_failure: true
|
||||
only:
|
||||
- tags
|
||||
script:
|
||||
- npmci command npm install -g tslint typescript
|
||||
- npmci npm prepare
|
||||
- npmci npm install
|
||||
- npmci command "tslint -c tslint.json ./ts/**/*.ts"
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- priv
|
||||
|
||||
trigger:
|
||||
stage: metadata
|
||||
script:
|
||||
- npmci trigger
|
||||
only:
|
||||
- tags
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- notpriv
|
||||
|
||||
pages:
|
||||
stage: metadata
|
||||
script:
|
||||
- npmci node install lts
|
||||
- npmci command npm install -g @gitzone/tsdoc
|
||||
- npmci npm prepare
|
||||
- npmci npm install
|
||||
- npmci command tsdoc
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- notpriv
|
||||
only:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
paths:
|
||||
- public
|
||||
allow_failure: true
|
||||
|
13
.snyk
Normal file
13
.snyk
Normal file
@ -0,0 +1,13 @@
|
||||
# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.
|
||||
version: v1.13.5
|
||||
# ignores vulnerabilities until expiry date; change duration by modifying expiry date
|
||||
ignore:
|
||||
SNYK-JS-JSYAML-173999:
|
||||
- '@pushrocks/smartexpress > @pushrocks/smartfile > js-yaml':
|
||||
reason: None given
|
||||
expires: '2019-05-24T15:16:11.291Z'
|
||||
SNYK-JS-JSYAML-174129:
|
||||
- '@pushrocks/smartexpress > @pushrocks/smartfile > js-yaml':
|
||||
reason: None given
|
||||
expires: '2019-05-24T15:16:11.291Z'
|
||||
patch: {}
|
29
.vscode/launch.json
vendored
Normal file
29
.vscode/launch.json
vendored
Normal 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"
|
||||
}
|
||||
]
|
||||
}
|
26
.vscode/settings.json
vendored
Normal file
26
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"json.schemas": [
|
||||
{
|
||||
"fileMatch": ["/npmextra.json"],
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"npmci": {
|
||||
"type": "object",
|
||||
"description": "settings for npmci"
|
||||
},
|
||||
"gitzone": {
|
||||
"type": "object",
|
||||
"description": "settings for gitzone",
|
||||
"properties": {
|
||||
"projectType": {
|
||||
"type": "string",
|
||||
"enum": ["website", "element", "service", "npm", "wcc"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
67
README.md
67
README.md
@ -1,67 +0,0 @@
|
||||
# smartsocket
|
||||
easy and secure websocket communication, Typescript ready
|
||||
|
||||
## Status
|
||||
[](https://gitlab.com/pushrocks/smartsocket/commits/master)
|
||||
|
||||
## Usage
|
||||
We recommend the use of typescript.
|
||||
Under the hood we use socket.io and shortid for managed data exchange.
|
||||
|
||||
### Serverside
|
||||
```typescript
|
||||
import * as smartsocket from "smartsocket";
|
||||
|
||||
let mySmartsocket = new smartsocket.Smartsocket({
|
||||
port: 3000 // the port smartsocket will listen on
|
||||
});
|
||||
|
||||
let mySocketRole = new smartsocket.SocketRole({
|
||||
name: "someRoleName",
|
||||
passwordHash: "someHashedString"
|
||||
});
|
||||
|
||||
let mySocketFunction = new smartsocket.SocketFunction({
|
||||
name:"newService",
|
||||
func:(data) => {
|
||||
|
||||
}, the function to execute
|
||||
roles:[mySocketRole] // all roles that have access to a specific function
|
||||
});
|
||||
|
||||
mySmartsocket.registerRole(mySocketRole);
|
||||
mySmartsocket.clientCall.select("client1","restart",data)
|
||||
.then((responseData) => {
|
||||
|
||||
});
|
||||
```
|
||||
|
||||
#### Client side
|
||||
```typescript
|
||||
import * as smartsocket from "smartsocket";
|
||||
|
||||
let mySmartsocketClient = new smartsocket.SmartsocketClient({
|
||||
url: "somedomain.com", // url, note: will only work over https, no http supported.
|
||||
port: 3000
|
||||
role:"dockerhost", // some role, in this example a dockerhost vm,
|
||||
password:"somePassword",
|
||||
alias:"client1"
|
||||
});
|
||||
|
||||
let mySocketFunction2 = new smartsocket.SocketFunction({
|
||||
name:"restart",
|
||||
func:(data) => {}, the function to execute
|
||||
});
|
||||
|
||||
mySmartsocketClient.registerFunction(mySocketFunction2);
|
||||
|
||||
mySmartsocketClient.serverCall("newService",data)
|
||||
.then((responseData) => {
|
||||
|
||||
});;
|
||||
```
|
||||
|
||||
> **NOTE:**
|
||||
you can easily chain dependent requests on eiter the server or client side with promises.
|
||||
`data` is always a js object that you can design for your specific needs.
|
||||
It supports buffers for large binary data network exchange.
|
2
dist/index.d.ts
vendored
2
dist/index.d.ts
vendored
@ -1,2 +0,0 @@
|
||||
export * from "./smartsocket.classes.smartsocket";
|
||||
export * from "./smartsocket.classes.smartsocketclient";
|
7
dist/index.js
vendored
7
dist/index.js
vendored
@ -1,7 +0,0 @@
|
||||
"use strict";
|
||||
function __export(m) {
|
||||
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
|
||||
}
|
||||
__export(require("./smartsocket.classes.smartsocket"));
|
||||
__export(require("./smartsocket.classes.smartsocketclient"));
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBRUEsaUJBQWMsbUNBQW1DLENBQUMsRUFBQTtBQUNsRCxpQkFBYyx5Q0FBeUMsQ0FBQyxFQUFBIn0=
|
21
dist/smartsocket.classes.smartsocket.d.ts
vendored
21
dist/smartsocket.classes.smartsocket.d.ts
vendored
@ -1,21 +0,0 @@
|
||||
/// <reference types="socket.io" />
|
||||
import { Objectmap } from "lik";
|
||||
import { SocketConnection } from "./smartsocket.classes.socketconnection";
|
||||
export interface ISmartsocketConstructorOptions {
|
||||
port: number;
|
||||
}
|
||||
export declare class Smartsocket {
|
||||
options: ISmartsocketConstructorOptions;
|
||||
io: SocketIO.Server;
|
||||
openSockets: Objectmap<SocketConnection>;
|
||||
constructor(optionsArg: ISmartsocketConstructorOptions);
|
||||
/**
|
||||
* the standard handler for new socket connections
|
||||
*/
|
||||
private _handleSocket(socketArg);
|
||||
/**
|
||||
* starts listening to incling sockets:
|
||||
*/
|
||||
startServer: () => void;
|
||||
closeServer: () => void;
|
||||
}
|
46
dist/smartsocket.classes.smartsocket.js
vendored
46
dist/smartsocket.classes.smartsocket.js
vendored
@ -1,46 +0,0 @@
|
||||
"use strict";
|
||||
const plugins = require("./smartsocket.plugins");
|
||||
// classes
|
||||
const lik_1 = require("lik");
|
||||
const smartsocket_classes_socketconnection_1 = require("./smartsocket.classes.socketconnection");
|
||||
;
|
||||
class Smartsocket {
|
||||
constructor(optionsArg) {
|
||||
this.openSockets = new lik_1.Objectmap();
|
||||
/**
|
||||
* starts listening to incling sockets:
|
||||
*/
|
||||
this.startServer = () => {
|
||||
this.io = plugins.socketIo(this.options.port);
|
||||
this.io.on('connection', (socketArg) => {
|
||||
this._handleSocket(socketArg);
|
||||
});
|
||||
};
|
||||
this.closeServer = () => {
|
||||
this.openSockets.forEach((socketObjectArg) => {
|
||||
plugins.beautylog.log(`disconnect socket with >>alias ${socketObjectArg.alias}`);
|
||||
socketObjectArg.socket.disconnect();
|
||||
});
|
||||
this.openSockets.wipe();
|
||||
this.io.close();
|
||||
};
|
||||
this.options = optionsArg;
|
||||
}
|
||||
;
|
||||
/**
|
||||
* the standard handler for new socket connections
|
||||
*/
|
||||
_handleSocket(socketArg) {
|
||||
let socketConnection = new smartsocket_classes_socketconnection_1.SocketConnection({
|
||||
authenticated: false,
|
||||
socket: socketArg
|
||||
});
|
||||
plugins.beautylog.log("Socket connected. Trying to authenticate...");
|
||||
this.openSockets.add(socketConnection);
|
||||
socketConnection.authenticate()
|
||||
.then(socketConnection.listenToFunctionRequests);
|
||||
}
|
||||
;
|
||||
}
|
||||
exports.Smartsocket = Smartsocket;
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRzb2NrZXQuY2xhc3Nlcy5zbWFydHNvY2tldC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3NtYXJ0c29ja2V0LmNsYXNzZXMuc21hcnRzb2NrZXQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLE1BQVksT0FBTyxXQUFNLHVCQUF1QixDQUFDLENBQUE7QUFHakQsVUFBVTtBQUNWLHNCQUEwQixLQUFLLENBQUMsQ0FBQTtBQUdoQyx1REFBaUMsd0NBQXdDLENBQUMsQ0FBQTtBQUt6RSxDQUFDO0FBRUY7SUFJSSxZQUFZLFVBQTBDO1FBRHRELGdCQUFXLEdBQUcsSUFBSSxlQUFTLEVBQW9CLENBQUM7UUFtQmhEOztXQUVHO1FBRUgsZ0JBQVcsR0FBRztZQUNWLElBQUksQ0FBQyxFQUFFLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQzlDLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLFlBQVksRUFBRSxDQUFDLFNBQVM7Z0JBQy9CLElBQUksQ0FBQyxhQUFhLENBQUMsU0FBUyxDQUFDLENBQUM7WUFDbEMsQ0FBQyxDQUFDLENBQUM7UUFDUCxDQUFDLENBQUE7UUFDRCxnQkFBVyxHQUFHO1lBQ1YsSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsQ0FBQyxlQUFpQztnQkFDdkQsT0FBTyxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsa0NBQWtDLGVBQWUsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDO2dCQUNqRixlQUFlLENBQUMsTUFBTSxDQUFDLFVBQVUsRUFBRSxDQUFDO1lBQ3hDLENBQUMsQ0FBQyxDQUFDO1lBQ0gsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUN4QixJQUFJLENBQUMsRUFBRSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ3BCLENBQUMsQ0FBQTtRQWxDRyxJQUFJLENBQUMsT0FBTyxHQUFHLFVBQVUsQ0FBQztJQUM5QixDQUFDOztJQUVEOztPQUVHO0lBQ0ssYUFBYSxDQUFDLFNBQVM7UUFDM0IsSUFBSSxnQkFBZ0IsR0FBc0IsSUFBSSx1REFBZ0IsQ0FBQztZQUMzRCxhQUFhLEVBQUMsS0FBSztZQUNuQixNQUFNLEVBQUMsU0FBUztTQUNuQixDQUFDLENBQUM7UUFDSCxPQUFPLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyw2Q0FBNkMsQ0FBQyxDQUFBO1FBQ3BFLElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLGdCQUFnQixDQUFDLENBQUM7UUFDdkMsZ0JBQWdCLENBQUMsWUFBWSxFQUFFO2FBQzFCLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyx3QkFBd0IsQ0FBQyxDQUFDO0lBQ3pELENBQUM7O0FBb0JMLENBQUM7QUF4Q1ksbUJBQVcsY0F3Q3ZCLENBQUEifQ==
|
14
dist/smartsocket.classes.smartsocketclient.d.ts
vendored
14
dist/smartsocket.classes.smartsocketclient.d.ts
vendored
@ -1,14 +0,0 @@
|
||||
/// <reference types="q" />
|
||||
import * as plugins from "./smartsocket.plugins";
|
||||
import { ISocketFunctionRequestObject, ISocketFunctionResponseObject } from "./smartsocket.classes.socketfunction";
|
||||
/**
|
||||
* interface for class SmartsocketClient
|
||||
*/
|
||||
export interface ISmartsocketClientOptions {
|
||||
port: number;
|
||||
url: string;
|
||||
}
|
||||
export declare class SmartsocketClient {
|
||||
constructor();
|
||||
dispatchFunctionRequest(dataArg: ISocketFunctionRequestObject): plugins.q.Promise<ISocketFunctionResponseObject>;
|
||||
}
|
15
dist/smartsocket.classes.smartsocketclient.js
vendored
15
dist/smartsocket.classes.smartsocketclient.js
vendored
@ -1,15 +0,0 @@
|
||||
"use strict";
|
||||
const plugins = require("./smartsocket.plugins");
|
||||
class SmartsocketClient {
|
||||
constructor() {
|
||||
}
|
||||
dispatchFunctionRequest(dataArg) {
|
||||
let done = plugins.q.defer();
|
||||
let responseData;
|
||||
done.resolve(responseData);
|
||||
return done.promise;
|
||||
}
|
||||
;
|
||||
}
|
||||
exports.SmartsocketClient = SmartsocketClient;
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRzb2NrZXQuY2xhc3Nlcy5zbWFydHNvY2tldGNsaWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3NtYXJ0c29ja2V0LmNsYXNzZXMuc21hcnRzb2NrZXRjbGllbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLE1BQVksT0FBTyxXQUFNLHVCQUl6QixDQUFDLENBSitDO0FBaUJoRDtJQUNJO0lBRUEsQ0FBQztJQUNELHVCQUF1QixDQUFDLE9BQW9DO1FBQ3hELElBQUksSUFBSSxHQUFHLE9BQU8sQ0FBQyxDQUFDLENBQUMsS0FBSyxFQUFpQyxDQUFDO1FBQzVELElBQUksWUFBMEMsQ0FBQztRQUMvQyxJQUFJLENBQUMsT0FBTyxDQUFDLFlBQVksQ0FBQyxDQUFDO1FBQzNCLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDO0lBQ3hCLENBQUM7O0FBQ0wsQ0FBQztBQVZZLHlCQUFpQixvQkFVN0IsQ0FBQSJ9
|
39
dist/smartsocket.classes.socketconnection.d.ts
vendored
39
dist/smartsocket.classes.socketconnection.d.ts
vendored
@ -1,39 +0,0 @@
|
||||
/// <reference types="socket.io" />
|
||||
/// <reference types="q" />
|
||||
import * as plugins from "./smartsocket.plugins";
|
||||
import { SocketRole } from "./smartsocket.classes.socketrole";
|
||||
/**
|
||||
* interface for constructor of class SocketConnection
|
||||
*/
|
||||
export interface ISocketConnectionOptions {
|
||||
alias?: string;
|
||||
authenticated: boolean;
|
||||
role?: SocketRole;
|
||||
socket: SocketIO.Socket;
|
||||
}
|
||||
/**
|
||||
* interface for authentication data
|
||||
*/
|
||||
export interface ISocketConnectionAuthenticationObject {
|
||||
role: "coreflowContainer";
|
||||
password: "somePassword";
|
||||
alias: "coreflow1";
|
||||
}
|
||||
/**
|
||||
* class SocketConnection represents a websocket connection
|
||||
*/
|
||||
export declare class SocketConnection {
|
||||
alias?: string;
|
||||
authenticated: boolean;
|
||||
role?: SocketRole;
|
||||
socket: SocketIO.Socket;
|
||||
constructor(optionsArg: ISocketConnectionOptions);
|
||||
/**
|
||||
* authenticate the socket
|
||||
*/
|
||||
authenticate(): plugins.q.Promise<{}>;
|
||||
/**
|
||||
* listen to function requests
|
||||
*/
|
||||
listenToFunctionRequests(): plugins.q.Promise<{}>;
|
||||
}
|
70
dist/smartsocket.classes.socketconnection.js
vendored
70
dist/smartsocket.classes.socketconnection.js
vendored
@ -1,70 +0,0 @@
|
||||
"use strict";
|
||||
const plugins = require("./smartsocket.plugins");
|
||||
const helpers = require("./smartsocket.helpers");
|
||||
;
|
||||
// export classes
|
||||
/**
|
||||
* class SocketConnection represents a websocket connection
|
||||
*/
|
||||
class SocketConnection {
|
||||
constructor(optionsArg) {
|
||||
this.alias = optionsArg.alias;
|
||||
this.authenticated = optionsArg.authenticated;
|
||||
this.role = optionsArg.role;
|
||||
this.socket = optionsArg.socket;
|
||||
}
|
||||
/**
|
||||
* authenticate the socket
|
||||
*/
|
||||
authenticate() {
|
||||
let done = plugins.q.defer();
|
||||
this.socket.on("dataAuth", dataArg => {
|
||||
plugins.beautylog.log("received authentication data. now hashing and comparing...");
|
||||
this.socket.removeListener("dataAuth", () => { });
|
||||
if ((true)) {
|
||||
this.alias = dataArg.alias;
|
||||
this.authenticated = true;
|
||||
this.role = helpers.findSocketRoleByString(dataArg.role);
|
||||
this.socket.emit("authenticated");
|
||||
plugins.beautylog.ok(`socket with >>alias ${this.alias} >>role ${this.role} is authenticated!`);
|
||||
done.resolve(this);
|
||||
}
|
||||
else {
|
||||
this.socket.disconnect();
|
||||
done.reject("not authenticated");
|
||||
}
|
||||
;
|
||||
});
|
||||
this.socket.emit("requestAuth");
|
||||
return done.promise;
|
||||
}
|
||||
;
|
||||
/**
|
||||
* listen to function requests
|
||||
*/
|
||||
listenToFunctionRequests() {
|
||||
let done = plugins.q.defer();
|
||||
if (this.authenticated) {
|
||||
this.socket.on("function", (dataArg) => {
|
||||
let referencedFunction = this.role.allowedFunctions.find((socketFunctionArg) => {
|
||||
return socketFunctionArg.name === dataArg.functionName;
|
||||
});
|
||||
if (referencedFunction !== undefined) {
|
||||
referencedFunction.invoke(dataArg);
|
||||
}
|
||||
else {
|
||||
plugins.beautylog.warn("function not existent or out of access scope");
|
||||
}
|
||||
;
|
||||
});
|
||||
}
|
||||
else {
|
||||
done.reject("socket needs to be authenticated first");
|
||||
}
|
||||
;
|
||||
return done.promise;
|
||||
}
|
||||
}
|
||||
exports.SocketConnection = SocketConnection;
|
||||
;
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRzb2NrZXQuY2xhc3Nlcy5zb2NrZXRjb25uZWN0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvc21hcnRzb2NrZXQuY2xhc3Nlcy5zb2NrZXRjb25uZWN0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxNQUFZLE9BQU8sV0FBTSx1QkFBdUIsQ0FBQyxDQUFBO0FBQ2pELE1BQVksT0FBTyxXQUFNLHVCQUF1QixDQUFDLENBQUE7QUFpQmhELENBQUM7QUFXRixpQkFBaUI7QUFFakI7O0dBRUc7QUFDSDtJQUtJLFlBQVksVUFBb0M7UUFDNUMsSUFBSSxDQUFDLEtBQUssR0FBRyxVQUFVLENBQUMsS0FBSyxDQUFDO1FBQzlCLElBQUksQ0FBQyxhQUFhLEdBQUcsVUFBVSxDQUFDLGFBQWEsQ0FBQztRQUM5QyxJQUFJLENBQUMsSUFBSSxHQUFHLFVBQVUsQ0FBQyxJQUFJLENBQUM7UUFDNUIsSUFBSSxDQUFDLE1BQU0sR0FBRyxVQUFVLENBQUMsTUFBTSxDQUFDO0lBQ3BDLENBQUM7SUFDRDs7T0FFRztJQUNILFlBQVk7UUFDUixJQUFJLElBQUksR0FBRyxPQUFPLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQzdCLElBQUksQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLFVBQVUsRUFBRSxPQUFPO1lBQzlCLE9BQU8sQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLDREQUE0RCxDQUFDLENBQUM7WUFDcEYsSUFBSSxDQUFDLE1BQU0sQ0FBQyxjQUFjLENBQUMsVUFBVSxFQUFFLFFBQVEsQ0FBQyxDQUFDLENBQUM7WUFDbEQsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7Z0JBQ1QsSUFBSSxDQUFDLEtBQUssR0FBRyxPQUFPLENBQUMsS0FBSyxDQUFBO2dCQUMxQixJQUFJLENBQUMsYUFBYSxHQUFHLElBQUksQ0FBQztnQkFDMUIsSUFBSSxDQUFDLElBQUksR0FBRyxPQUFPLENBQUMsc0JBQXNCLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUN6RCxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQztnQkFDbEMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsdUJBQXVCLElBQUksQ0FBQyxLQUFLLFdBQVcsSUFBSSxDQUFDLElBQUksb0JBQW9CLENBQUMsQ0FBQztnQkFDaEcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUN2QixDQUFDO1lBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQ0osSUFBSSxDQUFDLE1BQU0sQ0FBQyxVQUFVLEVBQUUsQ0FBQztnQkFDekIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO1lBQ3JDLENBQUM7WUFBQSxDQUFDO1FBQ04sQ0FBQyxDQUFDLENBQUM7UUFDSCxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUNoQyxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQztJQUN4QixDQUFDOztJQUVEOztPQUVHO0lBQ0gsd0JBQXdCO1FBQ3BCLElBQUksSUFBSSxHQUFHLE9BQU8sQ0FBQyxDQUFDLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDN0IsRUFBRSxDQUFBLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFBLENBQUM7WUFDbkIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsVUFBVSxFQUFFLENBQUMsT0FBb0M7Z0JBQzVELElBQUksa0JBQWtCLEdBQWtCLElBQUksQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLENBQUMsaUJBQWlCO29CQUN0RixNQUFNLENBQUMsaUJBQWlCLENBQUMsSUFBSSxLQUFLLE9BQU8sQ0FBQyxZQUFZLENBQUE7Z0JBQzFELENBQUMsQ0FBQyxDQUFDO2dCQUNILEVBQUUsQ0FBQSxDQUFDLGtCQUFrQixLQUFLLFNBQVMsQ0FBQyxDQUFBLENBQUM7b0JBQ2pDLGtCQUFrQixDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQztnQkFDdkMsQ0FBQztnQkFBQyxJQUFJLENBQUMsQ0FBQztvQkFDSixPQUFPLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyw4Q0FBOEMsQ0FBQyxDQUFDO2dCQUMzRSxDQUFDO2dCQUFBLENBQUM7WUFDTixDQUFDLENBQUMsQ0FBQTtRQUNOLENBQUM7UUFBQyxJQUFJLENBQUMsQ0FBQztZQUNKLElBQUksQ0FBQyxNQUFNLENBQUMsd0NBQXdDLENBQUMsQ0FBQztRQUMxRCxDQUFDO1FBQUEsQ0FBQztRQUNGLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDO0lBQ3hCLENBQUM7QUFDTCxDQUFDO0FBeERZLHdCQUFnQixtQkF3RDVCLENBQUE7QUFBQSxDQUFDIn0=
|
36
dist/smartsocket.classes.socketfunction.d.ts
vendored
36
dist/smartsocket.classes.socketfunction.d.ts
vendored
@ -1,36 +0,0 @@
|
||||
import { SocketRole } from "./smartsocket.classes.socketrole";
|
||||
export interface ISocketFunctionRequestObject {
|
||||
functionName: string;
|
||||
argumentObject: any;
|
||||
shortId: string;
|
||||
responseTimeout?: number;
|
||||
}
|
||||
export interface ISocketFunctionResponseObject {
|
||||
shortId: string;
|
||||
argumentObject: any;
|
||||
}
|
||||
export interface SocketFunctionOptions {
|
||||
name: string;
|
||||
func: any;
|
||||
roles: SocketRole[];
|
||||
}
|
||||
/**
|
||||
* class SocketFunction respresents a function that can be transparently called using a SocketConnection
|
||||
*/
|
||||
export declare class SocketFunction {
|
||||
name: string;
|
||||
func: any;
|
||||
roles: SocketRole[];
|
||||
/**
|
||||
* the constructor for SocketFunction
|
||||
*/
|
||||
constructor(optionsArg: SocketFunctionOptions);
|
||||
/**
|
||||
* notifies a role about access to this SocketFunction
|
||||
*/
|
||||
private _notifyRole(socketRoleArg);
|
||||
/**
|
||||
* invokes the function of this SocketFunction
|
||||
*/
|
||||
invoke(dataArg: ISocketFunctionRequestObject): void;
|
||||
}
|
36
dist/smartsocket.classes.socketfunction.js
vendored
36
dist/smartsocket.classes.socketfunction.js
vendored
@ -1,36 +0,0 @@
|
||||
"use strict";
|
||||
;
|
||||
;
|
||||
;
|
||||
// export classes
|
||||
/**
|
||||
* class SocketFunction respresents a function that can be transparently called using a SocketConnection
|
||||
*/
|
||||
class SocketFunction {
|
||||
/**
|
||||
* the constructor for SocketFunction
|
||||
*/
|
||||
constructor(optionsArg) {
|
||||
this.name = optionsArg.name;
|
||||
this.func = optionsArg.func;
|
||||
this.roles = optionsArg.roles;
|
||||
for (let socketRoleArg of this.roles) {
|
||||
this._notifyRole(socketRoleArg);
|
||||
}
|
||||
}
|
||||
;
|
||||
/**
|
||||
* notifies a role about access to this SocketFunction
|
||||
*/
|
||||
_notifyRole(socketRoleArg) {
|
||||
socketRoleArg.addSocketFunction(this);
|
||||
}
|
||||
/**
|
||||
* invokes the function of this SocketFunction
|
||||
*/
|
||||
invoke(dataArg) {
|
||||
}
|
||||
;
|
||||
}
|
||||
exports.SocketFunction = SocketFunction;
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRzb2NrZXQuY2xhc3Nlcy5zb2NrZXRmdW5jdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3NtYXJ0c29ja2V0LmNsYXNzZXMuc29ja2V0ZnVuY3Rpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQWFDLENBQUM7QUFLRCxDQUFDO0FBTUQsQ0FBQztBQUVGLGlCQUFpQjtBQUVqQjs7R0FFRztBQUNIO0lBS0k7O09BRUc7SUFDSCxZQUFZLFVBQWlDO1FBQ3pDLElBQUksQ0FBQyxJQUFJLEdBQUcsVUFBVSxDQUFDLElBQUksQ0FBQztRQUM1QixJQUFJLENBQUMsSUFBSSxHQUFHLFVBQVUsQ0FBQyxJQUFJLENBQUM7UUFDNUIsSUFBSSxDQUFDLEtBQUssR0FBRyxVQUFVLENBQUMsS0FBSyxDQUFDO1FBQzlCLEdBQUcsQ0FBQyxDQUFDLElBQUksYUFBYSxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQSxDQUFDO1lBQ2xDLElBQUksQ0FBQyxXQUFXLENBQUMsYUFBYSxDQUFDLENBQUM7UUFDcEMsQ0FBQztJQUNMLENBQUM7O0lBRUQ7O09BRUc7SUFDSyxXQUFXLENBQUMsYUFBd0I7UUFDeEMsYUFBYSxDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzFDLENBQUM7SUFFRDs7T0FFRztJQUNILE1BQU0sQ0FBQyxPQUFvQztJQUUzQyxDQUFDOztBQUVMLENBQUM7QUEvQlksc0JBQWMsaUJBK0IxQixDQUFBIn0=
|
18
dist/smartsocket.classes.socketrequest.d.ts
vendored
18
dist/smartsocket.classes.socketrequest.d.ts
vendored
@ -1,18 +0,0 @@
|
||||
import { ISocketFunctionResponseObject } from "./smartsocket.classes.socketfunction";
|
||||
import { Objectmap } from "lik";
|
||||
export declare type TSocketRequestStatus = "new" | "pending" | "finished";
|
||||
export declare type TSocketRequestSide = "requesting" | "responding";
|
||||
export interface SocketRequestConstructorOptions {
|
||||
side: TSocketRequestSide;
|
||||
shortid: string;
|
||||
}
|
||||
export declare let allRequestingSocketRequests: Objectmap<SocketRequest>;
|
||||
export declare let allRespondingSocketRequests: Objectmap<SocketRequest>;
|
||||
export declare class SocketRequest {
|
||||
status: TSocketRequestStatus;
|
||||
side: TSocketRequestSide;
|
||||
shortid: string;
|
||||
constructor(optionsArg: SocketRequestConstructorOptions);
|
||||
respond(dataArg: ISocketFunctionResponseObject): void;
|
||||
private _dispatch();
|
||||
}
|
30
dist/smartsocket.classes.socketrequest.js
vendored
30
dist/smartsocket.classes.socketrequest.js
vendored
@ -1,30 +0,0 @@
|
||||
"use strict";
|
||||
// import classes
|
||||
const lik_1 = require("lik");
|
||||
;
|
||||
//export objects
|
||||
exports.allRequestingSocketRequests = new lik_1.Objectmap();
|
||||
exports.allRespondingSocketRequests = new lik_1.Objectmap();
|
||||
// export classes
|
||||
class SocketRequest {
|
||||
constructor(optionsArg) {
|
||||
this.status = "new";
|
||||
this.side = optionsArg.side;
|
||||
this.shortid = optionsArg.shortid;
|
||||
if (this.side === "requesting") {
|
||||
exports.allRequestingSocketRequests.add(this);
|
||||
}
|
||||
else {
|
||||
exports.allRespondingSocketRequests.add(this);
|
||||
}
|
||||
;
|
||||
}
|
||||
;
|
||||
respond(dataArg) {
|
||||
}
|
||||
_dispatch() {
|
||||
}
|
||||
}
|
||||
exports.SocketRequest = SocketRequest;
|
||||
;
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRzb2NrZXQuY2xhc3Nlcy5zb2NrZXRyZXF1ZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvc21hcnRzb2NrZXQuY2xhc3Nlcy5zb2NrZXRyZXF1ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFLQSxpQkFBaUI7QUFDakIsc0JBQTBCLEtBQUssQ0FBQyxDQUFBO0FBVS9CLENBQUM7QUFFRixnQkFBZ0I7QUFDTCxtQ0FBMkIsR0FBRyxJQUFJLGVBQVMsRUFBaUIsQ0FBQztBQUM3RCxtQ0FBMkIsR0FBRyxJQUFJLGVBQVMsRUFBaUIsQ0FBQztBQUV4RSxpQkFBaUI7QUFDakI7SUFJSSxZQUFZLFVBQTJDO1FBSHZELFdBQU0sR0FBeUIsS0FBSyxDQUFDO1FBSWpDLElBQUksQ0FBQyxJQUFJLEdBQUcsVUFBVSxDQUFDLElBQUksQ0FBQztRQUM1QixJQUFJLENBQUMsT0FBTyxHQUFHLFVBQVUsQ0FBQyxPQUFPLENBQUM7UUFDbEMsRUFBRSxDQUFBLENBQUMsSUFBSSxDQUFDLElBQUksS0FBSyxZQUFZLENBQUMsQ0FBQSxDQUFDO1lBQzNCLG1DQUEyQixDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUMxQyxDQUFDO1FBQUMsSUFBSSxDQUFDLENBQUM7WUFDSixtQ0FBMkIsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDMUMsQ0FBQztRQUFBLENBQUM7SUFDTixDQUFDOztJQUNELE9BQU8sQ0FBQyxPQUFxQztJQUU3QyxDQUFDO0lBQ08sU0FBUztJQUVqQixDQUFDO0FBQ0wsQ0FBQztBQW5CWSxxQkFBYSxnQkFtQnpCLENBQUE7QUFBQSxDQUFDIn0=
|
20
dist/smartsocket.classes.socketrole.d.ts
vendored
20
dist/smartsocket.classes.socketrole.d.ts
vendored
@ -1,20 +0,0 @@
|
||||
import { Objectmap } from "lik";
|
||||
import { SocketFunction } from "./smartsocket.classes.socketfunction";
|
||||
export declare let allSocketRoles: Objectmap<SocketRole>;
|
||||
/**
|
||||
* interface for class SocketRole
|
||||
*/
|
||||
export interface SocketRoleOptions {
|
||||
name: string;
|
||||
passwordHash: string;
|
||||
}
|
||||
/**
|
||||
* A socketrole defines access to certain routines.
|
||||
*/
|
||||
export declare class SocketRole {
|
||||
name: string;
|
||||
passwordHash: string;
|
||||
allowedFunctions: Objectmap<SocketFunction>;
|
||||
constructor(optionsArg: SocketRoleOptions);
|
||||
addSocketFunction(socketFunctionArg: SocketFunction): void;
|
||||
}
|
21
dist/smartsocket.classes.socketrole.js
vendored
21
dist/smartsocket.classes.socketrole.js
vendored
@ -1,21 +0,0 @@
|
||||
"use strict";
|
||||
// import classes
|
||||
const lik_1 = require("lik");
|
||||
exports.allSocketRoles = new lik_1.Objectmap();
|
||||
/**
|
||||
* A socketrole defines access to certain routines.
|
||||
*/
|
||||
class SocketRole {
|
||||
constructor(optionsArg) {
|
||||
this.allowedFunctions = new lik_1.Objectmap();
|
||||
this.name = optionsArg.name;
|
||||
this.passwordHash = optionsArg.passwordHash;
|
||||
exports.allSocketRoles.add(this);
|
||||
}
|
||||
;
|
||||
addSocketFunction(socketFunctionArg) {
|
||||
this.allowedFunctions.add(socketFunctionArg);
|
||||
}
|
||||
}
|
||||
exports.SocketRole = SocketRole;
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRzb2NrZXQuY2xhc3Nlcy5zb2NrZXRyb2xlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvc21hcnRzb2NrZXQuY2xhc3Nlcy5zb2NrZXRyb2xlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFFQSxpQkFBaUI7QUFDakIsc0JBQTBCLEtBQUssQ0FBQyxDQUFBO0FBSXJCLHNCQUFjLEdBQUcsSUFBSSxlQUFTLEVBQWMsQ0FBQztBQVd4RDs7R0FFRztBQUNIO0lBSUksWUFBWSxVQUE2QjtRQUR6QyxxQkFBZ0IsR0FBRyxJQUFJLGVBQVMsRUFBa0IsQ0FBQztRQUUvQyxJQUFJLENBQUMsSUFBSSxHQUFHLFVBQVUsQ0FBQyxJQUFJLENBQUM7UUFDNUIsSUFBSSxDQUFDLFlBQVksR0FBRyxVQUFVLENBQUMsWUFBWSxDQUFDO1FBQzVDLHNCQUFjLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzdCLENBQUM7O0lBQ0QsaUJBQWlCLENBQUMsaUJBQWdDO1FBQzlDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsaUJBQWlCLENBQUMsQ0FBQztJQUNqRCxDQUFDO0FBQ0wsQ0FBQztBQVpZLGtCQUFVLGFBWXRCLENBQUEifQ==
|
2
dist/smartsocket.helpers.d.ts
vendored
2
dist/smartsocket.helpers.d.ts
vendored
@ -1,2 +0,0 @@
|
||||
import { SocketRole } from "./smartsocket.classes.socketrole";
|
||||
export declare let findSocketRoleByString: (socketRoleNameArg: string) => SocketRole;
|
7
dist/smartsocket.helpers.js
vendored
7
dist/smartsocket.helpers.js
vendored
@ -1,7 +0,0 @@
|
||||
"use strict";
|
||||
const smartsocket_classes_socketrole_1 = require("./smartsocket.classes.socketrole");
|
||||
// SocketRole helpers
|
||||
exports.findSocketRoleByString = (socketRoleNameArg) => {
|
||||
return smartsocket_classes_socketrole_1.allSocketRoles.find((socketRoleArg) => { return socketRoleArg.name === socketRoleNameArg; });
|
||||
};
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRzb2NrZXQuaGVscGVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3NtYXJ0c29ja2V0LmhlbHBlcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQU1BLGlEQUEyQyxrQ0FBa0MsQ0FBQyxDQUFBO0FBRzlFLHFCQUFxQjtBQUNWLDhCQUFzQixHQUFHLENBQUMsaUJBQXlCO0lBQzFELE1BQU0sQ0FBQywrQ0FBYyxDQUFDLElBQUksQ0FBQyxDQUFDLGFBQWEsT0FBTyxNQUFNLENBQUMsYUFBYSxDQUFDLElBQUksS0FBSyxpQkFBaUIsQ0FBQSxDQUFDLENBQUMsQ0FBQyxDQUFBO0FBQ3RHLENBQUMsQ0FBQyJ9
|
8
dist/smartsocket.plugins.d.ts
vendored
8
dist/smartsocket.plugins.d.ts
vendored
@ -1,8 +0,0 @@
|
||||
import "typings-global";
|
||||
export import beautylog = require("beautylog");
|
||||
export import lik = require("lik");
|
||||
export import q = require("q");
|
||||
export import shortid = require("shortid");
|
||||
export import socketIo = require("socket.io");
|
||||
export import socketIoClient = require("socket.io-client");
|
||||
export import taskbuffer = require("taskbuffer");
|
10
dist/smartsocket.plugins.js
vendored
10
dist/smartsocket.plugins.js
vendored
@ -1,10 +0,0 @@
|
||||
"use strict";
|
||||
require("typings-global");
|
||||
exports.beautylog = require("beautylog");
|
||||
exports.lik = require("lik");
|
||||
exports.q = require("q");
|
||||
exports.shortid = require("shortid");
|
||||
exports.socketIo = require("socket.io");
|
||||
exports.socketIoClient = require("socket.io-client");
|
||||
exports.taskbuffer = require("taskbuffer");
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRzb2NrZXQucGx1Z2lucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3NtYXJ0c29ja2V0LnBsdWdpbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLFFBQU8sZ0JBQWdCLENBQUMsQ0FBQTtBQUNWLGlCQUFTLFdBQVcsV0FBVyxDQUFDLENBQUM7QUFDakMsV0FBRyxXQUFZLEtBQUssQ0FBQyxDQUFDO0FBQ3RCLFNBQUMsV0FBVyxHQUFHLENBQUMsQ0FBQztBQUNqQixlQUFPLFdBQVcsU0FBUyxDQUFDLENBQUM7QUFDN0IsZ0JBQVEsV0FBVyxXQUFXLENBQUMsQ0FBQztBQUNoQyxzQkFBYyxXQUFXLGtCQUFrQixDQUFDLENBQUM7QUFDN0Msa0JBQVUsV0FBVyxZQUFZLENBQUMsQ0FBQyJ9
|
18
npmextra.json
Normal file
18
npmextra.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"gitzone": {
|
||||
"projectType": "npm",
|
||||
"module": {
|
||||
"githost": "gitlab.com",
|
||||
"gitscope": "pushrocks",
|
||||
"gitrepo": "smartsocket",
|
||||
"shortDescription": "easy and secure websocket communication",
|
||||
"npmPackagename": "@pushrocks/smartsocket",
|
||||
"license": "MIT",
|
||||
"projectDomain": "push.rocks"
|
||||
}
|
||||
},
|
||||
"npmci": {
|
||||
"npmGlobalTools": [],
|
||||
"npmAccessLevel": "public"
|
||||
}
|
||||
}
|
11048
package-lock.json
generated
Normal file
11048
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
67
package.json
67
package.json
@ -1,11 +1,12 @@
|
||||
{
|
||||
"name": "smartsocket",
|
||||
"version": "1.0.5",
|
||||
"description": "easy and secure websocket communication, Typescript ready",
|
||||
"main": "dist/index.js",
|
||||
"typings": "dist/index.d.ts",
|
||||
"name": "@pushrocks/smartsocket",
|
||||
"version": "1.2.0",
|
||||
"description": "easy and secure websocket communication",
|
||||
"main": "dist_ts/index.js",
|
||||
"typings": "dist_ts/index.d.ts",
|
||||
"scripts": {
|
||||
"test": "(npmts)"
|
||||
"test": "(tstest test/)",
|
||||
"build": "(tsbuild --web && tsbundle --from ./ts/index.ts --to dist_bundle/bundle.js)"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -18,21 +19,45 @@
|
||||
},
|
||||
"homepage": "https://gitlab.com/pushrocks/smartsocket#README",
|
||||
"dependencies": {
|
||||
"@types/q": "0.x.x",
|
||||
"@types/shortid": "0.0.27",
|
||||
"@types/socket.io": "^1.4.26",
|
||||
"@types/socket.io-client": "^1.4.26",
|
||||
"beautylog": "^5.0.20",
|
||||
"lik": "^1.0.15",
|
||||
"q": "^1.4.1",
|
||||
"shortid": "^2.2.6",
|
||||
"socket.io": "^1.4.8",
|
||||
"socket.io-client": "^1.4.8",
|
||||
"taskbuffer": "^1.0.7"
|
||||
"@apiglobal/typedrequest-interfaces": "^1.0.15",
|
||||
"@pushrocks/isohash": "^1.0.2",
|
||||
"@pushrocks/isounique": "^1.0.4",
|
||||
"@pushrocks/lik": "^4.0.20",
|
||||
"@pushrocks/smartdelay": "^2.0.10",
|
||||
"@pushrocks/smartenv": "^4.0.16",
|
||||
"@pushrocks/smartexpress": "^3.0.99",
|
||||
"@pushrocks/smartlog": "^2.0.39",
|
||||
"@pushrocks/smartpromise": "^3.1.3",
|
||||
"@pushrocks/smartrx": "^2.0.19",
|
||||
"@pushrocks/smarttime": "^3.0.37",
|
||||
"@types/socket.io": "^2.1.12",
|
||||
"@types/socket.io-client": "^1.4.34",
|
||||
"socket.io": "^3.0.4",
|
||||
"socket.io-client": "^3.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"npmts-g": "^5.2.8",
|
||||
"should": "^10.0.0",
|
||||
"typings-test": "^1.0.1"
|
||||
}
|
||||
"@gitzone/tsbuild": "^2.1.25",
|
||||
"@gitzone/tsrun": "^1.2.12",
|
||||
"@gitzone/tstest": "^1.0.52",
|
||||
"@pushrocks/tapbundle": "^3.2.9",
|
||||
"@types/node": "^14.14.14",
|
||||
"tslint": "^6.1.3",
|
||||
"tslint-config-prettier": "^1.18.0"
|
||||
},
|
||||
"private": false,
|
||||
"files": [
|
||||
"ts/**/*",
|
||||
"ts_web/**/*",
|
||||
"dist/**/*",
|
||||
"dist_*/**/*",
|
||||
"dist_ts/**/*",
|
||||
"dist_ts_web/**/*",
|
||||
"assets/**/*",
|
||||
"cli.js",
|
||||
"npmextra.json",
|
||||
"readme.md"
|
||||
],
|
||||
"browserslist": [
|
||||
"last 1 chrome versions"
|
||||
]
|
||||
}
|
||||
|
122
readme.md
Normal file
122
readme.md
Normal file
@ -0,0 +1,122 @@
|
||||
# @pushrocks/smartsocket
|
||||
easy and secure websocket communication
|
||||
|
||||
## Availabililty and Links
|
||||
* [npmjs.org (npm package)](https://www.npmjs.com/package/@pushrocks/smartsocket)
|
||||
* [gitlab.com (source)](https://gitlab.com/pushrocks/smartsocket)
|
||||
* [github.com (source mirror)](https://github.com/pushrocks/smartsocket)
|
||||
* [docs (typedoc)](https://pushrocks.gitlab.io/smartsocket/)
|
||||
|
||||
## Status for master
|
||||
|
||||
Status Category | Status Badge
|
||||
-- | --
|
||||
GitLab Pipelines | [](https://lossless.cloud)
|
||||
GitLab Pipline Test Coverage | [](https://lossless.cloud)
|
||||
npm | [](https://lossless.cloud)
|
||||
Snyk | [](https://lossless.cloud)
|
||||
TypeScript Support | [](https://lossless.cloud)
|
||||
node Support | [](https://nodejs.org/dist/latest-v10.x/docs/api/)
|
||||
Code Style | [](https://lossless.cloud)
|
||||
PackagePhobia (total standalone install weight) | [](https://lossless.cloud)
|
||||
PackagePhobia (package size on registry) | [](https://lossless.cloud)
|
||||
BundlePhobia (total size when bundled) | [](https://lossless.cloud)
|
||||
Platform support | [](https://lossless.cloud) [](https://lossless.cloud)
|
||||
|
||||
## Usage
|
||||
|
||||
Use TypeScript for best in class instellisense.
|
||||
|
||||
Under the hood we use socket.io and shortid for managed data exchange.
|
||||
|
||||
### Serverside
|
||||
|
||||
```typescript
|
||||
import * as smartsocket from 'smartsocket';
|
||||
import * as q from q; // q is a promise library
|
||||
|
||||
// The "Smartsocket" listens on a port and can receive new "SocketConnection" requests.
|
||||
let mySmartsocket = new smartsocket.Smartsocket({
|
||||
port: 3000, // the port smartsocket will listen on
|
||||
});
|
||||
|
||||
// optional:
|
||||
// run this with anothoer existing server like express
|
||||
declare var someExpressServer; // read the express docs about how express actually works
|
||||
mySmartsocket.setServer(someExpressServer);
|
||||
|
||||
// A "SocketRole" can be referenced by "SocketFunction"s.
|
||||
// All "SocketRequest"s carry authentication data for a specific "SocketRole".
|
||||
// "SocketFunction"s know which "SocketRole"s are allowed to execute them
|
||||
let mySocketRole = new smartsocket.SocketRole({
|
||||
name: 'someRoleName',
|
||||
passwordHash: 'someHashedString',
|
||||
});
|
||||
|
||||
// A "SocketFunction" executes a referenced function and passes in any data of the corresponding "SocketRequest".
|
||||
// The referenced function must return a promise and resolve with data of type any.
|
||||
// Any "SocketRequest" carries a unique identifier. If the referenced function's promise resolved any passed on argument will be returned to the requesting party
|
||||
let testSocketFunction1 = new smartsocket.SocketFunction({
|
||||
funcName: 'testSocketFunction1',
|
||||
funcDef: (data) => {
|
||||
console.log('testSocketFunction1 executed successfully!');
|
||||
},
|
||||
allowedRoles: [mySocketRole], // all roles that have access to a specific function
|
||||
});
|
||||
|
||||
// A "Smartsocket" exposes a .clientCall() that gets
|
||||
// 1. the name of the "SocketFunction" on the client side
|
||||
// 2. the data to pass in
|
||||
// 3. And a target "SocketConnection" (there can be multiple connections at once)
|
||||
// any unique id association is done internally
|
||||
mySmartsocket.clientCall('restart', data, someTargetConnection).then((responseData) => {});
|
||||
```
|
||||
|
||||
#### Client side
|
||||
|
||||
```typescript
|
||||
import * as smartsocket from 'smartsocket';
|
||||
|
||||
// A "SmartsocketClient" is different from a "Smartsocket" in that it doesn't expose any public address.
|
||||
// Thus any new "SocketConnection"s must be innitiated from a "SmartsocketClient".
|
||||
let testSmartsocketClient = new smartsocket.SmartsocketClient({
|
||||
port: testConfig.port,
|
||||
url: 'http://localhost',
|
||||
password: 'testPassword',
|
||||
alias: 'testClient1',
|
||||
role: 'testRole1',
|
||||
});
|
||||
|
||||
// You can .connect() and .disconnect() from a "Smartsocket"
|
||||
testSmartsocketClient.connect().then(() => {
|
||||
done();
|
||||
});
|
||||
|
||||
// The client can also specify "SocketFunction"s. It can also specify "SocketRole"s in case a client connects to multiple servers at once
|
||||
let testSocketFunction2 = new smartsocket.SocketFunction({
|
||||
funcName: 'testSocketFunction2',
|
||||
funcDef: (data) => {}, // the function to execute, has to return promise
|
||||
allowedRoles: [],
|
||||
});
|
||||
|
||||
// A "SmartsocketClient" can call functions on the serverside using .serverCall() analog to the "Smartsocket"'s .clientCall method.
|
||||
mySmartsocketClient.serverCall('function', functionCallData).then((functionResponseData) => {
|
||||
// the functionResponseData comes from the server... awesome, right?
|
||||
});
|
||||
```
|
||||
|
||||
> **NOTE:**
|
||||
> you can easily chain dependent requests on either the server or client side with promises.
|
||||
> `data` is always a js object that you can design for your specific needs.
|
||||
> It supports buffers for large binary data network exchange.
|
||||
|
||||
## 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). :)
|
||||
|
||||
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)
|
||||
|
||||
[](https://maintainedby.lossless.com)
|
1
test/common/test.ts
Normal file
1
test/common/test.ts
Normal file
@ -0,0 +1 @@
|
||||
console.log('TODO');
|
2
test/test.d.ts
vendored
2
test/test.d.ts
vendored
@ -1,2 +0,0 @@
|
||||
import "typings-test";
|
||||
import "should";
|
117
test/test.expressserver.ts
Normal file
117
test/test.expressserver.ts
Normal file
@ -0,0 +1,117 @@
|
||||
// tslint:disable-next-line:no-implicit-dependencies
|
||||
import { expect, tap } from '@pushrocks/tapbundle';
|
||||
|
||||
import * as isohash from '@pushrocks/isohash';
|
||||
import * as smartexpress from '@pushrocks/smartexpress';
|
||||
|
||||
import smartsocket = require('../ts/index');
|
||||
|
||||
let testSmartsocket: smartsocket.Smartsocket;
|
||||
let testSmartsocketClient: smartsocket.SmartsocketClient;
|
||||
let testSocketRole1: smartsocket.SocketRole;
|
||||
let testSocketFunction1: smartsocket.SocketFunction<any>;
|
||||
let myseServer: smartexpress.Server;
|
||||
|
||||
const testConfig = {
|
||||
port: 3005,
|
||||
};
|
||||
|
||||
// class smartsocket
|
||||
tap.test('should create a new smartsocket', async () => {
|
||||
testSmartsocket = new smartsocket.Smartsocket({ port: testConfig.port });
|
||||
expect(testSmartsocket).be.instanceOf(smartsocket.Smartsocket);
|
||||
});
|
||||
|
||||
tap.test('Should accept an smartExpressServer as server', async () => {
|
||||
myseServer = new smartexpress.Server({
|
||||
cors: true,
|
||||
forceSsl: false,
|
||||
port: testConfig.port,
|
||||
});
|
||||
|
||||
testSmartsocket.setExternalServer('smartexpress', myseServer);
|
||||
|
||||
await myseServer.start();
|
||||
});
|
||||
|
||||
// class socketrole
|
||||
tap.test('should add a socketrole', async () => {
|
||||
testSocketRole1 = new smartsocket.SocketRole({
|
||||
name: 'testRole1',
|
||||
passwordHash: await isohash.sha256FromString('testPassword'),
|
||||
});
|
||||
testSmartsocket.addSocketRoles([testSocketRole1]);
|
||||
});
|
||||
|
||||
// class SocketFunction
|
||||
tap.test('should register a new Function', async () => {
|
||||
testSocketFunction1 = new smartsocket.SocketFunction({
|
||||
allowedRoles: [testSocketRole1],
|
||||
funcDef: async (dataArg, socketConnectionArg) => {
|
||||
return dataArg;
|
||||
},
|
||||
funcName: 'testFunction1',
|
||||
});
|
||||
testSmartsocket.addSocketFunction(testSocketFunction1);
|
||||
console.log(testSmartsocket.socketFunctions);
|
||||
});
|
||||
|
||||
tap.test('should start listening when .started is called', async () => {
|
||||
await testSmartsocket.start();
|
||||
});
|
||||
|
||||
// class SmartsocketClient
|
||||
tap.test('should react to a new websocket connection from client', async () => {
|
||||
testSmartsocketClient = new smartsocket.SmartsocketClient({
|
||||
port: testConfig.port,
|
||||
url: 'http://localhost',
|
||||
password: 'testPassword',
|
||||
alias: 'testClient1',
|
||||
role: 'testRole1',
|
||||
});
|
||||
testSmartsocketClient.addSocketFunction(testSocketFunction1);
|
||||
console.log(testSmartsocketClient.socketFunctions);
|
||||
await testSmartsocketClient.connect();
|
||||
});
|
||||
|
||||
tap.test('client should disconnect and reconnect', async (tools) => {
|
||||
await testSmartsocketClient.disconnect();
|
||||
await tools.delayFor(100);
|
||||
await testSmartsocketClient.connect();
|
||||
});
|
||||
|
||||
tap.test('2 clients should connect in parallel', async () => {
|
||||
// TODO: implement parallel test
|
||||
});
|
||||
|
||||
tap.test('should be able to make a functionCall from client to server', async () => {
|
||||
const totalCycles = 20000;
|
||||
let counter = 0;
|
||||
let startTime = Date.now();
|
||||
while (counter < totalCycles) {
|
||||
const randomString = `hello ${Math.random()}`;
|
||||
const response: any = await testSmartsocketClient.serverCall('testFunction1', {
|
||||
value1: randomString,
|
||||
});
|
||||
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 () => {});
|
||||
|
||||
// terminate
|
||||
tap.test('should close the server', async () => {
|
||||
await testSmartsocket.stop();
|
||||
await myseServer.stop();
|
||||
});
|
||||
|
||||
tap.start();
|
37
test/test.js
37
test/test.js
@ -1,37 +0,0 @@
|
||||
"use strict";
|
||||
require("typings-test");
|
||||
require("should");
|
||||
const socketIoClient = require("socket.io-client");
|
||||
const smartsocket = require("../dist/index");
|
||||
let testSmartsocket;
|
||||
describe("smartsocket", function () {
|
||||
it("should create a new smartsocket", function () {
|
||||
testSmartsocket = new smartsocket.Smartsocket({ port: 3000 });
|
||||
testSmartsocket.should.be.instanceOf(smartsocket.Smartsocket);
|
||||
});
|
||||
it("should register a new Function", function () {
|
||||
});
|
||||
it("should start listening when .started is called", function () {
|
||||
testSmartsocket.startServer();
|
||||
});
|
||||
it("should react to a new websocket connection", function (done) {
|
||||
this.timeout(10000);
|
||||
let socket = socketIoClient("http://localhost:3000", {});
|
||||
socket.on("requestAuth", function () {
|
||||
console.log("server requested authentication");
|
||||
socket.emit("dataAuth", {
|
||||
role: "coreflowContainer",
|
||||
password: "somePassword",
|
||||
alias: "coreflow1"
|
||||
});
|
||||
socket.on("authenticated", () => {
|
||||
console.log("client is authenticated");
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
it("should close the server", function () {
|
||||
testSmartsocket.closeServer();
|
||||
});
|
||||
});
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInRlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLFFBQU8sY0FBYyxDQUFDLENBQUE7QUFDdEIsUUFBTyxRQUFRLENBQUMsQ0FBQTtBQUNoQixNQUFPLGNBQWMsV0FBVyxrQkFBa0IsQ0FBQyxDQUFDO0FBQ3BELE1BQU8sV0FBVyxXQUFXLGVBQWUsQ0FBQyxDQUFDO0FBRTlDLElBQUksZUFBd0MsQ0FBQztBQUU3QyxRQUFRLENBQUMsYUFBYSxFQUFFO0lBQ3BCLEVBQUUsQ0FBQyxpQ0FBaUMsRUFBRTtRQUNsQyxlQUFlLEdBQUcsSUFBSSxXQUFXLENBQUMsV0FBVyxDQUFDLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7UUFDOUQsZUFBZSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLFdBQVcsQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUNsRSxDQUFDLENBQUMsQ0FBQztJQUNILEVBQUUsQ0FBQyxnQ0FBZ0MsRUFBQztJQUVwQyxDQUFDLENBQUMsQ0FBQTtJQUNGLEVBQUUsQ0FBQyxnREFBZ0QsRUFBQztRQUNoRCxlQUFlLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDbEMsQ0FBQyxDQUFDLENBQUE7SUFDRixFQUFFLENBQUMsNENBQTRDLEVBQUUsVUFBVSxJQUFJO1FBQzNELElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDcEIsSUFBSSxNQUFNLEdBQUcsY0FBYyxDQUFDLHVCQUF1QixFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ3pELE1BQU0sQ0FBQyxFQUFFLENBQUMsYUFBYSxFQUFFO1lBQ3JCLE9BQU8sQ0FBQyxHQUFHLENBQUMsaUNBQWlDLENBQUMsQ0FBQztZQUMvQyxNQUFNLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRTtnQkFDcEIsSUFBSSxFQUFFLG1CQUFtQjtnQkFDekIsUUFBUSxFQUFFLGNBQWM7Z0JBQ3hCLEtBQUssRUFBRSxXQUFXO2FBQ3JCLENBQUMsQ0FBQztZQUNILE1BQU0sQ0FBQyxFQUFFLENBQUMsZUFBZSxFQUFDO2dCQUN0QixPQUFPLENBQUMsR0FBRyxDQUFDLHlCQUF5QixDQUFDLENBQUM7Z0JBQ3ZDLElBQUksRUFBRSxDQUFDO1lBQ1gsQ0FBQyxDQUFDLENBQUM7UUFDUCxDQUFDLENBQUMsQ0FBQztJQUNQLENBQUMsQ0FBQyxDQUFDO0lBQ0gsRUFBRSxDQUFDLHlCQUF5QixFQUFDO1FBQ3pCLGVBQWUsQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUNsQyxDQUFDLENBQUMsQ0FBQTtBQUNOLENBQUMsQ0FBQyxDQUFDIn0=
|
160
test/test.ts
160
test/test.ts
@ -1,38 +1,130 @@
|
||||
import "typings-test";
|
||||
import "should";
|
||||
import socketIoClient = require("socket.io-client");
|
||||
import smartsocket = require("../dist/index");
|
||||
// tslint:disable-next-line:no-implicit-dependencies
|
||||
import { expect, tap } from '@pushrocks/tapbundle';
|
||||
|
||||
import smartsocket = require('../ts/index');
|
||||
import * as isohash from '@pushrocks/isohash';
|
||||
|
||||
let testSmartsocket: smartsocket.Smartsocket;
|
||||
let testSmartsocketClient: smartsocket.SmartsocketClient;
|
||||
let testSocketConnection: smartsocket.SocketConnection;
|
||||
let testSocketRole1: smartsocket.SocketRole;
|
||||
let testSocketFunctionForServer: smartsocket.SocketFunction<any>;
|
||||
let testSocketFunctionClient: smartsocket.SocketFunction<any>;
|
||||
|
||||
describe("smartsocket", function () {
|
||||
it("should create a new smartsocket", function () {
|
||||
testSmartsocket = new smartsocket.Smartsocket({ port: 3000 });
|
||||
testSmartsocket.should.be.instanceOf(smartsocket.Smartsocket);
|
||||
});
|
||||
it("should register a new Function",function(){
|
||||
|
||||
export interface IReqResClient {
|
||||
method: 'testFunction1';
|
||||
request: {
|
||||
value1: string;
|
||||
};
|
||||
response: {
|
||||
value1: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReqResServer {
|
||||
method: 'testFunction2';
|
||||
request: {
|
||||
hi: string;
|
||||
};
|
||||
response: {
|
||||
hi: string;
|
||||
};
|
||||
}
|
||||
|
||||
const testConfig = {
|
||||
port: 3000,
|
||||
};
|
||||
|
||||
// class smartsocket
|
||||
tap.test('should create a new smartsocket', async () => {
|
||||
testSmartsocket = new smartsocket.Smartsocket({ port: testConfig.port });
|
||||
expect(testSmartsocket).be.instanceOf(smartsocket.Smartsocket);
|
||||
});
|
||||
|
||||
// class socketrole
|
||||
tap.test('should add a socketrole', async () => {
|
||||
testSocketRole1 = new smartsocket.SocketRole({
|
||||
name: 'testRole1',
|
||||
passwordHash: await isohash.sha256FromString('testPassword'),
|
||||
});
|
||||
testSmartsocket.addSocketRoles([testSocketRole1]);
|
||||
});
|
||||
|
||||
// class SocketFunction
|
||||
tap.test('should register a new Function', async () => {
|
||||
testSocketFunctionForServer = new smartsocket.SocketFunction({
|
||||
allowedRoles: [testSocketRole1],
|
||||
funcDef: async (dataArg, socketConnectionArg) => {
|
||||
return dataArg;
|
||||
},
|
||||
funcName: 'testFunction1',
|
||||
});
|
||||
testSmartsocket.addSocketFunction(testSocketFunctionForServer);
|
||||
|
||||
testSocketFunctionClient = new smartsocket.SocketFunction({
|
||||
allowedRoles: [],
|
||||
funcDef: async (dataArg, socketConnectionArg) => {
|
||||
return dataArg;
|
||||
},
|
||||
funcName: 'testFunction2',
|
||||
});
|
||||
testSmartsocket.addSocketFunction(testSocketFunctionForServer);
|
||||
console.log(testSmartsocket.socketFunctions);
|
||||
});
|
||||
|
||||
tap.test('should start listening when .started is called', async () => {
|
||||
await testSmartsocket.start();
|
||||
});
|
||||
|
||||
// class SmartsocketClient
|
||||
tap.test('should react to a new websocket connection from client', async () => {
|
||||
testSmartsocketClient = new smartsocket.SmartsocketClient({
|
||||
port: testConfig.port,
|
||||
url: 'http://localhost',
|
||||
password: 'testPassword',
|
||||
alias: 'testClient1',
|
||||
role: 'testRole1',
|
||||
});
|
||||
testSmartsocketClient.addSocketFunction(testSocketFunctionClient);
|
||||
console.log(testSmartsocketClient.socketFunctions);
|
||||
await testSmartsocketClient.connect();
|
||||
});
|
||||
|
||||
tap.test('2 clients should connect in parallel', async () => {
|
||||
// TODO: implement parallel test
|
||||
});
|
||||
|
||||
tap.test('should be able to make a functionCall from client to server', async () => {
|
||||
const response = await testSmartsocketClient.serverCall<IReqResClient>('testFunction1', {
|
||||
value1: 'hello',
|
||||
});
|
||||
console.log(response);
|
||||
expect(response.value1).to.equal('hello');
|
||||
});
|
||||
|
||||
tap.test('should be able to make a functionCall from server to client', async () => {
|
||||
const response = await testSmartsocket.clientCall<IReqResServer>(
|
||||
'testFunction2',
|
||||
{
|
||||
hi: 'hi there from server',
|
||||
},
|
||||
testSmartsocket.socketConnections.find((socketConnection) => {
|
||||
return true;
|
||||
})
|
||||
it("should start listening when .started is called",function(){
|
||||
testSmartsocket.startServer();
|
||||
})
|
||||
it("should react to a new websocket connection", function (done) {
|
||||
this.timeout(10000);
|
||||
let socket = socketIoClient("http://localhost:3000", {});
|
||||
socket.on("requestAuth", function () {
|
||||
console.log("server requested authentication");
|
||||
socket.emit("dataAuth", {
|
||||
role: "coreflowContainer",
|
||||
password: "somePassword",
|
||||
alias: "coreflow1"
|
||||
});
|
||||
socket.on("authenticated",() => {
|
||||
console.log("client is authenticated");
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
it("should close the server",function(){
|
||||
testSmartsocket.closeServer();
|
||||
})
|
||||
});
|
||||
);
|
||||
console.log(response);
|
||||
expect(response.hi).to.equal('hi there from server');
|
||||
});
|
||||
|
||||
tap.test('client should disconnect and reconnect', async (tools) => {
|
||||
await testSmartsocketClient.disconnect();
|
||||
await tools.delayFor(100);
|
||||
await testSmartsocketClient.connect();
|
||||
});
|
||||
|
||||
// terminate
|
||||
tap.test('should close the server', async () => {
|
||||
await testSmartsocket.stop();
|
||||
});
|
||||
|
||||
tap.start();
|
||||
|
10
ts/index.ts
10
ts/index.ts
@ -1,4 +1,8 @@
|
||||
import * as plugins from "./smartsocket.plugins";
|
||||
// export main classes
|
||||
export * from './smartsocket.classes.smartsocket';
|
||||
export * from './smartsocket.classes.smartsocketclient';
|
||||
|
||||
export * from "./smartsocket.classes.smartsocket";
|
||||
export * from "./smartsocket.classes.smartsocketclient";
|
||||
// export further classes and objects
|
||||
export * from './smartsocket.classes.socketfunction';
|
||||
export * from './smartsocket.classes.socketrole';
|
||||
export * from './smartsocket.classes.socketconnection';
|
||||
|
10
ts/interfaces/connection.ts
Normal file
10
ts/interfaces/connection.ts
Normal file
@ -0,0 +1,10 @@
|
||||
export interface IRequestAuthPayload {
|
||||
serverShortId: string;
|
||||
}
|
||||
|
||||
export type TConnectionStatus =
|
||||
| 'new'
|
||||
| 'connecting'
|
||||
| 'connected'
|
||||
| 'disconnecting'
|
||||
| 'disconnected';
|
1
ts/interfaces/index.ts
Normal file
1
ts/interfaces/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './connection';
|
@ -1,55 +1,130 @@
|
||||
import * as plugins from "./smartsocket.plugins";
|
||||
import * as helpers from "./smartsocket.helpers";
|
||||
import * as plugins from './smartsocket.plugins';
|
||||
import * as pluginsTyped from './smartsocket.pluginstyped';
|
||||
|
||||
// classes
|
||||
import { Objectmap } from "lik";
|
||||
import { SocketRole } from "./smartsocket.classes.socketrole";
|
||||
import { SocketFunction } from "./smartsocket.classes.socketfunction";
|
||||
import { SocketConnection } from "./smartsocket.classes.socketconnection";
|
||||
import { SocketConnection } from './smartsocket.classes.socketconnection';
|
||||
import {
|
||||
ISocketFunctionCallDataRequest,
|
||||
SocketFunction,
|
||||
ISocketFunctionCallDataResponse,
|
||||
} from './smartsocket.classes.socketfunction';
|
||||
import { SocketRequest } from './smartsocket.classes.socketrequest';
|
||||
import { SocketRole } from './smartsocket.classes.socketrole';
|
||||
import { SocketServer } from './smartsocket.classes.socketserver';
|
||||
|
||||
import { logger } from './smartsocket.logging';
|
||||
|
||||
export interface ISmartsocketConstructorOptions {
|
||||
port: number;
|
||||
|
||||
};
|
||||
port?: number;
|
||||
}
|
||||
|
||||
export class Smartsocket {
|
||||
options: ISmartsocketConstructorOptions
|
||||
io: SocketIO.Server;
|
||||
openSockets = new Objectmap<SocketConnection>();
|
||||
constructor(optionsArg: ISmartsocketConstructorOptions) {
|
||||
this.options = optionsArg;
|
||||
};
|
||||
/**
|
||||
* a unique id to detect server restarts
|
||||
*/
|
||||
public shortId = plugins.isounique.uni();
|
||||
public smartenv = new plugins.smartenv.Smartenv();
|
||||
public options: ISmartsocketConstructorOptions;
|
||||
public io: pluginsTyped.socketIo.Server;
|
||||
public socketConnections = new plugins.lik.ObjectMap<SocketConnection>();
|
||||
public socketRoles = new plugins.lik.ObjectMap<SocketRole>();
|
||||
public socketFunctions = new plugins.lik.ObjectMap<SocketFunction<any>>();
|
||||
public socketRequests = new plugins.lik.ObjectMap<SocketRequest<any>>();
|
||||
|
||||
/**
|
||||
* the standard handler for new socket connections
|
||||
*/
|
||||
private _handleSocket(socketArg) {
|
||||
let socketConnection: SocketConnection = new SocketConnection({
|
||||
authenticated:false,
|
||||
socket:socketArg
|
||||
});
|
||||
plugins.beautylog.log("Socket connected. Trying to authenticate...")
|
||||
this.openSockets.add(socketConnection);
|
||||
socketConnection.authenticate()
|
||||
.then(socketConnection.listenToFunctionRequests);
|
||||
};
|
||||
private socketServer = new SocketServer(this);
|
||||
|
||||
/**
|
||||
* starts listening to incling sockets:
|
||||
*/
|
||||
constructor(optionsArg: ISmartsocketConstructorOptions) {
|
||||
this.options = optionsArg;
|
||||
}
|
||||
|
||||
startServer = () => {
|
||||
this.io = plugins.socketIo(this.options.port);
|
||||
this.io.on('connection', (socketArg) => {
|
||||
this._handleSocket(socketArg);
|
||||
});
|
||||
// tslint:disable-next-line:member-ordering
|
||||
public async setExternalServer(serverType: 'smartexpress', serverArg: any) {
|
||||
await this.socketServer.setExternalServer(serverType, serverArg);
|
||||
}
|
||||
|
||||
/**
|
||||
* starts smartsocket
|
||||
*/
|
||||
public async start() {
|
||||
const socketIoModule = this.smartenv.getSafeNodeModule('socket.io');
|
||||
this.io = socketIoModule(this.socketServer.getServerForSocketIo());
|
||||
await this.socketServer.start();
|
||||
this.io.on('connection', (socketArg) => {
|
||||
this._handleSocketConnection(socketArg);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* stops smartsocket
|
||||
*/
|
||||
public async stop() {
|
||||
await plugins.smartdelay.delayFor(1000);
|
||||
this.socketConnections.forEach((socketObjectArg: SocketConnection) => {
|
||||
if (socketObjectArg) {
|
||||
logger.log('info', `disconnect socket with >>alias ${socketObjectArg.alias}`);
|
||||
socketObjectArg.socket.disconnect();
|
||||
}
|
||||
});
|
||||
this.socketConnections.wipe();
|
||||
this.io.close();
|
||||
|
||||
// stop the corresponging server
|
||||
this.socketServer.stop();
|
||||
}
|
||||
|
||||
// communication
|
||||
|
||||
/**
|
||||
* allows call to specific client.
|
||||
*/
|
||||
public async clientCall<T extends plugins.typedrequestInterfaces.ITypedRequest>(
|
||||
functionNameArg: T['method'],
|
||||
dataArg: T['request'],
|
||||
targetSocketConnectionArg: SocketConnection
|
||||
): Promise<T['response']> {
|
||||
const socketRequest = new SocketRequest<T>(this, {
|
||||
funcCallData: {
|
||||
funcDataArg: dataArg,
|
||||
funcName: functionNameArg,
|
||||
},
|
||||
originSocketConnection: targetSocketConnectionArg,
|
||||
shortId: plugins.isounique.uni(),
|
||||
side: 'requesting',
|
||||
});
|
||||
const response: ISocketFunctionCallDataResponse<T> = await socketRequest.dispatch();
|
||||
const result = response.funcDataArg;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* adds socketRoles
|
||||
*/
|
||||
public addSocketRoles(socketRolesArray: SocketRole[]): void {
|
||||
for (const socketRole of socketRolesArray) {
|
||||
this.socketRoles.add(socketRole);
|
||||
}
|
||||
closeServer = () => {
|
||||
this.openSockets.forEach((socketObjectArg: SocketConnection) => {
|
||||
plugins.beautylog.log(`disconnect socket with >>alias ${socketObjectArg.alias}`);
|
||||
socketObjectArg.socket.disconnect();
|
||||
});
|
||||
this.openSockets.wipe();
|
||||
this.io.close();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
public addSocketFunction(socketFunction: SocketFunction<any>) {
|
||||
this.socketFunctions.add(socketFunction);
|
||||
}
|
||||
|
||||
/**
|
||||
* the standard handler for new socket connections
|
||||
*/
|
||||
private async _handleSocketConnection(socketArg: pluginsTyped.socketIo.Socket) {
|
||||
const socketConnection: SocketConnection = new SocketConnection({
|
||||
alias: undefined,
|
||||
authenticated: false,
|
||||
role: undefined,
|
||||
side: 'server',
|
||||
smartsocketHost: this,
|
||||
socket: socketArg,
|
||||
});
|
||||
logger.log('info', 'Socket connected. Trying to authenticate...');
|
||||
this.socketConnections.add(socketConnection);
|
||||
await socketConnection.authenticate();
|
||||
await socketConnection.listenToFunctionRequests();
|
||||
}
|
||||
}
|
||||
|
@ -1,28 +1,212 @@
|
||||
import * as plugins from "./smartsocket.plugins"
|
||||
import * as plugins from './smartsocket.plugins';
|
||||
import * as pluginsTyped from './smartsocket.pluginstyped';
|
||||
import * as interfaces from './interfaces';
|
||||
|
||||
|
||||
// import interfaces
|
||||
import { ISocketFunctionRequestObject, ISocketFunctionResponseObject } from "./smartsocket.classes.socketfunction";
|
||||
|
||||
// import classes
|
||||
import { SocketFunction } from "./smartsocket.classes.socketfunction";
|
||||
import { SocketConnection } from './smartsocket.classes.socketconnection';
|
||||
import {
|
||||
ISocketFunctionCallDataRequest,
|
||||
SocketFunction,
|
||||
} from './smartsocket.classes.socketfunction';
|
||||
import { ISocketRequestDataObject, SocketRequest } from './smartsocket.classes.socketrequest';
|
||||
import { SocketRole } from './smartsocket.classes.socketrole';
|
||||
import { logger } from './smartsocket.logging';
|
||||
|
||||
/**
|
||||
* interface for class SmartsocketClient
|
||||
*/
|
||||
export interface ISmartsocketClientOptions {
|
||||
port: number;
|
||||
url: string;
|
||||
port: number;
|
||||
url: string;
|
||||
alias: string; // an alias makes it easier to identify this client in a multo client environment
|
||||
role: string;
|
||||
password: string; // by setting a password access to functions can be limited
|
||||
autoReconnect?: boolean;
|
||||
}
|
||||
|
||||
export class SmartsocketClient {
|
||||
constructor() {
|
||||
// a unique id
|
||||
public shortId = plugins.isounique.uni();
|
||||
|
||||
// the shortId of the remote we connect to
|
||||
public remoteShortId: string = null;
|
||||
|
||||
public alias: string;
|
||||
public socketRole: SocketRole;
|
||||
public socketConnection: SocketConnection;
|
||||
public serverUrl: string;
|
||||
public serverPort: number;
|
||||
public autoReconnect: boolean;
|
||||
|
||||
// status handling
|
||||
public eventSubject = new plugins.smartrx.rxjs.Subject<interfaces.TConnectionStatus>();
|
||||
public eventStatus: interfaces.TConnectionStatus = 'new';
|
||||
|
||||
public socketFunctions = new plugins.lik.ObjectMap<SocketFunction<any>>();
|
||||
public socketRequests = new plugins.lik.ObjectMap<SocketRequest<any>>();
|
||||
public socketRoles = new plugins.lik.ObjectMap<SocketRole>();
|
||||
|
||||
constructor(optionsArg: ISmartsocketClientOptions) {
|
||||
this.alias = optionsArg.alias;
|
||||
this.serverUrl = optionsArg.url;
|
||||
this.serverPort = optionsArg.port;
|
||||
this.socketRole = new SocketRole({
|
||||
name: optionsArg.role,
|
||||
passwordHash: optionsArg.password,
|
||||
});
|
||||
this.autoReconnect = optionsArg.autoReconnect;
|
||||
}
|
||||
|
||||
public addSocketFunction(socketFunction: SocketFunction<any>) {
|
||||
this.socketFunctions.add(socketFunction);
|
||||
this.socketRole.allowedFunctions.add(socketFunction);
|
||||
}
|
||||
|
||||
/**
|
||||
* connect the client to the server
|
||||
*/
|
||||
public async connect() {
|
||||
const done = plugins.smartpromise.defer();
|
||||
const smartenvInstance = new plugins.smartenv.Smartenv();
|
||||
const socketIoClient = await smartenvInstance.getEnvAwareModule({
|
||||
nodeModuleName: 'socket.io-client',
|
||||
webUrlArg: 'https://cdn.jsdelivr.net/npm/socket.io-client@2/dist/socket.io.js',
|
||||
getFunction: () => {
|
||||
return globalThis.io;
|
||||
},
|
||||
});
|
||||
logger.log('info', 'trying to connect...');
|
||||
const socketUrl = `${this.serverUrl}:${this.serverPort}`;
|
||||
this.socketConnection = new SocketConnection({
|
||||
alias: this.alias,
|
||||
authenticated: false,
|
||||
role: this.socketRole,
|
||||
side: 'client',
|
||||
smartsocketHost: this,
|
||||
socket: await socketIoClient.connect(socketUrl, {
|
||||
multiplex: false,
|
||||
reconnectionAttempts: 5,
|
||||
}),
|
||||
});
|
||||
|
||||
const timer = new plugins.smarttime.Timer(5000);
|
||||
timer.start();
|
||||
timer.completed.then(() => {
|
||||
logger.log('warn', 'connection to server timed out.');
|
||||
this.disconnect();
|
||||
});
|
||||
|
||||
// authentication flow
|
||||
this.socketConnection.socket.on(
|
||||
'requestAuth',
|
||||
(requestAuthPayload: interfaces.IRequestAuthPayload) => {
|
||||
timer.reset();
|
||||
logger.log('info', 'server requested authentication');
|
||||
|
||||
// lets register the authenticated event
|
||||
this.socketConnection.socket.on('authenticated', () => {
|
||||
this.remoteShortId = requestAuthPayload.serverShortId;
|
||||
logger.log('info', 'client is authenticated');
|
||||
this.socketConnection.authenticated = true;
|
||||
this.socketConnection.listenToFunctionRequests();
|
||||
done.resolve();
|
||||
});
|
||||
|
||||
// lets register the forbidden event
|
||||
this.socketConnection.socket.on('forbidden', async () => {
|
||||
logger.log('warn', `disconnecting due to being forbidden to use the ressource`);
|
||||
await this.disconnect();
|
||||
});
|
||||
|
||||
// lets provide the actual auth data
|
||||
this.socketConnection.socket.emit('dataAuth', {
|
||||
role: this.socketRole.name,
|
||||
password: this.socketRole.passwordHash,
|
||||
alias: this.alias,
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
// handle connection
|
||||
this.socketConnection.socket.on('connect', async () => {
|
||||
this.updateStatus('connected');
|
||||
});
|
||||
|
||||
// handle disconnection and errors
|
||||
this.socketConnection.socket.on('disconnect', async () => {
|
||||
await this.disconnect();
|
||||
});
|
||||
|
||||
this.socketConnection.socket.on('reconnect_failed', async () => {
|
||||
await this.disconnect();
|
||||
});
|
||||
this.socketConnection.socket.on('connect_error', async () => {
|
||||
await this.disconnect();
|
||||
});
|
||||
return done.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* disconnect from the server
|
||||
*/
|
||||
public async disconnect() {
|
||||
if (this.socketConnection) {
|
||||
await this.socketConnection.disconnect();
|
||||
this.socketConnection = undefined;
|
||||
logger.log('ok', 'disconnected!');
|
||||
}
|
||||
dispatchFunctionRequest(dataArg:ISocketFunctionRequestObject): plugins.q.Promise<ISocketFunctionResponseObject> {
|
||||
let done = plugins.q.defer<ISocketFunctionResponseObject>();
|
||||
let responseData:ISocketFunctionResponseObject;
|
||||
done.resolve(responseData);
|
||||
return done.promise;
|
||||
};
|
||||
}
|
||||
logger.log('warn', `disconnected from server ${this.remoteShortId}`);
|
||||
this.remoteShortId = null;
|
||||
this.updateStatus('disconnected');
|
||||
|
||||
if (this.autoReconnect) {
|
||||
this.tryDebouncedReconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* stops the client completely
|
||||
*/
|
||||
public async stop() {
|
||||
this.autoReconnect = false;
|
||||
await this.disconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* try a reconnection
|
||||
*/
|
||||
public async tryDebouncedReconnect() {
|
||||
await plugins.smartdelay.delayForRandom(10000, 60000);
|
||||
await this.connect();
|
||||
}
|
||||
|
||||
/**
|
||||
* dispatches a server call
|
||||
* @param functionNameArg
|
||||
* @param dataArg
|
||||
*/
|
||||
public async serverCall<T extends plugins.typedrequestInterfaces.ITypedRequest>(
|
||||
functionNameArg: T['method'],
|
||||
dataArg: T['request']
|
||||
): Promise<T['response']> {
|
||||
const done = plugins.smartpromise.defer();
|
||||
const socketRequest = new SocketRequest<T>(this, {
|
||||
side: 'requesting',
|
||||
originSocketConnection: this.socketConnection,
|
||||
shortId: plugins.isounique.uni(),
|
||||
funcCallData: {
|
||||
funcName: functionNameArg,
|
||||
funcDataArg: dataArg,
|
||||
},
|
||||
});
|
||||
const response = await socketRequest.dispatch();
|
||||
const result = response.funcDataArg;
|
||||
return result;
|
||||
}
|
||||
|
||||
private updateStatus(statusArg: interfaces.TConnectionStatus) {
|
||||
if (this.eventStatus !== statusArg) {
|
||||
this.eventSubject.next(statusArg);
|
||||
}
|
||||
this.eventStatus = statusArg;
|
||||
}
|
||||
}
|
||||
|
@ -1,91 +1,175 @@
|
||||
import * as plugins from "./smartsocket.plugins";
|
||||
import * as helpers from "./smartsocket.helpers";
|
||||
import * as plugins from './smartsocket.plugins';
|
||||
import * as interfaces from './interfaces';
|
||||
|
||||
// import classes
|
||||
import { SocketFunction, ISocketFunctionRequestObject } from "./smartsocket.classes.socketfunction";
|
||||
import { SocketRequest } from "./smartsocket.classes.socketrequest";
|
||||
import { SocketRole } from "./smartsocket.classes.socketrole";
|
||||
import { Smartsocket } from './smartsocket.classes.smartsocket';
|
||||
import { SocketFunction } from './smartsocket.classes.socketfunction';
|
||||
import { SocketRequest, ISocketRequestDataObject } from './smartsocket.classes.socketrequest';
|
||||
import { SocketRole } from './smartsocket.classes.socketrole';
|
||||
|
||||
// socket.io
|
||||
import * as SocketIO from 'socket.io';
|
||||
import { SmartsocketClient } from './smartsocket.classes.smartsocketclient';
|
||||
import { logger } from './smartsocket.logging';
|
||||
|
||||
// export interfaces
|
||||
|
||||
/**
|
||||
* defines is a SocketConnection is server or client side. Important for mesh setups.
|
||||
*/
|
||||
export type TSocketConnectionSide = 'server' | 'client';
|
||||
|
||||
/**
|
||||
* interface for constructor of class SocketConnection
|
||||
*/
|
||||
export interface ISocketConnectionOptions {
|
||||
alias?: string;
|
||||
authenticated: boolean;
|
||||
role?: SocketRole;
|
||||
socket: SocketIO.Socket;
|
||||
};
|
||||
export interface ISocketConnectionConstructorOptions {
|
||||
alias: string;
|
||||
authenticated: boolean;
|
||||
role: SocketRole;
|
||||
side: TSocketConnectionSide;
|
||||
smartsocketHost: Smartsocket | SmartsocketClient;
|
||||
socket: SocketIO.Socket | SocketIOClient.Socket;
|
||||
}
|
||||
|
||||
/**
|
||||
* interface for authentication data
|
||||
*/
|
||||
export interface ISocketConnectionAuthenticationObject {
|
||||
role: "coreflowContainer",
|
||||
password: "somePassword",
|
||||
alias: "coreflow1"
|
||||
role: 'coreflowContainer';
|
||||
password: 'somePassword';
|
||||
alias: 'coreflow1';
|
||||
}
|
||||
|
||||
// export classes
|
||||
export let allSocketConnections = new plugins.lik.ObjectMap<SocketConnection>();
|
||||
|
||||
/**
|
||||
* class SocketConnection represents a websocket connection
|
||||
*/
|
||||
export class SocketConnection {
|
||||
alias?: string;
|
||||
authenticated: boolean;
|
||||
role?: SocketRole;
|
||||
socket: SocketIO.Socket;
|
||||
constructor(optionsArg: ISocketConnectionOptions) {
|
||||
this.alias = optionsArg.alias;
|
||||
this.authenticated = optionsArg.authenticated;
|
||||
this.role = optionsArg.role;
|
||||
this.socket = optionsArg.socket;
|
||||
}
|
||||
/**
|
||||
* authenticate the socket
|
||||
*/
|
||||
authenticate() {
|
||||
let done = plugins.q.defer();
|
||||
this.socket.on("dataAuth", dataArg => {
|
||||
plugins.beautylog.log("received authentication data. now hashing and comparing...");
|
||||
this.socket.removeListener("dataAuth", () => { });
|
||||
if ((true)) { // TODO: authenticate password
|
||||
this.alias = dataArg.alias
|
||||
this.authenticated = true;
|
||||
this.role = helpers.findSocketRoleByString(dataArg.role);
|
||||
this.socket.emit("authenticated");
|
||||
plugins.beautylog.ok(`socket with >>alias ${this.alias} >>role ${this.role} is authenticated!`);
|
||||
done.resolve(this);
|
||||
} else {
|
||||
this.socket.disconnect();
|
||||
done.reject("not authenticated");
|
||||
};
|
||||
});
|
||||
this.socket.emit("requestAuth");
|
||||
return done.promise;
|
||||
};
|
||||
public alias: string;
|
||||
public side: TSocketConnectionSide;
|
||||
public authenticated: boolean = false;
|
||||
public role: SocketRole;
|
||||
public smartsocketRef: Smartsocket | SmartsocketClient;
|
||||
public socket: SocketIO.Socket | SocketIOClient.Socket;
|
||||
|
||||
/**
|
||||
* listen to function requests
|
||||
*/
|
||||
listenToFunctionRequests() {
|
||||
let done = plugins.q.defer();
|
||||
if(this.authenticated){
|
||||
this.socket.on("function", (dataArg:ISocketFunctionRequestObject) => {
|
||||
let referencedFunction:SocketFunction = this.role.allowedFunctions.find((socketFunctionArg) => {
|
||||
return socketFunctionArg.name === dataArg.functionName
|
||||
});
|
||||
if(referencedFunction !== undefined){
|
||||
referencedFunction.invoke(dataArg);
|
||||
} else {
|
||||
plugins.beautylog.warn("function not existent or out of access scope");
|
||||
};
|
||||
})
|
||||
public eventSubject = new plugins.smartrx.rxjs.Subject<interfaces.TConnectionStatus>();
|
||||
public eventStatus: interfaces.TConnectionStatus = 'new';
|
||||
|
||||
constructor(optionsArg: ISocketConnectionConstructorOptions) {
|
||||
this.alias = optionsArg.alias;
|
||||
this.authenticated = optionsArg.authenticated;
|
||||
this.role = optionsArg.role;
|
||||
this.side = optionsArg.side;
|
||||
this.smartsocketRef = optionsArg.smartsocketHost;
|
||||
this.socket = optionsArg.socket;
|
||||
|
||||
// standard behaviour that is always true
|
||||
allSocketConnections.add(this);
|
||||
|
||||
// handle connection
|
||||
this.socket.on('connect', async () => {
|
||||
this.updateStatus('connected');
|
||||
});
|
||||
this.socket.on('disconnect', async () => {
|
||||
logger.log(
|
||||
'info',
|
||||
`SocketConnection with >alias ${this.alias} on >side ${this.side} disconnected`
|
||||
);
|
||||
await this.disconnect();
|
||||
allSocketConnections.remove(this);
|
||||
});
|
||||
}
|
||||
|
||||
// authenticating --------------------------
|
||||
|
||||
/**
|
||||
* authenticate the socket
|
||||
*/
|
||||
public authenticate() {
|
||||
const done = plugins.smartpromise.defer();
|
||||
this.socket.on('dataAuth', async (dataArg: ISocketConnectionAuthenticationObject) => {
|
||||
logger.log('info', 'received authentication data. now hashing and comparing...');
|
||||
this.socket.removeListener('dataAuth', () => {});
|
||||
if (await SocketRole.checkPasswordForRole(dataArg, this.smartsocketRef)) {
|
||||
// TODO: authenticate password
|
||||
this.alias = dataArg.alias;
|
||||
this.authenticated = true;
|
||||
this.role = SocketRole.getSocketRoleByName(this.smartsocketRef, dataArg.role);
|
||||
this.socket.emit('authenticated');
|
||||
logger.log('ok', `socket with >>alias ${this.alias} >>role ${this.role} is authenticated!`);
|
||||
done.resolve(this);
|
||||
} else {
|
||||
this.authenticated = false;
|
||||
await this.disconnect();
|
||||
done.reject('not authenticated');
|
||||
}
|
||||
});
|
||||
const requestAuthPayload: interfaces.IRequestAuthPayload = {
|
||||
serverShortId: this.smartsocketRef.shortId,
|
||||
};
|
||||
this.socket.emit('requestAuth', requestAuthPayload);
|
||||
return done.promise;
|
||||
}
|
||||
|
||||
// listening -------------------------------
|
||||
|
||||
/**
|
||||
* listen to function requests
|
||||
*/
|
||||
public listenToFunctionRequests() {
|
||||
const done = plugins.smartpromise.defer();
|
||||
if (this.authenticated) {
|
||||
this.socket.on('function', (dataArg: ISocketRequestDataObject<any>) => {
|
||||
// check if requested function is available to the socket's scope
|
||||
// logger.log('info', 'function request received');
|
||||
const referencedFunction: SocketFunction<any> = this.role.allowedFunctions.find(
|
||||
(socketFunctionArg) => {
|
||||
return socketFunctionArg.name === dataArg.funcCallData.funcName;
|
||||
}
|
||||
);
|
||||
if (referencedFunction) {
|
||||
// logger.log('ok', 'function in access scope');
|
||||
const localSocketRequest = new SocketRequest(this.smartsocketRef, {
|
||||
side: 'responding',
|
||||
originSocketConnection: this,
|
||||
shortId: dataArg.shortId,
|
||||
funcCallData: dataArg.funcCallData,
|
||||
});
|
||||
localSocketRequest.createResponse(); // takes care of creating response and sending it back
|
||||
} else {
|
||||
done.reject("socket needs to be authenticated first");
|
||||
};
|
||||
return done.promise;
|
||||
logger.log('warn', 'function not existent or out of access scope');
|
||||
}
|
||||
});
|
||||
this.socket.on('functionResponse', (dataArg: ISocketRequestDataObject<any>) => {
|
||||
// logger.log('info', `received response for request with id ${dataArg.shortId}`);
|
||||
const targetSocketRequest = SocketRequest.getSocketRequestById(
|
||||
this.smartsocketRef,
|
||||
dataArg.shortId
|
||||
);
|
||||
targetSocketRequest.handleResponse(dataArg);
|
||||
});
|
||||
logger.log('info', `now listening to function requests for ${this.alias}`);
|
||||
done.resolve(this);
|
||||
} else {
|
||||
const errMessage = 'socket needs to be authenticated first';
|
||||
logger.log('error', errMessage);
|
||||
done.reject(errMessage);
|
||||
}
|
||||
};
|
||||
return done.promise;
|
||||
}
|
||||
|
||||
// disconnecting ----------------------
|
||||
public async disconnect() {
|
||||
this.socket.disconnect(true);
|
||||
this.updateStatus('disconnected');
|
||||
}
|
||||
|
||||
private updateStatus(statusArg: interfaces.TConnectionStatus) {
|
||||
if (this.eventStatus !== statusArg) {
|
||||
this.eventSubject.next(statusArg);
|
||||
}
|
||||
this.eventStatus = statusArg;
|
||||
}
|
||||
}
|
||||
|
@ -1,63 +1,107 @@
|
||||
import * as plugins from "./smartsocket.plugins";
|
||||
import * as plugins from './smartsocket.plugins';
|
||||
|
||||
// import classes
|
||||
import { Stringmap } from "lik";
|
||||
import { SocketRole } from "./smartsocket.classes.socketrole";
|
||||
import { SocketRole } from './smartsocket.classes.socketrole';
|
||||
import { SocketConnection } from './smartsocket.classes.socketconnection';
|
||||
import { Smartsocket } from './smartsocket.classes.smartsocket';
|
||||
import { SmartsocketClient } from './smartsocket.classes.smartsocketclient';
|
||||
|
||||
// export interfaces
|
||||
|
||||
export interface ISocketFunctionRequestObject {
|
||||
functionName:string,
|
||||
argumentObject:any,
|
||||
shortId:string,
|
||||
responseTimeout?:number
|
||||
};
|
||||
/**
|
||||
* interface of the contructor options of class SocketFunction
|
||||
*/
|
||||
export interface ISocketFunctionConstructorOptions<
|
||||
T extends plugins.typedrequestInterfaces.ITypedRequest
|
||||
> {
|
||||
funcName: T['method'];
|
||||
funcDef: TFuncDef<T>;
|
||||
allowedRoles: SocketRole[]; // all roles that are allowed to execute a SocketFunction
|
||||
}
|
||||
|
||||
export interface ISocketFunctionResponseObject {
|
||||
shortId:string;
|
||||
argumentObject:any;
|
||||
};
|
||||
/**
|
||||
* interface of the Socket Function call, in other words the object that routes a call to a function
|
||||
*/
|
||||
export interface ISocketFunctionCallDataRequest<
|
||||
T extends plugins.typedrequestInterfaces.ITypedRequest
|
||||
> {
|
||||
funcName: T['method'];
|
||||
funcDataArg: T['request'];
|
||||
}
|
||||
|
||||
export interface SocketFunctionOptions {
|
||||
name: string;
|
||||
func: any;
|
||||
roles: SocketRole[]; // all roles that are allowed to execute a SocketFunction
|
||||
};
|
||||
/**
|
||||
* interface of the Socket Function call, in other words the object that routes a call to a function
|
||||
*/
|
||||
export interface ISocketFunctionCallDataResponse<
|
||||
T extends plugins.typedrequestInterfaces.ITypedRequest
|
||||
> {
|
||||
funcName: T['method'];
|
||||
funcDataArg: T['response'];
|
||||
}
|
||||
|
||||
/**
|
||||
* interface for function definition of SocketFunction
|
||||
*/
|
||||
export type TFuncDef<T extends plugins.typedrequestInterfaces.ITypedRequest> = (
|
||||
dataArg: T['request'],
|
||||
connectionArg: SocketConnection
|
||||
) => PromiseLike<T['response']>;
|
||||
|
||||
// export classes
|
||||
|
||||
/**
|
||||
* class SocketFunction respresents a function that can be transparently called using a SocketConnection
|
||||
* class that respresents a function that can be transparently called using a SocketConnection
|
||||
*/
|
||||
export class SocketFunction {
|
||||
name: string;
|
||||
func: any;
|
||||
roles: SocketRole[];
|
||||
export class SocketFunction<T extends plugins.typedrequestInterfaces.ITypedRequest> {
|
||||
// STATIC
|
||||
public static getSocketFunctionByName<Q extends plugins.typedrequestInterfaces.ITypedRequest>(
|
||||
smartsocketRefArg: Smartsocket | SmartsocketClient,
|
||||
functionNameArg: string
|
||||
): SocketFunction<Q> {
|
||||
return smartsocketRefArg.socketFunctions.find((socketFunctionArg) => {
|
||||
return socketFunctionArg.name === functionNameArg;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* the constructor for SocketFunction
|
||||
*/
|
||||
constructor(optionsArg: SocketFunctionOptions) {
|
||||
this.name = optionsArg.name;
|
||||
this.func = optionsArg.func;
|
||||
this.roles = optionsArg.roles;
|
||||
for (let socketRoleArg of this.roles){
|
||||
this._notifyRole(socketRoleArg);
|
||||
}
|
||||
};
|
||||
// INSTANCE
|
||||
public name: string;
|
||||
public funcDef: TFuncDef<T>;
|
||||
public roles: SocketRole[];
|
||||
|
||||
/**
|
||||
* notifies a role about access to this SocketFunction
|
||||
*/
|
||||
private _notifyRole(socketRoleArg:SocketRole){
|
||||
socketRoleArg.addSocketFunction(this);
|
||||
/**
|
||||
* the constructor for SocketFunction
|
||||
*/
|
||||
constructor(optionsArg: ISocketFunctionConstructorOptions<T>) {
|
||||
this.name = optionsArg.funcName;
|
||||
this.funcDef = optionsArg.funcDef;
|
||||
this.roles = optionsArg.allowedRoles;
|
||||
for (const socketRoleArg of this.roles) {
|
||||
this._notifyRole(socketRoleArg);
|
||||
}
|
||||
|
||||
/**
|
||||
* invokes the function of this SocketFunction
|
||||
*/
|
||||
invoke(dataArg:ISocketFunctionRequestObject){
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* invokes the function of this SocketFunction
|
||||
*/
|
||||
public async invoke(
|
||||
dataArg: ISocketFunctionCallDataRequest<T>,
|
||||
socketConnectionArg: SocketConnection
|
||||
): Promise<ISocketFunctionCallDataResponse<T>> {
|
||||
if (dataArg.funcName === this.name) {
|
||||
const funcResponseData: ISocketFunctionCallDataResponse<T> = {
|
||||
funcName: this.name,
|
||||
funcDataArg: await this.funcDef(dataArg.funcDataArg, socketConnectionArg),
|
||||
};
|
||||
return funcResponseData;
|
||||
} else {
|
||||
throw new Error("SocketFunction.name does not match the data argument's .name!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* notifies a role about access to this SocketFunction
|
||||
*/
|
||||
private _notifyRole(socketRoleArg: SocketRole) {
|
||||
socketRoleArg.addSocketFunction(this);
|
||||
}
|
||||
}
|
||||
|
@ -1,43 +1,126 @@
|
||||
import * as plugins from "./smartsocket.plugins";
|
||||
import * as plugins from './smartsocket.plugins';
|
||||
|
||||
// import interfaces
|
||||
import { ISocketFunctionRequestObject, ISocketFunctionResponseObject } from "./smartsocket.classes.socketfunction";
|
||||
import {
|
||||
SocketFunction,
|
||||
ISocketFunctionCallDataRequest,
|
||||
ISocketFunctionCallDataResponse,
|
||||
} from './smartsocket.classes.socketfunction';
|
||||
|
||||
// import classes
|
||||
import { Objectmap } from "lik";
|
||||
import { SocketFunction } from "./smartsocket.classes.socketfunction";
|
||||
import { SocketConnection } from './smartsocket.classes.socketconnection';
|
||||
import { logger } from './smartsocket.logging';
|
||||
import { Smartsocket } from './smartsocket.classes.smartsocket';
|
||||
import { SmartsocketClient } from './smartsocket.classes.smartsocketclient';
|
||||
|
||||
// export interfaces
|
||||
export type TSocketRequestStatus = "new" | "pending" | "finished";
|
||||
export type TSocketRequestSide = "requesting" | "responding";
|
||||
export type TSocketRequestStatus = 'new' | 'pending' | 'finished';
|
||||
export type TSocketRequestSide = 'requesting' | 'responding';
|
||||
|
||||
export interface SocketRequestConstructorOptions {
|
||||
side: TSocketRequestSide;
|
||||
shortid: string;
|
||||
};
|
||||
/**
|
||||
* interface of constructor of class SocketRequest
|
||||
*/
|
||||
export interface ISocketRequestConstructorOptions<
|
||||
T extends plugins.typedrequestInterfaces.ITypedRequest
|
||||
> {
|
||||
side: TSocketRequestSide;
|
||||
originSocketConnection: SocketConnection;
|
||||
shortId: string;
|
||||
funcCallData?: ISocketFunctionCallDataRequest<T>;
|
||||
}
|
||||
|
||||
//export objects
|
||||
export let allRequestingSocketRequests = new Objectmap<SocketRequest>();
|
||||
export let allRespondingSocketRequests = new Objectmap<SocketRequest>();
|
||||
/**
|
||||
* request object that is sent initially and may or may not receive a response
|
||||
*/
|
||||
export interface ISocketRequestDataObject<T extends plugins.typedrequestInterfaces.ITypedRequest> {
|
||||
funcCallData: ISocketFunctionCallDataRequest<T> | ISocketFunctionCallDataResponse<T>;
|
||||
shortId: string;
|
||||
responseTimeout?: number;
|
||||
}
|
||||
|
||||
// export classes
|
||||
export class SocketRequest {
|
||||
status: TSocketRequestStatus = "new";
|
||||
side: TSocketRequestSide;
|
||||
shortid: string;
|
||||
constructor(optionsArg: SocketRequestConstructorOptions) {
|
||||
this.side = optionsArg.side;
|
||||
this.shortid = optionsArg.shortid;
|
||||
if(this.side === "requesting"){
|
||||
allRequestingSocketRequests.add(this);
|
||||
} else {
|
||||
allRespondingSocketRequests.add(this);
|
||||
};
|
||||
};
|
||||
respond(dataArg:ISocketFunctionResponseObject){
|
||||
export class SocketRequest<T extends plugins.typedrequestInterfaces.ITypedRequest> {
|
||||
// STATIC
|
||||
public static getSocketRequestById(
|
||||
smartsocketRef: Smartsocket | SmartsocketClient,
|
||||
shortIdArg: string
|
||||
): SocketRequest<any> {
|
||||
return smartsocketRef.socketRequests.find((socketRequestArg) => {
|
||||
return socketRequestArg.shortid === shortIdArg;
|
||||
});
|
||||
}
|
||||
|
||||
// INSTANCE
|
||||
public status: TSocketRequestStatus = 'new';
|
||||
public side: TSocketRequestSide;
|
||||
public shortid: string;
|
||||
public originSocketConnection: SocketConnection;
|
||||
public funcCallData: ISocketFunctionCallDataRequest<T>;
|
||||
public done = plugins.smartpromise.defer<ISocketFunctionCallDataResponse<T>>();
|
||||
|
||||
public smartsocketRef: Smartsocket | SmartsocketClient;
|
||||
|
||||
constructor(
|
||||
smartsocketRefArg: Smartsocket | SmartsocketClient,
|
||||
optionsArg: ISocketRequestConstructorOptions<T>
|
||||
) {
|
||||
this.smartsocketRef = smartsocketRefArg;
|
||||
this.side = optionsArg.side;
|
||||
this.shortid = optionsArg.shortId;
|
||||
this.funcCallData = optionsArg.funcCallData;
|
||||
this.originSocketConnection = optionsArg.originSocketConnection;
|
||||
this.smartsocketRef.socketRequests.add(this);
|
||||
}
|
||||
|
||||
// requesting --------------------------
|
||||
|
||||
/**
|
||||
* dispatches a socketrequest from the requesting to the receiving side
|
||||
*/
|
||||
public dispatch(): Promise<ISocketFunctionCallDataResponse<T>> {
|
||||
const requestData: ISocketRequestDataObject<T> = {
|
||||
funcCallData: this.funcCallData,
|
||||
shortId: this.shortid,
|
||||
};
|
||||
this.originSocketConnection.socket.emit('function', requestData);
|
||||
return this.done.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* handles the response that is received by the requesting side
|
||||
*/
|
||||
public async handleResponse(responseDataArg: ISocketRequestDataObject<T>) {
|
||||
// logger.log('info', 'handling response!');
|
||||
this.done.resolve(responseDataArg.funcCallData);
|
||||
this.smartsocketRef.socketRequests.remove(this);
|
||||
}
|
||||
|
||||
// responding --------------------------
|
||||
|
||||
/**
|
||||
* creates the response on the responding side
|
||||
*/
|
||||
public async createResponse(): Promise<void> {
|
||||
const targetSocketFunction: SocketFunction<T> = SocketFunction.getSocketFunctionByName(
|
||||
this.smartsocketRef,
|
||||
this.funcCallData.funcName
|
||||
);
|
||||
|
||||
if (!targetSocketFunction) {
|
||||
logger.log('error', `There is no SocketFunction defined for ${this.funcCallData.funcName}`);
|
||||
return;
|
||||
}
|
||||
private _dispatch(){ // note: dispatch is private as it will be fired from the constructor
|
||||
|
||||
}
|
||||
};
|
||||
// logger.log('info', `invoking ${targetSocketFunction.name}`);
|
||||
targetSocketFunction
|
||||
.invoke(this.funcCallData, this.originSocketConnection)
|
||||
.then((resultData) => {
|
||||
// logger.log('info', 'got resultData. Sending it to requesting party.');
|
||||
const responseData: ISocketRequestDataObject<T> = {
|
||||
funcCallData: resultData,
|
||||
shortId: this.shortid,
|
||||
};
|
||||
this.originSocketConnection.socket.emit('functionResponse', responseData);
|
||||
this.smartsocketRef.socketRequests.remove(this);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,34 +1,57 @@
|
||||
import * as plugins from "./smartsocket.plugins";
|
||||
import * as plugins from './smartsocket.plugins';
|
||||
|
||||
// import classes
|
||||
import { Objectmap } from "lik";
|
||||
import { SocketFunction } from "./smartsocket.classes.socketfunction";
|
||||
|
||||
|
||||
export let allSocketRoles = new Objectmap<SocketRole>();
|
||||
|
||||
import { SocketFunction } from './smartsocket.classes.socketfunction';
|
||||
import { Smartsocket } from './smartsocket.classes.smartsocket';
|
||||
import { SmartsocketClient } from './smartsocket.classes.smartsocketclient';
|
||||
import { ISocketConnectionAuthenticationObject } from './smartsocket.classes.socketconnection';
|
||||
|
||||
/**
|
||||
* interface for class SocketRole
|
||||
*/
|
||||
export interface SocketRoleOptions {
|
||||
name: string;
|
||||
passwordHash: string;
|
||||
export interface ISocketRoleOptions {
|
||||
name: string;
|
||||
passwordHash: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* A socketrole defines access to certain routines.
|
||||
*/
|
||||
export class SocketRole {
|
||||
name: string;
|
||||
passwordHash: string;
|
||||
allowedFunctions = new Objectmap<SocketFunction>();
|
||||
constructor(optionsArg: SocketRoleOptions) {
|
||||
this.name = optionsArg.name;
|
||||
this.passwordHash = optionsArg.passwordHash;
|
||||
allSocketRoles.add(this);
|
||||
};
|
||||
addSocketFunction(socketFunctionArg:SocketFunction){
|
||||
this.allowedFunctions.add(socketFunctionArg);
|
||||
}
|
||||
}
|
||||
// STATIC
|
||||
public static getSocketRoleByName(
|
||||
referenceSmartsocket: Smartsocket | SmartsocketClient,
|
||||
socketRoleNameArg: string
|
||||
): SocketRole {
|
||||
return referenceSmartsocket.socketRoles.find((socketRoleArg) => {
|
||||
return socketRoleArg.name === socketRoleNameArg;
|
||||
});
|
||||
}
|
||||
|
||||
public static async checkPasswordForRole(
|
||||
dataArg: ISocketConnectionAuthenticationObject,
|
||||
referenceSmartsocket: Smartsocket | SmartsocketClient
|
||||
): Promise<boolean> {
|
||||
const targetPasswordHash = SocketRole.getSocketRoleByName(referenceSmartsocket, dataArg.role)
|
||||
.passwordHash;
|
||||
const computedCompareHash = await plugins.isohash.sha256FromString(dataArg.password);
|
||||
return targetPasswordHash === computedCompareHash;
|
||||
}
|
||||
|
||||
// INSTANCE
|
||||
public name: string;
|
||||
public passwordHash: string;
|
||||
public allowedFunctions = new plugins.lik.ObjectMap<SocketFunction<any>>();
|
||||
constructor(optionsArg: ISocketRoleOptions) {
|
||||
this.name = optionsArg.name;
|
||||
this.passwordHash = optionsArg.passwordHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* adds the socketfunction to the socketrole
|
||||
* @param socketFunctionArg
|
||||
*/
|
||||
public addSocketFunction(socketFunctionArg: SocketFunction<any>) {
|
||||
this.allowedFunctions.add(socketFunctionArg);
|
||||
}
|
||||
}
|
||||
|
81
ts/smartsocket.classes.socketserver.ts
Normal file
81
ts/smartsocket.classes.socketserver.ts
Normal file
@ -0,0 +1,81 @@
|
||||
import * as plugins from './smartsocket.plugins';
|
||||
import * as pluginsTyped from './smartsocket.pluginstyped';
|
||||
|
||||
// used in case no other server is supplied
|
||||
import { Smartsocket } from './smartsocket.classes.smartsocket';
|
||||
import { logger } from './smartsocket.logging';
|
||||
|
||||
/**
|
||||
* class socketServer
|
||||
* handles the attachment of socketIo to whatever server is in play
|
||||
*/
|
||||
export class SocketServer {
|
||||
private smartsocket: Smartsocket;
|
||||
private httpServer: pluginsTyped.http.Server | pluginsTyped.https.Server;
|
||||
// wether httpServer is standalone
|
||||
private standaloneServer = false;
|
||||
|
||||
constructor(smartSocketInstance: Smartsocket) {
|
||||
this.smartsocket = smartSocketInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* starts the server with another server
|
||||
* also works with an express style server
|
||||
*/
|
||||
public async setExternalServer(
|
||||
serverType: 'smartexpress',
|
||||
serverArg: pluginsTyped.smartexpress.Server
|
||||
) {
|
||||
await serverArg.startedPromise;
|
||||
this.httpServer = serverArg.httpServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the server for socket.io
|
||||
*/
|
||||
public getServerForSocketIo() {
|
||||
if (this.httpServer) {
|
||||
return this.httpServer;
|
||||
} else {
|
||||
const httpModule = this.smartsocket.smartenv.getSafeNodeModule('http');
|
||||
this.httpServer = new httpModule.Server();
|
||||
this.standaloneServer = true;
|
||||
return this.httpServer;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* starts listening to incoming sockets:
|
||||
*/
|
||||
public async start() {
|
||||
const done = plugins.smartpromise.defer();
|
||||
|
||||
// handle http servers
|
||||
// in case an external server has been set "this.standaloneServer" should be false
|
||||
if (this.httpServer && this.standaloneServer) {
|
||||
if (!this.smartsocket.options.port) {
|
||||
logger.log('error', 'there should be a port specifed for smartsocket!');
|
||||
throw new Error('there should be a port specified for smartsocket');
|
||||
}
|
||||
this.httpServer.listen(this.smartsocket.options.port, () => {
|
||||
logger.log(
|
||||
'success',
|
||||
`Server started in standalone mode on ${this.smartsocket.options.port}`
|
||||
);
|
||||
done.resolve();
|
||||
});
|
||||
} else {
|
||||
done.resolve();
|
||||
}
|
||||
|
||||
// nothing else to do if express server is set
|
||||
await done.promise;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* closes the server
|
||||
*/
|
||||
public async stop() {}
|
||||
}
|
3
ts/smartsocket.classes.socketstats.ts
Normal file
3
ts/smartsocket.classes.socketstats.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import * as plugins from './smartsocket.plugins';
|
||||
|
||||
export class SocketStats {}
|
@ -1,14 +0,0 @@
|
||||
import * as plugins from "./smartsocket.plugins";
|
||||
|
||||
// classes
|
||||
import { Smartsocket } from "./smartsocket.classes.smartsocket";
|
||||
import { SocketFunction } from "./smartsocket.classes.socketfunction";
|
||||
import { SocketConnection } from "./smartsocket.classes.socketconnection";
|
||||
import { SocketRole, allSocketRoles } from "./smartsocket.classes.socketrole";
|
||||
|
||||
|
||||
// SocketRole helpers
|
||||
export let findSocketRoleByString = (socketRoleNameArg: string): SocketRole => {
|
||||
return allSocketRoles.find((socketRoleArg) => { return socketRoleArg.name === socketRoleNameArg })
|
||||
};
|
||||
|
3
ts/smartsocket.logging.ts
Normal file
3
ts/smartsocket.logging.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import * as plugins from './smartsocket.plugins';
|
||||
|
||||
export const logger = new plugins.smartlog.ConsoleLog();
|
@ -1,8 +1,27 @@
|
||||
import "typings-global";
|
||||
export import beautylog = require("beautylog");
|
||||
export import lik = require("lik");
|
||||
export import q = require("q");
|
||||
export import shortid = require("shortid");
|
||||
export import socketIo = require("socket.io");
|
||||
export import socketIoClient = require("socket.io-client");
|
||||
export import taskbuffer = require("taskbuffer");
|
||||
// apiglobal scope
|
||||
import * as typedrequestInterfaces from '@apiglobal/typedrequest-interfaces';
|
||||
|
||||
export { typedrequestInterfaces };
|
||||
|
||||
// pushrocks scope
|
||||
import * as isohash from '@pushrocks/isohash';
|
||||
import * as isounique from '@pushrocks/isounique';
|
||||
import * as lik from '@pushrocks/lik';
|
||||
import * as smartenv from '@pushrocks/smartenv';
|
||||
import * as smartlog from '@pushrocks/smartlog';
|
||||
import * as smartdelay from '@pushrocks/smartdelay';
|
||||
import * as smartpromise from '@pushrocks/smartpromise';
|
||||
import * as smarttime from '@pushrocks/smarttime';
|
||||
import * as smartrx from '@pushrocks/smartrx';
|
||||
|
||||
export {
|
||||
isohash,
|
||||
isounique,
|
||||
lik,
|
||||
smartenv,
|
||||
smartlog,
|
||||
smartdelay,
|
||||
smartpromise,
|
||||
smarttime,
|
||||
smartrx,
|
||||
};
|
||||
|
16
ts/smartsocket.pluginstyped.ts
Normal file
16
ts/smartsocket.pluginstyped.ts
Normal file
@ -0,0 +1,16 @@
|
||||
// node native
|
||||
import type http from 'http';
|
||||
import type https from 'https';
|
||||
|
||||
export { http, https };
|
||||
|
||||
// pushrocks scope
|
||||
import type * as smartexpress from '@pushrocks/smartexpress';
|
||||
|
||||
export { smartexpress };
|
||||
|
||||
// third party scope
|
||||
import type socketIo from 'socket.io';
|
||||
import type socketIoClient from 'socket.io-client';
|
||||
|
||||
export { socketIo, socketIoClient };
|
17
tslint.json
Normal file
17
tslint.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"extends": ["tslint:latest", "tslint-config-prettier"],
|
||||
"rules": {
|
||||
"semicolon": [true, "always"],
|
||||
"no-console": false,
|
||||
"ordered-imports": false,
|
||||
"object-literal-sort-keys": false,
|
||||
"member-ordering": {
|
||||
"options":{
|
||||
"order": [
|
||||
"static-method"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultSeverity": "warning"
|
||||
}
|
Reference in New Issue
Block a user