-
Notifications
You must be signed in to change notification settings - Fork 163
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
20 changed files
with
4,081 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
"20220524211519" |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
data |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
FROM node:16-alpine3.15 | ||
|
||
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories | ||
RUN sed -i 's/dl-4.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories | ||
|
||
RUN apk add --no-cache chromium | ||
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD true | ||
ENV CHROMIUM_PATH /usr/bin/chromium-browser | ||
COPY SourceHanSans.ttf /usr/share/fonts/TTF/SourceHanSans.ttf | ||
|
||
# 测试时注释掉下一行 | ||
COPY api /api | ||
|
||
COPY init.sh /init.sh | ||
RUN chmod +x /init.sh | ||
EXPOSE 80 | ||
|
||
RUN echo '* * * * * /usr/local/bin/node /api/cron.js > /data/cron.txt' > /etc/crontabs/root | ||
|
||
|
||
ENTRYPOINT ["/bin/sh", "/init.sh"] | ||
# ENTRYPOINT ["crond", "-l 2", "-f"] |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
const { monitor_auto, send_notify, get_data_dir, get_cookies, to_time_string, logstart, logit } = require("./func"); | ||
const express = require('express'); | ||
const path = require('path'); | ||
const fs = require('fs'); | ||
const ip = require('ip'); | ||
const app = express(); | ||
|
||
const cors = require('cors'); | ||
app.use(cors()); | ||
|
||
var multer = require('multer'); | ||
var forms = multer(); | ||
const bodyParser = require('body-parser') | ||
app.use(bodyParser.json()); | ||
app.use(forms.array()); | ||
app.use(bodyParser.urlencoded({ extended: true })); | ||
|
||
const image_dir = get_data_dir()+'/image'; | ||
if( !fs.existsSync(image_dir )) fs.mkdirSync(image_dir); | ||
|
||
app.use('/image', express.static(image_dir)); | ||
|
||
|
||
function checkApiKey (req, res, next) { | ||
|
||
if( process.env.API_KEY && process.env.API_KEY != ( req.query.key||req.body.key )) | ||
return res.json({"code":403,"message":"错误的API KEY"}); | ||
|
||
next(); | ||
} | ||
|
||
|
||
app.all(`/`, checkApiKey , (req, res) => { | ||
let data_write_access = true; | ||
try { | ||
fs.accessSync(get_data_dir(),fs.constants.W_OK); | ||
} catch (error) { | ||
data_write_access = false; | ||
} | ||
|
||
// res.json({"code":0,"message":"it works","version":"1.0","ip":ip.address(),data_write_access}); | ||
// 不再显示IP,以免误导 | ||
res.json({"code":0,"message":"it works","version":"1.0",data_write_access}); | ||
}); | ||
|
||
app.post(`/checks/upload`, checkApiKey , (req, res) => { | ||
const data = { checks: JSON.parse(req.body.checks)||[], cookies: JSON.parse(req.body.cookies) ||{} }; | ||
const data_file = get_data_dir()+'/data.json'; | ||
try { | ||
let cloud_checks = []; | ||
if( fs.existsSync( data_file ) ) | ||
{ | ||
// 如果存在旧数据 | ||
const old_data = JSON.parse(fs.readFileSync( data_file, 'utf8' )); | ||
|
||
if( old_data ) | ||
{ | ||
cloud_checks = old_data.checks.filter( item => item.is_cloud_task == 1 ); | ||
|
||
for( const check of cloud_checks ) | ||
{ | ||
const the_idx = data.checks.findIndex(item => item.id == check.id); | ||
|
||
// console.log(to_time_string( data.checks[the_idx]['last_time'] ) + '~' + to_time_string( check.last_time )); | ||
|
||
if( the_idx >= 0 && data.checks[the_idx]['last_time'] < check.last_time ) | ||
{ | ||
console.log("new", check.title, check.last_time); | ||
data.checks[the_idx]['last_content'] = check['last_content']; | ||
data.checks[the_idx]['last_time'] = check['last_time']; | ||
} | ||
} | ||
cloud_checks = data.checks.filter( item => item.is_cloud_task == 1 ); | ||
// console.log( cloud_checks ); | ||
|
||
} | ||
// if( old_data ) cloud_checks = old_data.checks.filter( item => item.is_cloud_task == 1 ); | ||
} | ||
|
||
fs.writeFileSync( data_file , JSON.stringify(data) ); | ||
if( fs.existsSync( data_file ) ) | ||
res.json({"code":0,"message":"设置已同步到自架服务",cloud_checks}); | ||
else | ||
res.json({"code":501,"message":"设置保存失败"}); | ||
} catch (error) { | ||
res.json({"code":500,"message":error}); | ||
} | ||
|
||
}); | ||
|
||
app.post(`/monitor`, checkApiKey , async (req, res) => { | ||
const item = JSON.parse(req.body.item); | ||
// cookie改为从请求获取,以确保最新 | ||
const cookies = req.body?.cookies ? JSON.parse(req.body.cookies) : get_cookies(); | ||
if( !item ) return res.json({"code":500,"message":"item格式不正确"}); | ||
const ret = await monitor_auto( item, cookies ); | ||
console.log( ret ); | ||
return res.json(ret); | ||
|
||
}); | ||
|
||
app.all(`/log`, checkApiKey , (req, res) => { | ||
const log_file = get_data_dir()+'/log.txt'; | ||
const log = fs.existsSync( log_file ) ? fs.readFileSync( log_file, 'utf8' ): ""; | ||
res.json({"code":0,"log":log}); | ||
}); | ||
|
||
// Error handler | ||
app.use(function (err, req, res, next) { | ||
console.error(err); | ||
res.status(500).send('Internal Serverless Error'); | ||
}); | ||
|
||
app.listen(80, () => { | ||
console.log(`Server start on http://localhost`); | ||
}); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
const fs = require("fs"); | ||
const dayjs = require("dayjs"); | ||
const { monitor_auto, send_notify, get_data_dir, cron_check, logstart, logit } = require("./func"); | ||
|
||
const data_file = get_data_dir() + 'data.json'; | ||
const content = fs.readFileSync( data_file ); | ||
const json_data = JSON.parse( content ); | ||
|
||
const to_checks = json_data.checks.filter( item => parseInt(item.enabled) === 1 && parseInt(item.is_cloud_task||0) >= 1 ); | ||
|
||
run = async () =>{ | ||
logstart(); | ||
logit("开始载入任务"); | ||
for( const item of to_checks ) | ||
{ | ||
let do_now = false; | ||
if( parseInt( item.interval ) < 1 ) item.interval = 10; | ||
|
||
// 判断是否应该监测 | ||
if( item.last_time ) | ||
{ | ||
if( item.interval > 0 ) | ||
{ | ||
if(dayjs(item.last_time).add(item.interval,'minutes').isBefore(dayjs())) do_now = true; | ||
} | ||
}else | ||
{ | ||
do_now = true; | ||
} | ||
|
||
// 处理cron逻辑 | ||
if( item.cron && !cron_check(item.cron) ) | ||
{ | ||
do_now = false; | ||
console.log("监测时间监测,跳过"+item.cron); | ||
} | ||
|
||
// 处理retry | ||
if( parseInt(item.retry) < 1 ) item.retry = 10; | ||
if( parseInt(item.retry_times) > parseInt(item.retry) ) | ||
{ | ||
do_now = false; | ||
logit("重试次数超过,跳过"+item.title); | ||
} | ||
logit( item.title + "...条件检查 " +do_now ); | ||
if( do_now ) | ||
{ | ||
// 返回状态,默认为成功 | ||
// 0:未检测,1:成功但没有变动,2:成功且有异动 | ||
let check_status = 0; | ||
let check_content = ""; | ||
|
||
logit("checking..."+item.title, dayjs().format('YYYY-MM-DD HH:mm:ss')); | ||
|
||
const ret = await monitor_auto( item, json_data.cookies ); | ||
if( ret && ret.status ) | ||
{ | ||
check_content = ret.value; | ||
check_status = 1; | ||
|
||
} | ||
else | ||
check_status = -1; | ||
|
||
logit( ret ); | ||
|
||
if( check_status < 0 ) | ||
{ | ||
// 失败 | ||
// 重试流程 | ||
const retry_times = parseInt( item.retry_times||0 ); | ||
if( retry_times >= item.retry ) | ||
{ | ||
// 发送通知 | ||
await send_notify( '监测点['+item.title+']多次重试失败', "已暂停执行,请检查登录状态或页面结构变动\r\n\r\n[点此查看]("+item.url+")" , item.sendkey); | ||
} | ||
check_update_field( item.id, 'retry_times', retry_times+1, json_data ); | ||
|
||
}else | ||
{ | ||
// 成功分支 | ||
const last_content = item.last_content; | ||
|
||
// 先更新再发通知,避免发送操作中断 | ||
check_update_field( item.id, 'last_content', check_content, json_data ); | ||
check_update_field( item.id, 'last_time', Date.now(), json_data ); | ||
|
||
// 重试计数清理 | ||
check_update_field( item.id, 'retry_times', 0, json_data); | ||
|
||
let can_send_notice = true; | ||
|
||
if( item.when == 'change' ) | ||
{ | ||
if( check_content.trim() == last_content.trim() )can_send_notice = false; | ||
}else | ||
{ | ||
if( item.compare_type == 'regex' ) | ||
{ | ||
if( item.regex && !check_content.match( new RegExp(item.regex, 'i') ) ) | ||
{ | ||
can_send_notice = false; | ||
logit( '通知正则不匹配,不发送异动通知' ); | ||
} | ||
} | ||
|
||
if( item.compare_type == 'op' ) | ||
{ | ||
let the_value = item.compare_value; | ||
|
||
if( item.compare_value == '*请求返回状态码*' ) the_value = item.code; | ||
|
||
if( item.compare_value == '*上次监测返回值*' ) the_value = last_content; | ||
|
||
|
||
if( item.compare_op == 'ne' && !(check_content != the_value)) can_send_notice = false; | ||
|
||
if( item.compare_op == 'eq' && !(check_content == the_value)) can_send_notice = false; | ||
|
||
if( item.compare_op == 'gt' && !(parseFloat(check_content) > parseFloat(the_value)||0)) can_send_notice = false; | ||
|
||
if( item.compare_op == 'gte' && !(parseFloat(check_content) >= parseFloat(the_value)||0)) can_send_notice = false; | ||
|
||
if( item.compare_op == 'lt' && !(parseFloat(check_content) < parseFloat(the_value)||0)) can_send_notice = false; | ||
|
||
if( item.compare_op == 'lte' && !(parseFloat(check_content) <= parseFloat(the_value)||0)) can_send_notice = false; | ||
|
||
console.log("op:",check_content,item.compare_op,the_value,can_send_notice); | ||
|
||
} | ||
} | ||
|
||
|
||
|
||
if( can_send_notice ) | ||
{ | ||
logit( '已发送通知' ); | ||
|
||
if( item.sendkey ) | ||
{ | ||
await send_notify( '监测点['+item.title+']有新的通知', check_content + (last_content ? ( '←' + last_content) : "") + "\r\n\r\n[去看看]("+item.url+")" , item.sendkey); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
logit("全部任务处理完成"); | ||
|
||
} | ||
|
||
run(); | ||
|
||
|
||
|
||
async function check_update_field( id, field, value, json_data ) | ||
{ | ||
const the_idx = json_data.checks.findIndex(item => item.id == id); | ||
if( the_idx < 0 ) return false; | ||
json_data.checks[the_idx][field] = value; | ||
fs.writeFileSync( data_file, JSON.stringify(json_data) ); | ||
} |
Oops, something went wrong.
8e7d21f
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
checkchan-dist – ./
ckc.ftqq.com
checkchan-dist-git-main-morexmore.vercel.app
checkchan-dist-morexmore.vercel.app