@tachybase/module-multi-app 0.23.8
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/.turbo/turbo-build.log +14 -0
- package/README.md +34 -0
- package/README.zh-CN.md +34 -0
- package/client.d.ts +1 -0
- package/client.js +1 -0
- package/dist/client/AppManager.d.ts +2 -0
- package/dist/client/AppNameInput.d.ts +2 -0
- package/dist/client/MultiAppBlockInitializer.d.ts +2 -0
- package/dist/client/MultiAppManagerProvider.d.ts +2 -0
- package/dist/client/MultiAppManagerProvider.style.d.ts +5 -0
- package/dist/client/Settings.d.ts +2 -0
- package/dist/client/index.d.ts +6 -0
- package/dist/client/index.js +1 -0
- package/dist/client/settings/schemas/applications.d.ts +13 -0
- package/dist/client/utils.d.ts +4 -0
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +27 -0
- package/dist/externalVersion.js +16 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +39 -0
- package/dist/locale/en-US.json +27 -0
- package/dist/locale/es-ES.json +9 -0
- package/dist/locale/ko_KR.json +11 -0
- package/dist/locale/pt-BR.json +9 -0
- package/dist/locale/zh-CN.json +27 -0
- package/dist/node_modules/mariadb/LICENSE +502 -0
- package/dist/node_modules/mariadb/callback.js +41 -0
- package/dist/node_modules/mariadb/lib/cmd/batch-bulk.js +278 -0
- package/dist/node_modules/mariadb/lib/cmd/batch-rewrite.js +372 -0
- package/dist/node_modules/mariadb/lib/cmd/change-user.js +149 -0
- package/dist/node_modules/mariadb/lib/cmd/class/ok-packet.js +17 -0
- package/dist/node_modules/mariadb/lib/cmd/column-definition.js +102 -0
- package/dist/node_modules/mariadb/lib/cmd/command.js +168 -0
- package/dist/node_modules/mariadb/lib/cmd/common-binary-cmd.js +327 -0
- package/dist/node_modules/mariadb/lib/cmd/common-text-cmd.js +427 -0
- package/dist/node_modules/mariadb/lib/cmd/handshake/auth/caching-sha2-password-auth.js +168 -0
- package/dist/node_modules/mariadb/lib/cmd/handshake/auth/clear-password-auth.js +23 -0
- package/dist/node_modules/mariadb/lib/cmd/handshake/auth/ed25519-password-auth.js +761 -0
- package/dist/node_modules/mariadb/lib/cmd/handshake/auth/native-password-auth.js +55 -0
- package/dist/node_modules/mariadb/lib/cmd/handshake/auth/pam-password-auth.js +58 -0
- package/dist/node_modules/mariadb/lib/cmd/handshake/auth/plugin-auth.js +19 -0
- package/dist/node_modules/mariadb/lib/cmd/handshake/auth/sha256-password-auth.js +142 -0
- package/dist/node_modules/mariadb/lib/cmd/handshake/client-capabilities.js +74 -0
- package/dist/node_modules/mariadb/lib/cmd/handshake/client-handshake-response.js +126 -0
- package/dist/node_modules/mariadb/lib/cmd/handshake/handshake.js +292 -0
- package/dist/node_modules/mariadb/lib/cmd/handshake/initial-handshake.js +74 -0
- package/dist/node_modules/mariadb/lib/cmd/handshake/ssl-request.js +29 -0
- package/dist/node_modules/mariadb/lib/cmd/ping.js +52 -0
- package/dist/node_modules/mariadb/lib/cmd/query.js +255 -0
- package/dist/node_modules/mariadb/lib/cmd/quit.js +28 -0
- package/dist/node_modules/mariadb/lib/cmd/reset.js +54 -0
- package/dist/node_modules/mariadb/lib/cmd/resultset.js +607 -0
- package/dist/node_modules/mariadb/lib/cmd/stream.js +45 -0
- package/dist/node_modules/mariadb/lib/config/connection-options.js +258 -0
- package/dist/node_modules/mariadb/lib/config/pool-cluster-options.js +19 -0
- package/dist/node_modules/mariadb/lib/config/pool-options.js +47 -0
- package/dist/node_modules/mariadb/lib/connection-callback.js +160 -0
- package/dist/node_modules/mariadb/lib/connection.js +1460 -0
- package/dist/node_modules/mariadb/lib/const/capabilities.js +64 -0
- package/dist/node_modules/mariadb/lib/const/collations.js +473 -0
- package/dist/node_modules/mariadb/lib/const/connection_status.js +13 -0
- package/dist/node_modules/mariadb/lib/const/error-code.js +1282 -0
- package/dist/node_modules/mariadb/lib/const/field-detail.js +35 -0
- package/dist/node_modules/mariadb/lib/const/field-type.js +71 -0
- package/dist/node_modules/mariadb/lib/const/server-status.js +30 -0
- package/dist/node_modules/mariadb/lib/const/state-change.js +12 -0
- package/dist/node_modules/mariadb/lib/filtered-pool-cluster.js +81 -0
- package/dist/node_modules/mariadb/lib/io/bulk-packet.js +590 -0
- package/dist/node_modules/mariadb/lib/io/compression-input-stream.js +141 -0
- package/dist/node_modules/mariadb/lib/io/compression-output-stream.js +171 -0
- package/dist/node_modules/mariadb/lib/io/packet-input-stream.js +193 -0
- package/dist/node_modules/mariadb/lib/io/packet-node-encoded.js +36 -0
- package/dist/node_modules/mariadb/lib/io/packet-node-iconv.js +37 -0
- package/dist/node_modules/mariadb/lib/io/packet-output-stream.js +502 -0
- package/dist/node_modules/mariadb/lib/io/packet.js +515 -0
- package/dist/node_modules/mariadb/lib/io/rewrite-packet.js +481 -0
- package/dist/node_modules/mariadb/lib/misc/connection-information.js +96 -0
- package/dist/node_modules/mariadb/lib/misc/errors.js +123 -0
- package/dist/node_modules/mariadb/lib/misc/parse.js +1033 -0
- package/dist/node_modules/mariadb/lib/misc/utils.js +298 -0
- package/dist/node_modules/mariadb/lib/pool-base.js +611 -0
- package/dist/node_modules/mariadb/lib/pool-callback.js +202 -0
- package/dist/node_modules/mariadb/lib/pool-cluster-callback.js +66 -0
- package/dist/node_modules/mariadb/lib/pool-cluster.js +407 -0
- package/dist/node_modules/mariadb/lib/pool-promise.js +108 -0
- package/dist/node_modules/mariadb/package.json +1 -0
- package/dist/node_modules/mariadb/promise.js +34 -0
- package/dist/node_modules/mariadb/types/index.d.ts +870 -0
- package/dist/server/actions/apps.d.ts +5 -0
- package/dist/server/actions/apps.js +117 -0
- package/dist/server/app-lifecycle.d.ts +8 -0
- package/dist/server/app-lifecycle.js +99 -0
- package/dist/server/app-start-env.d.ts +2 -0
- package/dist/server/app-start-env.js +105 -0
- package/dist/server/collections/applications.d.ts +2 -0
- package/dist/server/collections/applications.js +82 -0
- package/dist/server/index.d.ts +4 -0
- package/dist/server/index.js +29 -0
- package/dist/server/middlewares/app-selector.d.ts +1 -0
- package/dist/server/middlewares/app-selector.js +47 -0
- package/dist/server/middlewares/index.d.ts +2 -0
- package/dist/server/middlewares/index.js +23 -0
- package/dist/server/middlewares/inject-app-list.d.ts +1 -0
- package/dist/server/middlewares/inject-app-list.js +48 -0
- package/dist/server/migrations/20240820153000-add-apps-tmpl.d.ts +6 -0
- package/dist/server/migrations/20240820153000-add-apps-tmpl.js +47 -0
- package/dist/server/migrations/20241126124904-add-createdBy.d.ts +6 -0
- package/dist/server/migrations/20241126124904-add-createdBy.js +41 -0
- package/dist/server/models/application.d.ts +10 -0
- package/dist/server/models/application.js +57 -0
- package/dist/server/server.d.ts +19 -0
- package/dist/server/server.js +246 -0
- package/dist/swagger/index.d.ts +197 -0
- package/dist/swagger/index.js +227 -0
- package/package.json +38 -0
- package/server.d.ts +2 -0
- package/server.js +1 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const PoolBase = require('./pool-base');
|
|
4
|
+
const ConnectionCallback = require('./connection-callback');
|
|
5
|
+
const Errors = require('./misc/errors');
|
|
6
|
+
const util = require('util');
|
|
7
|
+
|
|
8
|
+
function PoolCallback(options) {
|
|
9
|
+
const processTaskCallback = function (conn, sql, values, isBatch) {
|
|
10
|
+
if (sql) {
|
|
11
|
+
return new Promise((resolve, reject) => {
|
|
12
|
+
const fct = isBatch ? conn.batch : conn.query;
|
|
13
|
+
fct(sql, values, (err, rows, fields) => {
|
|
14
|
+
conn.releaseWithoutError();
|
|
15
|
+
if (err) {
|
|
16
|
+
reject(err);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
return resolve(rows);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
} else {
|
|
23
|
+
return Promise.resolve(conn);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const pingPromise = function (conn) {
|
|
28
|
+
return new Promise((resolve, reject) => {
|
|
29
|
+
conn.ping(options.pingTimeout, (err) => {
|
|
30
|
+
if (err) {
|
|
31
|
+
reject(err);
|
|
32
|
+
} else resolve();
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const createConnectionPoolCallback = function (pool) {
|
|
38
|
+
const conn = new ConnectionCallback(options.connOptions);
|
|
39
|
+
return new Promise(function (resolve, reject) {
|
|
40
|
+
conn.connect((err) => {
|
|
41
|
+
if (err) {
|
|
42
|
+
reject(err);
|
|
43
|
+
} else {
|
|
44
|
+
if (pool.closed) {
|
|
45
|
+
//discard connection
|
|
46
|
+
conn.end((err) => {});
|
|
47
|
+
reject(
|
|
48
|
+
Errors.createError(
|
|
49
|
+
'Cannot create new connection to pool, pool closed',
|
|
50
|
+
null,
|
|
51
|
+
true,
|
|
52
|
+
null,
|
|
53
|
+
'08S01',
|
|
54
|
+
Errors.ER_ADD_CONNECTION_CLOSED_POOL,
|
|
55
|
+
null
|
|
56
|
+
)
|
|
57
|
+
);
|
|
58
|
+
} else {
|
|
59
|
+
const initialEnd = conn.end;
|
|
60
|
+
conn.forceEnd = () => {
|
|
61
|
+
return new Promise(function (res, rej) {
|
|
62
|
+
initialEnd((err) => {
|
|
63
|
+
if (err) {
|
|
64
|
+
rej(err);
|
|
65
|
+
} else {
|
|
66
|
+
res();
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
conn.release = function (cb) {
|
|
73
|
+
if (pool.closed) {
|
|
74
|
+
pool._discardConnection(conn);
|
|
75
|
+
if (cb) cb();
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (options.noControlAfterUse) {
|
|
79
|
+
pool._releaseConnection(conn);
|
|
80
|
+
if (cb) cb();
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
//if server permit it, reset the connection, or rollback only if not
|
|
85
|
+
// COM_RESET_CONNECTION exist since mysql 5.7.3 and mariadb 10.2.4
|
|
86
|
+
// but not possible to use it with mysql waiting for https://bugs.mysql.com/bug.php?id=97633 correction.
|
|
87
|
+
// and mariadb only since https://jira.mariadb.org/browse/MDEV-18281
|
|
88
|
+
let revertFunction = conn.rollback;
|
|
89
|
+
if (
|
|
90
|
+
options.resetAfterUse &&
|
|
91
|
+
conn.info.isMariaDB() &&
|
|
92
|
+
((conn.info.serverVersion.minor === 2 && conn.info.hasMinVersion(10, 2, 22)) ||
|
|
93
|
+
conn.info.hasMinVersion(10, 3, 13))
|
|
94
|
+
) {
|
|
95
|
+
revertFunction = conn.reset;
|
|
96
|
+
}
|
|
97
|
+
revertFunction((errCall) => {
|
|
98
|
+
if (errCall) {
|
|
99
|
+
//uncertain connection state.
|
|
100
|
+
pool._discardConnection(conn);
|
|
101
|
+
if (cb) cb();
|
|
102
|
+
return;
|
|
103
|
+
} else {
|
|
104
|
+
pool._releaseConnection(conn);
|
|
105
|
+
}
|
|
106
|
+
if (cb) cb();
|
|
107
|
+
});
|
|
108
|
+
};
|
|
109
|
+
conn.end = conn.release;
|
|
110
|
+
conn.releaseWithoutError = () => {
|
|
111
|
+
conn.end((err) => {});
|
|
112
|
+
};
|
|
113
|
+
resolve(conn);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
PoolBase.call(this, options, processTaskCallback, createConnectionPoolCallback, pingPromise);
|
|
121
|
+
|
|
122
|
+
const getConnectionPromise = this.getConnection.bind(this);
|
|
123
|
+
const endPromise = this.end.bind(this);
|
|
124
|
+
const queryPromise = this.query.bind(this);
|
|
125
|
+
const batchPromise = this.batch.bind(this);
|
|
126
|
+
const emptyError = (err) => {};
|
|
127
|
+
|
|
128
|
+
//*****************************************************************
|
|
129
|
+
// internal equivalent with callback of promised functions
|
|
130
|
+
//*****************************************************************
|
|
131
|
+
|
|
132
|
+
const _getConnectionCallback = (callback) => {
|
|
133
|
+
getConnectionPromise()
|
|
134
|
+
.then((conn) => {
|
|
135
|
+
if (callback) callback(null, conn);
|
|
136
|
+
})
|
|
137
|
+
.catch(callback || emptyError);
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const _endCallback = (callback) => {
|
|
141
|
+
endPromise()
|
|
142
|
+
.then(() => {
|
|
143
|
+
if (callback) callback(null);
|
|
144
|
+
})
|
|
145
|
+
.catch(callback || emptyError);
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Execute query using text protocol with callback emit columns/data/end/error
|
|
150
|
+
* events to permit streaming big result-set
|
|
151
|
+
*
|
|
152
|
+
* @param sql sql parameter Object can be used to supersede default option.
|
|
153
|
+
* Object must then have sql property.
|
|
154
|
+
* @param values object / array of placeholder values (not mandatory)
|
|
155
|
+
* @param cb callback
|
|
156
|
+
* @returns {Query} query
|
|
157
|
+
*/
|
|
158
|
+
const _queryCallback = function (sql, values, cb) {
|
|
159
|
+
let _cb = cb,
|
|
160
|
+
_values = values;
|
|
161
|
+
|
|
162
|
+
if (typeof values === 'function') {
|
|
163
|
+
_cb = values;
|
|
164
|
+
_values = undefined;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
queryPromise(sql, _values)
|
|
168
|
+
.then((rows) => {
|
|
169
|
+
if (_cb) _cb(null, rows, rows.meta);
|
|
170
|
+
})
|
|
171
|
+
.catch(_cb || emptyError);
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const _batchCallback = function (sql, values, cb) {
|
|
175
|
+
let _values = values,
|
|
176
|
+
_cb = cb;
|
|
177
|
+
|
|
178
|
+
if (typeof values === 'function') {
|
|
179
|
+
_cb = values;
|
|
180
|
+
_values = undefined;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
batchPromise(sql, _values)
|
|
184
|
+
.then((rows) => {
|
|
185
|
+
if (_cb) _cb(null, rows, rows.meta);
|
|
186
|
+
})
|
|
187
|
+
.catch(_cb || emptyError);
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
//*****************************************************************
|
|
191
|
+
// replacing public promise function with callback equivalent
|
|
192
|
+
//*****************************************************************
|
|
193
|
+
|
|
194
|
+
this.end = _endCallback;
|
|
195
|
+
this.query = _queryCallback;
|
|
196
|
+
this.batch = _batchCallback;
|
|
197
|
+
this.getConnection = _getConnectionCallback;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
util.inherits(PoolCallback, PoolBase);
|
|
201
|
+
|
|
202
|
+
module.exports = PoolCallback;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const PoolCluster = require('./pool-cluster');
|
|
4
|
+
const util = require('util');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Create a new Cluster.
|
|
8
|
+
* Cluster handle pools with patterns and handle failover / distributed load
|
|
9
|
+
* according to selectors (round robin / random / ordered )
|
|
10
|
+
*
|
|
11
|
+
* @param args cluster argurments. see pool-cluster-options.
|
|
12
|
+
* @constructor
|
|
13
|
+
*/
|
|
14
|
+
function PoolClusterCallback(args) {
|
|
15
|
+
PoolCluster.call(this, args);
|
|
16
|
+
this.setCallback();
|
|
17
|
+
|
|
18
|
+
const initialGetConnection = this.getConnection.bind(this);
|
|
19
|
+
const initialEnd = this.end.bind(this);
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* End cluster (and underlying pools).
|
|
23
|
+
*
|
|
24
|
+
* @param callback - not mandatory
|
|
25
|
+
*/
|
|
26
|
+
this.end = (callback) => {
|
|
27
|
+
if (callback && typeof callback !== 'function') {
|
|
28
|
+
throw new Error('callback parameter must be a function');
|
|
29
|
+
}
|
|
30
|
+
const endingFct = callback ? callback : () => {};
|
|
31
|
+
|
|
32
|
+
initialEnd()
|
|
33
|
+
.then(() => {
|
|
34
|
+
endingFct();
|
|
35
|
+
})
|
|
36
|
+
.catch(endingFct);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Get connection from available pools matching pattern, according to selector
|
|
41
|
+
*
|
|
42
|
+
* @param pattern pattern filter (not mandatory)
|
|
43
|
+
* @param selector node selector ('RR','RANDOM' or 'ORDER')
|
|
44
|
+
* @param callback callback function
|
|
45
|
+
*/
|
|
46
|
+
this.getConnection = (pattern, selector, callback) => {
|
|
47
|
+
let pat = pattern,
|
|
48
|
+
sel = selector,
|
|
49
|
+
cal = callback;
|
|
50
|
+
if (typeof pattern === 'function') {
|
|
51
|
+
pat = null;
|
|
52
|
+
sel = null;
|
|
53
|
+
cal = pattern;
|
|
54
|
+
} else if (typeof selector === 'function') {
|
|
55
|
+
sel = null;
|
|
56
|
+
cal = selector;
|
|
57
|
+
}
|
|
58
|
+
const endingFct = cal ? cal : (conn) => {};
|
|
59
|
+
|
|
60
|
+
initialGetConnection(pat, sel, endingFct);
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
util.inherits(PoolClusterCallback, PoolCluster);
|
|
65
|
+
|
|
66
|
+
module.exports = PoolClusterCallback;
|
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const PoolClusterOptions = require('./config/pool-cluster-options');
|
|
4
|
+
const PoolOptions = require('./config/pool-options');
|
|
5
|
+
const Pool = require('./pool-promise');
|
|
6
|
+
const PoolCallback = require('./pool-callback');
|
|
7
|
+
const FilteredPoolCluster = require('./filtered-pool-cluster');
|
|
8
|
+
const EventEmitter = require('events');
|
|
9
|
+
const util = require('util');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Create a new Cluster.
|
|
13
|
+
* Cluster handle pools with patterns and handle failover / distributed load
|
|
14
|
+
* according to selectors (round robin / random / ordered )
|
|
15
|
+
*
|
|
16
|
+
* @param args cluster argurments. see pool-cluster-options.
|
|
17
|
+
* @constructor
|
|
18
|
+
*/
|
|
19
|
+
function PoolCluster(args) {
|
|
20
|
+
const opts = new PoolClusterOptions(args);
|
|
21
|
+
const nodes = {};
|
|
22
|
+
let cachedPatterns = {};
|
|
23
|
+
let nodeCounter = 0;
|
|
24
|
+
EventEmitter.call(this);
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Add a new pool node to cluster.
|
|
28
|
+
*
|
|
29
|
+
* @param id identifier
|
|
30
|
+
* @param config pool configuration
|
|
31
|
+
*/
|
|
32
|
+
this.add = (id, config) => {
|
|
33
|
+
let identifier;
|
|
34
|
+
if (typeof id === 'string' || id instanceof String) {
|
|
35
|
+
identifier = id;
|
|
36
|
+
if (nodes[identifier])
|
|
37
|
+
throw new Error("Node identifier '" + identifier + "' already exist !");
|
|
38
|
+
} else {
|
|
39
|
+
identifier = 'PoolNode-' + nodeCounter++;
|
|
40
|
+
config = id;
|
|
41
|
+
}
|
|
42
|
+
const options = new PoolOptions(config);
|
|
43
|
+
const pool = _createPool(options);
|
|
44
|
+
pool.initialize();
|
|
45
|
+
nodes[identifier] = pool;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* End cluster (and underlying pools).
|
|
50
|
+
*
|
|
51
|
+
* @return {Promise<any[]>}
|
|
52
|
+
*/
|
|
53
|
+
this.end = () => {
|
|
54
|
+
cachedPatterns = {};
|
|
55
|
+
const poolEndPromise = [];
|
|
56
|
+
Object.keys(nodes).forEach((pool) => {
|
|
57
|
+
poolEndPromise.push(nodes[pool].end());
|
|
58
|
+
delete nodes[pool];
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
return Promise.all(poolEndPromise);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
this.of = (pattern, selector) => {
|
|
65
|
+
return new FilteredPoolCluster(this, pattern, selector);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Remove nodes according to pattern.
|
|
70
|
+
*
|
|
71
|
+
* @param pattern pattern
|
|
72
|
+
*/
|
|
73
|
+
this.remove = (pattern) => {
|
|
74
|
+
if (!pattern) throw new Error('pattern parameter in Cluster.remove(pattern) is mandatory');
|
|
75
|
+
|
|
76
|
+
const regex = RegExp(pattern);
|
|
77
|
+
Object.keys(nodes).forEach((key) => {
|
|
78
|
+
if (regex.test(key)) {
|
|
79
|
+
nodes[key].end();
|
|
80
|
+
delete nodes[key];
|
|
81
|
+
cachedPatterns = {};
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Get connection from available pools matching pattern, according to selector
|
|
88
|
+
*
|
|
89
|
+
* @param pattern pattern filter (not mandatory)
|
|
90
|
+
* @param selector node selector ('RR','RANDOM' or 'ORDER')
|
|
91
|
+
* @return {Promise}
|
|
92
|
+
*/
|
|
93
|
+
this.getConnection = (pattern, selector) => {
|
|
94
|
+
return _getConnection(this, pattern, selector);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Force using callback methods.
|
|
99
|
+
*/
|
|
100
|
+
this.setCallback = () => {
|
|
101
|
+
this.getConnection = _getConnectionCallback.bind(this, this);
|
|
102
|
+
_createPool = _createPoolCallback;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Get connection from available pools matching pattern, according to selector
|
|
107
|
+
* with additional parameter to avoid reusing failing node
|
|
108
|
+
*
|
|
109
|
+
* @param pattern pattern filter (not mandatory)
|
|
110
|
+
* @param selector node selector ('RR','RANDOM' or 'ORDER')
|
|
111
|
+
* @param avoidNodeKey failing node
|
|
112
|
+
* @param lastError last error
|
|
113
|
+
* @return {Promise}
|
|
114
|
+
* @private
|
|
115
|
+
*/
|
|
116
|
+
const _getConnection = (cluster, pattern, selector, avoidNodeKey, lastError) => {
|
|
117
|
+
const matchingNodeList = _matchingNodes(pattern || /^/);
|
|
118
|
+
|
|
119
|
+
if (matchingNodeList.length === 0) {
|
|
120
|
+
if (Object.keys(nodes).length === 0 && !lastError) {
|
|
121
|
+
return Promise.reject(
|
|
122
|
+
new Error(
|
|
123
|
+
'No node have been added to cluster ' +
|
|
124
|
+
'or nodes have been removed due to too much connection error'
|
|
125
|
+
)
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
if (avoidNodeKey === undefined)
|
|
129
|
+
return Promise.reject(new Error("No node found for pattern '" + pattern + "'"));
|
|
130
|
+
const errMsg =
|
|
131
|
+
"No Connection available for '" +
|
|
132
|
+
pattern +
|
|
133
|
+
"'" +
|
|
134
|
+
(lastError ? '. Last connection error was: ' + lastError.message : '');
|
|
135
|
+
return Promise.reject(new Error(errMsg));
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const retry = _getConnection.bind(this, this, pattern, selector);
|
|
139
|
+
try {
|
|
140
|
+
const nodeKey = _selectPool(matchingNodeList, selector, avoidNodeKey);
|
|
141
|
+
return _handleConnectionError(cluster, matchingNodeList, nodeKey, retry);
|
|
142
|
+
} catch (e) {
|
|
143
|
+
return Promise.reject(e);
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
let _createPool = (options) => {
|
|
148
|
+
return new Pool(options, false);
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const _createPoolCallback = (options) => {
|
|
152
|
+
return new PoolCallback(options, false);
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Get connection from available pools matching pattern, according to selector
|
|
157
|
+
* with additional parameter to avoid reusing failing node
|
|
158
|
+
*
|
|
159
|
+
* @param pattern pattern filter (not mandatory)
|
|
160
|
+
* @param selector node selector ('RR','RANDOM' or 'ORDER')
|
|
161
|
+
* @param callback callback function
|
|
162
|
+
* @param avoidNodeKey failing node
|
|
163
|
+
* @param lastError last error
|
|
164
|
+
* @private
|
|
165
|
+
*/
|
|
166
|
+
const _getConnectionCallback = (
|
|
167
|
+
cluster,
|
|
168
|
+
pattern,
|
|
169
|
+
selector,
|
|
170
|
+
callback,
|
|
171
|
+
avoidNodeKey,
|
|
172
|
+
lastError
|
|
173
|
+
) => {
|
|
174
|
+
const matchingNodeList = _matchingNodes(pattern || /^/);
|
|
175
|
+
|
|
176
|
+
if (matchingNodeList.length === 0) {
|
|
177
|
+
if (Object.keys(nodes).length === 0 && !lastError) {
|
|
178
|
+
callback(
|
|
179
|
+
new Error(
|
|
180
|
+
'No node have been added to cluster ' +
|
|
181
|
+
'or nodes have been removed due to too much connection error'
|
|
182
|
+
)
|
|
183
|
+
);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (avoidNodeKey === undefined)
|
|
188
|
+
callback(new Error("No node found for pattern '" + pattern + "'"));
|
|
189
|
+
const errMsg =
|
|
190
|
+
"No Connection available for '" +
|
|
191
|
+
pattern +
|
|
192
|
+
"'" +
|
|
193
|
+
(lastError ? '. Last connection error was: ' + lastError.message : '');
|
|
194
|
+
callback(new Error(errMsg));
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const retry = _getConnectionCallback.bind(this, this, pattern, selector, callback);
|
|
199
|
+
try {
|
|
200
|
+
const nodeKey = _selectPool(matchingNodeList, selector, avoidNodeKey);
|
|
201
|
+
_handleConnectionCallbackError(this, matchingNodeList, nodeKey, retry, callback);
|
|
202
|
+
} catch (e) {
|
|
203
|
+
callback(e);
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Selecting nodes according to pattern.
|
|
209
|
+
*
|
|
210
|
+
* @param pattern pattern
|
|
211
|
+
* @return {*}
|
|
212
|
+
* @private
|
|
213
|
+
*/
|
|
214
|
+
const _matchingNodes = (pattern) => {
|
|
215
|
+
if (cachedPatterns[pattern]) return cachedPatterns[pattern];
|
|
216
|
+
|
|
217
|
+
const regex = RegExp(pattern);
|
|
218
|
+
const matchingNodeList = [];
|
|
219
|
+
Object.keys(nodes).forEach((key) => {
|
|
220
|
+
if (regex.test(key)) {
|
|
221
|
+
matchingNodeList.push(key);
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
cachedPatterns[pattern] = matchingNodeList;
|
|
226
|
+
return matchingNodeList;
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Select next node to be chosen in nodeList according to selector and failed nodes.
|
|
231
|
+
*
|
|
232
|
+
* @param nodeList current node list
|
|
233
|
+
* @param selectorParam selector
|
|
234
|
+
* @param avoidNodeKey last failing node to avoid selecting this one.
|
|
235
|
+
* @return {Promise}
|
|
236
|
+
* @private
|
|
237
|
+
*/
|
|
238
|
+
const _selectPool = (nodeList, selectorParam, avoidNodeKey) => {
|
|
239
|
+
const selector = selectorParam || opts.defaultSelector;
|
|
240
|
+
let retry = 0;
|
|
241
|
+
let selectorFct;
|
|
242
|
+
let nodeKey;
|
|
243
|
+
switch (selector) {
|
|
244
|
+
case 'RR':
|
|
245
|
+
selectorFct = roundRobinSelector;
|
|
246
|
+
break;
|
|
247
|
+
|
|
248
|
+
case 'RANDOM':
|
|
249
|
+
selectorFct = randomSelector;
|
|
250
|
+
break;
|
|
251
|
+
|
|
252
|
+
case 'ORDER':
|
|
253
|
+
selectorFct = orderedSelector;
|
|
254
|
+
break;
|
|
255
|
+
|
|
256
|
+
default:
|
|
257
|
+
throw new Error(
|
|
258
|
+
"Wrong selector value '" + selector + "'. Possible values are 'RR','RANDOM' or 'ORDER'"
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
nodeKey = selectorFct(nodeList, retry);
|
|
263
|
+
while (
|
|
264
|
+
(avoidNodeKey === nodeKey || nodes[nodeKey].blacklistedUntil > Date.now()) &&
|
|
265
|
+
retry < nodeList.length - 1
|
|
266
|
+
) {
|
|
267
|
+
retry++;
|
|
268
|
+
nodeKey = selectorFct(nodeList, retry);
|
|
269
|
+
}
|
|
270
|
+
return nodeKey;
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Round robin selector: using nodes one after the other.
|
|
275
|
+
*
|
|
276
|
+
* @param nodeList node list
|
|
277
|
+
* @return {String}
|
|
278
|
+
*/
|
|
279
|
+
const roundRobinSelector = (nodeList) => {
|
|
280
|
+
let lastRoundRobin = nodeList.lastRrIdx;
|
|
281
|
+
if (lastRoundRobin === undefined) lastRoundRobin = -1;
|
|
282
|
+
if (++lastRoundRobin >= nodeList.length) lastRoundRobin = 0;
|
|
283
|
+
nodeList.lastRrIdx = lastRoundRobin;
|
|
284
|
+
return nodeList[lastRoundRobin];
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Random selector: use a random node.
|
|
289
|
+
*
|
|
290
|
+
* @param nodeList node list
|
|
291
|
+
* @return {String}
|
|
292
|
+
*/
|
|
293
|
+
const randomSelector = (nodeList) => {
|
|
294
|
+
let randomIdx = Math.floor(Math.random() * nodeList.length);
|
|
295
|
+
return nodeList[randomIdx];
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Ordered selector: always use the nodes in sequence, unless failing.
|
|
300
|
+
*
|
|
301
|
+
* @param nodeList node list
|
|
302
|
+
* @param retry sequence number if last node is tagged has failing
|
|
303
|
+
* @return {String}
|
|
304
|
+
*/
|
|
305
|
+
const orderedSelector = (nodeList, retry) => {
|
|
306
|
+
return nodeList[retry];
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Connect, or if fail handle retry / set timeout error
|
|
311
|
+
*
|
|
312
|
+
* @param cluster current cluster
|
|
313
|
+
* @param nodeList current node list
|
|
314
|
+
* @param nodeKey node name to connect
|
|
315
|
+
* @param retryFct retry function
|
|
316
|
+
* @return {Promise}
|
|
317
|
+
* @private
|
|
318
|
+
*/
|
|
319
|
+
const _handleConnectionError = (cluster, nodeList, nodeKey, retryFct) => {
|
|
320
|
+
const node = nodes[nodeKey];
|
|
321
|
+
return node
|
|
322
|
+
.getConnection()
|
|
323
|
+
.then((conn) => {
|
|
324
|
+
node.errorCount = 0;
|
|
325
|
+
return Promise.resolve(conn);
|
|
326
|
+
})
|
|
327
|
+
.catch((err) => {
|
|
328
|
+
node.errorCount = node.errorCount ? node.errorCount + 1 : 1;
|
|
329
|
+
node.blacklistedUntil = Date.now() + opts.restoreNodeTimeout;
|
|
330
|
+
if (
|
|
331
|
+
opts.removeNodeErrorCount &&
|
|
332
|
+
node.errorCount >= opts.removeNodeErrorCount &&
|
|
333
|
+
nodes[nodeKey]
|
|
334
|
+
) {
|
|
335
|
+
delete nodes[nodeKey];
|
|
336
|
+
cachedPatterns = {};
|
|
337
|
+
delete nodeList.lastRrIdx;
|
|
338
|
+
process.nextTick(() => cluster.emit('remove', nodeKey));
|
|
339
|
+
//remove node from configuration if not already removed
|
|
340
|
+
node.end().catch((err) => {
|
|
341
|
+
// dismiss error
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
if (nodeList.length !== 0 && opts.canRetry) {
|
|
346
|
+
return retryFct(nodeKey, err);
|
|
347
|
+
}
|
|
348
|
+
return Promise.reject(err);
|
|
349
|
+
});
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Connect, or if fail handle retry / set timeout error
|
|
354
|
+
*
|
|
355
|
+
* @param cluster current cluster
|
|
356
|
+
* @param nodeList current node list
|
|
357
|
+
* @param nodeKey node name to connect
|
|
358
|
+
* @param retryFct retry function
|
|
359
|
+
* @param callback callback function
|
|
360
|
+
* @private
|
|
361
|
+
*/
|
|
362
|
+
const _handleConnectionCallbackError = (cluster, nodeList, nodeKey, retryFct, callback) => {
|
|
363
|
+
const node = nodes[nodeKey];
|
|
364
|
+
node.getConnection((err, conn) => {
|
|
365
|
+
if (err) {
|
|
366
|
+
node.errorCount = node.errorCount ? node.errorCount + 1 : 1;
|
|
367
|
+
node.blacklistedUntil = Date.now() + opts.restoreNodeTimeout;
|
|
368
|
+
if (
|
|
369
|
+
opts.removeNodeErrorCount &&
|
|
370
|
+
node.errorCount >= opts.removeNodeErrorCount &&
|
|
371
|
+
nodes[nodeKey]
|
|
372
|
+
) {
|
|
373
|
+
delete nodes[nodeKey];
|
|
374
|
+
cachedPatterns = {};
|
|
375
|
+
delete nodeList.lastRrIdx;
|
|
376
|
+
process.nextTick(() => cluster.emit('remove', nodeKey));
|
|
377
|
+
//remove node from configuration if not already removed
|
|
378
|
+
node.end(() => {
|
|
379
|
+
//dismiss error
|
|
380
|
+
});
|
|
381
|
+
if (nodeList.length === 0) return Promise.reject(err);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
if (opts.canRetry) return retryFct(nodeKey, err);
|
|
385
|
+
callback(err);
|
|
386
|
+
} else {
|
|
387
|
+
node.errorCount = 0;
|
|
388
|
+
callback(null, conn);
|
|
389
|
+
}
|
|
390
|
+
});
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
//*****************************************************************
|
|
394
|
+
// internal public testing methods
|
|
395
|
+
//*****************************************************************
|
|
396
|
+
|
|
397
|
+
function TestMethods() {}
|
|
398
|
+
TestMethods.prototype.getNodes = () => {
|
|
399
|
+
return nodes;
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
this.__tests = new TestMethods();
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
util.inherits(PoolCluster, EventEmitter);
|
|
406
|
+
|
|
407
|
+
module.exports = PoolCluster;
|