mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-28 08:26:29 +00:00
shell script scheduler
This commit is contained in:
@@ -38,6 +38,7 @@
|
|||||||
"lodash": "^4.17.15",
|
"lodash": "^4.17.15",
|
||||||
"ncp": "^2.0.0",
|
"ncp": "^2.0.0",
|
||||||
"nedb-promises": "^4.0.1",
|
"nedb-promises": "^4.0.1",
|
||||||
|
"node-cron": "^2.0.3",
|
||||||
"tar": "^6.0.5",
|
"tar": "^6.0.5",
|
||||||
"uuid": "^3.4.0"
|
"uuid": "^3.4.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ const fs = require('fs-extra');
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const { filesdir } = require('../utility/directories');
|
const { filesdir } = require('../utility/directories');
|
||||||
const socket = require('../utility/socket');
|
const socket = require('../utility/socket');
|
||||||
|
const scheduler = require('./scheduler');
|
||||||
|
|
||||||
function serialize(format, data) {
|
function serialize(format, data) {
|
||||||
if (format == 'text') return data;
|
if (format == 'text') return data;
|
||||||
@@ -44,5 +45,8 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
await fs.writeFile(path.join(dir, file), serialize(format, data));
|
await fs.writeFile(path.join(dir, file), serialize(format, data));
|
||||||
socket.emitChanged(`files-changed-${folder}`);
|
socket.emitChanged(`files-changed-${folder}`);
|
||||||
|
if (folder == 'shell') {
|
||||||
|
scheduler.reload();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
41
packages/api/src/controllers/scheduler.js
Normal file
41
packages/api/src/controllers/scheduler.js
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
const { filesdir } = require('../utility/directories');
|
||||||
|
const fs = require('fs-extra');
|
||||||
|
const path = require('path');
|
||||||
|
const cron = require('node-cron');
|
||||||
|
const runners = require('./runners');
|
||||||
|
|
||||||
|
const scheduleRegex = /\s*\/\/\s*@schedule\s+([^\n]+)\n/;
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
tasks: [],
|
||||||
|
|
||||||
|
async unload() {
|
||||||
|
this.tasks.forEach((x) => x.destroy());
|
||||||
|
this.tasks = [];
|
||||||
|
},
|
||||||
|
|
||||||
|
async processFile(file) {
|
||||||
|
const text = await fs.readFile(file, { encoding: 'utf-8' });
|
||||||
|
const match = text.match(scheduleRegex);
|
||||||
|
if (!match) return;
|
||||||
|
const pattern = match[1];
|
||||||
|
if (!cron.validate(pattern)) return;
|
||||||
|
console.log(`Schedule script ${file} with pattern ${pattern}`);
|
||||||
|
const task = cron.schedule(pattern, () => runners.start({ script: text }));
|
||||||
|
this.tasks.push(task);
|
||||||
|
},
|
||||||
|
|
||||||
|
async reload() {
|
||||||
|
const shellDir = path.join(filesdir(), 'shell');
|
||||||
|
await this.unload();
|
||||||
|
if (!(await fs.exists(shellDir))) return;
|
||||||
|
const files = await fs.readdir(shellDir);
|
||||||
|
for (const file of files) {
|
||||||
|
await this.processFile(path.join(shellDir, file));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async _init() {
|
||||||
|
this.reload();
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -24,6 +24,7 @@ const archive = require('./controllers/archive');
|
|||||||
const uploads = require('./controllers/uploads');
|
const uploads = require('./controllers/uploads');
|
||||||
const plugins = require('./controllers/plugins');
|
const plugins = require('./controllers/plugins');
|
||||||
const files = require('./controllers/files');
|
const files = require('./controllers/files');
|
||||||
|
const scheduler = require('./controllers/scheduler');
|
||||||
|
|
||||||
const { rundir } = require('./utility/directories');
|
const { rundir } = require('./utility/directories');
|
||||||
|
|
||||||
@@ -69,6 +70,7 @@ function start(argument = null) {
|
|||||||
useController(app, '/uploads', uploads);
|
useController(app, '/uploads', uploads);
|
||||||
useController(app, '/plugins', plugins);
|
useController(app, '/plugins', plugins);
|
||||||
useController(app, '/files', files);
|
useController(app, '/files', files);
|
||||||
|
useController(app, '/scheduler', scheduler);
|
||||||
|
|
||||||
if (process.env.PAGES_DIRECTORY) {
|
if (process.env.PAGES_DIRECTORY) {
|
||||||
app.use('/pages', express.static(process.env.PAGES_DIRECTORY));
|
app.use('/pages', express.static(process.env.PAGES_DIRECTORY));
|
||||||
|
|||||||
@@ -32,9 +32,10 @@ export default function QueryTab({ tabid, conid, database, initialArgs, tabVisib
|
|||||||
const extensions = useExtensions();
|
const extensions = useExtensions();
|
||||||
const { editorData, setEditorData, isLoading } = useEditorData({
|
const { editorData, setEditorData, isLoading } = useEditorData({
|
||||||
tabid,
|
tabid,
|
||||||
loadFromArgs: initialArgs && initialArgs.sqlTemplate
|
loadFromArgs:
|
||||||
? () => applySqlTemplate(initialArgs.sqlTemplate, extensions, { conid, database, ...other })
|
initialArgs && initialArgs.sqlTemplate
|
||||||
: null,
|
? () => applySqlTemplate(initialArgs.sqlTemplate, extensions, { conid, database, ...other })
|
||||||
|
: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
const editorRef = React.useRef(null);
|
const editorRef = React.useRef(null);
|
||||||
@@ -113,12 +114,13 @@ export default function QueryTab({ tabid, conid, database, initialArgs, tabVisib
|
|||||||
editorRef.current.editor.clearSelection();
|
editorRef.current.editor.clearSelection();
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isLoading)
|
if (isLoading) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<LoadingInfo message="Loading SQL script" />
|
<LoadingInfo message="Loading SQL script" />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import ImportExportModal from '../modals/ImportExportModal';
|
|||||||
import useEditorData from '../utility/useEditorData';
|
import useEditorData from '../utility/useEditorData';
|
||||||
import SaveTabModal from '../modals/SaveTabModal';
|
import SaveTabModal from '../modals/SaveTabModal';
|
||||||
import useModalState from '../modals/useModalState';
|
import useModalState from '../modals/useModalState';
|
||||||
|
import LoadingInfo from '../widgets/LoadingInfo';
|
||||||
|
|
||||||
const configRegex = /\s*\/\/\s*@ImportExportConfigurator\s*\n\s*\/\/\s*(\{[^\n]+\})\n/;
|
const configRegex = /\s*\/\/\s*@ImportExportConfigurator\s*\n\s*\/\/\s*(\{[^\n]+\})\n/;
|
||||||
const requireRegex = /\s*(\/\/\s*@require\s+[^\n]+)\n/g;
|
const requireRegex = /\s*(\/\/\s*@require\s+[^\n]+)\n/g;
|
||||||
@@ -22,7 +23,7 @@ const requireRegex = /\s*(\/\/\s*@require\s+[^\n]+)\n/g;
|
|||||||
export default function ShellTab({ tabid, tabVisible, toolbarPortalRef, ...other }) {
|
export default function ShellTab({ tabid, tabVisible, toolbarPortalRef, ...other }) {
|
||||||
const [busy, setBusy] = React.useState(false);
|
const [busy, setBusy] = React.useState(false);
|
||||||
const showModal = useShowModal();
|
const showModal = useShowModal();
|
||||||
const { editorData, setEditorData } = useEditorData({ tabid });
|
const { editorData, setEditorData, isLoading } = useEditorData({ tabid });
|
||||||
const saveFileModalState = useModalState();
|
const saveFileModalState = useModalState();
|
||||||
|
|
||||||
const setOpenedTabs = useSetOpenedTabs();
|
const setOpenedTabs = useSetOpenedTabs();
|
||||||
@@ -89,6 +90,14 @@ export default function ShellTab({ tabid, tabVisible, toolbarPortalRef, ...other
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<LoadingInfo message="Loading shell script" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<VerticalSplitter>
|
<VerticalSplitter>
|
||||||
|
|||||||
18
yarn.lock
18
yarn.lock
@@ -7882,6 +7882,14 @@ no-case@^2.2.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
lower-case "^1.1.1"
|
lower-case "^1.1.1"
|
||||||
|
|
||||||
|
node-cron@^2.0.3:
|
||||||
|
version "2.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/node-cron/-/node-cron-2.0.3.tgz#b9649784d0d6c00758410eef22fa54a10e3f602d"
|
||||||
|
integrity sha512-eJI+QitXlwcgiZwNNSRbqsjeZMp5shyajMR81RZCqeW0ZDEj4zU9tpd4nTh/1JsBiKbF8d08FCewiipDmVIYjg==
|
||||||
|
dependencies:
|
||||||
|
opencollective-postinstall "^2.0.0"
|
||||||
|
tz-offset "0.0.1"
|
||||||
|
|
||||||
node-fetch@^1.0.1:
|
node-fetch@^1.0.1:
|
||||||
version "1.7.3"
|
version "1.7.3"
|
||||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef"
|
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef"
|
||||||
@@ -8208,6 +8216,11 @@ open@^6.4.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
is-wsl "^1.1.0"
|
is-wsl "^1.1.0"
|
||||||
|
|
||||||
|
opencollective-postinstall@^2.0.0:
|
||||||
|
version "2.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259"
|
||||||
|
integrity sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==
|
||||||
|
|
||||||
opn@^5.5.0:
|
opn@^5.5.0:
|
||||||
version "5.5.0"
|
version "5.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc"
|
resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc"
|
||||||
@@ -11627,6 +11640,11 @@ typescript@^3.7.4, typescript@^3.7.5:
|
|||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae"
|
||||||
integrity sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==
|
integrity sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==
|
||||||
|
|
||||||
|
tz-offset@0.0.1:
|
||||||
|
version "0.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/tz-offset/-/tz-offset-0.0.1.tgz#fef920257024d3583ed9072a767721a18bdb8a76"
|
||||||
|
integrity sha512-kMBmblijHJXyOpKzgDhKx9INYU4u4E1RPMB0HqmKSgWG8vEcf3exEfLh4FFfzd3xdQOw9EuIy/cP0akY6rHopQ==
|
||||||
|
|
||||||
ua-parser-js@^0.7.18:
|
ua-parser-js@^0.7.18:
|
||||||
version "0.7.22"
|
version "0.7.22"
|
||||||
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.22.tgz#960df60a5f911ea8f1c818f3747b99c6e177eae3"
|
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.22.tgz#960df60a5f911ea8f1c818f3747b99c6e177eae3"
|
||||||
|
|||||||
Reference in New Issue
Block a user