From 2f70f0fcca770d65dd223fa22caae9f76b086dcc Mon Sep 17 00:00:00 2001 From: master Date: Thu, 21 Mar 2024 19:31:21 +0800 Subject: [PATCH] add test case of common.mjs --- README.md | 18 ++--------------- common.mjs | 47 ++++++++++++++++++++++++++++++++++++++++++++ heroUnion.mjs | 36 +++++++++++++++++++++++++++++++-- test/common.test.mjs | 34 ++++++++++++++++++++++++++++++++ test/package.json | 16 +++++++++++++++ 5 files changed, 133 insertions(+), 18 deletions(-) create mode 100644 common.mjs create mode 100644 test/common.test.mjs create mode 100644 test/package.json diff --git a/README.md b/README.md index 03b950e..28c4192 100644 --- a/README.md +++ b/README.md @@ -143,7 +143,7 @@ https://herounion.filesite.io/api/stats/ ## 接口参数签名方法 -将所有参数按字母排序之后拼接成GET请求字符串,最后再拼接上token计算MD5值。 +将所有参数按字母排序之后转换成JSON字符串,最后再拼接上token计算MD5值。 示例如下: ``` @@ -161,24 +161,10 @@ var sortObj = function(obj) { //参数排序方法 }, {}); }; -var joinObj = function(obj, glue, separator) { //参数拼接方法 - if (typeof(glue) == 'undefined') { - glue = '='; - } - - if (typeof(separator) == 'undefined') { - separator = '&'; - } - - return Object.keys(obj).map(function(key) { - return [key, obj[key]].join(glue); - }).join(separator); -}; - //1. 排序参数 var sortedParams = sortObj(params); //2. 计算MD5值 -var sign = md5( joinObj(sortedParams, '=', '&') + token ); +var sign = md5( JSON.stringify(sortedParams) + token ); ``` diff --git a/common.mjs b/common.mjs new file mode 100644 index 0000000..0dba365 --- /dev/null +++ b/common.mjs @@ -0,0 +1,47 @@ +/** + * 公用方法 + */ + +import fs from 'node:fs'; +import { readdir, readFile } from 'node:fs/promises'; +import md5 from 'md5'; + +class Common { + + sortDict(obj) { //dict按key排序 + return Object.keys(obj).sort().reduce(function (result, key) { + result[key] = obj[key]; + return result; + }, {}); + } + + joinDict(obj, glue, separator) { //dict拼接成字符串 + if (typeof(glue) == 'undefined') { + glue = '='; + } + + if (typeof(separator) == 'undefined') { + separator = '&'; + } + + return Object.keys(obj).map(function(key) { + let arr = [key]; + let val = obj[key]; + if (typeof(val) == 'string' || typeof(val) == 'number') { + arr.push(val); + }else if (typeof(val) == 'object') { + arr.push(JSON.stringify(val)); + } + + return arr.join(glue); + }).join(separator); + } + + sign(params, token) { //对参数做MD5签名 + return md5( JSON.stringify(this.sortDict(params)) + token ); + } + +} + +let commonFuns = new Common(); +export default commonFuns; \ No newline at end of file diff --git a/heroUnion.mjs b/heroUnion.mjs index 3af0b38..3fe45f4 100644 --- a/heroUnion.mjs +++ b/heroUnion.mjs @@ -20,6 +20,8 @@ import fs from 'node:fs'; import { readdir, readFile } from 'node:fs/promises'; import path from 'node:path'; import cron from 'node-cron'; +import axios from 'axios'; +import common from './common.mjs'; class HeroUnion { @@ -29,6 +31,7 @@ class HeroUnion { //this.task_data_dir = path.resolve('./tmp/data/'); //任务数据保存目录 this.task_cache_time = 86400; //任务数据最长缓存时间,单位:秒 this.task_data_max_size = 1024; //任务数据最大字节数,单位:KB + this.notify_timeout = 8; //回调通知请求超时时长,单位:秒 this.stats = {}; @@ -210,10 +213,39 @@ class HeroUnion { return this.tasks.find((item) => item.id == id); } + //TODO: 根据uuid获取用户的签名密钥 + getUserToken(uuid) { + return 'token'; + } + //任务完成触发回调通知 - async handleTaskDone() { - //当任务完成回传回来的时候调用此方法触发回调通知 + async handleTaskDone(id) { + let notified = false; + + let task = this.getTaskById(id); + let notify_url = task.notify_url; + + try { + if (notify_url && /^http(s)?:\/\/[\w\.]+/i.test(notify_url)) { + let params = { + "task_id": task.id, + "task_result": task.results, + "timestamp": this.getTimestamp(), + }; + params.sign = common.sign(params, this.getUserToken(task.uuid)); + const response = await axios.post(notify_url, params, {timeout: this.notify_timeout*1000}); + if (response.status == 200) { + notified = true; + }else { + console.error('Notify to %s failed, response status: %s, status text: %s, result: %s', + notify_url, response.status, response.statusText, response.daa); + } + } + }catch(err) { + console.error('Notify to %s failed: %s', notify_url, err); + } + return notified; } diff --git a/test/common.test.mjs b/test/common.test.mjs new file mode 100644 index 0000000..5566729 --- /dev/null +++ b/test/common.test.mjs @@ -0,0 +1,34 @@ +/** + * Common公用方法测试用例 + */ + +import test from 'node:test'; +import assert from 'node:assert'; +import common from '../common.mjs'; + + +test('Common function sortDict test', (t) => { + let params = { + b: 2, + a: 1 + }; + + const expectRes = { + a: 1, + b: 2 + }; + + assert.deepEqual(common.sortDict(params), expectRes); +}); + +test('Common function joinDict test', (t) => { + let params = { + b: 2, + a: 1 + }; + + const expectRes = "a=1&b=2"; + + assert.strictEqual(common.joinDict(common.sortDict(params)), expectRes); +}); + diff --git a/test/package.json b/test/package.json new file mode 100644 index 0000000..fa4e3ae --- /dev/null +++ b/test/package.json @@ -0,0 +1,16 @@ +{ + "name": "Hero Union Test", + "version": "0.1", + "author": "filesite.io", + "type": "module", + "dependencies": { + "axios": "^1.3.3", + "body-parser": "^1.20.1", + "express": "^4.18.2", + "md5": "^2.3.0", + "node-cron": "^3.0.2" + }, + "scripts": { + "test": "node common.test.mjs" + } +}