dbgate-api 4.7.0 → 4.7.3-alpha.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dbgate-api",
3
3
  "main": "src/index.js",
4
- "version": "4.7.0",
4
+ "version": "4.7.3-alpha.2",
5
5
  "homepage": "https://dbgate.org/",
6
6
  "repository": {
7
7
  "type": "git",
@@ -25,9 +25,9 @@
25
25
  "compare-versions": "^3.6.0",
26
26
  "cors": "^2.8.5",
27
27
  "cross-env": "^6.0.3",
28
- "dbgate-query-splitter": "^4.7.0",
29
- "dbgate-sqltree": "^4.7.0",
30
- "dbgate-tools": "^4.7.0",
28
+ "dbgate-query-splitter": "^4.7.3-alpha.2",
29
+ "dbgate-sqltree": "^4.7.3-alpha.2",
30
+ "dbgate-tools": "^4.7.3-alpha.2",
31
31
  "diff": "^5.0.0",
32
32
  "diff2html": "^3.4.13",
33
33
  "eslint": "^6.8.0",
@@ -63,7 +63,7 @@
63
63
  "devDependencies": {
64
64
  "@types/fs-extra": "^9.0.11",
65
65
  "@types/lodash": "^4.14.149",
66
- "dbgate-types": "^4.7.0",
66
+ "dbgate-types": "^4.7.3-alpha.2",
67
67
  "env-cmd": "^10.1.0",
68
68
  "node-loader": "^1.0.2",
69
69
  "nodemon": "^2.0.2",
@@ -27,6 +27,7 @@ module.exports = {
27
27
 
28
28
  files_meta: true,
29
29
  async files({ folder }) {
30
+ if (!folder) return [];
30
31
  const dir = path.join(appdir(), folder);
31
32
  if (!(await fs.exists(dir))) return [];
32
33
  const files = await fs.readdir(dir);
@@ -264,4 +265,16 @@ module.exports = {
264
265
 
265
266
  return true;
266
267
  },
268
+
269
+ createConfigFile_meta: true,
270
+ async createConfigFile({ appFolder, fileName, content }) {
271
+ const file = path.join(appdir(), appFolder, fileName);
272
+ if (!(await fs.exists(file))) {
273
+ await fs.writeFile(file, JSON.stringify(content, undefined, 2));
274
+ socket.emitChanged(`app-files-changed-${appFolder}`);
275
+ socket.emitChanged('used-apps-changed');
276
+ return true;
277
+ }
278
+ return false;
279
+ },
267
280
  };
@@ -1,25 +1,29 @@
1
1
  const fs = require('fs-extra');
2
+ const os = require('os');
2
3
  const path = require('path');
3
4
  const axios = require('axios');
4
5
  const { datadir } = require('../utility/directories');
5
6
  const hasPermission = require('../utility/hasPermission');
6
7
  const socket = require('../utility/socket');
7
8
  const _ = require('lodash');
9
+ const AsyncLock = require('async-lock');
8
10
 
9
11
  const currentVersion = require('../currentVersion');
10
12
  const platformInfo = require('../utility/platformInfo');
11
13
  const connections = require('../controllers/connections');
12
14
 
15
+ const lock = new AsyncLock();
16
+
13
17
  module.exports = {
14
- settingsValue: {},
18
+ // settingsValue: {},
15
19
 
16
- async _init() {
17
- try {
18
- this.settingsValue = JSON.parse(await fs.readFile(path.join(datadir(), 'settings.json'), { encoding: 'utf-8' }));
19
- } catch (err) {
20
- this.settingsValue = {};
21
- }
22
- },
20
+ // async _init() {
21
+ // try {
22
+ // this.settingsValue = JSON.parse(await fs.readFile(path.join(datadir(), 'settings.json'), { encoding: 'utf-8' }));
23
+ // } catch (err) {
24
+ // this.settingsValue = {};
25
+ // }
26
+ // },
23
27
 
24
28
  get_meta: true,
25
29
  async get() {
@@ -40,24 +44,45 @@ module.exports = {
40
44
 
41
45
  getSettings_meta: true,
42
46
  async getSettings() {
43
- return this.settingsValue;
47
+ try {
48
+ return this.fillMissingSettings(
49
+ JSON.parse(await fs.readFile(path.join(datadir(), 'settings.json'), { encoding: 'utf-8' }))
50
+ );
51
+ } catch (err) {
52
+ return this.fillMissingSettings({});
53
+ }
54
+ },
55
+
56
+ fillMissingSettings(value) {
57
+ const res = {
58
+ ...value,
59
+ };
60
+ if (value['app.useNativeMenu'] !== true && value['app.useNativeMenu'] !== false) {
61
+ res['app.useNativeMenu'] = os.platform() == 'darwin' ? true : false;
62
+ }
63
+ return res;
44
64
  },
45
65
 
46
66
  updateSettings_meta: true,
47
67
  async updateSettings(values) {
48
68
  if (!hasPermission(`settings/change`)) return false;
49
- try {
50
- const updated = {
51
- ...this.settingsValue,
52
- ...values,
53
- };
54
- await fs.writeFile(path.join(datadir(), 'settings.json'), JSON.stringify(updated, undefined, 2));
55
- this.settingsValue = updated;
56
- socket.emitChanged(`settings-changed`);
57
- return updated;
58
- } catch (err) {
59
- return false;
60
- }
69
+
70
+ const res = await lock.acquire('update', async () => {
71
+ const currentValue = await this.getSettings();
72
+ try {
73
+ const updated = {
74
+ ...currentValue,
75
+ ...values,
76
+ };
77
+ await fs.writeFile(path.join(datadir(), 'settings.json'), JSON.stringify(updated, undefined, 2));
78
+ // this.settingsValue = updated;
79
+ socket.emitChanged(`settings-changed`);
80
+ return updated;
81
+ } catch (err) {
82
+ return false;
83
+ }
84
+ });
85
+ return res;
61
86
  },
62
87
 
63
88
  changelog_meta: true,
@@ -110,7 +110,7 @@ module.exports = {
110
110
  msgtype: 'connect',
111
111
  connection: { ...connection, database },
112
112
  structure: lastClosed ? lastClosed.structure : null,
113
- globalSettings: config.settingsValue,
113
+ globalSettings: await config.getSettings(),
114
114
  });
115
115
  return newOpened;
116
116
  },
@@ -98,6 +98,7 @@ module.exports = {
98
98
  const app = folder.substring('app:'.length);
99
99
  await fs.writeFile(path.join(appdir(), app, file), serialize(format, data));
100
100
  socket.emitChanged(`app-files-changed-${app}`);
101
+ socket.emitChanged('used-apps-changed');
101
102
  apps.emitChangedDbApp(folder);
102
103
  return true;
103
104
  } else {
@@ -141,8 +142,8 @@ module.exports = {
141
142
  },
142
143
 
143
144
  generateUploadsFile_meta: true,
144
- async generateUploadsFile() {
145
- const fileName = `${uuidv1()}.html`;
145
+ async generateUploadsFile({ extension }) {
146
+ const fileName = `${uuidv1()}.${extension || 'html'}`;
146
147
  return {
147
148
  fileName,
148
149
  filePath: path.join(uploadsdir(), fileName),
@@ -69,7 +69,7 @@ module.exports = {
69
69
  if (newOpened.disconnected) return;
70
70
  this.close(conid, false);
71
71
  });
72
- subprocess.send({ msgtype: 'connect', ...connection, globalSettings: config.settingsValue });
72
+ subprocess.send({ msgtype: 'connect', ...connection, globalSettings: await config.getSettings() });
73
73
  return newOpened;
74
74
  });
75
75
  return res;
@@ -1,5 +1,5 @@
1
1
 
2
2
  module.exports = {
3
- version: '4.7.0',
4
- buildTime: '2022-02-21T18:54:46.663Z'
3
+ version: '4.7.3-alpha.2',
4
+ buildTime: '2022-03-13T15:52:44.332Z'
5
5
  };
package/src/main.js CHANGED
@@ -28,8 +28,7 @@ const queryHistory = require('./controllers/queryHistory');
28
28
 
29
29
  const { rundir } = require('./utility/directories');
30
30
  const platformInfo = require('./utility/platformInfo');
31
-
32
- let checkLocalhostOrigin = null;
31
+ const getExpressPath = require('./utility/getExpressPath');
33
32
 
34
33
  function start() {
35
34
  // console.log('process.argv', process.argv);
@@ -50,32 +49,13 @@ function start() {
50
49
  );
51
50
  }
52
51
 
53
- app.use(function (req, res, next) {
54
- if (checkLocalhostOrigin) {
55
- if (
56
- req.headers.origin &&
57
- req.headers.origin != checkLocalhostOrigin &&
58
- req.headers.origin != `http://${checkLocalhostOrigin}`
59
- ) {
60
- console.log('API origin check FAILED');
61
- console.log('HEADERS', { ...req.headers, authorization: '***' });
62
- return res.status(403).json({ error: 'Not authorized!' });
63
- }
64
- if (!req.headers.origin && req.headers.host != checkLocalhostOrigin) {
65
- console.log('API host check FAILED');
66
- console.log('HEADERS', { ...req.headers, authorization: '***' });
67
- return res.status(403).json({ error: 'Not authorized!' });
68
- }
69
- }
70
- next();
71
- });
72
-
73
52
  app.use(cors());
74
53
 
75
- app.get('/stream', async function (req, res) {
54
+ app.get(getExpressPath('/stream'), async function (req, res) {
76
55
  res.set({
77
56
  'Cache-Control': 'no-cache',
78
57
  'Content-Type': 'text/event-stream',
58
+ 'X-Accel-Buffering': 'no',
79
59
  Connection: 'keep-alive',
80
60
  });
81
61
  res.flushHeaders();
@@ -88,7 +68,7 @@ function start() {
88
68
  app.use(bodyParser.json({ limit: '50mb' }));
89
69
 
90
70
  app.use(
91
- '/uploads',
71
+ getExpressPath('/uploads'),
92
72
  fileUpload({
93
73
  limits: { fileSize: 4 * 1024 * 1024 },
94
74
  })
@@ -100,21 +80,21 @@ function start() {
100
80
  // app.use('/pages', express.static(process.env.PAGES_DIRECTORY));
101
81
  // }
102
82
 
103
- app.use('/runners/data', express.static(rundir()));
83
+ app.use(getExpressPath('/runners/data'), express.static(rundir()));
104
84
 
105
85
  if (platformInfo.isDocker) {
106
86
  // server static files inside docker container
107
- app.use(express.static('/home/dbgate-docker/public'));
87
+ app.use(getExpressPath('/'), express.static('/home/dbgate-docker/public'));
108
88
  } else {
109
89
  if (!platformInfo.isNpmDist) {
110
- app.get('/', (req, res) => {
90
+ app.get(getExpressPath('/'), (req, res) => {
111
91
  res.send('DbGate API');
112
92
  });
113
93
  }
114
94
  }
115
95
 
116
96
  if (platformInfo.isNpmDist) {
117
- app.use(express.static(path.join(__dirname, '../../dbgate-web/public')));
97
+ app.use(getExpressPath('/'), express.static(path.join(__dirname, '../../dbgate-web/public')));
118
98
  getPort({ port: 5000 }).then(port => {
119
99
  server.listen(port, () => {
120
100
  console.log(`DbGate API listening on port ${port}`);
@@ -165,4 +145,4 @@ function initializeElectronSender(electronSender) {
165
145
  socket.setElectronSender(electronSender);
166
146
  }
167
147
 
168
- module.exports = { start, useAllControllers, initializeElectronSender };
148
+ module.exports = { start, useAllControllers, initializeElectronSender, configController: config };
@@ -1,18 +1,47 @@
1
1
  const EnsureStreamHeaderStream = require('../utility/EnsureStreamHeaderStream');
2
+ const Stream = require('stream');
3
+ const ColumnMapTransformStream = require('../utility/ColumnMapTransformStream');
4
+
5
+ function copyStream(input, output, options) {
6
+ const { columns } = options || {};
7
+
8
+ const transforms = [];
9
+ if (columns) {
10
+ transforms.push(new ColumnMapTransformStream(columns));
11
+ }
12
+ if (output.requireFixedStructure) {
13
+ transforms.push(new EnsureStreamHeaderStream());
14
+ }
15
+
16
+ // return new Promise((resolve, reject) => {
17
+ // Stream.pipeline(input, ...transforms, output, err => {
18
+ // if (err) {
19
+ // reject(err);
20
+ // } else {
21
+ // resolve();
22
+ // }
23
+ // });
24
+ // });
2
25
 
3
- function copyStream(input, output) {
4
26
  return new Promise((resolve, reject) => {
5
27
  const finisher = output['finisher'] || output;
6
28
  finisher.on('finish', resolve);
7
29
  finisher.on('error', reject);
8
30
 
9
- if (output.requireFixedStructure) {
10
- const ensureHeader = new EnsureStreamHeaderStream();
11
- input.pipe(ensureHeader);
12
- ensureHeader.pipe(output);
13
- } else {
14
- input.pipe(output);
31
+ let lastStream = input;
32
+ for (const tran of transforms) {
33
+ lastStream.pipe(tran);
34
+ lastStream = tran;
15
35
  }
36
+ lastStream.pipe(output);
37
+
38
+ // if (output.requireFixedStructure) {
39
+ // const ensureHeader = new EnsureStreamHeaderStream();
40
+ // input.pipe(ensureHeader);
41
+ // ensureHeader.pipe(output);
42
+ // } else {
43
+ // input.pipe(output);
44
+ // }
16
45
  });
17
46
  }
18
47
 
@@ -0,0 +1,21 @@
1
+ const stream = require('stream');
2
+ const { transformRowUsingColumnMap } = require('dbgate-tools');
3
+
4
+ class ColumnMapTransformStream extends stream.Transform {
5
+ constructor(columns) {
6
+ super({ objectMode: true });
7
+ this.columns = columns;
8
+ }
9
+ _transform(chunk, encoding, done) {
10
+ if (chunk.__isStreamHeader) {
11
+ // skip stream header
12
+ done();
13
+ return;
14
+ }
15
+
16
+ this.push(transformRowUsingColumnMap(chunk, this.columns));
17
+ done();
18
+ }
19
+ }
20
+
21
+ module.exports = ColumnMapTransformStream;
@@ -3,7 +3,7 @@ const fs = require('fs-extra');
3
3
  async function saveFreeTableData(file, data) {
4
4
  const { structure, rows } = data;
5
5
  const fileStream = fs.createWriteStream(file);
6
- await fileStream.write(JSON.stringify(structure) + '\n');
6
+ await fileStream.write(JSON.stringify({ __isStreamHeader: true, ...structure }) + '\n');
7
7
  for (const row of rows) {
8
8
  await fileStream.write(JSON.stringify(row) + '\n');
9
9
  }
@@ -0,0 +1,10 @@
1
+ function getExpressPath(path) {
2
+ path = path.replace(/\/*$/, '').replace(/^\/*/, '');
3
+ const root = (process.env.WEB_ROOT || '').replace(/^\/*/, '').replace(/\/*$/, '');
4
+ if (root) {
5
+ return `/${root}/${path}`;
6
+ }
7
+ return `/${path}`;
8
+ }
9
+
10
+ module.exports = getExpressPath;
@@ -5,6 +5,7 @@ let init = '';
5
5
  module.exports = {
6
6
  setSseResponse(value) {
7
7
  sseResponse = value;
8
+ setInterval(() => this.emit('ping'), 29 * 1000);
8
9
  },
9
10
  setElectronSender(value) {
10
11
  electronSender = value;
@@ -1,5 +1,6 @@
1
1
  const _ = require('lodash');
2
2
  const express = require('express');
3
+ const getExpressPath = require('./getExpressPath');
3
4
 
4
5
  /**
5
6
  * @param {string} route
@@ -74,6 +75,6 @@ module.exports = function useController(app, electron, route, controller) {
74
75
  }
75
76
 
76
77
  if (app) {
77
- app.use(route, router);
78
+ app.use(getExpressPath(route), router);
78
79
  }
79
80
  };