dbgate-api-premium 5.5.7-alpha.45

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 (125) hide show
  1. package/.env +19 -0
  2. package/.yarnrc +2 -0
  3. package/README.md +1 -0
  4. package/env/dblogin/.env +14 -0
  5. package/env/portal/.env +70 -0
  6. package/env/singledb/.env +17 -0
  7. package/env/storage/.env +43 -0
  8. package/package.json +89 -0
  9. package/src/auth/authCommon.js +16 -0
  10. package/src/auth/authProvider.js +343 -0
  11. package/src/auth/storageAuthProvider.js +393 -0
  12. package/src/controllers/apps.js +280 -0
  13. package/src/controllers/archive.js +217 -0
  14. package/src/controllers/auth.js +136 -0
  15. package/src/controllers/config.js +271 -0
  16. package/src/controllers/connections.js +486 -0
  17. package/src/controllers/databaseConnections.js +561 -0
  18. package/src/controllers/files.js +222 -0
  19. package/src/controllers/jsldata.js +296 -0
  20. package/src/controllers/metadata.js +47 -0
  21. package/src/controllers/plugins.js +216 -0
  22. package/src/controllers/queryHistory.js +54 -0
  23. package/src/controllers/runners.js +234 -0
  24. package/src/controllers/scheduler.js +46 -0
  25. package/src/controllers/serverConnections.js +271 -0
  26. package/src/controllers/sessions.js +243 -0
  27. package/src/controllers/storage.js +380 -0
  28. package/src/controllers/storageDb.js +215 -0
  29. package/src/controllers/uploads.js +133 -0
  30. package/src/currentVersion.js +5 -0
  31. package/src/gistSecret.js +2 -0
  32. package/src/index.js +139 -0
  33. package/src/main.js +202 -0
  34. package/src/packagedPluginsContent.js +1 -0
  35. package/src/proc/connectProcess.js +38 -0
  36. package/src/proc/databaseConnectionProcess.js +431 -0
  37. package/src/proc/index.js +15 -0
  38. package/src/proc/jslDatastoreProcess.js +60 -0
  39. package/src/proc/serverConnectionProcess.js +188 -0
  40. package/src/proc/sessionProcess.js +390 -0
  41. package/src/proc/sshForwardProcess.js +75 -0
  42. package/src/shell/archiveReader.js +11 -0
  43. package/src/shell/archiveWriter.js +22 -0
  44. package/src/shell/autoIndexForeignKeysTransform.js +19 -0
  45. package/src/shell/collectorWriter.js +33 -0
  46. package/src/shell/consoleObjectWriter.js +16 -0
  47. package/src/shell/copyStream.js +48 -0
  48. package/src/shell/dataDuplicator.js +63 -0
  49. package/src/shell/dataTypeMapperTransform.js +21 -0
  50. package/src/shell/dbModelToJson.js +16 -0
  51. package/src/shell/deployDb.js +56 -0
  52. package/src/shell/download.js +15 -0
  53. package/src/shell/dropAllDbObjects.js +42 -0
  54. package/src/shell/dumpDatabase.js +49 -0
  55. package/src/shell/executeQuery.js +39 -0
  56. package/src/shell/fakeObjectReader.js +35 -0
  57. package/src/shell/finalizer.js +12 -0
  58. package/src/shell/generateDeploySql.js +95 -0
  59. package/src/shell/generateModelSql.js +30 -0
  60. package/src/shell/importDatabase.js +85 -0
  61. package/src/shell/index.js +80 -0
  62. package/src/shell/initializeApiEnvironment.js +9 -0
  63. package/src/shell/jslDataReader.js +9 -0
  64. package/src/shell/jsonLinesReader.js +52 -0
  65. package/src/shell/jsonLinesWriter.js +36 -0
  66. package/src/shell/jsonReader.js +84 -0
  67. package/src/shell/jsonToDbModel.js +9 -0
  68. package/src/shell/jsonWriter.js +97 -0
  69. package/src/shell/loadDatabase.js +27 -0
  70. package/src/shell/loadFile.js +10 -0
  71. package/src/shell/modifyJsonLinesReader.js +148 -0
  72. package/src/shell/queryReader.js +30 -0
  73. package/src/shell/registerPlugins.js +9 -0
  74. package/src/shell/requirePlugin.js +43 -0
  75. package/src/shell/runScript.js +19 -0
  76. package/src/shell/sqlDataWriter.js +52 -0
  77. package/src/shell/sqlTextReplacementTransform.js +32 -0
  78. package/src/shell/tableReader.js +39 -0
  79. package/src/shell/tableWriter.js +18 -0
  80. package/src/storageModel.js +819 -0
  81. package/src/utility/ColumnMapTransformStream.js +21 -0
  82. package/src/utility/DatastoreProxy.js +106 -0
  83. package/src/utility/EnsureStreamHeaderStream.js +31 -0
  84. package/src/utility/JsonLinesDatabase.js +148 -0
  85. package/src/utility/JsonLinesDatastore.js +232 -0
  86. package/src/utility/LineReader.js +88 -0
  87. package/src/utility/SSHConnection.js +251 -0
  88. package/src/utility/authProxy.js +133 -0
  89. package/src/utility/checkLicense.js +186 -0
  90. package/src/utility/childProcessChecker.js +21 -0
  91. package/src/utility/cleanDirectory.js +24 -0
  92. package/src/utility/cloudUpgrade.js +61 -0
  93. package/src/utility/connectUtility.js +111 -0
  94. package/src/utility/crypting.js +105 -0
  95. package/src/utility/diff2htmlPage.js +8 -0
  96. package/src/utility/directories.js +179 -0
  97. package/src/utility/downloadPackage.js +51 -0
  98. package/src/utility/downloader.js +25 -0
  99. package/src/utility/exceptions.js +9 -0
  100. package/src/utility/exportDbModel.js +31 -0
  101. package/src/utility/exportDbModelSql.js +80 -0
  102. package/src/utility/getChartExport.js +55 -0
  103. package/src/utility/getDiagramExport.js +25 -0
  104. package/src/utility/getExpressPath.js +10 -0
  105. package/src/utility/getJslFileName.js +16 -0
  106. package/src/utility/getMapExport.js +77 -0
  107. package/src/utility/hardwareFingerprint.js +89 -0
  108. package/src/utility/hasPermission.js +101 -0
  109. package/src/utility/importDbModel.js +9 -0
  110. package/src/utility/loadFilesRecursive.js +20 -0
  111. package/src/utility/loadModelFolder.js +29 -0
  112. package/src/utility/loadModelTransform.js +36 -0
  113. package/src/utility/pipeForkLogs.js +19 -0
  114. package/src/utility/platformInfo.js +62 -0
  115. package/src/utility/processArgs.js +39 -0
  116. package/src/utility/processComm.js +18 -0
  117. package/src/utility/requireEngineDriver.js +26 -0
  118. package/src/utility/requirePluginFunction.js +16 -0
  119. package/src/utility/socket.js +68 -0
  120. package/src/utility/sshTunnel.js +106 -0
  121. package/src/utility/sshTunnelProxy.js +36 -0
  122. package/src/utility/timingSafeCheckToken.js +9 -0
  123. package/src/utility/useController.js +99 -0
  124. package/tsconfig.json +13 -0
  125. package/webpack.config.js +55 -0
