Skip to content

About

飞书消息添加了更多类型

Resources

Stars

0 stars

Watchers

0 watching

Forks

 
 

Repository files navigation

message-pusher logo

消息推送服务

✨ 搭建专属于你的消息推送服务,支持多种消息推送方式,支持 Markdown,仅单可执行文件,开箱即用✨

license GitHub Tag Docker Image Version (tag)

程序下载 · 部署教程 · 使用教程 · 意见反馈

Warning:从 v0.3 版本升级到 v0.4 版本需要手动迁移数据库,具体方法见迁移数据库。

描述

  1. 多种消息推送方式:
    • 邮件消息,
    • 微信测试号,
    • QQ,
    • 企业微信应用号,
    • 企业微信群机器人
    • 飞书自建应用
    • 飞书群机器人,
    • 钉钉群机器人,
    • Bark App,
    • WebSocket 客户端(官方客户端,接入文档),
    • Telegram 机器人,
    • Discord 群机器人,
    • 腾讯云自定义告警:免费的短信提醒,
    • 群组消息:可以将多个推送通道组合成一个群组,然后向群组发送消息,可以实现一次性推送到多个渠道的功能,
    • 自定义消息:可以自定义消息请求 URL 和请求体格式,实现与其他服务的对接,支持众多第三方服务。
  2. 支持自定义 Webhook,反向适配各种调用平台,你可以接入各种已有的系统,而无需修改其代码。
  3. 支持在 Web 端编辑 & 管理发送的消息,新消息发送后 Web 端即时刷新。
  4. 支持异步消息发送。
  5. 支持用户管理,支持多种用户登录注册方式:
  6. 支持 Markdown。
  7. 支持 Cloudflare Turnstile 用户校验。
  8. 支持在线发布公告,设置关于界面以及页脚。
  9. API 兼容其他消息推送服务,例如 Server 酱。

用途

  1. 整合进自己的博客系统,每当有人登录时发微信消息提醒。
  2. 在进行深度学习模型训练时,在每个 epoch 结束后将关键数据发送到微信以方便及时监控。
  3. 在各种脚本运行结束后发消息提醒,例如监控 GitHub Star 数量的脚本,又例如自动健康填报的脚本,用来通知运行结果。
  4. 为其他系统提供消息推送功能。

部署

通过 Docker 部署

部署:

docker run -d --restart unless-stopped --name message-pusher -p 3000:3000 -e TZ=Asia/Shanghai -v "$(pwd)/data:/data beyondandsharp/message-pusher:alpine

开放的端口号为 3000,之后用 Nginx 配置域名,反代以及 SSL 证书即可,具体参考详细部署教程。

数据将会保存在宿主机的 $(pwd)/data 目录(只有一个 SQLite 数据库文件),请确保该目录存在且具有写入权限,或者更改为合适的目录。

Nginx 的参考配置:

server{
   server_name your-domain.com;  # 请根据实际情况修改你的域名
   
   # 消息推送流(SSE,/api/message/stream)必须关闭缓冲:
   # Nginx 默认会缓冲上游响应,被缓冲住的 SSE 前端一直收不到推送,
   # 连接超时后前端会不断重连(进而是无谓的请求量),消息页只能靠轮询。
   location /api/message/stream {
          proxy_pass http://localhost:3000;  # 请根据实际情况修改你的端口
          proxy_http_version 1.1;
          proxy_set_header Host $host;
          proxy_set_header X-Forwarded-For $remote_addr;
          proxy_set_header Connection '';
          proxy_buffering off;
          proxy_cache off;
          proxy_read_timeout 3600s;
          chunked_transfer_encoding off;
   }
   
   location / {
          client_max_body_size  64m;
          proxy_http_version 1.1;
          proxy_pass http://localhost:3000;  # 请根据实际情况修改你的端口
          proxy_set_header Host $host;
          proxy_set_header X-Forwarded-For $remote_addr;
          proxy_cache_bypass $http_upgrade;
   }
}

本地构建镜像

改过代码后想自己构建镜像、并导出成可直接导入 Docker 的镜像文件,用仓库根目录的 build-image.sh(在仓库根目录执行):

./build-image.sh                     # 默认 trixie 变体(运行时 Debian trixie)
./build-image.sh --variant alpine    # alpine 变体(运行时 Alpine)

