aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/controllers/api/remote.js
blob: d856576a9f2ae880c4f134bc4f9b3750566e0d41 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
'use strict'

const each = require('async/each')
const eachSeries = require('async/eachSeries')
const express = require('express')
const waterfall = require('async/waterfall')

const db = require('../../initializers/database')
const middlewares = require('../../middlewares')
const secureMiddleware = middlewares.secure
const validators = middlewares.validators.remote
const logger = require('../../helpers/logger')

const router = express.Router()

router.post('/videos',
  validators.signature,
  secureMiddleware.checkSignature,
  validators.remoteVideos,
  remoteVideos
)

// ---------------------------------------------------------------------------

module.exports = router

// ---------------------------------------------------------------------------

function remoteVideos (req, res, next) {
  const requests = req.body.data
  const fromHost = req.body.signature.host

  // We need to process in the same order to keep consistency
  // TODO: optimization
  eachSeries(requests, function (request, callbackEach) {
    const videoData = request.data

    if (request.type === 'add') {
      addRemoteVideo(videoData, fromHost, callbackEach)
    } else if (request.type === 'remove') {
      removeRemoteVideo(videoData, fromHost, callbackEach)
    } else {
      logger.error('Unkown remote request type %s.', request.type)
    }
  }, function (err) {
    if (err) logger.error('Error managing remote videos.', { error: err })
  })

  // We don't need to keep the other pod waiting
  return res.type('json').status(204).end()
}

function addRemoteVideo (videoToCreateData, fromHost, callback) {
  logger.debug('Adding remote video "%s".', videoToCreateData.name)

  waterfall([

    function findOrCreatePod (callback) {
      fromHost

      const query = {
        where: {
          host: fromHost
        },
        defaults: {
          host: fromHost
        }
      }

      db.Pod.findOrCreate(query).asCallback(function (err, result) {
        // [ instance, wasCreated ]
        return callback(err, result[0])
      })
    },

    function findOrCreateAuthor (pod, callback) {
      const username = videoToCreateData.author

      const query = {
        where: {
          name: username,
          podId: pod.id
        },
        defaults: {
          name: username,
          podId: pod.id
        }
      }

      db.Author.findOrCreate(query).asCallback(function (err, result) {
        // [ instance, wasCreated ]
        return callback(err, result[0])
      })
    },

    function createVideoObject (author, callback) {
      const videoData = {
        name: videoToCreateData.name,
        remoteId: videoToCreateData.remoteId,
        extname: videoToCreateData.extname,
        infoHash: videoToCreateData.infoHash,
        description: videoToCreateData.description,
        authorId: author.id,
        duration: videoToCreateData.duration,
        tags: videoToCreateData.tags
      }

      const video = db.Video.build(videoData)

      return callback(null, video)
    },

    function generateThumbnail (video, callback) {
      db.Video.generateThumbnailFromBase64(video, videoToCreateData.thumbnailBase64, function (err) {
        if (err) {
          logger.error('Cannot generate thumbnail from base 64 data.', { error: err })
          return callback(err)
        }

        video.save().asCallback(callback)
      })
    },

    function insertIntoDB (video, callback) {
      video.save().asCallback(callback)
    }

  ], callback)
}

function removeRemoteVideo (videoToRemoveData, fromHost, callback) {
  // TODO: use bulkDestroy?

  // We need the list because we have to remove some other stuffs (thumbnail etc)
  db.Video.listByHostAndRemoteId(fromHost, videoToRemoveData.remoteId, function (err, videosList) {
    if (err) {
      logger.error('Cannot list videos from host and remote id.', { error: err.message })
      return callback(err)
    }

    if (videosList.length === 0) {
      logger.error('No remote video was found for this pod.', { remoteId: videoToRemoveData.remoteId, podHost: fromHost })
    }

    each(videosList, function (video, callbackEach) {
      logger.debug('Removing remote video %s.', video.remoteId)

      video.destroy().asCallback(callbackEach)
    }, callback)
  })
}