@litert/televoke 0.4.4 → 0.4.6

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.
Files changed (79) hide show
  1. package/CHANGES.md +12 -0
  2. package/lib/Client/Common.d.ts +1 -1
  3. package/lib/Client/Common.d.ts.map +1 -1
  4. package/lib/Client/HttpClient.d.ts.map +1 -1
  5. package/lib/Client/HttpClient.js +17 -9
  6. package/lib/Client/HttpClient.js.map +1 -1
  7. package/lib/Client/HttpsClient.d.ts.map +1 -1
  8. package/lib/Client/HttpsClient.js +17 -9
  9. package/lib/Client/HttpsClient.js.map +1 -1
  10. package/lib/Client/TCPClient.d.ts +5 -0
  11. package/lib/Client/TCPClient.d.ts.map +1 -1
  12. package/lib/Client/TCPClient.js +8 -4
  13. package/lib/Client/TCPClient.js.map +1 -1
  14. package/lib/Client/TLSClient.d.ts.map +1 -1
  15. package/lib/Client/TLSClient.js +3 -4
  16. package/lib/Client/TLSClient.js.map +1 -1
  17. package/lib/Client/index.js +5 -1
  18. package/lib/Client/index.js.map +1 -1
  19. package/lib/Common/API.d.ts +1 -1
  20. package/lib/Common/API.d.ts.map +1 -1
  21. package/lib/Common/Request.d.ts +1 -1
  22. package/lib/Common/Request.d.ts.map +1 -1
  23. package/lib/Common/Response.js +1 -1
  24. package/lib/Common/Response.js.map +1 -1
  25. package/lib/Common/index.js +5 -1
  26. package/lib/Common/index.js.map +1 -1
  27. package/lib/Encoder/Decoder.d.ts.map +1 -1
  28. package/lib/Encoder/Decoder.js +23 -13
  29. package/lib/Encoder/Decoder.js.map +1 -1
  30. package/lib/Encoder/Encoder.d.ts.map +1 -1
  31. package/lib/Encoder/Encoder.js +4 -4
  32. package/lib/Encoder/Encoder.js.map +1 -1
  33. package/lib/Server/Common/Gateway.d.ts +3 -1
  34. package/lib/Server/Common/Gateway.d.ts.map +1 -1
  35. package/lib/Server/Common/Request.d.ts +2 -1
  36. package/lib/Server/Common/Request.d.ts.map +1 -1
  37. package/lib/Server/Common/Router.d.ts +2 -2
  38. package/lib/Server/Common/Router.d.ts.map +1 -1
  39. package/lib/Server/Common/Server.d.ts +6 -0
  40. package/lib/Server/Common/Server.d.ts.map +1 -1
  41. package/lib/Server/Common/index.js +5 -1
  42. package/lib/Server/Common/index.js.map +1 -1
  43. package/lib/Server/Errors.d.ts +1 -0
  44. package/lib/Server/Errors.d.ts.map +1 -1
  45. package/lib/Server/Errors.js +7 -1
  46. package/lib/Server/Errors.js.map +1 -1
  47. package/lib/Server/Gateways/Http.d.ts +1 -1
  48. package/lib/Server/Gateways/Http.d.ts.map +1 -1
  49. package/lib/Server/Gateways/Http.js +30 -13
  50. package/lib/Server/Gateways/Http.js.map +1 -1
  51. package/lib/Server/Gateways/TCP.d.ts +6 -1
  52. package/lib/Server/Gateways/TCP.d.ts.map +1 -1
  53. package/lib/Server/Gateways/TCP.js +19 -9
  54. package/lib/Server/Gateways/TCP.js.map +1 -1
  55. package/lib/Server/Server.d.ts.map +1 -1
  56. package/lib/Server/Server.js +30 -16
  57. package/lib/Server/Server.js.map +1 -1
  58. package/lib/Server/index.js +5 -1
  59. package/lib/Server/index.js.map +1 -1
  60. package/lib/index.js +5 -1
  61. package/lib/index.js.map +1 -1
  62. package/package.json +7 -9
  63. package/src/lib/Client/Common.ts +2 -1
  64. package/src/lib/Client/HttpClient.ts +19 -16
  65. package/src/lib/Client/HttpsClient.ts +19 -16
  66. package/src/lib/Client/TCPClient.ts +16 -12
  67. package/src/lib/Client/TLSClient.ts +12 -13
  68. package/src/lib/Common/Request.ts +1 -1
  69. package/src/lib/Encoder/Decoder.ts +28 -13
  70. package/src/lib/Encoder/Encoder.ts +4 -5
  71. package/src/lib/Server/Common/Gateway.ts +4 -0
  72. package/src/lib/Server/Common/Request.ts +3 -1
  73. package/src/lib/Server/Common/Router.ts +7 -2
  74. package/src/lib/Server/Common/Server.ts +7 -0
  75. package/src/lib/Server/Errors.ts +7 -0
  76. package/src/lib/Server/Gateways/Http.ts +37 -13
  77. package/src/lib/Server/Gateways/TCP.ts +21 -10
  78. package/src/lib/Server/Server.ts +38 -16
  79. package/src/lib/Server/SimpleRouter.ts +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@litert/televoke",
