aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--controllers/api/v1/index.js18
-rw-r--r--controllers/api/v1/pods.js136
-rw-r--r--controllers/api/v1/remoteVideos.js82
-rw-r--r--controllers/api/v1/videos.js232
-rw-r--r--controllers/index.js14
-rw-r--r--controllers/views.js36
-rw-r--r--helpers/customValidators.js52
-rw-r--r--helpers/logger.js70
-rw-r--r--helpers/peertubeCrypto.js252
-rw-r--r--helpers/requests.js178
-rw-r--r--helpers/utils.js24
-rw-r--r--initializers/checker.js84
-rw-r--r--initializers/constants.js86
-rw-r--r--initializers/database.js46
-rw-r--r--lib/friends.js356
-rw-r--r--lib/poolRequests.js358
-rw-r--r--lib/videos.js102
-rw-r--r--lib/webtorrent.js254
-rw-r--r--lib/webtorrentProcess.js144
-rw-r--r--middlewares/cache.js36
-rw-r--r--middlewares/index.js18
-rw-r--r--middlewares/reqValidators/index.js18
-rw-r--r--middlewares/reqValidators/pods.js80
-rw-r--r--middlewares/reqValidators/remote.js62
-rw-r--r--middlewares/reqValidators/utils.js36
-rw-r--r--middlewares/reqValidators/videos.js106
-rw-r--r--middlewares/secure.js100
-rw-r--r--models/pods.js152
-rw-r--r--models/poolRequests.js84
-rw-r--r--models/videos.js394
-rw-r--r--tests/api/checkParams.js490
-rw-r--r--tests/api/friendsAdvanced.js424
-rw-r--r--tests/api/friendsBasic.js300
-rw-r--r--tests/api/index.js16
-rw-r--r--tests/api/multiplePods.js544
-rw-r--r--tests/api/singlePod.js224
-rw-r--r--tests/api/utils.js340
37 files changed, 2937 insertions, 3011 deletions
diff --git a/controllers/api/v1/index.js b/controllers/api/v1/index.js
index b16eeb0f6..fc6bf4946 100644
--- a/controllers/api/v1/index.js
+++ b/controllers/api/v1/index.js
@@ -1,15 +1,13 @@
1;(function () { 1'use strict'
2 'use strict'
3 2
4 var express = require('express') 3var express = require('express')
5 4
6 var router = express.Router() 5var router = express.Router()
7 6
8 router.use('/pods', require('./pods')) 7router.use('/pods', require('./pods'))
9 router.use('/remotevideos', require('./remoteVideos')) 8router.use('/remotevideos', require('./remoteVideos'))
10 router.use('/videos', require('./videos')) 9router.use('/videos', require('./videos'))
11 10
12 // --------------------------------------------------------------------------- 11// ---------------------------------------------------------------------------
13 12
14 module.exports = router 13module.exports = router
15})()
diff --git a/controllers/api/v1/pods.js b/controllers/api/v1/pods.js
index 456f53dea..c93a86ee8 100644
--- a/controllers/api/v1/pods.js
+++ b/controllers/api/v1/pods.js
@@ -1,95 +1,93 @@
1;(function () { 1'use strict'
2 'use strict'
3 2
4 var express = require('express') 3var express = require('express')
5 var fs = require('fs') 4var fs = require('fs')
6 5
7 var logger = require('../../../helpers/logger') 6var logger = require('../../../helpers/logger')
8 var friends = require('../../../lib/friends') 7var friends = require('../../../lib/friends')
9 var middleware = require('../../../middlewares') 8var middleware = require('../../../middlewares')
10 var cacheMiddleware = middleware.cache 9var cacheMiddleware = middleware.cache
11 var peertubeCrypto = require('../../../helpers/peertubeCrypto') 10var peertubeCrypto = require('../../../helpers/peertubeCrypto')
12 var Pods = require('../../../models/pods') 11var Pods = require('../../../models/pods')
13 var reqValidator = middleware.reqValidators.pods 12var reqValidator = middleware.reqValidators.pods
14 var secureMiddleware = middleware.secure 13var secureMiddleware = middleware.secure
15 var secureRequest = middleware.reqValidators.remote.secureRequest 14var secureRequest = middleware.reqValidators.remote.secureRequest
16 var Videos = require('../../../models/videos') 15var Videos = require('../../../models/videos')
17 16
18 var router = express.Router() 17var router = express.Router()
19 18
20 router.get('/', cacheMiddleware.cache(false), listPods) 19router.get('/', cacheMiddleware.cache(false), listPods)
21 router.post('/', reqValidator.podsAdd, cacheMiddleware.cache(false), addPods) 20router.post('/', reqValidator.podsAdd, cacheMiddleware.cache(false), addPods)
22 router.get('/makefriends', reqValidator.makeFriends, cacheMiddleware.cache(false), makeFriends) 21router.get('/makefriends', reqValidator.makeFriends, cacheMiddleware.cache(false), makeFriends)
23 router.get('/quitfriends', cacheMiddleware.cache(false), quitFriends) 22router.get('/quitfriends', cacheMiddleware.cache(false), quitFriends)
24 // Post because this is a secured request 23// Post because this is a secured request
25 router.post('/remove', secureRequest, secureMiddleware.decryptBody, removePods) 24router.post('/remove', secureRequest, secureMiddleware.decryptBody, removePods)
26 25
27 // --------------------------------------------------------------------------- 26// ---------------------------------------------------------------------------
28 27
29 module.exports = router 28module.exports = router
30 29
31 // --------------------------------------------------------------------------- 30// ---------------------------------------------------------------------------
32 31
33 function addPods (req, res, next) { 32function addPods (req, res, next) {
34 var informations = req.body.data 33 var informations = req.body.data
35 Pods.add(informations, function (err) { 34 Pods.add(informations, function (err) {
36 if (err) return next(err) 35 if (err) return next(err)
37 36
38 Videos.addRemotes(informations.videos) 37 Videos.addRemotes(informations.videos)
39 38
40 fs.readFile(peertubeCrypto.getCertDir() + 'peertube.pub', 'utf8', function (err, cert) { 39 fs.readFile(peertubeCrypto.getCertDir() + 'peertube.pub', 'utf8', function (err, cert) {
40 if (err) {
41 logger.error('Cannot read cert file.')
42 return next(err)
43 }
44
45 Videos.listOwned(function (err, videos_list) {
41 if (err) { 46 if (err) {
42 logger.error('Cannot read cert file.') 47 logger.error('Cannot get the list of owned videos.')
43 return next(err) 48 return next(err)
44 } 49 }
45 50
46 Videos.listOwned(function (err, videos_list) { 51 res.json({ cert: cert, videos: videos_list })
47 if (err) {
48 logger.error('Cannot get the list of owned videos.')
49 return next(err)
50 }
51
52 res.json({ cert: cert, videos: videos_list })
53 })
54 }) 52 })
55 }) 53 })
56 } 54 })
55}
57 56
58 function listPods (req, res, next) { 57function listPods (req, res, next) {
59 Pods.list(function (err, pods_list) { 58 Pods.list(function (err, pods_list) {
60 if (err) return next(err) 59 if (err) return next(err)
61 60
62 res.json(pods_list) 61 res.json(pods_list)
63 }) 62 })
64 } 63}
65 64
66 function makeFriends (req, res, next) { 65function makeFriends (req, res, next) {
67 friends.makeFriends(function (err) { 66 friends.makeFriends(function (err) {
68 if (err) return next(err) 67 if (err) return next(err)
69 68
70 res.sendStatus(204) 69 res.sendStatus(204)
71 }) 70 })
72 } 71}
73 72
74 function removePods (req, res, next) { 73function removePods (req, res, next) {
75 var url = req.body.signature.url 74 var url = req.body.signature.url
76 Pods.remove(url, function (err) { 75 Pods.remove(url, function (err) {
77 if (err) return next(err) 76 if (err) return next(err)
78 77
79 Videos.removeAllRemotesOf(url, function (err) { 78 Videos.removeAllRemotesOf(url, function (err) {
80 if (err) logger.error('Cannot remove all remote videos of %s.', url) 79 if (err) logger.error('Cannot remove all remote videos of %s.', url)
81 else logger.info('%s pod removed.', url) 80 else logger.info('%s pod removed.', url)
82 81
83 res.sendStatus(204) 82 res.sendStatus(204)
84 })
85 }) 83 })
86 } 84 })
85}
87 86
88 function quitFriends (req, res, next) { 87function quitFriends (req, res, next) {
89 friends.quitFriends(function (err) { 88 friends.quitFriends(function (err) {
90 if (err) return next(err) 89 if (err) return next(err)
91 90
92 res.sendStatus(204) 91 res.sendStatus(204)
93 }) 92 })
94 } 93}
95})()
diff --git a/controllers/api/v1/remoteVideos.js b/controllers/api/v1/remoteVideos.js
index 58bb5f3cb..475a874cf 100644
--- a/controllers/api/v1/remoteVideos.js
+++ b/controllers/api/v1/remoteVideos.js
@@ -1,55 +1,53 @@
1;(function () { 1'use strict'
2 'use strict'
3 2
4 var express = require('express') 3var express = require('express')
5 var pluck = require('lodash-node/compat/collection/pluck') 4var pluck = require('lodash-node/compat/collection/pluck')
6 5
7 var middleware = require('../../../middlewares') 6var middleware = require('../../../middlewares')
8 var secureMiddleware = middleware.secure 7var secureMiddleware = middleware.secure
9 var cacheMiddleware = middleware.cache 8var cacheMiddleware = middleware.cache
10 var reqValidator = middleware.reqValidators.remote 9var reqValidator = middleware.reqValidators.remote
11 var videos = require('../../../models/videos') 10var videos = require('../../../models/videos')
12 11
13 var router = express.Router() 12var router = express.Router()
14 13
15 router.post('/add', 14router.post('/add',
16 reqValidator.secureRequest, 15 reqValidator.secureRequest,
17 secureMiddleware.decryptBody, 16 secureMiddleware.decryptBody,
18 reqValidator.remoteVideosAdd, 17 reqValidator.remoteVideosAdd,
19 cacheMiddleware.cache(false), 18 cacheMiddleware.cache(false),
20 addRemoteVideos 19 addRemoteVideos
21 ) 20)
22 21
23 router.post('/remove', 22router.post('/remove',
24 reqValidator.secureRequest, 23 reqValidator.secureRequest,
25 secureMiddleware.decryptBody, 24 secureMiddleware.decryptBody,
26 reqValidator.remoteVideosRemove, 25 reqValidator.remoteVideosRemove,
27 cacheMiddleware.cache(false), 26 cacheMiddleware.cache(false),
28 removeRemoteVideo 27 removeRemoteVideo
29 ) 28)
30 29
31 // --------------------------------------------------------------------------- 30// ---------------------------------------------------------------------------
32 31
33 module.exports = router 32module.exports = router
34 33
35 // --------------------------------------------------------------------------- 34// ---------------------------------------------------------------------------
36 35
37 function addRemoteVideos (req, res, next) { 36function addRemoteVideos (req, res, next) {
38 videos.addRemotes(req.body.data, function (err, videos) { 37 videos.addRemotes(req.body.data, function (err, videos) {
39 if (err) return next(err) 38 if (err) return next(err)
40 39
41 res.json(videos) 40 res.json(videos)
42 }) 41 })
43 } 42}
44 43
45 function removeRemoteVideo (req, res, next) { 44function removeRemoteVideo (req, res, next) {
46 var url = req.body.signature.url 45 var url = req.body.signature.url
47 var magnetUris = pluck(req.body.data, 'magnetUri') 46 var magnetUris = pluck(req.body.data, 'magnetUri')
48 47
49 videos.removeRemotesOfByMagnetUris(url, magnetUris, function (err) { 48 videos.removeRemotesOfByMagnetUris(url, magnetUris, function (err) {
50 if (err) return next(err) 49 if (err) return next(err)
51 50
52 res.sendStatus(204) 51 res.sendStatus(204)
53 }) 52 })
54 } 53}
55})()
diff --git a/controllers/api/v1/videos.js b/controllers/api/v1/videos.js
index 7dccfa7c3..620711925 100644
--- a/controllers/api/v1/videos.js
+++ b/controllers/api/v1/videos.js
@@ -1,146 +1,144 @@
1;(function () { 1'use strict'
2 'use strict' 2
3 3var config = require('config')
4 var config = require('config') 4var crypto = require('crypto')
5 var crypto = require('crypto') 5var express = require('express')
6 var express = require('express') 6var multer = require('multer')
7 var multer = require('multer') 7
8 8var logger = require('../../../helpers/logger')
9 var logger = require('../../../helpers/logger') 9var friends = require('../../../lib/friends')
10 var friends = require('../../../lib/friends') 10var middleware = require('../../../middlewares')
11 var middleware = require('../../../middlewares') 11var cacheMiddleware = middleware.cache
12 var cacheMiddleware = middleware.cache 12var reqValidator = middleware.reqValidators.videos
13 var reqValidator = middleware.reqValidators.videos 13var Videos = require('../../../models/videos') // model
14 var Videos = require('../../../models/videos') // model 14var videos = require('../../../lib/videos')
15 var videos = require('../../../lib/videos') 15var webtorrent = require('../../../lib/webtorrent')
16 var webtorrent = require('../../../lib/webtorrent') 16
17 17var router = express.Router()
18 var router = express.Router() 18var uploads = config.get('storage.uploads')
19 var uploads = config.get('storage.uploads') 19
20 20// multer configuration
21 // multer configuration 21var storage = multer.diskStorage({
22 var storage = multer.diskStorage({ 22 destination: function (req, file, cb) {
23 destination: function (req, file, cb) { 23 cb(null, uploads)
24 cb(null, uploads) 24 },
25 }, 25
26 26 filename: function (req, file, cb) {
27 filename: function (req, file, cb) { 27 var extension = ''
28 var extension = '' 28 if (file.mimetype === 'video/webm') extension = 'webm'
29 if (file.mimetype === 'video/webm') extension = 'webm' 29 else if (file.mimetype === 'video/mp4') extension = 'mp4'
30 else if (file.mimetype === 'video/mp4') extension = 'mp4' 30 else if (file.mimetype === 'video/ogg') extension = 'ogv'
31 else if (file.mimetype === 'video/ogg') extension = 'ogv' 31 crypto.pseudoRandomBytes(16, function (err, raw) {
32 crypto.pseudoRandomBytes(16, function (err, raw) { 32 var fieldname = err ? undefined : raw.toString('hex')
33 var fieldname = err ? undefined : raw.toString('hex') 33 cb(null, fieldname + '.' + extension)
34 cb(null, fieldname + '.' + extension) 34 })
35 }) 35 }
36 } 36})
37 }) 37
38var reqFiles = multer({ storage: storage }).fields([{ name: 'input_video', maxCount: 1 }])
38 39
39 var reqFiles = multer({ storage: storage }).fields([{ name: 'input_video', maxCount: 1 }]) 40router.get('/', cacheMiddleware.cache(false), listVideos)
41router.post('/', reqFiles, reqValidator.videosAdd, cacheMiddleware.cache(false), addVideo)
42router.get('/:id', reqValidator.videosGet, cacheMiddleware.cache(false), getVideos)
43router.delete('/:id', reqValidator.videosRemove, cacheMiddleware.cache(false), removeVideo)
44router.get('/search/:name', reqValidator.videosSearch, cacheMiddleware.cache(false), searchVideos)
40 45
41 router.get('/', cacheMiddleware.cache(false), listVideos) 46// ---------------------------------------------------------------------------
42 router.post('/', reqFiles, reqValidator.videosAdd, cacheMiddleware.cache(false), addVideo)
43 router.get('/:id', reqValidator.videosGet, cacheMiddleware.cache(false), getVideos)
44 router.delete('/:id', reqValidator.videosRemove, cacheMiddleware.cache(false), removeVideo)
45 router.get('/search/:name', reqValidator.videosSearch, cacheMiddleware.cache(false), searchVideos)
46 47
47 // --------------------------------------------------------------------------- 48module.exports = router
48 49
49 module.exports = router 50// ---------------------------------------------------------------------------
50 51
51 // --------------------------------------------------------------------------- 52function addVideo (req, res, next) {
53 var video_file = req.files.input_video[0]
54 var video_infos = req.body
55
56 videos.seed(video_file.path, function (err, torrent) {
57 if (err) {
58 logger.error('Cannot seed this video.')
59 return next(err)
60 }
52 61
53 function addVideo (req, res, next) { 62 var video_data = {
54 var video_file = req.files.input_video[0] 63 name: video_infos.name,
55 var video_infos = req.body 64 namePath: video_file.filename,
65 description: video_infos.description,
66 magnetUri: torrent.magnetURI
67 }
56 68
57 videos.seed(video_file.path, function (err, torrent) { 69 Videos.add(video_data, function (err) {
58 if (err) { 70 if (err) {
59 logger.error('Cannot seed this video.') 71 // TODO unseed the video
72 logger.error('Cannot insert this video in the database.')
60 return next(err) 73 return next(err)
61 } 74 }
62 75
63 var video_data = { 76 // Now we'll add the video's meta data to our friends
64 name: video_infos.name, 77 friends.addVideoToFriends(video_data)
65 namePath: video_file.filename,
66 description: video_infos.description,
67 magnetUri: torrent.magnetURI
68 }
69
70 Videos.add(video_data, function (err) {
71 if (err) {
72 // TODO unseed the video
73 logger.error('Cannot insert this video in the database.')
74 return next(err)
75 }
76
77 // Now we'll add the video's meta data to our friends
78 friends.addVideoToFriends(video_data)
79 78
80 // TODO : include Location of the new video 79 // TODO : include Location of the new video
81 res.sendStatus(201) 80 res.sendStatus(201)
82 })
83 }) 81 })
84 } 82 })
83}
85 84
86 function getVideos (req, res, next) { 85function getVideos (req, res, next) {
87 Videos.get(req.params.id, function (err, video) { 86 Videos.get(req.params.id, function (err, video) {
88 if (err) return next(err) 87 if (err) return next(err)
89 88
90 if (video === null) { 89 if (video === null) {
91 return res.sendStatus(404) 90 return res.sendStatus(404)
92 } 91 }
93 92
94 res.json(video) 93 res.json(video)
95 }) 94 })
96 } 95}
97 96
98 function listVideos (req, res, next) { 97function listVideos (req, res, next) {
99 Videos.list(function (err, videos_list) { 98 Videos.list(function (err, videos_list) {
100 if (err) return next(err) 99 if (err) return next(err)
101 100
102 res.json(videos_list) 101 res.json(videos_list)
103 }) 102 })
104 } 103}
105 104
106 function removeVideo (req, res, next) { 105function removeVideo (req, res, next) {
107 var video_id = req.params.id 106 var video_id = req.params.id
108 Videos.get(video_id, function (err, video) { 107 Videos.get(video_id, function (err, video) {
109 if (err) return next(err) 108 if (err) return next(err)
110 109
111 removeTorrent(video.magnetUri, function () { 110 removeTorrent(video.magnetUri, function () {
112 Videos.removeOwned(req.params.id, function (err) { 111 Videos.removeOwned(req.params.id, function (err) {
113 if (err) return next(err) 112 if (err) return next(err)
114 113
115 var params = { 114 var params = {
116 name: video.name, 115 name: video.name,
117 magnetUri: video.magnetUri 116 magnetUri: video.magnetUri
118 } 117 }
119 118
120 friends.removeVideoToFriends(params) 119 friends.removeVideoToFriends(params)
121 res.sendStatus(204) 120 res.sendStatus(204)
122 })
123 }) 121 })
124 }) 122 })
125 } 123 })
124}
126 125
127 function searchVideos (req, res, next) { 126function searchVideos (req, res, next) {
128 Videos.search(req.params.name, function (err, videos_list) { 127 Videos.search(req.params.name, function (err, videos_list) {
129 if (err) return next(err) 128 if (err) return next(err)
130 129
131 res.json(videos_list) 130 res.json(videos_list)
132 }) 131 })
133 } 132}
134 133
135 // --------------------------------------------------------------------------- 134// ---------------------------------------------------------------------------
136 135
137 // Maybe the torrent is not seeded, but we catch the error to don't stop the removing process 136// Maybe the torrent is not seeded, but we catch the error to don't stop the removing process
138 function removeTorrent (magnetUri, callback) { 137function removeTorrent (magnetUri, callback) {
139 try { 138 try {
140 webtorrent.remove(magnetUri, callback) 139 webtorrent.remove(magnetUri, callback)
141 } catch (err) { 140 } catch (err) {
142 logger.warn('Cannot remove the torrent from WebTorrent', { err: err }) 141 logger.warn('Cannot remove the torrent from WebTorrent', { err: err })
143 return callback(null) 142 return callback(null)
144 }
145 } 143 }
146})() 144}
diff --git a/controllers/index.js b/controllers/index.js
index 770d08248..35a0191c5 100644
--- a/controllers/index.js
+++ b/controllers/index.js
@@ -1,10 +1,8 @@
1;(function () { 1'use strict'
2 'use strict'
3 2
4 var constants = require('../initializers/constants') 3var constants = require('../initializers/constants')
5 4
6 module.exports = { 5module.exports = {
7 api: require('./api/' + constants.API_VERSION), 6 api: require('./api/' + constants.API_VERSION),
8 views: require('./views') 7 views: require('./views')
9 } 8}
10})()
diff --git a/controllers/views.js b/controllers/views.js
index 82d3d00ab..aa9718079 100644
--- a/controllers/views.js
+++ b/controllers/views.js
@@ -1,29 +1,27 @@
1;(function () { 1'use strict'
2 'use strict'
3 2
4 var express = require('express') 3var express = require('express')
5 4
6 var cacheMiddleware = require('../middlewares').cache 5var cacheMiddleware = require('../middlewares').cache
7 6
8 var router = express.Router() 7var router = express.Router()
9 8
10 router.get(/^\/(index)?$/, cacheMiddleware.cache(), getIndex) 9router.get(/^\/(index)?$/, cacheMiddleware.cache(), getIndex)
11 router.get('/partials/:directory/:name', cacheMiddleware.cache(), getPartial) 10router.get('/partials/:directory/:name', cacheMiddleware.cache(), getPartial)
12 11
13 // --------------------------------------------------------------------------- 12// ---------------------------------------------------------------------------
14 13
15 module.exports = router 14module.exports = router
16 15
17 // --------------------------------------------------------------------------- 16// ---------------------------------------------------------------------------
18 17
19 function getIndex (req, res) { 18function getIndex (req, res) {
20 res.render('index') 19 res.render('index')
21 } 20}
22 21
23 function getPartial (req, res) { 22function getPartial (req, res) {
24 var directory = req.params.directory 23 var directory = req.params.directory
25 var name = req.params.name 24 var name = req.params.name
26 25
27 res.render('partials/' + directory + '/' + name) 26 res.render('partials/' + directory + '/' + name)
28 } 27}
29})()
diff --git a/helpers/customValidators.js b/helpers/customValidators.js
index c433e5c5d..20c41f5da 100644
--- a/helpers/customValidators.js
+++ b/helpers/customValidators.js
@@ -1,34 +1,32 @@
1;(function () { 1'use strict'
2 'use strict'
3 2
4 var validator = require('validator') 3var validator = require('validator')
5 4
6 var customValidators = { 5var customValidators = {
7 eachIsRemoteVideosAddValid: eachIsRemoteVideosAddValid, 6 eachIsRemoteVideosAddValid: eachIsRemoteVideosAddValid,
8 eachIsRemoteVideosRemoveValid: eachIsRemoteVideosRemoveValid, 7 eachIsRemoteVideosRemoveValid: eachIsRemoteVideosRemoveValid,
9 isArray: isArray 8 isArray: isArray
10 } 9}
11 10
12 function eachIsRemoteVideosAddValid (values) { 11function eachIsRemoteVideosAddValid (values) {
13 return values.every(function (val) { 12 return values.every(function (val) {
14 return validator.isLength(val.name, 1, 50) && 13 return validator.isLength(val.name, 1, 50) &&
15 validator.isLength(val.description, 1, 50) && 14 validator.isLength(val.description, 1, 50) &&
16 validator.isLength(val.magnetUri, 10) && 15 validator.isLength(val.magnetUri, 10) &&
17 validator.isURL(val.podUrl) 16 validator.isURL(val.podUrl)
18 }) 17 })
19 } 18}
20 19
21 function eachIsRemoteVideosRemoveValid (values) { 20function eachIsRemoteVideosRemoveValid (values) {
22 return values.every(function (val) { 21 return values.every(function (val) {
23 return validator.isLength(val.magnetUri, 10) 22 return validator.isLength(val.magnetUri, 10)
24 }) 23 })
25 } 24}
26 25
27 function isArray (value) { 26function isArray (value) {
28 return Array.isArray(value) 27 return Array.isArray(value)
29 } 28}
30 29
31 // --------------------------------------------------------------------------- 30// ---------------------------------------------------------------------------
32 31
33 module.exports = customValidators 32module.exports = customValidators
34})()
diff --git a/helpers/logger.js b/helpers/logger.js
index 436091730..67f69a875 100644
--- a/helpers/logger.js
+++ b/helpers/logger.js
@@ -1,42 +1,40 @@
1;(function () { 1// Thanks http://tostring.it/2014/06/23/advanced-logging-with-nodejs/
2 // Thanks http://tostring.it/2014/06/23/advanced-logging-with-nodejs/ 2'use strict'
3 'use strict'
4 3
5 var config = require('config') 4var config = require('config')
6 var path = require('path') 5var path = require('path')
7 var winston = require('winston') 6var winston = require('winston')
8 winston.emitErrs = true 7winston.emitErrs = true
9 8
10 var logDir = path.join(__dirname, '..', config.get('storage.logs')) 9var logDir = path.join(__dirname, '..', config.get('storage.logs'))
11 var logger = new winston.Logger({ 10var logger = new winston.Logger({
12 transports: [ 11 transports: [
13 new winston.transports.File({ 12 new winston.transports.File({
14 level: 'debug', 13 level: 'debug',
15 filename: path.join(logDir, 'all-logs.log'), 14 filename: path.join(logDir, 'all-logs.log'),
16 handleExceptions: true, 15 handleExceptions: true,
17 json: true, 16 json: true,
18 maxsize: 5242880, 17 maxsize: 5242880,
19 maxFiles: 5, 18 maxFiles: 5,
20 colorize: false 19 colorize: false
21 }), 20 }),
22 new winston.transports.Console({ 21 new winston.transports.Console({
23 level: 'debug', 22 level: 'debug',
24 handleExceptions: true, 23 handleExceptions: true,
25 humanReadableUnhandledException: true, 24 humanReadableUnhandledException: true,
26 json: false, 25 json: false,
27 colorize: true 26 colorize: true
28 }) 27 })
29 ], 28 ],
30 exitOnError: true 29 exitOnError: true
31 }) 30})
32 31
33 logger.stream = { 32logger.stream = {
34 write: function (message, encoding) { 33 write: function (message, encoding) {
35 logger.info(message) 34 logger.info(message)
36 }
37 } 35 }
36}
38 37
39 // --------------------------------------------------------------------------- 38// ---------------------------------------------------------------------------
40 39
41 module.exports = logger 40module.exports = logger
42})()
diff --git a/helpers/peertubeCrypto.js b/helpers/peertubeCrypto.js
index 9031f6ae5..29b9d79c9 100644
--- a/helpers/peertubeCrypto.js
+++ b/helpers/peertubeCrypto.js
@@ -1,149 +1,147 @@
1;(function () { 1'use strict'
2 'use strict' 2
3 3var config = require('config')
4 var config = require('config') 4var crypto = require('crypto')
5 var crypto = require('crypto') 5var fs = require('fs')
6 var fs = require('fs') 6var openssl = require('openssl-wrapper')
7 var openssl = require('openssl-wrapper') 7var path = require('path')
8 var path = require('path') 8var ursa = require('ursa')
9 var ursa = require('ursa') 9
10 10var logger = require('./logger')
11 var logger = require('./logger') 11
12 12var certDir = path.join(__dirname, '..', config.get('storage.certs'))
13 var certDir = path.join(__dirname, '..', config.get('storage.certs')) 13var algorithm = 'aes-256-ctr'
14 var algorithm = 'aes-256-ctr' 14
15 15var peertubeCrypto = {
16 var peertubeCrypto = { 16 checkSignature: checkSignature,
17 checkSignature: checkSignature, 17 createCertsIfNotExist: createCertsIfNotExist,
18 createCertsIfNotExist: createCertsIfNotExist, 18 decrypt: decrypt,
19 decrypt: decrypt, 19 encrypt: encrypt,
20 encrypt: encrypt, 20 getCertDir: getCertDir,
21 getCertDir: getCertDir, 21 sign: sign
22 sign: sign 22}
23 } 23
24 24function checkSignature (public_key, raw_data, hex_signature) {
25 function checkSignature (public_key, raw_data, hex_signature) { 25 var crt = ursa.createPublicKey(public_key)
26 var crt = ursa.createPublicKey(public_key) 26 var is_valid = crt.hashAndVerify('sha256', new Buffer(raw_data).toString('hex'), hex_signature, 'hex')
27 var is_valid = crt.hashAndVerify('sha256', new Buffer(raw_data).toString('hex'), hex_signature, 'hex') 27 return is_valid
28 return is_valid 28}
29 } 29
30 30function createCertsIfNotExist (callback) {
31 function createCertsIfNotExist (callback) { 31 certsExist(function (exist) {
32 certsExist(function (exist) { 32 if (exist === true) {
33 if (exist === true) { 33 return callback(null)
34 return callback(null) 34 }
35 } 35
36 36 createCerts(function (err) {
37 createCerts(function (err) { 37 return callback(err)
38 return callback(err)
39 })
40 }) 38 })
41 } 39 })
40}
42 41
43 function decrypt (key, data, callback) { 42function decrypt (key, data, callback) {
44 fs.readFile(getCertDir() + 'peertube.key.pem', function (err, file) { 43 fs.readFile(getCertDir() + 'peertube.key.pem', function (err, file) {
45 if (err) return callback(err) 44 if (err) return callback(err)
46 45
47 var my_private_key = ursa.createPrivateKey(file) 46 var my_private_key = ursa.createPrivateKey(file)
48 var decrypted_key = my_private_key.decrypt(key, 'hex', 'utf8') 47 var decrypted_key = my_private_key.decrypt(key, 'hex', 'utf8')
49 var decrypted_data = symetricDecrypt(data, decrypted_key) 48 var decrypted_data = symetricDecrypt(data, decrypted_key)
50 49
51 return callback(null, decrypted_data) 50 return callback(null, decrypted_data)
52 }) 51 })
53 } 52}
54 53
55 function encrypt (public_key, data, callback) { 54function encrypt (public_key, data, callback) {
56 var crt = ursa.createPublicKey(public_key) 55 var crt = ursa.createPublicKey(public_key)
57 56
58 symetricEncrypt(data, function (err, dataEncrypted) { 57 symetricEncrypt(data, function (err, dataEncrypted) {
59 if (err) return callback(err) 58 if (err) return callback(err)
60 59
61 var key = crt.encrypt(dataEncrypted.password, 'utf8', 'hex') 60 var key = crt.encrypt(dataEncrypted.password, 'utf8', 'hex')
62 var encrypted = { 61 var encrypted = {
63 data: dataEncrypted.crypted, 62 data: dataEncrypted.crypted,
64 key: key 63 key: key
65 } 64 }
66 65
67 callback(null, encrypted) 66 callback(null, encrypted)
68 }) 67 })
69 } 68}
70 69
71 function getCertDir () { 70function getCertDir () {
72 return certDir 71 return certDir
73 } 72}
74 73
75 function sign (data) { 74function sign (data) {
76 var myKey = ursa.createPrivateKey(fs.readFileSync(certDir + 'peertube.key.pem')) 75 var myKey = ursa.createPrivateKey(fs.readFileSync(certDir + 'peertube.key.pem'))
77 var signature = myKey.hashAndSign('sha256', data, 'utf8', 'hex') 76 var signature = myKey.hashAndSign('sha256', data, 'utf8', 'hex')
78 77
79 return signature 78 return signature
80 } 79}
81 80
82 // --------------------------------------------------------------------------- 81// ---------------------------------------------------------------------------
83 82
84 module.exports = peertubeCrypto 83module.exports = peertubeCrypto
85 84
86 // --------------------------------------------------------------------------- 85// ---------------------------------------------------------------------------
87 86
88 function certsExist (callback) { 87function certsExist (callback) {
89 fs.exists(certDir + 'peertube.key.pem', function (exists) { 88 fs.exists(certDir + 'peertube.key.pem', function (exists) {
90 return callback(exists) 89 return callback(exists)
91 }) 90 })
92 } 91}
93 92
94 function createCerts (callback) { 93function createCerts (callback) {
95 certsExist(function (exist) { 94 certsExist(function (exist) {
96 if (exist === true) { 95 if (exist === true) {
97 var string = 'Certs already exist.' 96 var string = 'Certs already exist.'
98 logger.warning(string) 97 logger.warning(string)
99 return callback(new Error(string)) 98 return callback(new Error(string))
99 }
100
101 logger.info('Generating a RSA key...')
102 openssl.exec('genrsa', { 'out': certDir + 'peertube.key.pem', '2048': false }, function (err) {
103 if (err) {
104 logger.error('Cannot create private key on this pod.')
105 return callback(err)
100 } 106 }
107 logger.info('RSA key generated.')
101 108
102 logger.info('Generating a RSA key...') 109 logger.info('Manage public key...')
103 openssl.exec('genrsa', { 'out': certDir + 'peertube.key.pem', '2048': false }, function (err) { 110 openssl.exec('rsa', { 'in': certDir + 'peertube.key.pem', 'pubout': true, 'out': certDir + 'peertube.pub' }, function (err) {
104 if (err) { 111 if (err) {
105 logger.error('Cannot create private key on this pod.') 112 logger.error('Cannot create public key on this pod.')
106 return callback(err) 113 return callback(err)
107 } 114 }
108 logger.info('RSA key generated.')
109
110 logger.info('Manage public key...')
111 openssl.exec('rsa', { 'in': certDir + 'peertube.key.pem', 'pubout': true, 'out': certDir + 'peertube.pub' }, function (err) {
112 if (err) {
113 logger.error('Cannot create public key on this pod.')
114 return callback(err)
115 }
116
117 logger.info('Public key managed.')
118 return callback(null)
119 })
120 })
121 })
122 }
123 115
124 function generatePassword (callback) { 116 logger.info('Public key managed.')
125 crypto.randomBytes(32, function (err, buf) { 117 return callback(null)
126 if (err) return callback(err) 118 })
127
128 callback(null, buf.toString('utf8'))
129 })
130 }
131
132 function symetricDecrypt (text, password) {
133 var decipher = crypto.createDecipher(algorithm, password)
134 var dec = decipher.update(text, 'hex', 'utf8')
135 dec += decipher.final('utf8')
136 return dec
137 }
138
139 function symetricEncrypt (text, callback) {
140 generatePassword(function (err, password) {
141 if (err) return callback(err)
142
143 var cipher = crypto.createCipher(algorithm, password)
144 var crypted = cipher.update(text, 'utf8', 'hex')
145 crypted += cipher.final('hex')
146 callback(null, { crypted: crypted, password: password })
147 }) 119 })
148 } 120 })
149})() 121}
122
123function generatePassword (callback) {
124 crypto.randomBytes(32, function (err, buf) {
125 if (err) return callback(err)
126
127 callback(null, buf.toString('utf8'))
128 })
129}
130
131function symetricDecrypt (text, password) {
132 var decipher = crypto.createDecipher(algorithm, password)
133 var dec = decipher.update(text, 'hex', 'utf8')
134 dec += decipher.final('utf8')
135 return dec
136}
137
138function symetricEncrypt (text, callback) {
139 generatePassword(function (err, password) {
140 if (err) return callback(err)
141
142 var cipher = crypto.createCipher(algorithm, password)
143 var crypted = cipher.update(text, 'utf8', 'hex')
144 crypted += cipher.final('hex')
145 callback(null, { crypted: crypted, password: password })
146 })
147}
diff --git a/helpers/requests.js b/helpers/requests.js
index 0e301da79..e19afa5ca 100644
--- a/helpers/requests.js
+++ b/helpers/requests.js
@@ -1,111 +1,109 @@
1;(function () { 1'use strict'
2 'use strict'
3 2
4 var async = require('async') 3var async = require('async')
5 var config = require('config') 4var config = require('config')
6 var request = require('request') 5var request = require('request')
7 var replay = require('request-replay') 6var replay = require('request-replay')
8 7
9 var constants = require('../initializers/constants') 8var constants = require('../initializers/constants')
10 var logger = require('./logger') 9var logger = require('./logger')
11 var peertubeCrypto = require('./peertubeCrypto') 10var peertubeCrypto = require('./peertubeCrypto')
12 11
13 var http = config.get('webserver.https') ? 'https' : 'http' 12var http = config.get('webserver.https') ? 'https' : 'http'
14 var host = config.get('webserver.host') 13var host = config.get('webserver.host')
15 var port = config.get('webserver.port') 14var port = config.get('webserver.port')
16 15
17 var requests = { 16var requests = {
18 makeMultipleRetryRequest: makeMultipleRetryRequest 17 makeMultipleRetryRequest: makeMultipleRetryRequest
19 } 18}
20 19
21 function makeMultipleRetryRequest (all_data, pods, callbackEach, callback) { 20function makeMultipleRetryRequest (all_data, pods, callbackEach, callback) {
22 if (!callback) { 21 if (!callback) {
23 callback = callbackEach 22 callback = callbackEach
24 callbackEach = null 23 callbackEach = null
25 } 24 }
26 25
27 var url = http + '://' + host + ':' + port 26 var url = http + '://' + host + ':' + port
28 var signature 27 var signature
29 28
30 // Add signature if it is specified in the params 29 // Add signature if it is specified in the params
31 if (all_data.method === 'POST' && all_data.data && all_data.sign === true) { 30 if (all_data.method === 'POST' && all_data.data && all_data.sign === true) {
32 signature = peertubeCrypto.sign(url) 31 signature = peertubeCrypto.sign(url)
33 } 32 }
34 33
35 // Make a request for each pod 34 // Make a request for each pod
36 async.each(pods, function (pod, callback_each_async) { 35 async.each(pods, function (pod, callback_each_async) {
37 function callbackEachRetryRequest (err, response, body, url, pod) { 36 function callbackEachRetryRequest (err, response, body, url, pod) {
38 if (callbackEach !== null) { 37 if (callbackEach !== null) {
39 callbackEach(err, response, body, url, pod, function () { 38 callbackEach(err, response, body, url, pod, function () {
40 callback_each_async()
41 })
42 } else {
43 callback_each_async() 39 callback_each_async()
44 } 40 })
41 } else {
42 callback_each_async()
45 } 43 }
44 }
46 45
47 var params = { 46 var params = {
48 url: pod.url + all_data.path, 47 url: pod.url + all_data.path,
49 method: all_data.method 48 method: all_data.method
50 } 49 }
51 50
52 // Add data with POST requst ? 51 // Add data with POST requst ?
53 if (all_data.method === 'POST' && all_data.data) { 52 if (all_data.method === 'POST' && all_data.data) {
54 // Encrypt data ? 53 // Encrypt data ?
55 if (all_data.encrypt === true) { 54 if (all_data.encrypt === true) {
56 // TODO: ES6 with let 55 // TODO: ES6 with let
57 ;(function (copy_params, copy_url, copy_pod, copy_signature) { 56 ;(function (copy_params, copy_url, copy_pod, copy_signature) {
58 peertubeCrypto.encrypt(pod.publicKey, JSON.stringify(all_data.data), function (err, encrypted) { 57 peertubeCrypto.encrypt(pod.publicKey, JSON.stringify(all_data.data), function (err, encrypted) {
59 if (err) return callback(err) 58 if (err) return callback(err)
60 59
61 copy_params.json = { 60 copy_params.json = {
62 data: encrypted.data, 61 data: encrypted.data,
63 key: encrypted.key 62 key: encrypted.key
64 } 63 }
65 64
66 makeRetryRequest(copy_params, copy_url, copy_pod, copy_signature, callbackEachRetryRequest) 65 makeRetryRequest(copy_params, copy_url, copy_pod, copy_signature, callbackEachRetryRequest)
67 }) 66 })
68 })(params, url, pod, signature) 67 })(params, url, pod, signature)
69 } else {
70 params.json = { data: all_data.data }
71 makeRetryRequest(params, url, pod, signature, callbackEachRetryRequest)
72 }
73 } else { 68 } else {
69 params.json = { data: all_data.data }
74 makeRetryRequest(params, url, pod, signature, callbackEachRetryRequest) 70 makeRetryRequest(params, url, pod, signature, callbackEachRetryRequest)
75 } 71 }
76 }, callback) 72 } else {
77 } 73 makeRetryRequest(params, url, pod, signature, callbackEachRetryRequest)
74 }
75 }, callback)
76}
78 77
79 // --------------------------------------------------------------------------- 78// ---------------------------------------------------------------------------
80 79
81 module.exports = requests 80module.exports = requests
82 81
83 // --------------------------------------------------------------------------- 82// ---------------------------------------------------------------------------
84 83
85 function makeRetryRequest (params, from_url, to_pod, signature, callbackEach) { 84function makeRetryRequest (params, from_url, to_pod, signature, callbackEach) {
86 // Append the signature 85 // Append the signature
87 if (signature) { 86 if (signature) {
88 params.json.signature = { 87 params.json.signature = {
89 url: from_url, 88 url: from_url,
90 signature: signature 89 signature: signature
91 }
92 } 90 }
93
94 logger.debug('Make retry requests to %s.', to_pod.url)
95
96 replay(
97 request.post(params, function (err, response, body) {
98 callbackEach(err, response, body, params.url, to_pod)
99 }),
100 {
101 retries: constants.REQUEST_RETRIES,
102 factor: 3,
103 maxTimeout: Infinity,
104 errorCodes: [ 'EADDRINFO', 'ETIMEDOUT', 'ECONNRESET', 'ESOCKETTIMEDOUT', 'ENOTFOUND', 'ECONNREFUSED' ]
105 }
106 ).on('replay', function (replay) {
107 logger.info('Replaying request to %s. Request failed: %d %s. Replay number: #%d. Will retry in: %d ms.',
108 params.url, replay.error.code, replay.error.message, replay.number, replay.delay)
109 })
110 } 91 }
111})() 92
93 logger.debug('Make retry requests to %s.', to_pod.url)
94
95 replay(
96 request.post(params, function (err, response, body) {
97 callbackEach(err, response, body, params.url, to_pod)
98 }),
99 {
100 retries: constants.REQUEST_RETRIES,
101 factor: 3,
102 maxTimeout: Infinity,
103 errorCodes: [ 'EADDRINFO', 'ETIMEDOUT', 'ECONNRESET', 'ESOCKETTIMEDOUT', 'ENOTFOUND', 'ECONNREFUSED' ]
104 }
105 ).on('replay', function (replay) {
106 logger.info('Replaying request to %s. Request failed: %d %s. Replay number: #%d. Will retry in: %d ms.',
107 params.url, replay.error.code, replay.error.message, replay.number, replay.delay)
108 })
109}
diff --git a/helpers/utils.js b/helpers/utils.js
index 92684ea81..d2c9ad8b2 100644
--- a/helpers/utils.js
+++ b/helpers/utils.js
@@ -1,18 +1,16 @@
1;(function () { 1'use strict'
2 'use strict'
3 2
4 var logger = require('./logger') 3var logger = require('./logger')
5 4
6 var utils = { 5var utils = {
7 cleanForExit: cleanForExit 6 cleanForExit: cleanForExit
8 } 7}
9 8
10 function cleanForExit (webtorrent_process) { 9function cleanForExit (webtorrent_process) {
11 logger.info('Gracefully exiting.') 10 logger.info('Gracefully exiting.')
12 process.kill(-webtorrent_process.pid) 11 process.kill(-webtorrent_process.pid)
13 } 12}
14 13
15 // --------------------------------------------------------------------------- 14// ---------------------------------------------------------------------------
16 15
17 module.exports = utils 16module.exports = utils
18})()
diff --git a/initializers/checker.js b/initializers/checker.js
index f4458c5cf..9a7d04ed4 100644
--- a/initializers/checker.js
+++ b/initializers/checker.js
@@ -1,50 +1,48 @@
1;(function () { 1'use strict'
2 'use strict' 2
3 3var config = require('config')
4 var config = require('config') 4var mkdirp = require('mkdirp')
5 var mkdirp = require('mkdirp') 5var path = require('path')
6 var path = require('path') 6
7 7var checker = {
8 var checker = { 8 checkConfig: checkConfig,
9 checkConfig: checkConfig, 9 createDirectoriesIfNotExist: createDirectoriesIfNotExist
10 createDirectoriesIfNotExist: createDirectoriesIfNotExist 10}
11 } 11
12 12// Check the config files
13 // Check the config files 13function checkConfig () {
14 function checkConfig () { 14 var required = [ 'listen.port',
15 var required = [ 'listen.port', 15 'webserver.https', 'webserver.host', 'webserver.port',
16 'webserver.https', 'webserver.host', 'webserver.port', 16 'database.host', 'database.port', 'database.suffix',
17 'database.host', 'database.port', 'database.suffix', 17 'storage.certs', 'storage.uploads', 'storage.logs',
18 'storage.certs', 'storage.uploads', 'storage.logs', 18 'network.friends' ]
19 'network.friends' ] 19 var miss = []
20 var miss = [] 20
21 21 for (var key of required) {
22 for (var key of required) { 22 if (!config.has(key)) {
23 if (!config.has(key)) { 23 miss.push(key)
24 miss.push(key)
25 }
26 } 24 }
27
28 return miss
29 } 25 }
30 26
31 // Create directories for the storage if it doesn't exist 27 return miss
32 function createDirectoriesIfNotExist () { 28}
33 var storages = config.get('storage') 29
34 30// Create directories for the storage if it doesn't exist
35 for (var key of Object.keys(storages)) { 31function createDirectoriesIfNotExist () {
36 var dir = storages[key] 32 var storages = config.get('storage')
37 try { 33
38 mkdirp.sync(path.join(__dirname, '..', dir)) 34 for (var key of Object.keys(storages)) {
39 } catch (error) { 35 var dir = storages[key]
40 // Do not use logger 36 try {
41 console.error('Cannot create ' + path + ':' + error) 37 mkdirp.sync(path.join(__dirname, '..', dir))
42 process.exit(0) 38 } catch (error) {
43 } 39 // Do not use logger
40 console.error('Cannot create ' + path + ':' + error)
41 process.exit(0)
44 } 42 }
45 } 43 }
44}
46 45
47 // --------------------------------------------------------------------------- 46// ---------------------------------------------------------------------------
48 47
49 module.exports = checker 48module.exports = checker
50})()
diff --git a/initializers/constants.js b/initializers/constants.js
index 1e101a747..16e50443b 100644
--- a/initializers/constants.js
+++ b/initializers/constants.js
@@ -1,44 +1,42 @@
1;(function () { 1'use strict'
2 'use strict' 2
3 3// API version of our pod
4 // API version of our pod 4var API_VERSION = 'v1'
5 var API_VERSION = 'v1' 5
6 6// Score a pod has when we create it as a friend
7 // Score a pod has when we create it as a friend 7var FRIEND_BASE_SCORE = 100
8 var FRIEND_BASE_SCORE = 100 8
9 9// Time to wait between requests to the friends
10 // Time to wait between requests to the friends 10var INTERVAL = 60000
11 var INTERVAL = 60000 11
12 12// Number of points we add/remove from a friend after a successful/bad request
13 // Number of points we add/remove from a friend after a successful/bad request 13var PODS_SCORE = {
14 var PODS_SCORE = { 14 MALUS: -10,
15 MALUS: -10, 15 BONUS: 10
16 BONUS: 10 16}
17 } 17
18 18// Number of retries we make for the make retry requests (to friends...)
19 // Number of retries we make for the make retry requests (to friends...) 19var REQUEST_RETRIES = 10
20 var REQUEST_RETRIES = 10 20
21 21// Special constants for a test instance
22 // Special constants for a test instance 22if (isTestInstance() === true) {
23 if (isTestInstance() === true) { 23 FRIEND_BASE_SCORE = 20
24 FRIEND_BASE_SCORE = 20 24 INTERVAL = 10000
25 INTERVAL = 10000 25 REQUEST_RETRIES = 2
26 REQUEST_RETRIES = 2 26}
27 } 27
28 28// ---------------------------------------------------------------------------
29 // --------------------------------------------------------------------------- 29
30 30module.exports = {
31 module.exports = { 31 API_VERSION: API_VERSION,
32 API_VERSION: API_VERSION, 32 FRIEND_BASE_SCORE: FRIEND_BASE_SCORE,
33 FRIEND_BASE_SCORE: FRIEND_BASE_SCORE, 33 INTERVAL: INTERVAL,
34 INTERVAL: INTERVAL, 34 PODS_SCORE: PODS_SCORE,
35 PODS_SCORE: PODS_SCORE, 35 REQUEST_RETRIES: REQUEST_RETRIES
36 REQUEST_RETRIES: REQUEST_RETRIES 36}
37 } 37
38 38// ---------------------------------------------------------------------------
39 // --------------------------------------------------------------------------- 39
40 40function isTestInstance () {
41 function isTestInstance () { 41 return (process.env.NODE_ENV === 'test')
42 return (process.env.NODE_ENV === 'test') 42}
43 }
44})()
diff --git a/initializers/database.js b/initializers/database.js
index 96c172637..6e3f11df3 100644
--- a/initializers/database.js
+++ b/initializers/database.js
@@ -1,32 +1,30 @@
1;(function () { 1'use strict'
2 'use strict'
3 2
4 var config = require('config') 3var config = require('config')
5 var mongoose = require('mongoose') 4var mongoose = require('mongoose')
6 5
7 var logger = require('../helpers/logger') 6var logger = require('../helpers/logger')
8 7
9 var dbname = 'peertube' + config.get('database.suffix') 8var dbname = 'peertube' + config.get('database.suffix')
10 var host = config.get('database.host') 9var host = config.get('database.host')
11 var port = config.get('database.port') 10var port = config.get('database.port')
12 11
13 var database = { 12var database = {
14 connect: connect 13 connect: connect
15 } 14}
16 15
17 function connect () { 16function connect () {
18 mongoose.connect('mongodb://' + host + ':' + port + '/' + dbname) 17 mongoose.connect('mongodb://' + host + ':' + port + '/' + dbname)
19 mongoose.connection.on('error', function () { 18 mongoose.connection.on('error', function () {
20 logger.error('Mongodb connection error.') 19 logger.error('Mongodb connection error.')
21 process.exit(0) 20 process.exit(0)
22 }) 21 })
23 22
24 mongoose.connection.on('open', function () { 23 mongoose.connection.on('open', function () {
25 logger.info('Connected to mongodb.') 24 logger.info('Connected to mongodb.')
26 }) 25 })
27 } 26}
28 27
29 // --------------------------------------------------------------------------- 28// ---------------------------------------------------------------------------
30 29
31 module.exports = database 30module.exports = database
32})()
diff --git a/lib/friends.js b/lib/friends.js
index c05ccedb1..8cc1a3151 100644
--- a/lib/friends.js
+++ b/lib/friends.js
@@ -1,224 +1,222 @@
1;(function () { 1'use strict'
2 'use strict' 2
3 3var async = require('async')
4 var async = require('async') 4var config = require('config')
5 var config = require('config') 5var fs = require('fs')
6 var fs = require('fs') 6var request = require('request')
7 var request = require('request') 7
8 8var constants = require('../initializers/constants')
9 var constants = require('../initializers/constants') 9var logger = require('../helpers/logger')
10 var logger = require('../helpers/logger') 10var peertubeCrypto = require('../helpers/peertubeCrypto')
11 var peertubeCrypto = require('../helpers/peertubeCrypto') 11var Pods = require('../models/pods')
12 var Pods = require('../models/pods') 12var poolRequests = require('../lib/poolRequests')
13 var poolRequests = require('../lib/poolRequests') 13var requests = require('../helpers/requests')
14 var requests = require('../helpers/requests') 14var Videos = require('../models/videos')
15 var Videos = require('../models/videos') 15
16 16var http = config.get('webserver.https') ? 'https' : 'http'
17 var http = config.get('webserver.https') ? 'https' : 'http' 17var host = config.get('webserver.host')
18 var host = config.get('webserver.host') 18var port = config.get('webserver.port')
19 var port = config.get('webserver.port') 19
20 20var pods = {
21 var pods = { 21 addVideoToFriends: addVideoToFriends,
22 addVideoToFriends: addVideoToFriends, 22 hasFriends: hasFriends,
23 hasFriends: hasFriends, 23 makeFriends: makeFriends,
24 makeFriends: makeFriends, 24 quitFriends: quitFriends,
25 quitFriends: quitFriends, 25 removeVideoToFriends: removeVideoToFriends
26 removeVideoToFriends: removeVideoToFriends 26}
27 } 27
28function addVideoToFriends (video) {
29 // To avoid duplicates
30 var id = video.name + video.magnetUri
31 // ensure namePath is null
32 video.namePath = null
33 poolRequests.addRequest(id, 'add', video)
34}
35
36function hasFriends (callback) {
37 Pods.count(function (err, count) {
38 if (err) return callback(err)
39
40 var has_friends = (count !== 0)
41 callback(null, has_friends)
42 })
43}
44
45function makeFriends (callback) {
46 var pods_score = {}
47
48 logger.info('Make friends!')
49 fs.readFile(peertubeCrypto.getCertDir() + 'peertube.pub', 'utf8', function (err, cert) {
50 if (err) {
51 logger.error('Cannot read public cert.')
52 return callback(err)
53 }
28 54
29 function addVideoToFriends (video) { 55 var urls = config.get('network.friends')
30 // To avoid duplicates
31 var id = video.name + video.magnetUri
32 // ensure namePath is null
33 video.namePath = null
34 poolRequests.addRequest(id, 'add', video)
35 }
36 56
37 function hasFriends (callback) { 57 async.each(urls, computeForeignPodsList, function (err) {
38 Pods.count(function (err, count) {
39 if (err) return callback(err) 58 if (err) return callback(err)
40 59
41 var has_friends = (count !== 0) 60 logger.debug('Pods scores computed.', { pods_score: pods_score })
42 callback(null, has_friends) 61 var pods_list = computeWinningPods(urls, pods_score)
62 logger.debug('Pods that we keep computed.', { pods_to_keep: pods_list })
63
64 makeRequestsToWinningPods(cert, pods_list)
43 }) 65 })
44 } 66 })
45 67
46 function makeFriends (callback) { 68 // -----------------------------------------------------------------------
47 var pods_score = {}
48 69
49 logger.info('Make friends!') 70 function computeForeignPodsList (url, callback) {
50 fs.readFile(peertubeCrypto.getCertDir() + 'peertube.pub', 'utf8', function (err, cert) { 71 // Let's give 1 point to the pod we ask the friends list
51 if (err) { 72 pods_score[url] = 1
52 logger.error('Cannot read public cert.')
53 return callback(err)
54 }
55 73
56 var urls = config.get('network.friends') 74 getForeignPodsList(url, function (err, foreign_pods_list) {
75 if (err) return callback(err)
76 if (foreign_pods_list.length === 0) return callback()
57 77
58 async.each(urls, computeForeignPodsList, function (err) { 78 async.each(foreign_pods_list, function (foreign_pod, callback_each) {
59 if (err) return callback(err) 79 var foreign_url = foreign_pod.url
60 80
61 logger.debug('Pods scores computed.', { pods_score: pods_score }) 81 if (pods_score[foreign_url]) pods_score[foreign_url]++
62 var pods_list = computeWinningPods(urls, pods_score) 82 else pods_score[foreign_url] = 1
63 logger.debug('Pods that we keep computed.', { pods_to_keep: pods_list })
64 83
65 makeRequestsToWinningPods(cert, pods_list) 84 callback_each()
85 }, function () {
86 callback()
66 }) 87 })
67 }) 88 })
89 }
68 90
69 // ----------------------------------------------------------------------- 91 function computeWinningPods (urls, pods_score) {
70 92 // Build the list of pods to add
71 function computeForeignPodsList (url, callback) { 93 // Only add a pod if it exists in more than a half base pods
72 // Let's give 1 point to the pod we ask the friends list 94 var pods_list = []
73 pods_score[url] = 1 95 var base_score = urls.length / 2
74 96 Object.keys(pods_score).forEach(function (pod) {
75 getForeignPodsList(url, function (err, foreign_pods_list) { 97 if (pods_score[pod] > base_score) pods_list.push({ url: pod })
76 if (err) return callback(err) 98 })
77 if (foreign_pods_list.length === 0) return callback()
78
79 async.each(foreign_pods_list, function (foreign_pod, callback_each) {
80 var foreign_url = foreign_pod.url
81
82 if (pods_score[foreign_url]) pods_score[foreign_url]++
83 else pods_score[foreign_url] = 1
84
85 callback_each()
86 }, function () {
87 callback()
88 })
89 })
90 }
91 99
92 function computeWinningPods (urls, pods_score) { 100 return pods_list
93 // Build the list of pods to add 101 }
94 // Only add a pod if it exists in more than a half base pods
95 var pods_list = []
96 var base_score = urls.length / 2
97 Object.keys(pods_score).forEach(function (pod) {
98 if (pods_score[pod] > base_score) pods_list.push({ url: pod })
99 })
100 102
101 return pods_list 103 function makeRequestsToWinningPods (cert, pods_list) {
102 } 104 // Stop pool requests
105 poolRequests.deactivate()
106 // Flush pool requests
107 poolRequests.forceSend()
103 108
104 function makeRequestsToWinningPods (cert, pods_list) { 109 // Get the list of our videos to send to our new friends
105 // Stop pool requests 110 Videos.listOwned(function (err, videos_list) {
106 poolRequests.deactivate() 111 if (err) {
107 // Flush pool requests 112 logger.error('Cannot get the list of videos we own.')
108 poolRequests.forceSend() 113 return callback(err)
109 114 }
110 // Get the list of our videos to send to our new friends
111 Videos.listOwned(function (err, videos_list) {
112 if (err) {
113 logger.error('Cannot get the list of videos we own.')
114 return callback(err)
115 }
116 115
117 var data = { 116 var data = {
118 url: http + '://' + host + ':' + port, 117 url: http + '://' + host + ':' + port,
119 publicKey: cert, 118 publicKey: cert,
120 videos: videos_list 119 videos: videos_list
121 } 120 }
122 121
123 requests.makeMultipleRetryRequest( 122 requests.makeMultipleRetryRequest(
124 { method: 'POST', path: '/api/' + constants.API_VERSION + '/pods/', data: data }, 123 { method: 'POST', path: '/api/' + constants.API_VERSION + '/pods/', data: data },
125 124
126 pods_list, 125 pods_list,
127 126
128 function eachRequest (err, response, body, url, pod, callback_each_request) { 127 function eachRequest (err, response, body, url, pod, callback_each_request) {
129 // We add the pod if it responded correctly with its public certificate 128 // We add the pod if it responded correctly with its public certificate
130 if (!err && response.statusCode === 200) { 129 if (!err && response.statusCode === 200) {
131 Pods.add({ url: pod.url, publicKey: body.cert, score: constants.FRIEND_BASE_SCORE }, function (err) { 130 Pods.add({ url: pod.url, publicKey: body.cert, score: constants.FRIEND_BASE_SCORE }, function (err) {
132 if (err) logger.error('Error with adding %s pod.', pod.url, { error: err }) 131 if (err) logger.error('Error with adding %s pod.', pod.url, { error: err })
133 132
134 Videos.addRemotes(body.videos, function (err) { 133 Videos.addRemotes(body.videos, function (err) {
135 if (err) logger.error('Error with adding videos of pod.', pod.url, { error: err }) 134 if (err) logger.error('Error with adding videos of pod.', pod.url, { error: err })
136 135
137 logger.debug('Adding remote videos from %s.', pod.url, { videos: body.videos }) 136 logger.debug('Adding remote videos from %s.', pod.url, { videos: body.videos })
138 return callback_each_request() 137 return callback_each_request()
139 })
140 }) 138 })
141 } else { 139 })
142 logger.error('Error with adding %s pod.', pod.url, { error: err || new Error('Status not 200') }) 140 } else {
143 return callback_each_request() 141 logger.error('Error with adding %s pod.', pod.url, { error: err || new Error('Status not 200') })
144 } 142 return callback_each_request()
145 },
146
147 function endRequests (err) {
148 // Now we made new friends, we can re activate the pool of requests
149 poolRequests.activate()
150
151 if (err) {
152 logger.error('There was some errors when we wanted to make friends.')
153 return callback(err)
154 }
155
156 logger.debug('makeRequestsToWinningPods finished.')
157 return callback(null)
158 } 143 }
159 ) 144 },
160 })
161 }
162 }
163 145
164 function quitFriends (callback) { 146 function endRequests (err) {
165 // Stop pool requests 147 // Now we made new friends, we can re activate the pool of requests
166 poolRequests.deactivate() 148 poolRequests.activate()
167 // Flush pool requests
168 poolRequests.forceSend()
169 149
170 Pods.list(function (err, pods) { 150 if (err) {
171 if (err) return callback(err) 151 logger.error('There was some errors when we wanted to make friends.')
152 return callback(err)
153 }
172 154
173 var request = { 155 logger.debug('makeRequestsToWinningPods finished.')
174 method: 'POST', 156 return callback(null)
175 path: '/api/' + constants.API_VERSION + '/pods/remove',
176 sign: true,
177 encrypt: true,
178 data: {
179 url: 'me' // Fake data
180 } 157 }
158 )
159 })
160 }
161}
162
163function quitFriends (callback) {
164 // Stop pool requests
165 poolRequests.deactivate()
166 // Flush pool requests
167 poolRequests.forceSend()
168
169 Pods.list(function (err, pods) {
170 if (err) return callback(err)
171
172 var request = {
173 method: 'POST',
174 path: '/api/' + constants.API_VERSION + '/pods/remove',
175 sign: true,
176 encrypt: true,
177 data: {
178 url: 'me' // Fake data
181 } 179 }
180 }
182 181
183 // Announce we quit them 182 // Announce we quit them
184 requests.makeMultipleRetryRequest(request, pods, function () { 183 requests.makeMultipleRetryRequest(request, pods, function () {
185 Pods.removeAll(function (err) { 184 Pods.removeAll(function (err) {
186 poolRequests.activate() 185 poolRequests.activate()
187 186
188 if (err) return callback(err) 187 if (err) return callback(err)
189 188
190 logger.info('Broke friends, so sad :(') 189 logger.info('Broke friends, so sad :(')
191 190
192 Videos.removeAllRemotes(function (err) { 191 Videos.removeAllRemotes(function (err) {
193 if (err) return callback(err) 192 if (err) return callback(err)
194 193
195 logger.info('Removed all remote videos.') 194 logger.info('Removed all remote videos.')
196 callback(null) 195 callback(null)
197 })
198 }) 196 })
199 }) 197 })
200 }) 198 })
201 } 199 })
200}
202 201
203 function removeVideoToFriends (video) { 202function removeVideoToFriends (video) {
204 // To avoid duplicates 203 // To avoid duplicates
205 var id = video.name + video.magnetUri 204 var id = video.name + video.magnetUri
206 poolRequests.addRequest(id, 'remove', video) 205 poolRequests.addRequest(id, 'remove', video)
207 } 206}
208 207
209 // --------------------------------------------------------------------------- 208// ---------------------------------------------------------------------------
210 209
211 module.exports = pods 210module.exports = pods
212 211
213 // --------------------------------------------------------------------------- 212// ---------------------------------------------------------------------------
214 213
215 function getForeignPodsList (url, callback) { 214function getForeignPodsList (url, callback) {
216 var path = '/api/' + constants.API_VERSION + '/pods' 215 var path = '/api/' + constants.API_VERSION + '/pods'
217 216
218 request.get(url + path, function (err, response, body) { 217 request.get(url + path, function (err, response, body) {
219 if (err) return callback(err) 218 if (err) return callback(err)
220 219
221 callback(null, JSON.parse(body)) 220 callback(null, JSON.parse(body))
222 }) 221 })
223 } 222}
224})()
diff --git a/lib/poolRequests.js b/lib/poolRequests.js
index 9ea41f383..f786c3c7a 100644
--- a/lib/poolRequests.js
+++ b/lib/poolRequests.js
@@ -1,223 +1,221 @@
1;(function () { 1'use strict'
2 'use strict' 2
3 3var async = require('async')
4 var async = require('async') 4var pluck = require('lodash-node/compat/collection/pluck')
5 var pluck = require('lodash-node/compat/collection/pluck') 5
6 6var constants = require('../initializers/constants')
7 var constants = require('../initializers/constants') 7var logger = require('../helpers/logger')
8 var logger = require('../helpers/logger') 8var Pods = require('../models/pods')
9 var Pods = require('../models/pods') 9var PoolRequests = require('../models/poolRequests')
10 var PoolRequests = require('../models/poolRequests') 10var requests = require('../helpers/requests')
11 var requests = require('../helpers/requests') 11var Videos = require('../models/videos')
12 var Videos = require('../models/videos') 12
13 13var timer = null
14 var timer = null 14
15 15var poolRequests = {
16 var poolRequests = { 16 activate: activate,
17 activate: activate, 17 addRequest: addRequest,
18 addRequest: addRequest, 18 deactivate: deactivate,
19 deactivate: deactivate, 19 forceSend: forceSend
20 forceSend: forceSend 20}
21 } 21
22 22function activate () {
23 function activate () { 23 logger.info('Pool requests activated.')
24 logger.info('Pool requests activated.') 24 timer = setInterval(makePoolRequests, constants.INTERVAL)
25 timer = setInterval(makePoolRequests, constants.INTERVAL) 25}
26 } 26
27 27function addRequest (id, type, request) {
28 function addRequest (id, type, request) { 28 logger.debug('Add request to the pool requests.', { id: id, type: type, request: request })
29 logger.debug('Add request to the pool requests.', { id: id, type: type, request: request }) 29
30 30 PoolRequests.findById(id, function (err, entity) {
31 PoolRequests.findById(id, function (err, entity) { 31 if (err) {
32 if (err) { 32 logger.error('Cannot find one pool request.', { error: err })
33 logger.error('Cannot find one pool request.', { error: err }) 33 return // Abort
34 }
35
36 if (entity) {
37 if (entity.type === type) {
38 logger.error('Cannot insert two same requests.')
34 return // Abort 39 return // Abort
35 } 40 }
36 41
37 if (entity) { 42 // Remove the request of the other type
38 if (entity.type === type) { 43 PoolRequests.removeRequestById(id, function (err) {
39 logger.error('Cannot insert two same requests.') 44 if (err) {
45 logger.error('Cannot remove a pool request.', { error: err })
40 return // Abort 46 return // Abort
41 } 47 }
48 })
49 } else {
50 PoolRequests.create(id, type, request, function (err) {
51 if (err) logger.error('Cannot create a pool request.', { error: err })
52 return // Abort
53 })
54 }
55 })
56}
42 57
43 // Remove the request of the other type 58function deactivate () {
44 PoolRequests.removeRequestById(id, function (err) { 59 logger.info('Pool requests deactivated.')
45 if (err) { 60 clearInterval(timer)
46 logger.error('Cannot remove a pool request.', { error: err }) 61}
47 return // Abort
48 }
49 })
50 } else {
51 PoolRequests.create(id, type, request, function (err) {
52 if (err) logger.error('Cannot create a pool request.', { error: err })
53 return // Abort
54 })
55 }
56 })
57 }
58 62
59 function deactivate () { 63function forceSend () {
60 logger.info('Pool requests deactivated.') 64 logger.info('Force pool requests sending.')
61 clearInterval(timer) 65 makePoolRequests()
62 } 66}
63 67
64 function forceSend () { 68// ---------------------------------------------------------------------------
65 logger.info('Force pool requests sending.')
66 makePoolRequests()
67 }
68 69
69 // --------------------------------------------------------------------------- 70module.exports = poolRequests
70 71
71 module.exports = poolRequests 72// ---------------------------------------------------------------------------
72 73
73 // --------------------------------------------------------------------------- 74function makePoolRequest (type, requests_to_make, callback) {
75 if (!callback) callback = function () {}
74 76
75 function makePoolRequest (type, requests_to_make, callback) { 77 Pods.list(function (err, pods) {
76 if (!callback) callback = function () {} 78 if (err) return callback(err)
77 79
78 Pods.list(function (err, pods) { 80 var params = {
79 if (err) return callback(err) 81 encrypt: true,
82 sign: true,
83 method: 'POST',
84 path: null,
85 data: requests_to_make
86 }
80 87
81 var params = { 88 if (type === 'add') {
82 encrypt: true, 89 params.path = '/api/' + constants.API_VERSION + '/remotevideos/add'
83 sign: true, 90 } else if (type === 'remove') {
84 method: 'POST', 91 params.path = '/api/' + constants.API_VERSION + '/remotevideos/remove'
85 path: null, 92 } else {
86 data: requests_to_make 93 return callback(new Error('Unkown pool request type.'))
87 } 94 }
95
96 var bad_pods = []
97 var good_pods = []
88 98
89 if (type === 'add') { 99 requests.makeMultipleRetryRequest(params, pods, callbackEachPodFinished, callbackAllPodsFinished)
90 params.path = '/api/' + constants.API_VERSION + '/remotevideos/add' 100
91 } else if (type === 'remove') { 101 function callbackEachPodFinished (err, response, body, url, pod, callback_each_pod_finished) {
92 params.path = '/api/' + constants.API_VERSION + '/remotevideos/remove' 102 if (err || (response.statusCode !== 200 && response.statusCode !== 204)) {
103 bad_pods.push(pod._id)
104 logger.error('Error sending secure request to %s pod.', url, { error: err || new Error('Status code not 20x') })
93 } else { 105 } else {
94 return callback(new Error('Unkown pool request type.')) 106 good_pods.push(pod._id)
95 } 107 }
96 108
97 var bad_pods = [] 109 return callback_each_pod_finished()
98 var good_pods = [] 110 }
99
100 requests.makeMultipleRetryRequest(params, pods, callbackEachPodFinished, callbackAllPodsFinished)
101 111
102 function callbackEachPodFinished (err, response, body, url, pod, callback_each_pod_finished) { 112 function callbackAllPodsFinished (err) {
103 if (err || (response.statusCode !== 200 && response.statusCode !== 204)) { 113 if (err) return callback(err)
104 bad_pods.push(pod._id)
105 logger.error('Error sending secure request to %s pod.', url, { error: err || new Error('Status code not 20x') })
106 } else {
107 good_pods.push(pod._id)
108 }
109 114
110 return callback_each_pod_finished() 115 updatePodsScore(good_pods, bad_pods)
116 callback(null)
117 }
118 })
119}
120
121function makePoolRequests () {
122 logger.info('Making pool requests to friends.')
123
124 PoolRequests.list(function (err, pool_requests) {
125 if (err) {
126 logger.error('Cannot get the list of pool requests.', { err: err })
127 return // Abort
128 }
129
130 if (pool_requests.length === 0) return
131
132 var requests_to_make = {
133 add: {
134 ids: [],
135 requests: []
136 },
137 remove: {
138 ids: [],
139 requests: []
111 } 140 }
112 141 }
113 function callbackAllPodsFinished (err) { 142
114 if (err) return callback(err) 143 async.each(pool_requests, function (pool_request, callback_each) {
115 144 if (pool_request.type === 'add') {
116 updatePodsScore(good_pods, bad_pods) 145 requests_to_make.add.requests.push(pool_request.request)
117 callback(null) 146 requests_to_make.add.ids.push(pool_request._id)
147 } else if (pool_request.type === 'remove') {
148 requests_to_make.remove.requests.push(pool_request.request)
149 requests_to_make.remove.ids.push(pool_request._id)
150 } else {
151 logger.error('Unkown pool request type.', { request_type: pool_request.type })
152 return // abort
118 } 153 }
119 })
120 }
121 154
122 function makePoolRequests () { 155 callback_each()
123 logger.info('Making pool requests to friends.') 156 }, function () {
157 // Send the add requests
158 if (requests_to_make.add.requests.length !== 0) {
159 makePoolRequest('add', requests_to_make.add.requests, function (err) {
160 if (err) logger.error('Errors when sent add pool requests.', { error: err })
124 161
125 PoolRequests.list(function (err, pool_requests) { 162 PoolRequests.removeRequests(requests_to_make.add.ids)
126 if (err) { 163 })
127 logger.error('Cannot get the list of pool requests.', { err: err })
128 return // Abort
129 } 164 }
130 165
131 if (pool_requests.length === 0) return 166 // Send the remove requests
167 if (requests_to_make.remove.requests.length !== 0) {
168 makePoolRequest('remove', requests_to_make.remove.requests, function (err) {
169 if (err) logger.error('Errors when sent remove pool requests.', { error: err })
132 170
133 var requests_to_make = { 171 PoolRequests.removeRequests(requests_to_make.remove.ids)
134 add: { 172 })
135 ids: [],
136 requests: []
137 },
138 remove: {
139 ids: [],
140 requests: []
141 }
142 } 173 }
174 })
175 })
176}
143 177
144 async.each(pool_requests, function (pool_request, callback_each) { 178function removeBadPods () {
145 if (pool_request.type === 'add') { 179 Pods.findBadPods(function (err, pods) {
146 requests_to_make.add.requests.push(pool_request.request) 180 if (err) {
147 requests_to_make.add.ids.push(pool_request._id) 181 logger.error('Cannot find bad pods.', { error: err })
148 } else if (pool_request.type === 'remove') { 182 return // abort
149 requests_to_make.remove.requests.push(pool_request.request) 183 }
150 requests_to_make.remove.ids.push(pool_request._id)
151 } else {
152 logger.error('Unkown pool request type.', { request_type: pool_request.type })
153 return // abort
154 }
155
156 callback_each()
157 }, function () {
158 // Send the add requests
159 if (requests_to_make.add.requests.length !== 0) {
160 makePoolRequest('add', requests_to_make.add.requests, function (err) {
161 if (err) logger.error('Errors when sent add pool requests.', { error: err })
162
163 PoolRequests.removeRequests(requests_to_make.add.ids)
164 })
165 }
166 184
167 // Send the remove requests 185 if (pods.length === 0) return
168 if (requests_to_make.remove.requests.length !== 0) {
169 makePoolRequest('remove', requests_to_make.remove.requests, function (err) {
170 if (err) logger.error('Errors when sent remove pool requests.', { error: err })
171 186
172 PoolRequests.removeRequests(requests_to_make.remove.ids) 187 var urls = pluck(pods, 'url')
173 }) 188 var ids = pluck(pods, '_id')
174 }
175 })
176 })
177 }
178 189
179 function removeBadPods () { 190 Videos.removeAllRemotesOf(urls, function (err, r) {
180 Pods.findBadPods(function (err, pods) {
181 if (err) { 191 if (err) {
182 logger.error('Cannot find bad pods.', { error: err }) 192 logger.error('Cannot remove videos from a pod that we removing.', { error: err })
183 return // abort 193 } else {
194 var videos_removed = r.result.n
195 logger.info('Removed %d videos.', videos_removed)
184 } 196 }
185 197
186 if (pods.length === 0) return 198 Pods.removeAllByIds(ids, function (err, r) {
187
188 var urls = pluck(pods, 'url')
189 var ids = pluck(pods, '_id')
190
191 Videos.removeAllRemotesOf(urls, function (err, r) {
192 if (err) { 199 if (err) {
193 logger.error('Cannot remove videos from a pod that we removing.', { error: err }) 200 logger.error('Cannot remove bad pods.', { error: err })
194 } else { 201 } else {
195 var videos_removed = r.result.n 202 var pods_removed = r.result.n
196 logger.info('Removed %d videos.', videos_removed) 203 logger.info('Removed %d pods.', pods_removed)
197 } 204 }
198
199 Pods.removeAllByIds(ids, function (err, r) {
200 if (err) {
201 logger.error('Cannot remove bad pods.', { error: err })
202 } else {
203 var pods_removed = r.result.n
204 logger.info('Removed %d pods.', pods_removed)
205 }
206 })
207 }) 205 })
208 }) 206 })
209 } 207 })
208}
210 209
211 function updatePodsScore (good_pods, bad_pods) { 210function updatePodsScore (good_pods, bad_pods) {
212 logger.info('Updating %d good pods and %d bad pods scores.', good_pods.length, bad_pods.length) 211 logger.info('Updating %d good pods and %d bad pods scores.', good_pods.length, bad_pods.length)
213 212
214 Pods.incrementScores(good_pods, constants.PODS_SCORE.BONUS, function (err) { 213 Pods.incrementScores(good_pods, constants.PODS_SCORE.BONUS, function (err) {
215 if (err) logger.error('Cannot increment scores of good pods.') 214 if (err) logger.error('Cannot increment scores of good pods.')
216 }) 215 })
217 216
218 Pods.incrementScores(bad_pods, constants.PODS_SCORE.MALUS, function (err) { 217 Pods.incrementScores(bad_pods, constants.PODS_SCORE.MALUS, function (err) {
219 if (err) logger.error('Cannot increment scores of bad pods.') 218 if (err) logger.error('Cannot increment scores of bad pods.')
220 removeBadPods() 219 removeBadPods()
221 }) 220 })
222 } 221}
223})()
diff --git a/lib/videos.js b/lib/videos.js
index 0e8143351..2d7d9500d 100644
--- a/lib/videos.js
+++ b/lib/videos.js
@@ -1,52 +1,50 @@
1;(function () { 1'use strict'
2 'use strict' 2
3 3var async = require('async')
4 var async = require('async') 4var config = require('config')
5 var config = require('config') 5var path = require('path')
6 var path = require('path') 6var webtorrent = require('../lib/webtorrent')
7 var webtorrent = require('../lib/webtorrent') 7
8 8var logger = require('../helpers/logger')
9 var logger = require('../helpers/logger') 9var Videos = require('../models/videos')
10 var Videos = require('../models/videos') 10
11 11var uploadDir = path.join(__dirname, '..', config.get('storage.uploads'))
12 var uploadDir = path.join(__dirname, '..', config.get('storage.uploads')) 12
13 13var videos = {
14 var videos = { 14 seed: seed,
15 seed: seed, 15 seedAllExisting: seedAllExisting
16 seedAllExisting: seedAllExisting 16}
17 } 17
18 18function seed (path, callback) {
19 function seed (path, callback) { 19 logger.info('Seeding %s...', path)
20 logger.info('Seeding %s...', path) 20
21 21 webtorrent.seed(path, function (torrent) {
22 webtorrent.seed(path, function (torrent) { 22 logger.info('%s seeded (%s).', path, torrent.magnetURI)
23 logger.info('%s seeded (%s).', path, torrent.magnetURI) 23
24 24 return callback(null, torrent)
25 return callback(null, torrent) 25 })
26 }) 26}
27 } 27
28 28function seedAllExisting (callback) {
29 function seedAllExisting (callback) { 29 Videos.listOwned(function (err, videos_list) {
30 Videos.listOwned(function (err, videos_list) { 30 if (err) {
31 if (err) { 31 logger.error('Cannot get list of the videos to seed.')
32 logger.error('Cannot get list of the videos to seed.') 32 return callback(err)
33 return callback(err) 33 }
34 } 34
35 35 async.each(videos_list, function (video, each_callback) {
36 async.each(videos_list, function (video, each_callback) { 36 seed(uploadDir + video.namePath, function (err) {
37 seed(uploadDir + video.namePath, function (err) { 37 if (err) {
38 if (err) { 38 logger.error('Cannot seed this video.')
39 logger.error('Cannot seed this video.') 39 return callback(err)
40 return callback(err) 40 }
41 } 41
42 42 each_callback(null)
43 each_callback(null) 43 })
44 }) 44 }, callback)
45 }, callback) 45 })
46 }) 46}
47 } 47
48 48// ---------------------------------------------------------------------------
49 // --------------------------------------------------------------------------- 49
50 50module.exports = videos
51 module.exports = videos
52})()
diff --git a/lib/webtorrent.js b/lib/webtorrent.js
index 083e5b77a..5f10322a5 100644
--- a/lib/webtorrent.js
+++ b/lib/webtorrent.js
@@ -1,161 +1,159 @@
1;(function () { 1'use strict'
2 'use strict' 2
3 3var config = require('config')
4 var config = require('config') 4var ipc = require('node-ipc')
5 var ipc = require('node-ipc') 5var pathUtils = require('path')
6 var pathUtils = require('path') 6var spawn = require('electron-spawn')
7 var spawn = require('electron-spawn') 7
8 8var logger = require('../helpers/logger')
9 var logger = require('../helpers/logger') 9
10 10var host = config.get('webserver.host')
11 var host = config.get('webserver.host') 11var port = config.get('webserver.port')
12 var port = config.get('webserver.port') 12var nodeKey = 'webtorrentnode' + port
13 var nodeKey = 'webtorrentnode' + port 13var processKey = 'webtorrentprocess' + port
14 var processKey = 'webtorrentprocess' + port 14ipc.config.silent = true
15 ipc.config.silent = true 15ipc.config.id = nodeKey
16 ipc.config.id = nodeKey 16
17 17var webtorrent = {
18 var webtorrent = { 18 add: add,
19 add: add, 19 app: null, // Pid of the app
20 app: null, // Pid of the app 20 create: create,
21 create: create, 21 remove: remove,
22 remove: remove, 22 seed: seed,
23 seed: seed, 23 silent: false // Useful for beautiful tests
24 silent: false // Useful for beautiful tests 24}
25
26function create (options, callback) {
27 if (typeof options === 'function') {
28 callback = options
29 options = {}
25 } 30 }
26 31
27 function create (options, callback) { 32 // Override options
28 if (typeof options === 'function') { 33 if (options.host) host = options.host
29 callback = options 34 if (options.port) {
30 options = {} 35 port = options.port
31 } 36 nodeKey = 'webtorrentnode' + port
32 37 processKey = 'webtorrentprocess' + port
33 // Override options 38 ipc.config.id = nodeKey
34 if (options.host) host = options.host 39 }
35 if (options.port) {
36 port = options.port
37 nodeKey = 'webtorrentnode' + port
38 processKey = 'webtorrentprocess' + port
39 ipc.config.id = nodeKey
40 }
41
42 ipc.serve(function () {
43 if (!webtorrent.silent) logger.info('IPC server ready.')
44 40
45 // Run a timeout of 30s after which we exit the process 41 ipc.serve(function () {
46 var timeout_webtorrent_process = setTimeout(function () { 42 if (!webtorrent.silent) logger.info('IPC server ready.')
47 logger.error('Timeout : cannot run the webtorrent process. Please ensure you have electron-prebuilt npm package installed with xvfb-run.')
48 process.exit()
49 }, 30000)
50 43
51 ipc.server.on(processKey + '.ready', function () { 44 // Run a timeout of 30s after which we exit the process
52 if (!webtorrent.silent) logger.info('Webtorrent process ready.') 45 var timeout_webtorrent_process = setTimeout(function () {
53 clearTimeout(timeout_webtorrent_process) 46 logger.error('Timeout : cannot run the webtorrent process. Please ensure you have electron-prebuilt npm package installed with xvfb-run.')
54 callback() 47 process.exit()
55 }) 48 }, 30000)
56 49
57 ipc.server.on(processKey + '.exception', function (data) { 50 ipc.server.on(processKey + '.ready', function () {
58 logger.error('Received exception error from webtorrent process.', { exception: data.exception }) 51 if (!webtorrent.silent) logger.info('Webtorrent process ready.')
59 process.exit() 52 clearTimeout(timeout_webtorrent_process)
60 }) 53 callback()
54 })
61 55
62 var webtorrent_process = spawn(pathUtils.join(__dirname, 'webtorrentProcess.js'), host, port, { detached: true }) 56 ipc.server.on(processKey + '.exception', function (data) {
63 webtorrent_process.stderr.on('data', function (data) { 57 logger.error('Received exception error from webtorrent process.', { exception: data.exception })
64 // logger.debug('Webtorrent process stderr: ', data.toString()) 58 process.exit()
65 }) 59 })
66 60
67 webtorrent_process.stdout.on('data', function (data) { 61 var webtorrent_process = spawn(pathUtils.join(__dirname, 'webtorrentProcess.js'), host, port, { detached: true })
68 // logger.debug('Webtorrent process:', data.toString()) 62 webtorrent_process.stderr.on('data', function (data) {
69 }) 63 // logger.debug('Webtorrent process stderr: ', data.toString())
64 })
70 65
71 webtorrent.app = webtorrent_process 66 webtorrent_process.stdout.on('data', function (data) {
67 // logger.debug('Webtorrent process:', data.toString())
72 }) 68 })
73 69
74 ipc.server.start() 70 webtorrent.app = webtorrent_process
75 } 71 })
76 72
77 function seed (path, callback) { 73 ipc.server.start()
78 var extension = pathUtils.extname(path) 74}
79 var basename = pathUtils.basename(path, extension) 75
80 var data = { 76function seed (path, callback) {
81 _id: basename, 77 var extension = pathUtils.extname(path)
82 args: { 78 var basename = pathUtils.basename(path, extension)
83 path: path 79 var data = {
84 } 80 _id: basename,
81 args: {
82 path: path
85 } 83 }
84 }
86 85
87 if (!webtorrent.silent) logger.debug('Node wants to seed %s.', data._id) 86 if (!webtorrent.silent) logger.debug('Node wants to seed %s.', data._id)
88 87
89 // Finish signal 88 // Finish signal
90 var event_key = nodeKey + '.seedDone.' + data._id 89 var event_key = nodeKey + '.seedDone.' + data._id
91 ipc.server.on(event_key, function listener (received) { 90 ipc.server.on(event_key, function listener (received) {
92 if (!webtorrent.silent) logger.debug('Process seeded torrent %s.', received.magnetUri) 91 if (!webtorrent.silent) logger.debug('Process seeded torrent %s.', received.magnetUri)
93 92
94 // This is a fake object, we just use the magnetUri in this project 93 // This is a fake object, we just use the magnetUri in this project
95 var torrent = { 94 var torrent = {
96 magnetURI: received.magnetUri 95 magnetURI: received.magnetUri
97 } 96 }
98 97
99 ipc.server.off(event_key) 98 ipc.server.off(event_key)
100 callback(torrent) 99 callback(torrent)
101 }) 100 })
102 101
103 ipc.server.broadcast(processKey + '.seed', data) 102 ipc.server.broadcast(processKey + '.seed', data)
104 } 103}
105 104
106 function add (magnetUri, callback) { 105function add (magnetUri, callback) {
107 var data = { 106 var data = {
108 _id: magnetUri, 107 _id: magnetUri,
109 args: { 108 args: {
110 magnetUri: magnetUri 109 magnetUri: magnetUri
111 }
112 } 110 }
111 }
113 112
114 if (!webtorrent.silent) logger.debug('Node wants to add ' + data._id) 113 if (!webtorrent.silent) logger.debug('Node wants to add ' + data._id)
115 114
116 // Finish signal 115 // Finish signal
117 var event_key = nodeKey + '.addDone.' + data._id 116 var event_key = nodeKey + '.addDone.' + data._id
118 ipc.server.on(event_key, function (received) { 117 ipc.server.on(event_key, function (received) {
119 if (!webtorrent.silent) logger.debug('Process added torrent.') 118 if (!webtorrent.silent) logger.debug('Process added torrent.')
120 119
121 // This is a fake object, we just use the magnetUri in this project 120 // This is a fake object, we just use the magnetUri in this project
122 var torrent = { 121 var torrent = {
123 files: received.files 122 files: received.files
124 } 123 }
125 124
126 ipc.server.off(event_key) 125 ipc.server.off(event_key)
127 callback(torrent) 126 callback(torrent)
128 }) 127 })
129 128
130 ipc.server.broadcast(processKey + '.add', data) 129 ipc.server.broadcast(processKey + '.add', data)
131 } 130}
132 131
133 function remove (magnetUri, callback) { 132function remove (magnetUri, callback) {
134 var data = { 133 var data = {
135 _id: magnetUri, 134 _id: magnetUri,
136 args: { 135 args: {
137 magnetUri: magnetUri 136 magnetUri: magnetUri
138 }
139 } 137 }
138 }
140 139
141 if (!webtorrent.silent) logger.debug('Node wants to stop seeding %s.', data._id) 140 if (!webtorrent.silent) logger.debug('Node wants to stop seeding %s.', data._id)
142 141
143 // Finish signal 142 // Finish signal
144 var event_key = nodeKey + '.removeDone.' + data._id 143 var event_key = nodeKey + '.removeDone.' + data._id
145 ipc.server.on(event_key, function (received) { 144 ipc.server.on(event_key, function (received) {
146 if (!webtorrent.silent) logger.debug('Process removed torrent %s.', data._id) 145 if (!webtorrent.silent) logger.debug('Process removed torrent %s.', data._id)
147 146
148 var err = null 147 var err = null
149 if (received.err) err = received.err 148 if (received.err) err = received.err
150 149
151 ipc.server.off(event_key) 150 ipc.server.off(event_key)
152 callback(err) 151 callback(err)
153 }) 152 })
154 153
155 ipc.server.broadcast(processKey + '.remove', data) 154 ipc.server.broadcast(processKey + '.remove', data)
156 } 155}
157 156
158 // --------------------------------------------------------------------------- 157// ---------------------------------------------------------------------------
159 158
160 module.exports = webtorrent 159module.exports = webtorrent
161})()
diff --git a/lib/webtorrentProcess.js b/lib/webtorrentProcess.js
index 7dc655f10..96ebf9d02 100644
--- a/lib/webtorrentProcess.js
+++ b/lib/webtorrentProcess.js
@@ -1,95 +1,93 @@
1;(function () { 1'use strict'
2 'use strict'
3 2
4 function webtorrent (args) { 3function webtorrent (args) {
5 var WebTorrent = require('webtorrent') 4 var WebTorrent = require('webtorrent')
6 var ipc = require('node-ipc') 5 var ipc = require('node-ipc')
7 6
8 if (args.length !== 3) { 7 if (args.length !== 3) {
9 console.log('Wrong arguments number: ' + args.length + '/3') 8 console.log('Wrong arguments number: ' + args.length + '/3')
10 process.exit(-1) 9 process.exit(-1)
11 } 10 }
12
13 var host = args[1]
14 var port = args[2]
15 var nodeKey = 'webtorrentnode' + port
16 var processKey = 'webtorrentprocess' + port
17 11
18 ipc.config.silent = true 12 var host = args[1]
19 ipc.config.id = processKey 13 var port = args[2]
14 var nodeKey = 'webtorrentnode' + port
15 var processKey = 'webtorrentprocess' + port
20 16
21 if (host === 'client' && port === '1') global.WEBTORRENT_ANNOUNCE = [] 17 ipc.config.silent = true
22 else global.WEBTORRENT_ANNOUNCE = 'ws://' + host + ':' + port + '/tracker/socket' 18 ipc.config.id = processKey
23 var wt = new WebTorrent({ dht: false })
24 19
25 function seed (data) { 20 if (host === 'client' && port === '1') global.WEBTORRENT_ANNOUNCE = []
26 var args = data.args 21 else global.WEBTORRENT_ANNOUNCE = 'ws://' + host + ':' + port + '/tracker/socket'
27 var path = args.path 22 var wt = new WebTorrent({ dht: false })
28 var _id = data._id
29 23
30 wt.seed(path, { announceList: '' }, function (torrent) { 24 function seed (data) {
31 var to_send = { 25 var args = data.args
32 magnetUri: torrent.magnetURI 26 var path = args.path
33 } 27 var _id = data._id
34 28
35 ipc.of[nodeKey].emit(nodeKey + '.seedDone.' + _id, to_send) 29 wt.seed(path, { announceList: '' }, function (torrent) {
36 }) 30 var to_send = {
37 } 31 magnetUri: torrent.magnetURI
32 }
38 33
39 function add (data) { 34 ipc.of[nodeKey].emit(nodeKey + '.seedDone.' + _id, to_send)
40 var args = data.args 35 })
41 var magnetUri = args.magnetUri 36 }
42 var _id = data._id
43 37
44 wt.add(magnetUri, function (torrent) { 38 function add (data) {
45 var to_send = { 39 var args = data.args
46 files: [] 40 var magnetUri = args.magnetUri
47 } 41 var _id = data._id
48 42
49 torrent.files.forEach(function (file) { 43 wt.add(magnetUri, function (torrent) {
50 to_send.files.push({ path: file.path }) 44 var to_send = {
51 }) 45 files: []
46 }
52 47
53 ipc.of[nodeKey].emit(nodeKey + '.addDone.' + _id, to_send) 48 torrent.files.forEach(function (file) {
49 to_send.files.push({ path: file.path })
54 }) 50 })
55 }
56 51
57 function remove (data) { 52 ipc.of[nodeKey].emit(nodeKey + '.addDone.' + _id, to_send)
58 var args = data.args 53 })
59 var magnetUri = args.magnetUri 54 }
60 var _id = data._id
61 55
62 try { 56 function remove (data) {
63 wt.remove(magnetUri, callback) 57 var args = data.args
64 } catch (err) { 58 var magnetUri = args.magnetUri
65 console.log('Cannot remove the torrent from WebTorrent.') 59 var _id = data._id
66 return callback(null)
67 }
68 60
69 function callback () { 61 try {
70 var to_send = {} 62 wt.remove(magnetUri, callback)
71 ipc.of[nodeKey].emit(nodeKey + '.removeDone.' + _id, to_send) 63 } catch (err) {
72 } 64 console.log('Cannot remove the torrent from WebTorrent.')
65 return callback(null)
66 }
67
68 function callback () {
69 var to_send = {}
70 ipc.of[nodeKey].emit(nodeKey + '.removeDone.' + _id, to_send)
73 } 71 }
72 }
74 73
75 console.log('Configuration: ' + host + ':' + port) 74 console.log('Configuration: ' + host + ':' + port)
76 console.log('Connecting to IPC...') 75 console.log('Connecting to IPC...')
77 76
78 ipc.connectTo(nodeKey, function () { 77 ipc.connectTo(nodeKey, function () {
79 ipc.of[nodeKey].on(processKey + '.seed', seed) 78 ipc.of[nodeKey].on(processKey + '.seed', seed)
80 ipc.of[nodeKey].on(processKey + '.add', add) 79 ipc.of[nodeKey].on(processKey + '.add', add)
81 ipc.of[nodeKey].on(processKey + '.remove', remove) 80 ipc.of[nodeKey].on(processKey + '.remove', remove)
82 81
83 ipc.of[nodeKey].emit(processKey + '.ready') 82 ipc.of[nodeKey].emit(processKey + '.ready')
84 console.log('Ready.') 83 console.log('Ready.')
85 }) 84 })
86 85
87 process.on('uncaughtException', function (e) { 86 process.on('uncaughtException', function (e) {
88 ipc.of[nodeKey].emit(processKey + '.exception', { exception: e }) 87 ipc.of[nodeKey].emit(processKey + '.exception', { exception: e })
89 }) 88 })
90 } 89}
91 90
92 // --------------------------------------------------------------------------- 91// ---------------------------------------------------------------------------
93 92
94 module.exports = webtorrent 93module.exports = webtorrent
95})()
diff --git a/middlewares/cache.js b/middlewares/cache.js
index 782165155..0d3da0075 100644
--- a/middlewares/cache.js
+++ b/middlewares/cache.js
@@ -1,25 +1,23 @@
1;(function () { 1'use strict'
2 'use strict'
3 2
4 var cacheMiddleware = { 3var cacheMiddleware = {
5 cache: cache 4 cache: cache
6 } 5}
7
8 function cache (cache) {
9 return function (req, res, next) {
10 // If we want explicitly a cache
11 // Or if we don't specify if we want a cache or no and we are in production
12 if (cache === true || (cache !== false && process.env.NODE_ENV === 'production')) {
13 res.setHeader('Cache-Control', 'public')
14 } else {
15 res.setHeader('Cache-Control', 'no-cache, no-store, max-age=0, must-revalidate')
16 }
17 6
18 next() 7function cache (cache) {
8 return function (req, res, next) {
9 // If we want explicitly a cache
10 // Or if we don't specify if we want a cache or no and we are in production
11 if (cache === true || (cache !== false && process.env.NODE_ENV === 'production')) {
12 res.setHeader('Cache-Control', 'public')
13 } else {
14 res.setHeader('Cache-Control', 'no-cache, no-store, max-age=0, must-revalidate')
19 } 15 }
16
17 next()
20 } 18 }
19}
21 20
22 // --------------------------------------------------------------------------- 21// ---------------------------------------------------------------------------
23 22
24 module.exports = cacheMiddleware 23module.exports = cacheMiddleware
25})()
diff --git a/middlewares/index.js b/middlewares/index.js
index bfe325b1e..c76c4fc2e 100644
--- a/middlewares/index.js
+++ b/middlewares/index.js
@@ -1,13 +1,11 @@
1;(function () { 1'use strict'
2 'use strict'
3 2
4 var middlewares = { 3var middlewares = {
5 cache: require('./cache'), 4 cache: require('./cache'),
6 reqValidators: require('./reqValidators'), 5 reqValidators: require('./reqValidators'),
7 secure: require('./secure') 6 secure: require('./secure')
8 } 7}
9 8
10 // --------------------------------------------------------------------------- 9// ---------------------------------------------------------------------------
11 10
12 module.exports = middlewares 11module.exports = middlewares
13})()
diff --git a/middlewares/reqValidators/index.js b/middlewares/reqValidators/index.js
index 34d34013c..344387a80 100644
--- a/middlewares/reqValidators/index.js
+++ b/middlewares/reqValidators/index.js
@@ -1,13 +1,11 @@
1;(function () { 1'use strict'
2 'use strict'
3 2
4 var reqValidators = { 3var reqValidators = {
5 videos: require('./videos'), 4 videos: require('./videos'),
6 pods: require('./pods'), 5 pods: require('./pods'),
7 remote: require('./remote') 6 remote: require('./remote')
8 } 7}
9 8
10 // --------------------------------------------------------------------------- 9// ---------------------------------------------------------------------------
11 10
12 module.exports = reqValidators 11module.exports = reqValidators
13})()
diff --git a/middlewares/reqValidators/pods.js b/middlewares/reqValidators/pods.js
index 4d649b486..7d1612dde 100644
--- a/middlewares/reqValidators/pods.js
+++ b/middlewares/reqValidators/pods.js
@@ -1,41 +1,39 @@
1;(function () { 1'use strict'
2 'use strict' 2
3 3var checkErrors = require('./utils').checkErrors
4 var checkErrors = require('./utils').checkErrors 4var friends = require('../../lib/friends')
5 var friends = require('../../lib/friends') 5var logger = require('../../helpers/logger')
6 var logger = require('../../helpers/logger') 6
7 7var reqValidatorsPod = {
8 var reqValidatorsPod = { 8 makeFriends: makeFriends,
9 makeFriends: makeFriends, 9 podsAdd: podsAdd
10 podsAdd: podsAdd 10}
11 } 11
12 12function makeFriends (req, res, next) {
13 function makeFriends (req, res, next) { 13 friends.hasFriends(function (err, has_friends) {
14 friends.hasFriends(function (err, has_friends) { 14 if (err) {
15 if (err) { 15 logger.error('Cannot know if we have friends.', { error: err })
16 logger.error('Cannot know if we have friends.', { error: err }) 16 res.sendStatus(500)
17 res.sendStatus(500) 17 }
18 } 18
19 19 if (has_friends === true) {
20 if (has_friends === true) { 20 // We need to quit our friends before make new ones
21 // We need to quit our friends before make new ones 21 res.sendStatus(409)
22 res.sendStatus(409) 22 } else {
23 } else { 23 next()
24 next() 24 }
25 } 25 })
26 }) 26}
27 } 27
28 28function podsAdd (req, res, next) {
29 function podsAdd (req, res, next) { 29 req.checkBody('data.url', 'Should have an url').notEmpty().isURL({ require_protocol: true })
30 req.checkBody('data.url', 'Should have an url').notEmpty().isURL({ require_protocol: true }) 30 req.checkBody('data.publicKey', 'Should have a public key').notEmpty()
31 req.checkBody('data.publicKey', 'Should have a public key').notEmpty() 31
32 32 logger.debug('Checking podsAdd parameters', { parameters: req.body })
33 logger.debug('Checking podsAdd parameters', { parameters: req.body }) 33
34 34 checkErrors(req, res, next)
35 checkErrors(req, res, next) 35}
36 } 36
37 37// ---------------------------------------------------------------------------
38 // --------------------------------------------------------------------------- 38
39 39module.exports = reqValidatorsPod
40 module.exports = reqValidatorsPod
41})()
diff --git a/middlewares/reqValidators/remote.js b/middlewares/reqValidators/remote.js
index 9b61481ad..88de16b49 100644
--- a/middlewares/reqValidators/remote.js
+++ b/middlewares/reqValidators/remote.js
@@ -1,45 +1,43 @@
1;(function () { 1'use strict'
2 'use strict'
3 2
4 var checkErrors = require('./utils').checkErrors 3var checkErrors = require('./utils').checkErrors
5 var logger = require('../../helpers/logger') 4var logger = require('../../helpers/logger')
6 5
7 var reqValidatorsRemote = { 6var reqValidatorsRemote = {
8 remoteVideosAdd: remoteVideosAdd, 7 remoteVideosAdd: remoteVideosAdd,
9 remoteVideosRemove: remoteVideosRemove, 8 remoteVideosRemove: remoteVideosRemove,
10 secureRequest: secureRequest 9 secureRequest: secureRequest
11 } 10}
12 11
13 function remoteVideosAdd (req, res, next) { 12function remoteVideosAdd (req, res, next) {
14 req.checkBody('data').isArray() 13 req.checkBody('data').isArray()
15 req.checkBody('data').eachIsRemoteVideosAddValid() 14 req.checkBody('data').eachIsRemoteVideosAddValid()
16 15
17 logger.debug('Checking remoteVideosAdd parameters', { parameters: req.body }) 16 logger.debug('Checking remoteVideosAdd parameters', { parameters: req.body })
18 17
19 checkErrors(req, res, next) 18 checkErrors(req, res, next)
20 } 19}
21 20
22 function remoteVideosRemove (req, res, next) { 21function remoteVideosRemove (req, res, next) {
23 req.checkBody('data').isArray() 22 req.checkBody('data').isArray()
24 req.checkBody('data').eachIsRemoteVideosRemoveValid() 23 req.checkBody('data').eachIsRemoteVideosRemoveValid()
25 24
26 logger.debug('Checking remoteVideosRemove parameters', { parameters: req.body }) 25 logger.debug('Checking remoteVideosRemove parameters', { parameters: req.body })
27 26
28 checkErrors(req, res, next) 27 checkErrors(req, res, next)
29 } 28}
30 29
31 function secureRequest (req, res, next) { 30function secureRequest (req, res, next) {
32 req.checkBody('signature.url', 'Should have a signature url').isURL() 31 req.checkBody('signature.url', 'Should have a signature url').isURL()
33 req.checkBody('signature.signature', 'Should have a signature').notEmpty() 32 req.checkBody('signature.signature', 'Should have a signature').notEmpty()
34 req.checkBody('key', 'Should have a key').notEmpty() 33 req.checkBody('key', 'Should have a key').notEmpty()
35 req.checkBody('data', 'Should have data').notEmpty() 34 req.checkBody('data', 'Should have data').notEmpty()
36 35
37 logger.debug('Checking secureRequest parameters', { parameters: { data: req.body.data, keyLength: req.body.key.length } }) 36 logger.debug('Checking secureRequest parameters', { parameters: { data: req.body.data, keyLength: req.body.key.length } })
38 37
39 checkErrors(req, res, next) 38 checkErrors(req, res, next)
40 } 39}
41 40
42 // --------------------------------------------------------------------------- 41// ---------------------------------------------------------------------------
43 42
44 module.exports = reqValidatorsRemote 43module.exports = reqValidatorsRemote
45})()
diff --git a/middlewares/reqValidators/utils.js b/middlewares/reqValidators/utils.js
index c88f6df2e..46c982571 100644
--- a/middlewares/reqValidators/utils.js
+++ b/middlewares/reqValidators/utils.js
@@ -1,27 +1,25 @@
1;(function () { 1'use strict'
2 'use strict'
3 2
4 var util = require('util') 3var util = require('util')
5 4
6 var logger = require('../../helpers/logger') 5var logger = require('../../helpers/logger')
7 6
8 var reqValidatorsUtils = { 7var reqValidatorsUtils = {
9 checkErrors: checkErrors 8 checkErrors: checkErrors
10 } 9}
11
12 function checkErrors (req, res, next, status_code) {
13 if (status_code === undefined) status_code = 400
14 var errors = req.validationErrors()
15 10
16 if (errors) { 11function checkErrors (req, res, next, status_code) {
17 logger.warn('Incorrect request parameters', { path: req.originalUrl, err: errors }) 12 if (status_code === undefined) status_code = 400
18 return res.status(status_code).send('There have been validation errors: ' + util.inspect(errors)) 13 var errors = req.validationErrors()
19 }
20 14
21 return next() 15 if (errors) {
16 logger.warn('Incorrect request parameters', { path: req.originalUrl, err: errors })
17 return res.status(status_code).send('There have been validation errors: ' + util.inspect(errors))
22 } 18 }
23 19
24 // --------------------------------------------------------------------------- 20 return next()
21}
22
23// ---------------------------------------------------------------------------
25 24
26 module.exports = reqValidatorsUtils 25module.exports = reqValidatorsUtils
27})()
diff --git a/middlewares/reqValidators/videos.js b/middlewares/reqValidators/videos.js
index f7bd24658..4e5f4391f 100644
--- a/middlewares/reqValidators/videos.js
+++ b/middlewares/reqValidators/videos.js
@@ -1,76 +1,74 @@
1;(function () { 1'use strict'
2 'use strict'
3 2
4 var checkErrors = require('./utils').checkErrors 3var checkErrors = require('./utils').checkErrors
5 var logger = require('../../helpers/logger') 4var logger = require('../../helpers/logger')
6 var Videos = require('../../models/videos') 5var Videos = require('../../models/videos')
7 6
8 var reqValidatorsVideos = { 7var reqValidatorsVideos = {
9 videosAdd: videosAdd, 8 videosAdd: videosAdd,
10 videosGet: videosGet, 9 videosGet: videosGet,
11 videosRemove: videosRemove, 10 videosRemove: videosRemove,
12 videosSearch: videosSearch 11 videosSearch: videosSearch
13 } 12}
14 13
15 function videosAdd (req, res, next) { 14function videosAdd (req, res, next) {
16 req.checkFiles('input_video[0].originalname', 'Should have an input video').notEmpty() 15 req.checkFiles('input_video[0].originalname', 'Should have an input video').notEmpty()
17 req.checkFiles('input_video[0].mimetype', 'Should have a correct mime type').matches(/video\/(webm)|(mp4)|(ogg)/i) 16 req.checkFiles('input_video[0].mimetype', 'Should have a correct mime type').matches(/video\/(webm)|(mp4)|(ogg)/i)
18 req.checkBody('name', 'Should have a name').isLength(1, 50) 17 req.checkBody('name', 'Should have a name').isLength(1, 50)
19 req.checkBody('description', 'Should have a description').isLength(1, 250) 18 req.checkBody('description', 'Should have a description').isLength(1, 250)
20 19
21 logger.debug('Checking videosAdd parameters', { parameters: req.body, files: req.files }) 20 logger.debug('Checking videosAdd parameters', { parameters: req.body, files: req.files })
22 21
23 checkErrors(req, res, next) 22 checkErrors(req, res, next)
24 } 23}
25 24
26 function videosGet (req, res, next) { 25function videosGet (req, res, next) {
27 req.checkParams('id', 'Should have a valid id').notEmpty().isMongoId() 26 req.checkParams('id', 'Should have a valid id').notEmpty().isMongoId()
28 27
29 logger.debug('Checking videosGet parameters', { parameters: req.params }) 28 logger.debug('Checking videosGet parameters', { parameters: req.params })
30 29
31 checkErrors(req, res, function () { 30 checkErrors(req, res, function () {
32 Videos.getVideoState(req.params.id, function (err, state) { 31 Videos.getVideoState(req.params.id, function (err, state) {
33 if (err) { 32 if (err) {
34 logger.error('Error in videosGet request validator.', { error: err }) 33 logger.error('Error in videosGet request validator.', { error: err })
35 res.sendStatus(500) 34 res.sendStatus(500)
36 } 35 }
37 36
38 if (state.exist === false) return res.status(404).send('Video not found') 37 if (state.exist === false) return res.status(404).send('Video not found')
39 38
40 next() 39 next()
41 })
42 }) 40 })
43 } 41 })
42}
44 43
45 function videosRemove (req, res, next) { 44function videosRemove (req, res, next) {
46 req.checkParams('id', 'Should have a valid id').notEmpty().isMongoId() 45 req.checkParams('id', 'Should have a valid id').notEmpty().isMongoId()
47 46
48 logger.debug('Checking videosRemove parameters', { parameters: req.params }) 47 logger.debug('Checking videosRemove parameters', { parameters: req.params })
49 48
50 checkErrors(req, res, function () { 49 checkErrors(req, res, function () {
51 Videos.getVideoState(req.params.id, function (err, state) { 50 Videos.getVideoState(req.params.id, function (err, state) {
52 if (err) { 51 if (err) {
53 logger.error('Error in videosRemove request validator.', { error: err }) 52 logger.error('Error in videosRemove request validator.', { error: err })
54 res.sendStatus(500) 53 res.sendStatus(500)
55 } 54 }
56 55
57 if (state.exist === false) return res.status(404).send('Video not found') 56 if (state.exist === false) return res.status(404).send('Video not found')
58 else if (state.owned === false) return res.status(403).send('Cannot remove video of another pod') 57 else if (state.owned === false) return res.status(403).send('Cannot remove video of another pod')
59 58
60 next() 59 next()
61 })
62 }) 60 })
63 } 61 })
62}
64 63
65 function videosSearch (req, res, next) { 64function videosSearch (req, res, next) {
66 req.checkParams('name', 'Should have a name').notEmpty() 65 req.checkParams('name', 'Should have a name').notEmpty()
67 66
68 logger.debug('Checking videosSearch parameters', { parameters: req.params }) 67 logger.debug('Checking videosSearch parameters', { parameters: req.params })
69 68
70 checkErrors(req, res, next) 69 checkErrors(req, res, next)
71 } 70}
72 71
73 // --------------------------------------------------------------------------- 72// ---------------------------------------------------------------------------
74 73
75 module.exports = reqValidatorsVideos 74module.exports = reqValidatorsVideos
76})()
diff --git a/middlewares/secure.js b/middlewares/secure.js
index b7a18ad3e..bfd28316a 100644
--- a/middlewares/secure.js
+++ b/middlewares/secure.js
@@ -1,51 +1,49 @@
1;(function () { 1'use strict'
2 'use strict' 2
3 3var logger = require('../helpers/logger')
4 var logger = require('../helpers/logger') 4var peertubeCrypto = require('../helpers/peertubeCrypto')
5 var peertubeCrypto = require('../helpers/peertubeCrypto') 5var Pods = require('../models/pods')
6 var Pods = require('../models/pods') 6
7 7var secureMiddleware = {
8 var secureMiddleware = { 8 decryptBody: decryptBody
9 decryptBody: decryptBody 9}
10 } 10
11 11function decryptBody (req, res, next) {
12 function decryptBody (req, res, next) { 12 var url = req.body.signature.url
13 var url = req.body.signature.url 13 Pods.findByUrl(url, function (err, pod) {
14 Pods.findByUrl(url, function (err, pod) { 14 if (err) {
15 if (err) { 15 logger.error('Cannot get signed url in decryptBody.', { error: err })
16 logger.error('Cannot get signed url in decryptBody.', { error: err }) 16 return res.sendStatus(500)
17 return res.sendStatus(500) 17 }
18 } 18
19 19 if (pod === null) {
20 if (pod === null) { 20 logger.error('Unknown pod %s.', url)
21 logger.error('Unknown pod %s.', url) 21 return res.sendStatus(403)
22 return res.sendStatus(403) 22 }
23 } 23
24 24 logger.debug('Decrypting body from %s.', url)
25 logger.debug('Decrypting body from %s.', url) 25
26 26 var signature_ok = peertubeCrypto.checkSignature(pod.publicKey, url, req.body.signature.signature)
27 var signature_ok = peertubeCrypto.checkSignature(pod.publicKey, url, req.body.signature.signature) 27
28 28 if (signature_ok === true) {
29 if (signature_ok === true) { 29 peertubeCrypto.decrypt(req.body.key, req.body.data, function (err, decrypted) {
30 peertubeCrypto.decrypt(req.body.key, req.body.data, function (err, decrypted) { 30 if (err) {
31 if (err) { 31 logger.error('Cannot decrypt data.', { error: err })
32 logger.error('Cannot decrypt data.', { error: err }) 32 return res.sendStatus(500)
33 return res.sendStatus(500) 33 }
34 } 34
35 35 req.body.data = JSON.parse(decrypted)
36 req.body.data = JSON.parse(decrypted) 36 delete req.body.key
37 delete req.body.key 37
38 38 next()
39 next() 39 })
40 }) 40 } else {
41 } else { 41 logger.error('Signature is not okay in decryptBody for %s.', req.body.signature.url)
42 logger.error('Signature is not okay in decryptBody for %s.', req.body.signature.url) 42 return res.sendStatus(403)
43 return res.sendStatus(403) 43 }
44 } 44 })
45 }) 45}
46 } 46
47 47// ---------------------------------------------------------------------------
48 // --------------------------------------------------------------------------- 48
49 49module.exports = secureMiddleware
50 module.exports = secureMiddleware
51})()
diff --git a/models/pods.js b/models/pods.js
index 04fd042c3..57ed20292 100644
--- a/models/pods.js
+++ b/models/pods.js
@@ -1,90 +1,88 @@
1;(function () { 1'use strict'
2 'use strict' 2
3 3var mongoose = require('mongoose')
4 var mongoose = require('mongoose') 4
5 5var constants = require('../initializers/constants')
6 var constants = require('../initializers/constants') 6var logger = require('../helpers/logger')
7 var logger = require('../helpers/logger') 7
8 8// ---------------------------------------------------------------------------
9 // --------------------------------------------------------------------------- 9
10 10var podsSchema = mongoose.Schema({
11 var podsSchema = mongoose.Schema({ 11 url: String,
12 url: String, 12 publicKey: String,
13 publicKey: String, 13 score: { type: Number, max: constants.FRIEND_BASE_SCORE }
14 score: { type: Number, max: constants.FRIEND_BASE_SCORE } 14})
15 }) 15var PodsDB = mongoose.model('pods', podsSchema)
16 var PodsDB = mongoose.model('pods', podsSchema) 16
17 17// ---------------------------------------------------------------------------
18 // --------------------------------------------------------------------------- 18
19 19var Pods = {
20 var Pods = { 20 add: add,
21 add: add, 21 count: count,
22 count: count, 22 findByUrl: findByUrl,
23 findByUrl: findByUrl, 23 findBadPods: findBadPods,
24 findBadPods: findBadPods, 24 incrementScores: incrementScores,
25 incrementScores: incrementScores, 25 list: list,
26 list: list, 26 remove: remove,
27 remove: remove, 27 removeAll: removeAll,
28 removeAll: removeAll, 28 removeAllByIds: removeAllByIds
29 removeAllByIds: removeAllByIds 29}
30
31// TODO: check if the pod is not already a friend
32function add (data, callback) {
33 if (!callback) callback = function () {}
34 var params = {
35 url: data.url,
36 publicKey: data.publicKey,
37 score: constants.FRIEND_BASE_SCORE
30 } 38 }
31 39
32 // TODO: check if the pod is not already a friend 40 PodsDB.create(params, callback)
33 function add (data, callback) { 41}
34 if (!callback) callback = function () {}
35 var params = {
36 url: data.url,
37 publicKey: data.publicKey,
38 score: constants.FRIEND_BASE_SCORE
39 }
40
41 PodsDB.create(params, callback)
42 }
43 42
44 function count (callback) { 43function count (callback) {
45 return PodsDB.count(callback) 44 return PodsDB.count(callback)
46 } 45}
47 46
48 function findBadPods (callback) { 47function findBadPods (callback) {
49 PodsDB.find({ score: 0 }, callback) 48 PodsDB.find({ score: 0 }, callback)
50 } 49}
51 50
52 function findByUrl (url, callback) { 51function findByUrl (url, callback) {
53 PodsDB.findOne({ url: url }, callback) 52 PodsDB.findOne({ url: url }, callback)
54 } 53}
55 54
56 function incrementScores (ids, value, callback) { 55function incrementScores (ids, value, callback) {
57 if (!callback) callback = function () {} 56 if (!callback) callback = function () {}
58 PodsDB.update({ _id: { $in: ids } }, { $inc: { score: value } }, { multi: true }, callback) 57 PodsDB.update({ _id: { $in: ids } }, { $inc: { score: value } }, { multi: true }, callback)
59 } 58}
60 59
61 function list (callback) { 60function list (callback) {
62 PodsDB.find(function (err, pods_list) { 61 PodsDB.find(function (err, pods_list) {
63 if (err) { 62 if (err) {
64 logger.error('Cannot get the list of the pods.') 63 logger.error('Cannot get the list of the pods.')
65 return callback(err) 64 return callback(err)
66 } 65 }
67 66
68 return callback(null, pods_list) 67 return callback(null, pods_list)
69 }) 68 })
70 } 69}
71 70
72 function remove (url, callback) { 71function remove (url, callback) {
73 if (!callback) callback = function () {} 72 if (!callback) callback = function () {}
74 PodsDB.remove({ url: url }, callback) 73 PodsDB.remove({ url: url }, callback)
75 } 74}
76 75
77 function removeAll (callback) { 76function removeAll (callback) {
78 if (!callback) callback = function () {} 77 if (!callback) callback = function () {}
79 PodsDB.remove(callback) 78 PodsDB.remove(callback)
80 } 79}
81 80
82 function removeAllByIds (ids, callback) { 81function removeAllByIds (ids, callback) {
83 if (!callback) callback = function () {} 82 if (!callback) callback = function () {}
84 PodsDB.remove({ _id: { $in: ids } }, callback) 83 PodsDB.remove({ _id: { $in: ids } }, callback)
85 } 84}
86 85
87 // --------------------------------------------------------------------------- 86// ---------------------------------------------------------------------------
88 87
89 module.exports = Pods 88module.exports = Pods
90})()
diff --git a/models/poolRequests.js b/models/poolRequests.js
index 5070a1331..970315597 100644
--- a/models/poolRequests.js
+++ b/models/poolRequests.js
@@ -1,57 +1,55 @@
1;(function () { 1'use strict'
2 'use strict'
3 2
4 var mongoose = require('mongoose') 3var mongoose = require('mongoose')
5 4
6 var logger = require('../helpers/logger') 5var logger = require('../helpers/logger')
7 6
8 // --------------------------------------------------------------------------- 7// ---------------------------------------------------------------------------
9 8
10 var poolRequestsSchema = mongoose.Schema({ 9var poolRequestsSchema = mongoose.Schema({
11 type: String, 10 type: String,
12 id: String, // Special id to find duplicates (video created we want to remove...) 11 id: String, // Special id to find duplicates (video created we want to remove...)
13 request: mongoose.Schema.Types.Mixed 12 request: mongoose.Schema.Types.Mixed
14 }) 13})
15 var PoolRequestsDB = mongoose.model('poolRequests', poolRequestsSchema) 14var PoolRequestsDB = mongoose.model('poolRequests', poolRequestsSchema)
16 15
17 // --------------------------------------------------------------------------- 16// ---------------------------------------------------------------------------
18 17
19 var PoolRequests = { 18var PoolRequests = {
20 create: create, 19 create: create,
21 findById: findById, 20 findById: findById,
22 list: list, 21 list: list,
23 removeRequestById: removeRequestById, 22 removeRequestById: removeRequestById,
24 removeRequests: removeRequests 23 removeRequests: removeRequests
25 } 24}
26 25
27 function create (id, type, request, callback) { 26function create (id, type, request, callback) {
28 PoolRequestsDB.create({ id: id, type: type, request: request }, callback) 27 PoolRequestsDB.create({ id: id, type: type, request: request }, callback)
29 } 28}
30 29
31 function findById (id, callback) { 30function findById (id, callback) {
32 PoolRequestsDB.findOne({ id: id }, callback) 31 PoolRequestsDB.findOne({ id: id }, callback)
33 } 32}
34 33
35 function list (callback) { 34function list (callback) {
36 PoolRequestsDB.find({}, { _id: 1, type: 1, request: 1 }, callback) 35 PoolRequestsDB.find({}, { _id: 1, type: 1, request: 1 }, callback)
37 } 36}
38 37
39 function removeRequestById (id, callback) { 38function removeRequestById (id, callback) {
40 PoolRequestsDB.remove({ id: id }, callback) 39 PoolRequestsDB.remove({ id: id }, callback)
41 } 40}
42 41
43 function removeRequests (ids) { 42function removeRequests (ids) {
44 PoolRequestsDB.remove({ _id: { $in: ids } }, function (err) { 43 PoolRequestsDB.remove({ _id: { $in: ids } }, function (err) {
45 if (err) { 44 if (err) {
46 logger.error('Cannot remove requests from the pool requests database.', { error: err }) 45 logger.error('Cannot remove requests from the pool requests database.', { error: err })
47 return // Abort 46 return // Abort
48 } 47 }
49 48
50 logger.info('Pool requests flushed.') 49 logger.info('Pool requests flushed.')
51 }) 50 })
52 } 51}
53 52
54 // --------------------------------------------------------------------------- 53// ---------------------------------------------------------------------------
55 54
56 module.exports = PoolRequests 55module.exports = PoolRequests
57})()
diff --git a/models/videos.js b/models/videos.js
index ea1823e27..4da389c24 100644
--- a/models/videos.js
+++ b/models/videos.js
@@ -1,237 +1,235 @@
1;(function () { 1'use strict'
2 'use strict' 2
3 3var async = require('async')
4 var async = require('async') 4var config = require('config')
5 var config = require('config') 5var dz = require('dezalgo')
6 var dz = require('dezalgo') 6var fs = require('fs')
7 var fs = require('fs') 7var mongoose = require('mongoose')
8 var mongoose = require('mongoose') 8var path = require('path')
9 var path = require('path') 9
10 10var logger = require('../helpers/logger')
11 var logger = require('../helpers/logger') 11
12 12var http = config.get('webserver.https') === true ? 'https' : 'http'
13 var http = config.get('webserver.https') === true ? 'https' : 'http' 13var host = config.get('webserver.host')
14 var host = config.get('webserver.host') 14var port = config.get('webserver.port')
15 var port = config.get('webserver.port') 15var uploadDir = path.join(__dirname, '..', config.get('storage.uploads'))
16 var uploadDir = path.join(__dirname, '..', config.get('storage.uploads')) 16
17 17// ---------------------------------------------------------------------------
18 // --------------------------------------------------------------------------- 18
19 19var videosSchema = mongoose.Schema({
20 var videosSchema = mongoose.Schema({ 20 name: String,
21 name: String, 21 namePath: String,
22 namePath: String, 22 description: String,
23 description: String, 23 magnetUri: String,
24 magnetUri: String, 24 podUrl: String
25 podUrl: String 25})
26var VideosDB = mongoose.model('videos', videosSchema)
27
28// ---------------------------------------------------------------------------
29
30var Videos = {
31 add: add,
32 addRemotes: addRemotes,
33 get: get,
34 getVideoState: getVideoState,
35 isOwned: isOwned,
36 list: list,
37 listOwned: listOwned,
38 removeOwned: removeOwned,
39 removeAllRemotes: removeAllRemotes,
40 removeAllRemotesOf: removeAllRemotesOf,
41 removeRemotesOfByMagnetUris: removeRemotesOfByMagnetUris,
42 search: search
43}
44
45function add (video, callback) {
46 logger.info('Adding %s video to database.', video.name)
47
48 var params = video
49 params.podUrl = http + '://' + host + ':' + port
50
51 VideosDB.create(params, function (err, video) {
52 if (err) {
53 logger.error('Cannot insert this video into database.')
54 return callback(err)
55 }
56
57 callback(null)
26 }) 58 })
27 var VideosDB = mongoose.model('videos', videosSchema) 59}
28
29 // ---------------------------------------------------------------------------
30
31 var Videos = {
32 add: add,
33 addRemotes: addRemotes,
34 get: get,
35 getVideoState: getVideoState,
36 isOwned: isOwned,
37 list: list,
38 listOwned: listOwned,
39 removeOwned: removeOwned,
40 removeAllRemotes: removeAllRemotes,
41 removeAllRemotesOf: removeAllRemotesOf,
42 removeRemotesOfByMagnetUris: removeRemotesOfByMagnetUris,
43 search: search
44 }
45
46 function add (video, callback) {
47 logger.info('Adding %s video to database.', video.name)
48
49 var params = video
50 params.podUrl = http + '://' + host + ':' + port
51
52 VideosDB.create(params, function (err, video) {
53 if (err) {
54 logger.error('Cannot insert this video into database.')
55 return callback(err)
56 }
57
58 callback(null)
59 })
60 }
61 60
62 // TODO: avoid doublons 61// TODO: avoid doublons
63 function addRemotes (videos, callback) { 62function addRemotes (videos, callback) {
64 if (!callback) callback = function () {} 63 if (!callback) callback = function () {}
65 64
66 var to_add = [] 65 var to_add = []
67 66
68 async.each(videos, function (video, callback_each) { 67 async.each(videos, function (video, callback_each) {
69 callback_each = dz(callback_each) 68 callback_each = dz(callback_each)
70 logger.debug('Add remote video from pod: %s', video.podUrl) 69 logger.debug('Add remote video from pod: %s', video.podUrl)
71
72 var params = {
73 name: video.name,
74 namePath: null,
75 description: video.description,
76 magnetUri: video.magnetUri,
77 podUrl: video.podUrl
78 }
79 70
80 to_add.push(params) 71 var params = {
72 name: video.name,
73 namePath: null,
74 description: video.description,
75 magnetUri: video.magnetUri,
76 podUrl: video.podUrl
77 }
81 78
82 callback_each() 79 to_add.push(params)
83 }, function () {
84 VideosDB.create(to_add, function (err, videos) {
85 if (err) {
86 logger.error('Cannot insert this remote video.')
87 return callback(err)
88 }
89
90 return callback(null, videos)
91 })
92 })
93 }
94 80
95 function get (id, callback) { 81 callback_each()
96 VideosDB.findById(id, function (err, video) { 82 }, function () {
83 VideosDB.create(to_add, function (err, videos) {
97 if (err) { 84 if (err) {
98 logger.error('Cannot get this video.') 85 logger.error('Cannot insert this remote video.')
99 return callback(err) 86 return callback(err)
100 } 87 }
101 88
102 return callback(null, video) 89 return callback(null, videos)
103 }) 90 })
104 } 91 })
92}
105 93
106 function getVideoState (id, callback) { 94function get (id, callback) {
107 get(id, function (err, video) { 95 VideosDB.findById(id, function (err, video) {
108 if (err) return callback(err) 96 if (err) {
97 logger.error('Cannot get this video.')
98 return callback(err)
99 }
109 100
110 var exist = (video !== null) 101 return callback(null, video)
111 var owned = false 102 })
112 if (exist === true) { 103}
113 owned = (video.namePath !== null)
114 }
115 104
116 return callback(null, { exist: exist, owned: owned }) 105function getVideoState (id, callback) {
117 }) 106 get(id, function (err, video) {
118 } 107 if (err) return callback(err)
119 108
120 function isOwned (id, callback) { 109 var exist = (video !== null)
121 VideosDB.findById(id, function (err, video) { 110 var owned = false
122 if (err || !video) { 111 if (exist === true) {
123 if (!err) err = new Error('Cannot find this video.') 112 owned = (video.namePath !== null)
124 logger.error('Cannot find this video.') 113 }
125 return callback(err)
126 }
127 114
128 if (video.namePath === null) { 115 return callback(null, { exist: exist, owned: owned })
129 var error_string = 'Cannot remove the video of another pod.' 116 })
130 logger.error(error_string) 117}
131 return callback(new Error(error_string), false, video) 118
132 } 119function isOwned (id, callback) {
120 VideosDB.findById(id, function (err, video) {
121 if (err || !video) {
122 if (!err) err = new Error('Cannot find this video.')
123 logger.error('Cannot find this video.')
124 return callback(err)
125 }
126
127 if (video.namePath === null) {
128 var error_string = 'Cannot remove the video of another pod.'
129 logger.error(error_string)
130 return callback(new Error(error_string), false, video)
131 }
132
133 callback(null, true, video)
134 })
135}
133 136
134 callback(null, true, video) 137function list (callback) {
135 }) 138 VideosDB.find(function (err, videos_list) {
136 } 139 if (err) {
140 logger.error('Cannot get the list of the videos.')
141 return callback(err)
142 }
137 143
138 function list (callback) { 144 return callback(null, videos_list)
139 VideosDB.find(function (err, videos_list) { 145 })
140 if (err) { 146}
141 logger.error('Cannot get the list of the videos.')
142 return callback(err)
143 }
144 147
145 return callback(null, videos_list) 148function listOwned (callback) {
146 }) 149 // If namePath is not null this is *our* video
147 } 150 VideosDB.find({ namePath: { $ne: null } }, function (err, videos_list) {
151 if (err) {
152 logger.error('Cannot get the list of owned videos.')
153 return callback(err)
154 }
155
156 return callback(null, videos_list)
157 })
158}
159
160function removeOwned (id, callback) {
161 VideosDB.findByIdAndRemove(id, function (err, video) {
162 if (err) {
163 logger.error('Cannot remove the torrent.')
164 return callback(err)
165 }
148 166
149 function listOwned (callback) { 167 fs.unlink(uploadDir + video.namePath, function (err) {
150 // If namePath is not null this is *our* video
151 VideosDB.find({ namePath: { $ne: null } }, function (err, videos_list) {
152 if (err) { 168 if (err) {
153 logger.error('Cannot get the list of owned videos.') 169 logger.error('Cannot remove this video file.')
154 return callback(err) 170 return callback(err)
155 } 171 }
156 172
157 return callback(null, videos_list) 173 callback(null)
158 }) 174 })
159 } 175 })
160 176}
161 function removeOwned (id, callback) { 177
162 VideosDB.findByIdAndRemove(id, function (err, video) { 178function removeAllRemotes (callback) {
163 if (err) { 179 VideosDB.remove({ namePath: null }, callback)
164 logger.error('Cannot remove the torrent.') 180}
165 return callback(err) 181
182function removeAllRemotesOf (fromUrl, callback) {
183 // TODO { podUrl: { $in: urls } }
184 VideosDB.remove({ podUrl: fromUrl }, callback)
185}
186
187// Use the magnet Uri because the _id field is not the same on different servers
188function removeRemotesOfByMagnetUris (fromUrl, magnetUris, callback) {
189 if (callback === undefined) callback = function () {}
190
191 VideosDB.find({ magnetUri: { $in: magnetUris } }, function (err, videos) {
192 if (err || !videos) {
193 logger.error('Cannot find the torrent URI of these remote videos.')
194 return callback(err)
195 }
196
197 var to_remove = []
198 async.each(videos, function (video, callback_async) {
199 callback_async = dz(callback_async)
200
201 if (video.podUrl !== fromUrl) {
202 logger.error('The pod %s has not the rights on the video of %s.', fromUrl, video.podUrl)
203 } else {
204 to_remove.push(video._id)
166 } 205 }
167 206
168 fs.unlink(uploadDir + video.namePath, function (err) { 207 callback_async()
208 }, function () {
209 VideosDB.remove({ _id: { $in: to_remove } }, function (err) {
169 if (err) { 210 if (err) {
170 logger.error('Cannot remove this video file.') 211 logger.error('Cannot remove the remote videos.')
171 return callback(err) 212 return callback(err)
172 } 213 }
173 214
215 logger.info('Removed remote videos from %s.', fromUrl)
174 callback(null) 216 callback(null)
175 }) 217 })
176 }) 218 })
177 } 219 })
178 220}
179 function removeAllRemotes (callback) {
180 VideosDB.remove({ namePath: null }, callback)
181 }
182
183 function removeAllRemotesOf (fromUrl, callback) {
184 // TODO { podUrl: { $in: urls } }
185 VideosDB.remove({ podUrl: fromUrl }, callback)
186 }
187
188 // Use the magnet Uri because the _id field is not the same on different servers
189 function removeRemotesOfByMagnetUris (fromUrl, magnetUris, callback) {
190 if (callback === undefined) callback = function () {}
191
192 VideosDB.find({ magnetUri: { $in: magnetUris } }, function (err, videos) {
193 if (err || !videos) {
194 logger.error('Cannot find the torrent URI of these remote videos.')
195 return callback(err)
196 }
197
198 var to_remove = []
199 async.each(videos, function (video, callback_async) {
200 callback_async = dz(callback_async)
201
202 if (video.podUrl !== fromUrl) {
203 logger.error('The pod %s has not the rights on the video of %s.', fromUrl, video.podUrl)
204 } else {
205 to_remove.push(video._id)
206 }
207
208 callback_async()
209 }, function () {
210 VideosDB.remove({ _id: { $in: to_remove } }, function (err) {
211 if (err) {
212 logger.error('Cannot remove the remote videos.')
213 return callback(err)
214 }
215
216 logger.info('Removed remote videos from %s.', fromUrl)
217 callback(null)
218 })
219 })
220 })
221 }
222 221
223 function search (name, callback) { 222function search (name, callback) {
224 VideosDB.find({ name: new RegExp(name) }, function (err, videos) { 223 VideosDB.find({ name: new RegExp(name) }, function (err, videos) {
225 if (err) { 224 if (err) {
226 logger.error('Cannot search the videos.') 225 logger.error('Cannot search the videos.')
227 return callback(err) 226 return callback(err)
228 } 227 }
229 228
230 return callback(null, videos) 229 return callback(null, videos)
231 }) 230 })
232 } 231}
233 232
234 // --------------------------------------------------------------------------- 233// ---------------------------------------------------------------------------
235 234
236 module.exports = Videos 235module.exports = Videos
237})()
diff --git a/tests/api/checkParams.js b/tests/api/checkParams.js
index 8ce1bd476..1c1ec71b3 100644
--- a/tests/api/checkParams.js
+++ b/tests/api/checkParams.js
@@ -1,302 +1,300 @@
1;(function () { 1'use strict'
2 'use strict'
3 2
4 var async = require('async') 3var async = require('async')
5 var chai = require('chai') 4var chai = require('chai')
6 var expect = chai.expect 5var expect = chai.expect
7 var pathUtils = require('path') 6var pathUtils = require('path')
8 var request = require('supertest') 7var request = require('supertest')
9 8
10 var utils = require('./utils') 9var utils = require('./utils')
11 10
12 describe('Test parameters validator', function () { 11describe('Test parameters validator', function () {
13 var app = null 12 var app = null
14 var url = '' 13 var url = ''
15 14
16 function makePostRequest (path, fields, attach, done, fail) { 15 function makePostRequest (path, fields, attach, done, fail) {
17 var status_code = 400 16 var status_code = 400
18 if (fail !== undefined && fail === false) status_code = 200 17 if (fail !== undefined && fail === false) status_code = 200
19 18
20 var req = request(url) 19 var req = request(url)
21 .post(path) 20 .post(path)
22 .set('Accept', 'application/json') 21 .set('Accept', 'application/json')
23 22
24 Object.keys(fields).forEach(function (field) { 23 Object.keys(fields).forEach(function (field) {
25 var value = fields[field] 24 var value = fields[field]
26 req.field(field, value) 25 req.field(field, value)
27 })
28
29 req.expect(status_code, done)
30 }
31
32 function makePostBodyRequest (path, fields, done, fail) {
33 var status_code = 400
34 if (fail !== undefined && fail === false) status_code = 200
35
36 request(url)
37 .post(path)
38 .set('Accept', 'application/json')
39 .send(fields)
40 .expect(status_code, done)
41 }
42
43 // ---------------------------------------------------------------
44
45 before(function (done) {
46 this.timeout(20000)
47
48 async.series([
49 function (next) {
50 utils.flushTests(next)
51 },
52 function (next) {
53 utils.runServer(1, function (app1, url1) {
54 app = app1
55 url = url1
56 next()
57 })
58 }
59 ], done)
60 }) 26 })
61 27
62 describe('Of the pods API', function () { 28 req.expect(status_code, done)
63 var path = '/api/v1/pods/' 29 }
64 30
65 describe('When adding a pod', function () { 31 function makePostBodyRequest (path, fields, done, fail) {
66 it('Should fail with nothing', function (done) { 32 var status_code = 400
67 var data = {} 33 if (fail !== undefined && fail === false) status_code = 200
68 makePostBodyRequest(path, data, done) 34
35 request(url)
36 .post(path)
37 .set('Accept', 'application/json')
38 .send(fields)
39 .expect(status_code, done)
40 }
41
42 // ---------------------------------------------------------------
43
44 before(function (done) {
45 this.timeout(20000)
46
47 async.series([
48 function (next) {
49 utils.flushTests(next)
50 },
51 function (next) {
52 utils.runServer(1, function (app1, url1) {
53 app = app1
54 url = url1
55 next()
69 }) 56 })
57 }
58 ], done)
59 })
60
61 describe('Of the pods API', function () {
62 var path = '/api/v1/pods/'
63
64 describe('When adding a pod', function () {
65 it('Should fail with nothing', function (done) {
66 var data = {}
67 makePostBodyRequest(path, data, done)
68 })
70 69
71 it('Should fail without public key', function (done) { 70 it('Should fail without public key', function (done) {
72 var data = { 71 var data = {
73 data: { 72 data: {
74 url: 'http://coucou.com' 73 url: 'http://coucou.com'
75 }
76 } 74 }
77 makePostBodyRequest(path, data, done) 75 }
78 }) 76 makePostBodyRequest(path, data, done)
77 })
79 78
80 it('Should fail without an url', function (done) { 79 it('Should fail without an url', function (done) {
81 var data = { 80 var data = {
82 data: { 81 data: {
83 publicKey: 'mysuperpublickey' 82 publicKey: 'mysuperpublickey'
84 }
85 } 83 }
86 makePostBodyRequest(path, data, done) 84 }
87 }) 85 makePostBodyRequest(path, data, done)
86 })
88 87
89 it('Should fail with an incorrect url', function (done) { 88 it('Should fail with an incorrect url', function (done) {
90 var data = { 89 var data = {
91 data: { 90 data: {
92 url: 'coucou.com', 91 url: 'coucou.com',
93 publicKey: 'mysuperpublickey' 92 publicKey: 'mysuperpublickey'
94 }
95 } 93 }
94 }
95 makePostBodyRequest(path, data, function () {
96 data.data.url = 'http://coucou'
96 makePostBodyRequest(path, data, function () { 97 makePostBodyRequest(path, data, function () {
97 data.data.url = 'http://coucou' 98 data.data.url = 'coucou'
98 makePostBodyRequest(path, data, function () { 99 makePostBodyRequest(path, data, done)
99 data.data.url = 'coucou'
100 makePostBodyRequest(path, data, done)
101 })
102 }) 100 })
103 }) 101 })
102 })
104 103
105 it('Should succeed with the correct parameters', function (done) { 104 it('Should succeed with the correct parameters', function (done) {
106 var data = { 105 var data = {
107 data: { 106 data: {
108 url: 'http://coucou.com', 107 url: 'http://coucou.com',
109 publicKey: 'mysuperpublickey' 108 publicKey: 'mysuperpublickey'
110 }
111 } 109 }
112 makePostBodyRequest(path, data, done, false) 110 }
113 }) 111 makePostBodyRequest(path, data, done, false)
114 }) 112 })
115 }) 113 })
114 })
116 115
117 describe('Of the videos API', function () { 116 describe('Of the videos API', function () {
118 var path = '/api/v1/videos/' 117 var path = '/api/v1/videos/'
119 118
120 describe('When searching a video', function () { 119 describe('When searching a video', function () {
121 it('Should fail with nothing', function (done) { 120 it('Should fail with nothing', function (done) {
122 request(url) 121 request(url)
123 .get(pathUtils.join(path, 'search')) 122 .get(pathUtils.join(path, 'search'))
124 .set('Accept', 'application/json') 123 .set('Accept', 'application/json')
125 .expect(400, done) 124 .expect(400, done)
126 })
127 }) 125 })
126 })
128 127
129 describe('When adding a video', function () { 128 describe('When adding a video', function () {
130 it('Should fail with nothing', function (done) { 129 it('Should fail with nothing', function (done) {
131 var data = {} 130 var data = {}
132 var attach = {} 131 var attach = {}
133 makePostRequest(path, data, attach, done) 132 makePostRequest(path, data, attach, done)
134 }) 133 })
135 134
136 it('Should fail without name', function (done) { 135 it('Should fail without name', function (done) {
137 var data = { 136 var data = {
138 description: 'my super description' 137 description: 'my super description'
139 } 138 }
140 var attach = { 139 var attach = {
141 'input_video': pathUtils.join(__dirname, 'fixtures', 'video_short.webm') 140 'input_video': pathUtils.join(__dirname, 'fixtures', 'video_short.webm')
142 } 141 }
143 makePostRequest(path, data, attach, done) 142 makePostRequest(path, data, attach, done)
144 }) 143 })
145 144
146 it('Should fail with a long name', function (done) { 145 it('Should fail with a long name', function (done) {
147 var data = { 146 var data = {
148 name: 'My very very very very very very very very very very very very very very very very long name', 147 name: 'My very very very very very very very very very very very very very very very very long name',
149 description: 'my super description' 148 description: 'my super description'
150 } 149 }
151 var attach = { 150 var attach = {
152 'input_video': pathUtils.join(__dirname, 'fixtures', 'video_short.webm') 151 'input_video': pathUtils.join(__dirname, 'fixtures', 'video_short.webm')
153 } 152 }
154 makePostRequest(path, data, attach, done) 153 makePostRequest(path, data, attach, done)
155 }) 154 })
156 155
157 it('Should fail without description', function (done) { 156 it('Should fail without description', function (done) {
158 var data = { 157 var data = {
159 name: 'my super name' 158 name: 'my super name'
160 } 159 }
161 var attach = { 160 var attach = {
162 'input_video': pathUtils.join(__dirname, 'fixtures', 'video_short.webm') 161 'input_video': pathUtils.join(__dirname, 'fixtures', 'video_short.webm')
163 } 162 }
164 makePostRequest(path, data, attach, done) 163 makePostRequest(path, data, attach, done)
165 }) 164 })
166 165
167 it('Should fail with a long description', function (done) { 166 it('Should fail with a long description', function (done) {
168 var data = { 167 var data = {
169 name: 'my super name', 168 name: 'my super name',
170 description: 'my super description which is very very very very very very very very very very very very very very' + 169 description: 'my super description which is very very very very very very very very very very very very very very' +
171 'very very very very very very very very very very very very very very very very very very very very very' + 170 'very very very very very very very very very very very very very very very very very very very very very' +
172 'very very very very very very very very very very very very very very very long' 171 'very very very very very very very very very very very very very very very long'
173 } 172 }
174 var attach = { 173 var attach = {
175 'input_video': pathUtils.join(__dirname, 'fixtures', 'video_short.webm') 174 'input_video': pathUtils.join(__dirname, 'fixtures', 'video_short.webm')
176 } 175 }
177 makePostRequest(path, data, attach, done) 176 makePostRequest(path, data, attach, done)
178 }) 177 })
179 178
180 it('Should fail without an input file', function (done) { 179 it('Should fail without an input file', function (done) {
181 var data = { 180 var data = {
182 name: 'my super name', 181 name: 'my super name',
183 description: 'my super description' 182 description: 'my super description'
184 } 183 }
185 var attach = {} 184 var attach = {}
186 makePostRequest(path, data, attach, done) 185 makePostRequest(path, data, attach, done)
187 }) 186 })
188 187
189 it('Should fail without an incorrect input file', function (done) { 188 it('Should fail without an incorrect input file', function (done) {
190 var data = { 189 var data = {
191 name: 'my super name', 190 name: 'my super name',
192 description: 'my super description' 191 description: 'my super description'
193 } 192 }
194 var attach = { 193 var attach = {
195 'input_video': pathUtils.join(__dirname, '..', 'fixtures', 'video_short_fake.webm') 194 'input_video': pathUtils.join(__dirname, '..', 'fixtures', 'video_short_fake.webm')
196 } 195 }
197 makePostRequest(path, data, attach, done) 196 makePostRequest(path, data, attach, done)
198 }) 197 })
199 198
200 it('Should succeed with the correct parameters', function (done) { 199 it('Should succeed with the correct parameters', function (done) {
201 var data = { 200 var data = {
202 name: 'my super name', 201 name: 'my super name',
203 description: 'my super description' 202 description: 'my super description'
204 } 203 }
205 var attach = { 204 var attach = {
206 'input_video': pathUtils.join(__dirname, 'fixtures', 'video_short.webm') 205 'input_video': pathUtils.join(__dirname, 'fixtures', 'video_short.webm')
207 } 206 }
207 makePostRequest(path, data, attach, function () {
208 attach.input_video = pathUtils.join(__dirname, 'fixtures', 'video_short.mp4')
208 makePostRequest(path, data, attach, function () { 209 makePostRequest(path, data, attach, function () {
209 attach.input_video = pathUtils.join(__dirname, 'fixtures', 'video_short.mp4') 210 attach.input_video = pathUtils.join(__dirname, 'fixtures', 'video_short.ogv')
210 makePostRequest(path, data, attach, function () { 211 makePostRequest(path, data, attach, done, true)
211 attach.input_video = pathUtils.join(__dirname, 'fixtures', 'video_short.ogv')
212 makePostRequest(path, data, attach, done, true)
213 }, true)
214 }, true) 212 }, true)
215 }) 213 }, true)
216 }) 214 })
215 })
217 216
218 describe('When getting a video', function () { 217 describe('When getting a video', function () {
219 it('Should return the list of the videos with nothing', function (done) { 218 it('Should return the list of the videos with nothing', function (done) {
220 request(url) 219 request(url)
221 .get(path) 220 .get(path)
222 .set('Accept', 'application/json') 221 .set('Accept', 'application/json')
223 .expect(200) 222 .expect(200)
224 .expect('Content-Type', /json/) 223 .expect('Content-Type', /json/)
225 .end(function (err, res) { 224 .end(function (err, res) {
226 if (err) throw err 225 if (err) throw err
227
228 expect(res.body).to.be.an('array')
229 expect(res.body.length).to.equal(0)
230
231 done()
232 })
233 })
234 226
235 it('Should fail without a mongodb id', function (done) { 227 expect(res.body).to.be.an('array')
236 request(url) 228 expect(res.body.length).to.equal(0)
237 .get(path + 'coucou')
238 .set('Accept', 'application/json')
239 .expect(400, done)
240 })
241 229
242 it('Should return 404 with an incorrect video', function (done) { 230 done()
243 request(url) 231 })
244 .get(path + '123456789012345678901234') 232 })
245 .set('Accept', 'application/json')
246 .expect(404, done)
247 })
248 233
249 it('Should succeed with the correct parameters') 234 it('Should fail without a mongodb id', function (done) {
235 request(url)
236 .get(path + 'coucou')
237 .set('Accept', 'application/json')
238 .expect(400, done)
250 }) 239 })
251 240
252 describe('When removing a video', function () { 241 it('Should return 404 with an incorrect video', function (done) {
253 it('Should have 404 with nothing', function (done) { 242 request(url)
254 request(url) 243 .get(path + '123456789012345678901234')
255 .delete(path) 244 .set('Accept', 'application/json')
256 .expect(404, done) 245 .expect(404, done)
257 })
258
259 it('Should fail without a mongodb id', function (done) {
260 request(url)
261 .delete(path + 'hello')
262 .expect(400, done)
263 })
264
265 it('Should fail with a video which does not exist', function (done) {
266 request(url)
267 .delete(path + '123456789012345678901234')
268 .expect(404, done)
269 })
270
271 it('Should fail with a video of another pod')
272
273 it('Should succeed with the correct parameters')
274 }) 246 })
247
248 it('Should succeed with the correct parameters')
275 }) 249 })
276 250
277 describe('Of the remote videos API', function () { 251 describe('When removing a video', function () {
278 describe('When making a secure request', function () { 252 it('Should have 404 with nothing', function (done) {
279 it('Should check a secure request') 253 request(url)
254 .delete(path)
255 .expect(404, done)
280 }) 256 })
281 257
282 describe('When adding a video', function () { 258 it('Should fail without a mongodb id', function (done) {
283 it('Should check when adding a video') 259 request(url)
260 .delete(path + 'hello')
261 .expect(400, done)
284 }) 262 })
285 263
286 describe('When removing a video', function () { 264 it('Should fail with a video which does not exist', function (done) {
287 it('Should check when removing a video') 265 request(url)
266 .delete(path + '123456789012345678901234')
267 .expect(404, done)
288 }) 268 })
269
270 it('Should fail with a video of another pod')
271
272 it('Should succeed with the correct parameters')
289 }) 273 })
274 })
290 275
291 after(function (done) { 276 describe('Of the remote videos API', function () {
292 process.kill(-app.pid) 277 describe('When making a secure request', function () {
278 it('Should check a secure request')
279 })
293 280
294 // Keep the logs if the test failed 281 describe('When adding a video', function () {
295 if (this.ok) { 282 it('Should check when adding a video')
296 utils.flushTests(done)
297 } else {
298 done()
299 }
300 }) 283 })
284
285 describe('When removing a video', function () {
286 it('Should check when removing a video')
287 })
288 })
289
290 after(function (done) {
291 process.kill(-app.pid)
292
293 // Keep the logs if the test failed
294 if (this.ok) {
295 utils.flushTests(done)
296 } else {
297 done()
298 }
301 }) 299 })
302})() 300})
diff --git a/tests/api/friendsAdvanced.js b/tests/api/friendsAdvanced.js
index 61483bee6..9838d890f 100644
--- a/tests/api/friendsAdvanced.js
+++ b/tests/api/friendsAdvanced.js
@@ -1,252 +1,250 @@
1;(function () { 1'use strict'
2 'use strict'
3 2
4 var async = require('async') 3var async = require('async')
5 var chai = require('chai') 4var chai = require('chai')
6 var expect = chai.expect 5var expect = chai.expect
7 6
8 var utils = require('./utils') 7var utils = require('./utils')
9 8
10 describe('Test advanced friends', function () { 9describe('Test advanced friends', function () {
11 var apps = [] 10 var apps = []
12 var urls = [] 11 var urls = []
13 12
14 function makeFriends (pod_number, callback) { 13 function makeFriends (pod_number, callback) {
15 return utils.makeFriends(urls[pod_number - 1], callback) 14 return utils.makeFriends(urls[pod_number - 1], callback)
16 } 15 }
17 16
18 function quitFriends (pod_number, callback) { 17 function quitFriends (pod_number, callback) {
19 return utils.quitFriends(urls[pod_number - 1], callback) 18 return utils.quitFriends(urls[pod_number - 1], callback)
20 } 19 }
21 20
22 function getFriendsList (pod_number, end) { 21 function getFriendsList (pod_number, end) {
23 return utils.getFriendsList(urls[pod_number - 1], end) 22 return utils.getFriendsList(urls[pod_number - 1], end)
24 } 23 }
25 24
26 function uploadVideo (pod_number, callback) { 25 function uploadVideo (pod_number, callback) {
27 var name = 'my super video' 26 var name = 'my super video'
28 var description = 'my super description' 27 var description = 'my super description'
29 var fixture = 'video_short.webm' 28 var fixture = 'video_short.webm'
30 29
31 return utils.uploadVideo(urls[pod_number - 1], name, description, fixture, callback) 30 return utils.uploadVideo(urls[pod_number - 1], name, description, fixture, callback)
32 } 31 }
33 32
34 function getVideos (pod_number, callback) { 33 function getVideos (pod_number, callback) {
35 return utils.getVideosList(urls[pod_number - 1], callback) 34 return utils.getVideosList(urls[pod_number - 1], callback)
36 } 35 }
37 36
38 // --------------------------------------------------------------- 37 // ---------------------------------------------------------------
39 38
40 before(function (done) { 39 before(function (done) {
41 this.timeout(30000) 40 this.timeout(30000)
42 utils.flushAndRunMultipleServers(6, function (apps_run, urls_run) { 41 utils.flushAndRunMultipleServers(6, function (apps_run, urls_run) {
43 apps = apps_run 42 apps = apps_run
44 urls = urls_run 43 urls = urls_run
45 done() 44 done()
46 })
47 }) 45 })
46 })
48 47
49 it('Should make friends with two pod each in a different group', function (done) { 48 it('Should make friends with two pod each in a different group', function (done) {
50 this.timeout(20000) 49 this.timeout(20000)
51 50
52 async.series([ 51 async.series([
53 // Pod 3 makes friend with the first one 52 // Pod 3 makes friend with the first one
54 function (next) { 53 function (next) {
55 makeFriends(3, next) 54 makeFriends(3, next)
56 }, 55 },
57 // Pod 4 makes friend with the second one 56 // Pod 4 makes friend with the second one
58 function (next) { 57 function (next) {
59 makeFriends(4, next) 58 makeFriends(4, next)
60 }, 59 },
61 // Now if the fifth wants to make friends with the third et the first 60 // Now if the fifth wants to make friends with the third et the first
62 function (next) { 61 function (next) {
63 makeFriends(5, next) 62 makeFriends(5, next)
64 }, 63 },
65 function (next) { 64 function (next) {
66 setTimeout(next, 11000) 65 setTimeout(next, 11000)
67 }], 66 }],
68 function (err) { 67 function (err) {
68 if (err) throw err
69
70 // It should have 0 friends
71 getFriendsList(5, function (err, res) {
69 if (err) throw err 72 if (err) throw err
70 73
71 // It should have 0 friends 74 expect(res.body.length).to.equal(0)
72 getFriendsList(5, function (err, res) { 75
76 done()
77 })
78 }
79 )
80 })
81
82 it('Should quit all friends', function (done) {
83 this.timeout(10000)
84
85 async.series([
86 function (next) {
87 quitFriends(1, next)
88 },
89 function (next) {
90 quitFriends(2, next)
91 }],
92 function (err) {
93 if (err) throw err
94
95 async.each([ 1, 2, 3, 4, 5, 6 ], function (i, callback) {
96 getFriendsList(i, function (err, res) {
73 if (err) throw err 97 if (err) throw err
74 98
75 expect(res.body.length).to.equal(0) 99 expect(res.body.length).to.equal(0)
76 100
77 done() 101 callback()
78 }) 102 })
79 } 103 }, done)
80 ) 104 }
81 }) 105 )
106 })
82 107
83 it('Should quit all friends', function (done) { 108 it('Should make friends with the pods 1, 2, 3', function (done) {
84 this.timeout(10000) 109 this.timeout(150000)
85 110
86 async.series([ 111 async.series([
87 function (next) { 112 // Pods 1, 2, 3 and 4 become friends
88 quitFriends(1, next) 113 function (next) {
89 }, 114 makeFriends(2, next)
90 function (next) { 115 },
91 quitFriends(2, next) 116 function (next) {
92 }], 117 makeFriends(1, next)
93 function (err) { 118 },
119 function (next) {
120 makeFriends(4, next)
121 },
122 // Kill pod 4
123 function (next) {
124 apps[3].kill()
125 next()
126 },
127 // Expulse pod 4 from pod 1 and 2
128 function (next) {
129 uploadVideo(1, next)
130 },
131 function (next) {
132 uploadVideo(2, next)
133 },
134 function (next) {
135 setTimeout(next, 11000)
136 },
137 function (next) {
138 uploadVideo(1, next)
139 },
140 function (next) {
141 uploadVideo(2, next)
142 },
143 function (next) {
144 setTimeout(next, 20000)
145 },
146 // Rerun server 4
147 function (next) {
148 utils.runServer(4, function (app, url) {
149 apps[3] = app
150 next()
151 })
152 },
153 function (next) {
154 getFriendsList(4, function (err, res) {
94 if (err) throw err 155 if (err) throw err
95 156
96 async.each([ 1, 2, 3, 4, 5, 6 ], function (i, callback) { 157 // Pod 4 didn't know pod 1 and 2 removed it
97 getFriendsList(i, function (err, res) { 158 expect(res.body.length).to.equal(3)
98 if (err) throw err
99
100 expect(res.body.length).to.equal(0)
101 159
102 callback()
103 })
104 }, done)
105 }
106 )
107 })
108
109 it('Should make friends with the pods 1, 2, 3', function (done) {
110 this.timeout(150000)
111
112 async.series([
113 // Pods 1, 2, 3 and 4 become friends
114 function (next) {
115 makeFriends(2, next)
116 },
117 function (next) {
118 makeFriends(1, next)
119 },
120 function (next) {
121 makeFriends(4, next)
122 },
123 // Kill pod 4
124 function (next) {
125 apps[3].kill()
126 next() 160 next()
127 }, 161 })
128 // Expulse pod 4 from pod 1 and 2 162 },
129 function (next) { 163 // Pod 6 ask pod 1, 2 and 3
130 uploadVideo(1, next) 164 function (next) {
131 }, 165 makeFriends(6, next)
132 function (next) { 166 }],
133 uploadVideo(2, next) 167 function (err) {
134 }, 168 if (err) throw err
135 function (next) { 169
136 setTimeout(next, 11000) 170 getFriendsList(6, function (err, res) {
137 },
138 function (next) {
139 uploadVideo(1, next)
140 },
141 function (next) {
142 uploadVideo(2, next)
143 },
144 function (next) {
145 setTimeout(next, 20000)
146 },
147 // Rerun server 4
148 function (next) {
149 utils.runServer(4, function (app, url) {
150 apps[3] = app
151 next()
152 })
153 },
154 function (next) {
155 getFriendsList(4, function (err, res) {
156 if (err) throw err
157
158 // Pod 4 didn't know pod 1 and 2 removed it
159 expect(res.body.length).to.equal(3)
160
161 next()
162 })
163 },
164 // Pod 6 ask pod 1, 2 and 3
165 function (next) {
166 makeFriends(6, next)
167 }],
168 function (err) {
169 if (err) throw err 171 if (err) throw err
170 172
171 getFriendsList(6, function (err, res) { 173 // Pod 4 should not be our friend
172 if (err) throw err 174 var result = res.body
175 expect(result.length).to.equal(3)
176 for (var pod of result) {
177 expect(pod.url).not.equal(urls[3])
178 }
173 179
174 // Pod 4 should not be our friend 180 done()
175 var result = res.body 181 })
176 expect(result.length).to.equal(3) 182 }
177 for (var pod of result) { 183 )
178 expect(pod.url).not.equal(urls[3]) 184 })
179 }
180 185
181 done() 186 it('Should pod 1 quit friends', function (done) {
182 }) 187 this.timeout(25000)
183 } 188
184 ) 189 async.series([
185 }) 190 // Upload a video on server 3 for aditionnal tests
191 function (next) {
192 uploadVideo(3, next)
193 },
194 function (next) {
195 setTimeout(next, 15000)
196 },
197 function (next) {
198 quitFriends(1, next)
199 },
200 // Remove pod 1 from pod 2
201 function (next) {
202 getVideos(1, function (err, res) {
203 if (err) throw err
204 expect(res.body).to.be.an('array')
205 expect(res.body.length).to.equal(2)
186 206
187 it('Should pod 1 quit friends', function (done) { 207 next()
188 this.timeout(25000) 208 })
189 209 }],
190 async.series([ 210 function (err) {
191 // Upload a video on server 3 for aditionnal tests 211 if (err) throw err
192 function (next) {
193 uploadVideo(3, next)
194 },
195 function (next) {
196 setTimeout(next, 15000)
197 },
198 function (next) {
199 quitFriends(1, next)
200 },
201 // Remove pod 1 from pod 2
202 function (next) {
203 getVideos(1, function (err, res) {
204 if (err) throw err
205 expect(res.body).to.be.an('array')
206 expect(res.body.length).to.equal(2)
207 212
208 next() 213 getVideos(2, function (err, res) {
209 })
210 }],
211 function (err) {
212 if (err) throw err 214 if (err) throw err
215 expect(res.body).to.be.an('array')
216 expect(res.body.length).to.equal(3)
217 done()
218 })
219 }
220 )
221 })
213 222
214 getVideos(2, function (err, res) { 223 it('Should make friends between pod 1 and 2 and exchange their videos', function (done) {
215 if (err) throw err 224 this.timeout(20000)
216 expect(res.body).to.be.an('array') 225 makeFriends(1, function () {
217 expect(res.body.length).to.equal(3) 226 setTimeout(function () {
218 done() 227 getVideos(1, function (err, res) {
219 }) 228 if (err) throw err
220 }
221 )
222 })
223
224 it('Should make friends between pod 1 and 2 and exchange their videos', function (done) {
225 this.timeout(20000)
226 makeFriends(1, function () {
227 setTimeout(function () {
228 getVideos(1, function (err, res) {
229 if (err) throw err
230 229
231 expect(res.body).to.be.an('array') 230 expect(res.body).to.be.an('array')
232 expect(res.body.length).to.equal(5) 231 expect(res.body.length).to.equal(5)
233 232
234 done() 233 done()
235 }) 234 })
236 }, 5000) 235 }, 5000)
237 })
238 }) 236 })
237 })
239 238
240 after(function (done) { 239 after(function (done) {
241 apps.forEach(function (app) { 240 apps.forEach(function (app) {
242 process.kill(-app.pid) 241 process.kill(-app.pid)
243 })
244
245 if (this.ok) {
246 utils.flushTests(done)
247 } else {
248 done()
249 }
250 }) 242 })
243
244 if (this.ok) {
245 utils.flushTests(done)
246 } else {
247 done()
248 }
251 }) 249 })
252})() 250})
diff --git a/tests/api/friendsBasic.js b/tests/api/friendsBasic.js
index dbc918383..328724936 100644
--- a/tests/api/friendsBasic.js
+++ b/tests/api/friendsBasic.js
@@ -1,187 +1,185 @@
1;(function () { 1'use strict'
2 'use strict'
3 2
4 var async = require('async') 3var async = require('async')
5 var chai = require('chai') 4var chai = require('chai')
6 var expect = chai.expect 5var expect = chai.expect
7 var request = require('supertest') 6var request = require('supertest')
8 7
9 var utils = require('./utils') 8var utils = require('./utils')
10 9
11 describe('Test basic friends', function () { 10describe('Test basic friends', function () {
12 var apps = [] 11 var apps = []
13 var urls = [] 12 var urls = []
14 13
15 function testMadeFriends (urls, url_to_test, callback) { 14 function testMadeFriends (urls, url_to_test, callback) {
16 var friends = [] 15 var friends = []
17 for (var i = 0; i < urls.length; i++) { 16 for (var i = 0; i < urls.length; i++) {
18 if (urls[i] === url_to_test) continue 17 if (urls[i] === url_to_test) continue
19 friends.push(urls[i]) 18 friends.push(urls[i])
20 } 19 }
20
21 utils.getFriendsList(url_to_test, function (err, res) {
22 if (err) throw err
23
24 var result = res.body
25 var result_urls = [ result[0].url, result[1].url ]
26 expect(result).to.be.an('array')
27 expect(result.length).to.equal(2)
28 expect(result_urls[0]).to.not.equal(result_urls[1])
21 29
22 utils.getFriendsList(url_to_test, function (err, res) { 30 var error_string = 'Friends url do not correspond for ' + url_to_test
31 expect(friends).to.contain(result_urls[0], error_string)
32 expect(friends).to.contain(result_urls[1], error_string)
33 callback()
34 })
35 }
36
37 // ---------------------------------------------------------------
38
39 before(function (done) {
40 this.timeout(20000)
41 utils.flushAndRunMultipleServers(3, function (apps_run, urls_run) {
42 apps = apps_run
43 urls = urls_run
44 done()
45 })
46 })
47
48 it('Should not have friends', function (done) {
49 async.each(urls, function (url, callback) {
50 utils.getFriendsList(url, function (err, res) {
23 if (err) throw err 51 if (err) throw err
24 52
25 var result = res.body 53 var result = res.body
26 var result_urls = [ result[0].url, result[1].url ]
27 expect(result).to.be.an('array') 54 expect(result).to.be.an('array')
28 expect(result.length).to.equal(2) 55 expect(result.length).to.equal(0)
29 expect(result_urls[0]).to.not.equal(result_urls[1])
30
31 var error_string = 'Friends url do not correspond for ' + url_to_test
32 expect(friends).to.contain(result_urls[0], error_string)
33 expect(friends).to.contain(result_urls[1], error_string)
34 callback() 56 callback()
35 }) 57 })
36 } 58 }, done)
59 })
37 60
38 // --------------------------------------------------------------- 61 it('Should make friends', function (done) {
62 this.timeout(10000)
63
64 var path = '/api/v1/pods/makefriends'
65
66 async.series([
67 // The second pod make friend with the third
68 function (next) {
69 request(urls[1])
70 .get(path)
71 .set('Accept', 'application/json')
72 .expect(204)
73 .end(next)
74 },
75 // Wait for the request between pods
76 function (next) {
77 setTimeout(next, 1000)
78 },
79 // The second pod should have the third as a friend
80 function (next) {
81 utils.getFriendsList(urls[1], function (err, res) {
82 if (err) throw err
39 83
40 before(function (done) { 84 var result = res.body
41 this.timeout(20000) 85 expect(result).to.be.an('array')
42 utils.flushAndRunMultipleServers(3, function (apps_run, urls_run) { 86 expect(result.length).to.equal(1)
43 apps = apps_run 87 expect(result[0].url).to.be.equal(urls[2])
44 urls = urls_run
45 done()
46 })
47 })
48 88
49 it('Should not have friends', function (done) { 89 next()
50 async.each(urls, function (url, callback) { 90 })
51 utils.getFriendsList(url, function (err, res) { 91 },
92 // Same here, the third pod should have the second pod as a friend
93 function (next) {
94 utils.getFriendsList(urls[2], function (err, res) {
52 if (err) throw err 95 if (err) throw err
53 96
54 var result = res.body 97 var result = res.body
55 expect(result).to.be.an('array') 98 expect(result).to.be.an('array')
56 expect(result.length).to.equal(0) 99 expect(result.length).to.equal(1)
57 callback() 100 expect(result[0].url).to.be.equal(urls[1])
101
102 next()
58 }) 103 })
104 },
105 // Finally the first pod make friend with the second pod
106 function (next) {
107 request(urls[0])
108 .get(path)
109 .set('Accept', 'application/json')
110 .expect(204)
111 .end(next)
112 },
113 // Wait for the request between pods
114 function (next) {
115 setTimeout(next, 1000)
116 }
117 ],
118 // Now each pod should be friend with the other ones
119 function (err) {
120 if (err) throw err
121 async.each(urls, function (url, callback) {
122 testMadeFriends(urls, url, callback)
59 }, done) 123 }, done)
60 }) 124 })
125 })
61 126
62 it('Should make friends', function (done) { 127 it('Should not be allowed to make friend again', function (done) {
63 this.timeout(10000) 128 utils.makeFriends(urls[1], 409, done)
64 129 })
65 var path = '/api/v1/pods/makefriends'
66
67 async.series([
68 // The second pod make friend with the third
69 function (next) {
70 request(urls[1])
71 .get(path)
72 .set('Accept', 'application/json')
73 .expect(204)
74 .end(next)
75 },
76 // Wait for the request between pods
77 function (next) {
78 setTimeout(next, 1000)
79 },
80 // The second pod should have the third as a friend
81 function (next) {
82 utils.getFriendsList(urls[1], function (err, res) {
83 if (err) throw err
84 130
85 var result = res.body 131 it('Should quit friends of pod 2', function (done) {
86 expect(result).to.be.an('array') 132 async.series([
87 expect(result.length).to.equal(1) 133 // Pod 1 quit friends
88 expect(result[0].url).to.be.equal(urls[2]) 134 function (next) {
135 utils.quitFriends(urls[1], next)
136 },
137 // Pod 1 should not have friends anymore
138 function (next) {
139 utils.getFriendsList(urls[1], function (err, res) {
140 if (err) throw err
89 141
90 next() 142 var result = res.body
91 }) 143 expect(result).to.be.an('array')
92 }, 144 expect(result.length).to.equal(0)
93 // Same here, the third pod should have the second pod as a friend 145
94 function (next) { 146 next()
95 utils.getFriendsList(urls[2], function (err, res) { 147 })
148 },
149 // Other pods shouldn't have pod 1 too
150 function (next) {
151 async.each([ urls[0], urls[2] ], function (url, callback) {
152 utils.getFriendsList(url, function (err, res) {
96 if (err) throw err 153 if (err) throw err
97 154
98 var result = res.body 155 var result = res.body
99 expect(result).to.be.an('array') 156 expect(result).to.be.an('array')
100 expect(result.length).to.equal(1) 157 expect(result.length).to.equal(1)
101 expect(result[0].url).to.be.equal(urls[1]) 158 expect(result[0].url).not.to.be.equal(urls[1])
102 159 callback()
103 next()
104 }) 160 })
105 }, 161 }, next)
106 // Finally the first pod make friend with the second pod 162 }
107 function (next) { 163 ], done)
108 request(urls[0]) 164 })
109 .get(path)
110 .set('Accept', 'application/json')
111 .expect(204)
112 .end(next)
113 },
114 // Wait for the request between pods
115 function (next) {
116 setTimeout(next, 1000)
117 }
118 ],
119 // Now each pod should be friend with the other ones
120 function (err) {
121 if (err) throw err
122 async.each(urls, function (url, callback) {
123 testMadeFriends(urls, url, callback)
124 }, done)
125 })
126 })
127
128 it('Should not be allowed to make friend again', function (done) {
129 utils.makeFriends(urls[1], 409, done)
130 })
131
132 it('Should quit friends of pod 2', function (done) {
133 async.series([
134 // Pod 1 quit friends
135 function (next) {
136 utils.quitFriends(urls[1], next)
137 },
138 // Pod 1 should not have friends anymore
139 function (next) {
140 utils.getFriendsList(urls[1], function (err, res) {
141 if (err) throw err
142
143 var result = res.body
144 expect(result).to.be.an('array')
145 expect(result.length).to.equal(0)
146 165
147 next() 166 it('Should allow pod 2 to make friend again', function (done) {
148 }) 167 utils.makeFriends(urls[1], function () {
149 }, 168 async.each(urls, function (url, callback) {
150 // Other pods shouldn't have pod 1 too 169 testMadeFriends(urls, url, callback)
151 function (next) { 170 }, done)
152 async.each([ urls[0], urls[2] ], function (url, callback) {
153 utils.getFriendsList(url, function (err, res) {
154 if (err) throw err
155
156 var result = res.body
157 expect(result).to.be.an('array')
158 expect(result.length).to.equal(1)
159 expect(result[0].url).not.to.be.equal(urls[1])
160 callback()
161 })
162 }, next)
163 }
164 ], done)
165 }) 171 })
172 })
166 173
167 it('Should allow pod 2 to make friend again', function (done) { 174 after(function (done) {
168 utils.makeFriends(urls[1], function () { 175 apps.forEach(function (app) {
169 async.each(urls, function (url, callback) { 176 process.kill(-app.pid)
170 testMadeFriends(urls, url, callback)
171 }, done)
172 })
173 }) 177 })
174 178
175 after(function (done) { 179 if (this.ok) {
176 apps.forEach(function (app) { 180 utils.flushTests(done)
177 process.kill(-app.pid) 181 } else {
178 }) 182 done()
179 183 }
180 if (this.ok) {
181 utils.flushTests(done)
182 } else {
183 done()
184 }
185 })
186 }) 184 })
187})() 185})
diff --git a/tests/api/index.js b/tests/api/index.js
index 3bdcdae2d..9c4fdd48a 100644
--- a/tests/api/index.js
+++ b/tests/api/index.js
@@ -1,10 +1,8 @@
1;(function () { 1'use strict'
2 'use strict'
3 2
4 // Order of the tests we want to execute 3// Order of the tests we want to execute
5 require('./checkParams') 4require('./checkParams')
6 require('./friendsBasic') 5require('./friendsBasic')
7 require('./singlePod') 6require('./singlePod')
8 require('./multiplePods') 7require('./multiplePods')
9 require('./friendsAdvanced') 8require('./friendsAdvanced')
10})()
diff --git a/tests/api/multiplePods.js b/tests/api/multiplePods.js
index 7949da80a..9fdd0f308 100644
--- a/tests/api/multiplePods.js
+++ b/tests/api/multiplePods.js
@@ -1,330 +1,328 @@
1;(function () { 1'use strict'
2 'use strict' 2
3var async = require('async')
4var chai = require('chai')
5var expect = chai.expect
6var pathUtils = require('path')
7
8var utils = require('./utils')
9var webtorrent = require(pathUtils.join(__dirname, '../../lib/webtorrent'))
10webtorrent.silent = true
11
12describe('Test multiple pods', function () {
13 var apps = []
14 var urls = []
15 var to_remove = []
16
17 before(function (done) {
18 this.timeout(30000)
19
20 async.series([
21 // Run servers
22 function (next) {
23 utils.flushAndRunMultipleServers(3, function (apps_run, urls_run) {
24 apps = apps_run
25 urls = urls_run
26 next()
27 })
28 },
29 // The second pod make friend with the third
30 function (next) {
31 utils.makeFriends(urls[1], next)
32 },
33 // Wait for the request between pods
34 function (next) {
35 setTimeout(next, 10000)
36 },
37 // Pod 1 make friends too
38 function (next) {
39 utils.makeFriends(urls[0], next)
40 },
41 function (next) {
42 webtorrent.create({ host: 'client', port: '1' }, next)
43 }
44 ], done)
45 })
3 46
4 var async = require('async') 47 it('Should not have videos for all pods', function (done) {
5 var chai = require('chai') 48 async.each(urls, function (url, callback) {
6 var expect = chai.expect 49 utils.getVideosList(url, function (err, res) {
7 var pathUtils = require('path') 50 if (err) throw err
8 51
9 var utils = require('./utils') 52 expect(res.body).to.be.an('array')
10 var webtorrent = require(pathUtils.join(__dirname, '../../lib/webtorrent')) 53 expect(res.body.length).to.equal(0)
11 webtorrent.silent = true
12 54
13 describe('Test multiple pods', function () { 55 callback()
14 var apps = [] 56 })
15 var urls = [] 57 }, done)
16 var to_remove = [] 58 })
17 59
18 before(function (done) { 60 describe('Should upload the video and propagate on each pod', function () {
19 this.timeout(30000) 61 it('Should upload the video on pod 1 and propagate on each pod', function (done) {
62 this.timeout(15000)
20 63
21 async.series([ 64 async.series([
22 // Run servers
23 function (next) {
24 utils.flushAndRunMultipleServers(3, function (apps_run, urls_run) {
25 apps = apps_run
26 urls = urls_run
27 next()
28 })
29 },
30 // The second pod make friend with the third
31 function (next) { 65 function (next) {
32 utils.makeFriends(urls[1], next) 66 utils.uploadVideo(urls[0], 'my super name for pod 1', 'my super description for pod 1', 'video_short1.webm', next)
33 }, 67 },
34 // Wait for the request between pods
35 function (next) { 68 function (next) {
36 setTimeout(next, 10000) 69 setTimeout(next, 11000)
37 }, 70 }],
38 // Pod 1 make friends too 71 // All pods should have this video
72 function (err) {
73 if (err) throw err
74
75 async.each(urls, function (url, callback) {
76 var base_magnet = null
77
78 utils.getVideosList(url, function (err, res) {
79 if (err) throw err
80
81 var videos = res.body
82 expect(videos).to.be.an('array')
83 expect(videos.length).to.equal(1)
84 var video = videos[0]
85 expect(video.name).to.equal('my super name for pod 1')
86 expect(video.description).to.equal('my super description for pod 1')
87 expect(video.podUrl).to.equal('http://localhost:9001')
88 expect(video.magnetUri).to.exist
89
90 // All pods should have the same magnet Uri
91 if (base_magnet === null) {
92 base_magnet = video.magnetUri
93 } else {
94 expect(video.magnetUri).to.equal.magnetUri
95 }
96
97 callback()
98 })
99 }, done)
100 }
101 )
102 })
103
104 it('Should upload the video on pod 2 and propagate on each pod', function (done) {
105 this.timeout(15000)
106
107 async.series([
39 function (next) { 108 function (next) {
40 utils.makeFriends(urls[0], next) 109 utils.uploadVideo(urls[1], 'my super name for pod 2', 'my super description for pod 2', 'video_short2.webm', next)
41 }, 110 },
42 function (next) { 111 function (next) {
43 webtorrent.create({ host: 'client', port: '1' }, next) 112 setTimeout(next, 11000)
113 }],
114 // All pods should have this video
115 function (err) {
116 if (err) throw err
117
118 async.each(urls, function (url, callback) {
119 var base_magnet = null
120
121 utils.getVideosList(url, function (err, res) {
122 if (err) throw err
123
124 var videos = res.body
125 expect(videos).to.be.an('array')
126 expect(videos.length).to.equal(2)
127 var video = videos[1]
128 expect(video.name).to.equal('my super name for pod 2')
129 expect(video.description).to.equal('my super description for pod 2')
130 expect(video.podUrl).to.equal('http://localhost:9002')
131 expect(video.magnetUri).to.exist
132
133 // All pods should have the same magnet Uri
134 if (base_magnet === null) {
135 base_magnet = video.magnetUri
136 } else {
137 expect(video.magnetUri).to.equal.magnetUri
138 }
139
140 callback()
141 })
142 }, done)
44 } 143 }
45 ], done) 144 )
46 }) 145 })
47 146
48 it('Should not have videos for all pods', function (done) { 147 it('Should upload two videos on pod 3 and propagate on each pod', function (done) {
49 async.each(urls, function (url, callback) { 148 this.timeout(30000)
50 utils.getVideosList(url, function (err, res) {
51 if (err) throw err
52 149
53 expect(res.body).to.be.an('array') 150 async.series([
54 expect(res.body.length).to.equal(0) 151 function (next) {
152 utils.uploadVideo(urls[2], 'my super name for pod 3', 'my super description for pod 3', 'video_short3.webm', next)
153 },
154 function (next) {
155 utils.uploadVideo(urls[2], 'my super name for pod 3-2', 'my super description for pod 3-2', 'video_short.webm', next)
156 },
157 function (next) {
158 setTimeout(next, 22000)
159 }],
160 function (err) {
161 if (err) throw err
55 162
56 callback() 163 var base_magnet = null
57 }) 164 // All pods should have this video
58 }, done) 165 async.each(urls, function (url, callback) {
166 utils.getVideosList(url, function (err, res) {
167 if (err) throw err
168
169 var videos = res.body
170 expect(videos).to.be.an('array')
171 expect(videos.length).to.equal(4)
172 var video = videos[2]
173 expect(video.name).to.equal('my super name for pod 3')
174 expect(video.description).to.equal('my super description for pod 3')
175 expect(video.podUrl).to.equal('http://localhost:9003')
176 expect(video.magnetUri).to.exist
177
178 video = videos[3]
179 expect(video.name).to.equal('my super name for pod 3-2')
180 expect(video.description).to.equal('my super description for pod 3-2')
181 expect(video.podUrl).to.equal('http://localhost:9003')
182 expect(video.magnetUri).to.exist
183
184 // All pods should have the same magnet Uri
185 if (base_magnet === null) {
186 base_magnet = video.magnetUri
187 } else {
188 expect(video.magnetUri).to.equal.magnetUri
189 }
190
191 callback()
192 })
193 }, done)
194 }
195 )
59 }) 196 })
197 })
60 198
61 describe('Should upload the video and propagate on each pod', function () { 199 describe('Should seed the uploaded video', function () {
62 it('Should upload the video on pod 1 and propagate on each pod', function (done) { 200 it('Should add the file 1 by asking pod 3', function (done) {
63 this.timeout(15000) 201 // Yes, this could be long
64 202 this.timeout(200000)
65 async.series([
66 function (next) {
67 utils.uploadVideo(urls[0], 'my super name for pod 1', 'my super description for pod 1', 'video_short1.webm', next)
68 },
69 function (next) {
70 setTimeout(next, 11000)
71 }],
72 // All pods should have this video
73 function (err) {
74 if (err) throw err
75
76 async.each(urls, function (url, callback) {
77 var base_magnet = null
78
79 utils.getVideosList(url, function (err, res) {
80 if (err) throw err
81
82 var videos = res.body
83 expect(videos).to.be.an('array')
84 expect(videos.length).to.equal(1)
85 var video = videos[0]
86 expect(video.name).to.equal('my super name for pod 1')
87 expect(video.description).to.equal('my super description for pod 1')
88 expect(video.podUrl).to.equal('http://localhost:9001')
89 expect(video.magnetUri).to.exist
90
91 // All pods should have the same magnet Uri
92 if (base_magnet === null) {
93 base_magnet = video.magnetUri
94 } else {
95 expect(video.magnetUri).to.equal.magnetUri
96 }
97
98 callback()
99 })
100 }, done)
101 }
102 )
103 })
104 203
105 it('Should upload the video on pod 2 and propagate on each pod', function (done) { 204 utils.getVideosList(urls[2], function (err, res) {
106 this.timeout(15000) 205 if (err) throw err
107 206
108 async.series([ 207 var video = res.body[0]
109 function (next) { 208 to_remove.push(res.body[2]._id)
110 utils.uploadVideo(urls[1], 'my super name for pod 2', 'my super description for pod 2', 'video_short2.webm', next) 209 to_remove.push(res.body[3]._id)
111 },
112 function (next) {
113 setTimeout(next, 11000)
114 }],
115 // All pods should have this video
116 function (err) {
117 if (err) throw err
118
119 async.each(urls, function (url, callback) {
120 var base_magnet = null
121
122 utils.getVideosList(url, function (err, res) {
123 if (err) throw err
124
125 var videos = res.body
126 expect(videos).to.be.an('array')
127 expect(videos.length).to.equal(2)
128 var video = videos[1]
129 expect(video.name).to.equal('my super name for pod 2')
130 expect(video.description).to.equal('my super description for pod 2')
131 expect(video.podUrl).to.equal('http://localhost:9002')
132 expect(video.magnetUri).to.exist
133
134 // All pods should have the same magnet Uri
135 if (base_magnet === null) {
136 base_magnet = video.magnetUri
137 } else {
138 expect(video.magnetUri).to.equal.magnetUri
139 }
140
141 callback()
142 })
143 }, done)
144 }
145 )
146 })
147 210
148 it('Should upload two videos on pod 3 and propagate on each pod', function (done) { 211 webtorrent.add(video.magnetUri, function (torrent) {
149 this.timeout(30000) 212 expect(torrent.files).to.exist
150 213 expect(torrent.files.length).to.equal(1)
151 async.series([ 214 expect(torrent.files[0].path).to.exist.and.to.not.equal('')
152 function (next) {
153 utils.uploadVideo(urls[2], 'my super name for pod 3', 'my super description for pod 3', 'video_short3.webm', next)
154 },
155 function (next) {
156 utils.uploadVideo(urls[2], 'my super name for pod 3-2', 'my super description for pod 3-2', 'video_short.webm', next)
157 },
158 function (next) {
159 setTimeout(next, 22000)
160 }],
161 function (err) {
162 if (err) throw err
163 215
164 var base_magnet = null 216 done()
165 // All pods should have this video 217 })
166 async.each(urls, function (url, callback) {
167 utils.getVideosList(url, function (err, res) {
168 if (err) throw err
169
170 var videos = res.body
171 expect(videos).to.be.an('array')
172 expect(videos.length).to.equal(4)
173 var video = videos[2]
174 expect(video.name).to.equal('my super name for pod 3')
175 expect(video.description).to.equal('my super description for pod 3')
176 expect(video.podUrl).to.equal('http://localhost:9003')
177 expect(video.magnetUri).to.exist
178
179 video = videos[3]
180 expect(video.name).to.equal('my super name for pod 3-2')
181 expect(video.description).to.equal('my super description for pod 3-2')
182 expect(video.podUrl).to.equal('http://localhost:9003')
183 expect(video.magnetUri).to.exist
184
185 // All pods should have the same magnet Uri
186 if (base_magnet === null) {
187 base_magnet = video.magnetUri
188 } else {
189 expect(video.magnetUri).to.equal.magnetUri
190 }
191
192 callback()
193 })
194 }, done)
195 }
196 )
197 }) 218 })
198 }) 219 })
199 220
200 describe('Should seed the uploaded video', function () { 221 it('Should add the file 2 by asking pod 1', function (done) {
201 it('Should add the file 1 by asking pod 3', function (done) { 222 // Yes, this could be long
202 // Yes, this could be long 223 this.timeout(200000)
203 this.timeout(200000)
204 224
205 utils.getVideosList(urls[2], function (err, res) { 225 utils.getVideosList(urls[0], function (err, res) {
206 if (err) throw err 226 if (err) throw err
207 227
208 var video = res.body[0] 228 var video = res.body[1]
209 to_remove.push(res.body[2]._id)
210 to_remove.push(res.body[3]._id)
211 229
212 webtorrent.add(video.magnetUri, function (torrent) { 230 webtorrent.add(video.magnetUri, function (torrent) {
213 expect(torrent.files).to.exist 231 expect(torrent.files).to.exist
214 expect(torrent.files.length).to.equal(1) 232 expect(torrent.files.length).to.equal(1)
215 expect(torrent.files[0].path).to.exist.and.to.not.equal('') 233 expect(torrent.files[0].path).to.exist.and.to.not.equal('')
216 234
217 done() 235 done()
218 })
219 }) 236 })
220 }) 237 })
238 })
221 239
222 it('Should add the file 2 by asking pod 1', function (done) { 240 it('Should add the file 3 by asking pod 2', function (done) {
223 // Yes, this could be long 241 // Yes, this could be long
224 this.timeout(200000) 242 this.timeout(200000)
225 243
226 utils.getVideosList(urls[0], function (err, res) { 244 utils.getVideosList(urls[1], function (err, res) {
227 if (err) throw err 245 if (err) throw err
228 246
229 var video = res.body[1] 247 var video = res.body[2]
230 248
231 webtorrent.add(video.magnetUri, function (torrent) { 249 webtorrent.add(video.magnetUri, function (torrent) {
232 expect(torrent.files).to.exist 250 expect(torrent.files).to.exist
233 expect(torrent.files.length).to.equal(1) 251 expect(torrent.files.length).to.equal(1)
234 expect(torrent.files[0].path).to.exist.and.to.not.equal('') 252 expect(torrent.files[0].path).to.exist.and.to.not.equal('')
235 253
236 done() 254 done()
237 })
238 }) 255 })
239 }) 256 })
257 })
240 258
241 it('Should add the file 3 by asking pod 2', function (done) { 259 it('Should add the file 3-2 by asking pod 1', function (done) {
242 // Yes, this could be long 260 // Yes, this could be long
243 this.timeout(200000) 261 this.timeout(200000)
244 262
245 utils.getVideosList(urls[1], function (err, res) { 263 utils.getVideosList(urls[0], function (err, res) {
246 if (err) throw err 264 if (err) throw err
247 265
248 var video = res.body[2] 266 var video = res.body[3]
249 267
250 webtorrent.add(video.magnetUri, function (torrent) { 268 webtorrent.add(video.magnetUri, function (torrent) {
251 expect(torrent.files).to.exist 269 expect(torrent.files).to.exist
252 expect(torrent.files.length).to.equal(1) 270 expect(torrent.files.length).to.equal(1)
253 expect(torrent.files[0].path).to.exist.and.to.not.equal('') 271 expect(torrent.files[0].path).to.exist.and.to.not.equal('')
254 272
255 done() 273 done()
256 })
257 }) 274 })
258 }) 275 })
276 })
259 277
260 it('Should add the file 3-2 by asking pod 1', function (done) { 278 it('Should remove the file 3 and 3-2 by asking pod 3', function (done) {
261 // Yes, this could be long 279 this.timeout(15000)
262 this.timeout(200000)
263 280
264 utils.getVideosList(urls[0], function (err, res) { 281 async.series([
282 function (next) {
283 utils.removeVideo(urls[2], to_remove[0], next)
284 },
285 function (next) {
286 utils.removeVideo(urls[2], to_remove[1], next)
287 }],
288 function (err) {
265 if (err) throw err 289 if (err) throw err
290 setTimeout(done, 11000)
291 }
292 )
293 })
266 294
267 var video = res.body[3] 295 it('Should have videos 1 and 3 on each pod', function (done) {
296 async.each(urls, function (url, callback) {
297 utils.getVideosList(url, function (err, res) {
298 if (err) throw err
268 299
269 webtorrent.add(video.magnetUri, function (torrent) { 300 var videos = res.body
270 expect(torrent.files).to.exist 301 expect(videos).to.be.an('array')
271 expect(torrent.files.length).to.equal(1) 302 expect(videos.length).to.equal(2)
272 expect(torrent.files[0].path).to.exist.and.to.not.equal('') 303 expect(videos[0]._id).not.to.equal(videos[1]._id)
304 expect(videos[0]._id).not.to.equal(to_remove[0])
305 expect(videos[1]._id).not.to.equal(to_remove[0])
306 expect(videos[0]._id).not.to.equal(to_remove[1])
307 expect(videos[1]._id).not.to.equal(to_remove[1])
273 308
274 done() 309 callback()
275 })
276 }) 310 })
277 }) 311 }, done)
278
279 it('Should remove the file 3 and 3-2 by asking pod 3', function (done) {
280 this.timeout(15000)
281
282 async.series([
283 function (next) {
284 utils.removeVideo(urls[2], to_remove[0], next)
285 },
286 function (next) {
287 utils.removeVideo(urls[2], to_remove[1], next)
288 }],
289 function (err) {
290 if (err) throw err
291 setTimeout(done, 11000)
292 }
293 )
294 })
295
296 it('Should have videos 1 and 3 on each pod', function (done) {
297 async.each(urls, function (url, callback) {
298 utils.getVideosList(url, function (err, res) {
299 if (err) throw err
300
301 var videos = res.body
302 expect(videos).to.be.an('array')
303 expect(videos.length).to.equal(2)
304 expect(videos[0]._id).not.to.equal(videos[1]._id)
305 expect(videos[0]._id).not.to.equal(to_remove[0])
306 expect(videos[1]._id).not.to.equal(to_remove[0])
307 expect(videos[0]._id).not.to.equal(to_remove[1])
308 expect(videos[1]._id).not.to.equal(to_remove[1])
309
310 callback()
311 })
312 }, done)
313 })
314 }) 312 })
313 })
315 314
316 after(function (done) { 315 after(function (done) {
317 apps.forEach(function (app) { 316 apps.forEach(function (app) {
318 process.kill(-app.pid) 317 process.kill(-app.pid)
319 })
320 process.kill(-webtorrent.app.pid)
321
322 // Keep the logs if the test failed
323 if (this.ok) {
324 utils.flushTests(done)
325 } else {
326 done()
327 }
328 }) 318 })
319 process.kill(-webtorrent.app.pid)
320
321 // Keep the logs if the test failed
322 if (this.ok) {
323 utils.flushTests(done)
324 } else {
325 done()
326 }
329 }) 327 })
330})() 328})
diff --git a/tests/api/singlePod.js b/tests/api/singlePod.js
index f33aa8c7a..3dd72c01b 100644
--- a/tests/api/singlePod.js
+++ b/tests/api/singlePod.js
@@ -1,148 +1,146 @@
1;(function () { 1'use strict'
2 'use strict' 2
3 3var async = require('async')
4 var async = require('async') 4var chai = require('chai')
5 var chai = require('chai') 5var expect = chai.expect
6 var expect = chai.expect 6var fs = require('fs')
7 var fs = require('fs') 7var pathUtils = require('path')
8 var pathUtils = require('path') 8
9 9var webtorrent = require(pathUtils.join(__dirname, '../../lib/webtorrent'))
10 var webtorrent = require(pathUtils.join(__dirname, '../../lib/webtorrent')) 10webtorrent.silent = true
11 webtorrent.silent = true 11
12 12var utils = require('./utils')
13 var utils = require('./utils') 13
14 14describe('Test a single pod', function () {
15 describe('Test a single pod', function () { 15 var app = null
16 var app = null 16 var url = ''
17 var url = '' 17 var video_id = -1
18 var video_id = -1 18
19 19 before(function (done) {
20 before(function (done) { 20 this.timeout(20000)
21 this.timeout(20000) 21
22 22 async.series([
23 async.series([ 23 function (next) {
24 function (next) { 24 utils.flushTests(next)
25 utils.flushTests(next) 25 },
26 }, 26 function (next) {
27 function (next) { 27 utils.runServer(1, function (app1, url1) {
28 utils.runServer(1, function (app1, url1) { 28 app = app1
29 app = app1 29 url = url1
30 url = url1 30 next()
31 next() 31 })
32 }) 32 },
33 }, 33 function (next) {
34 function (next) { 34 webtorrent.create({ host: 'client', port: '1' }, next)
35 webtorrent.create({ host: 'client', port: '1' }, next) 35 }
36 } 36 ], done)
37 ], done) 37 })
38 })
39 38
40 it('Should not have videos', function (done) { 39 it('Should not have videos', function (done) {
41 utils.getVideosList(url, function (err, res) { 40 utils.getVideosList(url, function (err, res) {
42 if (err) throw err 41 if (err) throw err
43 42
44 expect(res.body).to.be.an('array') 43 expect(res.body).to.be.an('array')
45 expect(res.body.length).to.equal(0) 44 expect(res.body.length).to.equal(0)
46 45
47 done() 46 done()
48 })
49 }) 47 })
48 })
50 49
51 it('Should upload the video', function (done) { 50 it('Should upload the video', function (done) {
52 this.timeout(5000) 51 this.timeout(5000)
53 utils.uploadVideo(url, 'my super name', 'my super description', 'video_short.webm', done) 52 utils.uploadVideo(url, 'my super name', 'my super description', 'video_short.webm', done)
54 }) 53 })
55 54
56 it('Should seed the uploaded video', function (done) { 55 it('Should seed the uploaded video', function (done) {
57 // Yes, this could be long 56 // Yes, this could be long
58 this.timeout(60000) 57 this.timeout(60000)
59 58
60 utils.getVideosList(url, function (err, res) { 59 utils.getVideosList(url, function (err, res) {
61 if (err) throw err 60 if (err) throw err
62 61
63 expect(res.body).to.be.an('array') 62 expect(res.body).to.be.an('array')
64 expect(res.body.length).to.equal(1) 63 expect(res.body.length).to.equal(1)
65 64
66 var video = res.body[0] 65 var video = res.body[0]
67 expect(video.name).to.equal('my super name') 66 expect(video.name).to.equal('my super name')
68 expect(video.description).to.equal('my super description') 67 expect(video.description).to.equal('my super description')
69 expect(video.podUrl).to.equal('http://localhost:9001') 68 expect(video.podUrl).to.equal('http://localhost:9001')
70 expect(video.magnetUri).to.exist 69 expect(video.magnetUri).to.exist
71 70
72 video_id = video._id 71 video_id = video._id
73 72
74 webtorrent.add(video.magnetUri, function (torrent) { 73 webtorrent.add(video.magnetUri, function (torrent) {
75 expect(torrent.files).to.exist 74 expect(torrent.files).to.exist
76 expect(torrent.files.length).to.equal(1) 75 expect(torrent.files.length).to.equal(1)
77 expect(torrent.files[0].path).to.exist.and.to.not.equal('') 76 expect(torrent.files[0].path).to.exist.and.to.not.equal('')
78 77
79 done() 78 done()
80 })
81 }) 79 })
82 }) 80 })
81 })
83 82
84 it('Should search the video', function (done) { 83 it('Should search the video', function (done) {
85 utils.searchVideo(url, 'my', function (err, res) { 84 utils.searchVideo(url, 'my', function (err, res) {
86 if (err) throw err 85 if (err) throw err
87 86
88 expect(res.body).to.be.an('array') 87 expect(res.body).to.be.an('array')
89 expect(res.body.length).to.equal(1) 88 expect(res.body.length).to.equal(1)
90 89
91 var video = res.body[0] 90 var video = res.body[0]
92 expect(video.name).to.equal('my super name') 91 expect(video.name).to.equal('my super name')
93 expect(video.description).to.equal('my super description') 92 expect(video.description).to.equal('my super description')
94 expect(video.podUrl).to.equal('http://localhost:9001') 93 expect(video.podUrl).to.equal('http://localhost:9001')
95 expect(video.magnetUri).to.exist 94 expect(video.magnetUri).to.exist
96 95
97 done() 96 done()
98 })
99 }) 97 })
98 })
100 99
101 it('Should not find a search', function (done) { 100 it('Should not find a search', function (done) {
102 utils.searchVideo(url, 'hello', function (err, res) { 101 utils.searchVideo(url, 'hello', function (err, res) {
103 if (err) throw err 102 if (err) throw err
104 103
105 expect(res.body).to.be.an('array') 104 expect(res.body).to.be.an('array')
106 expect(res.body.length).to.equal(0) 105 expect(res.body.length).to.equal(0)
107 106
108 done() 107 done()
109 })
110 }) 108 })
109 })
111 110
112 it('Should remove the video', function (done) { 111 it('Should remove the video', function (done) {
113 utils.removeVideo(url, video_id, function (err) { 112 utils.removeVideo(url, video_id, function (err) {
114 if (err) throw err 113 if (err) throw err
115 114
116 fs.readdir(pathUtils.join(__dirname, '../../test1/uploads/'), function (err, files) { 115 fs.readdir(pathUtils.join(__dirname, '../../test1/uploads/'), function (err, files) {
117 if (err) throw err 116 if (err) throw err
118 117
119 expect(files.length).to.equal(0) 118 expect(files.length).to.equal(0)
120 done() 119 done()
121 })
122 }) 120 })
123 }) 121 })
122 })
124 123
125 it('Should not have videos', function (done) { 124 it('Should not have videos', function (done) {
126 utils.getVideosList(url, function (err, res) { 125 utils.getVideosList(url, function (err, res) {
127 if (err) throw err 126 if (err) throw err
128 127
129 expect(res.body).to.be.an('array') 128 expect(res.body).to.be.an('array')
130 expect(res.body.length).to.equal(0) 129 expect(res.body.length).to.equal(0)
131 130
132 done() 131 done()
133 })
134 }) 132 })
133 })
135 134
136 after(function (done) { 135 after(function (done) {
137 process.kill(-app.pid) 136 process.kill(-app.pid)
138 process.kill(-webtorrent.app.pid) 137 process.kill(-webtorrent.app.pid)
139 138
140 // Keep the logs if the test failed 139 // Keep the logs if the test failed
141 if (this.ok) { 140 if (this.ok) {
142 utils.flushTests(done) 141 utils.flushTests(done)
143 } else { 142 } else {
144 done() 143 done()
145 } 144 }
146 })
147 }) 145 })
148})() 146})
diff --git a/tests/api/utils.js b/tests/api/utils.js
index b71e943ed..47b706294 100644
--- a/tests/api/utils.js
+++ b/tests/api/utils.js
@@ -1,187 +1,185 @@
1;(function () { 1'use strict'
2 'use strict' 2
3 3var child_process = require('child_process')
4 var child_process = require('child_process') 4var exec = child_process.exec
5 var exec = child_process.exec 5var fork = child_process.fork
6 var fork = child_process.fork 6var pathUtils = require('path')
7 var pathUtils = require('path') 7var request = require('supertest')
8 var request = require('supertest') 8
9 9var testUtils = {
10 var testUtils = { 10 flushTests: flushTests,
11 flushTests: flushTests, 11 getFriendsList: getFriendsList,
12 getFriendsList: getFriendsList, 12 getVideosList: getVideosList,
13 getVideosList: getVideosList, 13 makeFriends: makeFriends,
14 makeFriends: makeFriends, 14 quitFriends: quitFriends,
15 quitFriends: quitFriends, 15 removeVideo: removeVideo,
16 removeVideo: removeVideo, 16 flushAndRunMultipleServers: flushAndRunMultipleServers,
17 flushAndRunMultipleServers: flushAndRunMultipleServers, 17 runServer: runServer,
18 runServer: runServer, 18 searchVideo: searchVideo,
19 searchVideo: searchVideo, 19 uploadVideo: uploadVideo
20 uploadVideo: uploadVideo 20}
21
22// ---------------------- Export functions --------------------
23
24function flushTests (callback) {
25 exec(pathUtils.join(__dirname, '../../scripts/clean_test.sh'), callback)
26}
27
28function getFriendsList (url, end) {
29 var path = '/api/v1/pods/'
30
31 request(url)
32 .get(path)
33 .set('Accept', 'application/json')
34 .expect(200)
35 .expect('Content-Type', /json/)
36 .end(end)
37}
38
39function getVideosList (url, end) {
40 var path = '/api/v1/videos'
41
42 request(url)
43 .get(path)
44 .set('Accept', 'application/json')
45 .expect(200)
46 .expect('Content-Type', /json/)
47 .end(end)
48}
49
50function makeFriends (url, expected_status, callback) {
51 if (!callback) {
52 callback = expected_status
53 expected_status = 204
21 } 54 }
22 55
23 // ---------------------- Export functions -------------------- 56 var path = '/api/v1/pods/makefriends'
24 57
25 function flushTests (callback) { 58 // The first pod make friend with the third
26 exec(pathUtils.join(__dirname, '../../scripts/clean_test.sh'), callback) 59 request(url)
27 } 60 .get(path)
28 61 .set('Accept', 'application/json')
29 function getFriendsList (url, end) { 62 .expect(expected_status)
30 var path = '/api/v1/pods/' 63 .end(function (err, res) {
31 64 if (err) throw err
32 request(url)
33 .get(path)
34 .set('Accept', 'application/json')
35 .expect(200)
36 .expect('Content-Type', /json/)
37 .end(end)
38 }
39
40 function getVideosList (url, end) {
41 var path = '/api/v1/videos'
42
43 request(url)
44 .get(path)
45 .set('Accept', 'application/json')
46 .expect(200)
47 .expect('Content-Type', /json/)
48 .end(end)
49 }
50
51 function makeFriends (url, expected_status, callback) {
52 if (!callback) {
53 callback = expected_status
54 expected_status = 204
55 }
56
57 var path = '/api/v1/pods/makefriends'
58
59 // The first pod make friend with the third
60 request(url)
61 .get(path)
62 .set('Accept', 'application/json')
63 .expect(expected_status)
64 .end(function (err, res) {
65 if (err) throw err
66
67 // Wait for the request between pods
68 setTimeout(callback, 1000)
69 })
70 }
71
72 function quitFriends (url, callback) {
73 var path = '/api/v1/pods/quitfriends'
74 65
75 // The first pod make friend with the third 66 // Wait for the request between pods
76 request(url) 67 setTimeout(callback, 1000)
77 .get(path)
78 .set('Accept', 'application/json')
79 .expect(204)
80 .end(function (err, res) {
81 if (err) throw err
82
83 // Wait for the request between pods
84 setTimeout(callback, 1000)
85 })
86 }
87
88 function removeVideo (url, id, end) {
89 var path = '/api/v1/videos'
90
91 request(url)
92 .delete(path + '/' + id)
93 .set('Accept', 'application/json')
94 .expect(204)
95 .end(end)
96 }
97
98 function flushAndRunMultipleServers (total_servers, serversRun) {
99 var apps = []
100 var urls = []
101 var i = 0
102
103 function anotherServerDone (number, app, url) {
104 apps[number - 1] = app
105 urls[number - 1] = url
106 i++
107 if (i === total_servers) {
108 serversRun(apps, urls)
109 }
110 }
111
112 flushTests(function () {
113 for (var j = 1; j <= total_servers; j++) {
114 (function (k) { // TODO: ES6 with let
115 // For the virtual buffer
116 setTimeout(function () {
117 runServer(k, function (app, url) {
118 anotherServerDone(k, app, url)
119 })
120 }, 1000 * k)
121 })(j)
122 }
123 }) 68 })
124 } 69}
125 70
126 function runServer (number, callback) { 71function quitFriends (url, callback) {
127 var port = 9000 + number 72 var path = '/api/v1/pods/quitfriends'
128 var server_run_string = {
129 'Connected to mongodb': false,
130 'Server listening on port': false
131 }
132 73
133 // Share the environment 74 // The first pod make friend with the third
134 var env = Object.create(process.env) 75 request(url)
135 env.NODE_ENV = 'test' 76 .get(path)
136 env.NODE_APP_INSTANCE = number 77 .set('Accept', 'application/json')
137 var options = { 78 .expect(204)
138 silent: true, 79 .end(function (err, res) {
139 env: env, 80 if (err) throw err
140 detached: true
141 }
142
143 var app = fork(pathUtils.join(__dirname, '../../server.js'), [], options)
144 app.stdout.on('data', function onStdout (data) {
145 var dont_continue = false
146 // Check if all required sentences are here
147 for (var key of Object.keys(server_run_string)) {
148 if (data.toString().indexOf(key) !== -1) server_run_string[key] = true
149 if (server_run_string[key] === false) dont_continue = true
150 }
151 81
152 // If no, there is maybe one thing not already initialized (mongodb...) 82 // Wait for the request between pods
153 if (dont_continue === true) return 83 setTimeout(callback, 1000)
154
155 app.stdout.removeListener('data', onStdout)
156 callback(app, 'http://localhost:' + port)
157 }) 84 })
85}
86
87function removeVideo (url, id, end) {
88 var path = '/api/v1/videos'
89
90 request(url)
91 .delete(path + '/' + id)
92 .set('Accept', 'application/json')
93 .expect(204)
94 .end(end)
95}
96
97function flushAndRunMultipleServers (total_servers, serversRun) {
98 var apps = []
99 var urls = []
100 var i = 0
101
102 function anotherServerDone (number, app, url) {
103 apps[number - 1] = app
104 urls[number - 1] = url
105 i++
106 if (i === total_servers) {
107 serversRun(apps, urls)
108 }
158 } 109 }
159 110
160 function searchVideo (url, search, end) { 111 flushTests(function () {
161 var path = '/api/v1/videos' 112 for (var j = 1; j <= total_servers; j++) {
162 113 (function (k) { // TODO: ES6 with let
163 request(url) 114 // For the virtual buffer
164 .get(path + '/search/' + search) 115 setTimeout(function () {
165 .set('Accept', 'application/json') 116 runServer(k, function (app, url) {
166 .expect(200) 117 anotherServerDone(k, app, url)
167 .expect('Content-Type', /json/) 118 })
168 .end(end) 119 }, 1000 * k)
120 })(j)
121 }
122 })
123}
124
125function runServer (number, callback) {
126 var port = 9000 + number
127 var server_run_string = {
128 'Connected to mongodb': false,
129 'Server listening on port': false
169 } 130 }
170 131
171 function uploadVideo (url, name, description, fixture, end) { 132 // Share the environment
172 var path = '/api/v1/videos' 133 var env = Object.create(process.env)
173 134 env.NODE_ENV = 'test'
174 request(url) 135 env.NODE_APP_INSTANCE = number
175 .post(path) 136 var options = {
176 .set('Accept', 'application/json') 137 silent: true,
177 .field('name', name) 138 env: env,
178 .field('description', description) 139 detached: true
179 .attach('input_video', pathUtils.join(__dirname, 'fixtures', fixture))
180 .expect(201)
181 .end(end)
182 } 140 }
183 141
184 // --------------------------------------------------------------------------- 142 var app = fork(pathUtils.join(__dirname, '../../server.js'), [], options)
143 app.stdout.on('data', function onStdout (data) {
144 var dont_continue = false
145 // Check if all required sentences are here
146 for (var key of Object.keys(server_run_string)) {
147 if (data.toString().indexOf(key) !== -1) server_run_string[key] = true
148 if (server_run_string[key] === false) dont_continue = true
149 }
185 150
186 module.exports = testUtils 151 // If no, there is maybe one thing not already initialized (mongodb...)
187})() 152 if (dont_continue === true) return
153
154 app.stdout.removeListener('data', onStdout)
155 callback(app, 'http://localhost:' + port)
156 })
157}
158
159function searchVideo (url, search, end) {
160 var path = '/api/v1/videos'
161
162 request(url)
163 .get(path + '/search/' + search)
164 .set('Accept', 'application/json')
165 .expect(200)
166 .expect('Content-Type', /json/)
167 .end(end)
168}
169
170function uploadVideo (url, name, description, fixture, end) {
171 var path = '/api/v1/videos'
172
173 request(url)
174 .post(path)
175 .set('Accept', 'application/json')
176 .field('name', name)
177 .field('description', description)
178 .attach('input_video', pathUtils.join(__dirname, 'fixtures', fixture))
179 .expect(201)
180 .end(end)
181}
182
183// ---------------------------------------------------------------------------
184
185module.exports = testUtils