mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-18 05:36:00 +00:00
192 lines
6.4 KiB
JavaScript
192 lines
6.4 KiB
JavaScript
const uuidv1 = require('uuid/v1');
|
|
const connections = require('./connections');
|
|
const socket = require('../utility/socket');
|
|
const { fork } = require('child_process');
|
|
const { DatabaseAnalyser } = require('dbgate-tools');
|
|
const { handleProcessCommunication } = require('../utility/processComm');
|
|
|
|
module.exports = {
|
|
/** @type {import('dbgate-types').OpenedDatabaseConnection[]} */
|
|
opened: [],
|
|
closed: {},
|
|
requests: {},
|
|
|
|
handle_structure(conid, database, { structure }) {
|
|
const existing = this.opened.find(x => x.conid == conid && x.database == database);
|
|
if (!existing) return;
|
|
existing.structure = structure;
|
|
socket.emitChanged(`database-structure-changed-${conid}-${database}`);
|
|
},
|
|
handle_error(conid, database, props) {
|
|
const { error } = props;
|
|
console.log(`Error in database connection ${conid}, database ${database}: ${error}`);
|
|
},
|
|
handle_response(conid, database, { msgid, ...response }) {
|
|
const [resolve, reject] = this.requests[msgid];
|
|
resolve(response);
|
|
delete this.requests[msgid];
|
|
},
|
|
handle_status(conid, database, { status }) {
|
|
const existing = this.opened.find(x => x.conid == conid && x.database == database);
|
|
if (!existing) return;
|
|
if (existing.status == status) return;
|
|
existing.status = status;
|
|
socket.emitChanged(`database-status-changed-${conid}-${database}`);
|
|
},
|
|
|
|
handle_ping() {},
|
|
|
|
async ensureOpened(conid, database) {
|
|
const existing = this.opened.find(x => x.conid == conid && x.database == database);
|
|
if (existing) return existing;
|
|
const connection = await connections.get({ conid });
|
|
const subprocess = fork(process.argv[1], ['databaseConnectionProcess', ...process.argv.slice(3)]);
|
|
const lastClosed = this.closed[`${conid}/${database}`];
|
|
const newOpened = {
|
|
conid,
|
|
database,
|
|
subprocess,
|
|
structure: lastClosed ? lastClosed.structure : DatabaseAnalyser.createEmptyStructure(),
|
|
connection,
|
|
status: { name: 'pending' },
|
|
};
|
|
this.opened.push(newOpened);
|
|
subprocess.on('message', message => {
|
|
// @ts-ignore
|
|
const { msgtype } = message;
|
|
if (handleProcessCommunication(message, subprocess)) return;
|
|
if (newOpened.disconnected) return;
|
|
this[`handle_${msgtype}`](conid, database, message);
|
|
});
|
|
subprocess.on('exit', () => {
|
|
if (newOpened.disconnected) return;
|
|
this.close(conid, database, false);
|
|
});
|
|
|
|
subprocess.send({
|
|
msgtype: 'connect',
|
|
connection: { ...connection, database },
|
|
structure: lastClosed ? lastClosed.structure : null,
|
|
});
|
|
return newOpened;
|
|
},
|
|
|
|
/** @param {import('dbgate-types').OpenedDatabaseConnection} conn */
|
|
sendRequest(conn, message) {
|
|
const msgid = uuidv1();
|
|
const promise = new Promise((resolve, reject) => {
|
|
this.requests[msgid] = [resolve, reject];
|
|
conn.subprocess.send({ msgid, ...message });
|
|
});
|
|
return promise;
|
|
},
|
|
|
|
queryData_meta: 'post',
|
|
async queryData({ conid, database, sql }) {
|
|
console.log(`Processing query, conid=${conid}, database=${database}, sql=${sql}`);
|
|
const opened = await this.ensureOpened(conid, database);
|
|
// if (opened && opened.status && opened.status.name == 'error') {
|
|
// return opened.status;
|
|
// }
|
|
const res = await this.sendRequest(opened, { msgtype: 'queryData', sql });
|
|
return res;
|
|
},
|
|
|
|
collectionData_meta: 'post',
|
|
async collectionData({ conid, database, options }) {
|
|
const opened = await this.ensureOpened(conid, database);
|
|
const res = await this.sendRequest(opened, { msgtype: 'collectionData', options });
|
|
return res.result;
|
|
},
|
|
|
|
updateCollection_meta: 'post',
|
|
async updateCollection({ conid, database, changeSet }) {
|
|
const opened = await this.ensureOpened(conid, database);
|
|
const res = await this.sendRequest(opened, { msgtype: 'updateCollection', changeSet });
|
|
return res.result;
|
|
},
|
|
|
|
status_meta: 'get',
|
|
async status({ conid, database }) {
|
|
const existing = this.opened.find(x => x.conid == conid && x.database == database);
|
|
if (existing) return existing.status;
|
|
const lastClosed = this.closed[`${conid}/${database}`];
|
|
if (lastClosed) return lastClosed.status;
|
|
return {
|
|
name: 'error',
|
|
message: 'Not connected',
|
|
};
|
|
},
|
|
|
|
ping_meta: 'post',
|
|
async ping({ conid, database }) {
|
|
let existing = this.opened.find(x => x.conid == conid && x.database == database);
|
|
|
|
if (existing) {
|
|
existing.subprocess.send({ msgtype: 'ping' });
|
|
} else {
|
|
existing = await this.ensureOpened(conid, database);
|
|
}
|
|
|
|
return {
|
|
status: 'ok',
|
|
connectionStatus: existing ? existing.status : null,
|
|
};
|
|
},
|
|
|
|
refresh_meta: 'post',
|
|
async refresh({ conid, database }) {
|
|
this.close(conid, database);
|
|
|
|
await this.ensureOpened(conid, database);
|
|
return { status: 'ok' };
|
|
},
|
|
|
|
close(conid, database, kill = true) {
|
|
const existing = this.opened.find(x => x.conid == conid && x.database == database);
|
|
if (existing) {
|
|
existing.disconnected = true;
|
|
if (kill) existing.subprocess.kill();
|
|
this.opened = this.opened.filter(x => x.conid != conid || x.database != database);
|
|
this.closed[`${conid}/${database}`] = {
|
|
status: {
|
|
...existing.status,
|
|
name: 'error',
|
|
},
|
|
structure: existing.structure,
|
|
};
|
|
socket.emitChanged(`database-status-changed-${conid}-${database}`);
|
|
}
|
|
},
|
|
|
|
structure_meta: 'get',
|
|
async structure({ conid, database }) {
|
|
const opened = await this.ensureOpened(conid, database);
|
|
return opened.structure;
|
|
// const existing = this.opened.find((x) => x.conid == conid && x.database == database);
|
|
// if (existing) return existing.status;
|
|
// return {
|
|
// name: 'error',
|
|
// message: 'Not connected',
|
|
// };
|
|
},
|
|
|
|
sqlPreview_meta: 'post',
|
|
async sqlPreview({ conid, database, objects, options }) {
|
|
// wait for structure
|
|
await this.structure({ conid, database });
|
|
|
|
const opened = await this.ensureOpened(conid, database);
|
|
const res = await this.sendRequest(opened, { msgtype: 'sqlPreview', objects, options });
|
|
return res;
|
|
},
|
|
|
|
// runCommand_meta: 'post',
|
|
// async runCommand({ conid, database, sql }) {
|
|
// console.log(`Running SQL command , conid=${conid}, database=${database}, sql=${sql}`);
|
|
// const opened = await this.ensureOpened(conid, database);
|
|
// const res = await this.sendRequest(opened, { msgtype: 'queryData', sql });
|
|
// return res;
|
|
// },
|
|
};
|