From 26bac99f2413a608492e11eee9599d3580f88bf4 Mon Sep 17 00:00:00 2001 From: cwxia0s Date: Tue, 24 Dec 2024 20:55:15 +0800 Subject: [PATCH] feat: Add Batch Push --- README.md | 3 +++ README.zh.md | 3 +++ main.js | 61 ++++++++++++++++++++++++++++++++++++++++------------ main_kv.js | 60 ++++++++++++++++++++++++++++++++++++++++----------- test.sh | 60 +++++++++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 158 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 487145e..7795543 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,9 @@ English | **[中文文档](README.zh.md)** > [!NOTE] > Device token may change, the previous way to use multi-key or key alias may be unavailable, refer to [Tips](doc/tips.md) for more details. +> [!NOTE] +> Batch Push has the highest priority, if `device_keys` is specified and not empty, `device_key` will be ignored, in both V1 and V2 APIs. + diff --git a/README.zh.md b/README.zh.md index 8467fa8..6826dc6 100644 --- a/README.zh.md +++ b/README.zh.md @@ -12,6 +12,9 @@ > [!NOTE] > Device token可能发生变化, 之前使用多Key或Key别名的方法可能会失效, 如有多Key使用需要参考[Tips](doc/tips.zh.md). +> [!NOTE] +> 批量推送有最高优先级, 如果指定了`device_keys`且不为空, `device_key`将被忽略. + diff --git a/main.js b/main.js index 01cb8e9..3917849 100644 --- a/main.js +++ b/main.js @@ -14,9 +14,9 @@ const rootPath = '/' const basicAuth = '' async function handleRequest(request, env, ctx) { - const { searchParams, pathname } = new URL(request.url) + const {searchParams, pathname} = new URL(request.url) const handler = new Handler(env) - const realPathname = pathname.replace((new RegExp('^'+rootPath.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"))), '/') + const realPathname = pathname.replace((new RegExp('^' + rootPath.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"))), '/') switch (realPathname) { case "/register": { @@ -76,10 +76,13 @@ async function handleRequest(request, env, ctx) { requestBody.body = pathParts[4] } } - } catch (err) { + if (requestBody.device_keys && typeof requestBody.device_keys === 'string') { + requestBody.device_keys = requestBody.device_keys.split(',').map(item => item.trim()) + } + } catch (error) { return new Response(JSON.stringify({ 'code': 400, - 'message': `request bind failed: ${err}`, + 'message': `request bind failed: ${error}`, 'timestamp': util.getTimestamp(), }), { status: 400, @@ -89,6 +92,36 @@ async function handleRequest(request, env, ctx) { }) } + if (requestBody.device_keys && requestBody.device_keys.length > 0) { + return new Response(JSON.stringify({ + 'code': 200, + 'message': 'success', + 'data': await Promise.all(requestBody.device_keys.map(async (device_key) => { + if (!device_key) { + return { + message: 'device key is empty', + code: 400, + device_key: device_key, + } + } + + const response = await handler.push({...requestBody, device_key}) + const responseBody = await response.json() + return { + message: responseBody.message, + code: response.status, + device_key: device_key, + } + })), + 'timestamp': util.getTimestamp(), + }), { + status: 200, + headers: { + 'content-type': 'application/json', + } + }) + } + if (realPathname != '/push') { requestBody.device_key = pathParts[1] } @@ -128,10 +161,10 @@ async function handleRequest(request, env, ctx) { */ class Handler { constructor(env) { - this.version = "v2.1.4" - this.build = "2024-12-16 18:27:31" + this.version = "v2.1.5" + this.build = "2024-12-24 20:46:57" this.arch = "js" - this.commit = "10d6f31e53bddb011290fffa7b7ede7dd7dec666" + this.commit = "157609b4732361a55f3bb1bb6eb7d5ac31d2a583" const db = new Database(env) @@ -141,8 +174,8 @@ class Handler { if (!deviceToken) { return new Response(JSON.stringify({ - 'message': 'device token is empty', 'code': 400, + 'message': 'device token is empty', 'timestamp': util.getTimestamp(), }), { status: 400, @@ -157,8 +190,8 @@ class Handler { key = util.newShortUUID() } else { return new Response(JSON.stringify({ - 'message': "device registration failed: register disabled", 'code': 500, + 'message': "device registration failed: register disabled", }), { status: 500, headers: { @@ -171,8 +204,8 @@ class Handler { await db.saveDeviceTokenByKey(key, deviceToken) return new Response(JSON.stringify({ - 'message': 'success', 'code': 200, + 'message': 'success', 'timestamp': util.getTimestamp(), 'data': { 'key': key, @@ -189,8 +222,8 @@ class Handler { this.ping = async (parameters) => { return new Response(JSON.stringify({ - 'message': 'pong', 'code': 200, + 'message': 'pong', 'timestamp': util.getTimestamp(), }), { status: 200, @@ -333,8 +366,8 @@ class Handler { if (response.status === 200) { return new Response(JSON.stringify({ - 'message': 'success', 'code': 200, + 'message': 'success', 'timestamp': util.getTimestamp(), }), { status: 200, @@ -353,8 +386,8 @@ class Handler { } return new Response(JSON.stringify({ - 'message': `push failed: ${message}`, 'code': response.status, + 'message': `push failed: ${message}`, 'timestamp': util.getTimestamp(), }), { status: response.status, @@ -531,4 +564,4 @@ class Util { } } -const util = new Util() +const util = new Util() \ No newline at end of file diff --git a/main_kv.js b/main_kv.js index a02a2d5..942078e 100644 --- a/main_kv.js +++ b/main_kv.js @@ -14,9 +14,9 @@ const rootPath = '/' const basicAuth = '' async function handleRequest(request, env, ctx) { - const { searchParams, pathname } = new URL(request.url) + const {searchParams, pathname} = new URL(request.url) const handler = new Handler(env) - const realPathname = pathname.replace((new RegExp('^'+rootPath.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"))), '/') + const realPathname = pathname.replace((new RegExp('^' + rootPath.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"))), '/') switch (realPathname) { case "/register": { @@ -76,10 +76,13 @@ async function handleRequest(request, env, ctx) { requestBody.body = pathParts[4] } } - } catch (err) { + if (requestBody.device_keys && typeof requestBody.device_keys === 'string') { + requestBody.device_keys = requestBody.device_keys.split(',').map(item => item.trim()) + } + } catch (error) { return new Response(JSON.stringify({ 'code': 400, - 'message': `request bind failed: ${err}`, + 'message': `request bind failed: ${error}`, 'timestamp': util.getTimestamp(), }), { status: 400, @@ -89,6 +92,36 @@ async function handleRequest(request, env, ctx) { }) } + if (requestBody.device_keys && requestBody.device_keys.length > 0) { + return new Response(JSON.stringify({ + 'code': 200, + 'message': 'success', + 'data': await Promise.all(requestBody.device_keys.map(async (device_key) => { + if (!device_key) { + return { + message: 'device key is empty', + code: 400, + device_key: device_key, + } + } + + const response = await handler.push({...requestBody, device_key}) + const responseBody = await response.json() + return { + message: responseBody.message, + code: response.status, + device_key: device_key, + } + })), + 'timestamp': util.getTimestamp(), + }), { + status: 200, + headers: { + 'content-type': 'application/json', + } + }) + } + if (realPathname != '/push') { requestBody.device_key = pathParts[1] } @@ -128,10 +161,10 @@ async function handleRequest(request, env, ctx) { */ class Handler { constructor(env) { - this.version = "v2.1.4" - this.build = "2024-12-16 18:27:31" + this.version = "v2.1.5" + this.build = "2024-12-24 20:46:57" this.arch = "js" - this.commit = "10d6f31e53bddb011290fffa7b7ede7dd7dec666" + this.commit = "157609b4732361a55f3bb1bb6eb7d5ac31d2a583" const db = new Database(env) @@ -141,8 +174,8 @@ class Handler { if (!deviceToken) { return new Response(JSON.stringify({ - 'message': 'device token is empty', 'code': 400, + 'message': 'device token is empty', 'timestamp': util.getTimestamp(), }), { status: 400, @@ -157,8 +190,8 @@ class Handler { key = util.newShortUUID() } else { return new Response(JSON.stringify({ - 'message': "device registration failed: register disabled", 'code': 500, + 'message': "device registration failed: register disabled", }), { status: 500, headers: { @@ -171,8 +204,8 @@ class Handler { await db.saveDeviceTokenByKey(key, deviceToken) return new Response(JSON.stringify({ - 'message': 'success', 'code': 200, + 'message': 'success', 'timestamp': util.getTimestamp(), 'data': { 'key': key, @@ -189,8 +222,8 @@ class Handler { this.ping = async (parameters) => { return new Response(JSON.stringify({ - 'message': 'pong', 'code': 200, + 'message': 'pong', 'timestamp': util.getTimestamp(), }), { status: 200, @@ -333,8 +366,8 @@ class Handler { if (response.status === 200) { return new Response(JSON.stringify({ - 'message': 'success', 'code': 200, + 'message': 'success', 'timestamp': util.getTimestamp(), }), { status: 200, @@ -353,8 +386,8 @@ class Handler { } return new Response(JSON.stringify({ - 'message': `push failed: ${message}`, 'code': response.status, + 'message': `push failed: ${message}`, 'timestamp': util.getTimestamp(), }), { status: response.status, @@ -470,6 +503,7 @@ class Database { } } + /** * Class Util */ diff --git a/test.sh b/test.sh index 97a3488..070a66d 100644 --- a/test.sh +++ b/test.sh @@ -5,6 +5,10 @@ DEVICE_KEY="" BAD_DEVICE_KEY="" INVALID_DEVICE_KEY="" +BATCH_PUSH_KEY_1="" +BATCH_PUSH_KEY_2=$DEVICE_KEY +BATCH_PUSH_KEY_3=$BAD_DEVICE_KEY + DEVICE_TOKEN="0000test0device0token0000" echo -e "\e[1;32m" @@ -30,8 +34,6 @@ curl -X "POST" "$SERVER_ADDRESS/$DEVICE_KEY" \ "isArchive": "0" }' -# Seems that icon is not compatible with subtitle - echo "" curl -X "POST" "$SERVER_ADDRESS/push" \ @@ -100,6 +102,36 @@ echo $ciphertext # URL encoding the ciphertext, there may be special characters. curl --data-urlencode "ciphertext=$ciphertext" $SERVER_ADDRESS/$DEVICE_KEY?isArchive=0 +echo -e "\e[1;32m" +echo "" +echo "---------------------------------------------------------------------" +echo "Test Batch Push" +echo "---------------------------------------------------------------------" +echo "" +echo -e "\e[0m" + +curl -X "POST" "$SERVER_ADDRESS/push" \ + -H 'Content-Type: application/json; charset=utf-8' \ + -d $'{ + "body": "Test Batch Message In Body", + "group": "testBatchPush", + "url": "https://mritd.com", + "isArchive": "0", + "device_keys": ["'$BATCH_PUSH_KEY_1'", "'$BATCH_PUSH_KEY_2'", "'$BATCH_PUSH_KEY_3'"] +}' + +echo "" + +curl -X "POST" "$SERVER_ADDRESS/push" \ + -H 'Content-Type: application/json; charset=utf-8' \ + -d $'{ + "body": "Test Batch Message In Body", + "group": "testBatchPush", + "url": "https://mritd.com", + "isArchive": "0", + "device_keys": "'$BATCH_PUSH_KEY_1','$BATCH_PUSH_KEY_2','$BATCH_PUSH_KEY_3'" +}' + echo -e "\e[1;32m" echo "" echo "---------------------------------------------------------------------" @@ -163,4 +195,28 @@ echo -e "\e[0m" curl "$SERVER_ADDRESS/push" +echo "" + +curl -X "POST" "$SERVER_ADDRESS/push" \ + -H 'Content-Type: application/json; charset=utf-8' \ + -d $'{ + "body": "Test Batch Message In Body", + "group": "testBatchPush", + "url": "https://mritd.com", + "isArchive": "0", + "device_keys": ",," +}' + +echo "" + +curl -X "POST" "$SERVER_ADDRESS/push" \ + -H 'Content-Type: application/json; charset=utf-8' \ + -d $'{ + "body": "Test Batch Message In Body", + "group": "testBatchPush", + "url": "https://mritd.com", + "isArchive": "0", + "device_keys": [] +}' + echo "" \ No newline at end of file