Compare commits

..

6 Commits

Author SHA1 Message Date
whyour 3987ef8d97 更新版本 v2.15.20 2023-07-24 22:02:33 +08:00
whyour 8b0dedaf8c 修复 linux 依赖是否存在判断 2023-07-24 22:02:26 +08:00
whyour 04edd97967 修复 node 依赖匹配判断 2023-07-21 21:22:48 +08:00
whyour 6131fe0110 更新版本 v2.15.19 2023-07-20 23:14:16 +08:00
whyour 665c344ae4 修复依赖是否已经安装判断 2023-07-20 22:54:11 +08:00
雨思 373b8c97d7 增加PushMe消息通道 (#2018),修复系统设置保存通知 2023-07-20 13:19:39 +08:00
17 changed files with 150 additions and 31 deletions
+3
View File
@@ -20,6 +20,7 @@ const rootPath = process.env.QL_DIR as string;
const envFound = dotenv.config({ path: path.join(rootPath, '.env') });
const dataPath = path.join(rootPath, 'data/');
const shellPath = path.join(rootPath, 'shell/');
const tmpPath = path.join(rootPath, '.tmp/');
const samplePath = path.join(rootPath, 'sample/');
const configPath = path.join(dataPath, 'config/');
@@ -44,6 +45,7 @@ const loginFaild = '请先登录!';
const configString = 'config sample crontab shareCode diy';
const versionFile = path.join(rootPath, 'version.yaml');
const dataTgzFile = path.join(tmpPath, 'data.tgz');
const shareShellFile = path.join(shellPath, 'share.sh');
if (envFound.error) {
throw new Error("⚠️ Couldn't find .env file ⚠️");
@@ -64,6 +66,7 @@ export default {
tmpPath,
dataPath,
dataTgzFile,
shareShellFile,
configString,
loginFaild,
authError,
+3 -3
View File
@@ -43,13 +43,13 @@ export enum DependenceTypes {
export enum InstallDependenceCommandTypes {
'pnpm add -g',
'pip3 install --disable-pip-version-check --root-user-action=ignore',
'apk add',
'apk add --no-check-certificate',
}
export enum GetDependenceCommandTypes {
'pnpm ls -g ',
'pip3 list --disable-pip-version-check',
'apk info',
'pip3 show --disable-pip-version-check',
'apk info -es',
}
export enum versionDependenceCommandTypes {
+6
View File
@@ -15,6 +15,7 @@ export enum NotificationMode {
'iGot' = 'iGot',
'pushPlus' = 'pushPlus',
'email' = 'email',
'pushMe' = 'pushMe',
'feishu' = 'feishu',
'webhook' = 'webhook',
}
@@ -101,6 +102,10 @@ export class EmailNotification extends NotificationBaseInfo {
public emailPass: string = '';
}
export class PushMeNotification extends NotificationBaseInfo {
public pushMeKey: string = '';
}
export class WebhookNotification extends NotificationBaseInfo {
public webhookHeaders: string = '';
public webhookBody: string = '';
@@ -131,5 +136,6 @@ export interface NotificationInfo
IGotNotification,
PushPlusNotification,
EmailNotification,
PushMeNotification,
WebhookNotification,
LarkNotification {}
+1 -1
View File
@@ -38,7 +38,7 @@ export default async () => {
// 初始化时安装所有处于安装中,安装成功,安装失败的依赖
DependenceModel.findAll({
where: {},
order: [['type', 'DESC']],
order: [['type', 'DESC'], ['createdAt', 'DESC']],
raw: true,
}).then(async (docs) => {
await DependenceModel.update(
+1 -1
View File
@@ -13,7 +13,7 @@ const client = new HealthClient(
app.get('/api/health', (req, res) => {
client.check({ service: 'cron' }, (err, response) => {
if (err) {
return res.status(500).send({ code: 500, error: err });
return res.status(200).send({ code: 500, error: err });
}
return res.status(200).send({ code: 200, data: response });
});
+27 -10
View File
@@ -23,7 +23,7 @@ export default class DependenceService {
constructor(
@Inject('logger') private logger: winston.Logger,
private sockService: SockService,
) {}
) { }
public async create(payloads: Dependence[]): Promise<Dependence[]> {
const tabs = payloads.map((x) => {
@@ -168,7 +168,7 @@ export default class DependenceService {
const socketMessageType = isInstall
? 'installDependence'
: 'uninstallDependence';
const depName = dependency.name.trim();
let depName = dependency.name.trim();
const depRunCommand = (
isInstall
? InstallDependenceCommandTypes
@@ -191,18 +191,35 @@ export default class DependenceService {
if (isInstall) {
const getCommandPrefix = GetDependenceCommandTypes[dependency.type];
const depVersionStr = versionDependenceCommandTypes[dependency.type];
const [_depName] = dependency.name.trim().split(depVersionStr);
let depVersion = '';
if (depName.includes(depVersionStr)) {
const symbolRegx = new RegExp(`(.*)${depVersionStr}([0-9\\.\\-\\+a-zA-Z]*)`);
const [, _depName, _depVersion] = depName.match(symbolRegx) || [];
if (_depVersion && _depName) {
depName = _depName;
depVersion = _depVersion;
}
}
const isNodeDependence = dependency.type === DependenceTypes.nodejs;
const isLinuxDependence = dependency.type === DependenceTypes.linux;
const isPythonDependence = dependency.type === DependenceTypes.python3;
const depInfo = (
await promiseExecSuccess(
dependency.type === DependenceTypes.linux
? `${getCommandPrefix} ${_depName}`
: `${getCommandPrefix} | grep "${_depName}"`,
isNodeDependence
? `${getCommandPrefix} | grep "${depName}" | head -1`
: `${getCommandPrefix} ${depName}`,
)
).replace(/\s{2,}/, ' ');
).replace(/\s{2,}/, ' ').replace(/\s+$/, '');
if (depInfo) {
if (
depInfo &&
((isNodeDependence && depInfo.split(' ')?.[0] === depName) ||
(isLinuxDependence && depInfo.toLocaleLowerCase().includes('installed')) ||
isPythonDependence) &&
(!depVersion || depInfo.includes(depVersion))
) {
const endTime = dayjs();
const _message = `检测到已经安装 ${_depName}\n\n${depInfo}\n跳过安装\n\n依赖${actionText}成功,结束时间 ${endTime.format(
const _message = `检测到已经安装 ${depName}\n\n${depInfo}\n\n跳过安装\n\n依赖${actionText}成功,结束时间 ${endTime.format(
'YYYY-MM-DD HH:mm:ss',
)},耗时 ${endTime.diff(startTime, 'second')}`;
this.sockService.sendMessage({
@@ -219,7 +236,7 @@ export default class DependenceService {
}
}
const cp = spawn(`${depRunCommand} ${depName}`, {
const cp = spawn(`${depRunCommand} ${dependency.name.trim()}`, {
shell: '/bin/bash',
});
+23
View File
@@ -28,6 +28,7 @@ export default class NotificationService {
['iGot', this.iGot],
['pushPlus', this.pushPlus],
['email', this.email],
['pushMe', this.pushMe],
['webhook', this.webhook],
['lark', this.lark],
]);
@@ -561,6 +562,28 @@ export default class NotificationService {
}
}
private async pushMe() {
const { pushMeKey } = this.params;
try {
const res: any = await got
.post(`https://push.i-i.me/?push_key=${pushMeKey}`, {
...this.gotOption,
json: {
title: this.title,
content: this.content
},
headers: { 'Content-Type': 'application/json' },
});
if (res.body === 'success') {
return true;
} else {
throw new Error(res.body);
}
} catch (error: any) {
throw new Error(error.response ? error.response.body : error);
}
}
private async webhook() {
const {
webhookUrl,
+44
View File
@@ -141,6 +141,11 @@ let SMTP_EMAIL = '';
let SMTP_PASSWORD = '';
let SMTP_NAME = '';
// =======================================PushMe通知设置区域===========================================
//官方文档:https://push.i-i.me/
//此处填你的PushMe KEY.
let PUSHME_KEY = '';
//==========================云端环境变量的判断与接收=========================
if (process.env.GOTIFY_URL) {
GOTIFY_URL = process.env.GOTIFY_URL;
@@ -288,6 +293,9 @@ if (process.env.SMTP_PASSWORD) {
if (process.env.SMTP_NAME) {
SMTP_NAME = process.env.SMTP_NAME;
}
if (process.env.PUSHME_KEY) {
PUSHME_KEY = process.env.PUSHME_KEY;
}
//==========================云端环境变量的判断与接收=========================
/**
@@ -336,6 +344,7 @@ async function sendNotify(
aibotkNotify(text, desp), //智能微秘书
fsBotNotify(text, desp), //飞书机器人
smtpNotify(text, desp), //SMTP 邮件
PushMeNotify(text, desp), //PushMe
]);
}
@@ -1117,6 +1126,41 @@ function smtpNotify(text, desp) {
});
}
function PushMeNotify(text, desp) {
return new Promise((resolve) => {
if (PUSHME_KEY) {
const options = {
url: `https://push.i-i.me?push_key=${PUSHME_KEY}`,
json: { title: text, content: desp },
headers: {
'Content-Type': 'application/json',
},
timeout,
};
$.post(options, (err, resp, data) => {
try {
if (err) {
console.log('PushMeNotify发送通知调用API失败!!\n');
console.log(err);
} else {
if (data === 'success') {
console.log('PushMe发送通知消息成功🎉\n');
} else {
console.log(`${data}\n`);
}
}
} catch (e) {
$.logErr(e, resp);
} finally {
resolve(data);
}
});
} else {
resolve();
}
});
}
module.exports = {
sendNotify,
BARK_PUSH,
+25
View File
@@ -98,6 +98,8 @@ push_config = {
'SMTP_EMAIL': '', # SMTP 收发件邮箱,通知将会由自己发给自己
'SMTP_PASSWORD': '', # SMTP 登录密码,也可能为特殊口令,视具体邮件服务商说明而定
'SMTP_NAME': '', # SMTP 收发件人姓名,可随意填写
'PUSHME_KEY': '', # PushMe 酱的 PUSHME_KEY
}
notify_function = []
# fmt: on
@@ -637,6 +639,27 @@ def smtp(title: str, content: str) -> None:
except Exception as e:
print(f"SMTP 邮件 推送失败!{e}")
def pushme(title: str, content: str) -> None:
"""
使用 PushMe 推送消息。
"""
if not push_config.get("PUSHME_KEY"):
print("PushMe 服务的 PUSHME_KEY 未设置!!\n取消推送")
return
print("PushMe 服务启动")
url = f'https://push.i-i.me/?push_key={push_config.get("PUSHME_KEY")}'
data = {
"title": title,
"content": content,
}
response = requests.post(url, data=data)
if response == 'success':
print("PushMe 推送成功!")
else:
print("PushMe 推送失败!{response}")
def one() -> str:
"""
@@ -692,6 +715,8 @@ if (
and push_config.get("SMTP_NAME")
):
notify_function.append(smtp)
if push_config.get("PUSHME_KEY"):
notify_function.append(pushme)
def send(title: str, content: str) -> None:
-2
View File
@@ -79,8 +79,6 @@ main() {
npm i -g pnpm@8.3.1
patch_version
apk add procps netcat-openbsd
if [[ $PipMirror ]]; then
pip3 config set global.index-url $PipMirror
fi
-1
View File
@@ -314,7 +314,6 @@ reload_pm2() {
unset_proxy
pm2 flush &>/dev/null
pm2 startOrGracefulReload $file_ecosystem_js --update-env
pm2 sendSignal SIGKILL panel &>/dev/null
}
diff_time() {
+1 -1
View File
@@ -290,7 +290,7 @@ const Dependence = () => {
const handleDependence = (dependence: any) => {
const result = [...value];
if (Array.isArray(dependence)) {
result.push(...dependence);
result.unshift(...dependence);
} else {
const index = value.findIndex((x) => x.id === dependence.id);
if (index !== -1) {
+1 -3
View File
@@ -50,9 +50,7 @@ const Initialization = () => {
const submitNotification = (values: any) => {
setLoading(true);
request
.put(`${config.apiPrefix}user/notification/init`, {
values,
})
.put(`${config.apiPrefix}user/notification/init`, values)
.then(({ code, data }) => {
if (code === 200) {
next();
+1 -3
View File
@@ -19,9 +19,7 @@ const NotificationSetting = ({ data }: any) => {
}
request
.put(`${config.apiPrefix}user/notification`, {
values,
})
.put(`${config.apiPrefix}user/notification`, values)
.then(({ code, data }) => {
if (code === 200) {
message.success(values.type ? '通知发送成功' : '通知关闭成功');
+8
View File
@@ -96,6 +96,7 @@ export default {
{ value: 'chat', label: '群晖chat' },
{ value: 'email', label: '邮箱' },
{ value: 'lark', label: '飞书机器人' },
{ value: 'pushMe', label: 'PushMe' },
{ value: 'webhook', label: '自定义通知' },
{ value: 'closed', label: '已关闭' },
],
@@ -268,6 +269,13 @@ export default {
{ label: 'emailUser', tip: '邮箱地址', required: true },
{ label: 'emailPass', tip: '邮箱SMTP授权码', required: true },
],
pushMe: [
{
label: 'pushMeKey',
tip: 'PushMe的Keyhttps://push.i-i.me/',
required: true,
},
],
webhook: [
{
label: 'webhookMethod',
+1
View File
@@ -11,6 +11,7 @@ interface IResponseData {
code?: number;
data?: any;
message?: string;
error?: any;
}
type Override<
+5 -6
View File
@@ -1,7 +1,6 @@
version: 2.15.18
changeLogLink: https://t.me/jiao_long/384
publishTime: 2023-07-19 21:21
version: 2.15.20
changeLogLink: https://t.me/jiao_long/386
publishTime: 2023-07-22 16:00
changeLog: |
1. 增加备份恢复功能
2. 重构系统检查更新逻辑
3. 修复系统设置自动删除日志启动时失效
1. 修复判断 linux 依赖已安装逻辑
2. 修复未启动完成时,页面提示 500