songs.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. const CoreClass = require("../core.js");
  2. const async = require("async");
  3. const mongoose = require("mongoose");
  4. class SongsModule extends CoreClass {
  5. constructor() {
  6. super("songs");
  7. }
  8. initialize() {
  9. return new Promise(async (resolve, reject) => {
  10. this.setStage(1);
  11. this.cache = this.moduleManager.modules["cache"];
  12. this.db = this.moduleManager.modules["db"];
  13. this.io = this.moduleManager.modules["io"];
  14. this.utils = this.moduleManager.modules["utils"];
  15. const songModel = await this.db.runJob("GET_MODEL", {
  16. modelName: "song",
  17. });
  18. const songSchema = await this.cache.runJob("GET_SCHEMA", {
  19. schemaName: "song",
  20. });
  21. async.waterfall(
  22. [
  23. (next) => {
  24. this.setStage(2);
  25. this.cache
  26. .runJob("HGETALL", { table: "songs" })
  27. .then((songs) => next(null, songs))
  28. .catch(next);
  29. },
  30. (songs, next) => {
  31. this.setStage(3);
  32. if (!songs) return next();
  33. let songIds = Object.keys(songs);
  34. async.each(
  35. songIds,
  36. (songId, next) => {
  37. songModel.findOne({ songId }, (err, song) => {
  38. if (err) next(err);
  39. else if (!song)
  40. this.cache
  41. .runJob("HDEL", {
  42. table: "songs",
  43. key: songId,
  44. })
  45. .then(() => next())
  46. .catch(next);
  47. else next();
  48. });
  49. },
  50. next
  51. );
  52. },
  53. (next) => {
  54. this.setStage(4);
  55. songModel.find({}, next);
  56. },
  57. (songs, next) => {
  58. this.setStage(5);
  59. async.each(
  60. songs,
  61. (song, next) => {
  62. this.cache
  63. .runJob("HSET", {
  64. table: "songs",
  65. key: song.songId,
  66. value: songSchema(song),
  67. })
  68. .then(() => next())
  69. .catch(next);
  70. },
  71. next
  72. );
  73. },
  74. ],
  75. async (err) => {
  76. if (err) {
  77. err = await this.utils.runJob("GET_ERROR", {
  78. error: err,
  79. });
  80. reject(new Error(err));
  81. } else {
  82. resolve();
  83. }
  84. }
  85. );
  86. });
  87. }
  88. /**
  89. * Gets a song by id from the cache or Mongo, and if it isn't in the cache yet, adds it the cache
  90. *
  91. * @param {String} id - the id of the song we are trying to get
  92. * @param {Function} cb - gets called once we're done initializing
  93. */
  94. GET_SONG(payload) {
  95. //id, cb
  96. return new Promise(async (resolve, reject) => {
  97. const songModel = await this.db.runJob("GET_MODEL", {
  98. modelName: "song",
  99. });
  100. async.waterfall(
  101. [
  102. (next) => {
  103. if (!mongoose.Types.ObjectId.isValid(payload.id))
  104. return next("Id is not a valid ObjectId.");
  105. this.cache
  106. .runJob("HGET", { table: "songs", key: payload.id })
  107. .then((song) => next(null, song))
  108. .catch(next);
  109. },
  110. (song, next) => {
  111. if (song) return next(true, song);
  112. songModel.findOne({ _id: payload.id }, next);
  113. },
  114. (song, next) => {
  115. if (song) {
  116. this.cache
  117. .runJob("HSET", {
  118. table: "songs",
  119. key: payload.id,
  120. value: song,
  121. })
  122. .then((song) => next(null, song));
  123. } else next("Song not found.");
  124. },
  125. ],
  126. (err, song) => {
  127. if (err && err !== true) return reject(new Error(err));
  128. resolve({ song });
  129. }
  130. );
  131. });
  132. }
  133. /**
  134. * Gets a song by song id from the cache or Mongo, and if it isn't in the cache yet, adds it the cache
  135. *
  136. * @param {String} songId - the mongo id of the song we are trying to get
  137. * @param {Function} cb - gets called once we're done initializing
  138. */
  139. GET_SONG_FROM_ID(payload) {
  140. //songId, cb
  141. return new Promise(async (resolve, reject) => {
  142. const songModel = await this.db.runJob("GET_MODEL", {
  143. modelName: "song",
  144. });
  145. async.waterfall(
  146. [
  147. (next) => {
  148. songModel.findOne({ songId: payload.songId }, next);
  149. },
  150. ],
  151. (err, song) => {
  152. if (err && err !== true) return reject(new Error(err));
  153. resolve({ song });
  154. }
  155. );
  156. });
  157. }
  158. /**
  159. * Gets a song from id from Mongo and updates the cache with it
  160. *
  161. * @param {String} songId - the id of the song we are trying to update
  162. * @param {Function} cb - gets called when an error occurred or when the operation was successful
  163. */
  164. UPDATE_SONG(payload) {
  165. //songId, cb
  166. return new Promise(async (resolve, reject) => {
  167. const songModel = await this.db.runJob("GET_MODEL", {
  168. modelName: "song",
  169. });
  170. async.waterfall(
  171. [
  172. (next) => {
  173. songModel.findOne({ _id: payload.songId }, next);
  174. },
  175. (song, next) => {
  176. if (!song) {
  177. this.cache.runJob("HDEL", {
  178. table: "songs",
  179. key: payload.songId,
  180. });
  181. return next("Song not found.");
  182. }
  183. this.cache
  184. .runJob("HSET", {
  185. table: "songs",
  186. key: payload.songId,
  187. value: song,
  188. })
  189. .then((song) => next(null, song))
  190. .catch(next);
  191. },
  192. ],
  193. (err, song) => {
  194. if (err && err !== true) return reject(new Error(err));
  195. resolve(song);
  196. }
  197. );
  198. });
  199. }
  200. /**
  201. * Deletes song from id from Mongo and cache
  202. *
  203. * @param {String} songId - the id of the song we are trying to delete
  204. * @param {Function} cb - gets called when an error occurred or when the operation was successful
  205. */
  206. DELETE_SONG(payload) {
  207. //songId, cb
  208. return new Promise(async (resolve, reject) => {
  209. const songModel = await this.db.runJob("GET_MODEL", {
  210. modelName: "song",
  211. });
  212. async.waterfall(
  213. [
  214. (next) => {
  215. songModel.deleteOne({ songId: payload.songId }, next);
  216. },
  217. (next) => {
  218. this.cache
  219. .runJob("HDEL", {
  220. table: "songs",
  221. key: payload.songId,
  222. })
  223. .then(() => next())
  224. .catch(next);
  225. },
  226. ],
  227. (err) => {
  228. if (err && err !== true) return reject(new Error(err));
  229. resolve();
  230. }
  231. );
  232. });
  233. }
  234. }
  235. module.exports = new SongsModule();