]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blobdiff - server/controllers/api/remote/videos.js
Server: make a basic "quick and dirty update" for videos
[github/Chocobozzz/PeerTube.git] / server / controllers / api / remote / videos.js
index 9d007246fd775ced2c3e4827be7917e5a9e5d885..79b503d4d0692217bc022d7a7f8e37eb65d9eaf0 100644 (file)
@@ -5,12 +5,22 @@ const express = require('express')
 const waterfall = require('async/waterfall')
 
 const db = require('../../../initializers/database')
+const constants = require('../../../initializers/constants')
 const middlewares = require('../../../middlewares')
 const secureMiddleware = middlewares.secure
 const videosValidators = middlewares.validators.remote.videos
 const signatureValidators = middlewares.validators.remote.signature
 const logger = require('../../../helpers/logger')
-const utils = require('../../../helpers/utils')
+const databaseUtils = require('../../../helpers/database-utils')
+
+const ENDPOINT_ACTIONS = constants.REQUEST_ENDPOINT_ACTIONS[constants.REQUEST_ENDPOINTS.VIDEOS]
+
+// Functions to call when processing a remote request
+const functionsHash = {}
+functionsHash[ENDPOINT_ACTIONS.ADD] = addRemoteVideoRetryWrapper
+functionsHash[ENDPOINT_ACTIONS.UPDATE] = updateRemoteVideoRetryWrapper
+functionsHash[ENDPOINT_ACTIONS.REMOVE] = removeRemoteVideo
+functionsHash[ENDPOINT_ACTIONS.REPORT_ABUSE] = reportAbuseRemoteVideo
 
 const router = express.Router()
 
@@ -21,6 +31,13 @@ router.post('/',
   remoteVideos
 )
 
+router.post('/qadu',
+  signatureValidators.signature,
+  secureMiddleware.checkSignature,
+  videosValidators.remoteQaduVideos,
+  remoteVideosQadu
+)
+
 // ---------------------------------------------------------------------------
 
 module.exports = router
