]>
git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/controllers/api/remote/videos.js
3 const eachSeries
= require('async/eachSeries')
4 const express
= require('express')
5 const waterfall
= require('async/waterfall')
7 const db
= require('../../../initializers/database')
8 const middlewares
= require('../../../middlewares')
9 const secureMiddleware
= middlewares
.secure
10 const videosValidators
= middlewares
.validators
.remote
.videos
11 const signatureValidators
= middlewares
.validators
.remote
.signature
12 const logger
= require('../../../helpers/logger')
13 const utils
= require('../../../helpers/utils')
15 const router
= express
.Router()
18 signatureValidators
.signature
,
19 secureMiddleware
.checkSignature
,
20 videosValidators
.remoteVideos
,
24 // ---------------------------------------------------------------------------
26 module
.exports
= router
28 // ---------------------------------------------------------------------------
30 function remoteVideos (req
, res
, next
) {
31 const requests
= req
.body
.data
32 const fromPod
= res
.locals
.secure
.pod
34 // We need to process in the same order to keep consistency
36 eachSeries(requests
, function (request
, callbackEach
) {
37 const data
= request
.data
39 switch (request
.type
) {
41 addRemoteVideoRetryWrapper(data
, fromPod
, callbackEach
)
45 updateRemoteVideoRetryWrapper(data
, fromPod
, callbackEach
)
49 removeRemoteVideo(data
, fromPod
, callbackEach
)
53 reportAbuseRemoteVideo(data
, fromPod
, callbackEach
)
57 logger
.error('Unkown remote request type %s.', request
.type
)
60 if (err
) logger
.error('Error managing remote videos.', { error: err
})
63 // We don't need to keep the other pod waiting
64 return res
.type('json').status(204).end()
67 // Handle retries on fail
68 function addRemoteVideoRetryWrapper (videoToCreateData
, fromPod
, finalCallback
) {
70 arguments: [ videoToCreateData
, fromPod
],
71 errorMessage: 'Cannot insert the remote video with many retries.'
74 utils
.retryWrapper(addRemoteVideo
, options
, finalCallback
)
77 function addRemoteVideo (videoToCreateData
, fromPod
, finalCallback
) {
78 logger
.debug('Adding remote video "%s".', videoToCreateData
.remoteId
)
82 function startTransaction (callback
) {
83 db
.sequelize
.transaction({ isolationLevel: 'SERIALIZABLE' }).asCallback(function (err
, t
) {
84 return callback(err
, t
)
88 function findOrCreateAuthor (t
, callback
) {
89 const name
= videoToCreateData
.author
90 const podId
= fromPod
.id
91 // This author is from another pod so we do not associate a user
94 db
.Author
.findOrCreateAuthor(name
, podId
, userId
, t
, function (err
, authorInstance
) {
95 return callback(err
, t
, authorInstance
)
99 function findOrCreateTags (t
, author
, callback
) {
100 const tags
= videoToCreateData
.tags
102 db
.Tag
.findOrCreateTags(tags
, t
, function (err
, tagInstances
) {
103 return callback(err
, t
, author
, tagInstances
)
107 function createVideoObject (t
, author
, tagInstances
, callback
) {
109 name: videoToCreateData
.name
,
110 remoteId: videoToCreateData
.remoteId
,
111 extname: videoToCreateData
.extname
,
112 infoHash: videoToCreateData
.infoHash
,
113 description: videoToCreateData
.description
,
115 duration: videoToCreateData
.duration
,
116 createdAt: videoToCreateData
.createdAt
,
117 // FIXME: updatedAt does not seems to be considered by Sequelize
118 updatedAt: videoToCreateData
.updatedAt
121 const video
= db
.Video
.build(videoData
)
123 return callback(null, t
, tagInstances
, video
)
126 function generateThumbnail (t
, tagInstances
, video
, callback
) {
127 db
.Video
.generateThumbnailFromData(video
, videoToCreateData
.thumbnailData
, function (err
) {
129 logger
.error('Cannot generate thumbnail from data.', { error: err
})
133 return callback(err
, t
, tagInstances
, video
)
137 function insertVideoIntoDB (t
, tagInstances
, video
, callback
) {
142 video
.save(options
).asCallback(function (err
, videoCreated
) {
143 return callback(err
, t
, tagInstances
, videoCreated
)
147 function associateTagsToVideo (t
, tagInstances
, video
, callback
) {
148 const options
= { transaction: t
}
150 video
.setTags(tagInstances
, options
).asCallback(function (err
) {
151 return callback(err
, t
)
155 ], function (err
, t
) {
157 // This is just a debug because we will retry the insert
158 logger
.debug('Cannot insert the remote video.', { error: err
})
160 // Abort transaction?
163 return finalCallback(err
)
166 // Commit transaction
167 t
.commit().asCallback(function (err
) {
168 if (err
) return finalCallback(err
)
170 logger
.info('Remote video %s inserted.', videoToCreateData
.name
)
171 return finalCallback(null)
176 // Handle retries on fail
177 function updateRemoteVideoRetryWrapper (videoAttributesToUpdate
, fromPod
, finalCallback
) {
179 arguments: [ fromPod
, videoAttributesToUpdate
],
180 errorMessage: 'Cannot update the remote video with many retries'
183 utils
.retryWrapper(updateRemoteVideo
, options
, finalCallback
)
186 function updateRemoteVideo (videoAttributesToUpdate
, fromPod
, finalCallback
) {
187 logger
.debug('Updating remote video "%s".', videoAttributesToUpdate
.remoteId
)
191 function startTransaction (callback
) {
192 db
.sequelize
.transaction({ isolationLevel: 'SERIALIZABLE' }).asCallback(function (err
, t
) {
193 return callback(err
, t
)
197 function findVideo (t
, callback
) {
198 fetchVideo(fromPod
.host
, videoAttributesToUpdate
.remoteId
, function (err
, videoInstance
) {
199 return callback(err
, t
, videoInstance
)
203 function findOrCreateTags (t
, videoInstance
, callback
) {
204 const tags
= videoAttributesToUpdate
.tags
206 db
.Tag
.findOrCreateTags(tags
, t
, function (err
, tagInstances
) {
207 return callback(err
, t
, videoInstance
, tagInstances
)
211 function updateVideoIntoDB (t
, videoInstance
, tagInstances
, callback
) {
212 const options
= { transaction: t
}
214 videoInstance
.set('name', videoAttributesToUpdate
.name
)
215 videoInstance
.set('description', videoAttributesToUpdate
.description
)
216 videoInstance
.set('infoHash', videoAttributesToUpdate
.infoHash
)
217 videoInstance
.set('duration', videoAttributesToUpdate
.duration
)
218 videoInstance
.set('createdAt', videoAttributesToUpdate
.createdAt
)
219 videoInstance
.set('updatedAt', videoAttributesToUpdate
.updatedAt
)
220 videoInstance
.set('extname', videoAttributesToUpdate
.extname
)
222 videoInstance
.save(options
).asCallback(function (err
) {
223 return callback(err
, t
, videoInstance
, tagInstances
)
227 function associateTagsToVideo (t
, videoInstance
, tagInstances
, callback
) {
228 const options
= { transaction: t
}
230 videoInstance
.setTags(tagInstances
, options
).asCallback(function (err
) {
231 return callback(err
, t
)
235 ], function (err
, t
) {
237 // This is just a debug because we will retry the insert
238 logger
.debug('Cannot update the remote video.', { error: err
})
240 // Abort transaction?
243 return finalCallback(err
)
246 // Commit transaction
247 t
.commit().asCallback(function (err
) {
248 if (err
) return finalCallback(err
)
250 logger
.info('Remote video %s updated', videoAttributesToUpdate
.name
)
251 return finalCallback(null)
256 function removeRemoteVideo (videoToRemoveData
, fromPod
, callback
) {
257 // We need the instance because we have to remove some other stuffs (thumbnail etc)
258 fetchVideo(fromPod
.host
, videoToRemoveData
.remoteId
, function (err
, video
) {
259 // Do not return the error, continue the process
260 if (err
) return callback(null)
262 logger
.debug('Removing remote video %s.', video
.remoteId
)
263 video
.destroy().asCallback(function (err
) {
264 // Do not return the error, continue the process
266 logger
.error('Cannot remove remote video with id %s.', videoToRemoveData
.remoteId
, { error: err
})
269 return callback(null)
274 function reportAbuseRemoteVideo (reportData
, fromPod
, callback
) {
275 db
.Video
.load(reportData
.videoRemoteId
, function (err
, video
) {
277 if (!err
) err
= new Error('video not found')
279 logger
.error('Cannot load video from id.', { error: err
, id: reportData
.videoRemoteId
})
280 // Do not return the error, continue the process
281 return callback(null)
284 logger
.debug('Reporting remote abuse for video %s.', video
.id
)
286 const videoAbuseData
= {
287 reporterUsername: reportData
.reporterUsername
,
288 reason: reportData
.reportReason
,
289 reporterPodId: fromPod
.id
,
293 db
.VideoAbuse
.create(videoAbuseData
).asCallback(function (err
) {
295 logger
.error('Cannot create remote abuse video.', { error: err
})
298 return callback(null)
303 function fetchVideo (podHost
, remoteId
, callback
) {
304 db
.Video
.loadByHostAndRemoteId(podHost
, remoteId
, function (err
, video
) {
306 if (!err
) err
= new Error('video not found')
308 logger
.error('Cannot load video from host and remote id.', { error: err
, podHost
, remoteId
})
312 return callback(null, video
)