diff options
author | Chocobozzz <florian.bigard@gmail.com> | 2016-12-30 11:27:42 +0100 |
---|---|---|
committer | Chocobozzz <florian.bigard@gmail.com> | 2016-12-30 11:27:42 +0100 |
commit | 3d118fb501f576a298f6bb059167e4c7f4dd8dcc (patch) | |
tree | f2c8e74e1ca9a9d39b86412a6444a95343d2833e | |
parent | 7b1f49de22c40ae121ddb3c399b2540ba56fd414 (diff) | |
download | PeerTube-3d118fb501f576a298f6bb059167e4c7f4dd8dcc.tar.gz PeerTube-3d118fb501f576a298f6bb059167e4c7f4dd8dcc.tar.zst PeerTube-3d118fb501f576a298f6bb059167e4c7f4dd8dcc.zip |
Server: propagate video update to other pods
-rw-r--r-- | server/controllers/api/remote.js | 108 | ||||
-rw-r--r-- | server/controllers/api/videos.js | 2 | ||||
-rw-r--r-- | server/helpers/custom-validators/videos.js | 15 | ||||
-rw-r--r-- | server/models/video.js | 6 | ||||
-rw-r--r-- | server/tests/api/multiple-pods.js | 55 |
5 files changed, 152 insertions, 34 deletions
diff --git a/server/controllers/api/remote.js b/server/controllers/api/remote.js index 929ade555..254ae56d5 100644 --- a/server/controllers/api/remote.js +++ b/server/controllers/api/remote.js | |||
@@ -35,12 +35,21 @@ function remoteVideos (req, res, next) { | |||
35 | eachSeries(requests, function (request, callbackEach) { | 35 | eachSeries(requests, function (request, callbackEach) { |
36 | const videoData = request.data | 36 | const videoData = request.data |
37 | 37 | ||
38 | if (request.type === 'add') { | 38 | switch (request.type) { |
39 | addRemoteVideo(videoData, fromPod, callbackEach) | 39 | case 'add': |
40 | } else if (request.type === 'remove') { | 40 | addRemoteVideo(videoData, fromPod, callbackEach) |
41 | removeRemoteVideo(videoData, fromPod, callbackEach) | 41 | break |
42 | } else { | 42 | |
43 | logger.error('Unkown remote request type %s.', request.type) | 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) | ||
44 | } | 53 | } |
45 | }, function (err) { | 54 | }, function (err) { |
46 | if (err) logger.error('Error managing remote videos.', { error: err }) | 55 | if (err) logger.error('Error managing remote videos.', { error: err }) |
@@ -143,24 +152,85 @@ function addRemoteVideo (videoToCreateData, fromPod, finalCallback) { | |||
143 | }) | 152 | }) |
144 | } | 153 | } |
145 | 154 | ||
146 | function removeRemoteVideo (videoToRemoveData, fromPod, callback) { | 155 | function updateRemoteVideo (videoAttributesToUpdate, fromPod, finalCallback) { |
147 | // TODO: use bulkDestroy? | 156 | logger.debug('Updating remote video "%s".', videoAttributesToUpdate.name) |
148 | 157 | ||
149 | // We need the list because we have to remove some other stuffs (thumbnail etc) | 158 | waterfall([ |
150 | db.Video.listByHostAndRemoteId(fromPod.host, videoToRemoveData.remoteId, function (err, videosList) { | 159 | |
151 | if (err) { | 160 | function startTransaction (callback) { |
152 | logger.error('Cannot list videos from host and remote id.', { error: err.message }) | 161 | db.sequelize.transaction().asCallback(function (err, t) { |
153 | return callback(err) | 162 | return callback(err, t) |
163 | }) | ||
164 | }, | ||
165 | |||
166 | function findVideo (t, callback) { | ||
167 | db.Video.loadByHostAndRemoteId(fromPod.host, videoAttributesToUpdate.remoteId, function (err, videoInstance) { | ||
168 | if (err || !videoInstance) { | ||
169 | logger.error('Cannot load video from host and remote id.', { error: err.message }) | ||
170 | return callback(err) | ||
171 | } | ||
172 | |||
173 | return callback(null, t, videoInstance) | ||
174 | }) | ||
175 | }, | ||
176 | |||
177 | function findOrCreateTags (t, videoInstance, callback) { | ||
178 | const tags = videoAttributesToUpdate.tags | ||
179 | |||
180 | db.Tag.findOrCreateTags(tags, t, function (err, tagInstances) { | ||
181 | return callback(err, t, videoInstance, tagInstances) | ||
182 | }) | ||
183 | }, | ||
184 | |||
185 | function updateVideoIntoDB (t, videoInstance, tagInstances, callback) { | ||
186 | const options = { transaction: t } | ||
187 | |||
188 | videoInstance.set('name', videoAttributesToUpdate.name) | ||
189 | videoInstance.set('description', videoAttributesToUpdate.description) | ||
190 | videoInstance.set('infoHash', videoAttributesToUpdate.infoHash) | ||
191 | videoInstance.set('duration', videoAttributesToUpdate.duration) | ||
192 | videoInstance.set('createdAt', videoAttributesToUpdate.createdAt) | ||
193 | videoInstance.set('extname', videoAttributesToUpdate.extname) | ||
194 | |||
195 | videoInstance.save(options).asCallback(function (err) { | ||
196 | return callback(err, t, videoInstance, tagInstances) | ||
197 | }) | ||
198 | }, | ||
199 | |||
200 | function associateTagsToVideo (t, videoInstance, tagInstances, callback) { | ||
201 | const options = { transaction: t } | ||
202 | |||
203 | videoInstance.setTags(tagInstances, options).asCallback(function (err) { | ||
204 | return callback(err, t) | ||
205 | }) | ||
154 | } | 206 | } |
155 | 207 | ||
156 | if (videosList.length === 0) { | 208 | ], function (err, t) { |
157 | logger.error('No remote video was found for this pod.', { remoteId: videoToRemoveData.remoteId, podHost: fromPod.host }) | 209 | if (err) { |
210 | logger.error('Cannot update the remote video.') | ||
211 | |||
212 | // Abort transaction? | ||
213 | if (t) t.rollback() | ||
214 | |||
215 | return finalCallback(err) | ||
158 | } | 216 | } |
159 | 217 | ||
160 | each(videosList, function (video, callbackEach) { | 218 | // Commit transaction |
161 | logger.debug('Removing remote video %s.', video.remoteId) | 219 | t.commit() |
220 | |||
221 | return finalCallback() | ||
222 | }) | ||
223 | } | ||
224 | |||
225 | function removeRemoteVideo (videoToRemoveData, fromPod, callback) { | ||
226 | // We need the instance because we have to remove some other stuffs (thumbnail etc) | ||
227 | db.Video.loadByHostAndRemoteId(fromPod.host, videoToRemoveData.remoteId, function (err, video) { | ||
228 | if (err || !video) { | ||
229 | logger.error('Cannot load video from host and remote id.', { error: err.message }) | ||
230 | return callback(err) | ||
231 | } | ||
162 | 232 | ||
163 | video.destroy().asCallback(callbackEach) | 233 | logger.debug('Removing remote video %s.', video.remoteId) |
164 | }, callback) | 234 | video.destroy().asCallback(callback) |
165 | }) | 235 | }) |
166 | } | 236 | } |
diff --git a/server/controllers/api/videos.js b/server/controllers/api/videos.js index 1b306d1cf..e5c52a87b 100644 --- a/server/controllers/api/videos.js +++ b/server/controllers/api/videos.js | |||
@@ -229,8 +229,6 @@ function updateVideo (req, res, next) { | |||
229 | 229 | ||
230 | // Add tags association | 230 | // Add tags association |
231 | videoInstance.save(options).asCallback(function (err) { | 231 | videoInstance.save(options).asCallback(function (err) { |
232 | if (err) return callback(err) | ||
233 | |||
234 | return callback(err, t, tagInstances) | 232 | return callback(err, t, tagInstances) |
235 | }) | 233 | }) |
236 | }, | 234 | }, |
diff --git a/server/helpers/custom-validators/videos.js b/server/helpers/custom-validators/videos.js index 4aaa6aaa9..b76eec1b5 100644 --- a/server/helpers/custom-validators/videos.js +++ b/server/helpers/custom-validators/videos.js | |||
@@ -38,6 +38,17 @@ function isEachRemoteVideosValid (requests) { | |||
38 | isVideoExtnameValid(video.extname) | 38 | isVideoExtnameValid(video.extname) |
39 | ) || | 39 | ) || |
40 | ( | 40 | ( |
41 | isRequestTypeUpdateValid(request.type) && | ||
42 | isVideoDateValid(video.createdAt) && | ||
43 | isVideoDescriptionValid(video.description) && | ||
44 | isVideoDurationValid(video.duration) && | ||
45 | isVideoInfoHashValid(video.infoHash) && | ||
46 | isVideoNameValid(video.name) && | ||
47 | isVideoTagsValid(video.tags) && | ||
48 | isVideoRemoteIdValid(video.remoteId) && | ||
49 | isVideoExtnameValid(video.extname) | ||
50 | ) || | ||
51 | ( | ||
41 | isRequestTypeRemoveValid(request.type) && | 52 | isRequestTypeRemoveValid(request.type) && |
42 | isVideoNameValid(video.name) && | 53 | isVideoNameValid(video.name) && |
43 | isVideoRemoteIdValid(video.remoteId) | 54 | isVideoRemoteIdValid(video.remoteId) |
@@ -104,6 +115,10 @@ function isRequestTypeAddValid (value) { | |||
104 | return value === 'add' | 115 | return value === 'add' |
105 | } | 116 | } |
106 | 117 | ||
118 | function isRequestTypeUpdateValid (value) { | ||
119 | return value === 'update' | ||
120 | } | ||
121 | |||
107 | function isRequestTypeRemoveValid (value) { | 122 | function isRequestTypeRemoveValid (value) { |
108 | return value === 'remove' | 123 | return value === 'remove' |
109 | } | 124 | } |
diff --git a/server/models/video.js b/server/models/video.js index 14fbe2f71..f51d08f06 100644 --- a/server/models/video.js +++ b/server/models/video.js | |||
@@ -111,10 +111,10 @@ module.exports = function (sequelize, DataTypes) { | |||
111 | getDurationFromFile, | 111 | getDurationFromFile, |
112 | list, | 112 | list, |
113 | listForApi, | 113 | listForApi, |
114 | listByHostAndRemoteId, | ||
115 | listOwnedAndPopulateAuthorAndTags, | 114 | listOwnedAndPopulateAuthorAndTags, |
116 | listOwnedByAuthor, | 115 | listOwnedByAuthor, |
117 | load, | 116 | load, |
117 | loadByHostAndRemoteId, | ||
118 | loadAndPopulateAuthor, | 118 | loadAndPopulateAuthor, |
119 | loadAndPopulateAuthorAndPodAndTags, | 119 | loadAndPopulateAuthorAndPodAndTags, |
120 | searchAndPopulateAuthorAndPodAndTags | 120 | searchAndPopulateAuthorAndPodAndTags |
@@ -428,7 +428,7 @@ function listForApi (start, count, sort, callback) { | |||
428 | }) | 428 | }) |
429 | } | 429 | } |
430 | 430 | ||
431 | function listByHostAndRemoteId (fromHost, remoteId, callback) { | 431 | function loadByHostAndRemoteId (fromHost, remoteId, callback) { |
432 | const query = { | 432 | const query = { |
433 | where: { | 433 | where: { |
434 | remoteId: remoteId | 434 | remoteId: remoteId |
@@ -449,7 +449,7 @@ function listByHostAndRemoteId (fromHost, remoteId, callback) { | |||
449 | ] | 449 | ] |
450 | } | 450 | } |
451 | 451 | ||
452 | return this.findAll(query).asCallback(callback) | 452 | return this.findOne(query).asCallback(callback) |
453 | } | 453 | } |
454 | 454 | ||
455 | function listOwnedAndPopulateAuthorAndTags (callback) { | 455 | function listOwnedAndPopulateAuthorAndTags (callback) { |
diff --git a/server/tests/api/multiple-pods.js b/server/tests/api/multiple-pods.js index f0fe59c5f..672187068 100644 --- a/server/tests/api/multiple-pods.js +++ b/server/tests/api/multiple-pods.js | |||
@@ -299,8 +299,8 @@ describe('Test multiple pods', function () { | |||
299 | if (err) throw err | 299 | if (err) throw err |
300 | 300 | ||
301 | const video = res.body.data[0] | 301 | const video = res.body.data[0] |
302 | toRemove.push(res.body.data[2].id) | 302 | toRemove.push(res.body.data[2]) |
303 | toRemove.push(res.body.data[3].id) | 303 | toRemove.push(res.body.data[3]) |
304 | 304 | ||
305 | webtorrent.add(video.magnetUri, function (torrent) { | 305 | webtorrent.add(video.magnetUri, function (torrent) { |
306 | expect(torrent.files).to.exist | 306 | expect(torrent.files).to.exist |
@@ -368,16 +368,51 @@ describe('Test multiple pods', function () { | |||
368 | }) | 368 | }) |
369 | }) | 369 | }) |
370 | }) | 370 | }) |
371 | }) | ||
372 | |||
373 | describe('Should manipulate these videos', function () { | ||
374 | it('Should update the video 3 by asking pod 3', function (done) { | ||
375 | this.timeout(15000) | ||
376 | |||
377 | const name = 'my super video updated' | ||
378 | const description = 'my super description updated' | ||
379 | const tags = [ 'tagup1', 'tagup2' ] | ||
380 | |||
381 | videosUtils.updateVideo(servers[2].url, servers[2].accessToken, toRemove[0].id, name, description, tags, function (err) { | ||
382 | if (err) throw err | ||
383 | |||
384 | setTimeout(done, 11000) | ||
385 | }) | ||
386 | }) | ||
387 | |||
388 | it('Should have the video 3 updated on each pod', function (done) { | ||
389 | each(servers, function (server, callback) { | ||
390 | videosUtils.getVideosList(server.url, function (err, res) { | ||
391 | if (err) throw err | ||
392 | |||
393 | const videos = res.body.data | ||
394 | const videoUpdated = videos.find(function (video) { | ||
395 | return video.name === 'my super video updated' | ||
396 | }) | ||
397 | |||
398 | expect(!!videoUpdated).to.be.true | ||
399 | expect(videoUpdated.description).to.equal('my super description updated') | ||
400 | expect(videoUpdated.tags).to.deep.equal([ 'tagup1', 'tagup2' ]) | ||
401 | |||
402 | callback() | ||
403 | }) | ||
404 | }, done) | ||
405 | }) | ||
371 | 406 | ||
372 | it('Should remove the file 3 and 3-2 by asking pod 3', function (done) { | 407 | it('Should remove the videos 3 and 3-2 by asking pod 3', function (done) { |
373 | this.timeout(15000) | 408 | this.timeout(15000) |
374 | 409 | ||
375 | series([ | 410 | series([ |
376 | function (next) { | 411 | function (next) { |
377 | videosUtils.removeVideo(servers[2].url, servers[2].accessToken, toRemove[0], next) | 412 | videosUtils.removeVideo(servers[2].url, servers[2].accessToken, toRemove[0].id, next) |
378 | }, | 413 | }, |
379 | function (next) { | 414 | function (next) { |
380 | videosUtils.removeVideo(servers[2].url, servers[2].accessToken, toRemove[1], next) | 415 | videosUtils.removeVideo(servers[2].url, servers[2].accessToken, toRemove[1].id, next) |
381 | }], | 416 | }], |
382 | function (err) { | 417 | function (err) { |
383 | if (err) throw err | 418 | if (err) throw err |
@@ -394,11 +429,11 @@ describe('Test multiple pods', function () { | |||
394 | const videos = res.body.data | 429 | const videos = res.body.data |
395 | expect(videos).to.be.an('array') | 430 | expect(videos).to.be.an('array') |
396 | expect(videos.length).to.equal(2) | 431 | expect(videos.length).to.equal(2) |
397 | expect(videos[0].id).not.to.equal(videos[1].id) | 432 | expect(videos[0].name).not.to.equal(videos[1].name) |
398 | expect(videos[0].id).not.to.equal(toRemove[0]) | 433 | expect(videos[0].name).not.to.equal(toRemove[0].name) |
399 | expect(videos[1].id).not.to.equal(toRemove[0]) | 434 | expect(videos[1].name).not.to.equal(toRemove[0].name) |
400 | expect(videos[0].id).not.to.equal(toRemove[1]) | 435 | expect(videos[0].name).not.to.equal(toRemove[1].name) |
401 | expect(videos[1].id).not.to.equal(toRemove[1]) | 436 | expect(videos[1].name).not.to.equal(toRemove[1].name) |
402 | 437 | ||
403 | callback() | 438 | callback() |
404 | }) | 439 | }) |