3
- "version": "0.4.4",
3
+ "version": "0.4.6",
4
4
  "description": "A simple RPC service framework.",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {
@@ -36,14 +36,12 @@
36
36
  "types": "lib/index.d.ts",
37
37
  "typings": "lib/index.d.ts",
38
38
  "devDependencies": {
39
- "@commitlint/cli": "^12.1.4",
40
- "@commitlint/config-conventional": "^12.1.4",
41
- "@types/node": "^16.3.1",
42
- "@typescript-eslint/eslint-plugin": "^4.28.2",
43
- "@typescript-eslint/parser": "^4.28.2",
44
- "eslint": "^7.30.0",
45
- "husky": "^7.0.1",
46
- "typescript": "^4.3.5"
39
+ "@commitlint/cli": "^17.7.2",
40
+ "@commitlint/config-conventional": "^17.6.6",
41
+ "@litert/eslint-plugin-rules": "^0.1.5",
42
+ "@types/node": "^20.8.4",
43
+ "husky": "^8.0.3",
44
+ "typescript": "^5.2.2"
47
45
  },
48
46
  "engines": {
49
47
  "node": ">=12.0.0"
@@ -32,7 +32,8 @@ export interface IResponse<T> extends G.IRawResponse<T> {
32
32
  crt: number;
33
33
  }
34
34
 
35
- export interface IClient<TAPIs extends G.IServiceAPIs = G.IServiceAPIs> extends Events.IObservable<Events.ICallbackDefinitions> {
35
+ export interface IClient<TAPIs extends G.IServiceAPIs = G.IServiceAPIs>
36
+ extends Events.IObservable<Events.ICallbackDefinitions> {
36
37
 
37
38
  connect(): Promise<void>;
38
39
 
@@ -23,17 +23,17 @@ import { Events } from '@litert/observable';
23
23
 
24
24
  class HttpClient extends Events.EventEmitter<Events.ICallbackDefinitions> implements C.IClient {
25
25
 
26
- private _agent: $Http.Agent;
26
+ private readonly _agent: $Http.Agent;
27
27
 
28
28
  public onError!: any;
29
29
 
30
30
  public constructor(
31
- private _host: string,
32
- private _port: number,
33
- private _ridGenerator: C.IRIDGenerator,
34
- private _path: string = '/',
35
- private _timeout: number = 30000,
36
- private _apiNameWrapper?: (name: string) => string
31
+ private readonly _host: string,
32
+ private readonly _port: number,
33
+ private readonly _ridGenerator: C.IRIDGenerator,
34
+ private readonly _path: string = '/',
35
+ private readonly _timeout: number = 30000,
36
+ private readonly _apiNameWrapper?: (name: string) => string
37
37
  ) {
38
38
 
39
39
  super();
@@ -75,7 +75,7 @@ class HttpClient extends Events.EventEmitter<Events.ICallbackDefinitions> implem
75
75
 
76
76
  if (length > G.MAX_PACKET_SIZE) {
77
77
 
78
- return reject(new GE.E_PACKET_TOO_LARGE());
78
+ reject(new GE.E_PACKET_TOO_LARGE()); return;
79
79
  }
80
80
 
81
81
  const req = $Http.request({
@@ -85,21 +85,22 @@ class HttpClient extends Events.EventEmitter<Events.ICallbackDefinitions> implem
85
85
  agent: this._agent,
86
86
  method: 'POST',
87
87
  headers: {
88
- 'content-length': Buffer.byteLength(content)
88
+ 'content-length': Buffer.byteLength(content),
89
+ 'x-tv-ver': 1
89
90
  },
90
91
  timeout: this._timeout
91
92
  }, (resp) => {
92
93
 
93
94
  if (!resp.headers['content-length']) {
94
95
 
95
- return reject(new E.E_INVALID_RESPONSE());
96
+ reject(new E.E_INVALID_RESPONSE()); return;
96
97
  }
97
98
 
98
99
  const length = parseInt(resp.headers['content-length']);
99
100
 
100
101
  if (!Number.isSafeInteger(length) || length > G.MAX_PACKET_SIZE) { // Maximum request packet is 64MB
101
102
 
102
- return reject(new GE.E_PACKET_TOO_LARGE());
103
+ reject(new GE.E_PACKET_TOO_LARGE()); return;
103
104
  }
104
105
 
105
106
  const buf = Buffer.allocUnsafe(length);
@@ -118,7 +119,7 @@ class HttpClient extends Events.EventEmitter<Events.ICallbackDefinitions> implem
118
119
  resp.removeAllListeners('data');
119
120
  resp.destroy();
120
121
 
121
- return reject(new GE.E_INVALID_PACKET());
122
+ reject(new GE.E_INVALID_PACKET()); return;
122
123
  }
123
124
 
124
125
  chunk.copy(buf, index);
@@ -133,7 +134,7 @@ class HttpClient extends Events.EventEmitter<Events.ICallbackDefinitions> implem
133
134
  }
134
135
  catch {
135
136
 
136
- return reject(new GE.E_INVALID_PACKET());
137
+ reject(new GE.E_INVALID_PACKET()); return;
137
138
  }
138
139
 
139
140
  const data = rawData as C.IResponse<any>;
@@ -168,9 +169,11 @@ class HttpClient extends Events.EventEmitter<Events.ICallbackDefinitions> implem
168
169
  });
169
170
  });
170
171
 
171
- req.once('timeout', () => reject(new E.E_REQUEST_TIMEOUT({
172
- metadata: { api, requestId: rid, time: Date.now(), details: null }
173
- })));
172
+ req.once('timeout', () => {
173
+ reject(new E.E_REQUEST_TIMEOUT({
174
+ metadata: { api, requestId: rid, time: Date.now(), details: null }
175
+ }));
176
+ });
174
177
 
175
178
  req.once('error', reject);
176
179
 
@@ -23,17 +23,17 @@ import { Events } from '@litert/observable';
23
23
 
24
24
  class HttpsClient extends Events.EventEmitter<Events.ICallbackDefinitions> implements C.IClient {
25
25
 
26
- private _agent: $Https.Agent;
26
+ private readonly _agent: $Https.Agent;
27
27
 
28
28
  public onError!: any;
29
29
 
30
30
  public constructor(
31
- private _host: string,
32
- private _port: number,
33
- private _ridGenerator: C.IRIDGenerator,
34
- private _path: string = '',
35
- private _timeout: number = 30000,
36
- private _apiNameWrapper?: (name: string) => string,
31
+ private readonly _host: string,
32
+ private readonly _port: number,
33
+ private readonly _ridGenerator: C.IRIDGenerator,
34
+ private readonly _path: string = '',
35
+ private readonly _timeout: number = 30000,
36
+ private readonly _apiNameWrapper?: (name: string) => string,
37
37
  tlsAgentOptions?: $Https.AgentOptions
38
38
  ) {
39
39
 
@@ -78,7 +78,7 @@ class HttpsClient extends Events.EventEmitter<Events.ICallbackDefinitions> imple
78
78
 
79
79
  if (length > G.MAX_PACKET_SIZE) {
80
80
 
81
- return reject(new GE.E_PACKET_TOO_LARGE());
81
+ reject(new GE.E_PACKET_TOO_LARGE()); return;
82
82
  }
83
83
 
84
84
  const req = $Https.request({
@@ -88,21 +88,22 @@ class HttpsClient extends Events.EventEmitter<Events.ICallbackDefinitions> imple
88
88
  agent: this._agent,
89
89
  method: 'POST',
90
90
  headers: {
91
- 'content-length': Buffer.byteLength(content)
91
+ 'content-length': Buffer.byteLength(content),
92
+ 'x-tv-ver': 1
92
93
  },
93
94
  timeout: this._timeout
94
95
  }, (resp) => {
95
96
 
96
97
  if (!resp.headers['content-length']) {
97
98
 
98
- return reject(new E.E_INVALID_RESPONSE());
99
+ reject(new E.E_INVALID_RESPONSE()); return;
99
100
  }
100
101
 
101
102
  const length = parseInt(resp.headers['content-length']);
102
103
 
103
104
  if (!Number.isSafeInteger(length) || length > G.MAX_PACKET_SIZE) { // Maximum request packet is 64MB
104
105
 
105
- return reject(new GE.E_PACKET_TOO_LARGE());
106
+ reject(new GE.E_PACKET_TOO_LARGE()); return;
106
107
  }
107
108
 
108
109
  const buf = Buffer.allocUnsafe(length);
@@ -121,7 +122,7 @@ class HttpsClient extends Events.EventEmitter<Events.ICallbackDefinitions> imple
121
122
  resp.removeAllListeners('data');
122
123
  resp.destroy();
123
124
 
124
- return reject(new GE.E_INVALID_PACKET());
125
+ reject(new GE.E_INVALID_PACKET()); return;
125
126
  }
126
127
 
127
128
  chunk.copy(buf, index);
@@ -136,7 +137,7 @@ class HttpsClient extends Events.EventEmitter<Events.ICallbackDefinitions> imple
136
137
  }
137
138
  catch {
138
139
 
139
- return reject(new GE.E_INVALID_PACKET());
140
+ reject(new GE.E_INVALID_PACKET()); return;
140
141
  }
141
142
 
142
143
  const data = rawData as C.IResponse<any>;
@@ -171,9 +172,11 @@ class HttpsClient extends Events.EventEmitter<Events.ICallbackDefinitions> imple
171
172
  });
172
173
  });
