@pathscale/wss-adapter 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/types/index.d.ts +68 -0
- package/dist/types/index.js +2 -0
- package/dist/wssAdapter.d.ts +3 -0
- package/dist/wssAdapter.js +169 -0
- package/package.json +23 -0
- package/tsconfig.json +15 -0
- package/types/index.ts +73 -0
- package/wssAdapter.ts +213 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
interface IService {
|
|
2
|
+
remote: string;
|
|
3
|
+
methods: {
|
|
4
|
+
[methodCode: string]: {
|
|
5
|
+
name: string;
|
|
6
|
+
parameters: string[];
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
interface IServiceConfig extends IService {
|
|
11
|
+
onDisconnect: () => void | null;
|
|
12
|
+
}
|
|
13
|
+
interface IServices {
|
|
14
|
+
[serviceName: string]: IServiceConfig;
|
|
15
|
+
}
|
|
16
|
+
interface IErrors {
|
|
17
|
+
[errorCode: number]: string;
|
|
18
|
+
}
|
|
19
|
+
interface IConfiguration {
|
|
20
|
+
timeout: number;
|
|
21
|
+
services: IServices;
|
|
22
|
+
errors: IErrors;
|
|
23
|
+
onError: (error: {
|
|
24
|
+
error: number;
|
|
25
|
+
message: string;
|
|
26
|
+
}) => void;
|
|
27
|
+
}
|
|
28
|
+
interface IServiceConnect {
|
|
29
|
+
connect<T>(payload: string | string[] | undefined): Promise<T>;
|
|
30
|
+
disconnect: () => void;
|
|
31
|
+
}
|
|
32
|
+
interface IWssAdapter {
|
|
33
|
+
services: {
|
|
34
|
+
[serviceName: string]: IServiceConnect;
|
|
35
|
+
};
|
|
36
|
+
sessions: {
|
|
37
|
+
[serviceName: string]: unknown;
|
|
38
|
+
};
|
|
39
|
+
configure: (configuration: IConfiguration) => void;
|
|
40
|
+
}
|
|
41
|
+
interface ISequence {
|
|
42
|
+
value: number;
|
|
43
|
+
getSeq: () => number;
|
|
44
|
+
decreaseSeq: () => void;
|
|
45
|
+
}
|
|
46
|
+
interface ISessions {
|
|
47
|
+
[serviceName: string]: WebSocket;
|
|
48
|
+
}
|
|
49
|
+
interface IPendingPromises {
|
|
50
|
+
[seq: number]: {
|
|
51
|
+
resolve: (payload: unknown) => void;
|
|
52
|
+
reject: (error: Error) => void;
|
|
53
|
+
toHandler: ReturnType<typeof setTimeout>;
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
interface IStore {
|
|
57
|
+
timeout: number;
|
|
58
|
+
errors: IErrors;
|
|
59
|
+
services: IServices;
|
|
60
|
+
sequence: ISequence;
|
|
61
|
+
sessions: ISessions;
|
|
62
|
+
pendingPromises: IPendingPromises;
|
|
63
|
+
onError: (error: {
|
|
64
|
+
error: number;
|
|
65
|
+
message: string;
|
|
66
|
+
}) => void;
|
|
67
|
+
}
|
|
68
|
+
export { IStore, IWssAdapter, IServiceConfig, IConfiguration, IErrors, IServices, IService };
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* eslint-disable compat/compat */
|
|
3
|
+
/* eslint-disable promise/avoid-new */
|
|
4
|
+
/* eslint-disable @typescript-eslint/no-empty-function */
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
var wssAdapter = {
|
|
7
|
+
services: {},
|
|
8
|
+
sessions: {},
|
|
9
|
+
configure: function () { },
|
|
10
|
+
};
|
|
11
|
+
var store = {
|
|
12
|
+
timeout: 0,
|
|
13
|
+
errors: {},
|
|
14
|
+
services: {},
|
|
15
|
+
sequence: {
|
|
16
|
+
value: 1,
|
|
17
|
+
getSeq: function () {
|
|
18
|
+
store.sequence.value += 1;
|
|
19
|
+
return store.sequence.value;
|
|
20
|
+
},
|
|
21
|
+
decreaseSeq: function () {
|
|
22
|
+
store.sequence.value -= 1;
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
sessions: {},
|
|
26
|
+
pendingPromises: {},
|
|
27
|
+
onError: function () { },
|
|
28
|
+
};
|
|
29
|
+
wssAdapter.configure = function (configuration) {
|
|
30
|
+
var timeout = configuration.timeout, services = configuration.services, errors = configuration.errors, onError = configuration.onError;
|
|
31
|
+
// save some stuff for later retrieval
|
|
32
|
+
store.timeout = timeout;
|
|
33
|
+
store.errors = errors;
|
|
34
|
+
store.services = services;
|
|
35
|
+
store.onError = onError;
|
|
36
|
+
var _loop_1 = function (serviceName, serviceConfig) {
|
|
37
|
+
// construct services objects with two simple functions
|
|
38
|
+
// intended use: `wssAdapter.services.admin.connect([1, 2, 3])` or `wssAdapter.services.auth.connect([1, 2, 3])`
|
|
39
|
+
wssAdapter.services[serviceName] = {
|
|
40
|
+
connect: function (payload) {
|
|
41
|
+
return connectHandler(serviceName, serviceConfig, payload);
|
|
42
|
+
},
|
|
43
|
+
disconnect: function () { return disconnectHandler(serviceName); },
|
|
44
|
+
};
|
|
45
|
+
// construct sessions objects that contain a proxy so you can ask unknown property
|
|
46
|
+
// intended use: `wssAdapter.sessions.admin.updatePassword({ newPassword: 'hotdog6737637' })`
|
|
47
|
+
wssAdapter.sessions[serviceName] = new Proxy({}, {
|
|
48
|
+
get: function (target, methodName) { return function (payload) {
|
|
49
|
+
return sendHandler(serviceName, serviceConfig, methodName, payload);
|
|
50
|
+
}; },
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
for (var _i = 0, _a = Object.entries(services); _i < _a.length; _i++) {
|
|
54
|
+
var _b = _a[_i], serviceName = _b[0], serviceConfig = _b[1];
|
|
55
|
+
_loop_1(serviceName, serviceConfig);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
var connectHandler = function (serviceName, serviceConfig, payload) {
|
|
59
|
+
return new Promise(function (resolve, reject) {
|
|
60
|
+
store.sessions[serviceName] = new WebSocket(serviceConfig.remote, payload);
|
|
61
|
+
store.sessions[serviceName].onmessage = function (event) {
|
|
62
|
+
var _a;
|
|
63
|
+
var response = JSON.parse(event.data);
|
|
64
|
+
console.log(response);
|
|
65
|
+
if (response.params.error) {
|
|
66
|
+
reject(new Error((_a = store.errors[response.params.error]) !== null && _a !== void 0 ? _a : 'Something went wrong'));
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
store.sessions[serviceName].onmessage = receiveHandler;
|
|
70
|
+
resolve(response.params);
|
|
71
|
+
};
|
|
72
|
+
store.sessions[serviceName].onclose = serviceConfig.onDisconnect;
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
var disconnectHandler = function (serviceName) {
|
|
76
|
+
var _a;
|
|
77
|
+
(_a = store.sessions[serviceName]) === null || _a === void 0 ? void 0 : _a.close();
|
|
78
|
+
};
|
|
79
|
+
var sendHandler = function (serviceName, serviceConfig, methodName, params) {
|
|
80
|
+
var _a;
|
|
81
|
+
var methodCode = (_a = Object.entries(serviceConfig.methods)
|
|
82
|
+
.map(function (_a) {
|
|
83
|
+
var code = _a[0], info = _a[1];
|
|
84
|
+
return ({ code: code, info: info });
|
|
85
|
+
})
|
|
86
|
+
.find(function (_a) {
|
|
87
|
+
var info = _a.info;
|
|
88
|
+
return info.name === methodName;
|
|
89
|
+
})) === null || _a === void 0 ? void 0 : _a.code;
|
|
90
|
+
if (!methodCode) {
|
|
91
|
+
throw new Error("method ".concat(methodName, " not available in ").concat(serviceName, " service"));
|
|
92
|
+
}
|
|
93
|
+
if (!Object.keys(params).every(function (param) {
|
|
94
|
+
return serviceConfig.methods[methodCode].parameters.includes(param);
|
|
95
|
+
})) {
|
|
96
|
+
throw new Error("method ".concat(methodCode, " is being called with missing parameters"));
|
|
97
|
+
}
|
|
98
|
+
var purgedParams = {};
|
|
99
|
+
serviceConfig.methods[methodCode].parameters.forEach(function (k) {
|
|
100
|
+
purgedParams[k] = params[k];
|
|
101
|
+
});
|
|
102
|
+
var difference = Object.keys(params).filter(function (x) { return !serviceConfig.methods[methodCode].parameters.includes(x); });
|
|
103
|
+
if (difference.length) {
|
|
104
|
+
throw new Error("method ".concat(methodCode, " is being called with unknow parameters, ").concat(difference));
|
|
105
|
+
}
|
|
106
|
+
var payload = {
|
|
107
|
+
method: Number.parseInt(methodCode),
|
|
108
|
+
seq: store.sequence.getSeq(),
|
|
109
|
+
params: purgedParams,
|
|
110
|
+
};
|
|
111
|
+
console.log("".concat(serviceName, "::").concat(methodName, " sends:"), payload);
|
|
112
|
+
return new Promise(function (resolve, reject) {
|
|
113
|
+
store.sessions[serviceName].send(JSON.stringify(payload));
|
|
114
|
+
// save executor so that when response for this request comes the promise can be resolved
|
|
115
|
+
store.pendingPromises[payload.seq] = {
|
|
116
|
+
resolve: resolve,
|
|
117
|
+
reject: reject,
|
|
118
|
+
toHandler: setTimeout(function () {
|
|
119
|
+
reject(new Error(methodCode.toString() + ' took to long, aborting'));
|
|
120
|
+
}, store.timeout),
|
|
121
|
+
};
|
|
122
|
+
});
|
|
123
|
+
};
|
|
124
|
+
var receiveHandler = function (event) {
|
|
125
|
+
var response = JSON.parse(event.data);
|
|
126
|
+
console.log("app::".concat(response.method, " got:"), response);
|
|
127
|
+
var error = response.method === 0;
|
|
128
|
+
var done = response.method.toString().endsWith('1');
|
|
129
|
+
var resolve = function (payload, code) {
|
|
130
|
+
console.log(code);
|
|
131
|
+
var executor = store.pendingPromises[response.seq];
|
|
132
|
+
clearTimeout(store.pendingPromises[response.seq].toHandler);
|
|
133
|
+
delete store.pendingPromises[response.seq];
|
|
134
|
+
executor.resolve(payload);
|
|
135
|
+
};
|
|
136
|
+
// handle error
|
|
137
|
+
if (error) {
|
|
138
|
+
onError(response);
|
|
139
|
+
}
|
|
140
|
+
else if (done) {
|
|
141
|
+
var code = response.method - 1;
|
|
142
|
+
resolve(response, code);
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
function onError(response) {
|
|
146
|
+
var _a, _b;
|
|
147
|
+
var errorCode = response.params.error;
|
|
148
|
+
var errorMsg = (_a = store.errors[errorCode]) !== null && _a !== void 0 ? _a : 'Something went wrong';
|
|
149
|
+
if ([45349638, 45349637].includes(errorCode)) {
|
|
150
|
+
store.sequence.decreaseSeq();
|
|
151
|
+
console.log('seq has been decreased because of error');
|
|
152
|
+
}
|
|
153
|
+
(_b = store.onError) === null || _b === void 0 ? void 0 : _b.call(store, {
|
|
154
|
+
error: errorCode,
|
|
155
|
+
message: errorMsg,
|
|
156
|
+
});
|
|
157
|
+
// if there was only one executor saved in store.pendingPromises, then it was that request that failed
|
|
158
|
+
if (Object.keys(store.pendingPromises).length === 1) {
|
|
159
|
+
var onlyKey = Number.parseInt(Object.keys(store.pendingPromises)[0]);
|
|
160
|
+
clearTimeout(store.pendingPromises[onlyKey].toHandler);
|
|
161
|
+
store.pendingPromises[onlyKey].reject(new Error(errorMsg));
|
|
162
|
+
delete store.pendingPromises[onlyKey];
|
|
163
|
+
}
|
|
164
|
+
// if there were more than one, there is no way of knowing who failed
|
|
165
|
+
else {
|
|
166
|
+
throw new Error('Unkown request failed');
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
exports.default = wssAdapter;
|
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pathscale/wss-adapter",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Websocket adapter for the Pathscale WSS",
|
|
5
|
+
"main": "dist/wssAdapter.js",
|
|
6
|
+
"types": "dist/wssAdapter.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc"
|
|
9
|
+
},
|
|
10
|
+
"author": "PathScale",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"devDependencies": {
|
|
13
|
+
"typescript": "^4.5.5"
|
|
14
|
+
},
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/skaptox/wss-adapter.git"
|
|
18
|
+
},
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/skaptox/wss-adapter/issues"
|
|
21
|
+
},
|
|
22
|
+
"homepage": "https://github.com/skaptox/wss-adapter#readme"
|
|
23
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "es5",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"lib": ["es2017", "es7", "es6", "dom"],
|
|
6
|
+
"declaration": true,
|
|
7
|
+
"outDir": "dist",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true
|
|
10
|
+
},
|
|
11
|
+
"exclude": [
|
|
12
|
+
"node_modules",
|
|
13
|
+
"dist"
|
|
14
|
+
]
|
|
15
|
+
}
|
package/types/index.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
interface IService {
|
|
2
|
+
remote: string
|
|
3
|
+
methods: {
|
|
4
|
+
[methodCode: string]: {
|
|
5
|
+
name: string
|
|
6
|
+
parameters: string[]
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface IServiceConfig extends IService {
|
|
12
|
+
onDisconnect: () => void | null
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface IServices {
|
|
16
|
+
[serviceName: string]: IServiceConfig
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface IErrors {
|
|
20
|
+
[errorCode: number]: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface IConfiguration {
|
|
24
|
+
timeout: number
|
|
25
|
+
services: IServices
|
|
26
|
+
errors: IErrors
|
|
27
|
+
onError: (error: { error: number; message: string }) => void
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface IServiceConnect {
|
|
31
|
+
connect<T>(payload: string | string[] | undefined): Promise<T>
|
|
32
|
+
disconnect: () => void
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface IWssAdapter {
|
|
36
|
+
services: {
|
|
37
|
+
[serviceName: string]: IServiceConnect
|
|
38
|
+
}
|
|
39
|
+
sessions: {
|
|
40
|
+
[serviceName: string]: unknown
|
|
41
|
+
}
|
|
42
|
+
configure: (configuration: IConfiguration) => void
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
interface ISequence {
|
|
46
|
+
value: number
|
|
47
|
+
getSeq: () => number
|
|
48
|
+
decreaseSeq: () => void
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
interface ISessions {
|
|
52
|
+
[serviceName: string]: WebSocket
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
interface IPendingPromises {
|
|
56
|
+
[seq: number]: {
|
|
57
|
+
resolve: (payload: unknown) => void
|
|
58
|
+
reject: (error: Error) => void
|
|
59
|
+
toHandler: ReturnType<typeof setTimeout>
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
interface IStore {
|
|
64
|
+
timeout: number
|
|
65
|
+
errors: IErrors
|
|
66
|
+
services: IServices
|
|
67
|
+
sequence: ISequence
|
|
68
|
+
sessions: ISessions
|
|
69
|
+
pendingPromises: IPendingPromises
|
|
70
|
+
onError: (error: { error: number; message: string }) => void
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export { IStore, IWssAdapter, IServiceConfig, IConfiguration, IErrors, IServices, IService }
|
package/wssAdapter.ts
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/* eslint-disable compat/compat */
|
|
2
|
+
/* eslint-disable promise/avoid-new */
|
|
3
|
+
/* eslint-disable @typescript-eslint/no-empty-function */
|
|
4
|
+
|
|
5
|
+
import { IStore, IWssAdapter, IServiceConfig } from './types'
|
|
6
|
+
|
|
7
|
+
const wssAdapter: IWssAdapter = {
|
|
8
|
+
services: {},
|
|
9
|
+
sessions: {},
|
|
10
|
+
configure() {},
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const store: IStore = {
|
|
14
|
+
timeout: 0,
|
|
15
|
+
errors: {},
|
|
16
|
+
services: {},
|
|
17
|
+
|
|
18
|
+
sequence: {
|
|
19
|
+
value: 1,
|
|
20
|
+
getSeq() {
|
|
21
|
+
store.sequence.value += 1
|
|
22
|
+
return store.sequence.value
|
|
23
|
+
},
|
|
24
|
+
decreaseSeq() {
|
|
25
|
+
store.sequence.value -= 1
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
sessions: {},
|
|
30
|
+
pendingPromises: {},
|
|
31
|
+
onError() {},
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
wssAdapter.configure = configuration => {
|
|
35
|
+
const { timeout, services, errors, onError } = configuration
|
|
36
|
+
|
|
37
|
+
// save some stuff for later retrieval
|
|
38
|
+
store.timeout = timeout
|
|
39
|
+
store.errors = errors
|
|
40
|
+
store.services = services
|
|
41
|
+
store.onError = onError
|
|
42
|
+
|
|
43
|
+
for (const [serviceName, serviceConfig] of Object.entries(services)) {
|
|
44
|
+
// construct services objects with two simple functions
|
|
45
|
+
// intended use: `wssAdapter.services.admin.connect([1, 2, 3])` or `wssAdapter.services.auth.connect([1, 2, 3])`
|
|
46
|
+
wssAdapter.services[serviceName] = {
|
|
47
|
+
connect: <T>(payload: string | string[] | undefined) =>
|
|
48
|
+
connectHandler<T>(serviceName, serviceConfig, payload),
|
|
49
|
+
disconnect: () => disconnectHandler(serviceName),
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// construct sessions objects that contain a proxy so you can ask unknown property
|
|
53
|
+
// intended use: `wssAdapter.sessions.admin.updatePassword({ newPassword: 'hotdog6737637' })`
|
|
54
|
+
wssAdapter.sessions[serviceName] = new Proxy(
|
|
55
|
+
{},
|
|
56
|
+
{
|
|
57
|
+
get: (target, methodName: string) => (payload: Record<string, unknown>) =>
|
|
58
|
+
sendHandler(serviceName, serviceConfig, methodName, payload),
|
|
59
|
+
},
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const connectHandler = <T>(
|
|
65
|
+
serviceName: string,
|
|
66
|
+
serviceConfig: IServiceConfig,
|
|
67
|
+
payload: string | string[] | undefined,
|
|
68
|
+
) => {
|
|
69
|
+
return new Promise((resolve, reject) => {
|
|
70
|
+
store.sessions[serviceName] = new WebSocket(serviceConfig.remote, payload)
|
|
71
|
+
|
|
72
|
+
store.sessions[serviceName].onmessage = function (event: { data: string }) {
|
|
73
|
+
const response = JSON.parse(event.data)
|
|
74
|
+
console.log(response)
|
|
75
|
+
|
|
76
|
+
if (response.params.error) {
|
|
77
|
+
reject(new Error(store.errors[response.params.error] ?? 'Something went wrong'))
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
store.sessions[serviceName].onmessage = receiveHandler
|
|
82
|
+
resolve(response.params)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
store.sessions[serviceName].onclose = serviceConfig.onDisconnect
|
|
86
|
+
}) as Promise<T>
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const disconnectHandler = (serviceName: string) => {
|
|
90
|
+
store.sessions[serviceName]?.close()
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const sendHandler = (
|
|
94
|
+
serviceName: string,
|
|
95
|
+
serviceConfig: IServiceConfig,
|
|
96
|
+
methodName: string,
|
|
97
|
+
params: Record<string, unknown>,
|
|
98
|
+
) => {
|
|
99
|
+
const methodCode = Object.entries(serviceConfig.methods)
|
|
100
|
+
.map(([code, info]) => ({ code, info }))
|
|
101
|
+
.find(({ info }) => info.name === methodName)?.code
|
|
102
|
+
|
|
103
|
+
if (!methodCode) {
|
|
104
|
+
throw new Error(`method ${methodName} not available in ${serviceName} service`)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (
|
|
108
|
+
!Object.keys(params).every(param =>
|
|
109
|
+
serviceConfig.methods[methodCode].parameters.includes(param),
|
|
110
|
+
)
|
|
111
|
+
) {
|
|
112
|
+
throw new Error(`method ${methodCode} is being called with missing parameters`)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const purgedParams: Record<string, unknown> = {}
|
|
116
|
+
serviceConfig.methods[methodCode].parameters.forEach(k => {
|
|
117
|
+
purgedParams[k] = params[k]
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
const difference = Object.keys(params).filter(
|
|
121
|
+
x => !serviceConfig.methods[methodCode].parameters.includes(x),
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
if (difference.length) {
|
|
125
|
+
throw new Error(`method ${methodCode} is being called with unknow parameters, ${difference}`)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const payload = {
|
|
129
|
+
method: Number.parseInt(methodCode),
|
|
130
|
+
seq: store.sequence.getSeq(),
|
|
131
|
+
params: purgedParams,
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
console.log(`${serviceName}::${methodName} sends:`, payload)
|
|
135
|
+
|
|
136
|
+
return new Promise((resolve, reject) => {
|
|
137
|
+
store.sessions[serviceName].send(JSON.stringify(payload))
|
|
138
|
+
|
|
139
|
+
// save executor so that when response for this request comes the promise can be resolved
|
|
140
|
+
store.pendingPromises[payload.seq] = {
|
|
141
|
+
resolve,
|
|
142
|
+
reject,
|
|
143
|
+
toHandler: setTimeout(() => {
|
|
144
|
+
reject(new Error(methodCode.toString() + ' took to long, aborting'))
|
|
145
|
+
}, store.timeout),
|
|
146
|
+
}
|
|
147
|
+
})
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const receiveHandler = (event: { data: string }) => {
|
|
151
|
+
const response = JSON.parse(event.data)
|
|
152
|
+
console.log(`app::${response.method} got:`, response)
|
|
153
|
+
|
|
154
|
+
const error = response.method === 0
|
|
155
|
+
const done = response.method.toString().endsWith('1')
|
|
156
|
+
|
|
157
|
+
const resolve = (payload: unknown, code: number) => {
|
|
158
|
+
console.log(code)
|
|
159
|
+
const executor = store.pendingPromises[response.seq]
|
|
160
|
+
clearTimeout(store.pendingPromises[response.seq].toHandler)
|
|
161
|
+
delete store.pendingPromises[response.seq]
|
|
162
|
+
executor.resolve(payload)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// handle error
|
|
166
|
+
if (error) {
|
|
167
|
+
onError(response)
|
|
168
|
+
} else if (done) {
|
|
169
|
+
const code = response.method - 1
|
|
170
|
+
resolve(response, code)
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// if it was one of these guys
|
|
175
|
+
// 1) protocol violation
|
|
176
|
+
// 2) malformed request
|
|
177
|
+
// seq must be decreased
|
|
178
|
+
|
|
179
|
+
interface IResponse {
|
|
180
|
+
params: {
|
|
181
|
+
error: number
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function onError(response: IResponse) {
|
|
186
|
+
const { error: errorCode } = response.params
|
|
187
|
+
const errorMsg = store.errors[errorCode] ?? 'Something went wrong'
|
|
188
|
+
|
|
189
|
+
if ([45349638, 45349637].includes(errorCode)) {
|
|
190
|
+
store.sequence.decreaseSeq()
|
|
191
|
+
console.log('seq has been decreased because of error')
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
store.onError?.({
|
|
195
|
+
error: errorCode,
|
|
196
|
+
message: errorMsg,
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
// if there was only one executor saved in store.pendingPromises, then it was that request that failed
|
|
200
|
+
if (Object.keys(store.pendingPromises).length === 1) {
|
|
201
|
+
const onlyKey = Number.parseInt(Object.keys(store.pendingPromises)[0])
|
|
202
|
+
clearTimeout(store.pendingPromises[onlyKey].toHandler)
|
|
203
|
+
store.pendingPromises[onlyKey].reject(new Error(errorMsg))
|
|
204
|
+
delete store.pendingPromises[onlyKey]
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// if there were more than one, there is no way of knowing who failed
|
|
208
|
+
else {
|
|
209
|
+
throw new Error('Unkown request failed')
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export default wssAdapter
|