]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/controllers/api/remote.js
c7a5658e850ab3dc1a5e42e2ca3b1d2a02c628c2
[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 fromHost = req.body.signature.host
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 if (request.type === 'add') {
39 addRemoteVideo(videoData, fromHost, callbackEach)
40 } else if (request.type === 'remove') {
41 removeRemoteVideo(videoData, fromHost, callbackEach)
42 } else {
43 logger.error('Unkown remote request type %s.', request.type)
44 }
45 }, function (err) {
46 if (err) logger.error('Error managing remote videos.', { error: err })
47 })
48
49 // We don't need to keep the other pod waiting
50 return res.type('json').status(204).end()
51 }
52
53 function addRemoteVideo (videoToCreateData, fromHost, finalCallback) {
54 logger.debug('Adding remote video "%s".', videoToCreateData.name)
55
56 waterfall([
57
58 function startTransaction (callback) {
59 db.sequelize.transaction().asCallback(function (err, t) {
60 return callback(err, t)
61 })
62 },
63
64 function findOrCreatePod (t, callback) {
65 const query = {
66 where: {
67 host: fromHost
68 },
69 defaults: {
70 host: fromHost
71 },
72 transaction: t
73 }
74
75 db.Pod.findOrCreate(query).asCallback(function (err, result) {
76 // [ instance, wasCreated ]
77 return callback(err, t, result[0])
78 })
79 },
80
81 function findOrCreateAuthor (t, pod, callback) {
82 const username = videoToCreateData.author
83
84 const query = {
85 where: {
86 name: username,
87 podId: pod.id
88 },
89 defaults: {
90 name: username,
91 podId: pod.id
92 },
93 transaction: t
94 }
95
96 db.Author.findOrCreate(query).asCallback(function (err, result) {
97 // [ instance, wasCreated ]
98 return callback(err, t, result[0])
99 })
100 },
101
102 function findOrCreateTags (t, author, callback) {
103 const tags = videoToCreateData.tags
104 const tagInstances = []
105
106 each(tags, function (tag, callbackEach) {
107 const query = {
108 where: {
109 name: tag
110 },
111 defaults: {
112 name: tag
113 },
114 transaction: t
115 }
116
117 db.Tag.findOrCreate(query).asCallback(function (err, res) {
118 if (err) return callbackEach(err)
119
120 // res = [ tag, isCreated ]
121 const tag = res[0]
122 tagInstances.push(tag)
123 return callbackEach()
124 })
125 }, function (err) {
126 return callback(err, t, author, tagInstances)
127 })
128 },
129
130 function createVideoObject (t, author, tagInstances, callback) {
131 const videoData = {
132 name: videoToCreateData.name,
133 remoteId: videoToCreateData.remoteId,
134 extname: videoToCreateData.extname,
135 infoHash: videoToCreateData.infoHash,
136 description: videoToCreateData.description,
137 authorId: author.id,
138 duration: videoToCreateData.duration
139 }
140
141 const video = db.Video.build(videoData)
142
143 return callback(null, t, tagInstances, video)
144 },
145
146 function generateThumbnail (t, tagInstances, video, callback) {
147 db.Video.generateThumbnailFromBase64(video, videoToCreateData.thumbnailBase64, function (err) {
148 if (err) {
149 logger.error('Cannot generate thumbnail from base 64 data.', { error: err })
150 return callback(err)
151 }
152
153 return callback(err, t, tagInstances, video)
154 })
155 },
156
157 function insertVideoIntoDB (t, tagInstances, video, callback) {
158 const options = {
159 transaction: t
160 }
161
162 video.save(options).asCallback(function (err, videoCreated) {
163 return callback(err, t, tagInstances, videoCreated)
164 })
165 },
166
167 function associateTagsToVideo (t, tagInstances, video, callback) {
168 const options = { transaction: t }
169
170 video.setTags(tagInstances, options).asCallback(function (err) {
171 return callback(err, t)
172 })
173 }
174
175 ], function (err, t) {
176 if (err) {
177 logger.error('Cannot insert the remote video.')
178
179 // Abort transaction?
180 if (t) t.rollback()
181
182 return finalCallback(err)
183 }
184
185 // Commit transaction
186 t.commit()
187
188 return finalCallback()
189 })
190 }
191
192 function removeRemoteVideo (videoToRemoveData, fromHost, callback) {
193 // TODO: use bulkDestroy?
194
195 // We need the list because we have to remove some other stuffs (thumbnail etc)
196 db.Video.listByHostAndRemoteId(fromHost, videoToRemoveData.remoteId, function (err, videosList) {
197 if (err) {
198 logger.error('Cannot list videos from host and remote id.', { error: err.message })
199 return callback(err)
200 }
201
202 if (videosList.length === 0) {
203 logger.error('No remote video was found for this pod.', { remoteId: videoToRemoveData.remoteId, podHost: fromHost })
204 }
205
206 each(videosList, function (video, callbackEach) {
207 logger.debug('Removing remote video %s.', video.remoteId)
208
209 video.destroy().asCallback(callbackEach)
210 }, callback)
211 })
212 }