两个变体与 CI 的发布变体一一对应,两条构建链完全分离:各自的基础镜像、构建阶段、工具链和产物互不共享。

变体 Dockerfile 构建链 运行时 二进制 默认标签
trixie-slim(默认) Dockerfile.trixie-slim 全 Debian(node:24-trixie-slim / golang:1.27-trixie) debian:trixie-slim(glibc) 动态链接 glibc message-pusher:<版本>(对应 latest)+ CI 另推 <镜像>:<版本>-trixie-slim
alpine Dockerfile.alpine 全 Alpine(node:24-alpine / golang:1.27-alpine) alpine:3.24(musl) musl 静态链接 message-pusher:<版本>-alpine

两个变体的链接方式不同是有意的:alpine 侧用 musl 编译成自包含的静态二进制;trixie 侧面向 glibc 运行时, 用动态链接(glibc 的静态链接反而要依赖运行时 dlopen 解析 DNS,容易出问题)。

CI(.forgejo/)按同一套变体发布:变体定义在 .forgejo/variants.txt(alpine 与 trixie-slim,各含 linux/amd64 + linux/arm64),build 作业按表内顺序逐个变体构建并只推 staging 标签, 全部成功后由独立的 publish 作业统一提升为最终标签(含 latest)——发布失败只需重跑 publish, 不用重新构建。workflow 里不写任何项目名,job 容器默认 docker:dind,容器内缺的包 (node/git/curl/buildx/QEMU binfmt)由 workflow 自己安装,runner 侧只需 container.privileged: true。 细节见 .forgejo/README.md。

脚本选项:

选项 说明
--variant NAME 构建哪个变体:trixie(默认)或 alpine
[镜像名[:标签]] 镜像名,默认按变体:message-pusher:<版本>(trixie)或 message-pusher:<版本>-alpine(alpine)
-o, --output-dir DIR 镜像文件输出目录,默认 dist
--no-save 只构建镜像,不导出镜像文件
-h, --help 显示帮助
./build-image.sh                                # 生成 dist/message-pusher_<版本>-<架构>.tar
./build-image.sh --variant alpine               # alpine 变体
./build-image.sh message-pusher:v1              # 指定镜像名:标签
./build-image.sh -o out --no-save               # 换输出目录,且只构建不导出

<架构> 由 uname -m 决定(amd64 / arm64)。脚本最后会把镜像 docker save 成 tar 文件, 在目标机器上导入并运行:

docker load -i dist/message-pusher_<版本>-<架构>.tar
docker run -d --restart always --name message-pusher -p 3000:3000 \
  -e TZ=Asia/Shanghai -v "$(pwd)/data:/data" message-pusher:<版本>

依赖:只需要本机有 docker(前端、后端都在容器内编译,本机不需要 node / pnpm / go)。

构建时用到的下载代理(全部通过环境变量传入,均无默认值;不设置就走各语言的官方源):

环境变量 用途
APK_PROXY / APK_REPO / APT_PROXY apk / apt 包缓存代理:Alpine 改写 /etc/apk/repositories,Debian 系改写 sources 的 URI(path 型反向代理,不能用 http_proxy)。取值顺序 APK_PROXY → APK_REPO → APT_PROXY
YUM_REPO yum/dnf 仓库根(只有自定义 Dockerfile 声明了 ARG YUM_REPO 时才生效)
GOPROXY Go 模块代理(不设置则用 Go 官方代理)
NPM_PROXY / NPM_REGISTRY npm registry(容器内安装 pnpm 与前端依赖时使用;不设置则用官方源)
HTTP_PROXY / HTTPS_PROXY / NO_PROXY / ALL_PROXY 真代理:显式作为 --build-arg 转发给构建容器(docker CLI 只会从 ~/.docker/config.json 自动补代理 build arg,不读自己的环境变量)
# 不用局域网缓存,走公网默认源
APK_PROXY= APT_PROXY= GOPROXY= ./build-image.sh

# 换成其它代理 / npm 镜像
GOPROXY=https://goproxy.cn,direct \
NPM_PROXY=https://registry.npmmirror.com \
./build-image.sh message-pusher:v1

注意

如果需要使用 WebSocket 客户端推送功能,则 Nginx 的配置文件中 proxy_read_timeout 和 proxy_send_timeout 务必设置超过 1 分钟。

