独自のメッセージ プッシュ サービスを構築し、複数のメッセージ プッシュ メソッドをサポートし、Markdown をサポートし、単一の実行可能ファイルのみをサポートし、すぐに使用できます
プログラムのダウンロード・導入チュートリアル・使用方法のチュートリアル・フィードバック・オンラインデモ
注: 公式展開サイト https://msgpusher.com は現在オンラインになっており、登録を受け付けています。肯定的なフィードバックを受け取った場合は、将来的に待機時間が短いサーバーへの切り替えを検討する可能性があります。
警告:
v0.3
からv0.4
にアップグレードするには、データベースを手動で移行する必要があります。詳細については、「データベースの移行」を参照してください。
デプロイメント: docker run -d --restart always --name message-pusher -p 3000:3000 -e TZ=Asia/Shanghai -v /home/ubuntu/data/message-pusher:/data justsong/message-pusher
pull できない場合は、 justsong/message-pusher
ghcr.io/songquanpeng/message-pusher
に置き換えてください。
更新: docker run --rm -v /var/run/docker.sock:/var/run/docker.sock containrrr/watchtower -cR
開いているポート番号は 3000 です。次に、Nginx を使用してドメイン名、逆生成、SSL 証明書を構成します。詳細については、詳細な導入チュートリアルを参照してください。
データはホスト マシンの/home/ubuntu/data/message-pusher
ディレクトリに保存されます (SQLite データベース ファイルは 1 つだけです)。ディレクトリが存在し、書き込み権限があることを確認するか、適切なディレクトリに変更してください。 。
Nginxの参考構成:
server{
server_name msgpusher.com; # 请根据实际情况修改你的域名
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;
proxy_set_header Accept-Encoding gzip;
}
}
次に、Let's Encrypt の certbot を使用して HTTPS を構成します。
# Ubuntu 安装 certbot:
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
# 生成证书 & 修改 Nginx 配置
sudo certbot --nginx
# 根据指示进行操作
# 重启 Nginx
sudo service nginx restart
git clone https://github.com/songquanpeng/message-pusher.git
cd message-pusher/web
npm install
npm run build
cd ..
go mod download
go build -ldflags " -s -w " -o message-pusher
chmod u+x message-pusher
./message-pusher --port 3000 --log-dir ./logs
root
、パスワードは123456
です。サービスを長時間実行する必要がある場合は、詳細な展開チュートリアルを開始するだけでは十分ではありません。
WebSocket クライアントのプッシュ機能を使用する必要がある場合は、Nginx 設定ファイルのproxy_read_timeout
とproxy_send_timeout
1 分以上に設定する必要があります。
推奨設定:
proxy_read_timeout 300s;
proxy_send_timeout 300s;
システム自体は実行可能ファイルをダウンロードするだけで使用を開始でき、他の依存関係はありません。
環境変数またはコマンド ライン パラメーターを設定することで構成できます。
システムが起動したら、 root
ユーザーを使用してシステムにログインし、デフォルトのパスワードは123456
です。
REDIS_CONN_STRING
: 設定後、メモリ ストレージを使用する代わりに、Redis がリクエスト頻度制限のストレージとして使用されます。REDIS_CONN_STRING=redis://default:redispw@localhost:49153
SESSION_SECRET
: 設定後、固定のセッション キーが使用されるため、ログイン ユーザーの Cookie はシステムの再起動後も有効になります。SESSION_SECRET=random_string
SQL_DSN
: 設定後、SQLite の代わりに指定されたデータベースが使用されます。SQL_DSN=root:123456@tcp(localhost:3306)/message-pusher
注: Docker を使用してデプロイする場合は、 -e key=value
を使用して環境変数を設定してください。
例: docker run -e SESSION_SECRET=random_string ...
--port <port_number>
: サーバーがリッスンするポート番号を指定します。デフォルトは3000
です。--port 3000
--log-dir <log_dir>
: ログ フォルダーを指定します。設定しない場合、ログは保存されません。--log-dir ./logs
--version
: システムのバージョン番号を出力して終了します。允许新用户注册
] の選択を解除してください。更新用户信息
をクリックして、デフォルトのユーザー名とパスワードを変更します。绑定邮箱地址
メールをバインドし、電子メール メッセージのプッシュを有効にします。默认推送方式
を設定します。デフォルトは電子メールによるプッシュです。推送token
を設定します。必要ない場合は空白のままにします。测试
ボタンをクリックして、設定が成功したかどうかをテストします。https://<domain>/push/<username>
<domain>
と<username>
を実際の値に置き換えます (例: https://push.mydomain.cn/push/admin
。GET
リクエストメソッド: https://<domain>/push/<username>?title=<标题>&description=<描述>&content=<Markdown 文本>&channel=<推送方式>&token=<推送token>
title
: オプション。特定のメッセージプッシュ方法によって制限され、無視される場合があります。description
: 必須。 desp
で置き換えることができます。content
: オプション。特定のメッセージ プッシュ方法によって制限されます。Markdown 構文のサポートは異なります。channel
: オプション。入力しない場合、システムはバックグラウンドで設定したデフォルトのプッシュ チャネルを使用します。ここでは、メッセージ チャネルの種類ではなく名前が入力されることに注意してください。オプションのプッシュ チャネル タイプは次のとおりです。email
: 電子メールを送信してプッシュします ( title
またはdescription
フィールドを使用して電子メールの件名を設定し、 content
フィールドを使用して本文を設定し、完全な Markdown 構文をサポートします)。test
: WeChat テスト アカウントをプッシュスルーします ( description
フィールドを使用してテンプレート メッセージのコンテンツを設定します。マークダウンはサポートされていません)。corp_app
: エンタープライズ WeChat アプリケーション アカウントを介してプッシュします (エンタープライズ WeChat APP を使用する場合のみ、 content
フィールドが設定されている場合、 title
とdescription
フィールドは無視されます。WeChat でエンタープライズ WeChat プラグインを使用する場合は正常です)。lark_app
: Feishu の自作アプリケーションをプッシュスルーします。corp
: エンタープライズ WeChat グループ ロボットを通じてプッシュされます ( content
フィールドを設定すると、Markdown メッセージがレンダリングされ、Markdown のサブセットがサポートされます。description description
を設定すると、通常のテキスト メッセージがレンダリングされます)。lark
: Feishqun ロボットを介してプッシュします (メモは上記と同じです)。ding
: DingTalk グループ ロボット経由でプッシュします (注意事項は上記と同じです)。bark
: Bark をプッシュスルーします ( title
およびdescription
フィールドをサポート)。client
: WebSocket クライアント経由でプッシュします ( title
およびdescription
フィールドをサポート)。telegram
: Telegram ロボット経由でプッシュします ( description
またはcontent
フィールドのいずれかを選択し、Markdown のサブセットをサポートします)。discord
: Discordグループボットを押します(注意事項は上と同じです)。one_api
: OneAPI プロトコルを通じてメッセージを QQ にプッシュします。group
: 事前設定されたメッセージ プッシュ チャネル グループを介してプッシュします。custom
: 事前設定されたカスタム プッシュ チャネルを介してプッシュします。tencent_alarm
: Tencent クラウド監視アラームを通じてプッシュされ、 description
フィールドのみがサポートされます。none
: データベースに保存するだけで、プッシュしません。token
: バックグラウンドでプッシュトークンを設定する場合、この項目は必須です。これは、HTTP Authorization
ヘッダーを設定することによっても設定できます。url
: オプション。入力しない場合、システムはメッセージの URL を自動的に生成し、その内容がメッセージの詳細になります。to
: オプション。指定したユーザーにプッシュします。入力しない場合、デフォルトでは特定のメッセージ プッシュ メソッドによって制限され、一部のプッシュ メソッドはこれをサポートしません。@all
: すべてのユーザーにプッシュします。user1|user2|user3
: |
で区切って複数のユーザーにプッシュします。async
: オプション。 true
に設定すると、メッセージのプッシュはバックグラウンドで非同期に実行され、返される結果にはuuid
フィールドが含まれます。このフィールドは、後続の [メッセージ送信ステータスの取得] (./docs/API.md#Get) に使用できます。メッセージ送信ステータス (メッセージ UUID) を介して。render_mode
: オプション、code
に設定すると、メッセージ本文はレンダリングのためにコード ブロックに自動的にネストされます。raw
に設定すると、Markdown 解析は実行されません。markdown
で、Markdown 解析を意味します。POST
リクエスト メソッド: フィールドは上記のGET
リクエスト メソッドと一致します。Content-Type
application/json
に設定する必要があります。それ以外の場合は、フォームとして処理されます。token
フィールドは、URL クエリ パラメータを通じて設定することもできます。さまざまなチャネルのサポート レベル:
チャネルの種類 | title | description | content | url | to | マークダウンのサポート |
---|---|---|---|---|---|---|
email | ✅ | ✅ | ✅ | ✅️ | ✅️ | |
test | ✅ | ✅ | ✅ | ✅️ | ✅️ | ✅ |
corp_app | ✅ | ✅ | ✅ | ✅️ | ✅ | ✅ |
corp | ✅ | ✅ | ✅️ | ✅️ | ✅ | |
lark | ✅ | ✅ | ✅ | ✅ | ||
lark_app | ✅ | ✅ | ️ | ✅ | ✅ | |
ding | ✅ | ✅ | ✅ | ✅️ | ✅ | ✅ |
bark | ✅ | ✅ | ✅ | ✅️ | ✅ | |
client | ✅ | ✅ | ||||
telegram | ✅ | ✅ | ✅ | |||
discord | ✅ | ✅ | ||||
tencent_alarm | ✅ |
知らせ:
description
フィールドとcontent
同時に存在させることはできません。テキスト メッセージのみが必要な場合は、 description
フィールドを使用してください。マークダウン メッセージを送信する必要がある場合は、 content
フィールドを使用してください。例:
#! /bin/bash
MESSAGE_PUSHER_SERVER= " https://msgpusher.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://msgpusher.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
import requests
SERVER = "https://msgpusher.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 )
package main
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"net/http"
"net/url"
)
var serverAddress = "https://msgpusher.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 ( "推送成功!" )
}
}
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/songquanpeng/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://msgpusher.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 ; }
}
}
}
const axios = require ( 'axios' ) ;
const querystring = require ( 'querystring' ) ;
const MESSAGE_PUSHER_SERVER = 'https://msgpusher.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
への移行v0.4
バージョンをダウンロードし、プログラムを起動すると、プログラムはデータベース テーブル構造を自動的に移行します。./bin/migrate_v3_to_v4.py
を実行してデータを移行します。実行前に、データベースのusers
テーブルのフィールドの順序がスクリプト内の順序と一致していることを確認してください。一致しない場合、データの混乱が発生します。
v0.3
より前のバージョンは Node.js に基づいています。このバージョンには機能更新がありませんnodejs
ブランチに切り替えることができます。v0.3
以降のバージョンは、Gin Template v0.2.1
に基づいて開発されています。pattern web/build: no matching files found
」が発生します。