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