'use strict'; const coreClass = require("../core"); const async = require('async'); module.exports = class extends coreClass { constructor(name, moduleManager) { super(name, moduleManager); this.dependsOn = ["cache", "db", "utils"]; } initialize() { return new Promise((resolve, reject) => { this.cache = this.moduleManager.modules["cache"]; this.db = this.moduleManager.modules["db"]; this.utils = this.moduleManager.modules["utils"]; async.waterfall([ (next) => { this.cache.hgetall('playlists', next); }, (playlists, next) => { if (!playlists) return next(); let playlistIds = Object.keys(playlists); async.each(playlistIds, (playlistId, next) => { this.db.models.playlist.findOne({_id: playlistId}, (err, playlist) => { if (err) next(err); else if (!playlist) { this.cache.hdel('playlists', playlistId, next); } else next(); }); }, next); }, (next) => { this.db.models.playlist.find({}, next); }, (playlists, next) => { async.each(playlists, (playlist, next) => { this.cache.hset('playlists', playlist._id, this.cache.schemas.playlist(playlist), next); }, next); } ], async (err) => { if (err) { err = await this.utils.getError(err); reject(err); } else { resolve(); } }); }); } /** * Gets a playlist by id from the cache or Mongo, and if it isn't in the cache yet, adds it the cache * * @param {String} playlistId - the id of the playlist we are trying to get * @param {Function} cb - gets called once we're done initializing */ async getPlaylist(playlistId, cb) { try { await this._validateHook(); } catch { return; } async.waterfall([ (next) => { this.cache.hgetall('playlists', next); }, (playlists, next) => { if (!playlists) return next(); let playlistIds = Object.keys(playlists); async.each(playlistIds, (playlistId, next) => { this.db.models.playlist.findOne({_id: playlistId}, (err, playlist) => { if (err) next(err); else if (!playlist) { this.cache.hdel('playlists', playlistId, next); } else next(); }); }, next); }, (next) => { this.cache.hget('playlists', playlistId, next); }, (playlist, next) => { if (playlist) return next(true, playlist); this.db.models.playlist.findOne({ _id: playlistId }, next); }, (playlist, next) => { if (playlist) { this.cache.hset('playlists', playlistId, playlist, next); } else next('Playlist not found'); }, ], (err, playlist) => { if (err && err !== true) return cb(err); else cb(null, playlist); }); } /** * Gets a playlist from id from Mongo and updates the cache with it * * @param {String} playlistId - the id of the playlist we are trying to update * @param {Function} cb - gets called when an error occurred or when the operation was successful */ async updatePlaylist(playlistId, cb) { try { await this._validateHook(); } catch { return; } async.waterfall([ (next) => { this.db.models.playlist.findOne({ _id: playlistId }, next); }, (playlist, next) => { if (!playlist) { this.cache.hdel('playlists', playlistId); return next('Playlist not found'); } this.cache.hset('playlists', playlistId, playlist, next); } ], (err, playlist) => { if (err && err !== true) return cb(err); cb(null, playlist); }); } /** * Deletes playlist from id from Mongo and cache * * @param {String} playlistId - the id of the playlist we are trying to delete * @param {Function} cb - gets called when an error occurred or when the operation was successful */ async deletePlaylist(playlistId, cb) { try { await this._validateHook(); } catch { return; } async.waterfall([ (next) => { this.db.models.playlist.deleteOne({ _id: playlistId }, next); }, (res, next) => { this.cache.hdel('playlists', playlistId, next); } ], (err) => { if (err && err !== true) return cb(err); cb(null); }); } }