6 Commits
Author SHA1 Message Date
mei 3831950780 feat(drivers/fwalert): - 新增饭碗警告
- 将 msg 移入饭碗警告body中
2026-08-02 20:53:39 +08:00
mei 9220cf82aa feat(drivers): 饭碗警告(WIP) 2026-07-29 11:24:23 +08:00
mei 4a61527952 update: README 2026-07-28 22:46:51 +08:00
mei 48bb6b8864 fix(workflows) 2026-07-28 22:16:26 +08:00
mei 58b30fa41a update(tests) 2026-07-28 22:13:08 +08:00
mei 2d73157a60 feat(workflows): check 2026-07-28 22:12:17 +08:00
10 changed files with 208 additions and 18 deletions
+34
View File
@@ -0,0 +1,34 @@
name: Quality check
on:
push:
branches:
- "*"
pull_request:
permissions:
contents: read
jobs:
web-ui:
name: Web UI
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '22'
cache: npm
cache-dependency-path: web/frontend/package-lock.json
- name: Install dependencies
run: npm ci
working-directory: web/frontend
- name: Build
run: npm run build
working-directory: web/frontend
+11 -16
View File
@@ -1,9 +1,14 @@
# goodBaby v2 # goodBaby v2
摇篮系统 —— 为独居青年准备的「死人开关」(Dead Man's Switch)。 ![GitHub go.mod Go version (subdirectory of monorepo)](https://img.shields.io/github/go-mod/go-version/ssdomei232/goodBaby)
![GitHub](https://img.shields.io/github/license/ssdomei232/goodBaby)
![GitHub tag (with filter)](https://img.shields.io/github/v/tag/ssdomei232/goodBaby)
一个人在大城市生活,最怕的是出了事都没人知道。goodBaby 让你定期回来报一声平安;一旦超过设定的期限没有签到,它就会替你把预先托付的留言送出去:给家人的邮件、给朋友的 QQ / 钉钉消息、一条 B 站动态,或是公开你的 GitHub 仓库,把作品留给世界。 根据《中国心血管健康与疾病报告2023》,中国 每年 猝死总人数(含心源性和非心源性)或达80万-100万,18-35岁人群占比为38%,也就是说,每天18-35岁人群有近1000人猝死
伴随着中国人口老龄化加剧,年轻人的牵挂越来越多,面对着可能的猝死,我们或许真的需要做好准备
所以我写了goodBaby来解决这个问题,他和apple app store里的“死了么”形式上有些接近,不过goodBaby支持了更多好玩的通知方式,比如bilibili动态,github仓库,邮件,OneBot,还可以方便的自托管
[![通过雨云一键部署](https://rainyun-apps.cn-nb1.rains3.com/materials/deploy-on-rainyun-cn.svg)](https://app.rainyun.com/apps/rca/store/7125/cat_) [![通过雨云一键部署](https://rainyun-apps.cn-nb1.rains3.com/materials/deploy-on-rainyun-cn.svg)](https://app.rainyun.com/apps/rca/store/7125/cat_)
## 功能 ## 功能
@@ -39,12 +44,10 @@ docker compose up -d
docker run -d --name goodbaby -p 8088:8088 -v ./data:/app/data ghcr.io/ssdomei232/goodbaby:latest docker run -d --name goodbaby -p 8088:8088 -v ./data:/app/data ghcr.io/ssdomei232/goodbaby:latest
``` ```
可用标签:`latest`、`v2.2.0`(完整版本)、`2.2`(次版本)、`2`(主版本)。
### 下载预编译二进制 ### 下载预编译二进制
[Releases](https://github.com/ssdomei232/goodBaby/releases) 提供 Linux / Windows / macOS 的 amd64 与 arm64 产物, [Releases](https://github.com/ssdomei232/goodBaby/releases) 提供 Linux / Windows / macOS 的 amd64 与 arm64 产物,
解压后直接运行即可(前端已内嵌,无需额外部署)。压缩包旁的 `checksums.txt` 可校验完整性: 解压后直接运行即可。压缩包旁的 `checksums.txt` 可校验完整性:
```bash ```bash
sha256sum -c checksums.txt --ignore-missing sha256sum -c checksums.txt --ignore-missing
@@ -55,7 +58,7 @@ sha256sum -c checksums.txt --ignore-missing
需要 Go 1.25+ 与 Node.js 20+: 需要 Go 1.25+ 与 Node.js 20+:
```bash ```bash
# 1. 构建前端(产物输出到 web/dist,会被 go:embed 打进二进制) # 1. 构建前端
cd web/frontend && npm install && npm run build && cd ../.. cd web/frontend && npm install && npm run build && cd ../..
# 2. 构建后端 # 2. 构建后端
@@ -97,16 +100,7 @@ cd web/frontend && npm run dev
### 管理员后台 ### 管理员后台
**第一个注册的用户自动成为管理员**(老版本升级上来时,注册最早的用户会被自动提升)。 **第一个注册的用户自动成为管理员**。
管理员在「设置」页面会多出一个「系统配置」区块,可以直接修改并立即生效,无需重启:
* 开放注册
* 检查间隔(保存后会自动重排定时任务)
* 规则重试时长
* 日志保留条数
监听地址、数据库、会话密钥这类启动项不在后台开放,只能改配置文件。
## 数据库 ## 数据库
@@ -126,6 +120,7 @@ cd web/frontend && npm run dev
* [OneBot (QQ)](docs/onebot-config.md) * [OneBot (QQ)](docs/onebot-config.md)
* [钉钉机器人](docs/dingtalk-config.md) * [钉钉机器人](docs/dingtalk-config.md)
* [GitHub](docs/github-config.md) * [GitHub](docs/github-config.md)
* [饭碗警告](docs/fwalert-config.md)
## 开发:新增一种规则类型 ## 开发:新增一种规则类型
+30
View File
@@ -0,0 +1,30 @@
# 饭碗警告配置
规则类型: `fwalert`。
定时器到期后,请求饭碗警告的 Webhook 地址
饭碗警告: 比较简单的(不用实名认证)支持电话和短信通知的第三方平台: `https://fwalert.com/`,价格不算最低,但比较方便
## 规则配置 (Rule Config)
```json
{
"webhook_url": "https://fwalert.com/xxx-xxx-xxx-xxx-xxx",
"msg": "消息内容"
}
```
## 饭碗警告平台配置
goodbaby 在请求饭碗警告时将`msg`放在请求体中,参照下面和官方教程设置:
| 字段 | 值 |
| --- | --- |
| `变量名` | `message` |
| `变量来源` | `请求体(body)` |
| `提取规则` | `序列化数据` |
| `键` | `message` |
| `通知简述` | 随便填 |
| `通知正文` | `{{message}}` |
| `联系方式类型` | 参照官方文档添加并选择 |
-2
View File
@@ -9,8 +9,6 @@ import (
) )
// DingTalkExecutor 钉钉机器人执行器 // DingTalkExecutor 钉钉机器人执行器
//
// 之前只注册了校验器却没有执行器,导致钉钉规则可以创建但永远不会被执行。
type DingTalkExecutor struct{} type DingTalkExecutor struct{}
func (e *DingTalkExecutor) GetType() string { func (e *DingTalkExecutor) GetType() string {
+26
View File
@@ -0,0 +1,26 @@
package fwalert
import (
"fmt"
"github.com/go-resty/resty/v2"
)
// send 发送消息
func send(config *FwAlertRuleConfig) error {
restyClient := resty.New()
req := restyClient.R()
req.SetBody(FwAlertRequest{
Message: config.Msg,
})
resp, err := req.Execute(resty.MethodPost, config.WebhookURL)
if err != nil {
return err
}
if resp.StatusCode() != 200 {
return fmt.Errorf("发送饭碗警告失败: %s", resp.Status())
}
return nil
}
+12
View File
@@ -0,0 +1,12 @@
package fwalert
const RuleTypeFwalert = "fwalert"
type FwAlertRuleConfig struct {
WebhookURL string `json:"webhook_url"`
Msg string `json:"msg"`
}
type FwAlertRequest struct {
Message string `json:"message"`
}
+62
View File
@@ -0,0 +1,62 @@
package fwalert
import (
"encoding/json"
"fmt"
"net/url"
"github.com/ssdomei232/goodBaby/internal/meta"
)
type FwalertRuleValidator struct{}
func (v *FwalertRuleValidator) GetType() string {
return RuleTypeFwalert
}
func (v *FwalertRuleValidator) Validate(configJSON string) error {
var config FwAlertRuleConfig
if err := json.Unmarshal([]byte(configJSON), &config); err != nil {
return fmt.Errorf("解析饭碗警告规则配置失败: %v", err)
}
parsed, err := url.Parse(config.WebhookURL)
if err != nil {
return fmt.Errorf("饭碗警告规则配置中 webhook_url 格式不正确: %v", err)
}
if parsed.Scheme != "http" && parsed.Scheme != "https" {
return fmt.Errorf("饭碗警告规则配置中 webhook_url 必须是 HTTP 或 HTTPS URL")
}
if config.Msg == "" {
return fmt.Errorf("饭碗警告规则配置中 msg 不能为空")
}
if len([]rune(config.Msg)) > 1000 {
return fmt.Errorf("饭碗警告内容过长")
}
return nil
}
func (v *FwalertRuleValidator) Meta() meta.RuleMeta {
return meta.RuleMeta{
Type: RuleTypeFwalert,
Label: "发送饭碗警告",
Description: "触发时发送饭碗警告消息。",
Docs: "docs/fwalert-config.md",
AccountType: "",
Fields: []meta.Field{
{Key: "webhook_url", Label: "Webhook URL", Type: meta.FieldString, Required: true, Help: "饭碗警告的触发地址", Placeholder: "https://fwalert.com/xxx-xxx-xxx-xxx-xxx"},
{Key: "msg", Label: "消息内容", Type: meta.FieldTextarea, Required: true, Help: "最大长度 1000 个字符"},
},
}
}
// ParseRuleConfig 解析饭碗警告规则配置
func ParseRuleConfig(configJSON string) (*FwAlertRuleConfig, error) {
var config FwAlertRuleConfig
if err := json.Unmarshal([]byte(configJSON), &config); err != nil {
return nil, fmt.Errorf("解析饭碗警告规则配置失败: %v", err)
}
return &config, nil
}
+29
View File
@@ -0,0 +1,29 @@
package fwalert
import (
"context"
"log"
"github.com/ssdomei232/goodBaby/internal/retry"
"github.com/ssdomei232/goodBaby/model"
)
// FwalertExecutor 饭碗警告执行器
type FwalertExecutor struct{}
func (e *FwalertExecutor) GetType() string {
return RuleTypeFwalert
}
func (e *FwalertExecutor) Execute(ctx context.Context, rule *model.Rule) error {
log.Printf("执行饭碗警告规则: %s (ID: %d)", rule.Name, rule.ID)
config, err := ParseRuleConfig(rule.ConfigJson)
if err != nil {
return err
}
return retry.Do(ctx, func() error {
return send(config)
})
}
+2
View File
@@ -9,6 +9,7 @@ import (
"github.com/ssdomei232/goodBaby/drivers/bilibili" "github.com/ssdomei232/goodBaby/drivers/bilibili"
"github.com/ssdomei232/goodBaby/drivers/dingtalk" "github.com/ssdomei232/goodBaby/drivers/dingtalk"
"github.com/ssdomei232/goodBaby/drivers/email" "github.com/ssdomei232/goodBaby/drivers/email"
"github.com/ssdomei232/goodBaby/drivers/fwalert"
"github.com/ssdomei232/goodBaby/drivers/github" "github.com/ssdomei232/goodBaby/drivers/github"
"github.com/ssdomei232/goodBaby/drivers/onebot" "github.com/ssdomei232/goodBaby/drivers/onebot"
"github.com/ssdomei232/goodBaby/model" "github.com/ssdomei232/goodBaby/model"
@@ -76,6 +77,7 @@ func InitExecutorRegistry() *ExecutorRegistry {
registry.Register(&github.GithubMakeRepoPublicExecutor{}) registry.Register(&github.GithubMakeRepoPublicExecutor{})
registry.Register(&onebot.OneBotExecutor{}) registry.Register(&onebot.OneBotExecutor{})
registry.Register(&dingtalk.DingTalkExecutor{}) registry.Register(&dingtalk.DingTalkExecutor{})
registry.Register(&fwalert.FwalertExecutor{})
// 未来添加新规则类型时,在这里注册即可 // 未来添加新规则类型时,在这里注册即可
globalExecutorRegistry = registry globalExecutorRegistry = registry
+2
View File
@@ -6,6 +6,7 @@ import (
"github.com/ssdomei232/goodBaby/drivers/bilibili" "github.com/ssdomei232/goodBaby/drivers/bilibili"
"github.com/ssdomei232/goodBaby/drivers/dingtalk" "github.com/ssdomei232/goodBaby/drivers/dingtalk"
"github.com/ssdomei232/goodBaby/drivers/email" "github.com/ssdomei232/goodBaby/drivers/email"
"github.com/ssdomei232/goodBaby/drivers/fwalert"
"github.com/ssdomei232/goodBaby/drivers/github" "github.com/ssdomei232/goodBaby/drivers/github"
"github.com/ssdomei232/goodBaby/drivers/onebot" "github.com/ssdomei232/goodBaby/drivers/onebot"
) )
@@ -27,6 +28,7 @@ func InitValidatorRegistry() *ValidatorRegistry {
r.Register(&onebot.OneBotRuleValidator{}) r.Register(&onebot.OneBotRuleValidator{})
r.Register(&dingtalk.DingTalkRuleValidator{}) r.Register(&dingtalk.DingTalkRuleValidator{})
r.Register(&github.GithubMakeRepositoryPublicRuleValidator{}) r.Register(&github.GithubMakeRepositoryPublicRuleValidator{})
r.Register(&fwalert.FwalertRuleValidator{})
registry = r registry = r
}) })