Skip to content

Diagnose PushPlus delivery #5

Diagnose PushPlus delivery

Diagnose PushPlus delivery #5

name: Diagnose PushPlus delivery
on:
workflow_dispatch:
permissions:
contents: read
concurrency:
group: pushplus-delivery-diagnostic
cancel-in-progress: false
jobs:
diagnose:
runs-on: ubuntu-latest
timeout-minutes: 5
env:
PUSHPLUS_TOKEN: ${{ secrets.PUSHPLUS_TOKEN }}
PUSHPLUS_SECRET_KEY: ${{ secrets.PUSHPLUS_SECRET_KEY }}
PUSHPLUS_WEBHOOK_URL: https://pushplus-sms-to-telegram.pages.dev/pushplus/webhook/${{ secrets.RELAY_TOKEN }}
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 22
- name: Inspect recent PushPlus records without message content
run: |
node <<'NODE'
const { fetchRecentMessages } = require('./src/pushplus');
async function main() {
const messages = await fetchRecentMessages({
token: process.env.PUSHPLUS_TOKEN,
secretKey: process.env.PUSHPLUS_SECRET_KEY,
baseUrl: 'https://www.pushplus.plus',
pageSize: 20,
titleKeyword: '短信转发',
bodyKeyword: '',
lookbackMinutes: 7 * 24 * 60,
});
const dayAgo = Date.now() - 24 * 60 * 60 * 1000;
const summary = {
matchingRecordsSevenDays: messages.length,
matchingRecordsTwentyFourHours: messages.filter(message => message.receivedAt >= dayAgo).length,
latestUpdateTime: messages.at(-1)?.updateTime || null,
readableDetails: messages.filter(message => message.text.length > 0).length,
smsMarkerRecords: messages.filter(message => message.text.includes('#SMS')).length,
senderFieldRecords: messages.filter(message => /发件(?:号码|人|号)?\s*[::]/.test(message.text)).length,
};
console.log(JSON.stringify(summary));
}
main().catch(error => {
console.error(error.message);
process.exit(1);
});
NODE
- name: Send end-to-end message through PushPlus
run: |
node <<'NODE'
const sleep = milliseconds => new Promise(resolve => setTimeout(resolve, milliseconds));
async function requestJson(url, options = {}) {
const response = await fetch(url, {
...options,
signal: AbortSignal.timeout(15_000),
});
const data = await response.json().catch(() => ({}));
if (!response.ok) throw new Error(`PushPlus HTTP ${response.status}`);
return data;
}
async function main() {
const submitted = await requestJson('https://www.pushplus.plus/send', {
method: 'POST',
headers: { 'content-type': 'application/json', accept: 'application/json' },
body: JSON.stringify({
token: process.env.PUSHPLUS_TOKEN,
title: '短信转发',
content: [
'PushPlus 完整生产链路诊断消息',
'发件号码: DIAGNOSTIC-PUSHPLUS',
`发件时间: ${new Date().toISOString()}`,
'#SMS',
].join('\n'),
}),
});
if (submitted.code !== 200 || !submitted.data) {
throw new Error(`PushPlus rejected the diagnostic request (code ${submitted.code ?? 'unknown'})`);
}
const access = await requestJson('https://www.pushplus.plus/api/common/openApi/getAccessKey', {
method: 'POST',
headers: { 'content-type': 'application/json', accept: 'application/json' },
body: JSON.stringify({
token: process.env.PUSHPLUS_TOKEN,
secretKey: process.env.PUSHPLUS_SECRET_KEY,
}),
});
const accessKey = access?.data?.accessKey;
if (access.code !== 200 || !accessKey) throw new Error('Could not obtain a PushPlus access key');
for (let attempt = 1; attempt <= 20; attempt += 1) {
const result = await requestJson(
`https://www.pushplus.plus/api/open/message/sendMessageResult?shortCode=${encodeURIComponent(submitted.data)}`,
{ headers: { accept: 'application/json', 'access-key': accessKey } },
);
if (result.code !== 200) {
throw new Error(`Could not query PushPlus delivery status (code ${result.code ?? 'unknown'})`);
}
const status = Number(result?.data?.status);
if (status === 2) {
console.log('PushPlus accepted the message and completed webhook delivery to Telegram.');
return;
}
if (status === 3) {
const detail = String(result?.data?.errorMessage || 'no detail returned')
.replace(/\/pushplus\/webhook\/[^/?\s]+/gi, '/pushplus/webhook/[redacted]')
.replace(/([?&](?:token|key|secret|authorization)=)[^&\s]+/gi, '$1[redacted]')
.slice(0, 500);
throw new Error(`PushPlus reported failed webhook delivery: ${detail}`);
}
if (attempt < 20) await sleep(2_000);
}
throw new Error('Timed out waiting for PushPlus webhook delivery');
}
main().catch(error => {
console.error(error.message);
process.exit(1);
});
NODE
- name: Send production webhook-to-Telegram smoke message
if: always()
env:
TEST_SOURCE_ID: delivery-smoke-${{ github.run_id }}-${{ github.run_attempt }}
run: |
node <<'NODE'
async function main() {
const response = await fetch(process.env.PUSHPLUS_WEBHOOK_URL, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({
shortCode: process.env.TEST_SOURCE_ID,
title: '短信转发',
content: [
'PushPlus 到 Telegram 生产链路诊断消息',
'发件号码: DIAGNOSTIC',
`发件时间: ${new Date().toISOString()}`,
'#SMS',
].join('\n'),
}),
});
const body = await response.text();
if (!response.ok) throw new Error(`Production webhook smoke failed: HTTP ${response.status}`);
const data = JSON.parse(body);
if (data.code !== 200) throw new Error('Production webhook smoke returned a non-success response');
console.log('Production webhook accepted the message and Telegram sendMessage succeeded.');
}
main().catch(error => {
console.error(error.message);
process.exit(1);
});
NODE