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