gridfs.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. // crowi-fileupload-gridFS
  2. module.exports = function(crowi) {
  3. 'use strict';
  4. const debug = require('debug')('growi:service:fileUploaderGridfs');
  5. const mongoose = require('mongoose');
  6. const path = require('path');
  7. const fs = require('fs');
  8. const lib = {};
  9. // instantiate mongoose-gridfs
  10. const gridfs = require('mongoose-gridfs')({
  11. collection: 'attachmentFiles',
  12. model: 'AttachmentFile',
  13. mongooseConnection: mongoose.connection
  14. });
  15. // obtain a model
  16. const AttachmentFile = gridfs.model;
  17. // delete a file
  18. lib.deleteFile = async function(fileId, filePath) {
  19. debug('File deletion: ' + fileId);
  20. const file = await getFile(filePath);
  21. const id = file.id;
  22. AttachmentFile.unlinkById(id, function(error, unlinkedAttachment) {
  23. if (error) {
  24. throw new Error(error);
  25. }
  26. });
  27. clearCache(fileId);
  28. };
  29. const clearCache = (fileId) => {
  30. const cacheFile = createCacheFileName(fileId);
  31. const stats = fs.statSync(crowi.cacheDir);
  32. if (stats.isFile(`attachment-${fileId}`)) {
  33. fs.unlink(cacheFile, (err) => {
  34. if (err) {
  35. throw new Error('fail to delete cache file', err);
  36. }
  37. });
  38. }
  39. };
  40. lib.uploadFile = async function(filePath, contentType, fileStream, options) {
  41. debug('File uploading: ' + filePath);
  42. await writeFile(filePath, contentType, fileStream);
  43. };
  44. /**
  45. * write file to MongoDB with GridFS (Promise wrapper)
  46. */
  47. const writeFile = (filePath, contentType, fileStream) => {
  48. return new Promise((resolve, reject) => {
  49. AttachmentFile.write({
  50. filename: filePath,
  51. contentType: contentType
  52. }, fileStream,
  53. function(error, createdFile) {
  54. if (error) {
  55. reject(error);
  56. }
  57. resolve();
  58. });
  59. });
  60. };
  61. lib.getFileData = async function(filePath) {
  62. const file = await getFile(filePath);
  63. const id = file.id;
  64. const contentType = file.contentType;
  65. const data = await readFileData(id);
  66. return {
  67. data,
  68. contentType
  69. };
  70. };
  71. /**
  72. * get file from MongoDB (Promise wrapper)
  73. */
  74. const getFile = (filePath) => {
  75. return new Promise((resolve, reject) => {
  76. AttachmentFile.findOne({
  77. filename: filePath
  78. }, function(err, file) {
  79. if (err) {
  80. reject(err);
  81. }
  82. resolve(file);
  83. });
  84. });
  85. };
  86. /**
  87. * read File in MongoDB (Promise wrapper)
  88. */
  89. const readFileData = (id) => {
  90. return new Promise((resolve, reject) => {
  91. let buf;
  92. const stream = AttachmentFile.readById(id);
  93. stream.on('error', function(error) {
  94. reject(error);
  95. });
  96. stream.on('data', function(data) {
  97. if (buf) {
  98. buf = Buffer.concat([buf, data]);
  99. }
  100. else {
  101. buf = data;
  102. }
  103. });
  104. stream.on('close', function() {
  105. debug('GridFS readstream closed');
  106. resolve(buf);
  107. });
  108. });
  109. };
  110. lib.findDeliveryFile = async function(fileId, filePath) {
  111. const cacheFile = createCacheFileName(fileId);
  112. debug('Load attachement file into local cache file', cacheFile);
  113. const fileStream = fs.createWriteStream(cacheFile);
  114. const file = await getFile(filePath);
  115. const id = file.id;
  116. const buf = await readFileData(id);
  117. await writeCacheFile(fileStream, buf);
  118. return cacheFile;
  119. };
  120. const createCacheFileName = (fileId) => {
  121. return path.join(crowi.cacheDir, `attachment-${fileId}`);
  122. };
  123. /**
  124. * write cache file (Promise wrapper)
  125. */
  126. const writeCacheFile = (fileStream, data) => {
  127. return new Promise((resolve, reject) => {
  128. fileStream.write(data);
  129. resolve();
  130. });
  131. };
  132. lib.generateUrl = function(filePath) {
  133. return `/${filePath}`;
  134. };
  135. return lib;
  136. };