推荐设置:

proxy_read_timeout 300s;
proxy_send_timeout 300s;   

配置

系统本身仅需要下载一个可执行文件即可开始使用,无其他依赖。

你可以通过设置环境变量或者命令行参数进行配置。

等到系统启动后,使用 root 用户登录系统并做进一步的配置,默认密码为 123456。

环境变量

  1. REDIS_CONN_STRING:设置之后将使用 Redis 作为请求频率限制的存储,而非使用内存存储。
    • 例子:REDIS_CONN_STRING=redis://default:redispw@localhost:49153
  2. SESSION_SECRET:设置之后将使用固定的会话密钥,这样系统重新启动后已登录用户的 cookie 将依旧有效。
    • 例子:SESSION_SECRET=random_string
  3. SQL_DSN:设置之后将使用指定数据库而非 SQLite。
    • 例子:SQL_DSN=root:123456@tcp(localhost:3306)/message-pusher

注意:使用 Docker 部署时,请使用 -e key=value 设置环境变量。

例子:docker run -e SESSION_SECRET=random_string ...

命令行参数

  1. --port <port_number>: 指定服务器监听的端口号,默认为 3000。
    • 例子:--port 3000
  2. --log-dir <log_dir>: 指定日志文件夹,如果没有设置,日志将不会被保存。
    • 例子:--log-dir ./logs
  3. --version: 打印系统版本号并退出。

进一步的配置

  1. 系统设置:
    1. 填写服务器地址。
    2. 配置登录注册选项,如果系统不对外开放,请取消选择允许新用户注册。
    3. 配置 SMTP 服务,可以使用 QQ 邮箱的 SMTP 服务。
    4. 其他配置可选,请按照页面上的指示完成配置。
  2. 个人设置:
    1. 点击更新用户信息更改默认用户名和密码。
    2. 点击绑定邮箱地址绑定邮箱以启用邮件消息推送方式。
  3. 推送设置:
    1. 设置默认推送方式,默认为通过邮件进行推送。
    2. 设置推送 token,用以推送 API 调用鉴权,如果不需要留空即可。
    3. 设置其他推送方式,按照页面上的指示即可,完成配置后点击对应的测试按钮即可测试配置是否成功。
  4. 其他设置:如果系统对外提供服务,本系统也提供了一定的个性化设置功能,你可以设置关于界面和页脚,以及发布公告。

