3 const async = require('async')
4 const config = require('config')
5 const fs = require('fs')
6 const request = require('request')
8 const constants = require('../initializers/constants')
9 const logger = require('../helpers/logger')
10 const peertubeCrypto = require('../helpers/peertubeCrypto')
11 const Pods = require('../models/pods')
12 const requestsScheduler = require('../lib/requestsScheduler')
13 const requests = require('../helpers/requests')
14 const videos = require('../lib/videos')
15 const Videos = require('../models/videos')
17 const http = config.get('webserver.https') ? 'https' : 'http'
18 const host = config.get('webserver.host')
19 const port = config.get('webserver.port')
22 addVideoToFriends: addVideoToFriends,
23 hasFriends: hasFriends,
24 getMyCertificate: getMyCertificate,
25 makeFriends: makeFriends,
26 quitFriends: quitFriends,
27 removeVideoToFriends: removeVideoToFriends
30 function addVideoToFriends (video) {
31 // To avoid duplicates
32 const id = video.name + video.magnetUri
33 // ensure namePath is null
35 requestsScheduler.addRequest(id, 'add', video)
38 function hasFriends (callback) {
39 Pods.count(function (err, count) {
40 if (err) return callback(err)
42 const hasFriends = (count !== 0)
43 callback(null, hasFriends)
47 function getMyCertificate (callback) {
48 fs.readFile(peertubeCrypto.getCertDir() + 'peertube.pub', 'utf8', callback)
51 function makeFriends (callback) {
54 logger.info('Make friends!')
55 getMyCertificate(function (err, cert) {
57 logger.error('Cannot read public cert.')
61 const urls = config.get('network.friends')
63 async.each(urls, function (url, callbackEach) {
64 computeForeignPodsList(url, podsScore, callbackEach)
66 if (err) return callback(err)
68 logger.debug('Pods scores computed.', { podsScore: podsScore })
69 const podsList = computeWinningPods(urls, podsScore)
70 logger.debug('Pods that we keep.', { podsToKeep: podsList })
72 makeRequestsToWinningPods(cert, podsList, callback)
77 function quitFriends (callback) {
79 requestsScheduler.deactivate()
80 // Flush pool requests
81 requestsScheduler.forceSend()
84 function getPodsList (callbackAsync) {
85 return Pods.list(callbackAsync)
88 function announceIQuitMyFriends (pods, callbackAsync) {
91 path: '/api/' + constants.API_VERSION + '/pods/remove',
95 url: 'me' // Fake data
99 // Announce we quit them
100 requests.makeMultipleRetryRequest(request, pods, function (err) {
101 return callbackAsync(err)
105 function removePodsFromDB (callbackAsync) {
106 Pods.removeAll(function (err) {
107 return callbackAsync(err)
111 function listRemoteVideos (callbackAsync) {
112 logger.info('Broke friends, so sad :(')
114 Videos.listFromRemotes(callbackAsync)
117 function removeTheRemoteVideos (videosList, callbackAsync) {
118 videos.removeRemoteVideos(videosList, function (err) {
120 logger.error('Cannot remove remote videos.', { error: err })
121 return callbackAsync(err)
124 return callbackAsync(null)
128 // Don't forget to re activate the scheduler, even if there was an error
129 requestsScheduler.activate()
131 if (err) return callback(err)
133 logger.info('Removed all remote videos.')
134 return callback(null)
138 function removeVideoToFriends (video) {
139 // To avoid duplicates
140 const id = video.name + video.magnetUri
141 requestsScheduler.addRequest(id, 'remove', video)
144 // ---------------------------------------------------------------------------
146 module.exports = pods
148 // ---------------------------------------------------------------------------
150 function computeForeignPodsList (url, podsScore, callback) {
151 // Let's give 1 point to the pod we ask the friends list
154 getForeignPodsList(url, function (err, foreignPodsList) {
155 if (err) return callback(err)
156 if (foreignPodsList.length === 0) return callback()
158 foreignPodsList.forEach(function (foreignPod) {
159 const foreignUrl = foreignPod.url
161 if (podsScore[foreignUrl]) podsScore[foreignUrl]++
162 else podsScore[foreignUrl] = 1
169 function computeWinningPods (urls, podsScore) {
170 // Build the list of pods to add
171 // Only add a pod if it exists in more than a half base pods
173 const baseScore = urls.length / 2
174 Object.keys(podsScore).forEach(function (pod) {
175 if (podsScore[pod] > baseScore) podsList.push({ url: pod })
181 function getForeignPodsList (url, callback) {
182 const path = '/api/' + constants.API_VERSION + '/pods'
184 request.get(url + path, function (err, response, body) {
185 if (err) return callback(err)
187 callback(null, JSON.parse(body))
191 function makeRequestsToWinningPods (cert, podsList, callback) {
192 // Stop pool requests
193 requestsScheduler.deactivate()
194 // Flush pool requests
195 requestsScheduler.forceSend()
197 // Get the list of our videos to send to our new friends
198 Videos.listOwned(function (err, videosList) {
200 logger.error('Cannot get the list of videos we own.')
205 url: http + '://' + host + ':' + port,
210 requests.makeMultipleRetryRequest(
211 { method: 'POST', path: '/api/' + constants.API_VERSION + '/pods/', data: data },
215 // Callback called after each request
216 function eachRequest (err, response, body, url, pod, callbackEachRequest) {
217 // We add the pod if it responded correctly with its public certificate
218 if (!err && response.statusCode === 200) {
219 Pods.add({ url: pod.url, publicKey: body.cert, score: constants.FRIEND_BASE_SCORE }, function (err) {
221 logger.error('Error with adding %s pod.', pod.url, { error: err })
222 return callbackEachRequest()
225 videos.createRemoteVideos(body.videos, function (err) {
227 logger.error('Error with adding videos of pod.', pod.url, { error: err })
228 return callbackEachRequest()
231 logger.debug('Adding remote videos from %s.', pod.url, { videos: body.videos })
232 return callbackEachRequest()
236 logger.error('Error with adding %s pod.', pod.url, { error: err || new Error('Status not 200') })
237 return callbackEachRequest()
241 // Final callback, we've ended all the requests
242 function endRequests (err) {
243 // Now we made new friends, we can re activate the pool of requests
244 requestsScheduler.activate()
247 logger.error('There was some errors when we wanted to make friends.')
251 logger.debug('makeRequestsToWinningPods finished.')
252 return callback(null)