First version with PostgreSQL
[oweals/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, callback) {
54   logger.debug('Adding remote video "%s".', videoToCreateData.name)
55
56   waterfall([
57
58     function findOrCreatePod (callback) {
59       fromHost
60
61       const query = {
62         where: {
63           host: fromHost
64         },
65         defaults: {
66           host: fromHost
67         }
68       }
69
70       db.Pod.findOrCreate(query).asCallback(function (err, result) {
71         // [ instance, wasCreated ]
72         return callback(err, result[0])
73       })
74     },
75
76     function findOrCreateAuthor (pod, callback) {
77       const username = videoToCreateData.author
78
79       const query = {
80         where: {
81           name: username,
82           podId: pod.id
83         },
84         defaults: {
85           name: username,
86           podId: pod.id
87         }
88       }
89
90       db.Author.findOrCreate(query).asCallback(function (err, result) {
91         // [ instance, wasCreated ]
92         return callback(err, result[0])
93       })
94     },
95
96     function createVideoObject (author, callback) {
97       const videoData = {
98         name: videoToCreateData.name,
99         remoteId: videoToCreateData.remoteId,
100         extname: videoToCreateData.extname,
101         infoHash: videoToCreateData.infoHash,
102         description: videoToCreateData.description,
103         authorId: author.id,
104         duration: videoToCreateData.duration,
105         tags: videoToCreateData.tags
106       }
107
108       const video = db.Video.build(videoData)
109
110       return callback(null, video)
111     },
112
113     function generateThumbnail (video, callback) {
114       db.Video.generateThumbnailFromBase64(video, videoToCreateData.thumbnailBase64, function (err) {
115         if (err) {
116           logger.error('Cannot generate thumbnail from base 64 data.', { error: err })
117           return callback(err)
118         }
119
120         video.save().asCallback(callback)
121       })
122     },
123
124     function insertIntoDB (video, callback) {
125       video.save().asCallback(callback)
126     }
127
128   ], callback)
129 }
130
131 function removeRemoteVideo (videoToRemoveData, fromHost, callback) {
132   // TODO: use bulkDestroy?
133
134   // We need the list because we have to remove some other stuffs (thumbnail etc)
135   db.Video.listByHostAndRemoteId(fromHost, videoToRemoveData.remoteId, function (err, videosList) {
136     if (err) {
137       logger.error('Cannot list videos from host and remote id.', { error: err.message })
138       return callback(err)
139     }
140
141     if (videosList.length === 0) {
142       logger.error('No remote video was found for this pod.', { remoteId: videoToRemoveData.remoteId, podHost: fromHost })
143     }
144
145     each(videosList, function (video, callbackEach) {
146       logger.debug('Removing remote video %s.', video.remoteId)
147
148       video.destroy().asCallback(callbackEach)
149     }, callback)
150   })
151 }