@waline/vercel
Version:
vercel server for waline comment system
191 lines (152 loc) • 3.98 kB
JavaScript
const IP2Region = require('ip2region').default;
const parser = require('ua-parser-js');
const preventMessage = 'PREVENT_NEXT_PROCESS';
// Cached IP2Region instance using IIFE closure pattern
// Instance is created on first access and reused for all subsequent calls
const getIP2RegionInstance = (() => {
let instance = null;
return () => {
if (!instance) {
instance = new IP2Region({
ipv4db: process.env.IP2REGION_DB_V4 || process.env.IP2REGION_DB,
ipv6db: process.env.IP2REGION_DB_V6,
});
}
return instance;
};
})();
const OS_VERSION_MAP = {
Windows: {
'NT 11.0': '11',
},
};
module.exports = {
prevent() {
throw new Error(preventMessage);
},
isPrevent(err) {
return think.isError(err) && err.message === preventMessage;
},
findLastIndex(arr, fn) {
for (let i = arr.length - 1; i >= 0; i--) {
const ret = fn(arr[i], i, arr);
if (!ret) {
continue;
}
return i;
}
return -1;
},
promiseAllQueue(promises, taskNum) {
return new Promise((resolve, reject) => {
if (promises.length === 0) {
resolve();
return;
}
const ret = [];
let index = 0;
let count = 0;
const runTask = () => {
const idx = index;
index += 1;
if (index > promises.length) {
return Promise.resolve();
}
return promises[idx].then((data) => {
ret[idx] = data;
count += 1;
if (count === promises.length) {
resolve(ret);
}
return runTask();
}, reject);
};
for (let i = 0; i < taskNum; i++) {
runTask();
}
});
},
async ip2region(ip, { depth = 1 }) {
if (!ip) return '';
try {
const res = getIP2RegionInstance().search(ip);
if (!res) {
return '';
}
const { province, city, isp } = res;
const address = [...new Set([province, city, isp].filter(Boolean))];
return address.slice(0, depth).join(' ');
} catch (err) {
console.log(err);
return '';
}
},
uaParser(uaText) {
const ua = parser(uaText);
if (OS_VERSION_MAP[ua.os.name]?.[ua.os.version]) {
ua.os.version = OS_VERSION_MAP[ua.os.name][ua.os.version];
}
return ua;
},
getLevel(val) {
const levels = this.config('levels');
const defaultLevel = 0;
if (!val) {
return defaultLevel;
}
const level = think.findLastIndex(levels, (level) => level <= val);
return level === -1 ? defaultLevel : level;
},
pluginMap(type, callback) {
const plugins = think.config('plugins');
const fns = [];
if (!think.isArray(plugins)) {
return fns;
}
for (const plugin of plugins) {
if (!plugin?.[type]) {
continue;
}
const res = callback(plugin[type]);
if (!res) {
continue;
}
fns.push(res);
}
return fns;
},
getPluginMiddlewares() {
const middlewares = think.pluginMap('middlewares', (middleware) => {
if (think.isFunction(middleware)) {
return middleware;
}
if (think.isArray(middleware)) {
return middleware.filter((middleware) => think.isFunction(middleware));
}
});
return middlewares.flat();
},
getPluginHook(hookName) {
return think
.pluginMap('hooks', (hook) => (think.isFunction(hook[hookName]) ? hook[hookName] : null))
.filter(Boolean);
},
buildUrl(path, query = {}) {
const notEmptyQuery = {};
for (const key in query) {
if (!query[key]) {
continue;
}
notEmptyQuery[key] = query[key];
}
const notEmptyQueryStr = new URLSearchParams(notEmptyQuery).toString();
let destUrl = path;
if (destUrl && notEmptyQueryStr) {
destUrl += destUrl.includes('?') ? '&' : '?';
}
if (notEmptyQueryStr) {
destUrl += notEmptyQueryStr;
}
return destUrl;
},
};