Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(push): 添加 WxPusher 推送支持 #356

Merged
merged 4 commits into from
Mar 4, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion examples/01-example.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { AxiosResponse } from 'axios'
import colors from '@colors/colors'
import { ServerChanTurbo, ServerChanV3, CustomEmail, Dingtalk, WechatRobot, WechatApp, PushPlus, IGot, Qmsg, XiZhi, PushDeer, Discord, OneBot, Telegram, PushPlusTemplateType, CustomEmailType, WechatRobotMsgType, WechatAppMsgType, PushPlusChannelType } from '../src'
import { ServerChanTurbo, ServerChanV3, CustomEmail, Dingtalk, WechatRobot, WechatApp, PushPlus, IGot, Qmsg, XiZhi, PushDeer, Discord, OneBot, Telegram, WxPusher, PushPlusTemplateType, CustomEmailType, WechatRobotMsgType, WechatAppMsgType, PushPlusChannelType } from '../src'
import { warn } from '../src/utils/helper'
import { SendResponse } from '../src/interfaces/response'

Expand Down Expand Up @@ -207,6 +207,20 @@ export async function batchPushAllInOne(title: string, desp?: string): Promise<P
info('未配置 OneBot 推送,已跳过')
}

if (env.WX_PUSHER_APP_TOKEN && env.WX_PUSHER_UID) {
// WxPusher 推送。官方文档:https://wxpusher.zjiecode.com/docs
const wxPusher = new WxPusher({
WX_PUSHER_APP_TOKEN: env.WX_PUSHER_APP_TOKEN,
WX_PUSHER_UID: env.WX_PUSHER_UID,
})
pushs.push(wxPusher.send(title, desp, {
contentType: 3, // 使用 markdown 格式
}))
info('WxPusher 推送 已加入推送队列')
} else {
info('未配置 WxPusher 推送,已跳过')
}

if (pushs.length === 0) {
warn('未配置任何推送,请检查推送配置的环境变量!')
return []
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export * from './push/telegram'
export * from './push/wechat-app'
export * from './push/wechat-robot'
export * from './push/xi-zhi'
export * from './push/wx-pusher'

export * from './interfaces/response'
export * from './interfaces/schema'
Expand Down
3 changes: 2 additions & 1 deletion src/one.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CustomEmail, Dingtalk, Discord, Feishu, IGot, Ntfy, OneBot, PushDeer, PushPlus, Qmsg, ServerChanTurbo, ServerChanV3, Telegram, WechatApp, WechatRobot, XiZhi } from './index'
import { CustomEmail, Dingtalk, Discord, Feishu, IGot, Ntfy, OneBot, PushDeer, PushPlus, Qmsg, ServerChanTurbo, ServerChanV3, Telegram, WechatApp, WechatRobot, XiZhi, WxPusher } from './index'
import { SendResponse } from '@/interfaces/response'

