mirror of
https://github.com/whyour/qinglong.git
synced 2025-05-22 22:36:06 +08:00
fs 文件操作替换为 fs.promise
This commit is contained in:
parent
66a2769e7c
commit
20f615eadf
|
@ -3,7 +3,7 @@ import { Router, Request, Response, NextFunction } from 'express';
|
|||
import { Container } from 'typedi';
|
||||
import { Logger } from 'winston';
|
||||
import config from '../config';
|
||||
import * as fs from 'fs';
|
||||
import * as fs from 'fs/promises';
|
||||
import { celebrate, Joi } from 'celebrate';
|
||||
import { join } from 'path';
|
||||
const route = Router();
|
||||
|
@ -16,7 +16,7 @@ export default (app: Router) => {
|
|||
async (req: Request, res: Response, next: NextFunction) => {
|
||||
const logger: Logger = Container.get('logger');
|
||||
try {
|
||||
const fileList = fs.readdirSync(config.configPath, 'utf-8');
|
||||
const fileList = await fs.readdir(config.configPath, 'utf-8');
|
||||
res.send({
|
||||
code: 200,
|
||||
data: fileList
|
||||
|
@ -41,11 +41,11 @@ export default (app: Router) => {
|
|||
res.send({ code: 403, message: '文件无法访问' });
|
||||
}
|
||||
if (req.params.file.includes('sample')) {
|
||||
content = getFileContentByName(
|
||||
content = await getFileContentByName(
|
||||
join(config.samplePath, req.params.file),
|
||||
);
|
||||
} else {
|
||||
content = getFileContentByName(
|
||||
content = await getFileContentByName(
|
||||
join(config.configPath, req.params.file),
|
||||
);
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ export default (app: Router) => {
|
|||
res.send({ code: 403, message: '文件无法访问' });
|
||||
}
|
||||
const path = join(config.configPath, name);
|
||||
fs.writeFileSync(path, content);
|
||||
await fs.writeFile(path, content);
|
||||
res.send({ code: 200, message: '保存成功' });
|
||||
} catch (e) {
|
||||
return next(e);
|
||||
|
|
|
@ -3,7 +3,7 @@ import { Container } from 'typedi';
|
|||
import { Logger } from 'winston';
|
||||
import * as fs from 'fs';
|
||||
import config from '../config';
|
||||
import { emptyDir, getFileContentByName, readDirs } from '../config/util';
|
||||
import { getFileContentByName, readDirs, rmPath } from '../config/util';
|
||||
import { join } from 'path';
|
||||
import { celebrate, Joi } from 'celebrate';
|
||||
const route = Router();
|
||||
|
@ -39,7 +39,7 @@ export default (app: Router) => {
|
|||
(req.query.path || '') as string,
|
||||
req.params.file,
|
||||
);
|
||||
const content = getFileContentByName(filePath);
|
||||
const content = await getFileContentByName(filePath);
|
||||
res.send({ code: 200, data: content });
|
||||
} catch (e) {
|
||||
return next(e);
|
||||
|
@ -64,11 +64,7 @@ export default (app: Router) => {
|
|||
type: string;
|
||||
};
|
||||
const filePath = join(config.logPath, path, filename);
|
||||
if (type === 'directory') {
|
||||
await emptyDir(filePath);
|
||||
} else {
|
||||
fs.unlinkSync(filePath);
|
||||
}
|
||||
await rmPath(filePath);
|
||||
res.send({ code: 200 });
|
||||
} catch (e) {
|
||||
return next(e);
|
||||
|
|
|
@ -4,13 +4,13 @@ import {
|
|||
readDirs,
|
||||
getLastModifyFilePath,
|
||||
readDir,
|
||||
emptyDir,
|
||||
rmPath,
|
||||
} from '../config/util';
|
||||
import { Router, Request, Response, NextFunction } from 'express';
|
||||
import { Container } from 'typedi';
|
||||
import { Logger } from 'winston';
|
||||
import config from '../config';
|
||||
import * as fs from 'fs';
|
||||
import * as fs from 'fs/promises';
|
||||
import { celebrate, Joi } from 'celebrate';
|
||||
import path, { join, parse } from 'path';
|
||||
import ScriptService from '../services/script';
|
||||
|
@ -40,9 +40,13 @@ export default (app: Router) => {
|
|||
config.scriptPath,
|
||||
req.query.path as string,
|
||||
);
|
||||
result = readDir(targetPath, config.scriptPath, blacklist);
|
||||
result = await readDir(targetPath, config.scriptPath, blacklist);
|
||||
} else {
|
||||
result = readDirs(config.scriptPath, config.scriptPath, blacklist);
|
||||
result = await readDirs(
|
||||
config.scriptPath,
|
||||
config.scriptPath,
|
||||
blacklist,
|
||||
);
|
||||
}
|
||||
res.send({
|
||||
code: 200,
|
||||
|
@ -64,7 +68,7 @@ export default (app: Router) => {
|
|||
req.query.path as string,
|
||||
req.params.file,
|
||||
);
|
||||
const content = getFileContentByName(filePath);
|
||||
const content = await getFileContentByName(filePath);
|
||||
res.send({ code: 200, data: content });
|
||||
} catch (e) {
|
||||
return next(e);
|
||||
|
@ -104,12 +108,12 @@ export default (app: Router) => {
|
|||
}
|
||||
|
||||
if (req.file) {
|
||||
fs.renameSync(req.file.path, join(path, req.file.filename));
|
||||
await fs.rename(req.file.path, join(path, req.file.filename));
|
||||
return res.send({ code: 200 });
|
||||
}
|
||||
|
||||
if (directory) {
|
||||
fs.mkdirSync(join(path, directory), { recursive: true });
|
||||
await fs.mkdir(join(path, directory), { recursive: true });
|
||||
return res.send({ code: 200 });
|
||||
}
|
||||
|
||||
|
@ -121,16 +125,17 @@ export default (app: Router) => {
|
|||
`${originFilename.replace(/\//g, '')}`,
|
||||
);
|
||||
const filePath = join(path, `${filename.replace(/\//g, '')}`);
|
||||
if (fs.existsSync(originFilePath)) {
|
||||
fs.copyFileSync(
|
||||
const fileExists = await fileExist(filePath);
|
||||
if (fileExists) {
|
||||
await fs.copyFile(
|
||||
originFilePath,
|
||||
join(config.bakPath, originFilename.replace(/\//g, '')),
|
||||
);
|
||||
if (filename !== originFilename) {
|
||||
fs.unlinkSync(originFilePath);
|
||||
await rmPath(originFilePath);
|
||||
}
|
||||
}
|
||||
fs.writeFileSync(filePath, content);
|
||||
await fs.writeFile(filePath, content);
|
||||
return res.send({ code: 200 });
|
||||
} catch (e) {
|
||||
return next(e);
|
||||
|
@ -156,7 +161,7 @@ export default (app: Router) => {
|
|||
path: string;
|
||||
};
|
||||
const filePath = join(config.scriptPath, path, filename);
|
||||
fs.writeFileSync(filePath, content);
|
||||
await fs.writeFile(filePath, content);
|
||||
return res.send({ code: 200 });
|
||||
} catch (e) {
|
||||
return next(e);
|
||||
|
@ -182,11 +187,7 @@ export default (app: Router) => {
|
|||
type: string;
|
||||
};
|
||||
const filePath = join(config.scriptPath, path, filename);
|
||||
if (type === 'directory') {
|
||||
await emptyDir(filePath);
|
||||
} else {
|
||||
fs.unlinkSync(filePath);
|
||||
}
|
||||
await rmPath(filePath);
|
||||
res.send({ code: 200 });
|
||||
} catch (e) {
|
||||
return next(e);
|
||||
|
@ -239,7 +240,7 @@ export default (app: Router) => {
|
|||
let { filename, content, path } = req.body;
|
||||
const { name, ext } = parse(filename);
|
||||
const filePath = join(config.scriptPath, path, `${name}.swap${ext}`);
|
||||
fs.writeFileSync(filePath, content || '', { encoding: 'utf8' });
|
||||
await fs.writeFile(filePath, content || '', { encoding: 'utf8' });
|
||||
|
||||
const scriptService = Container.get(ScriptService);
|
||||
const result = await scriptService.runScript(filePath);
|
||||
|
@ -269,7 +270,7 @@ export default (app: Router) => {
|
|||
const scriptService = Container.get(ScriptService);
|
||||
const result = await scriptService.stopScript(filePath, pid);
|
||||
setTimeout(() => {
|
||||
emptyDir(logPath);
|
||||
rmPath(logPath);
|
||||
}, 3000);
|
||||
res.send(result);
|
||||
} catch (e) {
|
||||
|
@ -297,7 +298,7 @@ export default (app: Router) => {
|
|||
};
|
||||
const filePath = join(config.scriptPath, path, filename);
|
||||
const newPath = join(config.scriptPath, path, newFilename);
|
||||
fs.renameSync(filePath, newPath);
|
||||
await fs.rename(filePath, newPath);
|
||||
res.send({ code: 200 });
|
||||
} catch (e) {
|
||||
return next(e);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Router, Request, Response, NextFunction } from 'express';
|
||||
import { Container } from 'typedi';
|
||||
import { Logger } from 'winston';
|
||||
import * as fs from 'fs';
|
||||
import * as fs from 'fs/promises';
|
||||
import config from '../config';
|
||||
import SystemService from '../services/system';
|
||||
import { celebrate, Joi } from 'celebrate';
|
||||
|
@ -174,7 +174,7 @@ export default (app: Router) => {
|
|||
async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const systemService = Container.get(SystemService);
|
||||
const command = req.body.command
|
||||
const command = req.body.command;
|
||||
const idStr = `cat ${config.crontabFile} | grep -E "${command}" | perl -pe "s|.*ID=(.*) ${command}.*|\\1|" | head -1 | awk -F " " '{print $1}' | xargs echo -n`;
|
||||
let id = await promiseExec(idStr);
|
||||
const uniqPath = await getUniqPath(command, id);
|
||||
|
@ -193,12 +193,12 @@ export default (app: Router) => {
|
|||
onError: async (message: string) => {
|
||||
res.write(`\n${message}`);
|
||||
const absolutePath = await handleLogPath(logPath);
|
||||
fs.appendFileSync(absolutePath, `\n${message}`);
|
||||
await fs.appendFile(absolutePath, `\n${message}`);
|
||||
},
|
||||
onLog: async (message: string) => {
|
||||
res.write(`\n${message}`);
|
||||
const absolutePath = await handleLogPath(logPath);
|
||||
fs.appendFileSync(absolutePath, `\n${message}`);
|
||||
await fs.appendFile(absolutePath, `\n${message}`);
|
||||
},
|
||||
},
|
||||
);
|
||||
|
@ -253,16 +253,12 @@ export default (app: Router) => {
|
|||
},
|
||||
);
|
||||
|
||||
route.get(
|
||||
'/log',
|
||||
async (req: Request, res: Response, next: NextFunction) => {
|
||||
route.get('/log', async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const systemService = Container.get(SystemService);
|
||||
await systemService.getSystemLog(res);
|
||||
} catch (e) {
|
||||
return next(e);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import * as fs from 'fs';
|
||||
import * as fs from 'fs/promises';
|
||||
import * as path from 'path';
|
||||
import got from 'got';
|
||||
import iconv from 'iconv-lite';
|
||||
|
@ -13,22 +13,24 @@ import Logger from '../loaders/logger';
|
|||
|
||||
export * from './share';
|
||||
|
||||
export function getFileContentByName(fileName: string) {
|
||||
if (fs.existsSync(fileName)) {
|
||||
return fs.readFileSync(fileName, 'utf8');
|
||||
export async function getFileContentByName(fileName: string) {
|
||||
const _exsit = await fileExist(fileName);
|
||||
if (_exsit) {
|
||||
return await fs.readFile(fileName, 'utf8');
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
export function getLastModifyFilePath(dir: string) {
|
||||
export async function getLastModifyFilePath(dir: string) {
|
||||
let filePath = '';
|
||||
|
||||
if (fs.existsSync(dir)) {
|
||||
const arr = fs.readdirSync(dir);
|
||||
const _exsit = await fileExist(dir);
|
||||
if (_exsit) {
|
||||
const arr = await fs.readdir(dir);
|
||||
|
||||
arr.forEach((item) => {
|
||||
arr.forEach(async (item) => {
|
||||
const fullpath = path.join(dir, item);
|
||||
const stats = fs.statSync(fullpath);
|
||||
const stats = await fs.stat(fullpath);
|
||||
if (stats.isFile()) {
|
||||
if (stats.mtimeMs >= 0) {
|
||||
filePath = fullpath;
|
||||
|
@ -152,22 +154,17 @@ export function getPlatform(userAgent: string): 'mobile' | 'desktop' {
|
|||
}
|
||||
|
||||
export async function fileExist(file: any) {
|
||||
return new Promise((resolve) => {
|
||||
try {
|
||||
fs.accessSync(file);
|
||||
resolve(true);
|
||||
await fs.access(file);
|
||||
return true;
|
||||
} catch (error) {
|
||||
resolve(false);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function createFile(file: string, data: string = '') {
|
||||
return new Promise((resolve) => {
|
||||
fs.mkdirSync(path.dirname(file), { recursive: true });
|
||||
fs.writeFileSync(file, data);
|
||||
resolve(true);
|
||||
});
|
||||
await fs.mkdir(path.dirname(file), { recursive: true });
|
||||
await fs.writeFile(file, data);
|
||||
}
|
||||
|
||||
export async function handleLogPath(
|
||||
|
@ -244,18 +241,18 @@ export function dirSort(a: IFile, b: IFile): number {
|
|||
}
|
||||
}
|
||||
|
||||
export function readDirs(
|
||||
export async function readDirs(
|
||||
dir: string,
|
||||
baseDir: string = '',
|
||||
blacklist: string[] = [],
|
||||
): IFile[] {
|
||||
): Promise<IFile[]> {
|
||||
const relativePath = path.relative(baseDir, dir);
|
||||
const files = fs.readdirSync(dir);
|
||||
const result: IFile[] = files
|
||||
const files = await fs.readdir(dir);
|
||||
const result: IFile[] = await Promise.all(files
|
||||
.filter((x) => !blacklist.includes(x))
|
||||
.map((file: string) => {
|
||||
.map(async (file: string) => {
|
||||
const subPath = path.join(dir, file);
|
||||
const stats = fs.statSync(subPath);
|
||||
const stats = await fs.stat(subPath);
|
||||
const key = path.join(relativePath, file);
|
||||
if (stats.isDirectory()) {
|
||||
return {
|
||||
|
@ -264,7 +261,7 @@ export function readDirs(
|
|||
type: 'directory',
|
||||
parent: relativePath,
|
||||
mtime: stats.mtime.getTime(),
|
||||
children: readDirs(subPath, baseDir).sort(dirSort),
|
||||
children: (await readDirs(subPath, baseDir)).sort(dirSort),
|
||||
};
|
||||
}
|
||||
return {
|
||||
|
@ -276,22 +273,22 @@ export function readDirs(
|
|||
size: stats.size,
|
||||
mtime: stats.mtime.getTime(),
|
||||
};
|
||||
});
|
||||
}));
|
||||
return result.sort(dirSort);
|
||||
}
|
||||
|
||||
export function readDir(
|
||||
export async function readDir(
|
||||
dir: string,
|
||||
baseDir: string = '',
|
||||
blacklist: string[] = [],
|
||||
) {
|
||||
const relativePath = path.relative(baseDir, dir);
|
||||
const files = fs.readdirSync(dir);
|
||||
const files = await fs.readdir(dir);
|
||||
const result: any = files
|
||||
.filter((x) => !blacklist.includes(x))
|
||||
.map((file: string) => {
|
||||
.map(async (file: string) => {
|
||||
const subPath = path.join(dir, file);
|
||||
const stats = fs.statSync(subPath);
|
||||
const stats = await fs.stat(subPath);
|
||||
const key = path.join(relativePath, file);
|
||||
return {
|
||||
title: file,
|
||||
|
@ -303,24 +300,6 @@ export function readDir(
|
|||
return result;
|
||||
}
|
||||
|
||||
export async function emptyDir(path: string) {
|
||||
const pathExist = await fileExist(path);
|
||||
if (!pathExist) {
|
||||
return;
|
||||
}
|
||||
const files = fs.readdirSync(path);
|
||||
for (const file of files) {
|
||||
const filePath = `${path}/${file}`;
|
||||
const stats = fs.statSync(filePath);
|
||||
if (stats.isDirectory()) {
|
||||
await emptyDir(filePath);
|
||||
} else {
|
||||
fs.unlinkSync(filePath);
|
||||
}
|
||||
}
|
||||
fs.rmdirSync(path);
|
||||
}
|
||||
|
||||
export async function promiseExec(command: string): Promise<string> {
|
||||
try {
|
||||
const { stderr, stdout } = await promisify(exec)(command, { maxBuffer: 200 * 1024 * 1024, encoding: 'utf8' });
|
||||
|
@ -449,7 +428,7 @@ interface IVersion {
|
|||
}
|
||||
|
||||
export async function parseVersion(path: string): Promise<IVersion> {
|
||||
return load(await promisify(fs.readFile)(path, 'utf8')) as IVersion;
|
||||
return load(await fs.readFile(path, 'utf8')) as IVersion;
|
||||
}
|
||||
|
||||
export async function parseContentVersion(content: string): Promise<IVersion> {
|
||||
|
@ -502,3 +481,14 @@ export function safeJSONParse(value?: string) {
|
|||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
export async function rmPath(path: string) {
|
||||
try {
|
||||
const _exsit = await fileExist(path);
|
||||
if (_exsit) {
|
||||
await fs.rm(path, { force: true, recursive: true, maxRetries: 5 });
|
||||
}
|
||||
} catch (error) {
|
||||
Logger.error('[rmPath失败]', error)
|
||||
}
|
||||
}
|
|
@ -1,20 +1,17 @@
|
|||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import fs from 'fs/promises';
|
||||
import chokidar from 'chokidar';
|
||||
import config from '../config/index';
|
||||
import { promiseExec } from '../config/util';
|
||||
import { fileExist, promiseExec, rmPath } from '../config/util';
|
||||
|
||||
function linkToNodeModule(src: string, dst?: string) {
|
||||
async function linkToNodeModule(src: string, dst?: string) {
|
||||
const target = path.join(config.rootPath, 'node_modules', dst || src);
|
||||
const source = path.join(config.rootPath, src);
|
||||
|
||||
fs.lstat(target, (err, stat) => {
|
||||
if (!stat) {
|
||||
fs.symlink(source, target, 'dir', (err) => {
|
||||
if (err) throw err;
|
||||
});
|
||||
const _exist = await fileExist(target);
|
||||
if (!_exist) {
|
||||
await fs.symlink(source, target, 'dir');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function linkCommand() {
|
||||
|
@ -34,16 +31,14 @@ async function linkCommand() {
|
|||
for (const link of linkShell) {
|
||||
const source = path.join(config.rootPath, 'shell', link.src);
|
||||
const target = path.join(commandDir, link.dest);
|
||||
if (fs.existsSync(target)) {
|
||||
fs.unlinkSync(target);
|
||||
}
|
||||
fs.symlink(source, target, (err) => { });
|
||||
await rmPath(target);
|
||||
await fs.symlink(source, target);
|
||||
}
|
||||
}
|
||||
|
||||
export default async (src: string = 'deps') => {
|
||||
await linkCommand();
|
||||
linkToNodeModule(src);
|
||||
await linkToNodeModule(src);
|
||||
|
||||
const source = path.join(config.rootPath, src);
|
||||
const watcher = chokidar.watch(source, {
|
||||
|
|
|
@ -4,7 +4,7 @@ import cors from 'cors';
|
|||
import routes from '../api';
|
||||
import config from '../config';
|
||||
import jwt, { UnauthorizedError } from 'express-jwt';
|
||||
import fs from 'fs';
|
||||
import fs from 'fs/promises';
|
||||
import { getPlatform, getToken, safeJSONParse } from '../config/util';
|
||||
import Container from 'typedi';
|
||||
import OpenService from '../services/open';
|
||||
|
@ -29,7 +29,7 @@ export default ({ app }: { app: Application }) => {
|
|||
target: `http://0.0.0.0:${config.publicPort}/api`,
|
||||
changeOrigin: true,
|
||||
pathRewrite: { '/api/public': '' },
|
||||
logProvider: () => Logger
|
||||
logProvider: () => Logger,
|
||||
}),
|
||||
);
|
||||
|
||||
|
@ -83,7 +83,7 @@ export default ({ app }: { app: Application }) => {
|
|||
return next();
|
||||
}
|
||||
|
||||
const data = fs.readFileSync(config.authConfigFile, 'utf8');
|
||||
const data = await fs.readFile(config.authConfigFile, 'utf8');
|
||||
if (data && headerToken) {
|
||||
const { token = '', tokens = {} } = safeJSONParse(data);
|
||||
if (headerToken === token || tokens[req.platform] === headerToken) {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import fs from 'fs';
|
||||
import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
import os from 'os';
|
||||
import dotenv from 'dotenv';
|
||||
import Logger from './logger';
|
||||
import { fileExist } from '../config/util';
|
||||
|
||||
|
@ -48,64 +47,70 @@ export default async () => {
|
|||
const TaskAfterFileExist = await fileExist(TaskAfterFile);
|
||||
|
||||
if (!configDirExist) {
|
||||
fs.mkdirSync(configPath);
|
||||
await fs.mkdir(configPath);
|
||||
}
|
||||
|
||||
if (!scriptDirExist) {
|
||||
fs.mkdirSync(scriptPath);
|
||||
await fs.mkdir(scriptPath);
|
||||
}
|
||||
|
||||
if (!logDirExist) {
|
||||
fs.mkdirSync(logPath);
|
||||
await fs.mkdir(logPath);
|
||||
}
|
||||
|
||||
if (!tmpDirExist) {
|
||||
fs.mkdirSync(tmpPath);
|
||||
await fs.mkdir(tmpPath);
|
||||
}
|
||||
|
||||
if (!uploadDirExist) {
|
||||
fs.mkdirSync(uploadPath);
|
||||
await fs.mkdir(uploadPath);
|
||||
}
|
||||
|
||||
if (!sshDirExist) {
|
||||
fs.mkdirSync(sshPath);
|
||||
await fs.mkdir(sshPath);
|
||||
}
|
||||
|
||||
if (!bakDirExist) {
|
||||
fs.mkdirSync(bakPath);
|
||||
await fs.mkdir(bakPath);
|
||||
}
|
||||
|
||||
if (!sshdDirExist) {
|
||||
fs.mkdirSync(sshdPath);
|
||||
await fs.mkdir(sshdPath);
|
||||
}
|
||||
|
||||
if (!systemLogDirExist) {
|
||||
fs.mkdirSync(systemLogPath);
|
||||
await fs.mkdir(systemLogPath);
|
||||
}
|
||||
|
||||
// 初始化文件
|
||||
if (!authFileExist) {
|
||||
fs.writeFileSync(authConfigFile, fs.readFileSync(sampleAuthFile));
|
||||
await fs.writeFile(authConfigFile, await fs.readFile(sampleAuthFile));
|
||||
}
|
||||
|
||||
if (!confFileExist) {
|
||||
fs.writeFileSync(confFile, fs.readFileSync(sampleConfigFile));
|
||||
await fs.writeFile(confFile, await fs.readFile(sampleConfigFile));
|
||||
}
|
||||
|
||||
if (!scriptNotifyJsFileExist) {
|
||||
fs.writeFileSync(scriptNotifyJsFile, fs.readFileSync(sampleNotifyJsFile));
|
||||
await fs.writeFile(
|
||||
scriptNotifyJsFile,
|
||||
await fs.readFile(sampleNotifyJsFile),
|
||||
);
|
||||
}
|
||||
|
||||
if (!scriptNotifyPyFileExist) {
|
||||
fs.writeFileSync(scriptNotifyPyFile, fs.readFileSync(sampleNotifyPyFile));
|
||||
await fs.writeFile(
|
||||
scriptNotifyPyFile,
|
||||
await fs.readFile(sampleNotifyPyFile),
|
||||
);
|
||||
}
|
||||
|
||||
if (!TaskBeforeFileExist) {
|
||||
fs.writeFileSync(TaskBeforeFile, fs.readFileSync(sampleTaskShellFile));
|
||||
await fs.writeFile(TaskBeforeFile, await fs.readFile(sampleTaskShellFile));
|
||||
}
|
||||
|
||||
if (!TaskAfterFileExist) {
|
||||
fs.writeFileSync(TaskAfterFile, fs.readFileSync(sampleTaskShellFile));
|
||||
await fs.writeFile(TaskAfterFile, await fs.readFile(sampleTaskShellFile));
|
||||
}
|
||||
|
||||
Logger.info('✌️ Init file down');
|
||||
|
|
|
@ -1,22 +1,21 @@
|
|||
import sockJs from 'sockjs';
|
||||
import { Server } from 'http';
|
||||
import Logger from './logger';
|
||||
import { Container } from 'typedi';
|
||||
import SockService from '../services/sock';
|
||||
import config from '../config/index';
|
||||
import fs from 'fs';
|
||||
import fs from 'fs/promises';
|
||||
import { getPlatform, safeJSONParse } from '../config/util';
|
||||
|
||||
export default async ({ server }: { server: Server }) => {
|
||||
const echo = sockJs.createServer({ prefix: '/api/ws', log: () => {} });
|
||||
const sockService = Container.get(SockService);
|
||||
|
||||
echo.on('connection', (conn) => {
|
||||
echo.on('connection', async (conn) => {
|
||||
if (!conn.headers || !conn.url || !conn.pathname) {
|
||||
conn.close('404');
|
||||
}
|
||||
|
||||
const data = fs.readFileSync(config.authConfigFile, 'utf8');
|
||||
const data = await fs.readFile(config.authConfigFile, 'utf8');
|
||||
const platform = getPlatform(conn.headers['user-agent'] || '') || 'desktop';
|
||||
const headerToken = conn.url.replace(`${conn.pathname}?token=`, '');
|
||||
if (data) {
|
||||
|
|
|
@ -3,10 +3,15 @@ import winston from 'winston';
|
|||
import config from '../config';
|
||||
import { Crontab, CrontabModel, CrontabStatus } from '../data/cron';
|
||||
import { exec, execSync } from 'child_process';
|
||||
import fs from 'fs';
|
||||
import fs from 'fs/promises';
|
||||
import cron_parser from 'cron-parser';
|
||||
import { getFileContentByName, fileExist, killTask, getUniqPath, safeJSONParse } from '../config/util';
|
||||
import { promises, existsSync } from 'fs';
|
||||
import {
|
||||
getFileContentByName,
|
||||
fileExist,
|
||||
killTask,
|
||||
getUniqPath,
|
||||
safeJSONParse,
|
||||
} from '../config/util';
|
||||
import { Op, where, col as colFn, FindOptions, fn } from 'sequelize';
|
||||
import path from 'path';
|
||||
import { TASK_PREFIX, QL_PREFIX } from '../config/const';
|
||||
|
@ -35,7 +40,13 @@ export default class CronService {
|
|||
const doc = await this.insert(tab);
|
||||
if (this.isSixCron(doc) || doc.extra_schedules?.length) {
|
||||
await cronClient.addCron([
|
||||
{ name: doc.name || '', id: String(doc.id), schedule: doc.schedule!, command: this.makeCommand(doc), extraSchedules: doc.extra_schedules || [] },
|
||||
{
|
||||
name: doc.name || '',
|
||||
id: String(doc.id),
|
||||
schedule: doc.schedule!,
|
||||
command: this.makeCommand(doc),
|
||||
extraSchedules: doc.extra_schedules || [],
|
||||
},
|
||||
]);
|
||||
}
|
||||
await this.set_crontab();
|
||||
|
@ -64,7 +75,7 @@ export default class CronService {
|
|||
id: String(newDoc.id),
|
||||
schedule: newDoc.schedule!,
|
||||
command: this.makeCommand(newDoc),
|
||||
extraSchedules: newDoc.extra_schedules || []
|
||||
extraSchedules: newDoc.extra_schedules || [],
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
@ -107,7 +118,10 @@ export default class CronService {
|
|||
if (status === CrontabStatus.idle && log_path !== cron.log_path) {
|
||||
options = omit(options, ['status', 'log_path', 'pid']);
|
||||
}
|
||||
await CrontabModel.update({ ...pickBy(options, (v) => v === 0 || !!v) }, { where: { id } });
|
||||
await CrontabModel.update(
|
||||
{ ...pickBy(options, (v) => v === 0 || !!v) },
|
||||
{ where: { id } },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -396,35 +410,45 @@ export default class CronService {
|
|||
return taskLimit.runWithCronLimit(() => {
|
||||
return new Promise(async (resolve: any) => {
|
||||
const cron = await this.getDb({ id: cronId });
|
||||
const params = { name: cron.name, command: cron.command, schedule: cron.schedule, extraSchedules: cron.extra_schedules };
|
||||
const params = {
|
||||
name: cron.name,
|
||||
command: cron.command,
|
||||
schedule: cron.schedule,
|
||||
extraSchedules: cron.extra_schedules,
|
||||
};
|
||||
if (cron.status !== CrontabStatus.queued) {
|
||||
resolve(params);
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.info(`[panel][开始执行任务] 参数 ${JSON.stringify(params)}`);
|
||||
this.logger.info(
|
||||
`[panel][开始执行任务] 参数 ${JSON.stringify(params)}`,
|
||||
);
|
||||
|
||||
let { id, command, log_path } = cron;
|
||||
const uniqPath = await getUniqPath(command, `${id}`);
|
||||
const logTime = dayjs().format('YYYY-MM-DD-HH-mm-ss-SSS');
|
||||
const logDirPath = path.resolve(config.logPath, `${uniqPath}`);
|
||||
if (log_path?.split('/')?.every(x => x !== uniqPath)) {
|
||||
fs.mkdirSync(logDirPath, { recursive: true });
|
||||
if (log_path?.split('/')?.every((x) => x !== uniqPath)) {
|
||||
await fs.mkdir(logDirPath, { recursive: true });
|
||||
}
|
||||
const logPath = `${uniqPath}/${logTime}.log`;
|
||||
const absolutePath = path.resolve(config.logPath, `${logPath}`);
|
||||
|
||||
const cp = spawn(`real_log_path=${logPath} no_delay=true ${this.makeCommand(cron)}`, { shell: '/bin/bash' });
|
||||
const cp = spawn(
|
||||
`real_log_path=${logPath} no_delay=true ${this.makeCommand(cron)}`,
|
||||
{ shell: '/bin/bash' },
|
||||
);
|
||||
|
||||
await CrontabModel.update(
|
||||
{ status: CrontabStatus.running, pid: cp.pid, log_path: logPath },
|
||||
{ where: { id } },
|
||||
);
|
||||
cp.stderr.on('data', (data) => {
|
||||
fs.appendFileSync(`${absolutePath}`, `${data.toString()}`);
|
||||
cp.stderr.on('data', async (data) => {
|
||||
await fs.appendFile(`${absolutePath}`, `${data.toString()}`);
|
||||
});
|
||||
cp.on('error', (err) => {
|
||||
fs.appendFileSync(`${absolutePath}`, `${JSON.stringify(err)}`);
|
||||
cp.on('error', async (err) => {
|
||||
await fs.appendFile(`${absolutePath}`, `${JSON.stringify(err)}`);
|
||||
});
|
||||
|
||||
cp.on('exit', async (code) => {
|
||||
|
@ -454,7 +478,7 @@ export default class CronService {
|
|||
id: String(doc.id),
|
||||
schedule: doc.schedule!,
|
||||
command: this.makeCommand(doc),
|
||||
extraSchedules: doc.extra_schedules || []
|
||||
extraSchedules: doc.extra_schedules || [],
|
||||
}));
|
||||
await cronClient.addCron(sixCron);
|
||||
await this.set_crontab();
|
||||
|
@ -469,7 +493,7 @@ export default class CronService {
|
|||
const absolutePath = path.resolve(config.logPath, `${doc.log_path}`);
|
||||
const logFileExist = doc.log_path && (await fileExist(absolutePath));
|
||||
if (logFileExist) {
|
||||
return getFileContentByName(`${absolutePath}`);
|
||||
return await getFileContentByName(`${absolutePath}`);
|
||||
} else {
|
||||
return '任务未运行';
|
||||
}
|
||||
|
@ -483,15 +507,18 @@ export default class CronService {
|
|||
|
||||
const relativeDir = path.dirname(`${doc.log_path}`);
|
||||
const dir = path.resolve(config.logPath, relativeDir);
|
||||
if (existsSync(dir)) {
|
||||
let files = await promises.readdir(dir);
|
||||
return files
|
||||
.map((x) => ({
|
||||
const dirExist = await fileExist(dir);
|
||||
if (dirExist) {
|
||||
let files = await fs.readdir(dir);
|
||||
return (
|
||||
await Promise.all(
|
||||
files.map(async (x) => ({
|
||||
filename: x,
|
||||
directory: relativeDir.replace(config.logPath, ''),
|
||||
time: fs.statSync(`${dir}/${x}`).mtime.getTime(),
|
||||
}))
|
||||
.sort((a, b) => b.time - a.time);
|
||||
time: (await fs.stat(`${dir}/${x}`)).mtime.getTime(),
|
||||
})),
|
||||
)
|
||||
).sort((a, b) => b.time - a.time);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
|
@ -502,13 +529,15 @@ export default class CronService {
|
|||
if (!command.startsWith(TASK_PREFIX) && !command.startsWith(QL_PREFIX)) {
|
||||
command = `${TASK_PREFIX}${tab.command}`;
|
||||
}
|
||||
let commandVariable = `no_tee=true ID=${tab.id} `
|
||||
let commandVariable = `no_tee=true ID=${tab.id} `;
|
||||
if (tab.task_before) {
|
||||
commandVariable += `task_before='${tab.task_before.replace(/'/g, "'\\''")
|
||||
commandVariable += `task_before='${tab.task_before
|
||||
.replace(/'/g, "'\\''")
|
||||
.trim()}' `;
|
||||
}
|
||||
if (tab.task_after) {
|
||||
commandVariable += `task_after='${tab.task_after.replace(/'/g, "'\\''")
|
||||
commandVariable += `task_after='${tab.task_after
|
||||
.replace(/'/g, "'\\''")
|
||||
.trim()}' `;
|
||||
}
|
||||
|
||||
|
@ -521,7 +550,11 @@ export default class CronService {
|
|||
var crontab_string = '';
|
||||
tabs.data.forEach((tab) => {
|
||||
const _schedule = tab.schedule && tab.schedule.split(/ +/);
|
||||
if (tab.isDisabled === 1 || _schedule!.length !== 5 || tab.extra_schedules?.length) {
|
||||
if (
|
||||
tab.isDisabled === 1 ||
|
||||
_schedule!.length !== 5 ||
|
||||
tab.extra_schedules?.length
|
||||
) {
|
||||
crontab_string += '# ';
|
||||
crontab_string += tab.schedule;
|
||||
crontab_string += ' ';
|
||||
|
@ -535,7 +568,7 @@ export default class CronService {
|
|||
}
|
||||
});
|
||||
|
||||
fs.writeFileSync(config.crontabFile, crontab_string);
|
||||
await fs.writeFile(config.crontabFile, crontab_string);
|
||||
|
||||
execSync(`crontab ${config.crontabFile}`);
|
||||
await CrontabModel.update({ saved: true }, { where: {} });
|
||||
|
@ -586,7 +619,7 @@ export default class CronService {
|
|||
id: String(doc.id),
|
||||
schedule: doc.schedule!,
|
||||
command: this.makeCommand(doc),
|
||||
extraSchedules: doc.extra_schedules || []
|
||||
extraSchedules: doc.extra_schedules || [],
|
||||
}));
|
||||
await cronClient.addCron(sixCron);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Service, Inject } from 'typedi';
|
||||
import winston from 'winston';
|
||||
import config from '../config';
|
||||
import * as fs from 'fs';
|
||||
import * as fs from 'fs/promises';
|
||||
import {
|
||||
Env,
|
||||
EnvModel,
|
||||
|
@ -208,6 +208,6 @@ export default class EnvService {
|
|||
}
|
||||
}
|
||||
}
|
||||
fs.writeFileSync(config.envFile, env_string);
|
||||
await fs.writeFile(config.envFile, env_string);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
import { Service, Inject } from 'typedi';
|
||||
import winston from 'winston';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import SockService from './sock';
|
||||
import CronService from './cron';
|
||||
import ScheduleService, { TaskCallbacks } from './schedule';
|
||||
import config from '../config';
|
||||
import { TASK_COMMAND } from '../config/const';
|
||||
import { getPid, killTask } from '../config/util';
|
||||
import { getPid, killTask, rmPath } from '../config/util';
|
||||
|
||||
@Service()
|
||||
export default class ScriptService {
|
||||
|
@ -21,9 +20,7 @@ export default class ScriptService {
|
|||
private taskCallbacks(filePath: string): TaskCallbacks {
|
||||
return {
|
||||
onEnd: async (cp, endTime, diff) => {
|
||||
try {
|
||||
fs.unlinkSync(filePath);
|
||||
} catch (error) { }
|
||||
await rmPath(filePath);
|
||||
},
|
||||
onError: async (message: string) => {
|
||||
this.sockService.sendMessage({
|
||||
|
@ -56,7 +53,7 @@ export default class ScriptService {
|
|||
public async stopScript(filePath: string, pid: number) {
|
||||
if (!pid) {
|
||||
const relativePath = path.relative(config.scriptPath, filePath);
|
||||
pid = await getPid(`${TASK_COMMAND} ${relativePath} now`) as number;
|
||||
pid = (await getPid(`${TASK_COMMAND} ${relativePath} now`)) as number;
|
||||
}
|
||||
try {
|
||||
await killTask(pid);
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import { Service, Inject } from 'typedi';
|
||||
import winston from 'winston';
|
||||
import fs, { existsSync } from 'fs';
|
||||
import fs from 'fs/promises';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
import { Subscription } from '../data/subscription';
|
||||
import { formatUrl } from '../config/subscription';
|
||||
import config from '../config';
|
||||
import { fileExist, rmPath } from '../config/util';
|
||||
|
||||
@Service()
|
||||
export default class SshKeyService {
|
||||
|
@ -18,15 +19,16 @@ export default class SshKeyService {
|
|||
this.initSshConfigFile();
|
||||
}
|
||||
|
||||
private initSshConfigFile() {
|
||||
private async initSshConfigFile() {
|
||||
let config = '';
|
||||
if (existsSync(this.sshConfigFilePath)) {
|
||||
config = fs.readFileSync(this.sshConfigFilePath, { encoding: 'utf-8' });
|
||||
const _exist = await fileExist(this.sshConfigFilePath);
|
||||
if (_exist) {
|
||||
config = await fs.readFile(this.sshConfigFilePath, { encoding: 'utf-8' });
|
||||
} else {
|
||||
fs.writeFileSync(this.sshConfigFilePath, '');
|
||||
await fs.writeFile(this.sshConfigFilePath, '');
|
||||
}
|
||||
if (!config.includes(this.sshConfigHeader)) {
|
||||
fs.writeFileSync(
|
||||
await fs.writeFile(
|
||||
this.sshConfigFilePath,
|
||||
`${this.sshConfigHeader}\n\n${config}`,
|
||||
{ encoding: 'utf-8' },
|
||||
|
@ -34,9 +36,12 @@ export default class SshKeyService {
|
|||
}
|
||||
}
|
||||
|
||||
private generatePrivateKeyFile(alias: string, key: string): void {
|
||||
private async generatePrivateKeyFile(
|
||||
alias: string,
|
||||
key: string,
|
||||
): Promise<void> {
|
||||
try {
|
||||
fs.writeFileSync(path.join(this.sshPath, alias), `${key}${os.EOL}`, {
|
||||
await fs.writeFile(path.join(this.sshPath, alias), `${key}${os.EOL}`, {
|
||||
encoding: 'utf8',
|
||||
mode: '400',
|
||||
});
|
||||
|
@ -45,18 +50,20 @@ export default class SshKeyService {
|
|||
}
|
||||
}
|
||||
|
||||
private removePrivateKeyFile(alias: string): void {
|
||||
private async removePrivateKeyFile(alias: string): Promise<void> {
|
||||
try {
|
||||
const filePath = path.join(this.sshPath, alias);
|
||||
if (existsSync(filePath)) {
|
||||
fs.unlinkSync(filePath);
|
||||
}
|
||||
await rmPath(filePath);
|
||||
} catch (error) {
|
||||
this.logger.error('删除私钥文件失败', error);
|
||||
}
|
||||
}
|
||||
|
||||
private generateSingleSshConfig(alias: string, host: string, proxy?: string) {
|
||||
private async generateSingleSshConfig(
|
||||
alias: string,
|
||||
host: string,
|
||||
proxy?: string,
|
||||
) {
|
||||
if (host === 'github.com') {
|
||||
host = `ssh.github.com\n Port 443\n HostkeyAlgorithms +ssh-rsa`;
|
||||
}
|
||||
|
@ -67,49 +74,51 @@ export default class SshKeyService {
|
|||
this.sshPath,
|
||||
alias,
|
||||
)}\n StrictHostKeyChecking no\n${proxyStr}`;
|
||||
fs.writeFileSync(`${path.join(this.sshPath, `${alias}.config`)}`, config, {
|
||||
await fs.writeFile(
|
||||
`${path.join(this.sshPath, `${alias}.config`)}`,
|
||||
config,
|
||||
{
|
||||
encoding: 'utf8',
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
private removeSshConfig(alias: string) {
|
||||
private async removeSshConfig(alias: string) {
|
||||
try {
|
||||
const filePath = path.join(this.sshPath, `${alias}.config`);
|
||||
if (existsSync(filePath)) {
|
||||
fs.unlinkSync(filePath);
|
||||
}
|
||||
await rmPath(filePath);
|
||||
} catch (error) {
|
||||
this.logger.error(`删除ssh配置文件${alias}失败`, error);
|
||||
}
|
||||
}
|
||||
|
||||
public addSSHKey(
|
||||
public async addSSHKey(
|
||||
key: string,
|
||||
alias: string,
|
||||
host: string,
|
||||
proxy?: string,
|
||||
): void {
|
||||
this.generatePrivateKeyFile(alias, key);
|
||||
this.generateSingleSshConfig(alias, host, proxy);
|
||||
): Promise<void> {
|
||||
await this.generatePrivateKeyFile(alias, key);
|
||||
await this.generateSingleSshConfig(alias, host, proxy);
|
||||
}
|
||||
|
||||
public removeSSHKey(alias: string, host: string, proxy?: string): void {
|
||||
this.removePrivateKeyFile(alias);
|
||||
this.removeSshConfig(alias);
|
||||
public async removeSSHKey(alias: string, host: string, proxy?: string): Promise<void> {
|
||||
await this.removePrivateKeyFile(alias);
|
||||
await this.removeSshConfig(alias);
|
||||
}
|
||||
|
||||
public setSshConfig(docs: Subscription[]) {
|
||||
public async setSshConfig(docs: Subscription[]) {
|
||||
for (const doc of docs) {
|
||||
if (doc.type === 'private-repo' && doc.pull_type === 'ssh-key') {
|
||||
const { alias, proxy } = doc;
|
||||
const { host } = formatUrl(doc);
|
||||
this.removePrivateKeyFile(alias);
|
||||
this.removeSshConfig(alias);
|
||||
this.generatePrivateKeyFile(
|
||||
await this.removePrivateKeyFile(alias);
|
||||
await this.removeSshConfig(alias);
|
||||
await this.generatePrivateKeyFile(
|
||||
alias,
|
||||
(doc.pull_option as any).private_key,
|
||||
);
|
||||
this.generateSingleSshConfig(alias, host, proxy);
|
||||
await this.generateSingleSshConfig(alias, host, proxy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import {
|
|||
SubscriptionStatus,
|
||||
} from '../data/subscription';
|
||||
import { ChildProcessWithoutNullStreams } from 'child_process';
|
||||
import fs from 'fs';
|
||||
import {
|
||||
getFileContentByName,
|
||||
concurrentRun,
|
||||
|
@ -16,9 +15,9 @@ import {
|
|||
killTask,
|
||||
handleLogPath,
|
||||
promiseExec,
|
||||
emptyDir,
|
||||
rmPath,
|
||||
} from '../config/util';
|
||||
import { promises, existsSync } from 'fs';
|
||||
import fs from 'fs/promises';
|
||||
import { FindOptions, Op } from 'sequelize';
|
||||
import path, { join } from 'path';
|
||||
import ScheduleService, { TaskCallbacks } from './schedule';
|
||||
|
@ -107,7 +106,7 @@ export default class SubscriptionService {
|
|||
|
||||
public async setSshConfig() {
|
||||
const docs = await SubscriptionModel.findAll();
|
||||
this.sshKeyService.setSshConfig(docs);
|
||||
await this.sshKeyService.setSshConfig(docs);
|
||||
}
|
||||
|
||||
private taskCallbacks(doc: Subscription): TaskCallbacks {
|
||||
|
@ -131,7 +130,7 @@ export default class SubscriptionService {
|
|||
let beforeStr = '';
|
||||
try {
|
||||
if (doc.sub_before) {
|
||||
fs.appendFileSync(absolutePath, `\n## 执行before命令...\n\n`);
|
||||
await fs.appendFile(absolutePath, `\n## 执行before命令...\n\n`);
|
||||
beforeStr = await promiseExec(doc.sub_before);
|
||||
}
|
||||
} catch (error: any) {
|
||||
|
@ -139,7 +138,7 @@ export default class SubscriptionService {
|
|||
(error.stderr && error.stderr.toString()) || JSON.stringify(error);
|
||||
}
|
||||
if (beforeStr) {
|
||||
fs.appendFileSync(absolutePath, `${beforeStr}\n`);
|
||||
await fs.appendFile(absolutePath, `${beforeStr}\n`);
|
||||
}
|
||||
},
|
||||
onStart: async (cp: ChildProcessWithoutNullStreams, startTime) => {
|
||||
|
@ -158,7 +157,7 @@ export default class SubscriptionService {
|
|||
let afterStr = '';
|
||||
try {
|
||||
if (sub.sub_after) {
|
||||
fs.appendFileSync(absolutePath, `\n\n## 执行after命令...\n\n`);
|
||||
await fs.appendFile(absolutePath, `\n\n## 执行after命令...\n\n`);
|
||||
afterStr = await promiseExec(sub.sub_after);
|
||||
}
|
||||
} catch (error: any) {
|
||||
|
@ -166,10 +165,10 @@ export default class SubscriptionService {
|
|||
(error.stderr && error.stderr.toString()) || JSON.stringify(error);
|
||||
}
|
||||
if (afterStr) {
|
||||
fs.appendFileSync(absolutePath, `${afterStr}\n`);
|
||||
await fs.appendFile(absolutePath, `${afterStr}\n`);
|
||||
}
|
||||
|
||||
fs.appendFileSync(
|
||||
await fs.appendFile(
|
||||
absolutePath,
|
||||
`\n## 执行结束... ${endTime.format(
|
||||
'YYYY-MM-DD HH:mm:ss',
|
||||
|
@ -190,12 +189,12 @@ export default class SubscriptionService {
|
|||
onError: async (message: string) => {
|
||||
const sub = await this.getDb({ id: doc.id });
|
||||
const absolutePath = await handleLogPath(sub.log_path as string);
|
||||
fs.appendFileSync(absolutePath, `\n${message}`);
|
||||
await fs.appendFile(absolutePath, `\n${message}`);
|
||||
},
|
||||
onLog: async (message: string) => {
|
||||
const sub = await this.getDb({ id: doc.id });
|
||||
const absolutePath = await handleLogPath(sub.log_path as string);
|
||||
fs.appendFileSync(absolutePath, `\n${message}`);
|
||||
await fs.appendFile(absolutePath, `\n${message}`);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -268,11 +267,11 @@ export default class SubscriptionService {
|
|||
if (query?.force === true) {
|
||||
const crons = await CrontabModel.findAll({ where: { sub_id: ids } });
|
||||
if (crons?.length) {
|
||||
await this.crontabService.remove(crons.map(x => x.id!))
|
||||
await this.crontabService.remove(crons.map((x) => x.id!));
|
||||
}
|
||||
for (const doc of docs) {
|
||||
const filePath = join(config.scriptPath, doc.alias);
|
||||
emptyDir(filePath);
|
||||
await rmPath(filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -323,7 +322,7 @@ export default class SubscriptionService {
|
|||
this.scheduleService.runTask(command, this.taskCallbacks(subscription), {
|
||||
name: subscription.name,
|
||||
schedule: subscription.schedule,
|
||||
command
|
||||
command,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -352,7 +351,7 @@ export default class SubscriptionService {
|
|||
}
|
||||
|
||||
const absolutePath = await handleLogPath(doc.log_path as string);
|
||||
return getFileContentByName(absolutePath);
|
||||
return await getFileContentByName(absolutePath);
|
||||
}
|
||||
|
||||
public async logs(id: number) {
|
||||
|
@ -364,15 +363,18 @@ export default class SubscriptionService {
|
|||
if (doc.log_path) {
|
||||
const relativeDir = path.dirname(`${doc.log_path}`);
|
||||
const dir = path.resolve(config.logPath, relativeDir);
|
||||
if (existsSync(dir)) {
|
||||
let files = await promises.readdir(dir);
|
||||
return files
|
||||
.map((x) => ({
|
||||
const _exist = await fileExist(dir);
|
||||
if (_exist) {
|
||||
let files = await fs.readdir(dir);
|
||||
return (
|
||||
await Promise.all(
|
||||
files.map(async (x) => ({
|
||||
filename: x,
|
||||
directory: relativeDir.replace(config.logPath, ''),
|
||||
time: fs.statSync(`${dir}/${x}`).mtime.getTime(),
|
||||
}))
|
||||
.sort((a, b) => b.time - a.time);
|
||||
time: (await fs.stat(`${dir}/${x}`)).mtime.getTime(),
|
||||
})),
|
||||
)
|
||||
).sort((a, b) => b.time - a.time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -234,7 +234,7 @@ export default class SystemService {
|
|||
callback,
|
||||
{
|
||||
command,
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -283,7 +283,7 @@ export default class SystemService {
|
|||
}
|
||||
|
||||
public async getSystemLog(res: Response) {
|
||||
const result = readDirs(config.systemLogPath, config.systemLogPath);
|
||||
const result = await readDirs(config.systemLogPath, config.systemLogPath);
|
||||
const logs = result.reverse().filter((x) => x.title.endsWith('.log'));
|
||||
res.set({
|
||||
'Content-Length': sum(logs.map((x) => x.size)),
|
||||
|
|
|
@ -8,7 +8,7 @@ import {
|
|||
safeJSONParse,
|
||||
} from '../config/util';
|
||||
import config from '../config';
|
||||
import * as fs from 'fs';
|
||||
import * as fs from 'fs/promises';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { authenticator } from '@otplib/preset-default';
|
||||
import {
|
||||
|
@ -44,12 +44,13 @@ export default class UserService {
|
|||
req: Request,
|
||||
needTwoFactor = true,
|
||||
): Promise<any> {
|
||||
if (!fs.existsSync(config.authConfigFile)) {
|
||||
const _exist = await fileExist(config.authConfigFile);
|
||||
if (!_exist) {
|
||||
return this.initAuthInfo();
|
||||
}
|
||||
|
||||
let { username, password } = payloads;
|
||||
const content = this.getAuthInfo();
|
||||
const content = await this.getAuthInfo();
|
||||
const timestamp = Date.now();
|
||||
if (content) {
|
||||
let {
|
||||
|
@ -187,7 +188,7 @@ export default class UserService {
|
|||
}
|
||||
|
||||
public async logout(platform: string): Promise<any> {
|
||||
const authInfo = this.getAuthInfo();
|
||||
const authInfo = await this.getAuthInfo();
|
||||
this.updateAuthInfo(authInfo, {
|
||||
token: '',
|
||||
tokens: { ...authInfo.tokens, [platform]: '' },
|
||||
|
@ -217,8 +218,8 @@ export default class UserService {
|
|||
return doc;
|
||||
}
|
||||
|
||||
private initAuthInfo() {
|
||||
fs.writeFileSync(
|
||||
private async initAuthInfo() {
|
||||
await fs.writeFile(
|
||||
config.authConfigFile,
|
||||
JSON.stringify({
|
||||
username: 'admin',
|
||||
|
@ -255,7 +256,7 @@ export default class UserService {
|
|||
public async getUserInfo(): Promise<any> {
|
||||
const authFileExist = await fileExist(config.authConfigFile);
|
||||
if (!authFileExist) {
|
||||
fs.writeFileSync(
|
||||
await fs.writeFile(
|
||||
config.authConfigFile,
|
||||
JSON.stringify({
|
||||
username: 'admin',
|
||||
|
@ -266,16 +267,16 @@ export default class UserService {
|
|||
return this.getAuthInfo();
|
||||
}
|
||||
|
||||
public initTwoFactor() {
|
||||
public async initTwoFactor() {
|
||||
const secret = authenticator.generateSecret();
|
||||
const authInfo = this.getAuthInfo();
|
||||
const authInfo = await this.getAuthInfo();
|
||||
const otpauth = authenticator.keyuri(authInfo.username, 'qinglong', secret);
|
||||
this.updateAuthInfo(authInfo, { twoFactorSecret: secret });
|
||||
return { secret, url: otpauth };
|
||||
}
|
||||
|
||||
public activeTwoFactor(code: string) {
|
||||
const authInfo = this.getAuthInfo();
|
||||
public async activeTwoFactor(code: string) {
|
||||
const authInfo = await this.getAuthInfo();
|
||||
const isValid = authenticator.verify({
|
||||
token: code,
|
||||
secret: authInfo.twoFactorSecret,
|
||||
|
@ -294,7 +295,7 @@ export default class UserService {
|
|||
}: { username: string; password: string; code: string },
|
||||
req: any,
|
||||
) {
|
||||
const authInfo = this.getAuthInfo();
|
||||
const authInfo = await this.getAuthInfo();
|
||||
const { isTwoFactorChecking, twoFactorSecret } = authInfo;
|
||||
if (!isTwoFactorChecking) {
|
||||
return { code: 450, message: '未知错误' };
|
||||
|
@ -326,13 +327,13 @@ export default class UserService {
|
|||
return true;
|
||||
}
|
||||
|
||||
private getAuthInfo() {
|
||||
const content = fs.readFileSync(config.authConfigFile, 'utf8');
|
||||
private async getAuthInfo() {
|
||||
const content = await fs.readFile(config.authConfigFile, 'utf8');
|
||||
return safeJSONParse(content);
|
||||
}
|
||||
|
||||
private updateAuthInfo(authInfo: any, info: any) {
|
||||
fs.writeFileSync(
|
||||
private async updateAuthInfo(authInfo: any, info: any) {
|
||||
await fs.writeFile(
|
||||
config.authConfigFile,
|
||||
JSON.stringify({ ...authInfo, ...info }),
|
||||
);
|
||||
|
|
0
shell/env.sh
Normal file → Executable file
0
shell/env.sh
Normal file → Executable file
Loading…
Reference in New Issue
Block a user