dbgate-api 5.2.1 → 5.2.2-alpha.11
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/package.json +7 -6
- package/src/controllers/archive.js +4 -1
- package/src/controllers/auth.js +6 -3
- package/src/controllers/config.js +3 -1
- package/src/controllers/connections.js +23 -13
- package/src/controllers/databaseConnections.js +35 -12
- package/src/controllers/runners.js +21 -13
- package/src/controllers/scheduler.js +4 -1
- package/src/controllers/serverConnections.js +37 -10
- package/src/controllers/sessions.js +27 -10
- package/src/controllers/uploads.js +3 -1
- package/src/currentVersion.js +2 -2
- package/src/index.js +96 -2
- package/src/main.js +12 -9
- package/src/proc/databaseConnectionProcess.js +8 -6
- package/src/proc/serverConnectionProcess.js +4 -3
- package/src/proc/sessionProcess.js +26 -1
- package/src/proc/sshForwardProcess.js +5 -2
- package/src/shell/archiveWriter.js +4 -1
- package/src/shell/dumpDatabase.js +5 -2
- package/src/shell/executeQuery.js +5 -2
- package/src/shell/generateModelSql.js +30 -0
- package/src/shell/importDatabase.js +5 -2
- package/src/shell/index.js +4 -0
- package/src/shell/jsonArrayWriter.js +4 -1
- package/src/shell/jsonLinesReader.js +3 -1
- package/src/shell/jsonLinesWriter.js +3 -1
- package/src/shell/loadDatabase.js +21 -0
- package/src/shell/queryReader.js +4 -2
- package/src/shell/requirePlugin.js +3 -1
- package/src/shell/runScript.js +3 -1
- package/src/shell/sqlDataWriter.js +3 -2
- package/src/shell/tableReader.js +6 -5
- package/src/shell/tableWriter.js +4 -3
- package/src/utility/DatastoreProxy.js +29 -9
- package/src/utility/childProcessChecker.js +6 -2
- package/src/utility/cleanDirectory.js +2 -2
- package/src/utility/directories.js +22 -6
- package/src/utility/pipeForkLogs.js +19 -0
- package/src/utility/processArgs.js +2 -0
- package/src/utility/sshTunnel.js +23 -14
- package/src/utility/sshTunnelProxy.js +7 -1
- package/src/utility/useController.js +9 -7
package/src/shell/tableReader.js
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
const { quoteFullName, fullNameToString } = require('dbgate-tools');
|
|
1
|
+
const { quoteFullName, fullNameToString, getLogger } = require('dbgate-tools');
|
|
2
2
|
const requireEngineDriver = require('../utility/requireEngineDriver');
|
|
3
3
|
const connectUtility = require('../utility/connectUtility');
|
|
4
|
+
const logger = getLogger('tableReader');
|
|
4
5
|
|
|
5
6
|
async function tableReader({ connection, pureName, schemaName }) {
|
|
6
7
|
const driver = requireEngineDriver(connection);
|
|
7
8
|
const pool = await connectUtility(driver, connection, 'read');
|
|
8
|
-
|
|
9
|
+
logger.info(`Connected.`);
|
|
9
10
|
|
|
10
11
|
const fullName = { pureName, schemaName };
|
|
11
12
|
|
|
12
13
|
if (driver.databaseEngineTypes.includes('document')) {
|
|
13
14
|
// @ts-ignore
|
|
14
|
-
|
|
15
|
+
logger.info(`Reading collection ${fullNameToString(fullName)}`);
|
|
15
16
|
// @ts-ignore
|
|
16
17
|
return await driver.readQuery(pool, JSON.stringify(fullName));
|
|
17
18
|
}
|
|
@@ -20,14 +21,14 @@ async function tableReader({ connection, pureName, schemaName }) {
|
|
|
20
21
|
const query = `select * from ${quoteFullName(driver.dialect, fullName)}`;
|
|
21
22
|
if (table) {
|
|
22
23
|
// @ts-ignore
|
|
23
|
-
|
|
24
|
+
logger.info(`Reading table ${fullNameToString(table)}`);
|
|
24
25
|
// @ts-ignore
|
|
25
26
|
return await driver.readQuery(pool, query, table);
|
|
26
27
|
}
|
|
27
28
|
const view = await driver.analyseSingleObject(pool, fullName, 'views');
|
|
28
29
|
if (view) {
|
|
29
30
|
// @ts-ignore
|
|
30
|
-
|
|
31
|
+
logger.info(`Reading view ${fullNameToString(view)}`);
|
|
31
32
|
// @ts-ignore
|
|
32
33
|
return await driver.readQuery(pool, query, view);
|
|
33
34
|
}
|
package/src/shell/tableWriter.js
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
const { fullNameToString } = require('dbgate-tools');
|
|
1
|
+
const { fullNameToString, getLogger } = require('dbgate-tools');
|
|
2
2
|
const requireEngineDriver = require('../utility/requireEngineDriver');
|
|
3
3
|
const connectUtility = require('../utility/connectUtility');
|
|
4
|
+
const logger = getLogger('tableWriter');
|
|
4
5
|
|
|
5
6
|
async function tableWriter({ connection, schemaName, pureName, driver, systemConnection, ...options }) {
|
|
6
|
-
|
|
7
|
+
logger.info(`Writing table ${fullNameToString({ schemaName, pureName })}`);
|
|
7
8
|
|
|
8
9
|
if (!driver) {
|
|
9
10
|
driver = requireEngineDriver(connection);
|
|
10
11
|
}
|
|
11
12
|
const pool = systemConnection || (await connectUtility(driver, connection, 'write'));
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
logger.info(`Connected.`);
|
|
14
15
|
return await driver.writeTable(pool, { schemaName, pureName }, options);
|
|
15
16
|
}
|
|
16
17
|
|
|
@@ -2,6 +2,9 @@ const { fork } = require('child_process');
|
|
|
2
2
|
const uuidv1 = require('uuid/v1');
|
|
3
3
|
const { handleProcessCommunication } = require('./processComm');
|
|
4
4
|
const processArgs = require('../utility/processArgs');
|
|
5
|
+
const pipeForkLogs = require('./pipeForkLogs');
|
|
6
|
+
const { getLogger } = require('dbgate-tools');
|
|
7
|
+
const logger = getLogger('DatastoreProxy');
|
|
5
8
|
|
|
6
9
|
class DatastoreProxy {
|
|
7
10
|
constructor(file) {
|
|
@@ -30,13 +33,20 @@ class DatastoreProxy {
|
|
|
30
33
|
|
|
31
34
|
async ensureSubprocess() {
|
|
32
35
|
if (!this.subprocess) {
|
|
33
|
-
this.subprocess = fork(
|
|
34
|
-
'
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
this.subprocess = fork(
|
|
37
|
+
global['API_PACKAGE'] || process.argv[1],
|
|
38
|
+
[
|
|
39
|
+
'--is-forked-api',
|
|
40
|
+
'--start-process',
|
|
41
|
+
'jslDatastoreProcess',
|
|
42
|
+
...processArgs.getPassArgs(),
|
|
43
|
+
// ...process.argv.slice(3),
|
|
44
|
+
],
|
|
45
|
+
{
|
|
46
|
+
stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
|
|
47
|
+
}
|
|
48
|
+
);
|
|
49
|
+
pipeForkLogs(this.subprocess);
|
|
40
50
|
|
|
41
51
|
this.subprocess.on('message', message => {
|
|
42
52
|
// @ts-ignore
|
|
@@ -60,7 +70,12 @@ class DatastoreProxy {
|
|
|
60
70
|
const msgid = uuidv1();
|
|
61
71
|
const promise = new Promise((resolve, reject) => {
|
|
62
72
|
this.requests[msgid] = [resolve, reject];
|
|
63
|
-
|
|
73
|
+
try {
|
|
74
|
+
this.subprocess.send({ msgtype: 'read', msgid, offset, limit });
|
|
75
|
+
} catch (err) {
|
|
76
|
+
logger.error({ err }, 'Error getting rows');
|
|
77
|
+
this.subprocess = null;
|
|
78
|
+
}
|
|
64
79
|
});
|
|
65
80
|
return promise;
|
|
66
81
|
}
|
|
@@ -69,7 +84,12 @@ class DatastoreProxy {
|
|
|
69
84
|
const msgid = uuidv1();
|
|
70
85
|
const promise = new Promise((resolve, reject) => {
|
|
71
86
|
this.requests[msgid] = [resolve, reject];
|
|
72
|
-
|
|
87
|
+
try {
|
|
88
|
+
this.subprocess.send({ msgtype: 'notify', msgid });
|
|
89
|
+
} catch (err) {
|
|
90
|
+
logger.error({ err }, 'Error notifying subprocess');
|
|
91
|
+
this.subprocess = null;
|
|
92
|
+
}
|
|
73
93
|
});
|
|
74
94
|
return promise;
|
|
75
95
|
}
|
|
@@ -1,14 +1,18 @@
|
|
|
1
|
+
const { getLogger } = require('dbgate-tools');
|
|
2
|
+
|
|
3
|
+
const logger = getLogger('childProcessChecked');
|
|
4
|
+
|
|
1
5
|
let counter = 0;
|
|
2
6
|
|
|
3
7
|
function childProcessChecker() {
|
|
4
8
|
setInterval(() => {
|
|
5
9
|
try {
|
|
6
10
|
process.send({ msgtype: 'ping', counter: counter++ });
|
|
7
|
-
} catch (
|
|
11
|
+
} catch (err) {
|
|
8
12
|
// This will come once parent dies.
|
|
9
13
|
// One way can be to check for error code ERR_IPC_CHANNEL_CLOSED
|
|
10
14
|
// and call process.exit()
|
|
11
|
-
|
|
15
|
+
logger.error({ err }, 'parent died');
|
|
12
16
|
process.exit(1);
|
|
13
17
|
}
|
|
14
18
|
}, 1000);
|
|
@@ -2,7 +2,7 @@ const fs = require('fs-extra');
|
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const ageSeconds = 3600;
|
|
4
4
|
|
|
5
|
-
async function cleanDirectory(directory) {
|
|
5
|
+
async function cleanDirectory(directory, age = undefined) {
|
|
6
6
|
const files = await fs.readdir(directory);
|
|
7
7
|
const now = new Date().getTime();
|
|
8
8
|
|
|
@@ -10,7 +10,7 @@ async function cleanDirectory(directory) {
|
|
|
10
10
|
const full = path.join(directory, file);
|
|
11
11
|
const stat = await fs.stat(full);
|
|
12
12
|
const mtime = stat.mtime.getTime();
|
|
13
|
-
const expirationTime = mtime + ageSeconds * 1000;
|
|
13
|
+
const expirationTime = mtime + (age || ageSeconds) * 1000;
|
|
14
14
|
if (now > expirationTime) {
|
|
15
15
|
if (stat.isDirectory()) {
|
|
16
16
|
await fs.rmdir(full, { recursive: true });
|
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
const os = require('os');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const fs = require('fs');
|
|
4
|
+
const _ = require('lodash');
|
|
4
5
|
const cleanDirectory = require('./cleanDirectory');
|
|
5
6
|
const platformInfo = require('./platformInfo');
|
|
6
7
|
const processArgs = require('./processArgs');
|
|
7
8
|
const consoleObjectWriter = require('../shell/consoleObjectWriter');
|
|
9
|
+
const { getLogger } = require('dbgate-tools');
|
|
10
|
+
|
|
11
|
+
let logsFilePath;
|
|
8
12
|
|
|
9
13
|
const createDirectories = {};
|
|
10
14
|
const ensureDirectory = (dir, clean) => {
|
|
11
15
|
if (!createDirectories[dir]) {
|
|
12
16
|
if (clean && fs.existsSync(dir) && !platformInfo.isForkedApi) {
|
|
13
|
-
|
|
14
|
-
cleanDirectory(dir);
|
|
17
|
+
getLogger('directories').info(`Cleaning directory ${dir}`);
|
|
18
|
+
cleanDirectory(dir, _.isNumber(clean) ? clean : null);
|
|
15
19
|
}
|
|
16
20
|
if (!fs.existsSync(dir)) {
|
|
17
|
-
|
|
21
|
+
getLogger('directories').info(`Creating directory ${dir}`);
|
|
18
22
|
fs.mkdirSync(dir);
|
|
19
23
|
}
|
|
20
24
|
createDirectories[dir] = true;
|
|
@@ -38,7 +42,7 @@ function datadir() {
|
|
|
38
42
|
return dir;
|
|
39
43
|
}
|
|
40
44
|
|
|
41
|
-
const dirFunc = (dirname, clean
|
|
45
|
+
const dirFunc = (dirname, clean) => () => {
|
|
42
46
|
const dir = path.join(datadir(), dirname);
|
|
43
47
|
ensureDirectory(dir, clean);
|
|
44
48
|
|
|
@@ -52,6 +56,7 @@ const pluginsdir = dirFunc('plugins');
|
|
|
52
56
|
const archivedir = dirFunc('archive');
|
|
53
57
|
const appdir = dirFunc('apps');
|
|
54
58
|
const filesdir = dirFunc('files');
|
|
59
|
+
const logsdir = dirFunc('logs', 3600 * 24 * 7);
|
|
55
60
|
|
|
56
61
|
function packagedPluginsDir() {
|
|
57
62
|
// console.log('CALL DIR FROM', new Error('xxx').stack);
|
|
@@ -127,11 +132,19 @@ function migrateDataDir() {
|
|
|
127
132
|
if (fs.existsSync(oldDir) && !fs.existsSync(newDir)) {
|
|
128
133
|
fs.renameSync(oldDir, newDir);
|
|
129
134
|
}
|
|
130
|
-
} catch (
|
|
131
|
-
|
|
135
|
+
} catch (err) {
|
|
136
|
+
getLogger('directories').error({ err }, 'Error migrating data dir');
|
|
132
137
|
}
|
|
133
138
|
}
|
|
134
139
|
|
|
140
|
+
function setLogsFilePath(value) {
|
|
141
|
+
logsFilePath = value;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function getLogsFilePath() {
|
|
145
|
+
return logsFilePath;
|
|
146
|
+
}
|
|
147
|
+
|
|
135
148
|
migrateDataDir();
|
|
136
149
|
|
|
137
150
|
module.exports = {
|
|
@@ -144,9 +157,12 @@ module.exports = {
|
|
|
144
157
|
ensureDirectory,
|
|
145
158
|
pluginsdir,
|
|
146
159
|
filesdir,
|
|
160
|
+
logsdir,
|
|
147
161
|
packagedPluginsDir,
|
|
148
162
|
packagedPluginList,
|
|
149
163
|
getPluginBackendPath,
|
|
150
164
|
resolveArchiveFolder,
|
|
151
165
|
clearArchiveLinksCache,
|
|
166
|
+
getLogsFilePath,
|
|
167
|
+
setLogsFilePath,
|
|
152
168
|
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const byline = require('byline');
|
|
2
|
+
const { safeJsonParse, getLogger } = require('dbgate-tools');
|
|
3
|
+
const logger = getLogger();
|
|
4
|
+
|
|
5
|
+
const logDispatcher = method => data => {
|
|
6
|
+
const json = safeJsonParse(data.toString());
|
|
7
|
+
if (json && json.level) {
|
|
8
|
+
logger.log(json);
|
|
9
|
+
} else {
|
|
10
|
+
logger[method](json || data.toString());
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
function pipeForkLogs(subprocess) {
|
|
15
|
+
byline(subprocess.stdout).on('data', logDispatcher('info'));
|
|
16
|
+
byline(subprocess.stderr).on('data', logDispatcher('error'));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
module.exports = pipeForkLogs;
|
|
@@ -11,6 +11,7 @@ const startProcess = getNamedArg('--start-process');
|
|
|
11
11
|
const isForkedApi = process.argv.includes('--is-forked-api');
|
|
12
12
|
const pluginsDir = getNamedArg('--plugins-dir');
|
|
13
13
|
const workspaceDir = getNamedArg('--workspace-dir');
|
|
14
|
+
const processDisplayName = getNamedArg('--process-display-name');
|
|
14
15
|
const listenApi = process.argv.includes('--listen-api');
|
|
15
16
|
const listenApiChild = process.argv.includes('--listen-api-child') || listenApi;
|
|
16
17
|
|
|
@@ -37,4 +38,5 @@ module.exports = {
|
|
|
37
38
|
workspaceDir,
|
|
38
39
|
listenApi,
|
|
39
40
|
listenApiChild,
|
|
41
|
+
processDisplayName,
|
|
40
42
|
};
|
package/src/utility/sshTunnel.js
CHANGED
|
@@ -5,6 +5,9 @@ const AsyncLock = require('async-lock');
|
|
|
5
5
|
const lock = new AsyncLock();
|
|
6
6
|
const { fork } = require('child_process');
|
|
7
7
|
const processArgs = require('../utility/processArgs');
|
|
8
|
+
const { getLogger } = require('dbgate-tools');
|
|
9
|
+
const pipeForkLogs = require('./pipeForkLogs');
|
|
10
|
+
const logger = getLogger('sshTunnel');
|
|
8
11
|
|
|
9
12
|
const sshTunnelCache = {};
|
|
10
13
|
|
|
@@ -21,18 +24,24 @@ const CONNECTION_FIELDS = [
|
|
|
21
24
|
const TUNNEL_FIELDS = [...CONNECTION_FIELDS, 'server', 'port'];
|
|
22
25
|
|
|
23
26
|
function callForwardProcess(connection, tunnelConfig, tunnelCacheKey) {
|
|
24
|
-
let subprocess = fork(
|
|
25
|
-
'
|
|
26
|
-
'--start-process',
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
let subprocess = fork(
|
|
28
|
+
global['API_PACKAGE'] || process.argv[1],
|
|
29
|
+
['--is-forked-api', '--start-process', 'sshForwardProcess', ...processArgs.getPassArgs()],
|
|
30
|
+
{
|
|
31
|
+
stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
|
|
32
|
+
}
|
|
33
|
+
);
|
|
34
|
+
pipeForkLogs(subprocess);
|
|
30
35
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
try {
|
|
37
|
+
subprocess.send({
|
|
38
|
+
msgtype: 'connect',
|
|
39
|
+
connection,
|
|
40
|
+
tunnelConfig,
|
|
41
|
+
});
|
|
42
|
+
} catch (err) {
|
|
43
|
+
logger.error({ err }, 'Error connecting SSH');
|
|
44
|
+
}
|
|
36
45
|
return new Promise((resolve, reject) => {
|
|
37
46
|
subprocess.on('message', resp => {
|
|
38
47
|
// @ts-ignore
|
|
@@ -45,7 +54,7 @@ function callForwardProcess(connection, tunnelConfig, tunnelCacheKey) {
|
|
|
45
54
|
}
|
|
46
55
|
});
|
|
47
56
|
subprocess.on('exit', code => {
|
|
48
|
-
|
|
57
|
+
logger.info('SSH forward process exited');
|
|
49
58
|
delete sshTunnelCache[tunnelCacheKey];
|
|
50
59
|
});
|
|
51
60
|
});
|
|
@@ -65,13 +74,13 @@ async function getSshTunnel(connection) {
|
|
|
65
74
|
toHost: connection.server,
|
|
66
75
|
};
|
|
67
76
|
try {
|
|
68
|
-
|
|
77
|
+
logger.info(
|
|
69
78
|
`Creating SSH tunnel to ${connection.sshHost}-${connection.server}:${connection.port}, using local port ${localPort}`
|
|
70
79
|
);
|
|
71
80
|
|
|
72
81
|
const subprocess = await callForwardProcess(connection, tunnelConfig, tunnelCacheKey);
|
|
73
82
|
|
|
74
|
-
|
|
83
|
+
logger.info(
|
|
75
84
|
`Created SSH tunnel to ${connection.sshHost}-${connection.server}:${connection.port}, using local port ${localPort}`
|
|
76
85
|
);
|
|
77
86
|
|
|
@@ -1,11 +1,17 @@
|
|
|
1
|
+
const { getLogger } = require('dbgate-tools');
|
|
1
2
|
const uuidv1 = require('uuid/v1');
|
|
2
3
|
const { getSshTunnel } = require('./sshTunnel');
|
|
4
|
+
const logger = getLogger('sshTunnelProxy');
|
|
3
5
|
|
|
4
6
|
const dispatchedMessages = {};
|
|
5
7
|
|
|
6
8
|
async function handleGetSshTunnelRequest({ msgid, connection }, subprocess) {
|
|
7
9
|
const response = await getSshTunnel(connection);
|
|
8
|
-
|
|
10
|
+
try {
|
|
11
|
+
subprocess.send({ msgtype: 'getsshtunnel-response', msgid, response });
|
|
12
|
+
} catch (err) {
|
|
13
|
+
logger.error({ err }, 'Error sending to SSH tunnel');
|
|
14
|
+
}
|
|
9
15
|
}
|
|
10
16
|
|
|
11
17
|
function handleGetSshTunnelResponse({ msgid, response }, subprocess) {
|
|
@@ -2,7 +2,9 @@ const _ = require('lodash');
|
|
|
2
2
|
const express = require('express');
|
|
3
3
|
const getExpressPath = require('./getExpressPath');
|
|
4
4
|
const { MissingCredentialsError } = require('./exceptions');
|
|
5
|
+
const { getLogger } = require('dbgate-tools');
|
|
5
6
|
|
|
7
|
+
const logger = getLogger('useController');
|
|
6
8
|
/**
|
|
7
9
|
* @param {string} route
|
|
8
10
|
*/
|
|
@@ -10,11 +12,11 @@ module.exports = function useController(app, electron, route, controller) {
|
|
|
10
12
|
const router = express.Router();
|
|
11
13
|
|
|
12
14
|
if (controller._init) {
|
|
13
|
-
|
|
15
|
+
logger.info(`Calling init controller for controller ${route}`);
|
|
14
16
|
try {
|
|
15
17
|
controller._init();
|
|
16
18
|
} catch (err) {
|
|
17
|
-
|
|
19
|
+
logger.error({ err }, `Error initializing controller, exiting application`);
|
|
18
20
|
process.exit(1);
|
|
19
21
|
}
|
|
20
22
|
}
|
|
@@ -75,16 +77,16 @@ module.exports = function useController(app, electron, route, controller) {
|
|
|
75
77
|
try {
|
|
76
78
|
const data = await controller[key]({ ...req.body, ...req.query }, req);
|
|
77
79
|
res.json(data);
|
|
78
|
-
} catch (
|
|
79
|
-
|
|
80
|
-
if (
|
|
80
|
+
} catch (err) {
|
|
81
|
+
logger.error({ err }, `Error when processing route ${route}/${key}`);
|
|
82
|
+
if (err instanceof MissingCredentialsError) {
|
|
81
83
|
res.json({
|
|
82
84
|
missingCredentials: true,
|
|
83
85
|
apiErrorMessage: 'Missing credentials',
|
|
84
|
-
detail:
|
|
86
|
+
detail: err.detail,
|
|
85
87
|
});
|
|
86
88
|
} else {
|
|
87
|
-
res.status(500).json({ apiErrorMessage:
|
|
89
|
+
res.status(500).json({ apiErrorMessage: err.message });
|
|
88
90
|
}
|
|
89
91
|
}
|
|
90
92
|
});
|