songs.js 9.4 KB

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