使用sqlite替换nedb

This commit is contained in:
whyour
2022-01-06 22:51:12 +08:00
parent 653b1cef20
commit 5d19ee0ab5
38 changed files with 1040 additions and 856 deletions
+102 -192
View File
@@ -1,25 +1,17 @@
import { Service, Inject } from 'typedi';
import winston from 'winston';
import DataStore from 'nedb';
import config from '../config';
import { Crontab, CrontabStatus } from '../data/cron';
import { Crontab, CrontabModel, CrontabStatus } from '../data/cron';
import { exec, execSync, spawn } from 'child_process';
import fs from 'fs';
import cron_parser from 'cron-parser';
import { getFileContentByName, concurrentRun } from '../config/util';
import PQueue from 'p-queue';
import { promises, existsSync } from 'fs';
import { promisify } from 'util';
import { dbs } from '../loaders/db';
import { Op } from 'sequelize';
@Service()
export default class CronService {
private cronDb = dbs.cronDb;
private queue = new PQueue({
concurrency: parseInt(process.env.MaxConcurrentNum as string) || 5,
});
constructor(@Inject('logger') private logger: winston.Logger) {}
private isSixCron(cron: Crontab) {
@@ -32,7 +24,6 @@ export default class CronService {
public async create(payload: Crontab): Promise<Crontab> {
const tab = new Crontab(payload);
tab.created = new Date().valueOf();
tab.saved = false;
const doc = await this.insert(tab);
await this.set_crontab(this.isSixCron(doc));
@@ -40,20 +31,12 @@ export default class CronService {
}
public async insert(payload: Crontab): Promise<Crontab> {
return new Promise((resolve) => {
this.cronDb.insert(payload, (err, docs) => {
if (err) {
this.logger.error(err);
} else {
resolve(docs);
}
});
});
return await CrontabModel.create(payload);
}
public async update(payload: Crontab): Promise<Crontab> {
const { _id, ...other } = payload;
const doc = await this.get(_id);
const { id, ...other } = payload;
const doc = await this.get(id as number);
const tab = new Crontab({ ...doc, ...other });
tab.saved = false;
const newDoc = await this.updateDb(tab);
@@ -62,20 +45,11 @@ export default class CronService {
}
public async updateDb(payload: Crontab): Promise<Crontab> {
return new Promise((resolve) => {
this.cronDb.update(
{ _id: payload._id },
payload,
{ returnUpdatedDocs: true },
(err, num, docs: any) => {
if (err) {
this.logger.error(err);
} else {
resolve(docs);
}
},
);
});
const result = await CrontabModel.update(
{ ...payload },
{ where: { id: payload.id } },
);
return result[1][0];
}
public async status({
@@ -86,7 +60,7 @@ export default class CronService {
last_running_time = 0,
last_execution_time = 0,
}: {
ids: string[];
ids: number[];
status: CrontabStatus;
pid: number;
log_path: string;
@@ -103,67 +77,35 @@ export default class CronService {
options.last_running_time = last_running_time;
}
return new Promise((resolve) => {
this.cronDb.update(
{ _id: { $in: ids } },
{
$set: options,
},
{ multi: true, returnUpdatedDocs: true },
(err) => {
resolve(null);
},
);
});
return await CrontabModel.update({ ...options }, { where: { id: ids } });
}
public async remove(ids: string[]) {
return new Promise((resolve: any) => {
this.cronDb.remove(
{ _id: { $in: ids } },
{ multi: true },
async (err) => {
await this.set_crontab(true);
resolve();
},
);
});
public async remove(ids: number[]) {
await CrontabModel.destroy({ where: { id: ids } });
await this.set_crontab(true);
}
public async pin(ids: string[]) {
return new Promise((resolve: any) => {
this.cronDb.update(
{ _id: { $in: ids } },
{ $set: { isPinned: 1 } },
{ multi: true },
async (err) => {
resolve();
},
);
});
public async pin(ids: number[]) {
await CrontabModel.update({ isPinned: 1 }, { where: { id: ids } });
}
public async unPin(ids: string[]) {
return new Promise((resolve: any) => {
this.cronDb.update(
{ _id: { $in: ids } },
{ $set: { isPinned: 0 } },
{ multi: true },
async (err) => {
resolve();
},
);
});
public async unPin(ids: number[]) {
await CrontabModel.update({ isPinned: 0 }, { where: { id: ids } });
}
public async crontabs(searchText?: string): Promise<Crontab[]> {
let query = {};
if (searchText) {
const encodeText = encodeURIComponent(searchText);
const reg = new RegExp(`${searchText}|${encodeText}`, 'i');
const reg = {
[Op.or]: [
{ [Op.like]: `%${searchText}&` },
{ [Op.like]: `%${encodeText}%` },
],
};
query = {
$or: [
[Op.or]: [
{
name: reg,
},
@@ -176,69 +118,56 @@ export default class CronService {
],
};
}
return new Promise((resolve) => {
this.cronDb
.find(query)
.sort({ created: -1 })
.exec((err, docs) => {
resolve(docs);
});
});
try {
const result = await CrontabModel.findAll({ where: query });
return result as any;
} catch (error) {
throw error;
}
}
public async get(_id: string): Promise<Crontab> {
return new Promise((resolve) => {
this.cronDb.find({ _id }).exec((err, docs) => {
resolve(docs[0]);
});
});
public async get(id: number): Promise<Crontab> {
const result = await CrontabModel.findAll({ where: { id } });
return result[0] as any;
}
public async run(ids: string[]) {
this.cronDb.update(
{ _id: { $in: ids } },
{ $set: { status: CrontabStatus.queued } },
{ multi: true },
public async run(ids: number[]) {
await CrontabModel.update(
{ status: CrontabStatus.queued },
{ where: { id: ids } },
);
concurrentRun(
ids.map((id) => () => this.runSingle(id)),
ids.map((id) => async () => await this.runSingle(id)),
10,
);
}
public async stop(ids: string[]) {
return new Promise((resolve: any) => {
this.cronDb
.find({ _id: { $in: ids } })
.exec(async (err, docs: Crontab[]) => {
for (const doc of docs) {
if (doc.pid) {
try {
process.kill(-doc.pid);
} catch (error) {
this.logger.silly(error);
}
}
const err = await this.killTask(doc.command);
if (doc.log_path) {
const str = err ? `\n${err}` : '';
fs.appendFileSync(
`${doc.log_path}`,
`${str}\n## 执行结束... ${new Date()
.toLocaleString('zh', { hour12: false })
.replace(' 24:', ' 00:')} `,
);
}
}
this.cronDb.update(
{ _id: { $in: ids } },
{ $set: { status: CrontabStatus.idle }, $unset: { pid: true } },
{ multi: true },
);
this.queue.clear();
resolve();
});
});
public async stop(ids: number[]) {
const docs = await CrontabModel.findAll({ where: { id: ids } });
for (const doc of docs) {
if (doc.pid) {
try {
process.kill(-doc.pid);
} catch (error) {
this.logger.silly(error);
}
}
const err = await this.killTask(doc.command);
if (doc.log_path) {
const str = err ? `\n${err}` : '';
fs.appendFileSync(
`${doc.log_path}`,
`${str}\n## 执行结束... ${new Date()
.toLocaleString('zh', { hour12: false })
.replace(' 24:', ' 00:')} `,
);
}
}
await CrontabModel.update(
{ status: CrontabStatus.queued, pid: undefined },
{ where: { id: ids } },
);
}
public async killTask(name: string) {
@@ -273,18 +202,18 @@ export default class CronService {
}
}
private async runSingle(id: string): Promise<number> {
private async runSingle(cronId: number): Promise<number> {
return new Promise(async (resolve: any) => {
const cron = await this.get(id);
const cron = await this.get(cronId);
if (cron.status !== CrontabStatus.queued) {
resolve();
return;
}
let { _id, command, log_path } = cron;
let { id, command, log_path } = cron;
this.logger.silly('Running job');
this.logger.silly('ID: ' + _id);
this.logger.silly('ID: ' + id);
this.logger.silly('Original command: ' + command);
let cmdStr = command;
@@ -296,9 +225,10 @@ export default class CronService {
}
const cp = spawn(cmdStr, { shell: '/bin/bash' });
this.cronDb.update(
{ _id },
{ $set: { status: CrontabStatus.running, pid: cp.pid } },
await CrontabModel.update(
{ status: CrontabStatus.running, pid: cp.pid },
{ where: { id } },
);
cp.stderr.on('data', (data) => {
if (log_path) {
@@ -311,57 +241,39 @@ export default class CronService {
}
});
cp.on('exit', (code, signal) => {
cp.on('exit', async (code, signal) => {
this.logger.info(
`${command} pid: ${cp.pid} exit ${code} signal ${signal}`,
);
this.cronDb.update(
{ _id },
{ $set: { status: CrontabStatus.idle }, $unset: { pid: true } },
await CrontabModel.update(
{ status: CrontabStatus.idle, pid: undefined },
{ where: { id } },
);
resolve();
});
cp.on('close', (code) => {
cp.on('close', async (code) => {
this.logger.info(`${command} pid: ${cp.pid} closed ${code}`);
this.cronDb.update(
{ _id },
{ $set: { status: CrontabStatus.idle }, $unset: { pid: true } },
await CrontabModel.update(
{ status: CrontabStatus.idle, pid: undefined },
{ where: { id } },
);
resolve();
});
});
}
public async disabled(ids: string[]) {
return new Promise((resolve: any) => {
this.cronDb.update(
{ _id: { $in: ids } },
{ $set: { isDisabled: 1 } },
{ multi: true },
async (err) => {
await this.set_crontab(true);
resolve();
},
);
});
public async disabled(ids: number[]) {
await CrontabModel.update({ isDisabled: 1 }, { where: { id: ids } });
await this.set_crontab(true);
}
public async enabled(ids: string[]) {
return new Promise((resolve: any) => {
this.cronDb.update(
{ _id: { $in: ids } },
{ $set: { isDisabled: 0 } },
{ multi: true },
async (err) => {
await this.set_crontab(true);
resolve();
},
);
});
public async enabled(ids: number[]) {
await CrontabModel.update({ isDisabled: 0 }, { where: { id: ids } });
await this.set_crontab(true);
}
public async log(_id: string) {
const doc = await this.get(_id);
public async log(id: number) {
const doc = await this.get(id);
if (!doc) {
return '';
}
@@ -401,7 +313,7 @@ export default class CronService {
}
private make_command(tab: Crontab) {
const crontab_job_string = `ID=${tab._id} ${tab.command}`;
const crontab_job_string = `ID=${tab.id} ${tab.command}`;
return crontab_job_string;
}
@@ -431,7 +343,7 @@ export default class CronService {
if (needReloadSchedule) {
exec(`pm2 reload schedule`);
}
this.cronDb.update({}, { $set: { saved: true } }, { multi: true });
await CrontabModel.update({ saved: true }, { where: {} });
}
public import_crontab() {
@@ -439,7 +351,7 @@ export default class CronService {
var lines = stdout.split('\n');
var namePrefix = new Date().getTime();
lines.reverse().forEach((line, index) => {
lines.reverse().forEach(async (line, index) => {
line = line.replace(/\t+/g, ' ');
var regex =
/^((\@[a-zA-Z]+\s+)|(([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+))/;
@@ -453,18 +365,16 @@ export default class CronService {
) {
var name = namePrefix + '_' + index;
this.cronDb.findOne({ command, schedule }, (err, doc) => {
if (err) {
throw err;
}
if (!doc) {
this.create({ name, command, schedule });
} else {
doc.command = command;
doc.schedule = schedule;
this.update(doc);
}
const _crontab = await CrontabModel.findOne({
where: { command, schedule },
});
if (!_crontab) {
await this.create({ name, command, schedule });
} else {
_crontab.command = command;
_crontab.schedule = schedule;
await this.update(_crontab);
}
}
});
});
+57 -109
View File
@@ -8,16 +8,15 @@ import {
DependenceStatus,
DependenceTypes,
unInstallDependenceCommandTypes,
DependenceModel,
} from '../data/dependence';
import _ from 'lodash';
import { spawn } from 'child_process';
import SockService from './sock';
import { dbs } from '../loaders/db';
import { Op } from 'sequelize';
@Service()
export default class DependenceService {
private dependenceDb = dbs.dependenceDb;
constructor(
@Inject('logger') private logger: winston.Logger,
private sockService: SockService,
@@ -34,22 +33,15 @@ export default class DependenceService {
}
public async insert(payloads: Dependence[]): Promise<Dependence[]> {
return new Promise((resolve) => {
this.dependenceDb.insert(payloads, (err, docs) => {
if (err) {
this.logger.error(err);
} else {
resolve(docs);
}
});
});
const docs = await DependenceModel.bulkCreate(payloads);
return docs;
}
public async update(
payload: Dependence & { _id: string },
payload: Dependence & { id: string },
): Promise<Dependence> {
const { _id, ...other } = payload;
const doc = await this.get(_id);
const { id, ...other } = payload;
const doc = await this.get(id);
const tab = new Dependence({
...doc,
...other,
@@ -61,46 +53,23 @@ export default class DependenceService {
}
private async updateDb(payload: Dependence): Promise<Dependence> {
return new Promise((resolve) => {
this.dependenceDb.update(
{ _id: payload._id },
payload,
{ returnUpdatedDocs: true },
(err, num, doc) => {
if (err) {
this.logger.error(err);
} else {
resolve(doc as Dependence);
}
},
);
});
const [, docs] = await DependenceModel.update(
{ ...payload },
{ where: { id: payload.id } },
);
return docs[0];
}
public async remove(ids: string[]) {
return new Promise((resolve: any) => {
this.dependenceDb.update(
{ _id: { $in: ids } },
{ $set: { status: DependenceStatus.removing, log: [] } },
{ multi: true, returnUpdatedDocs: true },
async (err, num, docs: Dependence[]) => {
this.installOrUninstallDependencies(docs, false);
resolve(docs);
},
);
});
const [, docs] = await DependenceModel.update(
{ status: DependenceStatus.removing, log: [] },
{ where: { id: ids } },
);
this.installOrUninstallDependencies(docs, false);
}
public async removeDb(ids: string[]) {
return new Promise((resolve: any) => {
this.dependenceDb.remove(
{ _id: { $in: ids } },
{ multi: true },
async (err) => {
resolve();
},
);
});
public async removeDb(ids: number[]) {
await DependenceModel.destroy({ where: { id: ids } });
}
public async dependencies(
@@ -110,68 +79,53 @@ export default class DependenceService {
): Promise<Dependence[]> {
let condition = { ...query, type: DependenceTypes[type as any] };
if (searchValue) {
const reg = new RegExp(searchValue);
condition = {
...condition,
$or: [
{
name: reg,
},
const encodeText = encodeURIComponent(searchValue);
const reg = {
[Op.or]: [
{ [Op.like]: `%${encodeText}&` },
{ [Op.like]: `%${encodeText}%` },
],
};
condition = {
...condition,
name: reg,
};
}
try {
const result = await this.find(condition);
return result as any;
} catch (error) {
throw error;
}
const newDocs = await this.find(condition, sort);
return newDocs;
}
public async reInstall(ids: string[]): Promise<Dependence[]> {
return new Promise((resolve: any) => {
this.dependenceDb.update(
{ _id: { $in: ids } },
{ $set: { status: DependenceStatus.installing, log: [] } },
{ multi: true, returnUpdatedDocs: true },
async (err, num, docs: Dependence[]) => {
await this.installOrUninstallDependencies(docs);
resolve(docs);
},
);
});
const [, docs] = await DependenceModel.update(
{ status: DependenceStatus.installing, log: [] },
{ where: { id: ids } },
);
await this.installOrUninstallDependencies(docs);
return docs;
}
private async find(query: any, sort: any): Promise<Dependence[]> {
return new Promise((resolve) => {
this.dependenceDb
.find(query)
.sort({ ...sort })
.exec((err, docs) => {
resolve(docs);
});
});
private async find(query: any, sort?: any): Promise<Dependence[]> {
const docs = await DependenceModel.findAll({ where: { ...query } });
return docs;
}
public async get(_id: string): Promise<Dependence> {
return new Promise((resolve) => {
this.dependenceDb.find({ _id }).exec((err, docs) => {
resolve(docs[0]);
});
});
public async get(id: string): Promise<Dependence> {
const docs = await DependenceModel.findAll({ where: { id } });
return docs[0];
}
private async updateLog(ids: string[], log: string): Promise<void> {
return new Promise((resolve) => {
this.dependenceDb.update(
{ _id: { $in: ids } },
{ $push: { log } },
{ multi: true },
(err, num, doc) => {
if (err) {
this.logger.error(err);
} else {
resolve();
}
},
);
});
private async updateLog(ids: number[], log: string): Promise<void> {
const doc = await DependenceModel.findOne({ where: { id: ids } });
const newLog = doc?.log ? [...doc.log, log] : [log];
const [, docs] = await DependenceModel.update(
{ status: DependenceStatus.installing, log: newLog },
{ where: { id: ids } },
);
}
public installOrUninstallDependencies(
@@ -190,7 +144,7 @@ export default class DependenceService {
: unInstallDependenceCommandTypes
)[dependencies[0].type as any];
const actionText = isInstall ? '安装' : '删除';
const depIds = dependencies.map((x) => x._id) as string[];
const depIds = dependencies.map((x) => x.id) as number[];
const cp = spawn(`${depRunCommand} ${depNames}`, { shell: '/bin/bash' });
const startTime = Date.now();
this.sockService.sendMessage({
@@ -263,14 +217,8 @@ export default class DependenceService {
? DependenceStatus.installFailed
: DependenceStatus.removeFailed;
}
this.dependenceDb.update(
{ _id: { $in: depIds } },
{
$set: { status },
$unset: { pid: true },
},
{ multi: true },
);
DependenceModel.update({ status }, { where: { id: depIds } });
// 如果删除依赖成功,3秒后删除数据库记录
if (isSucceed && !isInstall) {
+51 -106
View File
@@ -4,14 +4,12 @@ import { getFileContentByName } from '../config/util';
import config from '../config';
import * as fs from 'fs';
import DataStore from 'nedb';
import { Env, EnvStatus, initEnvPosition } from '../data/env';
import { Env, EnvModel, EnvStatus, initEnvPosition } from '../data/env';
import _ from 'lodash';
import { dbs } from '../loaders/db';
import { Op } from 'sequelize';
@Service()
export default class EnvService {
private envDb = dbs.envDb;
constructor(@Inject('logger') private logger: winston.Logger) {}
public async create(payloads: Env[]): Promise<Env[]> {
@@ -31,20 +29,13 @@ export default class EnvService {
}
public async insert(payloads: Env[]): Promise<Env[]> {
return new Promise((resolve) => {
this.envDb.insert(payloads, (err, docs) => {
if (err) {
this.logger.error(err);
} else {
resolve(docs);
}
});
});
const docs = await EnvModel.bulkCreate(payloads);
return docs;
}
public async update(payload: Env): Promise<Env> {
const { _id, ...other } = payload;
const doc = await this.get(_id);
const { id, ...other } = payload;
const doc = await this.get(id as number);
const tab = new Env({ ...doc, ...other });
const newDoc = await this.updateDb(tab);
await this.set_envs();
@@ -52,33 +43,19 @@ export default class EnvService {
}
private async updateDb(payload: Env): Promise<Env> {
return new Promise((resolve) => {
this.envDb.update(
{ _id: payload._id },
payload,
{ returnUpdatedDocs: true },
(err, num, doc) => {
if (err) {
this.logger.error(err);
} else {
resolve(doc as Env);
}
},
);
});
const [, docs] = await EnvModel.update(
{ ...payload },
{ where: { id: payload.id } },
);
return docs[0];
}
public async remove(ids: string[]) {
return new Promise((resolve: any) => {
this.envDb.remove({ _id: { $in: ids } }, { multi: true }, async (err) => {
await this.set_envs();
resolve();
});
});
await EnvModel.destroy({ where: { id: ids } });
}
public async move(
_id: string,
id: number,
{
fromIndex,
toIndex,
@@ -100,7 +77,7 @@ export default class EnvService {
: (envs[toIndex].position + envs[toIndex + 1].position) / 2;
}
const newDoc = await this.update({
_id,
id,
position: targetPosition,
});
return newDoc;
@@ -114,104 +91,72 @@ export default class EnvService {
let condition = { ...query };
if (searchText) {
const encodeText = encodeURIComponent(searchText);
const reg = new RegExp(`${searchText}|${encodeText}`, 'i');
const reg = {
[Op.or]: [
{ [Op.like]: `%${searchText}&` },
{ [Op.like]: `%${encodeText}%` },
],
};
condition = {
$or: [
{
value: reg,
},
...condition,
[Op.or]: [
{
name: reg,
},
{
remarks: reg,
command: reg,
},
{
schedule: reg,
},
],
};
}
const newDocs = await this.find(condition, sort);
return newDocs;
try {
const result = await this.find(condition);
return result as any;
} catch (error) {
throw error;
}
}
private async find(query: any, sort: any): Promise<Env[]> {
return new Promise((resolve) => {
this.envDb
.find(query)
.sort({ ...sort })
.exec((err, docs) => {
resolve(docs);
});
});
private async find(query: any, sort?: any): Promise<Env[]> {
const docs = await EnvModel.findAll({ where: { ...query } });
return docs;
}
public async get(_id: string): Promise<Env> {
return new Promise((resolve) => {
this.envDb.find({ _id }).exec((err, docs) => {
resolve(docs[0]);
});
});
}
public async getBySort(sort: any): Promise<Env> {
return new Promise((resolve) => {
this.envDb
.find({})
.sort({ ...sort })
.limit(1)
.exec((err, docs) => {
resolve(docs[0]);
});
});
public async get(id: number): Promise<Env> {
const docs = await EnvModel.findAll({ where: { id } });
return docs[0];
}
public async disabled(ids: string[]) {
return new Promise((resolve: any) => {
this.envDb.update(
{ _id: { $in: ids } },
{ $set: { status: EnvStatus.disabled } },
{ multi: true },
async (err) => {
await this.set_envs();
resolve();
},
);
});
const [, docs] = await EnvModel.update(
{ status: EnvStatus.disabled },
{ where: { id: ids } },
);
await this.set_envs();
}
public async enabled(ids: string[]) {
return new Promise((resolve: any) => {
this.envDb.update(
{ _id: { $in: ids } },
{ $set: { status: EnvStatus.normal } },
{ multi: true },
async (err, num) => {
await this.set_envs();
resolve();
},
);
});
const [, docs] = await EnvModel.update(
{ status: EnvStatus.normal },
{ where: { id: ids } },
);
await this.set_envs();
}
public async updateNames({ ids, name }: { ids: string[]; name: string }) {
return new Promise((resolve: any) => {
this.envDb.update(
{ _id: { $in: ids } },
{ $set: { name } },
{ multi: true },
async (err, num) => {
await this.set_envs();
resolve();
},
);
});
const [, docs] = await EnvModel.update({ name }, { where: { id: ids } });
await this.set_envs();
}
public async set_envs() {
const envs = await this.envs(
'',
{ position: -1 },
{ name: { $exists: true } },
{ name: { [Op.not]: null } },
);
const groups = _.groupBy(envs, 'name');
let env_string = '';
+64 -95
View File
@@ -3,29 +3,23 @@ import winston from 'winston';
import { createRandomString } from '../config/util';
import config from '../config';
import DataStore from 'nedb';
import { App } from '../data/open';
import { App, AppModel } from '../data/open';
import { v4 as uuidV4 } from 'uuid';
import { dbs } from '../loaders/db';
import sequelize, { Op } from 'sequelize';
@Service()
export default class OpenService {
private appDb = dbs.appDb;
constructor(@Inject('logger') private logger: winston.Logger) {}
public async findTokenByValue(token: string): Promise<App> {
return new Promise((resolve) => {
this.appDb.find(
{ tokens: { $elemMatch: { value: token } } },
(err, docs) => {
if (err) {
this.logger.error(err);
} else {
resolve(docs[0]);
}
},
);
public async findTokenByValue(token: string): Promise<App | null> {
const doc = await AppModel.findOne({
where: sequelize.fn(
'JSON_CONTAINS',
sequelize.col('tokens'),
JSON.stringify({ value: token }),
),
});
return doc;
}
public async create(payload: App): Promise<App> {
@@ -37,52 +31,32 @@ export default class OpenService {
}
public async insert(payloads: App[]): Promise<App[]> {
return new Promise((resolve) => {
this.appDb.insert(payloads, (err, docs) => {
if (err) {
this.logger.error(err);
} else {
resolve(docs);
}
});
});
const docs = await AppModel.bulkCreate(payloads);
return docs;
}
public async update(payload: App): Promise<App> {
const { _id, client_id, client_secret, tokens, ...other } = payload;
const doc = await this.get(_id);
const { id, client_id, client_secret, tokens, ...other } = payload;
const doc = await this.get(id);
const tab = new App({ ...doc, ...other });
const newDoc = await this.updateDb(tab);
return { ...newDoc, tokens: [] };
}
private async updateDb(payload: App): Promise<App> {
return new Promise((resolve) => {
this.appDb.update(
{ _id: payload._id },
payload,
{ returnUpdatedDocs: true },
(err, num, doc, up) => {
if (err) {
this.logger.error(err);
} else {
resolve(doc);
}
},
);
});
const [, docs] = await AppModel.update(
{ ...payload },
{ where: { id: payload.id } },
);
return docs[0];
}
public async remove(ids: string[]) {
return new Promise((resolve: any) => {
this.appDb.remove({ _id: { $in: ids } }, { multi: true }, async (err) => {
resolve();
});
});
public async remove(ids: number[]) {
await AppModel.destroy({ where: { id: ids } });
}
public async resetSecret(_id: string): Promise<App> {
const doc = await this.get(_id);
public async resetSecret(id: number): Promise<App> {
const doc = await this.get(id);
const tab = new App({ ...doc });
tab.client_secret = createRandomString(24, 24);
tab.tokens = [];
@@ -98,43 +72,44 @@ export default class OpenService {
let condition = { ...query };
if (searchText) {
const encodeText = encodeURIComponent(searchText);
const reg = new RegExp(`${searchText}|${encodeText}`, 'i');
const reg = {
[Op.or]: [
{ [Op.like]: `%${searchText}&` },
{ [Op.like]: `%${encodeText}%` },
],
};
condition = {
$or: [
{
value: reg,
},
...condition,
[Op.or]: [
{
name: reg,
},
{
remarks: reg,
command: reg,
},
{
schedule: reg,
},
],
};
}
const newDocs = await this.find(condition, sort);
return newDocs.map((x) => ({ ...x, tokens: [] }));
try {
const result = await this.find(condition);
return result.map((x) => ({ ...x, tokens: [] }));
} catch (error) {
throw error;
}
}
private async find(query: any, sort: any): Promise<App[]> {
return new Promise((resolve) => {
this.appDb
.find(query)
.sort({ ...sort })
.exec((err, docs) => {
resolve(docs);
});
});
private async find(query: any, sort?: any): Promise<App[]> {
const docs = await AppModel.findAll({ where: { ...query } });
return docs;
}
public async get(_id: string): Promise<App> {
return new Promise((resolve) => {
this.appDb.find({ _id }).exec((err, docs) => {
resolve(docs[0]);
});
});
public async get(id: number): Promise<App> {
const docs = await AppModel.findAll({ where: { id } });
return docs[0];
}
public async authToken({
@@ -146,28 +121,22 @@ export default class OpenService {
}): Promise<any> {
const token = uuidV4();
const expiration = Math.round(Date.now() / 1000) + 2592000; // 2592000 30天
return new Promise((resolve) => {
this.appDb.find({ client_id, client_secret }).exec((err, docs) => {
if (docs && docs[0]) {
this.appDb.update(
{ client_id, client_secret },
{ $push: { tokens: { value: token, expiration } } },
{},
(err, num, doc) => {
resolve({
code: 200,
data: {
token,
token_type: 'Bearer',
expiration,
},
});
},
);
} else {
resolve({ code: 400, message: 'client_id或client_seret有误' });
}
});
});
const doc = await AppModel.findOne({ where: { client_id, client_secret } });
if (doc) {
const [, docs] = await AppModel.update(
{ tokens: [...(doc.tokens || []), { value: token, expiration }] },
{ where: { client_id, client_secret } },
);
return {
code: 200,
data: {
token,
token_type: 'Bearer',
expiration,
},
};
} else {
return { code: 400, message: 'client_id或client_seret有误' };
}
}
}
+7 -7
View File
@@ -6,22 +6,22 @@ import { exec } from 'child_process';
@Service()
export default class ScheduleService {
private scheduleStacks = new Map<string, nodeSchedule.Job>();
private scheduleStacks = new Map<number, nodeSchedule.Job>();
constructor(@Inject('logger') private logger: winston.Logger) {}
async generateSchedule({ _id = '', command, name, schedule }: Crontab) {
async generateSchedule({ id = 0, command, name, schedule }: Crontab) {
this.logger.info(
'[创建定时任务],任务ID: %scron: %s,任务名: %s,执行命令: %s',
_id,
id,
schedule,
name,
command,
);
this.scheduleStacks.set(
_id,
nodeSchedule.scheduleJob(_id, schedule, async () => {
id,
nodeSchedule.scheduleJob(id + '', schedule, async () => {
try {
exec(command, async (error, stdout, stderr) => {
if (error) {
@@ -55,8 +55,8 @@ export default class ScheduleService {
);
}
async cancelSchedule({ _id = '', name }: Crontab) {
async cancelSchedule({ id = 0, name }: Crontab) {
this.logger.info('[取消定时任务],任务名:%s', name);
this.scheduleStacks.has(_id) && this.scheduleStacks.get(_id)?.cancel();
this.scheduleStacks.has(id) && this.scheduleStacks.get(id)?.cancel();
}
}
+8 -27
View File
@@ -3,7 +3,7 @@ import winston from 'winston';
import config from '../config';
import * as fs from 'fs';
import _ from 'lodash';
import { AuthDataType, AuthInfo, LoginStatus } from '../data/auth';
import { AuthDataType, AuthInfo, AuthModel, LoginStatus } from '../data/auth';
import { NotificationInfo } from '../data/notify';
import NotificationService from './notify';
import ScheduleService from './schedule';
@@ -16,7 +16,6 @@ import { dbs } from '../loaders/db';
export default class SystemService {
@Inject((type) => NotificationService)
private notificationService!: NotificationService;
private authDb = dbs.authDb;
constructor(
@Inject('logger') private logger: winston.Logger,
@@ -25,34 +24,16 @@ export default class SystemService {
) {}
public async getLogRemoveFrequency() {
return new Promise((resolve) => {
this.authDb
.find({ type: AuthDataType.removeLogFrequency })
.exec((err, docs) => {
if (err || docs.length === 0) {
resolve({});
} else {
resolve(docs[0].info);
}
});
const doc = await AuthModel.findOne({
where: { type: AuthDataType.removeLogFrequency },
});
return (doc && doc.info) || {};
}
private async updateAuthDb(payload: AuthInfo): Promise<any> {
return new Promise((resolve) => {
this.authDb.update(
{ type: payload.type },
{ ...payload },
{ upsert: true, returnUpdatedDocs: true },
(err, num, doc: any) => {
if (err) {
resolve({} as NotificationInfo);
} else {
resolve({ ...doc.info, _id: doc._id });
}
},
);
});
await AuthModel.upsert({ ...payload });
const doc = await AuthModel.findOne({ where: { type: payload.type } });
return doc;
}
public async updateNotificationMode(notificationInfo: NotificationInfo) {
@@ -79,7 +60,7 @@ export default class SystemService {
info: { frequency },
});
const cron = {
_id: result._id,
id: result.id,
name: '删除日志',
command: `ql rmlog ${frequency}`,
schedule: `5 23 */${frequency} * *`,
+25 -62
View File
@@ -6,8 +6,7 @@ import * as fs from 'fs';
import _ from 'lodash';
import jwt from 'jsonwebtoken';
import { authenticator } from '@otplib/preset-default';
import DataStore from 'nedb';
import { AuthDataType, AuthInfo, LoginStatus } from '../data/auth';
import { AuthDataType, AuthInfo, AuthModel, LoginStatus } from '../data/auth';
import { NotificationInfo } from '../data/notify';
import NotificationService from './notify';
import { Request } from 'express';
@@ -15,13 +14,11 @@ import ScheduleService from './schedule';
import { spawn } from 'child_process';
import SockService from './sock';
import got from 'got';
import { dbs } from '../loaders/db';
@Service()
export default class UserService {
@Inject((type) => NotificationService)
private notificationService!: NotificationService;
private authDb = dbs.authDb;
constructor(
@Inject('logger') private logger: winston.Logger,
@@ -174,33 +171,24 @@ export default class UserService {
}
public async getLoginLog(): Promise<AuthInfo[]> {
return new Promise((resolve) => {
this.authDb.find({ type: AuthDataType.loginLog }).exec((err, docs) => {
if (err || docs.length === 0) {
resolve([]);
} else {
const result = docs.sort(
(a, b) => b.info.timestamp - a.info.timestamp,
);
if (result.length > 100) {
this.authDb.remove({ _id: result[result.length - 1]._id });
}
resolve(result.map((x) => x.info));
}
});
const docs = await AuthModel.findAll({
where: { type: AuthDataType.loginLog },
});
if (docs && docs.length > 0) {
const result = docs.sort((a, b) => b.info.timestamp - a.info.timestamp);
if (result.length > 100) {
await AuthModel.destroy({
where: { id: result[result.length - 1].id },
});
}
return result.map((x) => x.info);
}
return [];
}
private async insertDb(payload: AuthInfo): Promise<AuthInfo> {
return new Promise((resolve) => {
this.authDb.insert(payload, (err, doc) => {
if (err) {
this.logger.error(err);
} else {
resolve(doc);
}
});
});
const doc = await AuthModel.create({ ...payload }, { returning: true });
return doc;
}
private initAuthInfo() {
@@ -315,48 +303,23 @@ export default class UserService {
}
public async getNotificationMode(): Promise<NotificationInfo> {
return new Promise((resolve) => {
this.authDb
.find({ type: AuthDataType.notification })
.exec((err, docs) => {
if (err || docs.length === 0) {
resolve({} as NotificationInfo);
} else {
resolve(docs[0].info);
}
});
const doc = await AuthModel.findOne({
where: { type: AuthDataType.notification },
});
return (doc && doc.info) || {};
}
public async getLogRemoveFrequency() {
return new Promise((resolve) => {
this.authDb
.find({ type: AuthDataType.removeLogFrequency })
.exec((err, docs) => {
if (err || docs.length === 0) {
resolve({});
} else {
resolve(docs[0].info);
}
});
const doc = await AuthModel.findOne({
where: { type: AuthDataType.removeLogFrequency },
});
return (doc && doc.info) || {};
}
private async updateAuthDb(payload: AuthInfo): Promise<any> {
return new Promise((resolve) => {
this.authDb.update(
{ type: payload.type },
{ ...payload },
{ upsert: true, returnUpdatedDocs: true },
(err, num, doc: any) => {
if (err) {
resolve({} as NotificationInfo);
} else {
resolve({ ...doc.info, _id: doc._id });
}
},
);
});
await AuthModel.upsert({ ...payload });
const doc = await AuthModel.findOne({ where: { type: payload.type } });
return doc;
}
public async updateNotificationMode(notificationInfo: NotificationInfo) {
@@ -383,7 +346,7 @@ export default class UserService {
info: { frequency },
});
const cron = {
_id: result._id,
id: result.id,
name: '删除日志',
command: `ql rmlog ${frequency}`,
schedule: `5 23 */${frequency} * *`,