]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/lib/friends.js
Use async series in installer for better readability
[github/Chocobozzz/PeerTube.git] / server / lib / friends.js
CommitLineData
9f10b292
C
1'use strict'
2
f0f5567b
C
3const async = require('async')
4const config = require('config')
5const fs = require('fs')
6const request = require('request')
7
8const constants = require('../initializers/constants')
9const logger = require('../helpers/logger')
10const peertubeCrypto = require('../helpers/peertubeCrypto')
11const Pods = require('../models/pods')
e3647ae2 12const requestsScheduler = require('../lib/requestsScheduler')
f0f5567b 13const requests = require('../helpers/requests')
cbe2f7c3 14const videos = require('../lib/videos')
f0f5567b
C
15const Videos = require('../models/videos')
16
17const http = config.get('webserver.https') ? 'https' : 'http'
18const host = config.get('webserver.host')
19const port = config.get('webserver.port')
20
21const pods = {
9f10b292
C
22 addVideoToFriends: addVideoToFriends,
23 hasFriends: hasFriends,
cbe2f7c3 24 getMyCertificate: getMyCertificate,
9f10b292
C
25 makeFriends: makeFriends,
26 quitFriends: quitFriends,
27 removeVideoToFriends: removeVideoToFriends
28}
29
30function addVideoToFriends (video) {
31 // To avoid duplicates
f0f5567b 32 const id = video.name + video.magnetUri
9f10b292
C
33 // ensure namePath is null
34 video.namePath = null
e3647ae2 35 requestsScheduler.addRequest(id, 'add', video)
9f10b292
C
36}
37
38function hasFriends (callback) {
39 Pods.count(function (err, count) {
40 if (err) return callback(err)
41
bc503c2a
C
42 const hasFriends = (count !== 0)
43 callback(null, hasFriends)
9f10b292
C
44 })
45}
46
cbe2f7c3
C
47function getMyCertificate (callback) {
48 fs.readFile(peertubeCrypto.getCertDir() + 'peertube.pub', 'utf8', callback)
49}
50
9f10b292 51function makeFriends (callback) {
bc503c2a 52 const podsScore = {}
9f10b292
C
53
54 logger.info('Make friends!')
cbe2f7c3 55 getMyCertificate(function (err, cert) {
9f10b292
C
56 if (err) {
57 logger.error('Cannot read public cert.')
58 return callback(err)
59 }
c173e565 60
f0f5567b 61 const urls = config.get('network.friends')
c173e565 62
bc503c2a
C
63 async.each(urls, function (url, callbackEach) {
64 computeForeignPodsList(url, podsScore, callbackEach)
89d1d8ba 65 }, function (err) {
c173e565
C
66 if (err) return callback(err)
67
bc503c2a
C
68 logger.debug('Pods scores computed.', { podsScore: podsScore })
69 const podsList = computeWinningPods(urls, podsScore)
70 logger.debug('Pods that we keep.', { podsToKeep: podsList })
9f10b292 71
bc503c2a 72 makeRequestsToWinningPods(cert, podsList, callback)
c173e565 73 })
9f10b292 74 })
9f10b292
C
75}
76
77function quitFriends (callback) {
78 // Stop pool requests
e3647ae2 79 requestsScheduler.deactivate()
9f10b292 80 // Flush pool requests
e3647ae2 81 requestsScheduler.forceSend()
9f10b292
C
82
83 Pods.list(function (err, pods) {
84 if (err) return callback(err)
85
f0f5567b 86 const request = {
9f10b292
C
87 method: 'POST',
88 path: '/api/' + constants.API_VERSION + '/pods/remove',
89 sign: true,
90 encrypt: true,
91 data: {
92 url: 'me' // Fake data
c173e565 93 }
9f10b292 94 }
c173e565 95
9f10b292
C
96 // Announce we quit them
97 requests.makeMultipleRetryRequest(request, pods, function () {
98 Pods.removeAll(function (err) {
e3647ae2 99 requestsScheduler.activate()
c173e565 100
9f10b292 101 if (err) return callback(err)
c173e565 102
9f10b292 103 logger.info('Broke friends, so sad :(')
c173e565 104
bc503c2a 105 Videos.listFromRemotes(function (err, videosList) {
9f10b292 106 if (err) return callback(err)
c173e565 107
bc503c2a 108 videos.removeRemoteVideos(videosList, function (err) {
cbe2f7c3
C
109 if (err) {
110 logger.error('Cannot remove remote videos.', { error: err })
111 return callback(err)
112 }
113
114 logger.info('Removed all remote videos.')
115 callback(null)
116 })
c173e565
C
117 })
118 })
119 })
9f10b292
C
120 })
121}
c173e565 122
9f10b292
C
123function removeVideoToFriends (video) {
124 // To avoid duplicates
f0f5567b 125 const id = video.name + video.magnetUri
e3647ae2 126 requestsScheduler.addRequest(id, 'remove', video)
9f10b292 127}
c173e565 128
9f10b292 129// ---------------------------------------------------------------------------
c173e565 130
9f10b292 131module.exports = pods
c173e565 132
9f10b292 133// ---------------------------------------------------------------------------
c173e565 134
bc503c2a 135function computeForeignPodsList (url, podsScore, callback) {
89d1d8ba 136 // Let's give 1 point to the pod we ask the friends list
bc503c2a 137 podsScore[url] = 1
89d1d8ba 138
bc503c2a 139 getForeignPodsList(url, function (err, foreignPodsList) {
89d1d8ba 140 if (err) return callback(err)
bc503c2a 141 if (foreignPodsList.length === 0) return callback()
89d1d8ba 142
bc503c2a
C
143 foreignPodsList.forEach(function (foreignPod) {
144 const foreignUrl = foreignPod.url
89d1d8ba 145
bc503c2a
C
146 if (podsScore[foreignUrl]) podsScore[foreignUrl]++
147 else podsScore[foreignUrl] = 1
89d1d8ba 148 })
cbe2f7c3
C
149
150 callback()
89d1d8ba
C
151 })
152}
153
bc503c2a 154function computeWinningPods (urls, podsScore) {
89d1d8ba
C
155 // Build the list of pods to add
156 // Only add a pod if it exists in more than a half base pods
bc503c2a
C
157 const podsList = []
158 const baseScore = urls.length / 2
d6ea0175 159 Object.keys(podsScore).forEach(function (pod) {
bc503c2a 160 if (podsScore[pod] > baseScore) podsList.push({ url: pod })
89d1d8ba 161 })
d6ea0175
C
162 console.log(urls)
163 console.log(podsScore)
164 console.log(podsList)
bc503c2a 165 return podsList
89d1d8ba
C
166}
167
9f10b292 168function getForeignPodsList (url, callback) {
f0f5567b 169 const path = '/api/' + constants.API_VERSION + '/pods'
c173e565 170
9f10b292
C
171 request.get(url + path, function (err, response, body) {
172 if (err) return callback(err)
8425cb89 173
9f10b292
C
174 callback(null, JSON.parse(body))
175 })
176}
89d1d8ba 177
bc503c2a 178function makeRequestsToWinningPods (cert, podsList, callback) {
89d1d8ba 179 // Stop pool requests
e3647ae2 180 requestsScheduler.deactivate()
89d1d8ba 181 // Flush pool requests
e3647ae2 182 requestsScheduler.forceSend()
89d1d8ba
C
183
184 // Get the list of our videos to send to our new friends
bc503c2a 185 Videos.listOwned(function (err, videosList) {
89d1d8ba
C
186 if (err) {
187 logger.error('Cannot get the list of videos we own.')
188 return callback(err)
189 }
190
f0f5567b 191 const data = {
89d1d8ba
C
192 url: http + '://' + host + ':' + port,
193 publicKey: cert,
bc503c2a 194 videos: videosList
89d1d8ba
C
195 }
196
197 requests.makeMultipleRetryRequest(
198 { method: 'POST', path: '/api/' + constants.API_VERSION + '/pods/', data: data },
199
bc503c2a 200 podsList,
89d1d8ba 201
bc503c2a 202 function eachRequest (err, response, body, url, pod, callbackEachRequest) {
89d1d8ba
C
203 // We add the pod if it responded correctly with its public certificate
204 if (!err && response.statusCode === 200) {
205 Pods.add({ url: pod.url, publicKey: body.cert, score: constants.FRIEND_BASE_SCORE }, function (err) {
206 if (err) {
207 logger.error('Error with adding %s pod.', pod.url, { error: err })
bc503c2a 208 return callbackEachRequest()
89d1d8ba 209 }
bc503c2a 210
cbe2f7c3 211 videos.createRemoteVideos(body.videos, function (err) {
89d1d8ba
C
212 if (err) {
213 logger.error('Error with adding videos of pod.', pod.url, { error: err })
bc503c2a 214 return callbackEachRequest()
89d1d8ba
C
215 }
216
217 logger.debug('Adding remote videos from %s.', pod.url, { videos: body.videos })
bc503c2a 218 return callbackEachRequest()
89d1d8ba
C
219 })
220 })
221 } else {
222 logger.error('Error with adding %s pod.', pod.url, { error: err || new Error('Status not 200') })
bc503c2a 223 return callbackEachRequest()
89d1d8ba
C
224 }
225 },
226
227 function endRequests (err) {
228 // Now we made new friends, we can re activate the pool of requests
e3647ae2 229 requestsScheduler.activate()
89d1d8ba
C
230
231 if (err) {
232 logger.error('There was some errors when we wanted to make friends.')
233 return callback(err)
234 }
235
236 logger.debug('makeRequestsToWinningPods finished.')
237 return callback(null)
238 }
239 )
240 })
241}