UNPKG

@sync-in/server

Version:

The secure, open-source platform for file storage, sharing, collaboration, and sync

169 lines (168 loc) 7.87 kB
/* * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com> * This file is part of Sync-in | The open source file sync and share solution * See the LICENSE file for licensing details */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "MysqlCacheAdapter", { enumerable: true, get: function() { return MysqlCacheAdapter; } }); const _common = require("@nestjs/common"); const _schedule = require("@nestjs/schedule"); const _cron = require("cron"); const _drizzleorm = require("drizzle-orm"); const _nodecluster = /*#__PURE__*/ _interop_require_default(require("node:cluster")); const _shared = require("../../../common/shared"); const _configenvironment = require("../../../configuration/config.environment"); const _constants = require("../../database/constants"); const _databaseinterface = require("../../database/interfaces/database.interface"); const _utils = require("../../database/utils"); const _mysqlcacheschema = require("../schemas/mysql-cache.schema"); const _cacheservice = require("../services/cache.service"); function _interop_require_default(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _ts_decorate(decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; } function _ts_metadata(k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); } function _ts_param(paramIndex, decorator) { return function(target, key) { decorator(target, key, paramIndex); }; } let MysqlCacheAdapter = class MysqlCacheAdapter { async initScheduler() { if (!_nodecluster.default.worker || _nodecluster.default.worker.id === 1) { try { await this.db.execute(`SET GLOBAL event_scheduler = ON;`); await this.db.execute(`DROP EVENT IF EXISTS ${this.scheduledJobName};`); await this.db.execute(`CREATE EVENT IF NOT EXISTS ${this.scheduledJobName} ON SCHEDULE EVERY ${this.scheduledJobInterval} MINUTE DO DELETE FROM cache WHERE cache.expiration BETWEEN 0 AND UNIX_TIMESTAMP();`); this.logger.log(`Using MySQL scheduler`); } catch (e) { this.logger.error(`MySQL scheduler on '${e?.sql || e?.code}' : ${e.message || e}`); this.logger.warn(`Fallback to internal scheduler`); this.scheduledJob = new _cron.CronJob(`0 */${this.scheduledJobInterval} * * * *`, async ()=>await this.clearExpiredKeys()); this.scheduler.addCronJob(this.scheduledJobName, this.scheduledJob); this.scheduledJob.start(); } } } async keys(pattern) { const ks = await this.db.select({ key: _mysqlcacheschema.cache.key }).from(_mysqlcacheschema.cache).where((0, _drizzleorm.and)((0, _drizzleorm.like)(_mysqlcacheschema.cache.key, pattern.replaceAll('*', '%')), this.whereNotExpired())); return ks.map((k)=>k.key); } async has(key) { const [r] = await this.db.select({ key: _mysqlcacheschema.cache.key }).from(_mysqlcacheschema.cache).where((0, _drizzleorm.exists)(this.db.select({ key: _mysqlcacheschema.cache.key }).from(_mysqlcacheschema.cache).where((0, _drizzleorm.and)((0, _drizzleorm.eq)(_mysqlcacheschema.cache.key, key), this.whereNotExpired())))); return !!r; } async get(key) { const [v] = await this.db.select({ value: (0, _drizzleorm.sql)`${_mysqlcacheschema.cache.value}`.mapWith(JSON.parse) }).from(_mysqlcacheschema.cache).where((0, _drizzleorm.and)((0, _drizzleorm.eq)(_mysqlcacheschema.cache.key, key), this.whereNotExpired())).limit(1); return v ? v.value : v; } async mget(keys) { const vs = await this.db.select({ value: (0, _drizzleorm.sql)`${_mysqlcacheschema.cache.value}`.mapWith(JSON.parse) }).from(_mysqlcacheschema.cache).where((0, _drizzleorm.and)((0, _drizzleorm.inArray)(_mysqlcacheschema.cache.key, keys), this.whereNotExpired())); return vs.map((v)=>v.value); } async set(key, data, ttl) { data = this.serialize(data); const exp = this.getTTL(ttl); try { await this.db.insert(_mysqlcacheschema.cache).values({ key: key, value: data, expiration: exp }).onDuplicateKeyUpdate({ set: { value: data, expiration: exp } }); return true; } catch (e) { this.logger.error(`${this.set.name} - ${e}`); return false; } } async del(key) { return (0, _utils.dbCheckAffectedRows)(await this.db.delete(_mysqlcacheschema.cache).where((0, _drizzleorm.eq)(_mysqlcacheschema.cache.key, key)), 1, false); } async mdel(keys) { return (0, _utils.dbCheckAffectedRows)(await this.db.delete(_mysqlcacheschema.cache).where((0, _drizzleorm.inArray)(_mysqlcacheschema.cache.key, keys)), keys.length, false); } genSlugKey(...args) { return (0, _shared.createSlug)(args.join(' ')); } getTTL(ttl) { /* ttl (seconds): - 0 : infinite expiration - undefined : default ttl */ return ttl ? (0, _shared.currentTimeStamp)() + ttl : ttl === 0 ? this.infiniteExpiration : (0, _shared.currentTimeStamp)() + this.defaultTTL; } async quit() { this.logger.verbose(`${this.quit.name}`); } serialize(data) { if (data === undefined) { // undefined values are not handled by JSON serialization return null; } return data; } async clearExpiredKeys() { try { await this.db.delete(_mysqlcacheschema.cache).where(this.whereExpired()); } catch (e) { this.logger.error(`${this.clearExpiredKeys.name} - ${e?.code || e}`); } } constructor(db, scheduler){ this.db = db; this.scheduler = scheduler; /* Useful sql commands to stats the scheduler SHOW VARIABLES LIKE 'event_scheduler'; SHOW EVENTS; */ this.defaultTTL = _configenvironment.configuration.cache.ttl; this.infiniteExpiration = -1; this.scheduledJobName = 'cache_expired_keys'; this.scheduledJobInterval = 5; // minutes this.logger = new _common.Logger(_cacheservice.Cache.name.toUpperCase()); this.whereNotExpired = ()=>(0, _drizzleorm.notBetween)(_mysqlcacheschema.cache.expiration, 0, (0, _shared.currentTimeStamp)()); this.whereExpired = ()=>(0, _drizzleorm.between)(_mysqlcacheschema.cache.expiration, 0, (0, _shared.currentTimeStamp)()); this.initScheduler().catch((e)=>this.logger.error(e)); } }; MysqlCacheAdapter = _ts_decorate([ (0, _common.Injectable)(), _ts_param(0, (0, _common.Inject)(_constants.DB_TOKEN_PROVIDER)), _ts_metadata("design:type", Function), _ts_metadata("design:paramtypes", [ typeof _databaseinterface.DBSchema === "undefined" ? Object : _databaseinterface.DBSchema, typeof _schedule.SchedulerRegistry === "undefined" ? Object : _schedule.SchedulerRegistry ]) ], MysqlCacheAdapter); //# sourceMappingURL=mysql-cache.adapter.js.map