export const PushAllInOne = {
Expand All @@ -17,6 +17,7 @@ export const PushAllInOne = {
Telegram,
WechatApp,
WechatRobot,
WxPusher,
XiZhi,
} as const

Expand Down
203 changes: 203 additions & 0 deletions src/push/wx-pusher.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
import debug from 'debug'
import { Send } from '@/interfaces/send'
import { ajax } from '@/utils/ajax'
import { SendResponse } from '@/interfaces/response'
import { ConfigSchema, OptionSchema } from '@/interfaces/schema'
import { validate } from '@/utils/validate'

const Debugger = debug('push:wx-pusher')

export interface WxPusherConfig {
/**
* WxPusher 的 appToken。在 https://wxpusher.zjiecode.com/admin/main/app/appToken 申请
*/
WX_PUSHER_APP_TOKEN: string
/**
* WxPusher 的 uid。在 https://wxpusher.zjiecode.com/admin/main/wxuser/list 查看
*/
WX_PUSHER_UID: string
}

export type WxPusherConfigSchema = ConfigSchema<WxPusherConfig>

export const wxPusherConfigSchema: WxPusherConfigSchema = {
WX_PUSHER_APP_TOKEN: {
type: 'string',
title: 'appToken',
description: '在 https://wxpusher.zjiecode.com/admin/main/app/appToken 申请',
required: true,
},
WX_PUSHER_UID: {
type: 'string',
title: 'uid',
description: '在 https://wxpusher.zjiecode.com/admin/main/wxuser/list 查看',
required: true,
},
} as const

export interface WxPusherOption {
/**
* 消息摘要,显示在微信聊天页面或者模版消息卡片上,限制长度100,可以不传,不传默认截取content前面的内容。
*/
summary?: string
/**
* 内容类型 1表示文字 2表示html(只发送body标签内部的数据即可,不包括body标签) 3表示markdown
*/
contentType?: 1 | 2 | 3
/**
* 是否保存发送内容,1保存,0不保存,默认0
*/
save?: 0 | 1
/**
* 主题ID,可以根据主题ID发送消息,可以在主题管理中查看主题ID
*/
topicIds?: number[]
/**
* 发送url,可以不传,如果传了,则根据url弹出通知
*/
url?: string
/**
* 仅针对text消息类型有效
*/
verifyPayload?: string
}

export type WxPusherOptionSchema = OptionSchema<WxPusherOption>

export const wxPusherOptionSchema: WxPusherOptionSchema = {
summary: {
type: 'string',
title: '消息摘要',
description: '显示在微信聊天页面或者模版消息卡片上,限制长度100,可以不传,不传默认截取content前面的内容。',
required: false,
},
contentType: {
type: 'select',
title: '内容类型',
description: '内容类型',
required: false,
default: 1,
options: [
{
label: '文本',
value: 1,
},
{
label: 'HTML',
value: 2,
},
{
label: 'Markdown',
value: 3,
},
],
},
save: {
type: 'select',
title: '是否保存发送内容',
description: '是否保存发送内容,1保存,0不保存,默认0',
required: false,
options: [
{
label: '不保存',
value: 0,
},
{
label: '保存',
value: 1,
},
],
},
topicIds: {
type: 'array',
title: '主题ID',
description: '主题ID,可以根据主题ID发送消息,可以在主题管理中查看主题ID',
required: false,
},
url: {
type: 'string',
title: '发送url',
description: '发送url,可以不传,如果传了,则根据url弹出通知',
required: false,
},
verifyPayload: {
type: 'string',
title: '验证负载',
description: '仅针对text消息类型有效',
required: false,
},
} as const

export interface WxPusherResponse {
/**
* 请求是否成功
*/
success: boolean
/**
* 请求返回码
*/
code: number
/**
* 请求返回消息
*/
msg: string
/**
* 请求返回数据
*/
data: {
/**
* 消息ID
*/
messageId: number
/**
* 消息编码
*/
code: string
}
}

/**
* WxPusher 推送。官方文档:https://wxpusher.zjiecode.com/docs
*
* @author CaoMeiYouRen
* @date 2024-11-09
* @export
* @class WxPusher
*/
export class WxPusher implements Send {
static readonly namespace = 'WxPusher'
static readonly configSchema = wxPusherConfigSchema
static readonly optionSchema = wxPusherOptionSchema

private WX_PUSHER_APP_TOKEN: string
private WX_PUSHER_UID: string

constructor(config: WxPusherConfig) {
const { WX_PUSHER_APP_TOKEN, WX_PUSHER_UID } = config
this.WX_PUSHER_APP_TOKEN = WX_PUSHER_APP_TOKEN
this.WX_PUSHER_UID = WX_PUSHER_UID
Debugger('set WX_PUSHER_APP_TOKEN: "%s", WX_PUSHER_UID: "%s"', WX_PUSHER_APP_TOKEN, WX_PUSHER_UID)
// 根据 configSchema 验证 config
validate(config, WxPusher.configSchema)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

在调用validate函数时,请确保传递的配置对象符合WxPusher.configSchema的要求,以避免潜在的验证错误。

}

async send(title: string, desp?: string, option?: WxPusherOption): Promise<SendResponse<WxPusherResponse>> {
Debugger('title: "%s", desp: "%s", option: %O', title, desp, option)
const { contentType = 1, ...args } = option || {}
const content = `${title}${desp ? `\n${desp}` : ''}`
return ajax({
url: 'https://wxpusher.zjiecode.com/api/send/message',
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: {
appToken: this.WX_PUSHER_APP_TOKEN,
content,
contentType,
uids: [this.WX_PUSHER_UID],
...args,
},
})
}
}