]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/lib/friends.js
3b8a52060f5aac9b1994597ad038b294cd9bb917
[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 has_friends = (count !== 0)
43 callback(null, has_friends)
44 })
45 }
46
47 function getMyCertificate (callback) {
48 fs.readFile(peertubeCrypto.getCertDir() + 'peertube.pub', 'utf8', callback)
49 }
50
51 function makeFriends (callback) {
52 const pods_score = {}
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, callback_each) {
64 computeForeignPodsList(url, pods_score, callback_each)
65 }, function (err) {
66 if (err) return callback(err)
67
68 logger.debug('Pods scores computed.', { pods_score: pods_score })
69 const pods_list = computeWinningPods(urls, pods_score)
70 logger.debug('Pods that we keep.', { pods_to_keep: pods_list })
71
72 makeRequestsToWinningPods(cert, pods_list, 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, videos_list) {
106 if (err) return callback(err)
107
108 videos.removeRemoteVideos(videos_list, 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, pods_score, callback) {
136 // Let's give 1 point to the pod we ask the friends list
137 pods_score[url] = 1
138
139 getForeignPodsList(url, function (err, foreign_pods_list) {
140 if (err) return callback(err)
141 if (foreign_pods_list.length === 0) return callback()
142
143 foreign_pods_list.forEach(function (foreign_pod) {
144 const foreign_url = foreign_pod.url
145
146 if (pods_score[foreign_url]) pods_score[foreign_url]++
147 else pods_score[foreign_url] = 1
148 })
149
150 callback()
151 })
152 }
153
154 function computeWinningPods (urls, pods_score) {
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 pods_list = []
158 const base_score = urls.length / 2
159 Object.keys(pods_score).forEach(function (pod) {
160 if (pods_score[pod] > base_score) pods_list.push({ url: pod })
161 })
162
163 return pods_list
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, pods_list, 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, videos_list) {
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: videos_list
193 }
194
195 requests.makeMultipleRetryRequest(
196 { method: 'POST', path: '/api/' + constants.API_VERSION + '/pods/', data: data },
197
198 pods_list,
199
200 function eachRequest (err, response, body, url, pod, callback_each_request) {
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 callback_each_request()
207 }
208 console.log('hihi')
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 callback_each_request()
213 }
214
215 console.log('kik')
216
217 logger.debug('Adding remote videos from %s.', pod.url, { videos: body.videos })
218 return callback_each_request()
219 })
220 })
221 } else {
222 logger.error('Error with adding %s pod.', pod.url, { error: err || new Error('Status not 200') })
223 return callback_each_request()
224 }
225 },
226
227 function endRequests (err) {
228 // Now we made new friends, we can re activate the pool of requests
229 requestsScheduler.activate()
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 }