woodenfish-bot 4.4.5 → 4.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/es/index.js +180 -103
- package/lib/index.js +180 -103
- package/package.json +1 -1
package/es/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import _defineProperty from '@babel/runtime/helpers/defineProperty';
|
|
|
5
5
|
import _regeneratorRuntime from '@babel/runtime/regenerator';
|
|
6
6
|
import resty from 'resty-client';
|
|
7
7
|
import _typeof from '@babel/runtime/helpers/typeof';
|
|
8
|
+
import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
|
|
8
9
|
import fs from 'fs';
|
|
9
10
|
import https from 'https';
|
|
10
11
|
import _possibleConstructorReturn from '@babel/runtime/helpers/possibleConstructorReturn';
|
|
@@ -297,7 +298,7 @@ var Guild = /*#__PURE__*/function () {
|
|
|
297
298
|
}]);
|
|
298
299
|
}();
|
|
299
300
|
|
|
300
|
-
var version = "4.4.
|
|
301
|
+
var version = "4.4.6";
|
|
301
302
|
|
|
302
303
|
function getDefaultExportFromCjs (x) {
|
|
303
304
|
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
@@ -677,9 +678,45 @@ log.setLevel('info');
|
|
|
677
678
|
log.setLevel('trace');
|
|
678
679
|
var BotLogger = log;
|
|
679
680
|
|
|
681
|
+
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: true } : { done: false, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = true, u = false; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = true, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
|
|
682
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
683
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
684
|
+
|
|
680
685
|
// 全局token刷新锁,避免并发刷新
|
|
681
686
|
var tokenRefreshPromises = new Map();
|
|
682
687
|
|
|
688
|
+
// 定期清理可能遗留的Promise(防止内存泄漏)
|
|
689
|
+
setInterval(function () {
|
|
690
|
+
var now = Date.now();
|
|
691
|
+
var keysToDelete = [];
|
|
692
|
+
var _iterator = _createForOfIteratorHelper(tokenRefreshPromises.entries()),
|
|
693
|
+
_step;
|
|
694
|
+
try {
|
|
695
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
696
|
+
var _step$value = _slicedToArray(_step.value, 2),
|
|
697
|
+
key = _step$value[0],
|
|
698
|
+
_step$value$ = _step$value[1],
|
|
699
|
+
promise = _step$value$.promise,
|
|
700
|
+
timestamp = _step$value$.timestamp;
|
|
701
|
+
// 如果Promise已经存在超过5分钟,可能出现了问题,清理掉
|
|
702
|
+
if (now - timestamp > 5 * 60 * 1000) {
|
|
703
|
+
keysToDelete.push(key);
|
|
704
|
+
console.warn("\u6E05\u7406\u8D85\u65F6\u7684token\u5237\u65B0Promise (key: ".concat(key, ", \u5B58\u5728\u65F6\u95F4: ").concat((now - timestamp) / 1000, "s)"));
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
} catch (err) {
|
|
708
|
+
_iterator.e(err);
|
|
709
|
+
} finally {
|
|
710
|
+
_iterator.f();
|
|
711
|
+
}
|
|
712
|
+
keysToDelete.forEach(function (key) {
|
|
713
|
+
return tokenRefreshPromises["delete"](key);
|
|
714
|
+
});
|
|
715
|
+
if (keysToDelete.length > 0) {
|
|
716
|
+
console.log("\u6E05\u7406\u4E86 ".concat(keysToDelete.length, " \u4E2A\u8D85\u65F6\u7684token\u5237\u65B0Promise"));
|
|
717
|
+
}
|
|
718
|
+
}, 60000); // 每分钟清理一次
|
|
719
|
+
|
|
683
720
|
// 转为对象
|
|
684
721
|
var toObject = function toObject(data) {
|
|
685
722
|
if (Buffer.isBuffer(data)) return JSON.parse(data.toString());
|
|
@@ -758,150 +795,190 @@ function getAccessToken(access_token_file, url, data, appID) {
|
|
|
758
795
|
});
|
|
759
796
|
}
|
|
760
797
|
|
|
761
|
-
//
|
|
798
|
+
// 等待Promise完成,带超时机制
|
|
799
|
+
var waitForPromiseWithTimeout = /*#__PURE__*/function () {
|
|
800
|
+
var _ref = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee(promise) {
|
|
801
|
+
var timeoutMs,
|
|
802
|
+
timeoutPromise,
|
|
803
|
+
_args = arguments;
|
|
804
|
+
return _regeneratorRuntime.wrap(function (_context) {
|
|
805
|
+
while (1) switch (_context.prev = _context.next) {
|
|
806
|
+
case 0:
|
|
807
|
+
timeoutMs = _args.length > 1 && _args[1] !== undefined ? _args[1] : 10000;
|
|
808
|
+
timeoutPromise = new Promise(function (_, reject) {
|
|
809
|
+
setTimeout(function () {
|
|
810
|
+
return reject(new Error("Token refresh timeout after ".concat(timeoutMs, "ms")));
|
|
811
|
+
}, timeoutMs);
|
|
812
|
+
});
|
|
813
|
+
return _context.abrupt("return", Promise.race([promise, timeoutPromise]));
|
|
814
|
+
case 1:
|
|
815
|
+
case "end":
|
|
816
|
+
return _context.stop();
|
|
817
|
+
}
|
|
818
|
+
}, _callee);
|
|
819
|
+
}));
|
|
820
|
+
return function waitForPromiseWithTimeout(_x) {
|
|
821
|
+
return _ref.apply(this, arguments);
|
|
822
|
+
};
|
|
823
|
+
}();
|
|
824
|
+
|
|
825
|
+
// 获取或刷新token(带并发控制和超时保护)
|
|
762
826
|
var getOrRefreshToken = /*#__PURE__*/function () {
|
|
763
|
-
var
|
|
764
|
-
var key,
|
|
765
|
-
return _regeneratorRuntime.wrap(function (
|
|
766
|
-
while (1) switch (
|
|
827
|
+
var _ref2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3(appID, clientSecret) {
|
|
828
|
+
var now_time, url, data, access_token_file, access_token, expires_in, needsRefresh, access_token_json, expiresStr, parsed, default_token_json, key, existingEntry, refreshPromise, _t2;
|
|
829
|
+
return _regeneratorRuntime.wrap(function (_context3) {
|
|
830
|
+
while (1) switch (_context3.prev = _context3.next) {
|
|
767
831
|
case 0:
|
|
832
|
+
now_time = getTimeStampNumber();
|
|
833
|
+
url = 'https://bots.qq.com/app/getAppAccessToken';
|
|
834
|
+
data = {
|
|
835
|
+
appId: appID,
|
|
836
|
+
clientSecret: clientSecret
|
|
837
|
+
};
|
|
838
|
+
access_token_file = './access_token.json';
|
|
839
|
+
access_token = '';
|
|
840
|
+
expires_in = 0;
|
|
841
|
+
needsRefresh = false; // 首先读取当前token状态
|
|
842
|
+
try {
|
|
843
|
+
if (fs.existsSync(access_token_file)) {
|
|
844
|
+
access_token_json = JSON.parse(fs.readFileSync(access_token_file).toString());
|
|
845
|
+
if (access_token_json.hasOwnProperty('bot') && access_token_json['bot'].hasOwnProperty(appID)) {
|
|
846
|
+
access_token = access_token_json['bot'][appID]['access_token'];
|
|
847
|
+
expiresStr = access_token_json['bot'][appID]['expires_in'];
|
|
848
|
+
if (expiresStr && typeof expiresStr === 'string') {
|
|
849
|
+
parsed = parseInt(expiresStr);
|
|
850
|
+
if (!isNaN(parsed) && parsed > 0) {
|
|
851
|
+
expires_in = parsed;
|
|
852
|
+
} else {
|
|
853
|
+
console.log('expires_in解析失败,重置为0:', expiresStr);
|
|
854
|
+
expires_in = 0;
|
|
855
|
+
}
|
|
856
|
+
} else {
|
|
857
|
+
expires_in = 0;
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
} else {
|
|
861
|
+
default_token_json = {
|
|
862
|
+
bot: _defineProperty({}, appID, {
|
|
863
|
+
access_token: "",
|
|
864
|
+
expires_in: ""
|
|
865
|
+
})
|
|
866
|
+
};
|
|
867
|
+
fs.writeFileSync(access_token_file, JSON.stringify(default_token_json, null, 2), 'utf-8');
|
|
868
|
+
needsRefresh = true;
|
|
869
|
+
}
|
|
870
|
+
} catch (err) {
|
|
871
|
+
console.error('读取文件时发生错误:', err);
|
|
872
|
+
expires_in = 0;
|
|
873
|
+
needsRefresh = true;
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
// 如果token有效且不需要刷新,直接返回
|
|
877
|
+
if (!(access_token !== '' && now_time <= expires_in - 50 && !needsRefresh)) {
|
|
878
|
+
_context3.next = 1;
|
|
879
|
+
break;
|
|
880
|
+
}
|
|
881
|
+
return _context3.abrupt("return", access_token);
|
|
882
|
+
case 1:
|
|
883
|
+
// 需要刷新token,进入并发控制逻辑
|
|
768
884
|
key = "".concat(appID, ":").concat(clientSecret);
|
|
769
|
-
|
|
770
|
-
if (!
|
|
771
|
-
|
|
885
|
+
existingEntry = tokenRefreshPromises.get(key);
|
|
886
|
+
if (!existingEntry) {
|
|
887
|
+
_context3.next = 5;
|
|
772
888
|
break;
|
|
773
889
|
}
|
|
774
|
-
|
|
890
|
+
_context3.prev = 2;
|
|
891
|
+
// 等待已有的刷新完成,但设置超时防止无限等待
|
|
775
892
|
console.log("\u7B49\u5F85\u5DF2\u6709\u7684token\u5237\u65B0\u5B8C\u6210 (appID: ".concat(appID, ")"));
|
|
776
|
-
|
|
777
|
-
return
|
|
778
|
-
case
|
|
779
|
-
return
|
|
780
|
-
case
|
|
893
|
+
_context3.next = 3;
|
|
894
|
+
return waitForPromiseWithTimeout(existingEntry.promise, 10000);
|
|
895
|
+
case 3:
|
|
896
|
+
return _context3.abrupt("return", _context3.sent);
|
|
897
|
+
case 4:
|
|
898
|
+
_context3.prev = 4;
|
|
899
|
+
_t2 = _context3["catch"](2);
|
|
900
|
+
console.warn("\u7B49\u5F85token\u5237\u65B0\u8D85\u65F6\u6216\u5931\u8D25\uFF0C\u91CD\u65B0\u53D1\u8D77\u5237\u65B0 (appID: ".concat(appID, "):"), _t2);
|
|
901
|
+
// 移除失败的Promise,让新的请求可以重新发起刷新
|
|
902
|
+
tokenRefreshPromises["delete"](key);
|
|
903
|
+
case 5:
|
|
781
904
|
// 创建新的刷新Promise
|
|
782
|
-
refreshPromise = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function
|
|
783
|
-
var
|
|
784
|
-
return _regeneratorRuntime.wrap(function (
|
|
785
|
-
while (1) switch (
|
|
905
|
+
refreshPromise = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
|
|
906
|
+
var new_token, _t;
|
|
907
|
+
return _regeneratorRuntime.wrap(function (_context2) {
|
|
908
|
+
while (1) switch (_context2.prev = _context2.next) {
|
|
786
909
|
case 0:
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
data = {
|
|
791
|
-
appId: appID,
|
|
792
|
-
clientSecret: clientSecret
|
|
793
|
-
};
|
|
794
|
-
access_token_file = './access_token.json';
|
|
795
|
-
access_token = '';
|
|
796
|
-
expires_in = 0;
|
|
797
|
-
needsRefresh = false;
|
|
798
|
-
try {
|
|
799
|
-
// 判断文件是否存在
|
|
800
|
-
if (fs.existsSync(access_token_file)) {
|
|
801
|
-
// 执行文件存在时的处理逻辑
|
|
802
|
-
access_token_json = JSON.parse(fs.readFileSync(access_token_file).toString()); // 判断是否存在appID
|
|
803
|
-
if (access_token_json.hasOwnProperty('bot') && access_token_json['bot'].hasOwnProperty(appID)) {
|
|
804
|
-
access_token = access_token_json['bot'][appID]['access_token'];
|
|
805
|
-
expiresStr = access_token_json['bot'][appID]['expires_in']; // 改进expires_in解析,防止NaN
|
|
806
|
-
if (expiresStr && typeof expiresStr === 'string') {
|
|
807
|
-
parsed = parseInt(expiresStr);
|
|
808
|
-
if (!isNaN(parsed) && parsed > 0) {
|
|
809
|
-
expires_in = parsed;
|
|
810
|
-
} else {
|
|
811
|
-
console.log('expires_in解析失败,重置为0:', expiresStr);
|
|
812
|
-
expires_in = 0;
|
|
813
|
-
}
|
|
814
|
-
} else {
|
|
815
|
-
expires_in = 0;
|
|
816
|
-
}
|
|
817
|
-
}
|
|
818
|
-
} else {
|
|
819
|
-
// 执行文件不存在时的处理逻辑
|
|
820
|
-
default_token_json = {
|
|
821
|
-
bot: _defineProperty({}, appID, {
|
|
822
|
-
access_token: "",
|
|
823
|
-
expires_in: ""
|
|
824
|
-
})
|
|
825
|
-
};
|
|
826
|
-
fs.writeFileSync(access_token_file, JSON.stringify(default_token_json, null, 2), 'utf-8');
|
|
827
|
-
needsRefresh = true;
|
|
828
|
-
}
|
|
829
|
-
} catch (err) {
|
|
830
|
-
console.error('读取文件时发生错误:', err);
|
|
831
|
-
// 出错时重置expires_in为0,强制重新获取token
|
|
832
|
-
expires_in = 0;
|
|
833
|
-
needsRefresh = true;
|
|
834
|
-
}
|
|
835
|
-
|
|
836
|
-
// 判断是否需要刷新token
|
|
837
|
-
if (!(access_token === '' || now_time > expires_in - 50 || needsRefresh)) {
|
|
838
|
-
_context.next = 2;
|
|
839
|
-
break;
|
|
840
|
-
}
|
|
841
|
-
console.log('检测到access_token需要刷新 - 当前token:', access_token, '过期时间:', expires_in, '当前时间:', now_time);
|
|
842
|
-
_context.next = 1;
|
|
910
|
+
_context2.prev = 0;
|
|
911
|
+
console.log('开始刷新access_token - 当前token:', access_token, '过期时间:', expires_in, '当前时间:', now_time);
|
|
912
|
+
_context2.next = 1;
|
|
843
913
|
return getAccessToken(access_token_file, url, data, appID);
|
|
844
914
|
case 1:
|
|
845
|
-
|
|
846
|
-
console.log('access_token刷新成功,新token:',
|
|
915
|
+
new_token = _context2.sent;
|
|
916
|
+
console.log('access_token刷新成功,新token:', new_token);
|
|
917
|
+
return _context2.abrupt("return", new_token);
|
|
847
918
|
case 2:
|
|
848
|
-
|
|
919
|
+
_context2.prev = 2;
|
|
920
|
+
_t = _context2["catch"](0);
|
|
921
|
+
console.error("Token\u5237\u65B0\u5931\u8D25 (appID: ".concat(appID, "):"), _t);
|
|
922
|
+
throw _t;
|
|
849
923
|
case 3:
|
|
850
|
-
|
|
924
|
+
_context2.prev = 3;
|
|
851
925
|
// 刷新完成后移除Promise
|
|
852
926
|
tokenRefreshPromises["delete"](key);
|
|
853
|
-
return
|
|
927
|
+
return _context2.finish(3);
|
|
854
928
|
case 4:
|
|
855
929
|
case "end":
|
|
856
|
-
return
|
|
930
|
+
return _context2.stop();
|
|
857
931
|
}
|
|
858
|
-
},
|
|
859
|
-
}))(); // 存储Promise
|
|
860
|
-
tokenRefreshPromises.set(key,
|
|
861
|
-
|
|
932
|
+
}, _callee2, null, [[0, 2, 3, 4]]);
|
|
933
|
+
}))(); // 存储Promise和时间戳以便其他并发请求使用和超时清理
|
|
934
|
+
tokenRefreshPromises.set(key, {
|
|
935
|
+
promise: refreshPromise,
|
|
936
|
+
timestamp: Date.now()
|
|
937
|
+
});
|
|
938
|
+
_context3.next = 6;
|
|
862
939
|
return refreshPromise;
|
|
863
|
-
case
|
|
864
|
-
return
|
|
865
|
-
case
|
|
940
|
+
case 6:
|
|
941
|
+
return _context3.abrupt("return", _context3.sent);
|
|
942
|
+
case 7:
|
|
866
943
|
case "end":
|
|
867
|
-
return
|
|
944
|
+
return _context3.stop();
|
|
868
945
|
}
|
|
869
|
-
},
|
|
946
|
+
}, _callee3, null, [[2, 4]]);
|
|
870
947
|
}));
|
|
871
|
-
return function getOrRefreshToken(
|
|
872
|
-
return
|
|
948
|
+
return function getOrRefreshToken(_x2, _x3) {
|
|
949
|
+
return _ref2.apply(this, arguments);
|
|
873
950
|
};
|
|
874
951
|
}();
|
|
875
952
|
|
|
876
953
|
// 添加 User-Agent
|
|
877
954
|
var addAuthorization = /*#__PURE__*/function () {
|
|
878
|
-
var
|
|
955
|
+
var _ref4 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee4(header, appID, token, clientSecret, apiVersion) {
|
|
879
956
|
var access_token;
|
|
880
|
-
return _regeneratorRuntime.wrap(function (
|
|
881
|
-
while (1) switch (
|
|
957
|
+
return _regeneratorRuntime.wrap(function (_context4) {
|
|
958
|
+
while (1) switch (_context4.prev = _context4.next) {
|
|
882
959
|
case 0:
|
|
883
960
|
if (!(apiVersion == 'v2')) {
|
|
884
|
-
|
|
961
|
+
_context4.next = 2;
|
|
885
962
|
break;
|
|
886
963
|
}
|
|
887
|
-
|
|
964
|
+
_context4.next = 1;
|
|
888
965
|
return getOrRefreshToken(appID, clientSecret);
|
|
889
966
|
case 1:
|
|
890
|
-
access_token =
|
|
967
|
+
access_token = _context4.sent;
|
|
891
968
|
// 更新header['Authorization']
|
|
892
969
|
header['Authorization'] = "QQBot ".concat(access_token);
|
|
893
|
-
|
|
970
|
+
_context4.next = 3;
|
|
894
971
|
break;
|
|
895
972
|
case 2:
|
|
896
973
|
header['Authorization'] = "Bot ".concat(appID, ".").concat(token);
|
|
897
974
|
case 3:
|
|
898
975
|
case "end":
|
|
899
|
-
return
|
|
976
|
+
return _context4.stop();
|
|
900
977
|
}
|
|
901
|
-
},
|
|
978
|
+
}, _callee4);
|
|
902
979
|
}));
|
|
903
|
-
return function addAuthorization(
|
|
904
|
-
return
|
|
980
|
+
return function addAuthorization(_x4, _x5, _x6, _x7, _x8) {
|
|
981
|
+
return _ref4.apply(this, arguments);
|
|
905
982
|
};
|
|
906
983
|
}();
|
|
907
984
|
// 组装完整Url
|
package/lib/index.js
CHANGED
|
@@ -7,6 +7,7 @@ var _defineProperty = require('@babel/runtime/helpers/defineProperty');
|
|
|
7
7
|
var _regeneratorRuntime = require('@babel/runtime/regenerator');
|
|
8
8
|
var resty = require('resty-client');
|
|
9
9
|
var _typeof = require('@babel/runtime/helpers/typeof');
|
|
10
|
+
var _slicedToArray = require('@babel/runtime/helpers/slicedToArray');
|
|
10
11
|
var fs = require('fs');
|
|
11
12
|
var https = require('https');
|
|
12
13
|
var _possibleConstructorReturn = require('@babel/runtime/helpers/possibleConstructorReturn');
|
|
@@ -299,7 +300,7 @@ var Guild = /*#__PURE__*/function () {
|
|
|
299
300
|
}]);
|
|
300
301
|
}();
|
|
301
302
|
|
|
302
|
-
var version = "4.4.
|
|
303
|
+
var version = "4.4.6";
|
|
303
304
|
|
|
304
305
|
function getDefaultExportFromCjs (x) {
|
|
305
306
|
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
@@ -679,9 +680,45 @@ log.setLevel('info');
|
|
|
679
680
|
log.setLevel('trace');
|
|
680
681
|
var BotLogger = log;
|
|
681
682
|
|
|
683
|
+
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: true } : { done: false, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = true, u = false; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = true, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
|
|
684
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
685
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
686
|
+
|
|
682
687
|
// 全局token刷新锁,避免并发刷新
|
|
683
688
|
var tokenRefreshPromises = new Map();
|
|
684
689
|
|
|
690
|
+
// 定期清理可能遗留的Promise(防止内存泄漏)
|
|
691
|
+
setInterval(function () {
|
|
692
|
+
var now = Date.now();
|
|
693
|
+
var keysToDelete = [];
|
|
694
|
+
var _iterator = _createForOfIteratorHelper(tokenRefreshPromises.entries()),
|
|
695
|
+
_step;
|
|
696
|
+
try {
|
|
697
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
698
|
+
var _step$value = _slicedToArray(_step.value, 2),
|
|
699
|
+
key = _step$value[0],
|
|
700
|
+
_step$value$ = _step$value[1],
|
|
701
|
+
promise = _step$value$.promise,
|
|
702
|
+
timestamp = _step$value$.timestamp;
|
|
703
|
+
// 如果Promise已经存在超过5分钟,可能出现了问题,清理掉
|
|
704
|
+
if (now - timestamp > 5 * 60 * 1000) {
|
|
705
|
+
keysToDelete.push(key);
|
|
706
|
+
console.warn("\u6E05\u7406\u8D85\u65F6\u7684token\u5237\u65B0Promise (key: ".concat(key, ", \u5B58\u5728\u65F6\u95F4: ").concat((now - timestamp) / 1000, "s)"));
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
} catch (err) {
|
|
710
|
+
_iterator.e(err);
|
|
711
|
+
} finally {
|
|
712
|
+
_iterator.f();
|
|
713
|
+
}
|
|
714
|
+
keysToDelete.forEach(function (key) {
|
|
715
|
+
return tokenRefreshPromises["delete"](key);
|
|
716
|
+
});
|
|
717
|
+
if (keysToDelete.length > 0) {
|
|
718
|
+
console.log("\u6E05\u7406\u4E86 ".concat(keysToDelete.length, " \u4E2A\u8D85\u65F6\u7684token\u5237\u65B0Promise"));
|
|
719
|
+
}
|
|
720
|
+
}, 60000); // 每分钟清理一次
|
|
721
|
+
|
|
685
722
|
// 转为对象
|
|
686
723
|
var toObject = function toObject(data) {
|
|
687
724
|
if (Buffer.isBuffer(data)) return JSON.parse(data.toString());
|
|
@@ -760,150 +797,190 @@ function getAccessToken(access_token_file, url, data, appID) {
|
|
|
760
797
|
});
|
|
761
798
|
}
|
|
762
799
|
|
|
763
|
-
//
|
|
800
|
+
// 等待Promise完成,带超时机制
|
|
801
|
+
var waitForPromiseWithTimeout = /*#__PURE__*/function () {
|
|
802
|
+
var _ref = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee(promise) {
|
|
803
|
+
var timeoutMs,
|
|
804
|
+
timeoutPromise,
|
|
805
|
+
_args = arguments;
|
|
806
|
+
return _regeneratorRuntime.wrap(function (_context) {
|
|
807
|
+
while (1) switch (_context.prev = _context.next) {
|
|
808
|
+
case 0:
|
|
809
|
+
timeoutMs = _args.length > 1 && _args[1] !== undefined ? _args[1] : 10000;
|
|
810
|
+
timeoutPromise = new Promise(function (_, reject) {
|
|
811
|
+
setTimeout(function () {
|
|
812
|
+
return reject(new Error("Token refresh timeout after ".concat(timeoutMs, "ms")));
|
|
813
|
+
}, timeoutMs);
|
|
814
|
+
});
|
|
815
|
+
return _context.abrupt("return", Promise.race([promise, timeoutPromise]));
|
|
816
|
+
case 1:
|
|
817
|
+
case "end":
|
|
818
|
+
return _context.stop();
|
|
819
|
+
}
|
|
820
|
+
}, _callee);
|
|
821
|
+
}));
|
|
822
|
+
return function waitForPromiseWithTimeout(_x) {
|
|
823
|
+
return _ref.apply(this, arguments);
|
|
824
|
+
};
|
|
825
|
+
}();
|
|
826
|
+
|
|
827
|
+
// 获取或刷新token(带并发控制和超时保护)
|
|
764
828
|
var getOrRefreshToken = /*#__PURE__*/function () {
|
|
765
|
-
var
|
|
766
|
-
var key,
|
|
767
|
-
return _regeneratorRuntime.wrap(function (
|
|
768
|
-
while (1) switch (
|
|
829
|
+
var _ref2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3(appID, clientSecret) {
|
|
830
|
+
var now_time, url, data, access_token_file, access_token, expires_in, needsRefresh, access_token_json, expiresStr, parsed, default_token_json, key, existingEntry, refreshPromise, _t2;
|
|
831
|
+
return _regeneratorRuntime.wrap(function (_context3) {
|
|
832
|
+
while (1) switch (_context3.prev = _context3.next) {
|
|
769
833
|
case 0:
|
|
834
|
+
now_time = getTimeStampNumber();
|
|
835
|
+
url = 'https://bots.qq.com/app/getAppAccessToken';
|
|
836
|
+
data = {
|
|
837
|
+
appId: appID,
|
|
838
|
+
clientSecret: clientSecret
|
|
839
|
+
};
|
|
840
|
+
access_token_file = './access_token.json';
|
|
841
|
+
access_token = '';
|
|
842
|
+
expires_in = 0;
|
|
843
|
+
needsRefresh = false; // 首先读取当前token状态
|
|
844
|
+
try {
|
|
845
|
+
if (fs.existsSync(access_token_file)) {
|
|
846
|
+
access_token_json = JSON.parse(fs.readFileSync(access_token_file).toString());
|
|
847
|
+
if (access_token_json.hasOwnProperty('bot') && access_token_json['bot'].hasOwnProperty(appID)) {
|
|
848
|
+
access_token = access_token_json['bot'][appID]['access_token'];
|
|
849
|
+
expiresStr = access_token_json['bot'][appID]['expires_in'];
|
|
850
|
+
if (expiresStr && typeof expiresStr === 'string') {
|
|
851
|
+
parsed = parseInt(expiresStr);
|
|
852
|
+
if (!isNaN(parsed) && parsed > 0) {
|
|
853
|
+
expires_in = parsed;
|
|
854
|
+
} else {
|
|
855
|
+
console.log('expires_in解析失败,重置为0:', expiresStr);
|
|
856
|
+
expires_in = 0;
|
|
857
|
+
}
|
|
858
|
+
} else {
|
|
859
|
+
expires_in = 0;
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
} else {
|
|
863
|
+
default_token_json = {
|
|
864
|
+
bot: _defineProperty({}, appID, {
|
|
865
|
+
access_token: "",
|
|
866
|
+
expires_in: ""
|
|
867
|
+
})
|
|
868
|
+
};
|
|
869
|
+
fs.writeFileSync(access_token_file, JSON.stringify(default_token_json, null, 2), 'utf-8');
|
|
870
|
+
needsRefresh = true;
|
|
871
|
+
}
|
|
872
|
+
} catch (err) {
|
|
873
|
+
console.error('读取文件时发生错误:', err);
|
|
874
|
+
expires_in = 0;
|
|
875
|
+
needsRefresh = true;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
// 如果token有效且不需要刷新,直接返回
|
|
879
|
+
if (!(access_token !== '' && now_time <= expires_in - 50 && !needsRefresh)) {
|
|
880
|
+
_context3.next = 1;
|
|
881
|
+
break;
|
|
882
|
+
}
|
|
883
|
+
return _context3.abrupt("return", access_token);
|
|
884
|
+
case 1:
|
|
885
|
+
// 需要刷新token,进入并发控制逻辑
|
|
770
886
|
key = "".concat(appID, ":").concat(clientSecret);
|
|
771
|
-
|
|
772
|
-
if (!
|
|
773
|
-
|
|
887
|
+
existingEntry = tokenRefreshPromises.get(key);
|
|
888
|
+
if (!existingEntry) {
|
|
889
|
+
_context3.next = 5;
|
|
774
890
|
break;
|
|
775
891
|
}
|
|
776
|
-
|
|
892
|
+
_context3.prev = 2;
|
|
893
|
+
// 等待已有的刷新完成,但设置超时防止无限等待
|
|
777
894
|
console.log("\u7B49\u5F85\u5DF2\u6709\u7684token\u5237\u65B0\u5B8C\u6210 (appID: ".concat(appID, ")"));
|
|
778
|
-
|
|
779
|
-
return
|
|
780
|
-
case
|
|
781
|
-
return
|
|
782
|
-
case
|
|
895
|
+
_context3.next = 3;
|
|
896
|
+
return waitForPromiseWithTimeout(existingEntry.promise, 10000);
|
|
897
|
+
case 3:
|
|
898
|
+
return _context3.abrupt("return", _context3.sent);
|
|
899
|
+
case 4:
|
|
900
|
+
_context3.prev = 4;
|
|
901
|
+
_t2 = _context3["catch"](2);
|
|
902
|
+
console.warn("\u7B49\u5F85token\u5237\u65B0\u8D85\u65F6\u6216\u5931\u8D25\uFF0C\u91CD\u65B0\u53D1\u8D77\u5237\u65B0 (appID: ".concat(appID, "):"), _t2);
|
|
903
|
+
// 移除失败的Promise,让新的请求可以重新发起刷新
|
|
904
|
+
tokenRefreshPromises["delete"](key);
|
|
905
|
+
case 5:
|
|
783
906
|
// 创建新的刷新Promise
|
|
784
|
-
refreshPromise = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function
|
|
785
|
-
var
|
|
786
|
-
return _regeneratorRuntime.wrap(function (
|
|
787
|
-
while (1) switch (
|
|
907
|
+
refreshPromise = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
|
|
908
|
+
var new_token, _t;
|
|
909
|
+
return _regeneratorRuntime.wrap(function (_context2) {
|
|
910
|
+
while (1) switch (_context2.prev = _context2.next) {
|
|
788
911
|
case 0:
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
data = {
|
|
793
|
-
appId: appID,
|
|
794
|
-
clientSecret: clientSecret
|
|
795
|
-
};
|
|
796
|
-
access_token_file = './access_token.json';
|
|
797
|
-
access_token = '';
|
|
798
|
-
expires_in = 0;
|
|
799
|
-
needsRefresh = false;
|
|
800
|
-
try {
|
|
801
|
-
// 判断文件是否存在
|
|
802
|
-
if (fs.existsSync(access_token_file)) {
|
|
803
|
-
// 执行文件存在时的处理逻辑
|
|
804
|
-
access_token_json = JSON.parse(fs.readFileSync(access_token_file).toString()); // 判断是否存在appID
|
|
805
|
-
if (access_token_json.hasOwnProperty('bot') && access_token_json['bot'].hasOwnProperty(appID)) {
|
|
806
|
-
access_token = access_token_json['bot'][appID]['access_token'];
|
|
807
|
-
expiresStr = access_token_json['bot'][appID]['expires_in']; // 改进expires_in解析,防止NaN
|
|
808
|
-
if (expiresStr && typeof expiresStr === 'string') {
|
|
809
|
-
parsed = parseInt(expiresStr);
|
|
810
|
-
if (!isNaN(parsed) && parsed > 0) {
|
|
811
|
-
expires_in = parsed;
|
|
812
|
-
} else {
|
|
813
|
-
console.log('expires_in解析失败,重置为0:', expiresStr);
|
|
814
|
-
expires_in = 0;
|
|
815
|
-
}
|
|
816
|
-
} else {
|
|
817
|
-
expires_in = 0;
|
|
818
|
-
}
|
|
819
|
-
}
|
|
820
|
-
} else {
|
|
821
|
-
// 执行文件不存在时的处理逻辑
|
|
822
|
-
default_token_json = {
|
|
823
|
-
bot: _defineProperty({}, appID, {
|
|
824
|
-
access_token: "",
|
|
825
|
-
expires_in: ""
|
|
826
|
-
})
|
|
827
|
-
};
|
|
828
|
-
fs.writeFileSync(access_token_file, JSON.stringify(default_token_json, null, 2), 'utf-8');
|
|
829
|
-
needsRefresh = true;
|
|
830
|
-
}
|
|
831
|
-
} catch (err) {
|
|
832
|
-
console.error('读取文件时发生错误:', err);
|
|
833
|
-
// 出错时重置expires_in为0,强制重新获取token
|
|
834
|
-
expires_in = 0;
|
|
835
|
-
needsRefresh = true;
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
// 判断是否需要刷新token
|
|
839
|
-
if (!(access_token === '' || now_time > expires_in - 50 || needsRefresh)) {
|
|
840
|
-
_context.next = 2;
|
|
841
|
-
break;
|
|
842
|
-
}
|
|
843
|
-
console.log('检测到access_token需要刷新 - 当前token:', access_token, '过期时间:', expires_in, '当前时间:', now_time);
|
|
844
|
-
_context.next = 1;
|
|
912
|
+
_context2.prev = 0;
|
|
913
|
+
console.log('开始刷新access_token - 当前token:', access_token, '过期时间:', expires_in, '当前时间:', now_time);
|
|
914
|
+
_context2.next = 1;
|
|
845
915
|
return getAccessToken(access_token_file, url, data, appID);
|
|
846
916
|
case 1:
|
|
847
|
-
|
|
848
|
-
console.log('access_token刷新成功,新token:',
|
|
917
|
+
new_token = _context2.sent;
|
|
918
|
+
console.log('access_token刷新成功,新token:', new_token);
|
|
919
|
+
return _context2.abrupt("return", new_token);
|
|
849
920
|
case 2:
|
|
850
|
-
|
|
921
|
+
_context2.prev = 2;
|
|
922
|
+
_t = _context2["catch"](0);
|
|
923
|
+
console.error("Token\u5237\u65B0\u5931\u8D25 (appID: ".concat(appID, "):"), _t);
|
|
924
|
+
throw _t;
|
|
851
925
|
case 3:
|
|
852
|
-
|
|
926
|
+
_context2.prev = 3;
|
|
853
927
|
// 刷新完成后移除Promise
|
|
854
928
|
tokenRefreshPromises["delete"](key);
|
|
855
|
-
return
|
|
929
|
+
return _context2.finish(3);
|
|
856
930
|
case 4:
|
|
857
931
|
case "end":
|
|
858
|
-
return
|
|
932
|
+
return _context2.stop();
|
|
859
933
|
}
|
|
860
|
-
},
|
|
861
|
-
}))(); // 存储Promise
|
|
862
|
-
tokenRefreshPromises.set(key,
|
|
863
|
-
|
|
934
|
+
}, _callee2, null, [[0, 2, 3, 4]]);
|
|
935
|
+
}))(); // 存储Promise和时间戳以便其他并发请求使用和超时清理
|
|
936
|
+
tokenRefreshPromises.set(key, {
|
|
937
|
+
promise: refreshPromise,
|
|
938
|
+
timestamp: Date.now()
|
|
939
|
+
});
|
|
940
|
+
_context3.next = 6;
|
|
864
941
|
return refreshPromise;
|
|
865
|
-
case
|
|
866
|
-
return
|
|
867
|
-
case
|
|
942
|
+
case 6:
|
|
943
|
+
return _context3.abrupt("return", _context3.sent);
|
|
944
|
+
case 7:
|
|
868
945
|
case "end":
|
|
869
|
-
return
|
|
946
|
+
return _context3.stop();
|
|
870
947
|
}
|
|
871
|
-
},
|
|
948
|
+
}, _callee3, null, [[2, 4]]);
|
|
872
949
|
}));
|
|
873
|
-
return function getOrRefreshToken(
|
|
874
|
-
return
|
|
950
|
+
return function getOrRefreshToken(_x2, _x3) {
|
|
951
|
+
return _ref2.apply(this, arguments);
|
|
875
952
|
};
|
|
876
953
|
}();
|
|
877
954
|
|
|
878
955
|
// 添加 User-Agent
|
|
879
956
|
var addAuthorization = /*#__PURE__*/function () {
|
|
880
|
-
var
|
|
957
|
+
var _ref4 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee4(header, appID, token, clientSecret, apiVersion) {
|
|
881
958
|
var access_token;
|
|
882
|
-
return _regeneratorRuntime.wrap(function (
|
|
883
|
-
while (1) switch (
|
|
959
|
+
return _regeneratorRuntime.wrap(function (_context4) {
|
|
960
|
+
while (1) switch (_context4.prev = _context4.next) {
|
|
884
961
|
case 0:
|
|
885
962
|
if (!(apiVersion == 'v2')) {
|
|
886
|
-
|
|
963
|
+
_context4.next = 2;
|
|
887
964
|
break;
|
|
888
965
|
}
|
|
889
|
-
|
|
966
|
+
_context4.next = 1;
|
|
890
967
|
return getOrRefreshToken(appID, clientSecret);
|
|
891
968
|
case 1:
|
|
892
|
-
access_token =
|
|
969
|
+
access_token = _context4.sent;
|
|
893
970
|
// 更新header['Authorization']
|
|
894
971
|
header['Authorization'] = "QQBot ".concat(access_token);
|
|
895
|
-
|
|
972
|
+
_context4.next = 3;
|
|
896
973
|
break;
|
|
897
974
|
case 2:
|
|
898
975
|
header['Authorization'] = "Bot ".concat(appID, ".").concat(token);
|
|
899
976
|
case 3:
|
|
900
977
|
case "end":
|
|
901
|
-
return
|
|
978
|
+
return _context4.stop();
|
|
902
979
|
}
|
|
903
|
-
},
|
|
980
|
+
}, _callee4);
|
|
904
981
|
}));
|
|
905
|
-
return function addAuthorization(
|
|
906
|
-
return
|
|
982
|
+
return function addAuthorization(_x4, _x5, _x6, _x7, _x8) {
|
|
983
|
+
return _ref4.apply(this, arguments);
|
|
907
984
|
};
|
|
908
985
|
}();
|
|
909
986
|
// 组装完整Url
|