aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/controllers/api/videos.js
diff options
context:
space:
mode:
Diffstat (limited to 'server/controllers/api/videos.js')
-rw-r--r--server/controllers/api/videos.js114
1 files changed, 77 insertions, 37 deletions
diff --git a/server/controllers/api/videos.js b/server/controllers/api/videos.js
index 6829804ec..4d45c11c0 100644
--- a/server/controllers/api/videos.js
+++ b/server/controllers/api/videos.js
@@ -70,13 +70,13 @@ router.put('/:id',
70 oAuth.authenticate, 70 oAuth.authenticate,
71 reqFiles, 71 reqFiles,
72 validatorsVideos.videosUpdate, 72 validatorsVideos.videosUpdate,
73 updateVideo 73 updateVideoRetryWrapper
74) 74)
75router.post('/', 75router.post('/',
76 oAuth.authenticate, 76 oAuth.authenticate,
77 reqFiles, 77 reqFiles,
78 validatorsVideos.videosAdd, 78 validatorsVideos.videosAdd,
79 addVideo 79 addVideoRetryWrapper
80) 80)
81router.get('/:id', 81router.get('/:id',
82 validatorsVideos.videosGet, 82 validatorsVideos.videosGet,
@@ -103,19 +103,37 @@ module.exports = router
103 103
104// --------------------------------------------------------------------------- 104// ---------------------------------------------------------------------------
105 105
106function addVideo (req, res, next) { 106// Wrapper to video add that retry the function if there is a database error
107 const videoFile = req.files.videofile[0] 107// We need this because we run the transaction in SERIALIZABLE isolation that can fail
108function addVideoRetryWrapper (req, res, next) {
109 utils.transactionRetryer(
110 function (callback) {
111 return addVideo(req, res, req.files.videofile[0], callback)
112 },
113 function (err) {
114 if (err) {
115 logger.error('Cannot insert the video with many retries.', { error: err })
116 return next(err)
117 }
118
119 // TODO : include Location of the new video -> 201
120 return res.type('json').status(204).end()
121 }
122 )
123}
124
125function addVideo (req, res, videoFile, callback) {
108 const videoInfos = req.body 126 const videoInfos = req.body
109 127
110 waterfall([ 128 waterfall([
111 129
112 function startTransaction (callback) { 130 function startTransaction (callbackWaterfall) {
113 db.sequelize.transaction().asCallback(function (err, t) { 131 db.sequelize.transaction({ isolationLevel: 'SERIALIZABLE' }).asCallback(function (err, t) {
114 return callback(err, t) 132 return callbackWaterfall(err, t)
115 }) 133 })
116 }, 134 },
117 135
118 function findOrCreateAuthor (t, callback) { 136 function findOrCreateAuthor (t, callbackWaterfall) {
119 const user = res.locals.oauth.token.User 137 const user = res.locals.oauth.token.User
120 138
121 const name = user.username 139 const name = user.username
@@ -124,19 +142,19 @@ function addVideo (req, res, next) {
124 const userId = user.id 142 const userId = user.id
125 143
126 db.Author.findOrCreateAuthor(name, podId, userId, t, function (err, authorInstance) { 144 db.Author.findOrCreateAuthor(name, podId, userId, t, function (err, authorInstance) {
127 return callback(err, t, authorInstance) 145 return callbackWaterfall(err, t, authorInstance)
128 }) 146 })
129 }, 147 },
130 148
131 function findOrCreateTags (t, author, callback) { 149 function findOrCreateTags (t, author, callbackWaterfall) {
132 const tags = videoInfos.tags 150 const tags = videoInfos.tags
133 151
134 db.Tag.findOrCreateTags(tags, t, function (err, tagInstances) { 152 db.Tag.findOrCreateTags(tags, t, function (err, tagInstances) {
135 return callback(err, t, author, tagInstances) 153 return callbackWaterfall(err, t, author, tagInstances)
136 }) 154 })
137 }, 155 },
138 156
139 function createVideoObject (t, author, tagInstances, callback) { 157 function createVideoObject (t, author, tagInstances, callbackWaterfall) {
140 const videoData = { 158 const videoData = {
141 name: videoInfos.name, 159 name: videoInfos.name,
142 remoteId: null, 160 remoteId: null,
@@ -148,74 +166,97 @@ function addVideo (req, res, next) {
148 166
149 const video = db.Video.build(videoData) 167 const video = db.Video.build(videoData)
150 168
151 return callback(null, t, author, tagInstances, video) 169 return callbackWaterfall(null, t, author, tagInstances, video)
152 }, 170 },
153 171
154 // Set the videoname the same as the id 172 // Set the videoname the same as the id
155 function renameVideoFile (t, author, tagInstances, video, callback) { 173 function renameVideoFile (t, author, tagInstances, video, callbackWaterfall) {
156 const videoDir = constants.CONFIG.STORAGE.VIDEOS_DIR 174 const videoDir = constants.CONFIG.STORAGE.VIDEOS_DIR
157 const source = path.join(videoDir, videoFile.filename) 175 const source = path.join(videoDir, videoFile.filename)
158 const destination = path.join(videoDir, video.getVideoFilename()) 176 const destination = path.join(videoDir, video.getVideoFilename())
159 177
160 fs.rename(source, destination, function (err) { 178 fs.rename(source, destination, function (err) {
161 return callback(err, t, author, tagInstances, video) 179 if (err) return callbackWaterfall(err)
180
181 // This is important in case if there is another attempt
182 videoFile.filename = video.getVideoFilename()
183 return callbackWaterfall(null, t, author, tagInstances, video)
162 }) 184 })
163 }, 185 },
164 186
165 function insertVideoIntoDB (t, author, tagInstances, video, callback) { 187 function insertVideoIntoDB (t, author, tagInstances, video, callbackWaterfall) {
166 const options = { transaction: t } 188 const options = { transaction: t }
167 189
168 // Add tags association 190 // Add tags association
169 video.save(options).asCallback(function (err, videoCreated) { 191 video.save(options).asCallback(function (err, videoCreated) {
170 if (err) return callback(err) 192 if (err) return callbackWaterfall(err)
171 193
172 // Do not forget to add Author informations to the created video 194 // Do not forget to add Author informations to the created video
173 videoCreated.Author = author 195 videoCreated.Author = author
174 196
175 return callback(err, t, tagInstances, videoCreated) 197 return callbackWaterfall(err, t, tagInstances, videoCreated)
176 }) 198 })
177 }, 199 },
178 200
179 function associateTagsToVideo (t, tagInstances, video, callback) { 201 function associateTagsToVideo (t, tagInstances, video, callbackWaterfall) {
180 const options = { transaction: t } 202 const options = { transaction: t }
181 203
182 video.setTags(tagInstances, options).asCallback(function (err) { 204 video.setTags(tagInstances, options).asCallback(function (err) {
183 video.Tags = tagInstances 205 video.Tags = tagInstances
184 206
185 return callback(err, t, video) 207 return callbackWaterfall(err, t, video)
186 }) 208 })
187 }, 209 },
188 210
189 function sendToFriends (t, video, callback) { 211 function sendToFriends (t, video, callbackWaterfall) {
190 video.toAddRemoteJSON(function (err, remoteVideo) { 212 video.toAddRemoteJSON(function (err, remoteVideo) {
191 if (err) return callback(err) 213 if (err) return callbackWaterfall(err)
192 214
193 // Now we'll add the video's meta data to our friends 215 // Now we'll add the video's meta data to our friends
194 friends.addVideoToFriends(remoteVideo) 216 friends.addVideoToFriends(remoteVideo, t, function (err) {
195 217 return callbackWaterfall(err, t)
196 return callback(null, t) 218 })
197 }) 219 })
198 } 220 }
199 221
200 ], function andFinally (err, t) { 222 ], function andFinally (err, t) {
201 if (err) { 223 if (err) {
202 logger.error('Cannot insert the video.') 224 // This is just a debug because we will retry the insert
225 logger.debug('Cannot insert the video.', { error: err })
203 226
204 // Abort transaction? 227 // Abort transaction?
205 if (t) t.rollback() 228 if (t) t.rollback()
206 229
207 return next(err) 230 return callback(err)
208 } 231 }
209 232
210 // Commit transaction 233 // Commit transaction
211 t.commit() 234 t.commit()
212 235
213 // TODO : include Location of the new video -> 201 236 logger.info('Video with name %s created.', videoInfos.name)
214 return res.type('json').status(204).end() 237
238 return callback(null)
215 }) 239 })
216} 240}
217 241
218function updateVideo (req, res, next) { 242function updateVideoRetryWrapper (req, res, next) {
243 utils.transactionRetryer(
244 function (callback) {
245 return updateVideo(req, res, callback)
246 },
247 function (err) {
248 if (err) {
249 logger.error('Cannot update the video with many retries.', { error: err })
250 return next(err)
251 }
252
253 // TODO : include Location of the new video -> 201
254 return res.type('json').status(204).end()
255 }
256 )
257}
258
259function updateVideo (req, res, finalCallback) {
219 const videoInstance = res.locals.video 260 const videoInstance = res.locals.video
220 const videoInfosToUpdate = req.body 261 const videoInfosToUpdate = req.body
221 262
@@ -267,26 +308,25 @@ function updateVideo (req, res, next) {
267 const json = videoInstance.toUpdateRemoteJSON() 308 const json = videoInstance.toUpdateRemoteJSON()
268 309
269 // Now we'll update the video's meta data to our friends 310 // Now we'll update the video's meta data to our friends
270 friends.updateVideoToFriends(json) 311 friends.updateVideoToFriends(json, t, function (err) {
271 312 return callback(err, t)
272 return callback(null, t) 313 })
273 } 314 }
274 315
275 ], function andFinally (err, t) { 316 ], function andFinally (err, t) {
276 if (err) { 317 if (err) {
277 logger.error('Cannot insert the video.') 318 logger.debug('Cannot update the video.', { error: err })
278 319
279 // Abort transaction? 320 // Abort transaction?
280 if (t) t.rollback() 321 if (t) t.rollback()
281 322
282 return next(err) 323 return finalCallback(err)
283 } 324 }
284 325
285 // Commit transaction 326 // Commit transaction
286 t.commit() 327 t.commit()
287 328
288 // TODO : include Location of the new video -> 201 329 return finalCallback(null)
289 return res.type('json').status(204).end()
290 }) 330 })
291} 331}
292 332