ProjectOutputFileAgent.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. const AuthorizationManager = require('../Authorization/AuthorizationManager')
  2. const CompileManager = require('../Compile/CompileManager')
  3. const ClsiManager = require('../Compile/ClsiManager')
  4. const ProjectFileAgent = require('./ProjectFileAgent')
  5. const _ = require('underscore')
  6. const {
  7. CompileFailedError,
  8. BadDataError,
  9. AccessDeniedError,
  10. OutputFileFetchFailedError,
  11. } = require('./LinkedFilesErrors')
  12. const LinkedFilesHandler = require('./LinkedFilesHandler')
  13. function _prepare(projectId, linkedFileData, userId, callback) {
  14. _checkAuth(projectId, linkedFileData, userId, (err, allowed) => {
  15. if (err) {
  16. return callback(err)
  17. }
  18. if (!allowed) {
  19. return callback(new AccessDeniedError())
  20. }
  21. if (!_validate(linkedFileData)) {
  22. return callback(new BadDataError())
  23. }
  24. callback(null, linkedFileData)
  25. })
  26. }
  27. function createLinkedFile(
  28. projectId,
  29. linkedFileData,
  30. name,
  31. parentFolderId,
  32. userId,
  33. callback
  34. ) {
  35. if (!ProjectFileAgent._canCreate(linkedFileData)) {
  36. return callback(new AccessDeniedError())
  37. }
  38. linkedFileData = _sanitizeData(linkedFileData)
  39. _prepare(projectId, linkedFileData, userId, (err, linkedFileData) => {
  40. if (err) {
  41. return callback(err)
  42. }
  43. _getFileStream(linkedFileData, userId, (err, readStream) => {
  44. if (err) {
  45. return callback(err)
  46. }
  47. readStream.on('error', callback)
  48. readStream.on('response', response => {
  49. if (response.statusCode >= 200 && response.statusCode < 300) {
  50. LinkedFilesHandler.importFromStream(
  51. projectId,
  52. readStream,
  53. linkedFileData,
  54. name,
  55. parentFolderId,
  56. userId,
  57. (err, file) => {
  58. if (err) {
  59. return callback(err)
  60. }
  61. callback(null, file._id)
  62. }
  63. ) // Created
  64. } else {
  65. err = new OutputFileFetchFailedError(
  66. `Output file fetch failed: ${linkedFileData.build_id}, ${linkedFileData.source_output_file_path}`
  67. )
  68. err.statusCode = response.statusCode
  69. callback(err)
  70. }
  71. })
  72. })
  73. })
  74. }
  75. function refreshLinkedFile(
  76. projectId,
  77. linkedFileData,
  78. name,
  79. parentFolderId,
  80. userId,
  81. callback
  82. ) {
  83. _prepare(projectId, linkedFileData, userId, (err, linkedFileData) => {
  84. if (err) {
  85. return callback(err)
  86. }
  87. _compileAndGetFileStream(
  88. linkedFileData,
  89. userId,
  90. (err, readStream, newBuildId) => {
  91. if (err) {
  92. return callback(err)
  93. }
  94. readStream.on('error', callback)
  95. readStream.on('response', response => {
  96. if (response.statusCode >= 200 && response.statusCode < 300) {
  97. linkedFileData.build_id = newBuildId
  98. LinkedFilesHandler.importFromStream(
  99. projectId,
  100. readStream,
  101. linkedFileData,
  102. name,
  103. parentFolderId,
  104. userId,
  105. (err, file) => {
  106. if (err) {
  107. return callback(err)
  108. }
  109. callback(null, file._id)
  110. }
  111. ) // Created
  112. } else {
  113. err = new OutputFileFetchFailedError(
  114. `Output file fetch failed: ${linkedFileData.build_id}, ${linkedFileData.source_output_file_path}`
  115. )
  116. err.statusCode = response.statusCode
  117. callback(err)
  118. }
  119. })
  120. }
  121. )
  122. })
  123. }
  124. function _sanitizeData(data) {
  125. return {
  126. provider: data.provider,
  127. source_project_id: data.source_project_id,
  128. source_output_file_path: data.source_output_file_path,
  129. build_id: data.build_id,
  130. clsiServerId: data.clsiServerId,
  131. }
  132. }
  133. function _validate(data) {
  134. return (
  135. (data.v1_source_doc_id != null && data.source_output_file_path != null) ||
  136. (data.source_project_id != null &&
  137. data.source_output_file_path != null &&
  138. data.build_id != null)
  139. )
  140. }
  141. function _checkAuth(projectId, data, currentUserId, callback) {
  142. callback = _.once(callback)
  143. if (!_validate(data)) {
  144. return callback(new BadDataError())
  145. }
  146. LinkedFilesHandler.getSourceProject(data, (err, project) => {
  147. if (err) {
  148. return callback(err)
  149. }
  150. AuthorizationManager.canUserReadProject(
  151. currentUserId,
  152. project._id,
  153. null,
  154. (err, canRead) => {
  155. if (err) {
  156. return callback(err)
  157. }
  158. callback(null, canRead)
  159. }
  160. )
  161. })
  162. }
  163. function _getFileStream(linkedFileData, userId, callback) {
  164. callback = _.once(callback)
  165. const {
  166. source_output_file_path: sourceOutputFilePath,
  167. build_id: buildId,
  168. clsiServerId,
  169. } = linkedFileData
  170. LinkedFilesHandler.getSourceProject(linkedFileData, (err, project) => {
  171. if (err) {
  172. return callback(err)
  173. }
  174. const sourceProjectId = project._id
  175. CompileManager.getProjectCompileLimits(sourceProjectId, (err, limits) => {
  176. if (err) return callback(err)
  177. ClsiManager.getOutputFileStream(
  178. sourceProjectId,
  179. userId,
  180. limits,
  181. clsiServerId,
  182. buildId,
  183. sourceOutputFilePath,
  184. (err, readStream) => {
  185. if (err) {
  186. return callback(err)
  187. }
  188. readStream.pause()
  189. callback(null, readStream)
  190. }
  191. )
  192. })
  193. })
  194. }
  195. function _compileAndGetFileStream(linkedFileData, userId, callback) {
  196. callback = _.once(callback)
  197. const { source_output_file_path: sourceOutputFilePath } = linkedFileData
  198. LinkedFilesHandler.getSourceProject(linkedFileData, (err, project) => {
  199. if (err) {
  200. return callback(err)
  201. }
  202. const sourceProjectId = project._id
  203. CompileManager.compile(
  204. sourceProjectId,
  205. userId,
  206. {},
  207. (err, status, outputFiles, clsiServerId, limits) => {
  208. if (err) {
  209. return callback(err)
  210. }
  211. if (status !== 'success') {
  212. return callback(new CompileFailedError())
  213. }
  214. const outputFile = _.find(
  215. outputFiles,
  216. o => o.path === sourceOutputFilePath
  217. )
  218. if (outputFile == null) {
  219. return callback(new OutputFileFetchFailedError())
  220. }
  221. const buildId = outputFile.build
  222. ClsiManager.getOutputFileStream(
  223. sourceProjectId,
  224. userId,
  225. limits,
  226. clsiServerId,
  227. buildId,
  228. sourceOutputFilePath,
  229. (err, readStream) => {
  230. if (err) {
  231. return callback(err)
  232. }
  233. readStream.pause()
  234. callback(null, readStream, buildId)
  235. }
  236. )
  237. }
  238. )
  239. })
  240. }
  241. module.exports = { createLinkedFile, refreshLinkedFile }