123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787 |
- function MagicJS(scriptName = "MagicJS", logLevel = "INFO") {
- // HTTP/1.1协议头部header字段名大小写不敏感, 但是HTTP/2头部header字段名必须使用小写
- const headerFieldMap = {
- accept: "Accept",
- "accept-ch": "Accept-CH",
- "accept-charset": "Accept-Charset",
- "accept-features": "Accept-Features",
- "accept-encoding": "Accept-Encoding",
- "accept-language": "Accept-Language",
- "accept-ranges": "Accept-Ranges",
- "access-control-allow-credentials": "Access-Control-Allow-Credentials",
- "access-control-allow-origin": "Access-Control-Allow-Origin",
- "access-control-allow-methods": "Access-Control-Allow-Methods",
- "access-control-allow-headers": "Access-Control-Allow-Headers",
- "access-control-max-age": "Access-Control-Max-Age",
- "access-control-expose-headers": "Access-Control-Expose-Headers",
- "access-control-request-method": "Access-Control-Request-Method",
- "access-control-request-headers": "Access-Control-Request-Headers",
- age: "Age",
- allow: "Allow",
- alternates: "Alternates",
- authorization: "Authorization",
- "cache-control": "Cache-Control",
- connection: "Connection",
- "content-encoding": "Content-Encoding",
- "content-language": "Content-Language",
- "content-length": "Content-Length",
- "content-location": "Content-Location",
- "content-md5": "Content-MD5",
- "content-range": "Content-Range",
- "content-security-policy": "Content-Security-Policy",
- "content-type": "Content-Type",
- cookie: "Cookie",
- dnt: "DNT",
- date: "Date",
- etag: "ETag",
- expect: "Expect",
- expires: "Expires",
- from: "From",
- host: "Host",
- "if-match": "If-Match",
- "if-modified-since": "If-Modified-Since",
- "if-none-match": "If-None-Match",
- "if-range": "If-Range",
- "if-unmodified-since": "If-Unmodified-Since",
- "last-event-id": "Last-Event-ID",
- "last-modified": "Last-Modified",
- link: "Link",
- location: "Location",
- "max-forwards": "Max-Forwards",
- negotiate: "Negotiate",
- origin: "Origin",
- pragma: "Pragma",
- "proxy-authenticate": "Proxy-Authenticate",
- "proxy-authorization": "Proxy-Authorization",
- range: "Range",
- referer: "Referer",
- "retry-after": "Retry-After",
- "sec-websocket-extensions": "Sec-Websocket-Extensions",
- "sec-websocket-key": "Sec-Websocket-Key",
- "sec-websocket-origin": "Sec-Websocket-Origin",
- "sec-websocket-protocol": "Sec-Websocket-Protocol",
- "sec-websocket-version": "Sec-Websocket-Version",
- server: "Server",
- "set-cookie": "Set-Cookie",
- "set-cookie2": "Set-Cookie2",
- "strict-transport-security": "Strict-Transport-Security",
- tcn: "TCN",
- te: "TE",
- trailer: "Trailer",
- "transfer-encoding": "Transfer-Encoding",
- upgrade: "Upgrade",
- "user-agent": "User-Agent",
- "variant-vary": "Variant-Vary",
- vary: "Vary",
- via: "Via",
- warning: "Warning",
- "www-authenticate": "WWW-Authenticate",
- "x-content-duration": "X-Content-Duration",
- "x-content-security-policy": "X-Content-Security-Policy",
- "x-dnsprefetch-control": "X-DNSPrefetch-Control",
- "x-frame-options": "X-Frame-Options",
- "x-requested-with": "X-Requested-With",
- "x-surge-skip-scripting": "X-Surge-Skip-Scripting"
- };
- return new class {
- constructor() {
- this._startTime = Date.now();
- this.version = "2.2.3.7";
- this.scriptName = scriptName;
- this.logLevels = {
- DEBUG: 5,
- INFO: 4,
- NOTIFY: 3,
- WARNING: 2,
- ERROR: 1,
- CRITICAL: 0,
- NONE: -1
- };
- this.isLoon = typeof $loon !== "undefined";
- this.isQuanX = typeof $task !== "undefined";
- this.isJSBox = typeof $drive !== "undefined";
- this.isNode = typeof module !== "undefined" && !this.isJSBox;
- this.isSurge = typeof $httpClient !== "undefined" && !this.isLoon;
- this.node = {
- request: undefined,
- fs: undefined,
- data: {}
- };
- this.iOSUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 13_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.5 Mobile/15E148 Safari/604.1";
- this.pcUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36 Edg/84.0.522.59";
- this._logLevel = "INFO";
- this.logLevel = logLevel;
- this._barkUrl = "";
- this._barkKey = "";
- if (this.isNode) {
- this.node.fs = require("fs");
- this.node.request = require("request");
- try {
- this.node.fs.accessSync("./magic.json", this.node.fs.constants.R_OK | this.node.fs.constants.W_OK);
- } catch (err) {
- this.node.fs.writeFileSync("./magic.json", "{}", {
- encoding: "utf8"
- });
- }
- this.node.data = require("./magic.json");
- } else if (this.isJSBox) {
- if (!$file.exists("drive://MagicJS")) {
- $file.mkdir("drive://MagicJS");
- }
- if (!$file.exists("drive://MagicJS/magic.json")) {
- $file.write({
- data: $data({
- string: "{}"
- }),
- path: "drive://MagicJS/magic.json"
- });
- }
- }
- this.log(`${scriptName}, 开始执行!`);
- }
- /**
- * @param {string} url
- */
- set barkUrl(url) {
- try {
- let _url = url.replace(/\/+$/g, "");
- this._barkUrl = `${/^https?:\/\/([^/]*)/.exec(_url)[0]}/push`;
- this._barkKey = /\/([^\/]+)\/?$/.exec(_url)[1];
- } catch (err) {
- this.logDebug("Bark config error.");
- }
- }
- set logLevel(level) {
- let magic_loglevel = this.read("magicjs_loglevel");
- this._logLevel = magic_loglevel ? magic_loglevel : level.toUpperCase();
- }
- get logLevel() {
- return this._logLevel;
- }
- get isRequest() {
- return typeof $request !== "undefined" && typeof $response === "undefined";
- }
- get isResponse() {
- return typeof $response !== "undefined";
- }
- get isDebug() {
- return this.logLevel === "DEBUG";
- }
- get request() {
- return typeof $request !== "undefined" ? $request : undefined;
- }
- get response() {
- if (typeof $response !== "undefined") {
- if ($response.hasOwnProperty("status")) $response["statusCode"] = $response["status"];
- if ($response.hasOwnProperty("statusCode")) $response["status"] = $response["statusCode"];
- return $response;
- } else {
- return undefined;
- }
- }
- get platform() {
- if (this.isSurge) return "Surge"; else if (this.isQuanX) return "Quantumult X"; else if (this.isLoon) return "Loon"; else if (this.isJSBox) return "JSBox"; else if (this.isNode) return "Node.js"; else return "Unknown";
- }
- read(key, session = "") {
- let val = "";
- // 读取原始数据
- if (this.isSurge || this.isLoon) {
- val = $persistentStore.read(key);
- } else if (this.isQuanX) {
- val = $prefs.valueForKey(key);
- } else if (this.isNode) {
- val = this.node.data;
- } else if (this.isJSBox) {
- val = $file.read("drive://MagicJS/magic.json").string;
- }
- try {
- // Node 和 JSBox数据处理
- if (this.isNode) val = val[key];
- if (this.isJSBox) val = JSON.parse(val)[key];
- // 带Session的情况
- if (!!session) {
- if (typeof val === "string") val = JSON.parse(val);
- val = !!val && typeof val === "object" ? val[session] : null;
- }
- } catch (err) {
- this.logError(err);
- val = !!session ? {} : null;
- this.del(key);
- }
- if (typeof val === "undefined") val = null;
- try {
- if (!!val && typeof val === "string") {
- var obj = JSON.parse(val);
- if (typeof obj == "object" && obj) {
- val = obj;
- }
- }
- } catch (err) {}
- this.logDebug(`READ DATA [${key}]${!!session ? `[${session}]` : ""}(${typeof val})`+'\n'+`${JSON.stringify(val)}`);
- return val;
- }
- write(key, val, session = "") {
- let data = !!session ? {} : "";
- // 读取原先存储的JSON格式数据
- if (!!session && (this.isSurge || this.isLoon)) {
- data = $persistentStore.read(key);
- } else if (!!session && this.isQuanX) {
- data = $prefs.valueForKey(key);
- } else if (this.isNode) {
- data = this.node.data;
- } else if (this.isJSBox) {
- data = JSON.parse($file.read("drive://MagicJS/magic.json").string);
- }
- if (!!session) {
- // 有Session,所有数据都是Object
- try {
- if (typeof data === "string") data = JSON.parse(data);
- data = typeof data === "object" && !!data ? data : {};
- } catch (err) {
- this.logError(err);
- this.del(key);
- data = {};
- }
- if (this.isJSBox || this.isNode) {
- // 构造数据
- if (!data[key] || typeof data[key] != "object") {
- data[key] = {};
- }
- if (!data[key].hasOwnProperty(session)) {
- data[key][session] = null;
- }
- // 写入或删除数据
- if (typeof val === "undefined") {
- delete data[key][session];
- } else {
- data[key][session] = val;
- }
- } else {
- // 写入或删除数据
- if (typeof val === "undefined") {
- delete data[session];
- } else {
- data[session] = val;
- }
- }
- }
- // 没有Session时
- else {
- if (this.isNode || this.isJSBox) {
- // 删除数据
- if (typeof val === "undefined") {
- delete data[key];
- } else {
- data[key] = val;
- }
- } else {
- // 删除数据
- if (typeof val === "undefined") {
- data = null;
- } else {
- data = val;
- }
- }
- }
- // 数据回写
- if (typeof data === "object") data = JSON.stringify(data);
- if (this.isSurge || this.isLoon) {
- $persistentStore.write(data, key);
- } else if (this.isQuanX) {
- $prefs.setValueForKey(data, key);
- } else if (this.isNode) {
- this.node.fs.writeFileSync("./magic.json", data);
- } else if (this.isJSBox) {
- $file.write({
- data: $data({
- string: data
- }),
- path: "drive://MagicJS/magic.json"
- });
- }
- this.logDebug(`WRITE DATA [${key}]${!!session ? `[${session}]` : ""}(${typeof val})`+'\n'+`${JSON.stringify(val)}`);
- }
- del(key, session = "") {
- this.logDebug(`DELETE KEY [${key}]${!!session ? `[${session}]` : ""}`);
- this.write(key, null, session);
- }
- /**
- * iOS系统通知
- * @param {*} title 通知标题
- * @param {*} subTitle 通知副标题
- * @param {*} body 通知内容
- * @param {*} opts 通知选项,目前支持传入超链接或Object
- * Surge不支持通知选项,Loon和QuantumultX支持打开URL和多媒体通知
- * opts "applestore://" 打开Apple Store
- * opts "https://www.apple.com.cn/" 打开Apple.com.cn
- * opts {'open-url': 'https://www.apple.com.cn/'} 打开Apple.com.cn
- * opts {'open-url': 'https://www.apple.com.cn/', 'media-url': 'https://raw.githubusercontent.com/Orz-3/mini/master/Apple.png'} 打开Apple.com.cn,显示一个苹果Logo
- */
- notify(title = this.scriptName, subTitle = "", body = "", opts = "") {
- let convertOptions = _opts => {
- let newOpts = {};
- if (typeof _opts === "string") {
- if(_opts.length > 0){
- if (this.isLoon){
- newOpts = {
- openUrl: _opts
- };
- }else if (this.isQuanX){
- newOpts = {
- "open-url": _opts
- };
- }else if (this.isSurge){
- newOpts = {
- url: _opts
- };
- }
- }
- } else if (typeof _opts === "object") {
- if (this.isLoon) {
- newOpts["openUrl"] = !!_opts["open-url"] ? _opts["open-url"] : "";
- newOpts["mediaUrl"] = !!_opts["media-url"] ? _opts["media-url"] : "";
- } else if (this.isQuanX) {
- newOpts = !!_opts["open-url"] || !!_opts["media-url"] ? _opts : {};
- } else if (this.isSurge) {
- let openUrl = _opts["open-url"] || _opts["openUrl"];
- newOpts = openUrl ? {
- url: openUrl
- } : {};
- }
- }
- return newOpts;
- };
- opts = convertOptions(opts);
- // 支持单个参数通知
- if (arguments.length == 1) {
- title = this.scriptName;
- subTitle = "", body = arguments[0];
- }
- // 生成通知日志
- this.logNotify('\n'+`title:${title}`+'\n'+`subTitle:${subTitle}`+'\n'+`body:${body}`+'\n'+`options:${typeof opts === "object" ? JSON.stringify(opts) : opts}`);
- if (this.isSurge) {
- $notification.post(title, subTitle, body, opts);
- } else if (this.isLoon) {
- if (!!opts) $notification.post(title, subTitle, body, opts); else $notification.post(title, subTitle, body);
- } else if (this.isQuanX) {
- $notify(title, subTitle, body, opts);
- } else if (this.isJSBox) {
- let push = {
- title: title,
- body: !!subTitle ? `${subTitle}`+'\n'+`${body}` : body
- };
- $push.schedule(push);
- }
- // 跨设备统一推送
- if (this._barkUrl && this._barkKey) {
- this.notifyBark(title, subTitle, body);
- }
- }
- /**
- * iOS系统通知,仅在DEBUG模式下推送
- * @param {*} title 通知标题
- * @param {*} subTitle 通知副标题
- * @param {*} body 通知内容
- * @param {*} opts 通知选项,目前支持传入超链接或Object
- * Surge不支持通知选项,Loon和QuantumultX支持打开URL和多媒体通知
- * opts "applestore://" 打开Apple Store
- * opts "https://www.apple.com.cn/" 打开Apple.com.cn
- * opts {'open-url': 'https://www.apple.com.cn/'} 打开Apple.com.cn
- * opts {'open-url': 'https://www.apple.com.cn/', 'media-url': 'https://raw.githubusercontent.com/Orz-3/mini/master/Apple.png'} 打开Apple.com.cn,显示一个苹果Logo
- */
- notifyDebug(title = this.scriptName, subTitle = "", body = "", opts = "") {
- if (this.logLevel === "DEBUG") {
- // 适配单个参数通知
- if (arguments.length == 1) {
- title = this.scriptName;
- subTitle = "", body = arguments[0];
- }
- this.notify(title, subTitle, body, opts);
- }
- }
- notifyBark(title = this.scriptName, subTitle = "", body = "", opts = "") {
- let options = {
- url: this._barkUrl,
- headers: {
- "Content-Type": "application/json; charset=utf-8"
- },
- body: {
- title: title,
- body: subTitle ? `${subTitle}`+'\n'+`${body}` : body,
- device_key: this._barkKey
- }
- };
- this.post(options, err => {});
- }
- log(msg, level = "INFO") {
- if (!(this.logLevels[this._logLevel] < this.logLevels[level.toUpperCase()])) console.log(`██[${this.scriptName}][${level}]`+''+`${msg}`+'\n');
- }
- logDebug(msg) {
- this.log(msg, "DEBUG");
- }
- logInfo(msg) {
- this.log(msg, "INFO");
- }
- logNotify(msg) {
- this.log(msg, "NOTIFY");
- }
- logWarning(msg) {
- this.log(msg, "WARNING");
- }
- logError(msg) {
- this.log(msg, "ERROR");
- }
- logRetry(msg) {
- this.log(msg, "RETRY");
- }
- /**
- * 对传入的Http Options根据不同环境进行适配
- * @param {*} options
- */
- adapterHttpOptions(options, method) {
- let _options = typeof options === "object" ? Object.assign({}, options) : {
- url: options,
- headers: {}
- };
- if (_options.hasOwnProperty("header") && !_options.hasOwnProperty("headers")) {
- _options["headers"] = _options["header"];
- delete _options["header"];
- }
- // // 将HTTP/2头部header字段统一转成
- // if (typeof _options.headers === "object" && !!s) {
- // for (let key in _options.headers) {
- // if (headerFieldMap[key]) {
- // _options.headers[headerFieldMap[key]] = _options.headers[key];
- // delete _options.headers[key];
- // }
- // }
- // }
- // 自动补完User-Agent,减少请求特征
- if (!!!_options.headers || typeof _options.headers !== "object" || !!!_options.headers["User-Agent"] && !!!_options.headers["user-agent"]) {
- if (!!!_options.headers || typeof _options.headers !== "object") _options.headers = {};
- if (this.isNode) _options.headers["User-Agent"] = this.pcUserAgent; else _options.headers["User-Agent"] = this.iOSUserAgent;
- }
- // 判断是否跳过脚本处理
- let skipScripting = false;
- if (typeof _options["opts"] === "object" && (_options["opts"]["hints"] === true || _options["opts"]["Skip-Scripting"] === true) || typeof _options["headers"] === "object" && _options["headers"]["X-Surge-Skip-Scripting"] === true) {
- skipScripting = true;
- }
- if (!skipScripting) {
- if (this.isSurge) _options.headers["X-Surge-Skip-Scripting"] = false; else if (this.isLoon) _options.headers["X-Requested-With"] = "XMLHttpRequest"; else if (this.isQuanX) {
- if (typeof _options["opts"] !== "object") _options.opts = {};
- _options.opts["hints"] = false;
- }
- }
- // 对请求数据做清理
- if (!this.isSurge || skipScripting) delete _options.headers["X-Surge-Skip-Scripting"];
- if (!this.isQuanX && _options.hasOwnProperty("opts")) delete _options["opts"];
- if (this.isQuanX && _options.hasOwnProperty("opts")) delete _options["opts"]["Skip-Scripting"];
- // GET请求将body转换成QueryString(beta)
- if (method === "GET" && !this.isNode && !!_options.body) {
- let qs = Object.keys(_options.body).map(key => {
- if (typeof _options.body === "undefined") return "";
- return `${encodeURIComponent(key)}=${encodeURIComponent(_options.body[key])}`;
- }).join("&");
- if (_options.url.indexOf("?") < 0) _options.url += "?";
- if (_options.url.lastIndexOf("&") + 1 != _options.url.length && _options.url.lastIndexOf("?") + 1 != _options.url.length) _options.url += "&";
- _options.url += qs;
- delete _options.body;
- }
- // 适配多环境
- if (this.isQuanX) {
- if (_options.hasOwnProperty("body") && typeof _options["body"] !== "string") _options["body"] = JSON.stringify(_options["body"]);
- _options["method"] = method;
- } else if (this.isNode) {
- delete _options.headers["Accept-Encoding"];
- if (typeof _options.body === "object") {
- if (method === "GET") {
- _options.qs = _options.body;
- delete _options.body;
- } else if (method === "POST") {
- _options["json"] = true;
- _options.body = _options.body;
- }
- }
- } else if (this.isJSBox) {
- _options["header"] = _options["headers"];
- delete _options["headers"];
- }
- return _options;
- }
- adapterHttpResponse(resp) {
- let _resp = {
- body: resp.body,
- headers: resp.headers,
- json: () => {
- return JSON.parse(_resp.body);
- }
- };
- if (resp.hasOwnProperty("statusCode") && resp.statusCode) {
- _resp["status"] = resp.statusCode;
- }
- return _resp;
- }
- /**
- * Http客户端发起GET请求
- * @param {*} options
- * @param {*} callback
- * options可配置参数headers和opts,用于判断由脚本发起的http请求是否跳过脚本处理。
- * 支持Surge和Quantumult X两种配置方式。
- * 以下几种配置会跳过脚本处理,options没有opts或opts的值不匹配,则不跳过脚本处理
- * {opts:{"hints": true}}
- * {opts:{"Skip-Scripting": true}}
- * {headers: {"X-Surge-Skip-Scripting": true}}
- */
- get(options, callback) {
- let _options = this.adapterHttpOptions(options, "GET");
- this.logDebug(`HTTP GET: ${JSON.stringify(_options)}`);
- if (this.isSurge || this.isLoon) {
- $httpClient.get(_options, callback);
- } else if (this.isQuanX) {
- $task.fetch(_options).then(resp => {
- resp["status"] = resp.statusCode;
- callback(null, resp, resp.body);
- }, reason => callback(reason.error, null, null));
- } else if (this.isNode) {
- this.node.request.get(_options, (err, resp, data) => {
- resp = this.adapterHttpResponse(resp);
- callback(err, resp, data);
- });
- } else if (this.isJSBox) {
- _options["handler"] = resp => {
- let err = resp.error ? JSON.stringify(resp.error) : undefined;
- let data = typeof resp.data === "object" ? JSON.stringify(resp.data) : resp.data;
- callback(err, resp.response, data);
- };
- $http.get(_options);
- }
- }
- getPromise(options) {
- return new Promise((resolve, reject) => {
- magicJS.get(options, (err, resp) => {
- if (err) {
- reject(err);
- } else {
- resolve(resp);
- }
- });
- });
- }
- /**
- * Http客户端发起POST请求
- * @param {*} options
- * @param {*} callback
- * options可配置参数headers和opts,用于判断由脚本发起的http请求是否跳过脚本处理。
- * 支持Surge和Quantumult X两种配置方式。
- * 以下几种配置会跳过脚本处理,options没有opts或opts的值不匹配,则不跳过脚本处理
- * {opts:{"hints": true}}
- * {opts:{"Skip-Scripting": true}}
- * {headers: {"X-Surge-Skip-Scripting": true}}
- */
- post(options, callback) {
- let _options = this.adapterHttpOptions(options, "POST");
- this.logDebug(`HTTP POST: ${JSON.stringify(_options)}`);
- if (this.isSurge || this.isLoon) {
- $httpClient.post(_options, callback);
- } else if (this.isQuanX) {
- $task.fetch(_options).then(resp => {
- resp["status"] = resp.statusCode;
- callback(null, resp, resp.body);
- }, reason => {
- callback(reason.error, null, null);
- });
- } else if (this.isNode) {
- let resp = this.node.request.post(_options, callback);
- resp["status"] = resp.statusCode;
- delete resp.statusCode;
- } else if (this.isJSBox) {
- _options["handler"] = resp => {
- let err = resp.error ? JSON.stringify(resp.error) : undefined;
- let data = typeof resp.data === "object" ? JSON.stringify(resp.data) : resp.data;
- callback(err, resp.response, data);
- };
- $http.post(_options, {});
- }
- }
- costTime() {
- let info = `${this.scriptName}执行完毕!`
- // if (this.isNode && this.isExecComm) {
- // info = `指令【${this.comm[1]}】执行完毕!`
- // }
- this._endTime = new Date().getTime();
- const ms = this._endTime - this._startTime;
- const costTime = ms / 1000;
- this.log(`${info}耗时【${costTime}】秒`);
- }
- done(value = {}) {
- // this._endTime = Date.now();
- // let span = (this._endTime - this._startTime) / 1e3;
- // this.log(`SCRIPT COMPLETED: ${span}S.`);
- this.costTime();
- if (typeof $done !== "undefined") {
- $done(value);
- }
- }
- isToday(day) {
- if (day == null) {
- return false;
- } else {
- let today = new Date();
- if (typeof day == "string") {
- day = new Date(day);
- }
- if (today.getFullYear() == day.getFullYear() && today.getMonth() == day.getMonth() && today.getDay() == day.getDay()) {
- return true;
- } else {
- return false;
- }
- }
- }
- isNumber(val) {
- return parseFloat(val).toString() === "NaN" ? false : true;
- }
- /**
- * 对await执行中出现的异常进行捕获并返回,避免写过多的try catch语句
- * 示例:let [err,val] = await magicJS.attempt(func(), 'defaultvalue');
- * 或者:let [err, [val1,val2]] = await magicJS.attempt(func(), ['defaultvalue1', 'defaultvalue2']);
- * @param {*} promise Promise 对象
- * @param {*} defaultValue 出现异常时返回的默认值
- * @returns 返回两个值,第一个值为异常,第二个值为执行结果
- */
- attempt(promise, defaultValue = null) {
- return promise.then(args => {
- return [ null, args ];
- }).catch(ex => {
- this.logError(ex);
- return [ ex, defaultValue ];
- });
- }
- /**
- * 重试方法
- * @param {*} fn 需要重试的函数
- * @param {number} [retries=5] 重试次数
- * @param {number} [interval=0] 每次重试间隔
- * @param {function} [callback=null] 函数没有异常时的回调,会将函数执行结果result传入callback,根据result的值进行判断,如果需要再次重试,在callback中throw一个异常,适用于函数本身没有异常但仍需重试的情况。
- * @returns 返回一个Promise对象
- */
- retry(fn, retries = 5, interval = 0, callback = null) {
- return (...args) => {
- return new Promise((resolve, reject) => {
- function _retry(...args) {
- Promise.resolve().then(() => fn.apply(this, args)).then(result => {
- if (typeof callback === "function") {
- Promise.resolve().then(() => callback(result)).then(() => {
- resolve(result);
- }).catch(ex => {
- if (retries >= 1) {
- if (interval > 0) setTimeout(() => _retry.apply(this, args), interval); else _retry.apply(this, args);
- } else {
- reject(ex);
- }
- retries--;
- });
- } else {
- resolve(result);
- }
- }).catch(ex => {
- this.logRetry(ex);
- if (retries >= 1 && interval > 0) {
- setTimeout(() => _retry.apply(this, args), interval);
- } else if (retries >= 1) {
- _retry.apply(this, args);
- } else {
- reject(ex);
- }
- retries--;
- });
- }
- _retry.apply(this, args);
- });
- };
- }
- formatTime(time, fmt = "yyyy-MM-dd hh:mm:ss") {
- var o = {
- "M+": time.getMonth() + 1,
- "d+": time.getDate(),
- "h+": time.getHours(),
- "m+": time.getMinutes(),
- "s+": time.getSeconds(),
- "q+": Math.floor((time.getMonth() + 3) / 3),
- S: time.getMilliseconds()
- };
- if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (time.getFullYear() + "").substr(4 - RegExp.$1.length));
- for (let k in o) if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length));
- return fmt;
- }
- now() {
- return this.formatTime(new Date(), "yyyy-MM-dd hh:mm:ss");
- }
- today() {
- return this.formatTime(new Date(), "yyyy-MM-dd");
- }
- sleep(time) {
- return new Promise(resolve => setTimeout(resolve, time));
- }
- objToQueryStr(obj, encode) {
- let str = '';
- for (const key in obj) {
- let value = obj[key];
- if (value != null && value !== '') {
- if (typeof value === 'object') {
- value = JSON.stringify(value);
- } else if (encode) {
- value = encodeURIComponent(value);
- }
- str += `${key}=${value}&`;
- }
- }
- str = str.substring(0, str.length - 1);
- return str;
- }
- parseQueryStr(str) {
- let obj = {};
- if (str.indexOf("?") > -1) {
- str = str.split("?")[1];
- }
- let arr = str.split("&");
- for (let i = 0; i < arr.length; i++) {
- let kv = arr[i].split("=");
- obj[kv[0]] = kv[1];
- }
- return obj;
- }
- deepClone(obj, newObj) {
- newObj = newObj || {};
- for (let key in obj) {
- if (typeof obj[key] == 'object') {
- newObj[key] = (obj[key].constructor === Array) ? [] : {};
- this.deepClone(obj[key], newObj[key]);
- } else {
- newObj[key] = obj[key];
- }
- }
- return newObj;
- }
- convertToObject(input) {
- if (typeof input === "string") {
- let retObj = {};
- try {
- retObj = JSON.parse(input);
- const resultType = typeof retObj;
- if (resultType !== "object" || retObj instanceof Array || resultType === "boolean" || retObj === null) {
- retObj = {};
- }
- } catch {
- }
- return retObj;
- }
- else if (input instanceof Array || input === null || typeof input === "undefined" || input !== input || typeof input === "boolean") {
- return {};
- } else {
- return input;
- }
- };
- }(scriptName);
- }
|