UNPKG

hexo-seo

Version:
299 lines (286 loc) 7.47 kB
import { existsSync } from 'fs-extra'; import NodeCache from 'node-cache'; import { bindProcessExit, writefile } from 'sbg-utility'; import path from 'upath'; import { buildFolder, readFile, tmpFolder } from './fm'; import logger from './log'; import md5File, { md5, sync as md5FileSync } from './utils/md5-file'; const myCache = new NodeCache({ stdTTL: 500, checkperiod: 520 }); /** * @summary IN MEMORY CACHE * @description cache will be saved in memory/RAM */ class Cache { /** * Identifier Hash for cache */ static md5Cache: Record<string, any> = {}; /** * Set cache * @param key * @param value * @returns */ set(key: string, value: any) { return this.setCache(key, value); } setCache(key: string, value: any) { if (!key || !value) return; if (!key) key = md5(value); return myCache.set(key, value); } get(key: string, fallback?: any) { return this.getCache(key, fallback); } /** * Get cache for given key * @param key * @param fallback fallback if key not in cache * @returns */ getCache(key: string, fallback = null) { return myCache.get(key) || fallback; } isFileChanged(filePath: string) { return md5File(filePath) .then((hash1) => { const hash = Cache.md5Cache[filePath]; Cache.md5Cache[filePath] = hash1; if (!hash) { return true; } if (hash === hash1) { return false; } return true; }) .catch((_err) => { return true; }); } } /** * Transform any variable to string * @param variable * @returns */ export function resolveString(variable: any, _encode = false) { if (typeof variable === 'number') variable = variable.toString(); if (Buffer.isBuffer(variable)) variable = variable.toString(); } /** * @summary IN FILE CACHE. * @description Save cache to file (not in-memory), cache will be restored on next process restart. */ export class CacheFile { md5Cache: Record<string, any> = {}; dbFile: string; constructor(hash = null) { if (!hash) { const stack = new Error().stack.split('at')[2]; hash = md5(stack); } this.dbFile = path.join(tmpFolder, 'db-' + hash + '.json'); let db = readFile(this.dbFile, { encoding: 'utf8' }, {}); if (typeof db != 'object') { try { db = JSON.parse(db.toString()); } catch (e) { logger.error('cache database lost'); logger.error(e); } } if (typeof db == 'object') { this.md5Cache = db; } } setCache(key: string, value: any) { return this.set(key, value); } set(key: string, value: any) { this.md5Cache[key] = value; // save cache on process exit bindProcessExit('writeCacheFile', () => { logger.log('saved cache', this.dbFile); writefile(this.dbFile, JSON.stringify(this.md5Cache)); }); } has(key: string): boolean { return typeof this.md5Cache[key] !== 'undefined'; } /** * Get cache by key * @param key * @param fallback * @returns */ get<T>(key: string, fallback: T = null): T { const Get = this.md5Cache[key]; if (Get === undefined) return fallback; return Get; } /** * alias {get} * @param key * @param fallback * @returns */ getCache<T>(key: string, fallback: T = null): T { return this.get(key, fallback); } /** * Check file is changed with md5 algorithm * @param path0 * @returns */ isFileChanged(path0: string): boolean { if (typeof path0 != 'string') { //console.log("", typeof path0, path0); return true; } try { // get md5 hash from path0 const pathMd5 = md5FileSync(path0); // get index hash const savedMd5 = this.md5Cache[path0 + '-hash']; const result = savedMd5 != pathMd5; if (result) { // set, if file hash is not found this.md5Cache[path0 + '-hash'] = pathMd5; } return result; } catch (e) { return true; } } } /** * @summary IN FILE CACHE. * @description Save cache to file (not in-memory), cache will be restored on next process restart. */ export class CacheFile2 { md5Cache: Record<string, any> = {}; /** * temporary cache */ dbTemp: Record<string, any> = {}; /** * database file */ dbFile: string; /** * database folder */ dbFolder: string; /** * Unique cache id */ cacheHash = ''; constructor(hash = null) { const stack = new Error().stack.split('at')[2]; hash = hash + '-' + md5(stack); this.cacheHash = hash; this.dbFile = path.join(buildFolder, 'db-' + hash + '.json'); this.dbFolder = path.join(buildFolder, hash); let db = readFile(this.dbFile, { encoding: 'utf8' }, {}); if (typeof db != 'object') { try { db = JSON.parse(db.toString()); } catch (e) { logger.error('cache database lost'); logger.error(e); } } if (typeof db == 'object') { this.md5Cache = db; } } getKeyLocation(key: string) { if (key.startsWith('/')) { key = path.join(md5(path.dirname(key)), path.basename(key)); } return path.join(this.dbFolder, key); } set(key: string, value: any) { if (!key && !value) { return; } else if (!key) { key = md5(value); } const saveLocation = this.getKeyLocation(key); this.md5Cache[key] = saveLocation; const dbLocation = path.join(this.dbFile); const db = this.md5Cache; //dump("cache-" + this.cacheHash, db); bindProcessExit('save-' + this.cacheHash, function () { logger.log('saving caches...', saveLocation, dbLocation); writefile(saveLocation, value); writefile(dbLocation, JSON.stringify(db, null, 2)); }); this.dbTemp[key] = value; } /** * Get cache by key * @param key * @param fallback * @returns */ get(key: string, fallback = null) { if (typeof this.dbTemp[key] == 'undefined') { const saveLocation = this.getKeyLocation(key); if (existsSync(saveLocation)) { const readCache = readFile(saveLocation).toString(); this.dbTemp[key] = readCache; return readCache; } if (typeof fallback === 'function') return fallback(); return fallback; } return this.dbTemp[key]; } has(key: string): boolean { return typeof this.md5Cache[key] !== 'undefined'; } getCache(key: string, fallback = null) { return this.get(key, fallback); } setCache(key: string, value: any) { return this.set(key, value); } /** * Check file is changed with md5 algorithm * @param path0 * @returns */ isFileChanged(path0: string): boolean { if (typeof path0 != 'string') { //console.log("", typeof path0, path0); return true; } // get md5 hash from path0 const pathMd5 = md5FileSync(path0); // get index hash const savedMd5 = this.md5Cache[path0 + '-hash']; const isChanged = savedMd5 !== pathMd5; //console.log(savedMd5, pathMd5, result); if (isChanged) { // set, if file hash is not found this.md5Cache[path0 + '-hash'] = pathMd5; } return isChanged; } } /** * Release memories */ export function releaseMemory() { if (!global.gc) { //console.log("Garbage collection is not exposed"); return; } if (process.memoryUsage().heapUsed > 200000000) { // memory use is above 200MB global.gc(); } } export default Cache;