用法

  1. 消息推送 API URL:https://<domain>/push/<username>
    • 将上面的 <domain> 以及 <username> 替换为真实值,例如:https://push.mydomain.cn/push/admin
  2. GET 请求方式:https://<domain>/push/<username>?title=<标题>&description=<描述>&content=<Markdown 文本>&channel=<推送方式>&token=<推送 token>
    1. title:选填,受限于具体的消息推送方式,其可能被忽略。
    2. description:必填,可以替换为 short。
    3. content:选填,可以替换为 desp,受限于具体的消息推送方式,Markdown 语法的支持有所区别。
    4. channel:选填,如果不填则系统使用你在后台设置的默认推送通道。注意,此处填的是消息通道的名称,而非类型。可选的推送通道类型有:
      1. email:通过发送邮件的方式进行推送(使用 title 或 description 字段设置邮件主题,使用 content 字段设置正文,支持完整的 Markdown 语法)。
      2. test:通过微信测试号进行推送(使用 description 字段设置模板消息内容,不支持 Markdown)。
      3. corp_app:通过企业微信应用号进行推送(仅当使用企业微信 APP 时,如果设置了 content 字段,title 和 description 字段会被忽略;使用微信中的企业微信插件时正常)。
      4. lark_app:通过飞书自建应用进行推送(支持 msg_type 指定消息类型,详见下方《飞书消息类型》)。
      5. corp:通过企业微信群机器人推送(设置 content 字段则将渲染 Markdown 消息,支持 Markdown 的子集;设置 description 字段则为普通文本消息)。
      6. lark:通过飞书群机器人进行推送(注意事项同上)。
      7. ding:通过钉钉群机器人进行推送(注意事项同上)。
      8. bark:通过 Bark 进行推送(支持 title 和 description 字段)。
      9. client:通过 WebSocket 客户端进行推送(支持 title 和 description 字段)。
      10. telegram:通过 Telegram 机器人进行推送(description 或 content 字段二选一,支持 Markdown 的子集)。
      11. discord:通过 Discord 群机器人进行推送(注意事项同上)。
      12. one_api:通过 OneAPI 协议推送消息到 QQ。
      13. group:通过预先配置的消息推送通道群组进行推送。
      14. custom:通过预先配置好的自定义推送通道进行推送。
      15. tencent_alarm:通过腾讯云监控告警进行推送,仅支持 description 字段。
      16. none:仅保存到数据库,不做推送。
    5. token:如果你在后台设置了推送 token,则此项必填。另外可以通过设置 HTTP Authorization 头部设置此项。
      • 注意令牌有两种,一种是全局鉴权令牌,一种是通道维度的令牌,前者可以鉴权任何通道,后者只能鉴权指定通道。
    6. url:选填,如果不填则系统自动为消息生成 URL,其内容为消息详情。
    7. to:选填,推送给指定用户,如果不填则默认推送给自己,受限于具体的消息推送方式,有些推送方式不支持此项。
      1. @all:推送给所有用户。
      2. user1|user2|user3:推送给多个用户,用户之间使用 | 分隔。
    8. async:选填,如果设置为 true 则消息推送将在后台异步进行,返回结果包含 uuid 字段,可用于后续[获取消息发送状态](./docs/API.md#通过消息 UUID 获取消息发送状态)。
    9. render_mode:选填,
      1. 如果设置为 code,则消息体会被自动嵌套在代码块中进行渲染;
      2. 如果设置为 raw,则不进行 Markdown 解析;
      3. 默认 markdown,即进行 Markdown 解析。
    10. msg_type:选填,目前仅对 lark_app(飞书自建应用)生效,用于指定飞书的消息类型,取值与写法见下方《飞书消息类型》;不填时保持原有行为(description 作为文本消息,content 作为交互卡片)。
  3. POST 请求方式:字段与上面 GET 请求方式保持一致。
    • 如果发送的是 JSON,HTTP Header Content-Type 请务必设置为 application/json,否则一律按 Form 处理。
    • POST 请求方式下的 token 字段也可以通过 URL 查询参数进行设置。

各种通道的支持程度:

通道类型 title description content url to Markdown 支持
email ✅ ✅ ✅ ❌ ✅️ ✅️
test ✅ ✅ ✅ ✅️ ✅️ ✅
corp_app ✅ ✅ ✅ ✅️ ✅ ✅
corp ❌ ✅ ✅ ✅️ ✅️ ✅
lark ❌ ✅ ✅ ❌ ✅ ✅
lark_app ❌ ✅ ✅ ❌️ ✅ ✅
ding ✅ ✅ ✅ ✅️ ✅ ✅
bark ✅ ✅ ✅ ✅️ ❌ ✅
client ✅ ✅ ❌ ❌ ❌ ❌
telegram ❌ ❌ ✅ ❌ ✅ ✅
discord ❌ ❌ ✅ ❌ ✅ ❌
tencent_alarm ❌ ✅ ❌ ❌ ❌ ❌

注意:

  1. 对于大部分通道,description 字段和 content 是不能同时存在的,如果你只需要文字消息,请使用 description 字段,如果你需要发送 Markdown 消息,请使用 content 字段。
  2. 部分通道的 Markdown 支持实际上是通过 URL 跳转到本系统所渲染的消息详情实现的,其他通道的 Markdown 支持受限于具体的通道,支持的语法并不统一。
  3. 字段别名:short 等价于 description,desp 等价于 content,openid 等价于 to。

接口(Webhook)规则说明:

在「接口」页面创建的 Webhook 会按「提取规则 → 构建规则」的顺序把入站请求转换成一条消息:

  1. 提取规则:一个 JSON 对象,键是模板变量名,值是该请求体里的取值路径(用 gjson,数组下标写成 .0.),例如:
    {
      "to": "imoke_email",
      "title": "alerts.0.labels.alertname",
      "content": "alerts.0.annotations.description"
    }
    这里左边只是变量名,右边才是取值路径,所以 "to": "imoke_email" 这类写法是成立的。
  2. 构建规则:一个 JSON 对象,其中 title / description / content / url / to 对应消息字段;其它键会原样保留,并成为自定义消息通道可用的模板变量(例如 "content_test": "mmmmmsg" 可以用 $content_test 引用)。值可以:
    • 直接写字符串,用 $变量名 引用提取规则里的变量(注意是 $VAR,不是 ${VAR});
    • 写成 JSON 对象或数组(例如飞书卡片模板),嵌套在其中的 $变量名 同样会被替换。
    {
      "to": "$to",
      "content": {
        "type": "template",
        "data": { "template_variable": { "title": "$title" } }
      },
      "content_test": "mmmmmsg"
    }
    只有 to 会被传给消息的接收者字段,自定义消息通道的请求体里可以用 $to 引用它。

自定义消息通道的模板变量:

自定义通道的请求体是一个 JSON 模板,支持 $变量名:

  • 消息字段:$id、$title、$description、$content、$url、$to、$link、$channel、$timestamp、$render_mode、$msg_type;
  • Webhook 构建规则里的自定义键,例如 "content_test": "mmmmmsg" 在请求体里写成 $content_test;
  • 如果变量本身是 JSON(例如构建规则生成的 content 是对象),可以用点号访问嵌套字段,数组下标用数字:
    {
      "title": "$title",
      "template_id": "$content.data.template_id",
      "nested_title": "$content.data.template_variable.title",
      "content_test": "$content_test"
    }
  • 未定义的变量或无法解析的路径会原样保留;替换值会按 JSON 字符串转义,因此变量建议放在 JSON 引号内使用。

飞书消息类型(msg_type):

msg_type 目前仅对 lark_app(飞书自建应用)生效,不填时保持原有行为。各取值与 content 的对应关系如下:

msg_type 说明 content 写法
text 文本消息 直接填写文本:优先使用 description,description 为空时使用 content
post 富文本消息 富文本 JSON,如 {"zh_cn":{"title":"标题","content":[[{"tag":"text","text":"内容"}]]}};也接受 {"post":{...}} 以及省略 zh_cn 的简写
interactive 消息卡片 卡片 JSON,1.0 与 2.0 均可;如果不是合法的 JSON 对象,则将 content 作为 Markdown 自动生成卡片
image 图片 image_key,或 {"image_key":"img_xxx"}
share_chat 分享群名片 chat_id,或 {"chat_id":"oc_xxx"}
share_user 分享个人名片 user_id,或 {"user_id":"ou_xxx"}
audio 语音 file_key,或 {"file_key":"file_xxx"}
media 视频 {"file_key":"file_xxx","image_key":"img_xxx"},其中 image_key 是视频封面,选填
file 文件 file_key,或 {"file_key":"file_xxx"}
sticker 表情包 file_key,或 {"file_key":"file_xxx"}

补充说明:

  1. image_key、file_key 需要先调用飞书的上传图片或上传文件接口获取,本系统暂不代为上传。
  2. 在 lark_app 通道中,to 表示消息接收者(格式为 类型:ID),不再用于 @ 用户;如果需要 @ 用户,请在 content 中直接编写飞书的 at 标签。
  3. 如果 msg_type 是上表之外的未知类型,当 content 是合法的 JSON 对象时会原样透传,否则返回错误。

示例:

Bash 示例
#!/bin/bash

MESSAGE_PUSHER_SERVER="https://your-domain.com"
MESSAGE_PUSHER_USERNAME="test"
MESSAGE_PUSHER_TOKEN="666"

function send_message {
  # POST Form
  curl -s -X POST "$MESSAGE_PUSHER_SERVER/push/$MESSAGE_PUSHER_USERNAME" \
    -d "title=$1&description=$2&content=$3&token=$MESSAGE_PUSHER_TOKEN" \
    >/dev/null
}

function send_message_with_json {
  # POST JSON
  curl -s -X POST "$MESSAGE_PUSHER_SERVER/push/$MESSAGE_PUSHER_USERNAME" \
    -H 'Content-Type: application/json' \
    -d '{"title":"'"$1"'","desp":"'"$2"'", "content":"'"$3"'", "token":"'"$MESSAGE_PUSHER_TOKEN"'"}' \
    >/dev/null
}

send_message 'title' 'description' 'content'

另一个版本:

MESSAGE_PUSHER_SERVER="https://your-domain.com"
MESSAGE_PUSHER_USERNAME="test"
MESSAGE_PUSHER_TOKEN="666"
MESSAGE_PUSHER_CHANNEL="lark"

sendmsg() {
    if [ -t 0 ]; then
        local param="$*"
    else
        local param=$(</dev/stdin)
    fi
    curl -s -o /dev/null --get --data-urlencode "content=${param}" "$MESSAGE_PUSHER_SERVER/push/$MESSAGE_PUSHER_USERNAME?channel=$MESSAGE_PUSHER_CHANNEL&token=$MESSAGE_PUSHER_TOKEN"
}

之后便可以进行这样的操作:

uname -ra | sendmsg
Python 示例
import requests

SERVER = "https://your-domain.com"
USERNAME = "test"
TOKEN = "666"


def send_message(title, description, content):
    # GET 方式
    # res = requests.get(f"{SERVER}/push/{USERNAME}?title={title}"
    #                    f"&description={description}&content={content}&token={TOKEN}")

    # POST 方式
    res = requests.post(f"{SERVER}/push/{USERNAME}", json={
        "title": title,
        "description": description,
        "content": content,
        "token": TOKEN
    })
    res = res.json()
    if res["success"]:
        return None
    else:
        return res["message"]


error = send_message("标题", "描述", "**Markdown 内容**")
if error:
    print(error)
Go 示例
package main

import (
   "bytes"
   "encoding/json"
   "errors"
   "fmt"
   "net/http"
   "net/url"
)

var serverAddress = "https://your-domain.com"
var username = "test"
var token = "666"

type request struct {
   Title       string `json:"title"`
   Description string `json:"description"`
   Content     string `json:"content"`
   URL         string `json:"url"`
   Channel     string `json:"channel"`
   Token       string `json:"token"`
}

type response struct {
   Success bool   `json:"success"`
   Message string `json:"message"`
}

func SendMessage(title string, description string, content string) error {
   req := request{
      Title:       title,
      Description: description,
      Content:     content,
      Token:       token,
   }
   data, err := json.Marshal(req)
   if err != nil {
      return err
   }
   resp, err := http.Post(fmt.Sprintf("%s/push/%s", serverAddress, username),
      "application/json", bytes.NewBuffer(data))
   if err != nil {
      return err
   }
   var res response
   err = json.NewDecoder(resp.Body).Decode(&res)
   if err != nil {
      return err
   }
   if !res.Success {
      return errors.New(res.Message)
   }
   return nil
}

func SendMessageWithForm(title string, description string, content string) error {
   resp, err := http.PostForm(fmt.Sprintf("%s/push/%s", serverAddress, username),
      url.Values{"title": {title}, "description": {description}, "content": {content}, "token": {token}})
   if err != nil {
      return err
   }
   var res response
   err = json.NewDecoder(resp.Body).Decode(&res)
   if err != nil {
      return err
   }
   if !res.Success {
      return errors.New(res.Message)
   }
   return nil
}

func main() {
   //err := SendMessage("标题", "描述", "**Markdown 内容**")
   err := SendMessageWithForm("标题", "描述", "**Markdown 内容**")
   if err != nil {
      fmt.Println("推送失败:" + err.Error())
   } else {
      fmt.Println("推送成功!")
   }
}
C# 示例
using Newtonsoft.Json;
using RestSharp;

namespace Demo
{
    public class Program
    {
        public static void Main(string[] args)
        {
            //推送消息
            var sendMsg = MessagePusherTool.SendMessage("标题", "描述", "**Markdown 内容**");
            if(sendMsg.Success)
            {
                Console.WriteLine($"推送成功!");
            }
            else
            {
                Console.WriteLine($"推送失败:{sendMsg.Message}");
            }
        }
    }

    /// <summary>
    /// 消息推送工具
    /// 
    /// <para>开源地址:https://github.com/BeyondandSharp/message-pusher</para>
    /// <para>支持:Framework、Net3.1、Net5、Net6</para>
    /// <para>引用包:</para>
    /// <para>dotnet add package Newtonsoft.Json -v 13.0.2</para>
    /// <para>dotnet add package RestSharp -v 108.0.3</para>
    /// </summary>
    public class MessagePusherTool
    {
        /// <summary>
        /// ServerAddress
        /// </summary>
        public const string ServerAddress = "https://your-domain.com";

        /// <summary>
        /// UserName
        /// </summary>
        public const string UserName = "test";

        /// <summary>
        /// Token
        /// </summary>
        public const string Token = "666";

        /// <summary>
        /// SendMessage
        /// </summary>
        /// <param name="title">title</param>
        /// <param name="description">description</param>
        /// <param name="content">content</param>
        public static Response SendMessage(string title, string description, string content)
        {
            var requestData = new Request()
            {
                Title = title,
                Description = description,
                Content = content,
                Token = Token,
            };
            var url = $"{ServerAddress}";
            var client = new RestClient(url);
            var request = new RestRequest($"push/{UserName}", Method.Post);
            request.AddJsonBody(requestData);
            var response = client.Execute(request);
            var responseData = response.Content;
            var responseJson = JsonConvert.DeserializeObject<Response>(responseData);
            return responseJson;
        }

        /// <summary>
        /// Request
        /// </summary>
        public class Request
        {
            /// <summary>
            /// Title
            /// </summary>
            [JsonProperty(PropertyName = "title")]
            public string Title { get; set; }

            /// <summary>
            /// Description
            /// </summary>
            [JsonProperty(PropertyName = "description")]
            public string Description { get; set; }

            /// <summary>
            /// Content
            /// </summary>
            [JsonProperty(PropertyName = "content")]
            public string Content { get; set; }

            /// <summary>
            /// URL
            /// </summary>
            [JsonProperty(PropertyName = "url")]
            public string URL { get; set; }

            /// <summary>
            /// Channel
            /// </summary>
            [JsonProperty(PropertyName = "channel")]
            public string Channel { get; set; }

            /// <summary>
            /// Token
            /// </summary>
            [JsonProperty(PropertyName = "token")]
            public string Token { get; set; }
        }

        /// <summary>
        /// Response
        /// </summary>
        public class Response
        {
            /// <summary>
            /// Success
            /// </summary>
            [JsonProperty(PropertyName = "success")]
            public bool Success { get; set; }

            /// <summary>
            /// Message
            /// </summary>
            [JsonProperty(PropertyName = "message")]
            public string Message { get; set; }
        }
    }
}
Node.js 示例
const axios = require('axios');
const querystring = require('querystring');

const MESSAGE_PUSHER_SERVER = 'https://your-domain.com'
const MESSAGE_PUSHER_USERNAME = 'test'
const MESSAGE_PUSHER_TOKEN = '666'

async function send_message(title, description, content) {
  try {
    const postData = querystring.stringify({
      title: title,
      desp: description,
      content: content,
      token: MESSAGE_PUSHER_TOKEN,
    })

    const response = await axios.post(`${MESSAGE_PUSHER_SERVER}/push/${MESSAGE_PUSHER_USERNAME}`, postData, {
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
      },
    })
    if (response.data.success) {
      return response.data
    }
  } catch (error) {
    if (error.response) {
      return error.response.data
    } else {
      throw error
    }

  }
}