173
174
 
174
- req.once('timeout', () => reject(new E.E_REQUEST_TIMEOUT({
175
- metadata: { api, requestId: rid, time: Date.now(), details: null }
176
- })));
175
+ req.once('timeout', () => {
176
+ reject(new E.E_REQUEST_TIMEOUT({
177
+ metadata: { api, requestId: rid, time: Date.now(), details: null }
178
+ }));
179
+ });
177
180
 
178
181
  req.once('error', reject);
179
182
 
@@ -17,11 +17,10 @@
17
17
  import * as $Net from 'net';
18
18
  import * as C from './Common';
19
19
  import * as G from '../Common';
20
- import { Promises } from '@litert/observable';
20
+ import { Promises, Events } from '@litert/observable';
21
21
  import * as E from './Errors';
22
22
  import { createDecoder } from '../Encoder/Decoder';
23
23
  import { createEncoder } from '../Encoder/Encoder';
24
- import { Events } from '@litert/observable';
25
24
 
26
25
  enum EStatus {
27
26
 
@@ -48,7 +47,7 @@ interface IRequest {
48
47
 
49
48
  class TCPClient extends Events.EventEmitter<Events.ICallbackDefinitions> implements C.IClient {
50
49
 
51
- private static _$promises = Promises.getGlobalFactory();
50
+ private static readonly _$promises = Promises.getGlobalFactory();
52
51
 
53
52
  private static _$clientCounter = 0;
54
53
 
@@ -56,11 +55,11 @@ class TCPClient extends Events.EventEmitter<Events.ICallbackDefinitions> impleme
56
55
 
57
56
  private _status: EStatus = EStatus.IDLE;
58
57
 
59
- private _clientId: number = TCPClient._$clientCounter++;
58
+ private readonly _clientId: number = TCPClient._$clientCounter++;
60
59
 
61
- private _connPrId: string;
60
+ private readonly _connPrId: string;
62
61
 
63
- private _closePrId: string;
62
+ private readonly _closePrId: string;
64
63
 
65
64
  private _sent: Record<string, IRequest> = {};
66
65
 
@@ -70,14 +69,14 @@ class TCPClient extends Events.EventEmitter<Events.ICallbackDefinitions> impleme
70
69
 
71
70
  private _sendingQty: number = 0;
72
71
 
73
- private _encoder = createEncoder();
72
+ private readonly _encoder = createEncoder();
74
73
 
75
74
  public constructor(
76
- private _host: string,
77
- private _port: number,
78
- private _ridGenerator: C.IRIDGenerator,
79
- private _timeout: number = 30000,
80
- private _apiNameWrapper?: (name: string) => string
75
+ private readonly _host: string,
76
+ private readonly _port: number,
77
+ private readonly _ridGenerator: C.IRIDGenerator,
78
+ private readonly _timeout: number = 30000,
79
+ private readonly _apiNameWrapper?: (name: string) => string
81
80
  ) {
82
81
 
83
82
  super();
@@ -404,6 +403,11 @@ export interface ITCPClientOptions {
404
403
  apiNameWrapper?: (name: string) => string;
405
404
  }
406
405
 
406
+ /**
407
+ * Create a client of TCP-base televoke/1 protocol.
408
+ *
409
+ * @deprecated This legacy TCP-based televoke/1 protocol is no longer maintained, and will be removed in v2.0.0
410
+ */
407
411
  export function createTCPClient<TAPIs extends G.IServiceAPIs>(opts: ITCPClientOptions): C.IClient<TAPIs> {
408
412
 
409
413
  return new TCPClient(
@@ -17,11 +17,10 @@
17
17
  import * as $TLS from 'tls';
18
18
  import * as C from './Common';
19
19
  import * as G from '../Common';
20
- import { Promises } from '@litert/observable';
20
+ import { Promises, Events } from '@litert/observable';
21
21
  import * as E from './Errors';
22
22
  import { createDecoder } from '../Encoder/Decoder';
23
23
  import { createEncoder } from '../Encoder/Encoder';
24
- import { Events } from '@litert/observable';
25
24
 
26
25
  enum EStatus {
27
26
 
@@ -48,7 +47,7 @@ interface IRequest {
48
47
 
49
48
  class TLSClient extends Events.EventEmitter<Events.ICallbackDefinitions> implements C.IClient {
50
49
 
51
- private static _$promises = Promises.getGlobalFactory();
50
+ private static readonly _$promises = Promises.getGlobalFactory();
52
51
 
53
52
  private static _$clientCounter = 0;
54
53
 
@@ -56,11 +55,11 @@ class TLSClient extends Events.EventEmitter<Events.ICallbackDefinitions> impleme
56
55
 
57
56
  private _status: EStatus = EStatus.IDLE;
58
57
 
59
- private _clientId: number = TLSClient._$clientCounter++;
58
+ private readonly _clientId: number = TLSClient._$clientCounter++;
60
59
 
61
- private _connPrId: string;
60
+ private readonly _connPrId: string;
62
61
 
63
- private _closePrId: string;
62
+ private readonly _closePrId: string;
64
63
 
65
64
  private _sent: Record<string, IRequest> = {};
66
65
 
@@ -70,15 +69,15 @@ class TLSClient extends Events.EventEmitter<Events.ICallbackDefinitions> impleme
70
69
 
71
70
  private _sendingQty: number = 0;
72
71
 
73
- private _encoder = createEncoder();
72
+ private readonly _encoder = createEncoder();
74
73
 
75
74
  public constructor(
76
- private _host: string,
77
- private _port: number,
78
- private _ridGenerator: C.IRIDGenerator,
79
- private _timeout: number = 30000,
80
- private _apiNameWrapper?: (name: string) => string,
81
- private _tlsOptions?: $TLS.ConnectionOptions
75
+ private readonly _host: string,
76
+ private readonly _port: number,
77
+ private readonly _ridGenerator: C.IRIDGenerator,
78
+ private readonly _timeout: number = 30000,
79
+ private readonly _apiNameWrapper?: (name: string) => string,
80
+ private readonly _tlsOptions?: $TLS.ConnectionOptions
82
81
  ) {
83
82
 
84
83
  super();
@@ -14,7 +14,7 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
- export interface IRawRequest<T extends any = any> {
17
+ export interface IRawRequest<T = any> {
18
18
 
19
19
  ttl: number;
20
20
 
@@ -37,7 +37,7 @@ class Decoder implements C.IDecoder<any> {
37
37
 
38
38
  private _packetLength!: number;
39
39
 
40
- private _plBuf: Buffer = Buffer.allocUnsafe(4);
40
+ private readonly _plBuf: Buffer = Buffer.allocUnsafe(8);
41
41
 
42
42
  private _plBufLength: number = 0;
43
43
 
@@ -72,7 +72,7 @@ class Decoder implements C.IDecoder<any> {
72
72
 
73
73
  try {
74
74
 
75
- data = JSON.parse(chunk.slice(0, this._packetLength).toString());
75
+ data = JSON.parse(chunk.subarray(0, this._packetLength).toString());
76
76
  }
77
77
  catch (e) {
78
78
 
@@ -81,7 +81,7 @@ class Decoder implements C.IDecoder<any> {
81
81
  return;
82
82
  }
83
83
 
84
- chunk = chunk.slice(this._packetLength);
84
+ chunk = chunk.subarray(this._packetLength);
85
85
  this.reset();
86
86
 
87
87
  try {
@@ -98,15 +98,15 @@ class Decoder implements C.IDecoder<any> {
98
98
 
99
99
  if (chunk.length + this._bufLength >= this._packetLength) {
100
100
 
101
- let restLength = this._packetLength - this._bufLength;
101
+ const restLength = this._packetLength - this._bufLength;
102
102
  chunk.copy(this._buf, this._bufLength, 0, this._packetLength - this._bufLength);
103
- chunk = chunk.slice(restLength);
103
+ chunk = chunk.subarray(restLength);
104
104
 
105
105
  let data: any;
106
106
 
107
107
  try {
108
108
 
109
- data = JSON.parse(this._buf.slice(0, this._packetLength).toString());
109
+ data = JSON.parse(this._buf.subarray(0, this._packetLength).toString());
110
110
  }
111
111
  catch (e) {
112
112
 
@@ -137,13 +137,21 @@ class Decoder implements C.IDecoder<any> {
137
137
 
138
138
  if (this._plBufLength) {
139
139
 
140
- if (this._plBufLength + chunk.byteLength >= 4) {
140
+ if (this._plBufLength + chunk.byteLength >= 8) {
141
141
 
142
- chunk.copy(this._plBuf, this._plBufLength, 0, 4 - this._plBufLength);
142
+ chunk.copy(this._plBuf, this._plBufLength, 0, 8 - this._plBufLength);
143
+
144
+ chunk = chunk.subarray(8 - this._plBufLength);
145
+
146
+ if (this._plBuf.readUInt32LE(0) !== 1) {
147
+
148
+ this.onProtocolError(new GE.E_INVALID_PACKET());
149
+ this.reset();
150
+ return;
151
+ }
143
152
 
144
- chunk = chunk.slice(4 - this._plBufLength);
145
153
  this._plBufLength = 0;
146
- this._packetLength = this._plBuf.readUInt32LE(0);
154
+ this._packetLength = this._plBuf.readUInt32LE(4);
147
155
  }
148
156
  else {
149
157
 
@@ -155,10 +163,17 @@ class Decoder implements C.IDecoder<any> {
155
163
  }
156
164
  else {
157
165
 
158
- if (chunk.length >= 4) {
166
+ if (chunk.length >= 8) {
167
+
168
+ if (chunk.readUInt32LE(0) !== 1) {
169
+
170
+ this.onProtocolError(new GE.E_INVALID_PACKET());
171
+ this.reset();
172
+ return;
173
+ }
159
174
 
160
- this._packetLength = chunk.readUInt32LE(0);
161
- chunk = chunk.slice(4);
175
+ this._packetLength = chunk.readUInt32LE(4);
176
+ chunk = chunk.subarray(8);
162
177
  this._plBufLength = 0;
163
178
  }
164
179
  else {
@@ -22,16 +22,15 @@ class Encoder implements C.IEncoder {
22
22
 
23
23
  content = JSON.stringify(content);
24
24
 
25
- const contentLength = Buffer.byteLength(content);
25
+ const ret = Buffer.allocUnsafe(8);
26
26
 
27
- const ret = Buffer.allocUnsafe(contentLength + 4);
28
-
29
- ret.writeUInt32LE(contentLength, 0);
30
- ret.write(content, 4);
27
+ ret.writeUInt32LE(1, 0);
28
+ ret.writeUInt32LE(Buffer.byteLength(content), 4);
31
29
 
32
30
  if (socket.writable) {
33
31
 
34
32
  socket.write(ret);
33
+ socket.write(content);
35
34
  }
36
35
  }
37
36
  }
@@ -20,6 +20,10 @@ export type IReplyCallbak = (data: IRawResponse) => void;
20
20
 
21
21
  export interface IGateway {
22
22
 
23
+ readonly host: string;
24
+
25
+ readonly port: number;
26
+
23
27
  onRequest?: (
24
28
  request: IRawRequest,
25
29
  reply: IReplyCallbak
@@ -16,7 +16,9 @@
16
16
 
17
17
  import { IRawRequest } from '../../Common';
18
18
 
19
- export interface IRequest<T extends any = any> extends IRawRequest<T> {
19
+ export interface IRequest<T = any> extends IRawRequest<T> {
20
20
 
21
21
  srt: number;
22
+
23
+ ip: string;
22
24
  }
@@ -16,9 +16,14 @@
16
16
 
17
17
  import { IRequest } from './Request';
18
18
 
19
- export type IHandler<TAPI extends (...args: any[]) => any> = (...args: Parameters<TAPI>) => ReturnType<TAPI> | Promise<ReturnType<TAPI>>;
19
+ export type IHandler<TApi extends (...args: any[]) => any> = (
20
+ ...args: Parameters<TApi>
21
+ ) => ReturnType<TApi> | Promise<ReturnType<TApi>>;
20
22
 
21
- export type IHandlerEx<TAPI extends (...args: any[]) => any> = (req: IRequest<Parameters<TAPI>>, ...args: Parameters<TAPI>) => ReturnType<TAPI> | Promise<ReturnType<TAPI>>;
23
+ export type IHandlerEx<TApi extends (...args: any[]) => any> = (
24
+ req: IRequest<Parameters<TApi>>,
25
+ ...args: Parameters<TApi>
26
+ ) => ReturnType<TApi> | Promise<ReturnType<TApi>>;
22
27
 
23
28
  export interface IRouter {
24
29
 
@@ -35,6 +35,13 @@ export interface IServer extends Events.IObservable<IServerEvents> {
35
35
  */
36
36
  addGateway(name: string, gateway: IGateway): this;
37
37
 
38
+ /**
39
+ * Get a mounted gateway by name.
40
+ *
41
+ * @param name The name of the gateway.
42
+ */
43
+ getGateway(name: string): IGateway;
44
+
38
45
  /**
39
46
  * Unmount a gateway.
40
47
  *
@@ -71,3 +71,10 @@ export const E_GATEWAY_BUSY = errorRegistry.register({
71
71
  metadata: {},
72
72
  type: 'public'
73
73
  });
74
+
75
+ export const E_GATEWAY_NOT_FOUND = errorRegistry.register({
76
+ name: 'gateway_not_found',
77
+ message: 'No such a gateway.',
78
+ metadata: {},
79
+ type: 'public'
80
+ });
@@ -14,6 +14,7 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
+ import * as $Net from 'net';
17
18
  import * as C from '../Common';
18
19
  import * as G from '../../Common';
19
20
  import * as E from '../Errors';
@@ -27,9 +28,28 @@ enum EStatus {
27
28
  CLOSING,
28
29
  }
29
30
 
31
+ const INVALID_REQUEST_RESPONSE = Buffer.from('{"rid":"null","body":INVALID REQUEST,"sst":1698886839989,"srt":0,"code":4}');
32
+
33
+ function refuseBadRequest(resp: $Http.ServerResponse): void {
34
+
35
+ try {
36
+
37
+ resp.writeHead(400, {
38
+ 'content-length': INVALID_REQUEST_RESPONSE.byteLength,
39
+ });
40
+ const socket = resp.socket!;
41
+ resp.end(INVALID_REQUEST_RESPONSE);
42
+ socket.destroy();
43
+ }
44
+ catch {
45
+
46
+ // do nothing.
47
+ }
48
+ }
49
+
30
50
  class HttpGateway implements C.IGateway {
31
51
 
32
- private _server: $Http.Server = $Http.createServer(this._onRequest.bind(this));
52
+ private readonly _server: $Http.Server = $Http.createServer(this._onRequest.bind(this));
33
53
 
34
54
  private _status: EStatus = EStatus.IDLE;
35
55
 
@@ -41,16 +61,16 @@ class HttpGateway implements C.IGateway {
41
61
  ) => void;
42
62
 
43
63
  public constructor(
44
- private _host: string,
45
- private _port: number
64
+ public host: string,
65
+ public port: number,
66
+ private readonly _backlog?: number,
46
67
  ) { }
47
68
 
48
69
  private _onRequest(req: $Http.IncomingMessage, resp: $Http.ServerResponse): void {
49
70
 
50
71
  if (req.method !== 'POST' || !req.headers['content-length']) {
51
72
 
52
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
53
- resp.socket!.destroy();
73
+ refuseBadRequest(resp);
54
74
  return;
55
75
  }
56
76
 
@@ -58,8 +78,7 @@ class HttpGateway implements C.IGateway {
58
78
 
59
79
  if (!Number.isSafeInteger(length) || length > G.MAX_PACKET_SIZE) { // Maximum request packet is 64MB
60
80
 
61
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
62
- resp.socket!.destroy();
81
+ refuseBadRequest(resp);
63
82
  return;
64
83
  }
65
84
 
@@ -79,7 +98,7 @@ class HttpGateway implements C.IGateway {
79
98
 
80
99
  req.removeAllListeners('end');
81
100
  req.removeAllListeners('data');
82
- req.destroy();
101
+ refuseBadRequest(resp);
83
102
  return;
84
103
  }
85
104
 
@@ -91,11 +110,12 @@ class HttpGateway implements C.IGateway {
91
110
  try {
92
111
 
93
112
  input = JSON.parse(buf as any);
113
+ input.ip = (req.socket.address() as any).address;
94
114
  }
95
115
  catch (e) {
96
116
 
117
+ refuseBadRequest(resp);
97
118
  this.onError(e);
98
- req.destroy();
99
119
  return;
100
120
  }
101
121
 
@@ -130,11 +150,15 @@ class HttpGateway implements C.IGateway {
130
150
 
131
151
  return new Promise((resolve, reject) => {
132
152
 
133
- this._server.listen(this._port, this._host)
153
+ this._server.listen(this.port, this.host, this._backlog)
134
154
  .once('listening', () => {
135
155
 
136
156
  this._server.removeAllListeners('error');
137
157
  this._status = EStatus.WORKING;
158
+ if (this.port === 0) {
159
+
160
+ this.port = (this._server.address() as $Net.AddressInfo).port;
161
+ }
138
162
  resolve();
139
163
  })
140
164
  .once('error', (e) => {
@@ -167,13 +191,13 @@ class HttpGateway implements C.IGateway {
167
191
  case EStatus.WORKING:
168
192
  return new Promise((resolve) => {
169
193
 
170
- this._server.close(() => resolve());
194
+ this._server.close(() => { resolve(); });
171
195
  });
172
196
  }
173
197
  }
174
198
  }
175
199
 
176
- export function createHttpGateway(host: string, port: number): C.IGateway {
200
+ export function createHttpGateway(host: string, port: number, backlog?: number): C.IGateway {
177
201
 
178
- return new HttpGateway(host, port);
202
+ return new HttpGateway(host, port, backlog);
179
203
  }