@sync-in/server
Version:
The secure, open-source platform for file storage, sharing, collaboration, and sync
171 lines (170 loc) • 7.9 kB
JavaScript
/*
* 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 _schedulerconstants = require("../../scheduler/scheduler.constants");
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 onModuleInit() {
if (_nodecluster.default.isWorker && process.env[_schedulerconstants.SCHEDULER_ENV] === _schedulerconstants.SCHEDULER_STATE.ENABLED) {
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 onModuleDestroy() {
if (this.scheduledJob) {
await this.scheduledJob.stop();
}
}
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: _mysqlcacheschema.cache.value
}).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: _mysqlcacheschema.cache.value
}).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;
}
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)());
}
};
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