@@ -0,0 +1,271 @@
1
+ const crypto = require('crypto');
2
+ const connections = require('./connections');
3
+ const socket = require('../utility/socket');
4
+ const { fork } = require('child_process');
5
+ const _ = require('lodash');
6
+ const AsyncLock = require('async-lock');
7
+ const { handleProcessCommunication } = require('../utility/processComm');
8
+ const lock = new AsyncLock();
9
+ const config = require('./config');
10
+ const processArgs = require('../utility/processArgs');
11
+ const { testConnectionPermission } = require('../utility/hasPermission');
12
+ const { MissingCredentialsError } = require('../utility/exceptions');
13
+ const pipeForkLogs = require('../utility/pipeForkLogs');
14
+ const { getLogger, extractErrorLogData } = require('dbgate-tools');
15
+
16
+ const logger = getLogger('serverConnection');
17
+
18
+ module.exports = {
19
+ opened: [],
20
+ closed: {},
21
+ lastPinged: {},
22
+ requests: {},
23
+
24
+ handle_databases(conid, { databases }) {
25
+ const existing = this.opened.find(x => x.conid == conid);
26
+ if (!existing) return;
27
+ existing.databases = databases;
28
+ socket.emitChanged(`database-list-changed`, { conid });
29
+ },
30
+ handle_version(conid, { version }) {
31
+ const existing = this.opened.find(x => x.conid == conid);
32
+ if (!existing) return;
33
+ existing.version = version;
34
+ socket.emitChanged(`server-version-changed`, { conid });
35
+ },
36
+ handle_status(conid, { status }) {
37
+ const existing = this.opened.find(x => x.conid == conid);
38
+ if (!existing) return;
39
+ existing.status = status;
40
+ socket.emitChanged(`server-status-changed`);
41
+ },
42
+ handle_ping() {},
43
+ handle_response(conid, { msgid, ...response }) {
44
+ const [resolve, reject] = this.requests[msgid];
45
+ resolve(response);
46
+ delete this.requests[msgid];
47
+ },
48
+
49
+ async ensureOpened(conid) {
50
+ const res = await lock.acquire(conid, async () => {
51
+ const existing = this.opened.find(x => x.conid == conid);
52
+ if (existing) return existing;
53
+ const connection = await connections.getCore({ conid });
54
+ if (!connection) {
55
+ throw new Error(`Connection with conid="${conid}" not fund`);
56
+ }
57
+ if (connection.passwordMode == 'askPassword' || connection.passwordMode == 'askUser') {
58
+ throw new MissingCredentialsError({ conid, passwordMode: connection.passwordMode });
59
+ }
60
+ if (connection.useRedirectDbLogin) {
61
+ throw new MissingCredentialsError({ conid, redirectToDbLogin: true });
62
+ }
63
+ const subprocess = fork(
64
+ global['API_PACKAGE'] || process.argv[1],
65
+ [
66
+ '--is-forked-api',
67
+ '--start-process',
68
+ 'serverConnectionProcess',
69
+ ...processArgs.getPassArgs(),
70
+ // ...process.argv.slice(3),
71
+ ],
72
+ {
73
+ stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
74
+ }
75
+ );
76
+ pipeForkLogs(subprocess);
77
+ const newOpened = {
78
+ conid,
79
+ subprocess,
80
+ databases: [],
81
+ connection,
82
+ status: {
83
+ name: 'pending',
84
+ },
85
+ disconnected: false,
86
+ };
87
+ this.opened.push(newOpened);
88
+ delete this.closed[conid];
89
+ socket.emitChanged(`server-status-changed`);
90
+ subprocess.on('message', message => {
91
+ // @ts-ignore
92
+ const { msgtype } = message;
93
+ if (handleProcessCommunication(message, subprocess)) return;
94
+ if (newOpened.disconnected) return;
95
+ this[`handle_${msgtype}`](conid, message);
96
+ });
97
+ subprocess.on('exit', () => {
98
+ if (newOpened.disconnected) return;
99
+ this.close(conid, false);
100
+ });
101
+ subprocess.send({ msgtype: 'connect', ...connection, globalSettings: await config.getSettings() });
102
+ return newOpened;
103
+ });
104
+ return res;
105
+ },
106
+
107
+ close(conid, kill = true) {
108
+ const existing = this.opened.find(x => x.conid == conid);
109
+ if (existing) {
110
+ existing.disconnected = true;
111
+ if (kill) {
112
+ try {
113
+ existing.subprocess.kill();
114
+ } catch (err) {
115
+ logger.error(extractErrorLogData(err), 'Error killing subprocess');
116
+ }
117
+ }
118
+ this.opened = this.opened.filter(x => x.conid != conid);
119
+ this.closed[conid] = {
120
+ ...existing.status,
121
+ name: 'error',
122
+ };
123
+ socket.emitChanged(`server-status-changed`);
124
+ }
125
+ },
126
+
127
+ disconnect_meta: true,
128
+ async disconnect({ conid }, req) {
129
+ testConnectionPermission(conid, req);
130
+ await this.close(conid, true);
131
+ return { status: 'ok' };
132
+ },
133
+
134
+ listDatabases_meta: true,
135
+ async listDatabases({ conid }, req) {
136
+ if (!conid) return [];
137
+ if (conid == '__model') return [];
138
+ testConnectionPermission(conid, req);
139
+ const opened = await this.ensureOpened(conid);
140
+ return opened.databases;
141
+ },
142
+
143
+ version_meta: true,
144
+ async version({ conid }, req) {
145
+ testConnectionPermission(conid, req);
146
+ const opened = await this.ensureOpened(conid);
147
+ return opened.version;
148
+ },
149
+
150
+ serverStatus_meta: true,
151
+ async serverStatus() {
152
+ return {
153
+ ...this.closed,
154
+ ..._.mapValues(_.keyBy(this.opened, 'conid'), 'status'),
155
+ };
156
+ },
157
+
158
+ ping_meta: true,
159
+ async ping({ conidArray, strmid }) {
160
+ await Promise.all(
161
+ _.uniq(conidArray).map(async conid => {
162
+ const last = this.lastPinged[conid];
163
+ if (last && new Date().getTime() - last < 30 * 1000) {
164
+ return Promise.resolve();
165
+ }
166
+ this.lastPinged[conid] = new Date().getTime();
167
+ const opened = await this.ensureOpened(conid);
168
+ try {
169
+ opened.subprocess.send({ msgtype: 'ping' });
170
+ } catch (err) {
171
+ logger.error(extractErrorLogData(err), 'Error pinging server connection');
172
+ this.close(conid);
173
+ }
174
+ })
175
+ );
176
+ socket.setStreamIdFilter(strmid, { conid: [...(conidArray ?? []), '__model'] });
177
+ return { status: 'ok' };
178
+ },
179
+
180
+ refresh_meta: true,
181
+ async refresh({ conid, keepOpen }, req) {
182
+ testConnectionPermission(conid, req);
183
+ if (!keepOpen) this.close(conid);
184
+
185
+ await this.ensureOpened(conid);
186
+ return { status: 'ok' };
187
+ },
188
+
189
+ async sendDatabaseOp({ conid, msgtype, name }, req) {
190
+ testConnectionPermission(conid, req);
191
+ const opened = await this.ensureOpened(conid);
192
+ if (opened.connection.isReadOnly) return false;
193
+ const res = await this.sendRequest(opened, { msgtype, name });
194
+ if (res.errorMessage) {
195
+ console.error(res.errorMessage);
196
+
197
+ return {
198
+ apiErrorMessage: res.errorMessage,
199
+ };
200
+ }
201
+ return res.result || null;
202
+ },
203
+
204
+ createDatabase_meta: true,
205
+ async createDatabase({ conid, name }, req) {
206
+ return this.sendDatabaseOp({ conid, msgtype: 'createDatabase', name }, req);
207
+ },
208
+
209
+ dropDatabase_meta: true,
210
+ async dropDatabase({ conid, name }, req) {
211
+ return this.sendDatabaseOp({ conid, msgtype: 'dropDatabase', name }, req);
212
+ },
213
+
214
+ sendRequest(conn, message) {
215
+ const msgid = crypto.randomUUID();
216
+ const promise = new Promise((resolve, reject) => {
217
+ this.requests[msgid] = [resolve, reject];
218
+ try {
219
+ conn.subprocess.send({ msgid, ...message });
220
+ } catch (err) {
221
+ logger.error(extractErrorLogData(err), 'Error sending request');
222
+ this.close(conn.conid);
223
+ }
224
+ });
225
+ return promise;
226
+ },
227
+
228
+ async loadDataCore(msgtype, { conid, ...args }, req) {
229
+ testConnectionPermission(conid, req);
230
+ const opened = await this.ensureOpened(conid);
231
+ const res = await this.sendRequest(opened, { msgtype, ...args });
232
+ if (res.errorMessage) {
233
+ console.error(res.errorMessage);
234
+
235
+ return {
236
+ errorMessage: res.errorMessage,
237
+ };
238
+ }
239
+ return res.result || null;
240
+ },
241
+
242
+ serverSummary_meta: true,
243
+ async serverSummary({ conid }, req) {
244
+ testConnectionPermission(conid, req);
245
+ return this.loadDataCore('serverSummary', { conid });
246
+ },
247
+
248
+ summaryCommand_meta: true,
249
+ async summaryCommand({ conid, command, row }, req) {
250
+ testConnectionPermission(conid, req);
251
+ const opened = await this.ensureOpened(conid);
252
+ if (opened.connection.isReadOnly) return false;
253
+ return this.loadDataCore('summaryCommand', { conid, command, row });
254
+ },
255
+
256
+ getOpenedConnectionReport() {
257
+ return this.opened.map(con => ({
258
+ status: con.status,
259
+ versionText: con.version?.versionText,
260
+ databaseCount: con.databases.length,
261
+ connection: _.pick(con.connection, [
262
+ 'engine',
263
+ 'useSshTunnel',
264
+ 'authType',
265
+ 'trustServerCertificate',
266
+ 'useSsl',
267
+ 'sshMode',
268
+ ]),
269
+ }));
270
+ },
271
+ };
@@ -0,0 +1,243 @@
1
+ const crypto = require('crypto');
2
+ const _ = require('lodash');
3
+ const connections = require('./connections');
4
+ const socket = require('../utility/socket');
5
+ const { fork } = require('child_process');
6
+ const jsldata = require('./jsldata');
7
+ const path = require('path');
8
+ const { handleProcessCommunication } = require('../utility/processComm');
9
+ const processArgs = require('../utility/processArgs');
10
+ const { appdir } = require('../utility/directories');
11
+ const { getLogger, extractErrorLogData } = require('dbgate-tools');
12
+ const pipeForkLogs = require('../utility/pipeForkLogs');
13
+ const config = require('./config');
14
+
15
+ const logger = getLogger('sessions');
16
+
17
+ module.exports = {
18
+ /** @type {import('dbgate-types').OpenedSession[]} */
19
+ opened: [],
20
+
21
+ // handle_error(sesid, props) {
22
+ // const { error } = props;
23
+ // console.log(`Error in database session ${sesid}`, error);
24
+ // this.dispatchMessage(sesid, {
25
+ // severity: 'error',
26
+ // message: error && error.toString(),
27
+ // });
28
+ // },
29
+
30
+ // handle_row(sesid, props) {
31
+ // const { row } = props;
32
+ // socket.emit('sessionRow', row);
33
+ // },
34
+ dispatchMessage(sesid, message) {
35
+ if (_.isString(message)) {
36
+ socket.emit(`session-info-${sesid}`, {
37
+ message,
38
+ time: new Date(),
39
+ severity: 'info',
40
+ });
41
+ }
42
+ if (_.isPlainObject(message)) {
43
+ socket.emit(`session-info-${sesid}`, {
44
+ time: new Date(),
45
+ severity: 'info',
46
+ ...message,
47
+ });
48
+ }
49
+ },
50
+
51
+ handle_info(sesid, props) {
52
+ const { info } = props;
53
+ this.dispatchMessage(sesid, info);
54
+ },
55
+
56
+ handle_done(sesid, props) {
57
+ socket.emit(`session-done-${sesid}`);
58
+ if (!props.skipFinishedMessage) {
59
+ this.dispatchMessage(sesid, 'Query execution finished');
60
+ }
61
+ const session = this.opened.find(x => x.sesid == sesid);
62
+ if (session.loadingReader_jslid) {
63
+ socket.emit(`session-jslid-done-${session.loadingReader_jslid}`);
64
+ }
65
+ if (session.killOnDone) {
66
+ this.kill({ sesid });
67
+ }
68
+ },
69
+
70
+ handle_recordset(sesid, props) {
71
+ const { jslid, resultIndex } = props;
72
+ socket.emit(`session-recordset-${sesid}`, { jslid, resultIndex });
73
+ },
74
+
75
+ handle_stats(sesid, stats) {
76
+ jsldata.notifyChangedStats(stats);
77
+ },
78
+
79
+ handle_initializeFile(sesid, props) {
80
+ const { jslid } = props;
81
+ socket.emit(`session-initialize-file-${jslid}`);
82
+ },
83
+
84
+ handle_ping() {},
85
+
86
+ create_meta: true,
87
+ async create({ conid, database }) {
88
+ const sesid = crypto.randomUUID();
89
+ const connection = await connections.getCore({ conid });
90
+ const subprocess = fork(
91
+ global['API_PACKAGE'] || process.argv[1],
92
+ [
93
+ '--is-forked-api',
94
+ '--start-process',
95
+ 'sessionProcess',
96
+ ...processArgs.getPassArgs(),
97
+ // ...process.argv.slice(3),
98
+ ],
99
+ {
100
+ stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
101
+ }
102
+ );
103
+ pipeForkLogs(subprocess);
104
+ const newOpened = {
105
+ conid,
106
+ database,
107
+ subprocess,
108
+ connection,
109
+ sesid,
110
+ };
111
+ this.opened.push(newOpened);
112
+ subprocess.on('message', message => {
113
+ // @ts-ignore
114
+ const { msgtype } = message;
115
+ if (handleProcessCommunication(message, subprocess)) return;
116
+ this[`handle_${msgtype}`](sesid, message);
117
+ });
118
+ subprocess.on('exit', () => {
119
+ this.opened = this.opened.filter(x => x.sesid != sesid);
120
+ this.dispatchMessage(sesid, 'Query session closed');
121
+ socket.emit(`session-closed-${sesid}`);
122
+ });
123
+
124
+ subprocess.send({
125
+ msgtype: 'connect',
126
+ ...connection,
127
+ database,
128
+ globalSettings: await config.getSettings(),
129
+ });
130
+ return _.pick(newOpened, ['conid', 'database', 'sesid']);
131
+ },
132
+
133
+ executeQuery_meta: true,
134
+ async executeQuery({ sesid, sql }) {
135
+ const session = this.opened.find(x => x.sesid == sesid);
136
+ if (!session) {
137
+ throw new Error('Invalid session');
138
+ }
139
+
140
+ logger.info({ sesid, sql }, 'Processing query');
141
+ this.dispatchMessage(sesid, 'Query execution started');
142
+ session.subprocess.send({ msgtype: 'executeQuery', sql });
143
+
144
+ return { state: 'ok' };
145
+ },
146
+
147
+ executeReader_meta: true,
148
+ async executeReader({ conid, database, sql, queryName, appFolder }) {
149
+ const { sesid } = await this.create({ conid, database });
150
+ const session = this.opened.find(x => x.sesid == sesid);
151
+ session.killOnDone = true;
152
+ const jslid = crypto.randomUUID();
153
+ session.loadingReader_jslid = jslid;
154
+ const fileName = queryName && appFolder ? path.join(appdir(), appFolder, `${queryName}.query.sql`) : null;
155
+
156
+ session.subprocess.send({ msgtype: 'executeReader', sql, fileName, jslid });
157
+
158
+ return { jslid };
159
+ },
160
+
161
+ stopLoadingReader_meta: true,
162
+ async stopLoadingReader({ jslid }) {
163
+ const session = this.opened.find(x => x.loadingReader_jslid == jslid);
164
+ if (session) {
165
+ this.kill({ sesid: session.sesid });
166
+ }
167
+ return true;
168
+ },
169
+
170
+ startProfiler_meta: true,
171
+ async startProfiler({ sesid }) {
172
+ const jslid = crypto.randomUUID();
173
+ const session = this.opened.find(x => x.sesid == sesid);
174
+ if (!session) {
175
+ throw new Error('Invalid session');
176
+ }
177
+
178
+ logger.info({ sesid }, 'Starting profiler');
179
+ session.loadingReader_jslid = jslid;
180
+ session.subprocess.send({ msgtype: 'startProfiler', jslid });
181
+
182
+ return { state: 'ok', jslid };
183
+ },
184
+
185
+ stopProfiler_meta: true,
186
+ async stopProfiler({ sesid }) {
187
+ const session = this.opened.find(x => x.sesid == sesid);
188
+ if (!session) {
189
+ throw new Error('Invalid session');
190
+ }
191
+ session.subprocess.send({ msgtype: 'stopProfiler' });
192
+ return { state: 'ok' };
193
+ },
194
+
195
+ // cancel_meta: true,
196
+ // async cancel({ sesid }) {
197
+ // const session = this.opened.find((x) => x.sesid == sesid);
198
+ // if (!session) {
199
+ // throw new Error('Invalid session');
200
+ // }
201
+ // session.subprocess.send({ msgtype: 'cancel' });
202
+ // return { state: 'ok' };
203
+ // },
204
+
205
+ kill_meta: true,
206
+ async kill({ sesid }) {
207
+ const session = this.opened.find(x => x.sesid == sesid);
208
+ if (!session) {
209
+ throw new Error('Invalid session');
210
+ }
211
+ session.subprocess.kill();
212
+ this.dispatchMessage(sesid, 'Connection closed');
213
+ return { state: 'ok' };
214
+ },
215
+
216
+ ping_meta: true,
217
+ async ping({ sesid }) {
218
+ const session = this.opened.find(x => x.sesid == sesid);
219
+ if (!session) {
220
+ throw new Error('Invalid session');
221
+ }
222
+ try {
223
+ session.subprocess.send({ msgtype: 'ping' });
224
+ } catch (err) {
225
+ logger.error(extractErrorLogData(err), 'Error pinging session');
226
+
227
+ return {
228
+ status: 'error',
229
+ message: 'Ping failed',
230
+ };
231
+ }
232
+
233
+ return { state: 'ok' };
234
+ },
235
+
236
+ // runCommand_meta: true,
237
+ // async runCommand({ conid, database, sql }) {
238
+ // console.log(`Running SQL command , conid=${conid}, database=${database}, sql=${sql}`);
239
+ // const opened = await this.ensureOpened(conid, database);
240
+ // const res = await this.sendRequest(opened, { msgtype: 'queryData', sql });
241
+ // return res;
242
+ // },
243
+ };