]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/controllers/api/remote.js
a36c31c38c897ff0f1d03da5d92e2401c93bf85f
[github/Chocobozzz/PeerTube.git] / server / controllers / api / remote.js
1 'use strict'
2
3 const each = require('async/each')
4 const eachSeries = require('async/eachSeries')
5 const express = require('express')
6 const waterfall = require('async/waterfall')
7
8 const db = require('../../initializers/database')
9 const middlewares = require('../../middlewares')
10 const secureMiddleware = middlewares.secure
11 const validators = middlewares.validators.remote
12 const logger = require('../../helpers/logger')
13
14 const router = express.Router()
15
16 router.post('/videos',
17 validators.signature,
18 secureMiddleware.checkSignature,
19 validators.remoteVideos,
20 remoteVideos
21 )
22
23 // ---------------------------------------------------------------------------
24
25 module.exports = router
26
27 // ---------------------------------------------------------------------------
28
29 function remoteVideos (req, res, next) {
30 const requests = req.body.data
31 const fromPod = res.locals.secure.pod
32
33 // We need to process in the same order to keep consistency
34 // TODO: optimization
35 eachSeries(requests, function (request, callbackEach) {
36 const videoData = request.data
37
38 switch (request.type) {
39 case 'add':
40 addRemoteVideo(videoData, fromPod, callbackEach)
41 break
42
43 case 'update':
44 updateRemoteVideo(videoData, fromPod, callbackEach)
45 break
46
47 case 'remove':
48 removeRemoteVideo(videoData, fromPod, callbackEach)
49 break
50
51 default:
52 logger.error('Unkown remote request type %s.', request.type)
53 }
54 }, function (err) {
55 if (err) logger.error('Error managing remote videos.', { error: err })
56 })
57
58 // We don't need to keep the other pod waiting
59 return res.type('json').status(204).end()
60 }
61
62 function addRemoteVideo (videoToCreateData, fromPod, finalCallback) {
63 logger.debug('Adding remote video "%s".', videoToCreateData.name)
64
65 waterfall([
66
67 function startTransaction (callback) {
68 db.sequelize.transaction().asCallback(function (err, t) {
69 return callback(err, t)
70 })
71 },
72
73 function findOrCreateAuthor (t, callback) {
74 const name = videoToCreateData.author
75 const podId = fromPod.id
76 // This author is from another pod so we do not associate a user
77 const userId = null
78
79 db.Author.findOrCreateAuthor(name, podId, userId, t, function (err, authorInstance) {
80 return callback(err, t, authorInstance)
81 })
82 },
83
84 function findOrCreateTags (t, author, callback) {
85 const tags = videoToCreateData.tags
86
87 db.Tag.findOrCreateTags(tags, t, function (err, tagInstances) {
88 return callback(err, t, author, tagInstances)
89 })
90 },
91
92 function createVideoObject (t, author, tagInstances, callback) {
93 const videoData = {
94 name: videoToCreateData.name,
95 remoteId: videoToCreateData.remoteId,
96 extname: videoToCreateData.extname,
97 infoHash: videoToCreateData.infoHash,
98 description: videoToCreateData.description,
99 authorId: author.id,
100 duration: videoToCreateData.duration,
101 createdAt: videoToCreateData.createdAt,
102 updatedAt: videoToCreateData.updatedAt
103 }
104
105 const video = db.Video.build(videoData)
106
107 return callback(null, t, tagInstances, video)
108 },
109
110 function generateThumbnail (t, tagInstances, video, callback) {
111 db.Video.generateThumbnailFromData(video, videoToCreateData.thumbnailData, function (err) {
112 if (err) {
113 logger.error('Cannot generate thumbnail from data.', { error: err })
114 return callback(err)
115 }
116
117 return callback(err, t, tagInstances, video)
118 })
119 },
120
121 function insertVideoIntoDB (t, tagInstances, video, callback) {
122 const options = {
123 transaction: t
124 }
125
126 video.save(options).asCallback(function (err, videoCreated) {
127 return callback(err, t, tagInstances, videoCreated)
128 })
129 },
130
131 function associateTagsToVideo (t, tagInstances, video, callback) {
132 const options = { transaction: t }
133
134 video.setTags(tagInstances, options).asCallback(function (err) {
135 return callback(err, t)
136 })
137 }
138
139 ], function (err, t) {
140 if (err) {
141 logger.error('Cannot insert the remote video.')
142
143 // Abort transaction?
144 if (t) t.rollback()
145
146 return finalCallback(err)
147 }
148
149 // Commit transaction
150 t.commit()
151
152 return finalCallback()
153 })
154 }
155
156 function updateRemoteVideo (videoAttributesToUpdate, fromPod, finalCallback) {
157 logger.debug('Updating remote video "%s".', videoAttributesToUpdate.name)
158
159 waterfall([
160
161 function startTransaction (callback) {
162 db.sequelize.transaction().asCallback(function (err, t) {
163 return callback(err, t)
164 })
165 },
166
167 function findVideo (t, callback) {
168 db.Video.loadByHostAndRemoteId(fromPod.host, videoAttributesToUpdate.remoteId, function (err, videoInstance) {
169 if (err || !videoInstance) {
170 logger.error('Cannot load video from host and remote id.', { error: err.message })
171 return callback(err)
172 }
173
174 return callback(null, t, videoInstance)
175 })
176 },
177
178 function findOrCreateTags (t, videoInstance, callback) {
179 const tags = videoAttributesToUpdate.tags
180
181 db.Tag.findOrCreateTags(tags, t, function (err, tagInstances) {
182 return callback(err, t, videoInstance, tagInstances)
183 })
184 },
185
186 function updateVideoIntoDB (t, videoInstance, tagInstances, callback) {
187 const options = { transaction: t }
188
189 videoInstance.set('name', videoAttributesToUpdate.name)
190 videoInstance.set('description', videoAttributesToUpdate.description)
191 videoInstance.set('infoHash', videoAttributesToUpdate.infoHash)
192 videoInstance.set('duration', videoAttributesToUpdate.duration)
193 videoInstance.set('createdAt', videoAttributesToUpdate.createdAt)
194 videoInstance.set('updatedAt', videoAttributesToUpdate.updatedAt)
195 videoInstance.set('extname', videoAttributesToUpdate.extname)
196
197 videoInstance.save(options).asCallback(function (err) {
198 return callback(err, t, videoInstance, tagInstances)
199 })
200 },
201
202 function associateTagsToVideo (t, videoInstance, tagInstances, callback) {
203 const options = { transaction: t }
204
205 videoInstance.setTags(tagInstances, options).asCallback(function (err) {
206 return callback(err, t)
207 })
208 }
209
210 ], function (err, t) {
211 if (err) {
212 logger.error('Cannot update the remote video.')
213
214 // Abort transaction?
215 if (t) t.rollback()
216
217 return finalCallback(err)
218 }
219
220 // Commit transaction
221 t.commit()
222
223 return finalCallback()
224 })
225 }
226
227 function removeRemoteVideo (videoToRemoveData, fromPod, callback) {
228 // We need the instance because we have to remove some other stuffs (thumbnail etc)
229 db.Video.loadByHostAndRemoteId(fromPod.host, videoToRemoveData.remoteId, function (err, video) {
230 if (err || !video) {
231 logger.error('Cannot load video from host and remote id.', { error: err.message })
232 return callback(err)
233 }
234
235 logger.debug('Removing remote video %s.', video.remoteId)
236 video.destroy().asCallback(callback)
237 })
238 }