eip-cloud-services 1.1.14 → 1.2.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/index.js +2 -1
- package/package.json +2 -1
- package/src/mysql8.js +141 -0
- package/src/s3.js +4 -0
package/index.js
CHANGED
|
@@ -3,4 +3,5 @@ exports.redis = require ( './src/redis' );
|
|
|
3
3
|
exports.s3 = require ( './src/s3' );
|
|
4
4
|
exports.cdn = require ( './src/cdn' );
|
|
5
5
|
exports.lambda = require ( './src/lambda' );
|
|
6
|
-
exports.mysql = require ( './src/mysql' );
|
|
6
|
+
exports.mysql = require ( './src/mysql' );
|
|
7
|
+
exports.mysql8 = require ( './src/mysql8' );
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eip-cloud-services",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Houses a collection of helpers for connecting with Cloud services.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"google-auth-library": "^8.8.0",
|
|
23
23
|
"ioredis": "^5.3.2",
|
|
24
24
|
"mysql": "^2.18.1",
|
|
25
|
+
"mysql2": "^3.14.4",
|
|
25
26
|
"redis": "^4.6.7"
|
|
26
27
|
}
|
|
27
28
|
}
|
package/src/mysql8.js
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
// eip-cloud-services/mysql8.js
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const mysql = require('mysql2/promise'); // Promise API (app code)
|
|
6
|
+
const mysqlCb = require('mysql2'); // Callback API (for migrations)
|
|
7
|
+
|
|
8
|
+
// Load config only if ./config exists
|
|
9
|
+
let config = {};
|
|
10
|
+
const configDirPath = `${process.cwd()}/config`;
|
|
11
|
+
if (fs.existsSync(configDirPath) && fs.statSync(configDirPath).isDirectory()) {
|
|
12
|
+
// eslint-disable-next-line global-require
|
|
13
|
+
config = require('config');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Promise pools (existing)
|
|
17
|
+
const pools = {};
|
|
18
|
+
// NEW: Callback pools
|
|
19
|
+
const callbackPools = {};
|
|
20
|
+
|
|
21
|
+
/** Get promise pool (existing) */
|
|
22
|
+
function getPool(poolId = 'main') {
|
|
23
|
+
const poolConfig = (config.mysql && (config.mysql[poolId] || config.mysql)) || {};
|
|
24
|
+
|
|
25
|
+
if (!pools[poolId]) {
|
|
26
|
+
pools[poolId] = mysql.createPool({
|
|
27
|
+
host: poolConfig.host,
|
|
28
|
+
user: poolConfig.user,
|
|
29
|
+
password: poolConfig.password,
|
|
30
|
+
database: poolConfig.database || undefined,
|
|
31
|
+
connectionLimit: poolConfig.connectionLimit || 10,
|
|
32
|
+
multipleStatements: poolConfig.multipleStatements !== false,
|
|
33
|
+
waitForConnections: true,
|
|
34
|
+
queueLimit: 0,
|
|
35
|
+
// Works fine with MySQL 8's caching_sha2_password; add TLS in prod as needed
|
|
36
|
+
// ssl: { minVersion: 'TLSv1.2', rejectUnauthorized: false },
|
|
37
|
+
// allowPublicKeyRetrieval: true, // only needed for sha256_password without SSL
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
return pools[poolId];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** NEW: Get callback-style pool (for tools like mysql-migrations) */
|
|
44
|
+
function getCallbackPool(poolId = 'main') {
|
|
45
|
+
const poolConfig = (config.mysql && (config.mysql[poolId] || config.mysql)) || {};
|
|
46
|
+
|
|
47
|
+
if (!callbackPools[poolId]) {
|
|
48
|
+
callbackPools[poolId] = mysqlCb.createPool({
|
|
49
|
+
host: poolConfig.host,
|
|
50
|
+
user: poolConfig.user,
|
|
51
|
+
password: poolConfig.password,
|
|
52
|
+
database: poolConfig.database || undefined,
|
|
53
|
+
connectionLimit: poolConfig.connectionLimit || 10,
|
|
54
|
+
multipleStatements: poolConfig.multipleStatements !== false,
|
|
55
|
+
waitForConnections: true,
|
|
56
|
+
queueLimit: 0,
|
|
57
|
+
// Same note re: TLS / allowPublicKeyRetrieval as above.
|
|
58
|
+
// ssl: { minVersion: 'TLSv1.2', rejectUnauthorized: false },
|
|
59
|
+
// allowPublicKeyRetrieval: true,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
return callbackPools[poolId];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ----- promise query helpers (existing) -----
|
|
66
|
+
async function runQuery(connection, query) {
|
|
67
|
+
try {
|
|
68
|
+
const [rows] = await connection.query(query);
|
|
69
|
+
return rows;
|
|
70
|
+
} catch (error) {
|
|
71
|
+
const MAX_ERROR_LENGTH = 500;
|
|
72
|
+
const MAX_QUERY_LENGTH = 300;
|
|
73
|
+
const raw = error && (error.stack || error.message || String(error));
|
|
74
|
+
const shortError = String(raw).slice(0, MAX_ERROR_LENGTH);
|
|
75
|
+
const shortQuery = String(query).slice(0, MAX_QUERY_LENGTH);
|
|
76
|
+
console.error('Query Error:', shortError);
|
|
77
|
+
console.error('Truncated Query:', shortQuery);
|
|
78
|
+
throw new Error(`There was a problem with query: ${shortError}`);
|
|
79
|
+
} finally {
|
|
80
|
+
try { if (connection?.release) connection.release(); } catch {}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
exports.getPool = getPool;
|
|
85
|
+
exports.getCallbackPool = getCallbackPool; // <-- NEW EXPORT
|
|
86
|
+
|
|
87
|
+
exports.getConnection = async (poolId = 'main') => {
|
|
88
|
+
try {
|
|
89
|
+
const pool = getPool(poolId);
|
|
90
|
+
const connection = await pool.getConnection();
|
|
91
|
+
return connection;
|
|
92
|
+
} catch (error) {
|
|
93
|
+
console.error(error);
|
|
94
|
+
console.error('There was a problem getting a new database connection.');
|
|
95
|
+
throw new Error('There was a problem getting a new database connection.');
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
exports.query = async (queryString, poolId = 'main') => {
|
|
100
|
+
let sql = String(queryString || '');
|
|
101
|
+
if (!sql.endsWith(';')) sql += ';';
|
|
102
|
+
const connection = await exports.getConnection(poolId);
|
|
103
|
+
return runQuery(connection, sql);
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
/** Delete a promise pool */
|
|
107
|
+
exports.deletePool = async (poolId) => {
|
|
108
|
+
const pool = pools[poolId];
|
|
109
|
+
if (!pool) return;
|
|
110
|
+
await pool.end().catch(() => {});
|
|
111
|
+
delete pools[poolId];
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
/** NEW: Delete a callback pool */
|
|
115
|
+
exports.deleteCallbackPool = async (poolId) => {
|
|
116
|
+
const pool = callbackPools[poolId];
|
|
117
|
+
if (!pool) return;
|
|
118
|
+
await new Promise((res) => pool.end(res));
|
|
119
|
+
delete callbackPools[poolId];
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
/** Close all pools (promise + callback) */
|
|
123
|
+
exports.kill = async () => {
|
|
124
|
+
const p1 = Promise.all(
|
|
125
|
+
Object.keys(pools).map(async (id) => {
|
|
126
|
+
try { await pools[id].end(); } catch {}
|
|
127
|
+
delete pools[id];
|
|
128
|
+
})
|
|
129
|
+
);
|
|
130
|
+
const p2 = Promise.all(
|
|
131
|
+
Object.keys(callbackPools).map(
|
|
132
|
+
(id) =>
|
|
133
|
+
new Promise((res) => {
|
|
134
|
+
try { callbackPools[id].end(() => res()); }
|
|
135
|
+
catch { res(); }
|
|
136
|
+
finally { delete callbackPools[id]; }
|
|
137
|
+
})
|
|
138
|
+
)
|
|
139
|
+
);
|
|
140
|
+
await Promise.all([p1, p2]);
|
|
141
|
+
};
|
package/src/s3.js
CHANGED
|
@@ -134,6 +134,10 @@ exports.get = async ( key, bucket = config?.s3?.Bucket, options = {} ) => {
|
|
|
134
134
|
data = zlib.unzipSync ( data );
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
+
if ( response.ContentType.includes('image') ) {
|
|
138
|
+
return data;
|
|
139
|
+
}
|
|
140
|
+
|
|
137
141
|
if ( response.ContentType !== 'application/json' && !response.Metadata[ 'tmg-json' ] ) {
|
|
138
142
|
if ( config?.s3?.logs === 'output' )
|
|
139
143
|
log ( `S3 [GET]: Returned ${response.ContentType} from ${bucket}/${key}.` );
|