]>
Commit | Line | Data |
---|---|---|
8c308c2b C |
1 | ;(function () { |
2 | 'use strict' | |
3 | ||
8c308c2b | 4 | var async = require('async') |
a1860380 C |
5 | var config = require('config') |
6 | var fs = require('fs') | |
8c308c2b C |
7 | var request = require('request') |
8 | ||
9 | var logger = require('./logger') | |
8c308c2b | 10 | var PodsDB = require('./database').PodsDB |
a1860380 | 11 | var utils = require('./utils') |
8c308c2b C |
12 | |
13 | var pods = {} | |
a1860380 | 14 | |
8c308c2b C |
15 | var http = config.get('webserver.https') ? 'https' : 'http' |
16 | var host = config.get('webserver.host') | |
17 | var port = config.get('webserver.port') | |
18 | ||
3bcb78b3 C |
19 | // ----------- Constants ----------- |
20 | ||
21 | var PODS_SCORE = { | |
22 | MALUS: -10, | |
23 | BONUS: 10 | |
24 | } | |
25 | ||
8c308c2b C |
26 | // ----------- Private functions ----------- |
27 | ||
28 | function getForeignPodsList (url, callback) { | |
f5a60a51 | 29 | var path = '/api/' + global.API_VERSION + '/pods' |
8c308c2b C |
30 | |
31 | request.get(url + path, function (err, response, body) { | |
32 | if (err) throw err | |
33 | callback(JSON.parse(body)) | |
34 | }) | |
35 | } | |
36 | ||
3bcb78b3 C |
37 | function updatePodsScore (good_pods, bad_pods) { |
38 | logger.info('Updating %d good pods and %d bad pods scores.', good_pods.length, bad_pods.length) | |
39 | ||
40 | PodsDB.update({ _id: { $in: good_pods } }, { $inc: { score: PODS_SCORE.BONUS } }, { multi: true }).exec() | |
41 | PodsDB.update({ _id: { $in: bad_pods } }, { $inc: { score: PODS_SCORE.MALUS } }, { multi: true }, function (err) { | |
42 | if (err) throw err | |
43 | removeBadPods() | |
44 | }) | |
45 | } | |
46 | ||
47 | function removeBadPods () { | |
48 | PodsDB.remove({ score: 0 }, function (err, result) { | |
49 | if (err) throw err | |
50 | ||
51 | var number_removed = result.result.n | |
52 | if (number_removed !== 0) logger.info('Removed %d pod.', number_removed) | |
53 | }) | |
54 | } | |
55 | ||
8c308c2b | 56 | // ----------- Public functions ----------- |
a1860380 | 57 | |
8c308c2b C |
58 | pods.list = function (callback) { |
59 | PodsDB.find(function (err, pods_list) { | |
60 | if (err) { | |
61 | logger.error('Cannot get the list of the pods.', { error: err }) | |
62 | return callback(err) | |
63 | } | |
64 | ||
65 | return callback(null, pods_list) | |
66 | }) | |
67 | } | |
68 | ||
69 | // { url } | |
70 | pods.add = function (data, callback) { | |
71 | logger.info('Adding pod: %s', data.url) | |
72 | ||
73 | var params = { | |
74 | url: data.url, | |
3bcb78b3 C |
75 | publicKey: data.publicKey, |
76 | score: global.FRIEND_BASE_SCORE | |
8c308c2b C |
77 | } |
78 | ||
79 | PodsDB.create(params, function (err, pod) { | |
80 | if (err) { | |
81 | logger.error('Cannot insert the pod.', { error: err }) | |
82 | return callback(err) | |
83 | } | |
84 | ||
d148f3b9 | 85 | fs.readFile(utils.certDir + 'peertube.pub', 'utf8', function (err, cert) { |
8c308c2b C |
86 | if (err) { |
87 | logger.error('Cannot read cert file.', { error: err }) | |
88 | return callback(err) | |
89 | } | |
90 | ||
91 | return callback(null, { cert: cert }) | |
92 | }) | |
93 | }) | |
94 | } | |
95 | ||
96 | // { path, data } | |
97 | pods.makeSecureRequest = function (data, callback) { | |
3bcb78b3 C |
98 | if (callback === undefined) callback = function () {} |
99 | ||
100 | PodsDB.find({}, { _id: 1, url: 1, publicKey: 1 }).exec(function (err, pods) { | |
8c308c2b C |
101 | if (err) { |
102 | logger.error('Cannot get the list of the pods.', { error: err }) | |
103 | return callback(err) | |
104 | } | |
105 | ||
106 | logger.debug('Make multiple requests.') | |
a1860380 C |
107 | |
108 | var params = { | |
109 | encrypt: true, | |
110 | sign: true, | |
111 | method: data.method, | |
112 | path: data.path, | |
113 | data: data.data | |
114 | } | |
115 | ||
3bcb78b3 C |
116 | var bad_pods = [] |
117 | var good_pods = [] | |
118 | ||
8c308c2b | 119 | utils.makeMultipleRetryRequest( |
a1860380 | 120 | params, |
8c308c2b | 121 | |
3bcb78b3 | 122 | pods, |
8c308c2b | 123 | |
3bcb78b3 | 124 | function callbackEachPodFinished (err, response, body, pod, callback_each_pod_finished) { |
8c308c2b | 125 | if (err || response.statusCode !== 200) { |
3bcb78b3 C |
126 | bad_pods.push(pod._id) |
127 | logger.error('Error sending secure request to %s/%s pod.', pod.url, data.path, { error: err }) | |
128 | } else { | |
129 | good_pods.push(pod._id) | |
8c308c2b | 130 | } |
3bcb78b3 C |
131 | |
132 | return callback_each_pod_finished() | |
8c308c2b C |
133 | }, |
134 | ||
a1860380 | 135 | function callbackAllPodsFinished (err) { |
8c308c2b C |
136 | if (err) { |
137 | logger.error('There was some errors when sending the video meta data.', { error: err }) | |
138 | return callback(err) | |
139 | } | |
140 | ||
141 | logger.debug('Finished') | |
3bcb78b3 C |
142 | |
143 | updatePodsScore(good_pods, bad_pods) | |
8c308c2b C |
144 | callback(null) |
145 | } | |
146 | ) | |
147 | }) | |
148 | } | |
149 | ||
150 | pods.makeFriends = function (callback) { | |
a1860380 C |
151 | var pods_score = {} |
152 | ||
153 | logger.info('Make friends!') | |
d148f3b9 | 154 | fs.readFile(utils.certDir + 'peertube.pub', 'utf8', function (err, cert) { |
8c308c2b C |
155 | if (err) { |
156 | logger.error('Cannot read public cert.', { error: err }) | |
157 | return callback(err) | |
158 | } | |
159 | ||
160 | var urls = config.get('network.friends') | |
8c308c2b | 161 | |
a1860380 C |
162 | async.each(urls, computeForeignPodsList, function () { |
163 | logger.debug('Pods scores computed.', { pods_score: pods_score }) | |
164 | var pods_list = computeWinningPods(urls, pods_score) | |
165 | logger.debug('Pods that we keep computed.', { pods_to_keep: pods_list }) | |
166 | ||
167 | logger.debug('Make requests...') | |
168 | makeRequestsToWinningPods(cert, pods_list) | |
169 | }) | |
170 | }) | |
171 | ||
172 | // ----------------------------------------------------------------------- | |
8c308c2b | 173 | |
a1860380 | 174 | function computeForeignPodsList (url, callback) { |
3bcb78b3 C |
175 | // Let's give 1 point to the pod we ask the friends list |
176 | pods_score[url] = 1 | |
8c308c2b | 177 | |
a1860380 C |
178 | getForeignPodsList(url, function (foreign_pods_list) { |
179 | if (foreign_pods_list.length === 0) return callback() | |
180 | ||
181 | async.each(foreign_pods_list, function (foreign_pod, callback_each) { | |
182 | var foreign_url = foreign_pod.url | |
183 | ||
184 | if (pods_score[foreign_url]) pods_score[foreign_url]++ | |
185 | else pods_score[foreign_url] = 1 | |
186 | ||
187 | callback_each() | |
188 | }, function () { | |
189 | callback() | |
8c308c2b | 190 | }) |
a1860380 C |
191 | }) |
192 | } | |
8c308c2b | 193 | |
a1860380 C |
194 | function computeWinningPods (urls, pods_score) { |
195 | // Build the list of pods to add | |
196 | // Only add a pod if it exists in more than a half base pods | |
197 | var pods_list = [] | |
198 | var base_score = urls.length / 2 | |
199 | Object.keys(pods_score).forEach(function (pod) { | |
200 | if (pods_score[pod] > base_score) pods_list.push({ url: pod }) | |
201 | }) | |
8c308c2b | 202 | |
a1860380 C |
203 | return pods_list |
204 | } | |
8c308c2b | 205 | |
a1860380 C |
206 | function makeRequestsToWinningPods (cert, pods_list) { |
207 | var data = { | |
208 | url: http + '://' + host + ':' + port, | |
209 | publicKey: cert | |
210 | } | |
8c308c2b | 211 | |
a1860380 C |
212 | utils.makeMultipleRetryRequest( |
213 | { method: 'POST', path: '/api/' + global.API_VERSION + '/pods/', data: data }, | |
214 | ||
215 | pods_list, | |
216 | ||
3bcb78b3 | 217 | function eachRequest (err, response, body, pod, callback_each_request) { |
a1860380 C |
218 | // We add the pod if it responded correctly with its public certificate |
219 | if (!err && response.statusCode === 200) { | |
3bcb78b3 | 220 | pods.add({ url: pod.url, publicKey: body.cert, score: global.FRIEND_BASE_SCORE }, function (err) { |
a1860380 | 221 | if (err) { |
3bcb78b3 | 222 | logger.error('Error with adding %s pod.', pod.url, { error: err }) |
a1860380 | 223 | } |
3bcb78b3 C |
224 | |
225 | return callback_each_request() | |
a1860380 C |
226 | }) |
227 | } else { | |
3bcb78b3 C |
228 | logger.error('Error with adding %s pod.', pod.url, { error: err || new Error('Status not 200') }) |
229 | return callback_each_request() | |
8c308c2b | 230 | } |
a1860380 C |
231 | }, |
232 | ||
233 | function endRequests (err) { | |
234 | if (err) { | |
235 | logger.error('There was some errors when we wanted to make friends.', { error: err }) | |
236 | return callback(err) | |
237 | } | |
238 | ||
239 | logger.debug('makeRequestsToWinningPods finished.') | |
240 | return callback(null) | |
241 | } | |
242 | ) | |
243 | } | |
8c308c2b C |
244 | } |
245 | ||
246 | module.exports = pods | |
247 | })() |