UNPKG

f2e-server3

Version:

f2e-server 3.0

126 lines (116 loc) 4.71 kB
import logger from "./logger" import { networkInterfaces } from 'node:os' import mime from "./mime" import { page_layout } from "./templates" export const REG_FILENAME = /[^\\/,\s\t\n]+/g export const pathname_arr = (str = ''): string[] => (str.split(/[#?]+/)[0].replace(/^\.+\//, '').match(REG_FILENAME) || []) export const pathname_fixer = (str = '') => pathname_arr(str).join('/') export const pathname_dirname = (str = '') => (str.match(REG_FILENAME) || []).slice(0, -1).join('/') export const createSessionId = () => 'xxxx-xxxx-xxxx-xxxx'.replace(/xxxx/g, () => Math.floor((1 << 16) + Math.random() * (1 << 24)).toString(16).substring(0, 4)) export const minimatch = (str = '', pattern = '') => { const reg = new RegExp(pattern.replace(/\./g, '\\.').replace(/\*/g, '.*').replace(/,/g, '|')) return reg.test(str) } export const getMimeType = (pathname: string) => { const suffix = (pathname || '').split('.').pop() || '' return mime.getType(suffix) || 'application/octet-stream' } export const isText = (pathname: string) => { const type = getMimeType(pathname) return /\b(html?|txt|javascript|json)\b/.test(type || 'exe') } export const decode = (str: string) => { try { return decodeURIComponent(str) } catch (e) { logger.warn(e) return str } } export const toBuffer = function (arrayBuffer: ArrayBuffer) { const buffer = Buffer.alloc(arrayBuffer.byteLength); const arrayBufferView = new Uint8Array(arrayBuffer); for (let i = 0; i < arrayBufferView.length; i++) { buffer[i] = arrayBufferView[i]; } return buffer } export const ServerIP = (Object.entries(networkInterfaces()) .find(([__, info]) => info?.filter((t) => t.family === 'IPv4' && !t.internal)[0])?.[1]?.filter((t) => t.family === 'IPv4' && !t.internal)[0] || {address: '127.0.0.1'}).address export const queryparams = (search: string) => { const searchParams = new URLSearchParams(search) const params: Record<string, string | string[]> = {} searchParams.forEach((v, k) => { if (params[k]) { params[k] = ([] as string[]).concat(params[k]).concat(v) } else { params[k] = v } }) return params } export const get = function loopGet (obj: any, path: string | string[]): any { const [key, ...rest] = path.toString().match(REG_FILENAME) || [] if (!key || !obj) { return obj } if (rest.length === 0) { return obj[key] } return loopGet(obj[key], rest) } export const set = function loopSet (obj: any, path: string | string[], value: any): any { const [key, ...rest] = path.toString().match(REG_FILENAME) || [] if (!key) return if (rest.length === 0) { Object.assign(obj, { [key]: value }) } else { if (!obj[key]) { obj[key] = {} } loopSet(obj[key], rest, value) } } export const isPlainObject = function (value: any) { if (!value || typeof value != 'object') { return false } return Object.prototype.toString.call(value) === '[object Object]' } /** 简单字符串模板,类似 handlebars */ export const template = function template (tpl: string, data: any, toBlank = true, index?: number): string { return tpl .replace(/{{!--[\s\S]*?--}}/g, '') // 删除注释 .replace(/\{\{#?(\w+)\s+(\w+)[^{}]*\}\}([\s\S\t\r\n]*?)\{\{\/\1\}\}/g, function (_: any, fn: any, item_key: any, line: any) { const items = data[item_key] const _placeholder = toBlank ? '' : _ switch (fn) { case 'each': return items ? items.map((item: any, index: number) => template(line, item, toBlank, index)).join('') : _placeholder case 'if': return items ? template(line, items) : _placeholder default: return template(line, items) } }) .replace(/\{\{([@\$\.\w]+)\}\}/g, (__, key) => { const _placeholder = toBlank ? '' : __ switch (key) { case '@': return typeof data !== 'undefined' ? data : _placeholder; case '@index': return index; default: return typeof data[key] !== 'undefined' ? data[key] : _placeholder } }) } export const renderHTML = (body: string, data: any) => { if (!isPlainObject(data)) { return body } return template(page_layout, { title: data.title || 'F2E Page', body: template(body, data) }) }