send_message('标题', '描述', '**Markdown 内容**')
  .then((response) => {
    if (response.success) {
      console.log('推送成功:', response)
    } else {
      console.log('推送失败:', response)
    }
  }, (error) => {
    console.log(error.message);
  })

欢迎 PR 添加更多语言的示例。

迁移数据库

此处均以 SQLite 为例,其他数据库请自行修改。我已经让 ChatGPT 翻译成对应的 SQL 版本,见 bin 文件夹,供参考。

从 v0.3 迁移到 v0.4

  1. 首先备份你的数据库文件。
  2. 下载最新的 v0.4 版本,启动程序,程序会自动进行数据库表结构的迁移。
  3. 终止程序。
  4. 之后执行脚本:./bin/migrate_v3_to_v4.py,进行数据的迁移。
  5. 重新启动程序即可。

注意,执行前请确保数据库中 users 表中字段的顺序和脚本中的一致,否则会出现数据错乱的情况。

其他

  1. v0.3 之前的版本基于 Node.js,你可以切换到 nodejs 分支查看,该版本不再有功能性更新。
  2. v0.3 以及后续版本基于 Gin Template v0.2.1 版本开发。
  3. 需要自行构建时,用仓库根目录的 ./build-image.sh --variant alpine 或 ./build-image.sh --variant trixie 构建镜像(前端与后端都在容器内编译,本机不需要 node / pnpm / go)。

About

飞书消息添加了更多类型

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages