123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389 |
- /**
- * OpenAPI
- * @author: Peng-YM
- * https://github.com/Peng-YM/QuanX/blob/master/Tools/OpenAPI/api-minified.js
- * https://github.com/Peng-YM/QuanX/blob/master/Tools/OpenAPI/README.md
- */
- function ENV() {
- const isJSBox = typeof require == "function" && typeof $jsbox != "undefined";
- return {
- isQX: typeof $task !== "undefined",
- isLoon: typeof $loon !== "undefined",
- isSurge: typeof $httpClient !== "undefined" && typeof $utils !== "undefined",
- isBrowser: typeof document !== "undefined",
- isNode: typeof require == "function" && !isJSBox,
- isJSBox,
- isRequest: typeof $request !== "undefined",
- isScriptable: typeof importModule !== "undefined",
- };
- }
- function HTTP(defaultOptions = {
- baseURL: ""
- }) {
- const {
- isQX,
- isLoon,
- isSurge,
- isScriptable,
- isNode,
- isBrowser
- } = ENV();
- const methods = ["GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS", "PATCH"];
- const URL_REGEX = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/
- function send(method, options) {
- options = typeof options === "string" ? {
- url: options
- } : options;
- const baseURL = defaultOptions.baseURL;
- if (baseURL && !URL_REGEX.test(options.url || "")) {
- options.url = baseURL ? baseURL + options.url : options.url;
- }
- if (options.body && options.headers && !options.headers['Content-Type']) {
- options.headers['Content-Type'] = 'application/x-www-form-urlencoded'
- }
- options = {
- ...defaultOptions,
- ...options
- };
- const timeout = options.timeout;
- const events = {
- ...{
- onRequest: () => {
- },
- onResponse: (resp) => resp,
- onTimeout: () => {
- },
- },
- ...options.events,
- };
- events.onRequest(method, options);
- let worker;
- if (isQX) {
- worker = $task.fetch({
- method,
- ...options
- });
- } else if (isLoon || isSurge || isNode) {
- worker = new Promise((resolve, reject) => {
- const request = isNode ? require("request") : $httpClient;
- request[method.toLowerCase()](options, (err, response, body) => {
- if (err) reject(err);
- else
- resolve({
- statusCode: response.status || response.statusCode,
- headers: response.headers,
- body,
- });
- });
- });
- } else if (isScriptable) {
- const request = new Request(options.url);
- request.method = method;
- request.headers = options.headers;
- request.body = options.body;
- worker = new Promise((resolve, reject) => {
- request
- .loadString()
- .then((body) => {
- resolve({
- statusCode: request.response.statusCode,
- headers: request.response.headers,
- body,
- });
- })
- .catch((err) => reject(err));
- });
- } else if (isBrowser) {
- worker = new Promise((resolve, reject) => {
- fetch(options.url, {
- method,
- headers: options.headers,
- body: options.body,
- })
- .then(response => response.json())
- .then(response => resolve({
- statusCode: response.status,
- headers: response.headers,
- body: response.data,
- })).catch(reject);
- });
- }
- let timeoutid;
- const timer = timeout ?
- new Promise((_, reject) => {
- timeoutid = setTimeout(() => {
- events.onTimeout();
- return reject(
- `${method} URL: ${options.url} exceeds the timeout ${timeout} ms`
- );
- }, timeout);
- }) :
- null;
- return (timer ?
- Promise.race([timer, worker]).then((res) => {
- clearTimeout(timeoutid);
- return res;
- }) :
- worker
- ).then((resp) => events.onResponse(resp));
- }
- const http = {};
- methods.forEach(
- (method) =>
- (http[method.toLowerCase()] = (options) => send(method, options))
- );
- return http;
- }
- function API(name = "untitled", debug = false) {
- const {
- isQX,
- isLoon,
- isSurge,
- isNode,
- isJSBox,
- isScriptable
- } = ENV();
- return new (class {
- constructor(name, debug) {
- this.name = name;
- this.debug = debug;
- this.http = HTTP();
- this.env = ENV();
- this.node = (() => {
- if (isNode) {
- const fs = require("fs");
- return {
- fs,
- };
- } else {
- return null;
- }
- })();
- this.initCache();
- const delay = (t, v) =>
- new Promise(function (resolve) {
- setTimeout(resolve.bind(null, v), t);
- });
- Promise.prototype.delay = function (t) {
- return this.then(function (v) {
- return delay(t, v);
- });
- };
- }
- // persistence
- // initialize cache
- initCache() {
- if (isQX) this.cache = JSON.parse($prefs.valueForKey(this.name) || "{}");
- if (isLoon || isSurge)
- this.cache = JSON.parse($persistentStore.read(this.name) || "{}");
- if (isNode) {
- // create a json for root cache
- let fpath = "root.json";
- if (!this.node.fs.existsSync(fpath)) {
- this.node.fs.writeFileSync(
- fpath,
- JSON.stringify({}), {
- flag: "wx"
- },
- (err) => console.log(err)
- );
- }
- this.root = {};
- // create a json file with the given name if not exists
- fpath = `${this.name}.json`;
- if (!this.node.fs.existsSync(fpath)) {
- this.node.fs.writeFileSync(
- fpath,
- JSON.stringify({}), {
- flag: "wx"
- },
- (err) => console.log(err)
- );
- this.cache = {};
- } else {
- this.cache = JSON.parse(
- this.node.fs.readFileSync(`${this.name}.json`)
- );
- }
- }
- }
- // store cache
- persistCache() {
- const data = JSON.stringify(this.cache, null, 2);
- if (isQX) $prefs.setValueForKey(data, this.name);
- if (isLoon || isSurge) $persistentStore.write(data, this.name);
- if (isNode) {
- this.node.fs.writeFileSync(
- `${this.name}.json`,
- data, {
- flag: "w"
- },
- (err) => console.log(err)
- );
- this.node.fs.writeFileSync(
- "root.json",
- JSON.stringify(this.root, null, 2), {
- flag: "w"
- },
- (err) => console.log(err)
- );
- }
- }
- write(data, key) {
- this.log(`SET ${key}`);
- if (key.indexOf("#") !== -1) {
- key = key.substr(1);
- if (isSurge || isLoon) {
- return $persistentStore.write(data, key);
- }
- if (isQX) {
- return $prefs.setValueForKey(data, key);
- }
- if (isNode) {
- this.root[key] = data;
- }
- } else {
- this.cache[key] = data;
- }
- this.persistCache();
- }
- read(key) {
- this.log(`READ ${key}`);
- if (key.indexOf("#") !== -1) {
- key = key.substr(1);
- if (isSurge || isLoon) {
- return $persistentStore.read(key);
- }
- if (isQX) {
- return $prefs.valueForKey(key);
- }
- if (isNode) {
- return this.root[key];
- }
- } else {
- return this.cache[key];
- }
- }
- delete(key) {
- this.log(`DELETE ${key}`);
- if (key.indexOf("#") !== -1) {
- key = key.substr(1);
- if (isSurge || isLoon) {
- return $persistentStore.write(null, key);
- }
- if (isQX) {
- return $prefs.removeValueForKey(key);
- }
- if (isNode) {
- delete this.root[key];
- }
- } else {
- delete this.cache[key];
- }
- this.persistCache();
- }
- // notification
- notify(title, subtitle = "", content = "", options = {}) {
- const openURL = options["open-url"];
- const mediaURL = options["media-url"];
- if (isQX) $notify(title, subtitle, content, options);
- if (isSurge) {
- $notification.post(
- title,
- subtitle,
- content + `${mediaURL ? "\n多媒体:" + mediaURL : ""}`, {
- url: openURL,
- }
- );
- }
- if (isLoon) {
- let opts = {};
- if (openURL) opts["openUrl"] = openURL;
- if (mediaURL) opts["mediaUrl"] = mediaURL;
- if (JSON.stringify(opts) === "{}") {
- $notification.post(title, subtitle, content);
- } else {
- $notification.post(title, subtitle, content, opts);
- }
- }
- if (isNode || isScriptable) {
- const content_ =
- content +
- (openURL ? `\n点击跳转: ${openURL}` : "") +
- (mediaURL ? `\n多媒体: ${mediaURL}` : "");
- if (isJSBox) {
- const push = require("push");
- push.schedule({
- title: title,
- body: (subtitle ? subtitle + "\n" : "") + content_,
- });
- } else {
- console.log(`${title}\n${subtitle}\n${content_}\n\n`);
- }
- }
- }
- // other helper functions
- log(msg) {
- if (this.debug) console.log(`[${this.name}] LOG: ${this.stringify(msg)}`);
- }
- info(msg) {
- console.log(`[${this.name}] INFO: ${this.stringify(msg)}`);
- }
- error(msg) {
- console.log(`[${this.name}] ERROR: ${this.stringify(msg)}`);
- }
- wait(millisec) {
- return new Promise((resolve) => setTimeout(resolve, millisec));
- }
- done(value = {}) {
- if (isQX || isLoon || isSurge) {
- $done(value);
- } else if (isNode && !isJSBox) {
- if (typeof $context !== "undefined") {
- $context.headers = value.headers;
- $context.statusCode = value.statusCode;
- $context.body = value.body;
- }
- }
- }
- stringify(obj_or_str) {
- if (typeof obj_or_str === 'string' || obj_or_str instanceof String)
- return obj_or_str;
- else
- try {
- return JSON.stringify(obj_or_str, null, 2);
- } catch (err) {
- return "[object Object]";
- }
- }
- })(name, debug);
- }
|