diff options
-rw-r--r-- | controllers/api/v1/index.js | 7 | ||||
-rw-r--r-- | controllers/api/v1/pods.js | 46 | ||||
-rw-r--r-- | controllers/api/v1/remoteVideos.js | 30 | ||||
-rw-r--r-- | controllers/api/v1/videos.js | 83 | ||||
-rw-r--r-- | controllers/index.js | 4 | ||||
-rw-r--r-- | controllers/views.js | 29 | ||||
-rw-r--r-- | helpers/customValidators.js | 15 | ||||
-rw-r--r-- | helpers/logger.js | 11 | ||||
-rw-r--r-- | helpers/utils.js | 111 | ||||
-rw-r--r-- | initializers/checker.js | 12 | ||||
-rw-r--r-- | initializers/constants.js | 39 | ||||
-rw-r--r-- | initializers/database.js | 37 | ||||
-rw-r--r-- | lib/poolRequests.js | 211 | ||||
-rw-r--r-- | lib/webTorrentNode.js | 27 | ||||
-rw-r--r-- | lib/webtorrent.js | 6 | ||||
-rw-r--r-- | middlewares/index.js | 10 | ||||
-rw-r--r-- | middlewares/misc.js | 19 | ||||
-rw-r--r-- | middlewares/reqValidators/index.js | 6 | ||||
-rw-r--r-- | middlewares/reqValidators/pods.js | 10 | ||||
-rw-r--r-- | middlewares/reqValidators/remote.js | 34 | ||||
-rw-r--r-- | middlewares/reqValidators/utils.js | 11 | ||||
-rw-r--r-- | middlewares/reqValidators/videos.js | 51 | ||||
-rw-r--r-- | models/pods.js | 120 | ||||
-rw-r--r-- | models/videos.js | 222 | ||||
-rw-r--r-- | tests/api/singlePod.js | 2 | ||||
-rw-r--r-- | tests/api/utils.js | 6 |
26 files changed, 648 insertions, 511 deletions
diff --git a/controllers/api/v1/index.js b/controllers/api/v1/index.js index f5504ad85..b16eeb0f6 100644 --- a/controllers/api/v1/index.js +++ b/controllers/api/v1/index.js | |||
@@ -2,11 +2,14 @@ | |||
2 | 'use strict' | 2 | 'use strict' |
3 | 3 | ||
4 | var express = require('express') | 4 | var express = require('express') |
5 | |||
5 | var router = express.Router() | 6 | var router = express.Router() |
6 | 7 | ||
7 | router.use('/videos', require('./videos')) | ||
8 | router.use('/remotevideos', require('./remoteVideos')) | ||
9 | router.use('/pods', require('./pods')) | 8 | router.use('/pods', require('./pods')) |
9 | router.use('/remotevideos', require('./remoteVideos')) | ||
10 | router.use('/videos', require('./videos')) | ||
11 | |||
12 | // --------------------------------------------------------------------------- | ||
10 | 13 | ||
11 | module.exports = router | 14 | module.exports = router |
12 | })() | 15 | })() |
diff --git a/controllers/api/v1/pods.js b/controllers/api/v1/pods.js index 30385bd5a..b073e85af 100644 --- a/controllers/api/v1/pods.js +++ b/controllers/api/v1/pods.js | |||
@@ -2,20 +2,27 @@ | |||
2 | 'use strict' | 2 | 'use strict' |
3 | 3 | ||
4 | var express = require('express') | 4 | var express = require('express') |
5 | var router = express.Router() | 5 | |
6 | var middleware = require('../../../middlewares') | 6 | var middleware = require('../../../middlewares') |
7 | var miscMiddleware = middleware.misc | 7 | var miscMiddleware = middleware.misc |
8 | var pods = require('../../../models/pods') | ||
8 | var reqValidator = middleware.reqValidators.pods | 9 | var reqValidator = middleware.reqValidators.pods |
9 | var secureRequest = middleware.reqValidators.remote.secureRequest | 10 | var secureRequest = middleware.reqValidators.remote.secureRequest |
10 | var pods = require('../../../models/pods') | ||
11 | 11 | ||
12 | function listPods (req, res, next) { | 12 | var router = express.Router() |
13 | pods.list(function (err, pods_list) { | ||
14 | if (err) return next(err) | ||
15 | 13 | ||
16 | res.json(pods_list) | 14 | router.get('/', miscMiddleware.cache(false), listPods) |
17 | }) | 15 | router.post('/', reqValidator.podsAdd, miscMiddleware.cache(false), addPods) |
18 | } | 16 | router.get('/makefriends', miscMiddleware.cache(false), makeFriends) |
17 | router.get('/quitfriends', miscMiddleware.cache(false), quitFriends) | ||
18 | // Post because this is a secured request | ||
19 | router.post('/remove', secureRequest, miscMiddleware.decryptBody, removePods) | ||
20 | |||
21 | // --------------------------------------------------------------------------- | ||
22 | |||
23 | module.exports = router | ||
24 | |||
25 | // --------------------------------------------------------------------------- | ||
19 | 26 | ||
20 | function addPods (req, res, next) { | 27 | function addPods (req, res, next) { |
21 | pods.add(req.body.data, function (err, json) { | 28 | pods.add(req.body.data, function (err, json) { |
@@ -25,11 +32,11 @@ | |||
25 | }) | 32 | }) |
26 | } | 33 | } |
27 | 34 | ||
28 | function removePods (req, res, next) { | 35 | function listPods (req, res, next) { |
29 | pods.remove(req.body.signature.url, function (err) { | 36 | pods.list(function (err, pods_list) { |
30 | if (err) return next(err) | 37 | if (err) return next(err) |
31 | 38 | ||
32 | res.sendStatus(204) | 39 | res.json(pods_list) |
33 | }) | 40 | }) |
34 | } | 41 | } |
35 | 42 | ||
@@ -50,20 +57,19 @@ | |||
50 | }) | 57 | }) |
51 | } | 58 | } |
52 | 59 | ||
53 | function quitFriends (req, res, next) { | 60 | function removePods (req, res, next) { |
54 | pods.quitFriends(function (err) { | 61 | pods.remove(req.body.signature.url, function (err) { |
55 | if (err) return next(err) | 62 | if (err) return next(err) |
56 | 63 | ||
57 | res.sendStatus(204) | 64 | res.sendStatus(204) |
58 | }) | 65 | }) |
59 | } | 66 | } |
60 | 67 | ||
61 | router.get('/', miscMiddleware.cache(false), listPods) | 68 | function quitFriends (req, res, next) { |
62 | router.get('/makefriends', miscMiddleware.cache(false), makeFriends) | 69 | pods.quitFriends(function (err) { |
63 | router.get('/quitfriends', miscMiddleware.cache(false), quitFriends) | 70 | if (err) return next(err) |
64 | router.post('/', reqValidator.podsAdd, miscMiddleware.cache(false), addPods) | ||
65 | // Post because this is a secured request | ||
66 | router.post('/remove', secureRequest, miscMiddleware.decryptBody, removePods) | ||
67 | 71 | ||
68 | module.exports = router | 72 | res.sendStatus(204) |
73 | }) | ||
74 | } | ||
69 | })() | 75 | })() |
diff --git a/controllers/api/v1/remoteVideos.js b/controllers/api/v1/remoteVideos.js index d534d6792..2be2fc87e 100644 --- a/controllers/api/v1/remoteVideos.js +++ b/controllers/api/v1/remoteVideos.js | |||
@@ -2,7 +2,6 @@ | |||
2 | 'use strict' | 2 | 'use strict' |
3 | 3 | ||
4 | var express = require('express') | 4 | var express = require('express') |
5 | var router = express.Router() | ||
6 | var pluck = require('lodash-node/compat/collection/pluck') | 5 | var pluck = require('lodash-node/compat/collection/pluck') |
7 | 6 | ||
8 | var middleware = require('../../../middlewares') | 7 | var middleware = require('../../../middlewares') |
@@ -10,6 +9,30 @@ | |||
10 | var reqValidator = middleware.reqValidators.remote | 9 | var reqValidator = middleware.reqValidators.remote |
11 | var videos = require('../../../models/videos') | 10 | var videos = require('../../../models/videos') |
12 | 11 | ||
12 | var router = express.Router() | ||
13 | |||
14 | router.post('/add', | ||
15 | reqValidator.secureRequest, | ||
16 | miscMiddleware.decryptBody, | ||
17 | reqValidator.remoteVideosAdd, | ||
18 | miscMiddleware.cache(false), | ||
19 | addRemoteVideos | ||
20 | ) | ||
21 | |||
22 | router.post('/remove', | ||
23 | reqValidator.secureRequest, | ||
24 | miscMiddleware.decryptBody, | ||
25 | reqValidator.remoteVideosRemove, | ||
26 | miscMiddleware.cache(false), | ||
27 | removeRemoteVideo | ||
28 | ) | ||
29 | |||
30 | // --------------------------------------------------------------------------- | ||
31 | |||
32 | module.exports = router | ||
33 | |||
34 | // --------------------------------------------------------------------------- | ||
35 | |||
13 | function addRemoteVideos (req, res, next) { | 36 | function addRemoteVideos (req, res, next) { |
14 | videos.addRemotes(req.body.data, function (err, videos) { | 37 | videos.addRemotes(req.body.data, function (err, videos) { |
15 | if (err) return next(err) | 38 | if (err) return next(err) |
@@ -25,9 +48,4 @@ | |||
25 | res.sendStatus(204) | 48 | res.sendStatus(204) |
26 | }) | 49 | }) |
27 | } | 50 | } |
28 | |||
29 | router.post('/add', reqValidator.secureRequest, miscMiddleware.decryptBody, reqValidator.remoteVideosAdd, miscMiddleware.cache(false), addRemoteVideos) | ||
30 | router.post('/remove', reqValidator.secureRequest, miscMiddleware.decryptBody, reqValidator.remoteVideosRemove, miscMiddleware.cache(false), removeRemoteVideo) | ||
31 | |||
32 | module.exports = router | ||
33 | })() | 51 | })() |
diff --git a/controllers/api/v1/videos.js b/controllers/api/v1/videos.js index aa8cb466b..64b05e32b 100644 --- a/controllers/api/v1/videos.js +++ b/controllers/api/v1/videos.js | |||
@@ -1,34 +1,50 @@ | |||
1 | ;(function () { | 1 | ;(function () { |
2 | 'use strict' | 2 | 'use strict' |
3 | 3 | ||
4 | var express = require('express') | ||
5 | var config = require('config') | 4 | var config = require('config') |
6 | var crypto = require('crypto') | 5 | var crypto = require('crypto') |
6 | var express = require('express') | ||
7 | var multer = require('multer') | 7 | var multer = require('multer') |
8 | var router = express.Router() | ||
9 | 8 | ||
10 | var middleware = require('../../../middlewares') | 9 | var middleware = require('../../../middlewares') |
11 | var miscMiddleware = middleware.misc | 10 | var miscMiddleware = middleware.misc |
12 | var reqValidator = middleware.reqValidators.videos | 11 | var reqValidator = middleware.reqValidators.videos |
13 | var videos = require('../../../models/videos') | 12 | var videos = require('../../../models/videos') |
14 | 13 | ||
14 | var router = express.Router() | ||
15 | var uploads = config.get('storage.uploads') | 15 | var uploads = config.get('storage.uploads') |
16 | 16 | ||
17 | function listVideos (req, res, next) { | 17 | // multer configuration |
18 | videos.list(function (err, videos_list) { | 18 | var storage = multer.diskStorage({ |
19 | if (err) return next(err) | 19 | destination: function (req, file, cb) { |
20 | cb(null, uploads) | ||
21 | }, | ||
20 | 22 | ||
21 | res.json(videos_list) | 23 | filename: function (req, file, cb) { |
22 | }) | 24 | var extension = '' |
23 | } | 25 | if (file.mimetype === 'video/webm') extension = 'webm' |
26 | else if (file.mimetype === 'video/mp4') extension = 'mp4' | ||
27 | else if (file.mimetype === 'video/ogg') extension = 'ogv' | ||
28 | crypto.pseudoRandomBytes(16, function (err, raw) { | ||
29 | var fieldname = err ? undefined : raw.toString('hex') | ||
30 | cb(null, fieldname + '.' + extension) | ||
31 | }) | ||
32 | } | ||
33 | }) | ||
24 | 34 | ||
25 | function searchVideos (req, res, next) { | 35 | var reqFiles = multer({ storage: storage }).fields([{ name: 'input_video', maxCount: 1 }]) |
26 | videos.search(req.params.name, function (err, videos_list) { | ||
27 | if (err) return next(err) | ||
28 | 36 | ||
29 | res.json(videos_list) | 37 | router.get('/', miscMiddleware.cache(false), listVideos) |
30 | }) | 38 | router.post('/', reqFiles, reqValidator.videosAdd, miscMiddleware.cache(false), addVideos) |
31 | } | 39 | router.get('/:id', reqValidator.videosGet, miscMiddleware.cache(false), getVideos) |
40 | router.delete('/:id', reqValidator.videosRemove, miscMiddleware.cache(false), removeVideo) | ||
41 | router.get('/search/:name', reqValidator.videosSearch, miscMiddleware.cache(false), searchVideos) | ||
42 | |||
43 | // --------------------------------------------------------------------------- | ||
44 | |||
45 | module.exports = router | ||
46 | |||
47 | // --------------------------------------------------------------------------- | ||
32 | 48 | ||
33 | function addVideos (req, res, next) { | 49 | function addVideos (req, res, next) { |
34 | videos.add({ video: req.files.input_video[0], data: req.body }, function (err) { | 50 | videos.add({ video: req.files.input_video[0], data: req.body }, function (err) { |
@@ -51,6 +67,14 @@ | |||
51 | }) | 67 | }) |
52 | } | 68 | } |
53 | 69 | ||
70 | function listVideos (req, res, next) { | ||
71 | videos.list(function (err, videos_list) { | ||
72 | if (err) return next(err) | ||
73 | |||
74 | res.json(videos_list) | ||
75 | }) | ||
76 | } | ||
77 | |||
54 | function removeVideo (req, res, next) { | 78 | function removeVideo (req, res, next) { |
55 | videos.remove(req.params.id, function (err) { | 79 | videos.remove(req.params.id, function (err) { |
56 | if (err) return next(err) | 80 | if (err) return next(err) |
@@ -59,30 +83,11 @@ | |||
59 | }) | 83 | }) |
60 | } | 84 | } |
61 | 85 | ||
62 | // multer configuration | 86 | function searchVideos (req, res, next) { |
63 | var storage = multer.diskStorage({ | 87 | videos.search(req.params.name, function (err, videos_list) { |
64 | destination: function (req, file, cb) { | 88 | if (err) return next(err) |
65 | cb(null, uploads) | ||
66 | }, | ||
67 | |||
68 | filename: function (req, file, cb) { | ||
69 | var extension = '' | ||
70 | if (file.mimetype === 'video/webm') extension = 'webm' | ||
71 | else if (file.mimetype === 'video/mp4') extension = 'mp4' | ||
72 | else if (file.mimetype === 'video/ogg') extension = 'ogv' | ||
73 | crypto.pseudoRandomBytes(16, function (err, raw) { | ||
74 | var fieldname = err ? undefined : raw.toString('hex') | ||
75 | cb(null, fieldname + '.' + extension) | ||
76 | }) | ||
77 | } | ||
78 | }) | ||
79 | var reqFiles = multer({ storage: storage }).fields([{ name: 'input_video', maxCount: 1 }]) | ||
80 | |||
81 | router.get('/', miscMiddleware.cache(false), listVideos) | ||
82 | router.post('/', reqFiles, reqValidator.videosAdd, miscMiddleware.cache(false), addVideos) | ||
83 | router.get('/search/:name', reqValidator.videosSearch, miscMiddleware.cache(false), searchVideos) | ||
84 | router.get('/:id', reqValidator.videosGet, miscMiddleware.cache(false), getVideos) | ||
85 | router.delete('/:id', reqValidator.videosRemove, miscMiddleware.cache(false), removeVideo) | ||
86 | 89 | ||
87 | module.exports = router | 90 | res.json(videos_list) |
91 | }) | ||
92 | } | ||
88 | })() | 93 | })() |
diff --git a/controllers/index.js b/controllers/index.js index 7dca002ff..770d08248 100644 --- a/controllers/index.js +++ b/controllers/index.js | |||
@@ -3,10 +3,8 @@ | |||
3 | 3 | ||
4 | var constants = require('../initializers/constants') | 4 | var constants = require('../initializers/constants') |
5 | 5 | ||
6 | var routes = { | 6 | module.exports = { |
7 | api: require('./api/' + constants.API_VERSION), | 7 | api: require('./api/' + constants.API_VERSION), |
8 | views: require('./views') | 8 | views: require('./views') |
9 | } | 9 | } |
10 | |||
11 | module.exports = routes | ||
12 | })() | 10 | })() |
diff --git a/controllers/views.js b/controllers/views.js index ebd97380e..1bb4ffe70 100644 --- a/controllers/views.js +++ b/controllers/views.js | |||
@@ -1,24 +1,29 @@ | |||
1 | ;(function () { | 1 | ;(function () { |
2 | 'use strict' | 2 | 'use strict' |
3 | 3 | ||
4 | function getPartial (req, res) { | ||
5 | var directory = req.params.directory | ||
6 | var name = req.params.name | ||
7 | |||
8 | res.render('partials/' + directory + '/' + name) | ||
9 | } | ||
10 | |||
11 | function getIndex (req, res) { | ||
12 | res.render('index') | ||
13 | } | ||
14 | |||
15 | var express = require('express') | 4 | var express = require('express') |
5 | |||
16 | var middleware = require('../middlewares').misc | 6 | var middleware = require('../middlewares').misc |
17 | 7 | ||
18 | var router = express.Router() | 8 | var router = express.Router() |
19 | 9 | ||
20 | router.get('/partials/:directory/:name', middleware.cache(), getPartial) | ||
21 | router.get(/^\/(index)?$/, middleware.cache(), getIndex) | 10 | router.get(/^\/(index)?$/, middleware.cache(), getIndex) |
11 | router.get('/partials/:directory/:name', middleware.cache(), getPartial) | ||
12 | |||
13 | // --------------------------------------------------------------------------- | ||
22 | 14 | ||
23 | module.exports = router | 15 | module.exports = router |
16 | |||
17 | // --------------------------------------------------------------------------- | ||
18 | |||
19 | function getIndex (req, res) { | ||
20 | res.render('index') | ||
21 | } | ||
22 | |||
23 | function getPartial (req, res) { | ||
24 | var directory = req.params.directory | ||
25 | var name = req.params.name | ||
26 | |||
27 | res.render('partials/' + directory + '/' + name) | ||
28 | } | ||
24 | })() | 29 | })() |
diff --git a/helpers/customValidators.js b/helpers/customValidators.js index 73c2f8461..c433e5c5d 100644 --- a/helpers/customValidators.js +++ b/helpers/customValidators.js | |||
@@ -3,9 +3,13 @@ | |||
3 | 3 | ||
4 | var validator = require('validator') | 4 | var validator = require('validator') |
5 | 5 | ||
6 | var customValidators = {} | 6 | var customValidators = { |
7 | eachIsRemoteVideosAddValid: eachIsRemoteVideosAddValid, | ||
8 | eachIsRemoteVideosRemoveValid: eachIsRemoteVideosRemoveValid, | ||
9 | isArray: isArray | ||
10 | } | ||
7 | 11 | ||
8 | customValidators.eachIsRemoteVideosAddValid = function (values) { | 12 | function eachIsRemoteVideosAddValid (values) { |
9 | return values.every(function (val) { | 13 | return values.every(function (val) { |
10 | return validator.isLength(val.name, 1, 50) && | 14 | return validator.isLength(val.name, 1, 50) && |
11 | validator.isLength(val.description, 1, 50) && | 15 | validator.isLength(val.description, 1, 50) && |
@@ -14,16 +18,17 @@ | |||
14 | }) | 18 | }) |
15 | } | 19 | } |
16 | 20 | ||
17 | customValidators.eachIsRemoteVideosRemoveValid = function (values) { | 21 | function eachIsRemoteVideosRemoveValid (values) { |
18 | return values.every(function (val) { | 22 | return values.every(function (val) { |
19 | return validator.isLength(val.magnetUri, 10) | 23 | return validator.isLength(val.magnetUri, 10) |
20 | }) | 24 | }) |
21 | } | 25 | } |
22 | 26 | ||
23 | customValidators.isArray = function (value) { | 27 | function isArray (value) { |
24 | return Array.isArray(value) | 28 | return Array.isArray(value) |
25 | } | 29 | } |
26 | 30 | ||
27 | // ----------- Export ----------- | 31 | // --------------------------------------------------------------------------- |
32 | |||
28 | module.exports = customValidators | 33 | module.exports = customValidators |
29 | })() | 34 | })() |
diff --git a/helpers/logger.js b/helpers/logger.js index 850af10cb..fa5b53708 100644 --- a/helpers/logger.js +++ b/helpers/logger.js | |||
@@ -4,11 +4,9 @@ | |||
4 | 4 | ||
5 | var config = require('config') | 5 | var config = require('config') |
6 | var winston = require('winston') | 6 | var winston = require('winston') |
7 | |||
8 | var logDir = __dirname + '/../' + config.get('storage.logs') | ||
9 | |||
10 | winston.emitErrs = true | 7 | winston.emitErrs = true |
11 | 8 | ||
9 | var logDir = __dirname + '/../' + config.get('storage.logs') | ||
12 | var logger = new winston.Logger({ | 10 | var logger = new winston.Logger({ |
13 | transports: [ | 11 | transports: [ |
14 | new winston.transports.File({ | 12 | new winston.transports.File({ |
@@ -31,10 +29,13 @@ | |||
31 | exitOnError: true | 29 | exitOnError: true |
32 | }) | 30 | }) |
33 | 31 | ||
34 | module.exports = logger | 32 | logger.stream = { |
35 | module.exports.stream = { | ||
36 | write: function (message, encoding) { | 33 | write: function (message, encoding) { |
37 | logger.info(message) | 34 | logger.info(message) |
38 | } | 35 | } |
39 | } | 36 | } |
37 | |||
38 | // --------------------------------------------------------------------------- | ||
39 | |||
40 | module.exports = logger | ||
40 | })() | 41 | })() |
diff --git a/helpers/utils.js b/helpers/utils.js index 7cdb2600d..ec46631b1 100644 --- a/helpers/utils.js +++ b/helpers/utils.js | |||
@@ -13,47 +13,29 @@ | |||
13 | var constants = require('../initializers/constants') | 13 | var constants = require('../initializers/constants') |
14 | var logger = require('./logger') | 14 | var logger = require('./logger') |
15 | 15 | ||
16 | var utils = {} | 16 | var certDir = __dirname + '/../' + config.get('storage.certs') |
17 | |||
18 | var http = config.get('webserver.https') ? 'https' : 'http' | 17 | var http = config.get('webserver.https') ? 'https' : 'http' |
19 | var host = config.get('webserver.host') | 18 | var host = config.get('webserver.host') |
20 | var port = config.get('webserver.port') | 19 | var port = config.get('webserver.port') |
21 | var algorithm = 'aes-256-ctr' | 20 | var algorithm = 'aes-256-ctr' |
22 | 21 | ||
23 | // ----------- Private functions ---------- | 22 | var utils = { |
24 | 23 | getCertDir: getCertDir, | |
25 | function makeRetryRequest (params, from_url, to_pod, signature, callbackEach) { | 24 | certsExist: certsExist, |
26 | // Append the signature | 25 | cleanForExit: cleanForExit, |
27 | if (signature) { | 26 | createCerts: createCerts, |
28 | params.json.signature = { | 27 | createCertsIfNotExist: createCertsIfNotExist, |
29 | url: from_url, | 28 | generatePassword: generatePassword, |
30 | signature: signature | 29 | makeMultipleRetryRequest: makeMultipleRetryRequest, |
31 | } | 30 | symetricEncrypt: symetricEncrypt, |
32 | } | 31 | symetricDecrypt: symetricDecrypt |
33 | |||
34 | logger.debug('Make retry requests to %s.', to_pod.url) | ||
35 | |||
36 | replay( | ||
37 | request.post(params, function (err, response, body) { | ||
38 | callbackEach(err, response, body, params.url, to_pod) | ||
39 | }), | ||
40 | { | ||
41 | retries: constants.REQUEST_RETRIES, | ||
42 | factor: 3, | ||
43 | maxTimeout: Infinity, | ||
44 | errorCodes: [ 'EADDRINFO', 'ETIMEDOUT', 'ECONNRESET', 'ESOCKETTIMEDOUT', 'ENOTFOUND', 'ECONNREFUSED' ] | ||
45 | } | ||
46 | ).on('replay', function (replay) { | ||
47 | logger.info('Replaying request to %s. Request failed: %d %s. Replay number: #%d. Will retry in: %d ms.', | ||
48 | params.url, replay.error.code, replay.error.message, replay.number, replay.delay) | ||
49 | }) | ||
50 | } | 32 | } |
51 | 33 | ||
52 | // ----------- Public attributes ---------- | 34 | function getCertDir () { |
53 | utils.certDir = __dirname + '/../' + config.get('storage.certs') | 35 | return certDir |
36 | } | ||
54 | 37 | ||
55 | // { path, data } | 38 | function makeMultipleRetryRequest (all_data, pods, callbackEach, callback) { |
56 | utils.makeMultipleRetryRequest = function (all_data, pods, callbackEach, callback) { | ||
57 | if (!callback) { | 39 | if (!callback) { |
58 | callback = callbackEach | 40 | callback = callbackEach |
59 | callbackEach = null | 41 | callbackEach = null |
@@ -64,7 +46,7 @@ | |||
64 | 46 | ||
65 | // Add signature if it is specified in the params | 47 | // Add signature if it is specified in the params |
66 | if (all_data.method === 'POST' && all_data.data && all_data.sign === true) { | 48 | if (all_data.method === 'POST' && all_data.data && all_data.sign === true) { |
67 | var myKey = ursa.createPrivateKey(fs.readFileSync(utils.certDir + 'peertube.key.pem')) | 49 | var myKey = ursa.createPrivateKey(fs.readFileSync(certDir + 'peertube.key.pem')) |
68 | signature = myKey.hashAndSign('sha256', url, 'utf8', 'hex') | 50 | signature = myKey.hashAndSign('sha256', url, 'utf8', 'hex') |
69 | } | 51 | } |
70 | 52 | ||
@@ -93,7 +75,7 @@ | |||
93 | 75 | ||
94 | // TODO: ES6 with let | 76 | // TODO: ES6 with let |
95 | ;(function (crt_copy, copy_params, copy_url, copy_pod, copy_signature) { | 77 | ;(function (crt_copy, copy_params, copy_url, copy_pod, copy_signature) { |
96 | utils.symetricEncrypt(JSON.stringify(all_data.data), function (err, dataEncrypted) { | 78 | symetricEncrypt(JSON.stringify(all_data.data), function (err, dataEncrypted) { |
97 | if (err) throw err | 79 | if (err) throw err |
98 | 80 | ||
99 | var passwordEncrypted = crt_copy.encrypt(dataEncrypted.password, 'utf8', 'hex') | 81 | var passwordEncrypted = crt_copy.encrypt(dataEncrypted.password, 'utf8', 'hex') |
@@ -115,14 +97,14 @@ | |||
115 | }, callback) | 97 | }, callback) |
116 | } | 98 | } |
117 | 99 | ||
118 | utils.certsExist = function (callback) { | 100 | function certsExist (callback) { |
119 | fs.exists(utils.certDir + 'peertube.key.pem', function (exists) { | 101 | fs.exists(certDir + 'peertube.key.pem', function (exists) { |
120 | return callback(exists) | 102 | return callback(exists) |
121 | }) | 103 | }) |
122 | } | 104 | } |
123 | 105 | ||
124 | utils.createCerts = function (callback) { | 106 | function createCerts (callback) { |
125 | utils.certsExist(function (exist) { | 107 | certsExist(function (exist) { |
126 | if (exist === true) { | 108 | if (exist === true) { |
127 | var string = 'Certs already exist.' | 109 | var string = 'Certs already exist.' |
128 | logger.warning(string) | 110 | logger.warning(string) |
@@ -130,7 +112,7 @@ | |||
130 | } | 112 | } |
131 | 113 | ||
132 | logger.info('Generating a RSA key...') | 114 | logger.info('Generating a RSA key...') |
133 | openssl.exec('genrsa', { 'out': utils.certDir + 'peertube.key.pem', '2048': false }, function (err) { | 115 | openssl.exec('genrsa', { 'out': certDir + 'peertube.key.pem', '2048': false }, function (err) { |
134 | if (err) { | 116 | if (err) { |
135 | logger.error('Cannot create private key on this pod.', { error: err }) | 117 | logger.error('Cannot create private key on this pod.', { error: err }) |
136 | return callback(err) | 118 | return callback(err) |
@@ -138,7 +120,7 @@ | |||
138 | logger.info('RSA key generated.') | 120 | logger.info('RSA key generated.') |
139 | 121 | ||
140 | logger.info('Manage public key...') | 122 | logger.info('Manage public key...') |
141 | openssl.exec('rsa', { 'in': utils.certDir + 'peertube.key.pem', 'pubout': true, 'out': utils.certDir + 'peertube.pub' }, function (err) { | 123 | openssl.exec('rsa', { 'in': certDir + 'peertube.key.pem', 'pubout': true, 'out': certDir + 'peertube.pub' }, function (err) { |
142 | if (err) { | 124 | if (err) { |
143 | logger.error('Cannot create public key on this pod .', { error: err }) | 125 | logger.error('Cannot create public key on this pod .', { error: err }) |
144 | return callback(err) | 126 | return callback(err) |
@@ -151,19 +133,19 @@ | |||
151 | }) | 133 | }) |
152 | } | 134 | } |
153 | 135 | ||
154 | utils.createCertsIfNotExist = function (callback) { | 136 | function createCertsIfNotExist (callback) { |
155 | utils.certsExist(function (exist) { | 137 | certsExist(function (exist) { |
156 | if (exist === true) { | 138 | if (exist === true) { |
157 | return callback(null) | 139 | return callback(null) |
158 | } | 140 | } |
159 | 141 | ||
160 | utils.createCerts(function (err) { | 142 | createCerts(function (err) { |
161 | return callback(err) | 143 | return callback(err) |
162 | }) | 144 | }) |
163 | }) | 145 | }) |
164 | } | 146 | } |
165 | 147 | ||
166 | utils.generatePassword = function (callback) { | 148 | function generatePassword (callback) { |
167 | crypto.randomBytes(32, function (err, buf) { | 149 | crypto.randomBytes(32, function (err, buf) { |
168 | if (err) { | 150 | if (err) { |
169 | return callback(err) | 151 | return callback(err) |
@@ -173,8 +155,8 @@ | |||
173 | }) | 155 | }) |
174 | } | 156 | } |
175 | 157 | ||
176 | utils.symetricEncrypt = function (text, callback) { | 158 | function symetricEncrypt (text, callback) { |
177 | utils.generatePassword(function (err, password) { | 159 | generatePassword(function (err, password) { |
178 | if (err) { | 160 | if (err) { |
179 | return callback(err) | 161 | return callback(err) |
180 | } | 162 | } |
@@ -186,17 +168,48 @@ | |||
186 | }) | 168 | }) |
187 | } | 169 | } |
188 | 170 | ||
189 | utils.symetricDecrypt = function (text, password) { | 171 | function symetricDecrypt (text, password) { |
190 | var decipher = crypto.createDecipher(algorithm, password) | 172 | var decipher = crypto.createDecipher(algorithm, password) |
191 | var dec = decipher.update(text, 'hex', 'utf8') | 173 | var dec = decipher.update(text, 'hex', 'utf8') |
192 | dec += decipher.final('utf8') | 174 | dec += decipher.final('utf8') |
193 | return dec | 175 | return dec |
194 | } | 176 | } |
195 | 177 | ||
196 | utils.cleanForExit = function (webtorrent_process) { | 178 | function cleanForExit (webtorrent_process) { |
197 | logger.info('Gracefully exiting') | 179 | logger.info('Gracefully exiting') |
198 | process.kill(-webtorrent_process.pid) | 180 | process.kill(-webtorrent_process.pid) |
199 | } | 181 | } |
200 | 182 | ||
183 | // --------------------------------------------------------------------------- | ||
184 | |||
201 | module.exports = utils | 185 | module.exports = utils |
186 | |||
187 | // --------------------------------------------------------------------------- | ||
188 | |||
189 | function makeRetryRequest (params, from_url, to_pod, signature, callbackEach) { | ||
190 | // Append the signature | ||
191 | if (signature) { | ||
192 | params.json.signature = { | ||
193 | url: from_url, | ||
194 | signature: signature | ||
195 | } | ||
196 | } | ||
197 | |||
198 | logger.debug('Make retry requests to %s.', to_pod.url) | ||
199 | |||
200 | replay( | ||
201 | request.post(params, function (err, response, body) { | ||
202 | callbackEach(err, response, body, params.url, to_pod) | ||
203 | }), | ||
204 | { | ||
205 | retries: constants.REQUEST_RETRIES, | ||
206 | factor: 3, | ||
207 | maxTimeout: Infinity, | ||
208 | errorCodes: [ 'EADDRINFO', 'ETIMEDOUT', 'ECONNRESET', 'ESOCKETTIMEDOUT', 'ENOTFOUND', 'ECONNREFUSED' ] | ||
209 | } | ||
210 | ).on('replay', function (replay) { | ||
211 | logger.info('Replaying request to %s. Request failed: %d %s. Replay number: #%d. Will retry in: %d ms.', | ||
212 | params.url, replay.error.code, replay.error.message, replay.number, replay.delay) | ||
213 | }) | ||
214 | } | ||
202 | })() | 215 | })() |
diff --git a/initializers/checker.js b/initializers/checker.js index 7a3a53616..7a09c02d1 100644 --- a/initializers/checker.js +++ b/initializers/checker.js | |||
@@ -4,10 +4,13 @@ | |||
4 | var config = require('config') | 4 | var config = require('config') |
5 | var mkdirp = require('mkdirp') | 5 | var mkdirp = require('mkdirp') |
6 | 6 | ||
7 | var checker = {} | 7 | var checker = { |
8 | checkConfig: checkConfig, | ||
9 | createDirectoriesIfNotExist: createDirectoriesIfNotExist | ||
10 | } | ||
8 | 11 | ||
9 | // Check the config files | 12 | // Check the config files |
10 | checker.checkConfig = function () { | 13 | function checkConfig () { |
11 | var required = [ 'listen.port', | 14 | var required = [ 'listen.port', |
12 | 'webserver.https', 'webserver.host', 'webserver.port', | 15 | 'webserver.https', 'webserver.host', 'webserver.port', |
13 | 'database.host', 'database.port', 'database.suffix', | 16 | 'database.host', 'database.port', 'database.suffix', |
@@ -25,7 +28,7 @@ | |||
25 | } | 28 | } |
26 | 29 | ||
27 | // Create directories for the storage if it doesn't exist | 30 | // Create directories for the storage if it doesn't exist |
28 | checker.createDirectoriesIfNotExist = function () { | 31 | function createDirectoriesIfNotExist () { |
29 | var storages = config.get('storage') | 32 | var storages = config.get('storage') |
30 | 33 | ||
31 | for (var key of Object.keys(storages)) { | 34 | for (var key of Object.keys(storages)) { |
@@ -40,6 +43,7 @@ | |||
40 | } | 43 | } |
41 | } | 44 | } |
42 | 45 | ||
43 | // ----------- Export ----------- | 46 | // --------------------------------------------------------------------------- |
47 | |||
44 | module.exports = checker | 48 | module.exports = checker |
45 | })() | 49 | })() |
diff --git a/initializers/constants.js b/initializers/constants.js index 00b713961..1e101a747 100644 --- a/initializers/constants.js +++ b/initializers/constants.js | |||
@@ -1,37 +1,44 @@ | |||
1 | ;(function () { | 1 | ;(function () { |
2 | 'use strict' | 2 | 'use strict' |
3 | 3 | ||
4 | var constants = {} | ||
5 | |||
6 | function isTestInstance () { | ||
7 | return (process.env.NODE_ENV === 'test') | ||
8 | } | ||
9 | |||
10 | // API version of our pod | 4 | // API version of our pod |
11 | constants.API_VERSION = 'v1' | 5 | var API_VERSION = 'v1' |
12 | 6 | ||
13 | // Score a pod has when we create it as a friend | 7 | // Score a pod has when we create it as a friend |
14 | constants.FRIEND_BASE_SCORE = 100 | 8 | var FRIEND_BASE_SCORE = 100 |
15 | 9 | ||
16 | // Time to wait between requests to the friends | 10 | // Time to wait between requests to the friends |
17 | constants.INTERVAL = 60000 | 11 | var INTERVAL = 60000 |
18 | 12 | ||
19 | // 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 |
20 | constants.PODS_SCORE = { | 14 | var PODS_SCORE = { |
21 | MALUS: -10, | 15 | MALUS: -10, |
22 | BONUS: 10 | 16 | BONUS: 10 |
23 | } | 17 | } |
24 | 18 | ||
25 | // 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...) |
26 | constants.REQUEST_RETRIES = 10 | 20 | var REQUEST_RETRIES = 10 |
27 | 21 | ||
28 | // Special constants for a test instance | 22 | // Special constants for a test instance |
29 | if (isTestInstance() === true) { | 23 | if (isTestInstance() === true) { |
30 | constants.FRIEND_BASE_SCORE = 20 | 24 | FRIEND_BASE_SCORE = 20 |
31 | constants.INTERVAL = 10000 | 25 | INTERVAL = 10000 |
32 | constants.REQUEST_RETRIES = 2 | 26 | REQUEST_RETRIES = 2 |
27 | } | ||
28 | |||
29 | // --------------------------------------------------------------------------- | ||
30 | |||
31 | module.exports = { | ||
32 | API_VERSION: API_VERSION, | ||
33 | FRIEND_BASE_SCORE: FRIEND_BASE_SCORE, | ||
34 | INTERVAL: INTERVAL, | ||
35 | PODS_SCORE: PODS_SCORE, | ||
36 | REQUEST_RETRIES: REQUEST_RETRIES | ||
33 | } | 37 | } |
34 | 38 | ||
35 | // ----------- Export ----------- | 39 | // --------------------------------------------------------------------------- |
36 | module.exports = constants | 40 | |
41 | function isTestInstance () { | ||
42 | return (process.env.NODE_ENV === 'test') | ||
43 | } | ||
37 | })() | 44 | })() |
diff --git a/initializers/database.js b/initializers/database.js index 4570d3739..e041d5c4b 100644 --- a/initializers/database.js +++ b/initializers/database.js | |||
@@ -11,17 +11,6 @@ | |||
11 | var host = config.get('database.host') | 11 | var host = config.get('database.host') |
12 | var port = config.get('database.port') | 12 | var port = config.get('database.port') |
13 | 13 | ||
14 | // ----------- Videos ----------- | ||
15 | var videosSchema = mongoose.Schema({ | ||
16 | name: String, | ||
17 | namePath: String, | ||
18 | description: String, | ||
19 | magnetUri: String, | ||
20 | podUrl: String | ||
21 | }) | ||
22 | |||
23 | var VideosDB = mongoose.model('videos', videosSchema) | ||
24 | |||
25 | // ----------- Pods ----------- | 14 | // ----------- Pods ----------- |
26 | var podsSchema = mongoose.Schema({ | 15 | var podsSchema = mongoose.Schema({ |
27 | url: String, | 16 | url: String, |
@@ -40,6 +29,25 @@ | |||
40 | 29 | ||
41 | var PoolRequestsDB = mongoose.model('poolRequests', poolRequestsSchema) | 30 | var PoolRequestsDB = mongoose.model('poolRequests', poolRequestsSchema) |
42 | 31 | ||
32 | // ----------- Videos ----------- | ||
33 | var videosSchema = mongoose.Schema({ | ||
34 | name: String, | ||
35 | namePath: String, | ||
36 | description: String, | ||
37 | magnetUri: String, | ||
38 | podUrl: String | ||
39 | }) | ||
40 | |||
41 | var VideosDB = mongoose.model('videos', videosSchema) | ||
42 | |||
43 | // --------------------------------------------------------------------------- | ||
44 | |||
45 | module.exports = { | ||
46 | PodsDB: PodsDB, | ||
47 | PoolRequestsDB: PoolRequestsDB, | ||
48 | VideosDB: VideosDB | ||
49 | } | ||
50 | |||
43 | // ----------- Connection ----------- | 51 | // ----------- Connection ----------- |
44 | 52 | ||
45 | mongoose.connect('mongodb://' + host + ':' + port + '/' + dbname) | 53 | mongoose.connect('mongodb://' + host + ':' + port + '/' + dbname) |
@@ -51,11 +59,4 @@ | |||
51 | mongoose.connection.on('open', function () { | 59 | mongoose.connection.on('open', function () { |
52 | logger.info('Connected to mongodb.') | 60 | logger.info('Connected to mongodb.') |
53 | }) | 61 | }) |
54 | |||
55 | // ----------- Export ----------- | ||
56 | module.exports = { | ||
57 | VideosDB: VideosDB, | ||
58 | PodsDB: PodsDB, | ||
59 | PoolRequestsDB: PoolRequestsDB | ||
60 | } | ||
61 | })() | 62 | })() |
diff --git a/lib/poolRequests.js b/lib/poolRequests.js index 9c7f3238b..53f47d629 100644 --- a/lib/poolRequests.js +++ b/lib/poolRequests.js | |||
@@ -2,29 +2,114 @@ | |||
2 | 'use strict' | 2 | 'use strict' |
3 | 3 | ||
4 | var async = require('async') | 4 | var async = require('async') |
5 | var pluck = require('lodash-node/compat/collection/pluck') | ||
5 | 6 | ||
6 | var constants = require('../initializers/constants') | 7 | var constants = require('../initializers/constants') |
7 | var logger = require('../helpers/logger') | ||
8 | var database = require('../initializers/database') | 8 | var database = require('../initializers/database') |
9 | var pluck = require('lodash-node/compat/collection/pluck') | 9 | var logger = require('../helpers/logger') |
10 | var PoolRequestsDB = database.PoolRequestsDB | ||
11 | var PodsDB = database.PodsDB | 10 | var PodsDB = database.PodsDB |
11 | var PoolRequestsDB = database.PoolRequestsDB | ||
12 | var utils = require('../helpers/utils') | 12 | var utils = require('../helpers/utils') |
13 | var VideosDB = database.VideosDB | 13 | var VideosDB = database.VideosDB |
14 | 14 | ||
15 | var poolRequests = {} | ||
16 | |||
17 | // ----------- Private ----------- | ||
18 | var timer = null | 15 | var timer = null |
19 | 16 | ||
20 | function removePoolRequestsFromDB (ids) { | 17 | var poolRequests = { |
21 | PoolRequestsDB.remove({ _id: { $in: ids } }, function (err) { | 18 | activate: activate, |
22 | if (err) { | 19 | addToPoolRequests: addToPoolRequests, |
23 | logger.error('Cannot remove requests from the pool requests database.', { error: err }) | 20 | deactivate: deactivate, |
24 | return | 21 | forceSend: forceSend |
22 | } | ||
23 | |||
24 | function deactivate () { | ||
25 | logger.info('Pool requests deactivated.') | ||
26 | clearInterval(timer) | ||
27 | } | ||
28 | |||
29 | function forceSend () { | ||
30 | logger.info('Force pool requests sending.') | ||
31 | makePoolRequests() | ||
32 | } | ||
33 | |||
34 | function activate () { | ||
35 | logger.info('Pool requests activated.') | ||
36 | timer = setInterval(makePoolRequests, constants.INTERVAL) | ||
37 | } | ||
38 | |||
39 | function addToPoolRequests (id, type, request) { | ||
40 | logger.debug('Add request to the pool requests.', { id: id, type: type, request: request }) | ||
41 | |||
42 | PoolRequestsDB.findOne({ id: id }, function (err, entity) { | ||
43 | if (err) logger.error(err) | ||
44 | |||
45 | if (entity) { | ||
46 | if (entity.type === type) { | ||
47 | logger.error(new Error('Cannot insert two same requests.')) | ||
48 | return | ||
49 | } | ||
50 | |||
51 | // Remove the request of the other type | ||
52 | PoolRequestsDB.remove({ id: id }, function (err) { | ||
53 | if (err) logger.error(err) | ||
54 | }) | ||
55 | } else { | ||
56 | PoolRequestsDB.create({ id: id, type: type, request: request }, function (err) { | ||
57 | if (err) logger.error(err) | ||
58 | }) | ||
25 | } | 59 | } |
60 | }) | ||
61 | } | ||
26 | 62 | ||
27 | logger.info('Pool requests flushed.') | 63 | // --------------------------------------------------------------------------- |
64 | |||
65 | module.exports = poolRequests | ||
66 | |||
67 | // --------------------------------------------------------------------------- | ||
68 | |||
69 | function makePoolRequest (type, requests, callback) { | ||
70 | if (!callback) callback = function () {} | ||
71 | |||
72 | PodsDB.find({}, { _id: 1, url: 1, publicKey: 1 }).exec(function (err, pods) { | ||
73 | if (err) throw err | ||
74 | |||
75 | var params = { | ||
76 | encrypt: true, | ||
77 | sign: true, | ||
78 | method: 'POST', | ||
79 | path: null, | ||
80 | data: requests | ||
81 | } | ||
82 | |||
83 | if (type === 'add') { | ||
84 | params.path = '/api/' + constants.API_VERSION + '/remotevideos/add' | ||
85 | } else if (type === 'remove') { | ||
86 | params.path = '/api/' + constants.API_VERSION + '/remotevideos/remove' | ||
87 | } else { | ||
88 | throw new Error('Unkown pool request type.') | ||
89 | } | ||
90 | |||
91 | var bad_pods = [] | ||
92 | var good_pods = [] | ||
93 | |||
94 | utils.makeMultipleRetryRequest(params, pods, callbackEachPodFinished, callbackAllPodsFinished) | ||
95 | |||
96 | function callbackEachPodFinished (err, response, body, url, pod, callback_each_pod_finished) { | ||
97 | if (err || (response.statusCode !== 200 && response.statusCode !== 204)) { | ||
98 | bad_pods.push(pod._id) | ||
99 | logger.error('Error sending secure request to %s pod.', url, { error: err || new Error('Status code not 20x') }) | ||
100 | } else { | ||
101 | good_pods.push(pod._id) | ||
102 | } | ||
103 | |||
104 | return callback_each_pod_finished() | ||
105 | } | ||
106 | |||
107 | function callbackAllPodsFinished (err) { | ||
108 | if (err) return callback(err) | ||
109 | |||
110 | updatePodsScore(good_pods, bad_pods) | ||
111 | callback(null) | ||
112 | } | ||
28 | }) | 113 | }) |
29 | } | 114 | } |
30 | 115 | ||
@@ -81,16 +166,6 @@ | |||
81 | }) | 166 | }) |
82 | } | 167 | } |
83 | 168 | ||
84 | function updatePodsScore (good_pods, bad_pods) { | ||
85 | logger.info('Updating %d good pods and %d bad pods scores.', good_pods.length, bad_pods.length) | ||
86 | |||
87 | PodsDB.update({ _id: { $in: good_pods } }, { $inc: { score: constants.PODS_SCORE.BONUS } }, { multi: true }).exec() | ||
88 | PodsDB.update({ _id: { $in: bad_pods } }, { $inc: { score: constants.PODS_SCORE.MALUS } }, { multi: true }, function (err) { | ||
89 | if (err) throw err | ||
90 | removeBadPods() | ||
91 | }) | ||
92 | } | ||
93 | |||
94 | function removeBadPods () { | 169 | function removeBadPods () { |
95 | PodsDB.find({ score: 0 }, { _id: 1, url: 1 }, function (err, pods) { | 170 | PodsDB.find({ score: 0 }, { _id: 1, url: 1 }, function (err, pods) { |
96 | if (err) throw err | 171 | if (err) throw err |
@@ -115,92 +190,24 @@ | |||
115 | }) | 190 | }) |
116 | } | 191 | } |
117 | 192 | ||
118 | function makePoolRequest (type, requests, callback) { | 193 | function removePoolRequestsFromDB (ids) { |
119 | if (!callback) callback = function () {} | 194 | PoolRequestsDB.remove({ _id: { $in: ids } }, function (err) { |
120 | 195 | if (err) { | |
121 | PodsDB.find({}, { _id: 1, url: 1, publicKey: 1 }).exec(function (err, pods) { | 196 | logger.error('Cannot remove requests from the pool requests database.', { error: err }) |
122 | if (err) throw err | 197 | return |
123 | |||
124 | var params = { | ||
125 | encrypt: true, | ||
126 | sign: true, | ||
127 | method: 'POST', | ||
128 | path: null, | ||
129 | data: requests | ||
130 | } | ||
131 | |||
132 | if (type === 'add') { | ||
133 | params.path = '/api/' + constants.API_VERSION + '/remotevideos/add' | ||
134 | } else if (type === 'remove') { | ||
135 | params.path = '/api/' + constants.API_VERSION + '/remotevideos/remove' | ||
136 | } else { | ||
137 | throw new Error('Unkown pool request type.') | ||
138 | } | ||
139 | |||
140 | var bad_pods = [] | ||
141 | var good_pods = [] | ||
142 | |||
143 | utils.makeMultipleRetryRequest(params, pods, callbackEachPodFinished, callbackAllPodsFinished) | ||
144 | |||
145 | function callbackEachPodFinished (err, response, body, url, pod, callback_each_pod_finished) { | ||
146 | if (err || (response.statusCode !== 200 && response.statusCode !== 204)) { | ||
147 | bad_pods.push(pod._id) | ||
148 | logger.error('Error sending secure request to %s pod.', url, { error: err || new Error('Status code not 20x') }) | ||
149 | } else { | ||
150 | good_pods.push(pod._id) | ||
151 | } | ||
152 | |||
153 | return callback_each_pod_finished() | ||
154 | } | 198 | } |
155 | 199 | ||
156 | function callbackAllPodsFinished (err) { | 200 | logger.info('Pool requests flushed.') |
157 | if (err) return callback(err) | ||
158 | |||
159 | updatePodsScore(good_pods, bad_pods) | ||
160 | callback(null) | ||
161 | } | ||
162 | }) | 201 | }) |
163 | } | 202 | } |
164 | 203 | ||
165 | // ----------- Public ----------- | 204 | function updatePodsScore (good_pods, bad_pods) { |
166 | poolRequests.activate = function () { | 205 | logger.info('Updating %d good pods and %d bad pods scores.', good_pods.length, bad_pods.length) |
167 | logger.info('Pool requests activated.') | ||
168 | timer = setInterval(makePoolRequests, constants.INTERVAL) | ||
169 | } | ||
170 | |||
171 | poolRequests.addToPoolRequests = function (id, type, request) { | ||
172 | logger.debug('Add request to the pool requests.', { id: id, type: type, request: request }) | ||
173 | |||
174 | PoolRequestsDB.findOne({ id: id }, function (err, entity) { | ||
175 | if (err) logger.error(err) | ||
176 | |||
177 | if (entity) { | ||
178 | if (entity.type === type) { | ||
179 | logger.error(new Error('Cannot insert two same requests.')) | ||
180 | return | ||
181 | } | ||
182 | 206 | ||
183 | // Remove the request of the other type | 207 | PodsDB.update({ _id: { $in: good_pods } }, { $inc: { score: constants.PODS_SCORE.BONUS } }, { multi: true }).exec() |
184 | PoolRequestsDB.remove({ id: id }, function (err) { | 208 | PodsDB.update({ _id: { $in: bad_pods } }, { $inc: { score: constants.PODS_SCORE.MALUS } }, { multi: true }, function (err) { |
185 | if (err) logger.error(err) | 209 | if (err) throw err |
186 | }) | 210 | removeBadPods() |
187 | } else { | ||
188 | PoolRequestsDB.create({ id: id, type: type, request: request }, function (err) { | ||
189 | if (err) logger.error(err) | ||
190 | }) | ||
191 | } | ||
192 | }) | 211 | }) |
193 | } | 212 | } |
194 | |||
195 | poolRequests.deactivate = function () { | ||
196 | logger.info('Pool requests deactivated.') | ||
197 | clearInterval(timer) | ||
198 | } | ||
199 | |||
200 | poolRequests.forceSend = function () { | ||
201 | logger.info('Force pool requests sending.') | ||
202 | makePoolRequests() | ||
203 | } | ||
204 | |||
205 | module.exports = poolRequests | ||
206 | })() | 213 | })() |
diff --git a/lib/webTorrentNode.js b/lib/webTorrentNode.js index 8827c68c5..69fa6b012 100644 --- a/lib/webTorrentNode.js +++ b/lib/webTorrentNode.js | |||
@@ -10,22 +10,21 @@ | |||
10 | 10 | ||
11 | var host = config.get('webserver.host') | 11 | var host = config.get('webserver.host') |
12 | var port = config.get('webserver.port') | 12 | var port = config.get('webserver.port') |
13 | |||
14 | var nodeKey = 'webtorrentnode' + port | 13 | var nodeKey = 'webtorrentnode' + port |
15 | var processKey = 'webtorrent' + port | 14 | var processKey = 'webtorrent' + port |
16 | |||
17 | ipc.config.silent = true | 15 | ipc.config.silent = true |
18 | ipc.config.id = nodeKey | 16 | ipc.config.id = nodeKey |
19 | 17 | ||
20 | var webtorrentnode = {} | 18 | var webtorrentnode = { |
21 | 19 | add: add, | |
22 | // Useful for beautiful tests | 20 | app: null, // Pid of the app |
23 | webtorrentnode.silent = false | 21 | create: create, |
24 | 22 | remove: remove, | |
25 | // Useful to kill it | 23 | seed: seed, |
26 | webtorrentnode.app = null | 24 | silent: false // Useful for beautiful tests |
25 | } | ||
27 | 26 | ||
28 | webtorrentnode.create = function (options, callback) { | 27 | function create (options, callback) { |
29 | if (typeof options === 'function') { | 28 | if (typeof options === 'function') { |
30 | callback = options | 29 | callback = options |
31 | options = {} | 30 | options = {} |
@@ -75,7 +74,7 @@ | |||
75 | ipc.server.start() | 74 | ipc.server.start() |
76 | } | 75 | } |
77 | 76 | ||
78 | webtorrentnode.seed = function (path, callback) { | 77 | function seed (path, callback) { |
79 | var extension = pathUtils.extname(path) | 78 | var extension = pathUtils.extname(path) |
80 | var basename = pathUtils.basename(path, extension) | 79 | var basename = pathUtils.basename(path, extension) |
81 | var data = { | 80 | var data = { |
@@ -104,7 +103,7 @@ | |||
104 | ipc.server.broadcast(processKey + '.seed', data) | 103 | ipc.server.broadcast(processKey + '.seed', data) |
105 | } | 104 | } |
106 | 105 | ||
107 | webtorrentnode.add = function (magnetUri, callback) { | 106 | function add (magnetUri, callback) { |
108 | var data = { | 107 | var data = { |
109 | _id: magnetUri, | 108 | _id: magnetUri, |
110 | args: { | 109 | args: { |
@@ -131,7 +130,7 @@ | |||
131 | ipc.server.broadcast(processKey + '.add', data) | 130 | ipc.server.broadcast(processKey + '.add', data) |
132 | } | 131 | } |
133 | 132 | ||
134 | webtorrentnode.remove = function (magnetUri, callback) { | 133 | function remove (magnetUri, callback) { |
135 | var data = { | 134 | var data = { |
136 | _id: magnetUri, | 135 | _id: magnetUri, |
137 | args: { | 136 | args: { |
@@ -156,5 +155,7 @@ | |||
156 | ipc.server.broadcast(processKey + '.remove', data) | 155 | ipc.server.broadcast(processKey + '.remove', data) |
157 | } | 156 | } |
158 | 157 | ||
158 | // --------------------------------------------------------------------------- | ||
159 | |||
159 | module.exports = webtorrentnode | 160 | module.exports = webtorrentnode |
160 | })() | 161 | })() |
diff --git a/lib/webtorrent.js b/lib/webtorrent.js index b72bc500d..41e60499f 100644 --- a/lib/webtorrent.js +++ b/lib/webtorrent.js | |||
@@ -1,7 +1,7 @@ | |||
1 | ;(function () { | 1 | ;(function () { |
2 | 'use strict' | 2 | 'use strict' |
3 | 3 | ||
4 | module.exports = function (args) { | 4 | function webtorrent (args) { |
5 | var WebTorrent = require('webtorrent') | 5 | var WebTorrent = require('webtorrent') |
6 | var ipc = require('node-ipc') | 6 | var ipc = require('node-ipc') |
7 | 7 | ||
@@ -88,4 +88,8 @@ | |||
88 | ipc.of[nodeKey].emit(processKey + '.exception', { exception: e }) | 88 | ipc.of[nodeKey].emit(processKey + '.exception', { exception: e }) |
89 | }) | 89 | }) |
90 | } | 90 | } |
91 | |||
92 | // --------------------------------------------------------------------------- | ||
93 | |||
94 | module.exports = webtorrent | ||
91 | })() | 95 | })() |
diff --git a/middlewares/index.js b/middlewares/index.js index e727202ba..311dfb6d2 100644 --- a/middlewares/index.js +++ b/middlewares/index.js | |||
@@ -1,10 +1,12 @@ | |||
1 | ;(function () { | 1 | ;(function () { |
2 | 'use strict' | 2 | 'use strict' |
3 | 3 | ||
4 | var middleware = { | 4 | var middlewares = { |
5 | reqValidators: require('./reqValidators'), | 5 | misc: require('./misc'), |
6 | misc: require('./misc') | 6 | reqValidators: require('./reqValidators') |
7 | } | 7 | } |
8 | 8 | ||
9 | module.exports = middleware | 9 | // --------------------------------------------------------------------------- |
10 | |||
11 | module.exports = middlewares | ||
10 | })() | 12 | })() |
diff --git a/middlewares/misc.js b/middlewares/misc.js index f814acd9f..dbb604db3 100644 --- a/middlewares/misc.js +++ b/middlewares/misc.js | |||
@@ -1,16 +1,19 @@ | |||
1 | ;(function () { | 1 | ;(function () { |
2 | 'use strict' | 2 | 'use strict' |
3 | 3 | ||
4 | var ursa = require('ursa') | ||
5 | var fs = require('fs') | 4 | var fs = require('fs') |
5 | var ursa = require('ursa') | ||
6 | 6 | ||
7 | var logger = require('../helpers/logger') | 7 | var logger = require('../helpers/logger') |
8 | var utils = require('../helpers/utils') | ||
9 | var PodsDB = require('../initializers/database').PodsDB | 8 | var PodsDB = require('../initializers/database').PodsDB |
9 | var utils = require('../helpers/utils') | ||
10 | 10 | ||
11 | var misc = {} | 11 | var miscMiddleware = { |
12 | cache: cache, | ||
13 | decryptBody: decryptBody | ||
14 | } | ||
12 | 15 | ||
13 | misc.cache = function (cache) { | 16 | function cache (cache) { |
14 | return function (req, res, next) { | 17 | return function (req, res, next) { |
15 | // If we want explicitly a cache | 18 | // If we want explicitly a cache |
16 | // Or if we don't specify if we want a cache or no and we are in production | 19 | // Or if we don't specify if we want a cache or no and we are in production |
@@ -24,7 +27,7 @@ | |||
24 | } | 27 | } |
25 | } | 28 | } |
26 | 29 | ||
27 | misc.decryptBody = function (req, res, next) { | 30 | function decryptBody (req, res, next) { |
28 | PodsDB.findOne({ url: req.body.signature.url }, function (err, pod) { | 31 | PodsDB.findOne({ url: req.body.signature.url }, function (err, pod) { |
29 | if (err) { | 32 | if (err) { |
30 | logger.error('Cannot get signed url in decryptBody.', { error: err }) | 33 | logger.error('Cannot get signed url in decryptBody.', { error: err }) |
@@ -42,7 +45,7 @@ | |||
42 | var signature_ok = crt.hashAndVerify('sha256', new Buffer(req.body.signature.url).toString('hex'), req.body.signature.signature, 'hex') | 45 | var signature_ok = crt.hashAndVerify('sha256', new Buffer(req.body.signature.url).toString('hex'), req.body.signature.signature, 'hex') |
43 | 46 | ||
44 | if (signature_ok === true) { | 47 | if (signature_ok === true) { |
45 | var myKey = ursa.createPrivateKey(fs.readFileSync(utils.certDir + 'peertube.key.pem')) | 48 | var myKey = ursa.createPrivateKey(fs.readFileSync(utils.getCertDir() + 'peertube.key.pem')) |
46 | var decryptedKey = myKey.decrypt(req.body.key, 'hex', 'utf8') | 49 | var decryptedKey = myKey.decrypt(req.body.key, 'hex', 'utf8') |
47 | req.body.data = JSON.parse(utils.symetricDecrypt(req.body.data, decryptedKey)) | 50 | req.body.data = JSON.parse(utils.symetricDecrypt(req.body.data, decryptedKey)) |
48 | delete req.body.key | 51 | delete req.body.key |
@@ -55,5 +58,7 @@ | |||
55 | }) | 58 | }) |
56 | } | 59 | } |
57 | 60 | ||
58 | module.exports = misc | 61 | // --------------------------------------------------------------------------- |
62 | |||
63 | module.exports = miscMiddleware | ||
59 | })() | 64 | })() |
diff --git a/middlewares/reqValidators/index.js b/middlewares/reqValidators/index.js index 1ea611031..34d34013c 100644 --- a/middlewares/reqValidators/index.js +++ b/middlewares/reqValidators/index.js | |||
@@ -1,11 +1,13 @@ | |||
1 | ;(function () { | 1 | ;(function () { |
2 | 'use strict' | 2 | 'use strict' |
3 | 3 | ||
4 | var reqValidator = { | 4 | var reqValidators = { |
5 | videos: require('./videos'), | 5 | videos: require('./videos'), |
6 | pods: require('./pods'), | 6 | pods: require('./pods'), |
7 | remote: require('./remote') | 7 | remote: require('./remote') |
8 | } | 8 | } |
9 | 9 | ||
10 | module.exports = reqValidator | 10 | // --------------------------------------------------------------------------- |
11 | |||
12 | module.exports = reqValidators | ||
11 | })() | 13 | })() |
diff --git a/middlewares/reqValidators/pods.js b/middlewares/reqValidators/pods.js index 0d023842d..6ccfd7361 100644 --- a/middlewares/reqValidators/pods.js +++ b/middlewares/reqValidators/pods.js | |||
@@ -4,9 +4,11 @@ | |||
4 | var checkErrors = require('./utils').checkErrors | 4 | var checkErrors = require('./utils').checkErrors |
5 | var logger = require('../../helpers/logger') | 5 | var logger = require('../../helpers/logger') |
6 | 6 | ||
7 | var pods = {} | 7 | var reqValidatorsPod = { |
8 | podsAdd: podsAdd | ||
9 | } | ||
8 | 10 | ||
9 | pods.podsAdd = function (req, res, next) { | 11 | function podsAdd (req, res, next) { |
10 | req.checkBody('data.url', 'Should have an url').notEmpty().isURL({ require_protocol: true }) | 12 | req.checkBody('data.url', 'Should have an url').notEmpty().isURL({ require_protocol: true }) |
11 | req.checkBody('data.publicKey', 'Should have a public key').notEmpty() | 13 | req.checkBody('data.publicKey', 'Should have a public key').notEmpty() |
12 | 14 | ||
@@ -15,5 +17,7 @@ | |||
15 | checkErrors(req, res, next) | 17 | checkErrors(req, res, next) |
16 | } | 18 | } |
17 | 19 | ||
18 | module.exports = pods | 20 | // --------------------------------------------------------------------------- |
21 | |||
22 | module.exports = reqValidatorsPod | ||
19 | })() | 23 | })() |
diff --git a/middlewares/reqValidators/remote.js b/middlewares/reqValidators/remote.js index 4b161e292..9b61481ad 100644 --- a/middlewares/reqValidators/remote.js +++ b/middlewares/reqValidators/remote.js | |||
@@ -4,20 +4,13 @@ | |||
4 | var checkErrors = require('./utils').checkErrors | 4 | var checkErrors = require('./utils').checkErrors |
5 | var logger = require('../../helpers/logger') | 5 | var logger = require('../../helpers/logger') |
6 | 6 | ||
7 | var remote = {} | 7 | var reqValidatorsRemote = { |
8 | 8 | remoteVideosAdd: remoteVideosAdd, | |
9 | remote.secureRequest = function (req, res, next) { | 9 | remoteVideosRemove: remoteVideosRemove, |
10 | req.checkBody('signature.url', 'Should have a signature url').isURL() | 10 | secureRequest: secureRequest |
11 | req.checkBody('signature.signature', 'Should have a signature').notEmpty() | ||
12 | req.checkBody('key', 'Should have a key').notEmpty() | ||
13 | req.checkBody('data', 'Should have data').notEmpty() | ||
14 | |||
15 | logger.debug('Checking secureRequest parameters', { parameters: { data: req.body.data, keyLength: req.body.key.length } }) | ||
16 | |||
17 | checkErrors(req, res, next) | ||
18 | } | 11 | } |
19 | 12 | ||
20 | remote.remoteVideosAdd = function (req, res, next) { | 13 | function remoteVideosAdd (req, res, next) { |
21 | req.checkBody('data').isArray() | 14 | req.checkBody('data').isArray() |
22 | req.checkBody('data').eachIsRemoteVideosAddValid() | 15 | req.checkBody('data').eachIsRemoteVideosAddValid() |
23 | 16 | ||
@@ -26,7 +19,7 @@ | |||
26 | checkErrors(req, res, next) | 19 | checkErrors(req, res, next) |
27 | } | 20 | } |
28 | 21 | ||
29 | remote.remoteVideosRemove = function (req, res, next) { | 22 | function remoteVideosRemove (req, res, next) { |
30 | req.checkBody('data').isArray() | 23 | req.checkBody('data').isArray() |
31 | req.checkBody('data').eachIsRemoteVideosRemoveValid() | 24 | req.checkBody('data').eachIsRemoteVideosRemoveValid() |
32 | 25 | ||
@@ -35,5 +28,18 @@ | |||
35 | checkErrors(req, res, next) | 28 | checkErrors(req, res, next) |
36 | } | 29 | } |
37 | 30 | ||
38 | module.exports = remote | 31 | function secureRequest (req, res, next) { |
32 | req.checkBody('signature.url', 'Should have a signature url').isURL() | ||
33 | req.checkBody('signature.signature', 'Should have a signature').notEmpty() | ||
34 | req.checkBody('key', 'Should have a key').notEmpty() | ||
35 | req.checkBody('data', 'Should have data').notEmpty() | ||
36 | |||
37 | logger.debug('Checking secureRequest parameters', { parameters: { data: req.body.data, keyLength: req.body.key.length } }) | ||
38 | |||
39 | checkErrors(req, res, next) | ||
40 | } | ||
41 | |||
42 | // --------------------------------------------------------------------------- | ||
43 | |||
44 | module.exports = reqValidatorsRemote | ||
39 | })() | 45 | })() |
diff --git a/middlewares/reqValidators/utils.js b/middlewares/reqValidators/utils.js index 5bc9f4f0b..c88f6df2e 100644 --- a/middlewares/reqValidators/utils.js +++ b/middlewares/reqValidators/utils.js | |||
@@ -2,11 +2,14 @@ | |||
2 | 'use strict' | 2 | 'use strict' |
3 | 3 | ||
4 | var util = require('util') | 4 | var util = require('util') |
5 | |||
5 | var logger = require('../../helpers/logger') | 6 | var logger = require('../../helpers/logger') |
6 | 7 | ||
7 | var utils = {} | 8 | var reqValidatorsUtils = { |
9 | checkErrors: checkErrors | ||
10 | } | ||
8 | 11 | ||
9 | utils.checkErrors = function (req, res, next, status_code) { | 12 | function checkErrors (req, res, next, status_code) { |
10 | if (status_code === undefined) status_code = 400 | 13 | if (status_code === undefined) status_code = 400 |
11 | var errors = req.validationErrors() | 14 | var errors = req.validationErrors() |
12 | 15 | ||
@@ -18,5 +21,7 @@ | |||
18 | return next() | 21 | return next() |
19 | } | 22 | } |
20 | 23 | ||
21 | module.exports = utils | 24 | // --------------------------------------------------------------------------- |
25 | |||
26 | module.exports = reqValidatorsUtils | ||
22 | })() | 27 | })() |
diff --git a/middlewares/reqValidators/videos.js b/middlewares/reqValidators/videos.js index a34445f7a..3479c47c3 100644 --- a/middlewares/reqValidators/videos.js +++ b/middlewares/reqValidators/videos.js | |||
@@ -2,28 +2,17 @@ | |||
2 | 'use strict' | 2 | 'use strict' |
3 | 3 | ||
4 | var checkErrors = require('./utils').checkErrors | 4 | var checkErrors = require('./utils').checkErrors |
5 | var VideosDB = require('../../initializers/database').VideosDB | ||
6 | var logger = require('../../helpers/logger') | 5 | var logger = require('../../helpers/logger') |
6 | var VideosDB = require('../../initializers/database').VideosDB | ||
7 | 7 | ||
8 | var videos = {} | 8 | var reqValidatorsVideos = { |
9 | 9 | videosAdd: videosAdd, | |
10 | function findVideoById (id, callback) { | 10 | videosGet: videosGet, |
11 | VideosDB.findById(id, { _id: 1, namePath: 1 }).limit(1).exec(function (err, video) { | 11 | videosRemove: videosRemove, |
12 | if (err) throw err | 12 | videosSearch: videosSearch |
13 | |||
14 | callback(video) | ||
15 | }) | ||
16 | } | ||
17 | |||
18 | videos.videosSearch = function (req, res, next) { | ||
19 | req.checkParams('name', 'Should have a name').notEmpty() | ||
20 | |||
21 | logger.debug('Checking videosSearch parameters', { parameters: req.params }) | ||
22 | |||
23 | checkErrors(req, res, next) | ||
24 | } | 13 | } |
25 | 14 | ||
26 | videos.videosAdd = function (req, res, next) { | 15 | function videosAdd (req, res, next) { |
27 | req.checkFiles('input_video[0].originalname', 'Should have an input video').notEmpty() | 16 | req.checkFiles('input_video[0].originalname', 'Should have an input video').notEmpty() |
28 | req.checkFiles('input_video[0].mimetype', 'Should have a correct mime type').matches(/video\/(webm)|(mp4)|(ogg)/i) | 17 | req.checkFiles('input_video[0].mimetype', 'Should have a correct mime type').matches(/video\/(webm)|(mp4)|(ogg)/i) |
29 | req.checkBody('name', 'Should have a name').isLength(1, 50) | 18 | req.checkBody('name', 'Should have a name').isLength(1, 50) |
@@ -34,7 +23,7 @@ | |||
34 | checkErrors(req, res, next) | 23 | checkErrors(req, res, next) |
35 | } | 24 | } |
36 | 25 | ||
37 | videos.videosGet = function (req, res, next) { | 26 | function videosGet (req, res, next) { |
38 | req.checkParams('id', 'Should have a valid id').notEmpty().isMongoId() | 27 | req.checkParams('id', 'Should have a valid id').notEmpty().isMongoId() |
39 | 28 | ||
40 | logger.debug('Checking videosGet parameters', { parameters: req.params }) | 29 | logger.debug('Checking videosGet parameters', { parameters: req.params }) |
@@ -48,7 +37,7 @@ | |||
48 | }) | 37 | }) |
49 | } | 38 | } |
50 | 39 | ||
51 | videos.videosRemove = function (req, res, next) { | 40 | function videosRemove (req, res, next) { |
52 | req.checkParams('id', 'Should have a valid id').notEmpty().isMongoId() | 41 | req.checkParams('id', 'Should have a valid id').notEmpty().isMongoId() |
53 | 42 | ||
54 | logger.debug('Checking videosRemove parameters', { parameters: req.params }) | 43 | logger.debug('Checking videosRemove parameters', { parameters: req.params }) |
@@ -63,5 +52,25 @@ | |||
63 | }) | 52 | }) |
64 | } | 53 | } |
65 | 54 | ||
66 | module.exports = videos | 55 | function videosSearch (req, res, next) { |
56 | req.checkParams('name', 'Should have a name').notEmpty() | ||
57 | |||
58 | logger.debug('Checking videosSearch parameters', { parameters: req.params }) | ||
59 | |||
60 | checkErrors(req, res, next) | ||
61 | } | ||
62 | |||
63 | // --------------------------------------------------------------------------- | ||
64 | |||
65 | module.exports = reqValidatorsVideos | ||
66 | |||
67 | // --------------------------------------------------------------------------- | ||
68 | |||
69 | function findVideoById (id, callback) { | ||
70 | VideosDB.findById(id, { _id: 1, namePath: 1 }).limit(1).exec(function (err, video) { | ||
71 | if (err) throw err | ||
72 | |||
73 | callback(video) | ||
74 | }) | ||
75 | } | ||
67 | })() | 76 | })() |
diff --git a/models/pods.js b/models/pods.js index c8d08b26f..ed2f0d8ee 100644 --- a/models/pods.js +++ b/models/pods.js | |||
@@ -12,39 +12,23 @@ | |||
12 | var poolRequests = require('../lib/poolRequests') | 12 | var poolRequests = require('../lib/poolRequests') |
13 | var utils = require('../helpers/utils') | 13 | var utils = require('../helpers/utils') |
14 | 14 | ||
15 | var pods = {} | ||
16 | |||
17 | var http = config.get('webserver.https') ? 'https' : 'http' | 15 | var http = config.get('webserver.https') ? 'https' : 'http' |
18 | var host = config.get('webserver.host') | 16 | var host = config.get('webserver.host') |
19 | var port = config.get('webserver.port') | 17 | var port = config.get('webserver.port') |
20 | 18 | ||
21 | // ----------- Private functions ----------- | 19 | var pods = { |
22 | 20 | add: add, | |
23 | function getForeignPodsList (url, callback) { | 21 | addVideoToFriends: addVideoToFriends, |
24 | var path = '/api/' + constants.API_VERSION + '/pods' | 22 | list: list, |
25 | 23 | hasFriends: hasFriends, | |
26 | request.get(url + path, function (err, response, body) { | 24 | makeFriends: makeFriends, |
27 | if (err) throw err | 25 | quitFriends: quitFriends, |
28 | callback(JSON.parse(body)) | 26 | remove: remove, |
29 | }) | 27 | removeVideoToFriends |
30 | } | 28 | } |
31 | 29 | ||
32 | // ----------- Public functions ----------- | ||
33 | |||
34 | pods.list = function (callback) { | ||
35 | PodsDB.find(function (err, pods_list) { | ||
36 | if (err) { | ||
37 | logger.error('Cannot get the list of the pods.', { error: err }) | ||
38 | return callback(err) | ||
39 | } | ||
40 | |||
41 | return callback(null, pods_list) | ||
42 | }) | ||
43 | } | ||
44 | |||
45 | // { url } | ||
46 | // TODO: check if the pod is not already a friend | 30 | // TODO: check if the pod is not already a friend |
47 | pods.add = function (data, callback) { | 31 | function add (data, callback) { |
48 | var videos = require('./videos') | 32 | var videos = require('./videos') |
49 | logger.info('Adding pod: %s', data.url) | 33 | logger.info('Adding pod: %s', data.url) |
50 | 34 | ||
@@ -62,7 +46,7 @@ | |||
62 | 46 | ||
63 | videos.addRemotes(data.videos) | 47 | videos.addRemotes(data.videos) |
64 | 48 | ||
65 | fs.readFile(utils.certDir + 'peertube.pub', 'utf8', function (err, cert) { | 49 | fs.readFile(utils.getCertDir() + 'peertube.pub', 'utf8', function (err, cert) { |
66 | if (err) { | 50 | if (err) { |
67 | logger.error('Cannot read cert file.', { error: err }) | 51 | logger.error('Cannot read cert file.', { error: err }) |
68 | return callback(err) | 52 | return callback(err) |
@@ -80,40 +64,38 @@ | |||
80 | }) | 64 | }) |
81 | } | 65 | } |
82 | 66 | ||
83 | pods.remove = function (url, callback) { | 67 | function addVideoToFriends (video) { |
84 | var videos = require('./videos') | 68 | // To avoid duplicates |
85 | logger.info('Removing %s pod.', url) | 69 | var id = video.name + video.magnetUri |
86 | 70 | poolRequests.addToPoolRequests(id, 'add', video) | |
87 | videos.removeAllRemotesOf(url, function (err) { | 71 | } |
88 | if (err) logger.error('Cannot remove all remote videos of %s.', url) | ||
89 | 72 | ||
90 | PodsDB.remove({ url: url }, function (err) { | 73 | function list (callback) { |
91 | if (err) return callback(err) | 74 | PodsDB.find(function (err, pods_list) { |
75 | if (err) { | ||
76 | logger.error('Cannot get the list of the pods.', { error: err }) | ||
77 | return callback(err) | ||
78 | } | ||
92 | 79 | ||
93 | logger.info('%s pod removed.', url) | 80 | return callback(null, pods_list) |
94 | callback(null) | ||
95 | }) | ||
96 | }) | 81 | }) |
97 | } | 82 | } |
98 | 83 | ||
99 | pods.addVideoToFriends = function (video) { | 84 | function hasFriends (callback) { |
100 | // To avoid duplicates | 85 | PodsDB.count(function (err, count) { |
101 | var id = video.name + video.magnetUri | 86 | if (err) return callback(err) |
102 | poolRequests.addToPoolRequests(id, 'add', video) | ||
103 | } | ||
104 | 87 | ||
105 | pods.removeVideoToFriends = function (video) { | 88 | var has_friends = (count !== 0) |
106 | // To avoid duplicates | 89 | callback(null, has_friends) |
107 | var id = video.name + video.magnetUri | 90 | }) |
108 | poolRequests.addToPoolRequests(id, 'remove', video) | ||
109 | } | 91 | } |
110 | 92 | ||
111 | pods.makeFriends = function (callback) { | 93 | function makeFriends (callback) { |
112 | var videos = require('./videos') | 94 | var videos = require('./videos') |
113 | var pods_score = {} | 95 | var pods_score = {} |
114 | 96 | ||
115 | logger.info('Make friends!') | 97 | logger.info('Make friends!') |
116 | fs.readFile(utils.certDir + 'peertube.pub', 'utf8', function (err, cert) { | 98 | fs.readFile(utils.getCertDir() + 'peertube.pub', 'utf8', function (err, cert) { |
117 | if (err) { | 99 | if (err) { |
118 | logger.error('Cannot read public cert.', { error: err }) | 100 | logger.error('Cannot read public cert.', { error: err }) |
119 | return callback(err) | 101 | return callback(err) |
@@ -188,7 +170,7 @@ | |||
188 | function eachRequest (err, response, body, url, pod, callback_each_request) { | 170 | function eachRequest (err, response, body, url, pod, callback_each_request) { |
189 | // We add the pod if it responded correctly with its public certificate | 171 | // We add the pod if it responded correctly with its public certificate |
190 | if (!err && response.statusCode === 200) { | 172 | if (!err && response.statusCode === 200) { |
191 | pods.add({ url: pod.url, publicKey: body.cert, score: constants.FRIEND_BASE_SCORE }, function (err) { | 173 | add({ url: pod.url, publicKey: body.cert, score: constants.FRIEND_BASE_SCORE }, function (err) { |
192 | if (err) logger.error('Error with adding %s pod.', pod.url, { error: err }) | 174 | if (err) logger.error('Error with adding %s pod.', pod.url, { error: err }) |
193 | 175 | ||
194 | videos.addRemotes(body.videos, function (err) { | 176 | videos.addRemotes(body.videos, function (err) { |
@@ -221,7 +203,7 @@ | |||
221 | } | 203 | } |
222 | } | 204 | } |
223 | 205 | ||
224 | pods.quitFriends = function (callback) { | 206 | function quitFriends (callback) { |
225 | // Stop pool requests | 207 | // Stop pool requests |
226 | poolRequests.deactivate() | 208 | poolRequests.deactivate() |
227 | // Flush pool requests | 209 | // Flush pool requests |
@@ -261,14 +243,40 @@ | |||
261 | }) | 243 | }) |
262 | } | 244 | } |
263 | 245 | ||
264 | pods.hasFriends = function (callback) { | 246 | function remove (url, callback) { |
265 | PodsDB.count(function (err, count) { | 247 | var videos = require('./videos') |
266 | if (err) return callback(err) | 248 | logger.info('Removing %s pod.', url) |
267 | 249 | ||
268 | var has_friends = (count !== 0) | 250 | videos.removeAllRemotesOf(url, function (err) { |
269 | callback(null, has_friends) | 251 | if (err) logger.error('Cannot remove all remote videos of %s.', url) |
252 | |||
253 | PodsDB.remove({ url: url }, function (err) { | ||
254 | if (err) return callback(err) | ||
255 | |||
256 | logger.info('%s pod removed.', url) | ||
257 | callback(null) | ||
258 | }) | ||
270 | }) | 259 | }) |
271 | } | 260 | } |
272 | 261 | ||
262 | function removeVideoToFriends (video) { | ||
263 | // To avoid duplicates | ||
264 | var id = video.name + video.magnetUri | ||
265 | poolRequests.addToPoolRequests(id, 'remove', video) | ||
266 | } | ||
267 | |||
268 | // --------------------------------------------------------------------------- | ||
269 | |||
273 | module.exports = pods | 270 | module.exports = pods |
271 | |||
272 | // --------------------------------------------------------------------------- | ||
273 | |||
274 | function getForeignPodsList (url, callback) { | ||
275 | var path = '/api/' + constants.API_VERSION + '/pods' | ||
276 | |||
277 | request.get(url + path, function (err, response, body) { | ||
278 | if (err) throw err | ||
279 | callback(JSON.parse(body)) | ||
280 | }) | ||
281 | } | ||
274 | })() | 282 | })() |
diff --git a/models/videos.js b/models/videos.js index 626c55819..5711c5657 100644 --- a/models/videos.js +++ b/models/videos.js | |||
@@ -11,51 +11,29 @@ | |||
11 | var pods = require('./pods') | 11 | var pods = require('./pods') |
12 | var VideosDB = require('../initializers/database').VideosDB | 12 | var VideosDB = require('../initializers/database').VideosDB |
13 | 13 | ||
14 | var videos = {} | ||
15 | |||
16 | var http = config.get('webserver.https') === true ? 'https' : 'http' | 14 | var http = config.get('webserver.https') === true ? 'https' : 'http' |
17 | var host = config.get('webserver.host') | 15 | var host = config.get('webserver.host') |
18 | var port = config.get('webserver.port') | 16 | var port = config.get('webserver.port') |
19 | 17 | ||
20 | // ----------- Private functions ----------- | 18 | var videos = { |
21 | function seedVideo (path, callback) { | 19 | add: add, |
22 | logger.info('Seeding %s...', path) | 20 | addRemotes: addRemotes, |
23 | 21 | get: get, | |
24 | webtorrent.seed(path, function (torrent) { | 22 | list: list, |
25 | logger.info('%s seeded (%s).', path, torrent.magnetURI) | 23 | listOwned: listOwned, |
26 | 24 | remove: remove, | |
27 | return callback(null, torrent) | 25 | removeAllRemotes: removeAllRemotes, |
28 | }) | 26 | removeAllRemotesOf: removeAllRemotesOf, |
27 | removeRemotes: removeRemotes, | ||
28 | search: search, | ||
29 | seedAll: seedAll, | ||
30 | uploadDir: uploadDir | ||
29 | } | 31 | } |
30 | 32 | ||
31 | // ----------- Public attributes ---------- | 33 | // ----------- Public attributes ---------- |
32 | videos.uploadDir = __dirname + '/../' + config.get('storage.uploads') | 34 | var uploadDir = __dirname + '/../' + config.get('storage.uploads') |
33 | |||
34 | // ----------- Public functions ----------- | ||
35 | videos.list = function (callback) { | ||
36 | VideosDB.find(function (err, videos_list) { | ||
37 | if (err) { | ||
38 | logger.error('Cannot get list of the videos.', { error: err }) | ||
39 | return callback(err) | ||
40 | } | ||
41 | |||
42 | return callback(null, videos_list) | ||
43 | }) | ||
44 | } | ||
45 | |||
46 | videos.listOwned = function (callback) { | ||
47 | // If namePath is not null this is *our* video | ||
48 | VideosDB.find({ namePath: { $ne: null } }, function (err, videos_list) { | ||
49 | if (err) { | ||
50 | logger.error('Cannot get list of the videos.', { error: err }) | ||
51 | return callback(err) | ||
52 | } | ||
53 | 35 | ||
54 | return callback(null, videos_list) | 36 | function add (data, callback) { |
55 | }) | ||
56 | } | ||
57 | |||
58 | videos.add = function (data, callback) { | ||
59 | var video_file = data.video | 37 | var video_file = data.video |
60 | var video_data = data.data | 38 | var video_data = data.data |
61 | 39 | ||
@@ -89,7 +67,74 @@ | |||
89 | }) | 67 | }) |
90 | } | 68 | } |
91 | 69 | ||
92 | videos.remove = function (id, callback) { | 70 | // TODO: avoid doublons |
71 | function addRemotes (videos, callback) { | ||
72 | if (callback === undefined) callback = function () {} | ||
73 | |||
74 | var to_add = [] | ||
75 | |||
76 | async.each(videos, function (video, callback_each) { | ||
77 | callback_each = dz(callback_each) | ||
78 | logger.debug('Add remote video from pod: %s', video.podUrl) | ||
79 | |||
80 | var params = { | ||
81 | name: video.name, | ||
82 | namePath: null, | ||
83 | description: video.description, | ||
84 | magnetUri: video.magnetUri, | ||
85 | podUrl: video.podUrl | ||
86 | } | ||
87 | |||
88 | to_add.push(params) | ||
89 | |||
90 | callback_each() | ||
91 | }, function () { | ||
92 | VideosDB.create(to_add, function (err, videos) { | ||
93 | if (err) { | ||
94 | logger.error('Cannot insert this remote video.', { error: err }) | ||
95 | return callback(err) | ||
96 | } | ||
97 | |||
98 | return callback(null, videos) | ||
99 | }) | ||
100 | }) | ||
101 | } | ||
102 | |||
103 | function get (id, callback) { | ||
104 | VideosDB.findById(id, function (err, video) { | ||
105 | if (err) { | ||
106 | logger.error('Cannot get this video.', { error: err }) | ||
107 | return callback(err) | ||
108 | } | ||
109 | |||
110 | return callback(null, video) | ||
111 | }) | ||
112 | } | ||
113 | |||
114 | function list (callback) { | ||
115 | VideosDB.find(function (err, videos_list) { | ||
116 | if (err) { | ||
117 | logger.error('Cannot get list of the videos.', { error: err }) | ||
118 | return callback(err) | ||
119 | } | ||
120 | |||
121 | return callback(null, videos_list) | ||
122 | }) | ||
123 | } | ||
124 | |||
125 | function listOwned (callback) { | ||
126 | // If namePath is not null this is *our* video | ||
127 | VideosDB.find({ namePath: { $ne: null } }, function (err, videos_list) { | ||
128 | if (err) { | ||
129 | logger.error('Cannot get list of the videos.', { error: err }) | ||
130 | return callback(err) | ||
131 | } | ||
132 | |||
133 | return callback(null, videos_list) | ||
134 | }) | ||
135 | } | ||
136 | |||
137 | function remove (id, callback) { | ||
93 | // Maybe the torrent is not seeded, but we catch the error to don't stop the removing process | 138 | // Maybe the torrent is not seeded, but we catch the error to don't stop the removing process |
94 | function removeTorrent (magnetUri, callback) { | 139 | function removeTorrent (magnetUri, callback) { |
95 | try { | 140 | try { |
@@ -122,7 +167,7 @@ | |||
122 | return callback(err) | 167 | return callback(err) |
123 | } | 168 | } |
124 | 169 | ||
125 | fs.unlink(videos.uploadDir + video.namePath, function (err) { | 170 | fs.unlink(uploadDir + video.namePath, function (err) { |
126 | if (err) { | 171 | if (err) { |
127 | logger.error('Cannot remove this video file.', { error: err }) | 172 | logger.error('Cannot remove this video file.', { error: err }) |
128 | return callback(err) | 173 | return callback(err) |
@@ -141,8 +186,24 @@ | |||
141 | }) | 186 | }) |
142 | } | 187 | } |
143 | 188 | ||
189 | function removeAllRemotes (callback) { | ||
190 | VideosDB.remove({ namePath: null }, function (err) { | ||
191 | if (err) return callback(err) | ||
192 | |||
193 | callback(null) | ||
194 | }) | ||
195 | } | ||
196 | |||
197 | function removeAllRemotesOf (fromUrl, callback) { | ||
198 | VideosDB.remove({ podUrl: fromUrl }, function (err) { | ||
199 | if (err) return callback(err) | ||
200 | |||
201 | callback(null) | ||
202 | }) | ||
203 | } | ||
204 | |||
144 | // Use the magnet Uri because the _id field is not the same on different servers | 205 | // Use the magnet Uri because the _id field is not the same on different servers |
145 | videos.removeRemotes = function (fromUrl, magnetUris, callback) { | 206 | function removeRemotes (fromUrl, magnetUris, callback) { |
146 | if (callback === undefined) callback = function () {} | 207 | if (callback === undefined) callback = function () {} |
147 | 208 | ||
148 | VideosDB.find({ magnetUri: { $in: magnetUris } }, function (err, videos) { | 209 | VideosDB.find({ magnetUri: { $in: magnetUris } }, function (err, videos) { |
@@ -176,68 +237,7 @@ | |||
176 | }) | 237 | }) |
177 | } | 238 | } |
178 | 239 | ||
179 | videos.removeAllRemotes = function (callback) { | 240 | function search (name, callback) { |
180 | VideosDB.remove({ namePath: null }, function (err) { | ||
181 | if (err) return callback(err) | ||
182 | |||
183 | callback(null) | ||
184 | }) | ||
185 | } | ||
186 | |||
187 | videos.removeAllRemotesOf = function (fromUrl, callback) { | ||
188 | VideosDB.remove({ podUrl: fromUrl }, function (err) { | ||
189 | if (err) return callback(err) | ||
190 | |||
191 | callback(null) | ||
192 | }) | ||
193 | } | ||
194 | |||
195 | // { name, magnetUri, podUrl } | ||
196 | // TODO: avoid doublons | ||
197 | videos.addRemotes = function (videos, callback) { | ||
198 | if (callback === undefined) callback = function () {} | ||
199 | |||
200 | var to_add = [] | ||
201 | |||
202 | async.each(videos, function (video, callback_each) { | ||
203 | callback_each = dz(callback_each) | ||
204 | logger.debug('Add remote video from pod: %s', video.podUrl) | ||
205 | |||
206 | var params = { | ||
207 | name: video.name, | ||
208 | namePath: null, | ||
209 | description: video.description, | ||
210 | magnetUri: video.magnetUri, | ||
211 | podUrl: video.podUrl | ||
212 | } | ||
213 | |||
214 | to_add.push(params) | ||
215 | |||
216 | callback_each() | ||
217 | }, function () { | ||
218 | VideosDB.create(to_add, function (err, videos) { | ||
219 | if (err) { | ||
220 | logger.error('Cannot insert this remote video.', { error: err }) | ||
221 | return callback(err) | ||
222 | } | ||
223 | |||
224 | return callback(null, videos) | ||
225 | }) | ||
226 | }) | ||
227 | } | ||
228 | |||
229 | videos.get = function (id, callback) { | ||
230 | VideosDB.findById(id, function (err, video) { | ||
231 | if (err) { | ||
232 | logger.error('Cannot get this video.', { error: err }) | ||
233 | return callback(err) | ||
234 | } | ||
235 | |||
236 | return callback(null, video) | ||
237 | }) | ||
238 | } | ||
239 | |||
240 | videos.search = function (name, callback) { | ||
241 | VideosDB.find({ name: new RegExp(name) }, function (err, videos) { | 241 | VideosDB.find({ name: new RegExp(name) }, function (err, videos) { |
242 | if (err) { | 242 | if (err) { |
243 | logger.error('Cannot search the videos.', { error: err }) | 243 | logger.error('Cannot search the videos.', { error: err }) |
@@ -248,7 +248,7 @@ | |||
248 | }) | 248 | }) |
249 | } | 249 | } |
250 | 250 | ||
251 | videos.seedAll = function (callback) { | 251 | function seedAll (callback) { |
252 | VideosDB.find({ namePath: { $ne: null } }, function (err, videos_list) { | 252 | VideosDB.find({ namePath: { $ne: null } }, function (err, videos_list) { |
253 | if (err) { | 253 | if (err) { |
254 | logger.error('Cannot get list of the videos to seed.', { error: err }) | 254 | logger.error('Cannot get list of the videos to seed.', { error: err }) |
@@ -256,7 +256,7 @@ | |||
256 | } | 256 | } |
257 | 257 | ||
258 | async.each(videos_list, function (video, each_callback) { | 258 | async.each(videos_list, function (video, each_callback) { |
259 | seedVideo(videos.uploadDir + video.namePath, function (err) { | 259 | seedVideo(uploadDir + video.namePath, function (err) { |
260 | if (err) { | 260 | if (err) { |
261 | logger.error('Cannot seed this video.', { error: err }) | 261 | logger.error('Cannot seed this video.', { error: err }) |
262 | return callback(err) | 262 | return callback(err) |
@@ -268,5 +268,19 @@ | |||
268 | }) | 268 | }) |
269 | } | 269 | } |
270 | 270 | ||
271 | // --------------------------------------------------------------------------- | ||
272 | |||
271 | module.exports = videos | 273 | module.exports = videos |
274 | |||
275 | // --------------------------------------------------------------------------- | ||
276 | |||
277 | function seedVideo (path, callback) { | ||
278 | logger.info('Seeding %s...', path) | ||
279 | |||
280 | webtorrent.seed(path, function (torrent) { | ||
281 | logger.info('%s seeded (%s).', path, torrent.magnetURI) | ||
282 | |||
283 | return callback(null, torrent) | ||
284 | }) | ||
285 | } | ||
272 | })() | 286 | })() |
diff --git a/tests/api/singlePod.js b/tests/api/singlePod.js index ce3ca80f2..7621d766c 100644 --- a/tests/api/singlePod.js +++ b/tests/api/singlePod.js | |||
@@ -3,8 +3,8 @@ | |||
3 | 3 | ||
4 | var async = require('async') | 4 | var async = require('async') |
5 | var chai = require('chai') | 5 | var chai = require('chai') |
6 | var fs = require('fs') | ||
7 | var expect = chai.expect | 6 | var expect = chai.expect |
7 | var fs = require('fs') | ||
8 | 8 | ||
9 | var webtorrent = require(__dirname + '/../../lib/webTorrentNode') | 9 | var webtorrent = require(__dirname + '/../../lib/webTorrentNode') |
10 | webtorrent.silent = true | 10 | webtorrent.silent = true |
diff --git a/tests/api/utils.js b/tests/api/utils.js index afb0abb33..a1996b4d7 100644 --- a/tests/api/utils.js +++ b/tests/api/utils.js | |||
@@ -6,7 +6,7 @@ | |||
6 | var fork = child_process.fork | 6 | var fork = child_process.fork |
7 | var request = require('supertest') | 7 | var request = require('supertest') |
8 | 8 | ||
9 | module.exports = { | 9 | var testUtils = { |
10 | flushTests: flushTests, | 10 | flushTests: flushTests, |
11 | getFriendsList: getFriendsList, | 11 | getFriendsList: getFriendsList, |
12 | getVideosList: getVideosList, | 12 | getVideosList: getVideosList, |
@@ -179,4 +179,8 @@ | |||
179 | .expect(201) | 179 | .expect(201) |
180 | .end(end) | 180 | .end(end) |
181 | } | 181 | } |
182 | |||
183 | // --------------------------------------------------------------------------- | ||
184 | |||
185 | module.exports = testUtils | ||
182 | })() | 186 | })() |