Create redundancy endpoint
authorChocobozzz <me@florianbigard.com>
Tue, 4 Dec 2018 16:08:55 +0000 (17:08 +0100)
committerChocobozzz <me@florianbigard.com>
Tue, 4 Dec 2018 16:08:55 +0000 (17:08 +0100)
server/controllers/static.ts
server/initializers/constants.ts
server/lib/schedulers/videos-redundancy-scheduler.ts
server/models/redundancy/video-redundancy.ts
server/models/video/video.ts
server/tests/api/redundancy/redundancy.ts
support/nginx/peertube

index f16a7d72bbd802aa0e1c1a7af8efa41876dc30d2..55e7392a1a1af040f667d170c8f1ee8030f31bf9 100644 (file)
@@ -37,12 +37,12 @@ staticRouter.use(
 staticRouter.use(
   STATIC_PATHS.WEBSEED,
   cors(),
-  express.static(CONFIG.STORAGE.VIDEOS_DIR)
+  express.static(CONFIG.STORAGE.VIDEOS_DIR, { fallthrough: false }) // 404 because we don't have this video
 )
 staticRouter.use(
-  STATIC_PATHS.WEBSEED,
+  STATIC_PATHS.REDUNDANCY,
   cors(),
-  express.static(CONFIG.STORAGE.REDUNDANCY_DIR, { fallthrough: false }) // 404, because we don't have this video
+  express.static(CONFIG.STORAGE.REDUNDANCY_DIR, { fallthrough: false }) // 404 because we don't have this video
 )
 
 staticRouter.use(
index 876aa1cf534e19f12ef8ef7c71bb85705ea8b0c0..7195ae6c57e77d035cc369bdfabc52d9131893ad 100644 (file)
@@ -571,6 +571,7 @@ const STATIC_PATHS = {
   THUMBNAILS: '/static/thumbnails/',
   TORRENTS: '/static/torrents/',
   WEBSEED: '/static/webseed/',
+  REDUNDANCY: '/static/redundancy/',
   AVATARS: '/static/avatars/',
   VIDEO_CAPTIONS: '/static/video-captions/'
 }
index 8b7f335398acdf9b419a9d5fcd847cffbbb07966..2a99a665d12fd05d755c5360f734532f2f7a54b5 100644 (file)
@@ -145,13 +145,13 @@ export class VideosRedundancyScheduler extends AbstractScheduler {
 
       const tmpPath = await downloadWebTorrentVideo({ magnetUri }, VIDEO_IMPORT_TIMEOUT)
 
-      const destPath = join(CONFIG.STORAGE.VIDEOS_DIR, video.getVideoFilename(file))
+      const destPath = join(CONFIG.STORAGE.REDUNDANCY_DIR, video.getVideoFilename(file))
       await rename(tmpPath, destPath)
 
       const createdModel = await VideoRedundancyModel.create({
         expiresOn: this.buildNewExpiration(redundancy.minLifetime),
         url: getVideoCacheFileActivityPubUrl(file),
-        fileUrl: video.getVideoFileUrl(file, CONFIG.WEBSERVER.URL),
+        fileUrl: video.getVideoRedundancyUrl(file, CONFIG.WEBSERVER.URL),
         strategy: redundancy.strategy,
         videoFileId: file.id,
         actorId: serverActor.id
index 9de4356b408c45961ea52e7087969c984f1dca3a..dd37dad22c05a7c5fbbe729d2bafed77fc47ce68 100644 (file)
@@ -15,7 +15,7 @@ import {
 import { ActorModel } from '../activitypub/actor'
 import { getVideoSort, throwIfNotValid } from '../utils'
 import { isActivityPubUrlValid, isUrlValid } from '../../helpers/custom-validators/activitypub/misc'
-import { CONFIG, CONSTRAINTS_FIELDS, VIDEO_EXT_MIMETYPE } from '../../initializers'
+import { CONFIG, CONSTRAINTS_FIELDS, STATIC_PATHS, VIDEO_EXT_MIMETYPE } from '../../initializers'
 import { VideoFileModel } from '../video/video-file'
 import { getServerActor } from '../../helpers/utils'
 import { VideoModel } from '../video/video'
@@ -124,7 +124,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> {
     const logIdentifier = `${videoFile.Video.uuid}-${videoFile.resolution}`
     logger.info('Removing duplicated video file %s.', logIdentifier)
 
-    videoFile.Video.removeFile(videoFile)
+    videoFile.Video.removeFile(videoFile, true)
              .catch(err => logger.error('Cannot delete %s files.', logIdentifier, { err }))
 
     return undefined
index 0f18d9f0c82e819371497c62691f6362d388f885..e8cb5aa8847b815b1988fcd33834e95c58d36d28 100644 (file)
@@ -1538,8 +1538,10 @@ export class VideoModel extends Model<VideoModel> {
       .catch(err => logger.warn('Cannot delete preview %s.', previewPath, { err }))
   }
 
-  removeFile (videoFile: VideoFileModel) {
-    const filePath = join(CONFIG.STORAGE.VIDEOS_DIR, this.getVideoFilename(videoFile))
+  removeFile (videoFile: VideoFileModel, isRedundancy = false) {
+    const baseDir = isRedundancy ? CONFIG.STORAGE.REDUNDANCY_DIR : CONFIG.STORAGE.VIDEOS_DIR
+
+    const filePath = join(baseDir, this.getVideoFilename(videoFile))
     return remove(filePath)
       .catch(err => logger.warn('Cannot delete file %s.', filePath, { err }))
   }
@@ -1617,6 +1619,10 @@ export class VideoModel extends Model<VideoModel> {
     return baseUrlHttp + STATIC_PATHS.WEBSEED + this.getVideoFilename(videoFile)
   }
 
+  getVideoRedundancyUrl (videoFile: VideoFileModel, baseUrlHttp: string) {
+    return baseUrlHttp + STATIC_PATHS.REDUNDANCY + this.getVideoFilename(videoFile)
+  }
+
   getVideoFileDownloadUrl (videoFile: VideoFileModel, baseUrlHttp: string) {
     return baseUrlHttp + STATIC_DOWNLOAD_PATHS.VIDEOS + this.getVideoFilename(videoFile)
   }
index a8a2f305fd5a91c2b2c3413f11e7838faa5c0521..5b29a503ae47793925f0dacdc2cbf49c1694b229 100644 (file)
@@ -136,7 +136,7 @@ async function check2Webseeds (strategy: VideoRedundancyStrategy, videoUUID?: st
   if (!videoUUID) videoUUID = video1Server2UUID
 
   const webseeds = [
-    'http://localhost:9001/static/webseed/' + videoUUID,
+    'http://localhost:9001/static/redundancy/' + videoUUID,
     'http://localhost:9002/static/webseed/' + videoUUID
   ]
 
@@ -148,20 +148,23 @@ async function check2Webseeds (strategy: VideoRedundancyStrategy, videoUUID?: st
     for (const file of video.files) {
       checkMagnetWebseeds(file, webseeds, server)
 
-      // Only servers 1 and 2 have the video
-      if (server.serverNumber !== 3) {
-        await makeGetRequest({
-          url: server.url,
-          statusCodeExpected: 200,
-          path: '/static/webseed/' + `${videoUUID}-${file.resolution.id}.mp4`,
-          contentType: null
-        })
-      }
+      await makeGetRequest({
+        url: servers[0].url,
+        statusCodeExpected: 200,
+        path: '/static/redundancy/' + `${videoUUID}-${file.resolution.id}.mp4`,
+        contentType: null
+      })
+      await makeGetRequest({
+        url: servers[1].url,
+        statusCodeExpected: 200,
+        path: '/static/webseed/' + `${videoUUID}-${file.resolution.id}.mp4`,
+        contentType: null
+      })
     }
   }
 
-  for (const directory of [ 'test1', 'test2' ]) {
-    const files = await readdir(join(root(), directory, 'videos'))
+  for (const directory of [ 'test1/redundancy', 'test2/videos' ]) {
+    const files = await readdir(join(root(), directory))
     expect(files).to.have.length.at.least(4)
 
     for (const resolution of [ 240, 360, 480, 720 ]) {
index b0003113371fb5601ee3783a32f5582b0dd33127..e0b0060883945cafa796591c423469d38602af07 100644 (file)
@@ -105,7 +105,7 @@ server {
   }
 
   # Bypass PeerTube for performance reasons. Could be removed
-  location /static/webseed {
+  location ~ ^/static/(webseed|redundancy)/ {
     # Clients usually have 4 simultaneous webseed connections, so the real limit is 3MB/s per client
     limit_rate 800k;
 
@@ -128,7 +128,12 @@ server {
       access_log off;
     }
 
-    alias /var/www/peertube/storage/videos;
+    root /var/www/peertube/storage;
+
+    rewrite ^/static/webseed/(.*)$ /videos/$1 break;
+    rewrite ^/static/redundancy/(.*)$ /redundancy/$1 break;
+
+    try_files $uri /;
   }
 
   # Websocket tracker