@@ -36,34 +53,89 @@ function remoteVideos (req, res, next) {
   eachSeries(requests, function (request, callbackEach) {
     const data = request.data
 
-    switch (request.type) {
-      case 'add':
-        addRemoteVideoRetryWrapper(data, fromPod, callbackEach)
-        break
+    // Get the function we need to call in order to process the request
+    const fun = functionsHash[request.type]
+    if (fun === undefined) {
+      logger.error('Unkown remote request type %s.', request.type)
+      return callbackEach(null)
+    }
+
+    fun.call(this, data, fromPod, callbackEach)
+  }, function (err) {
+    if (err) logger.error('Error managing remote videos.', { error: err })
+  })
 
-      case 'update':
-        updateRemoteVideoRetryWrapper(data, fromPod, callbackEach)
-        break
+  // We don't need to keep the other pod waiting
+  return res.type('json').status(204).end()
+}
 
-      case 'remove':
-        removeRemoteVideo(data, fromPod, callbackEach)
-        break
+function remoteVideosQadu (req, res, next) {
+  const requests = req.body.data
+  const fromPod = res.locals.secure.pod
 
-      case 'report-abuse':
-        reportAbuseRemoteVideo(data, fromPod, callbackEach)
-        break
+  eachSeries(requests, function (request, callbackEach) {
+    const videoData = request.data
 
-      default:
-        logger.error('Unkown remote request type %s.', request.type)
-    }
+    quickAndDirtyUpdateVideoRetryWrapper(videoData, fromPod, callbackEach)
   }, 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 quickAndDirtyUpdateVideoRetryWrapper (videoData, fromPod, finalCallback) {
+  const options = {
+    arguments: [ videoData, fromPod ],
+    errorMessage: 'Cannot update quick and dirty the remote video with many retries.'
+  }
+
+  databaseUtils.retryTransactionWrapper(quickAndDirtyUpdateVideo, options, finalCallback)
+}
+
+function quickAndDirtyUpdateVideo (videoData, fromPod, finalCallback) {
+  waterfall([
+    databaseUtils.startSerializableTransaction,
+
+    function findVideo (t, callback) {
+      fetchVideo(fromPod.host, videoData.remoteId, function (err, videoInstance) {
+        return callback(err, t, videoInstance)
+      })
+    },
+
+    function updateVideoIntoDB (t, videoInstance, callback) {
+      const options = { transaction: t }
+
+      if (videoData.views) {
+        videoInstance.set('views', videoData.views)
+      }
+
+      if (videoData.likes) {
+        videoInstance.set('likes', videoData.likes)
+      }
+
+      if (videoData.dislikes) {
+        videoInstance.set('dislikes', videoData.dislikes)
+      }
+
+      videoInstance.save(options).asCallback(function (err) {
+        return callback(err, t)
+      })
+    },
+
+    databaseUtils.commitTransaction
+
+  ], function (err, t) {
+    if (err) {
+      logger.debug('Cannot quick and dirty update the remote video.', { error: err })
+      return databaseUtils.rollbackTransaction(err, t, finalCallback)
+    }
+
+    logger.info('Remote video %s quick and dirty updated', videoData.name)
+    return finalCallback(null)
+  })
+}
+
 // Handle retries on fail
 function addRemoteVideoRetryWrapper (videoToCreateData, fromPod, finalCallback) {
   const options = {
@@ -71,7 +143,7 @@ function addRemoteVideoRetryWrapper (videoToCreateData, fromPod, finalCallback)
     errorMessage: 'Cannot insert the remote video with many retries.'
   }
 
-  utils.retryWrapper(addRemoteVideo, options, finalCallback)
+  databaseUtils.retryTransactionWrapper(addRemoteVideo, options, finalCallback)
 }
 
 function addRemoteVideo (videoToCreateData, fromPod, finalCallback) {
@@ -79,9 +151,15 @@ function addRemoteVideo (videoToCreateData, fromPod, finalCallback) {
 
   waterfall([
 
-    function startTransaction (callback) {
-      db.sequelize.transaction({ isolationLevel: 'SERIALIZABLE' }).asCallback(function (err, t) {
-        return callback(err, t)
+    databaseUtils.startSerializableTransaction,
+
+    function assertRemoteIdAndHostUnique (t, callback) {
+      db.Video.loadByHostAndRemoteId(fromPod.host, videoToCreateData.remoteId, function (err, video) {
+        if (err) return callback(err)
+
+        if (video) return callback(new Error('RemoteId and host pair is not unique.'))
+
+        return callback(null, t)
       })
     },
 
@@ -145,42 +223,37 @@ function addRemoteVideo (videoToCreateData, fromPod, finalCallback) {
     },
 
     function associateTagsToVideo (t, tagInstances, video, callback) {
-      const options = { transaction: t }
+      const options = {
+        transaction: t
+      }
 
       video.setTags(tagInstances, options).asCallback(function (err) {
         return callback(err, t)
       })
-    }
+    },
+
+    databaseUtils.commitTransaction
 
   ], function (err, t) {
     if (err) {
       // This is just a debug because we will retry the insert
       logger.debug('Cannot insert the remote video.', { error: err })
-
-      // Abort transaction?
-      if (t) t.rollback()
-
-      return finalCallback(err)
+      return databaseUtils.rollbackTransaction(err, t, finalCallback)
     }
 
-    // Commit transaction
-    t.commit().asCallback(function (err) {
-      if (err) return finalCallback(err)
-
-      logger.info('Remote video %s inserted.', videoToCreateData.name)
-      return finalCallback(null)
-    })
+    logger.info('Remote video %s inserted.', videoToCreateData.name)
+    return finalCallback(null)
   })
 }
 
 // Handle retries on fail
 function updateRemoteVideoRetryWrapper (videoAttributesToUpdate, fromPod, finalCallback) {
   const options = {
-    arguments: [ fromPod, videoAttributesToUpdate ],
+    arguments: [ videoAttributesToUpdate, fromPod ],
     errorMessage: 'Cannot update the remote video with many retries'
   }
 
-  utils.retryWrapper(updateRemoteVideo, options, finalCallback)
+  databaseUtils.retryTransactionWrapper(updateRemoteVideo, options, finalCallback)
 }
 
 function updateRemoteVideo (videoAttributesToUpdate, fromPod, finalCallback) {
@@ -188,11 +261,7 @@ function updateRemoteVideo (videoAttributesToUpdate, fromPod, finalCallback) {
 
   waterfall([
 
-    function startTransaction (callback) {
-      db.sequelize.transaction({ isolationLevel: 'SERIALIZABLE' }).asCallback(function (err, t) {
-        return callback(err, t)
-      })
-    },
+    databaseUtils.startSerializableTransaction,
 
     function findVideo (t, callback) {
       fetchVideo(fromPod.host, videoAttributesToUpdate.remoteId, function (err, videoInstance) {
@@ -230,26 +299,19 @@ function updateRemoteVideo (videoAttributesToUpdate, fromPod, finalCallback) {
       videoInstance.setTags(tagInstances, options).asCallback(function (err) {
         return callback(err, t)
       })
-    }
+    },
+
+    databaseUtils.commitTransaction
 
   ], function (err, t) {
     if (err) {
       // This is just a debug because we will retry the insert
       logger.debug('Cannot update the remote video.', { error: err })
-
-      // Abort transaction?
-      if (t) t.rollback()
-
-      return finalCallback(err)
+      return databaseUtils.rollbackTransaction(err, t, finalCallback)
     }
 
-   // Commit transaction
-    t.commit().asCallback(function (err) {
-      if (err) return finalCallback(err)
-
-      logger.info('Remote video %s updated', videoAttributesToUpdate.name)
-      return finalCallback(null)
-    })
+    logger.info('Remote video %s updated', videoAttributesToUpdate.name)
+    return finalCallback(null)
   })
 }