aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/models
diff options
context:
space:
mode:
Diffstat (limited to 'server/models')
-rw-r--r--server/models/pod.js63
-rw-r--r--server/models/request-to-pod.js4
-rw-r--r--server/models/request-video-qadu.js154
-rw-r--r--server/models/request.js63
-rw-r--r--server/models/video.js13
5 files changed, 232 insertions, 65 deletions
diff --git a/server/models/pod.js b/server/models/pod.js
index 79afb737a..14814708e 100644
--- a/server/models/pod.js
+++ b/server/models/pod.js
@@ -1,8 +1,11 @@
1'use strict' 1'use strict'
2 2
3const each = require('async/each')
3const map = require('lodash/map') 4const map = require('lodash/map')
5const waterfall = require('async/waterfall')
4 6
5const constants = require('../initializers/constants') 7const constants = require('../initializers/constants')
8const logger = require('../helpers/logger')
6const customPodsValidators = require('../helpers/custom-validators').pods 9const customPodsValidators = require('../helpers/custom-validators').pods
7 10
8// --------------------------------------------------------------------------- 11// ---------------------------------------------------------------------------
@@ -62,6 +65,7 @@ module.exports = function (sequelize, DataTypes) {
62 listBadPods, 65 listBadPods,
63 load, 66 load,
64 loadByHost, 67 loadByHost,
68 updatePodsScore,
65 removeAll 69 removeAll
66 }, 70 },
67 instanceMethods: { 71 instanceMethods: {
@@ -144,7 +148,7 @@ function listAllIds (transaction, callback) {
144 }) 148 })
145} 149}
146 150
147function listRandomPodIdsWithRequest (limit, callback) { 151function listRandomPodIdsWithRequest (limit, tableRequestPod, callback) {
148 const self = this 152 const self = this
149 153
150 self.count().asCallback(function (err, count) { 154 self.count().asCallback(function (err, count) {
@@ -166,7 +170,7 @@ function listRandomPodIdsWithRequest (limit, callback) {
166 where: { 170 where: {
167 id: { 171 id: {
168 $in: [ 172 $in: [
169 this.sequelize.literal('SELECT "podId" FROM "RequestToPods"') 173 this.sequelize.literal('SELECT "podId" FROM "' + tableRequestPod + '"')
170 ] 174 ]
171 } 175 }
172 } 176 }
@@ -207,3 +211,58 @@ function loadByHost (host, callback) {
207function removeAll (callback) { 211function removeAll (callback) {
208 return this.destroy().asCallback(callback) 212 return this.destroy().asCallback(callback)
209} 213}
214
215function updatePodsScore (goodPods, badPods) {
216 const self = this
217
218 logger.info('Updating %d good pods and %d bad pods scores.', goodPods.length, badPods.length)
219
220 if (goodPods.length !== 0) {
221 this.incrementScores(goodPods, constants.PODS_SCORE.BONUS, function (err) {
222 if (err) logger.error('Cannot increment scores of good pods.', { error: err })
223 })
224 }
225
226 if (badPods.length !== 0) {
227 this.incrementScores(badPods, constants.PODS_SCORE.MALUS, function (err) {
228 if (err) logger.error('Cannot decrement scores of bad pods.', { error: err })
229 removeBadPods.call(self)
230 })
231 }
232}
233
234// ---------------------------------------------------------------------------
235
236// Remove pods with a score of 0 (too many requests where they were unreachable)
237function removeBadPods () {
238 const self = this
239
240 waterfall([
241 function findBadPods (callback) {
242 self.sequelize.models.Pod.listBadPods(function (err, pods) {
243 if (err) {
244 logger.error('Cannot find bad pods.', { error: err })
245 return callback(err)
246 }
247
248 return callback(null, pods)
249 })
250 },
251
252 function removeTheseBadPods (pods, callback) {
253 each(pods, function (pod, callbackEach) {
254 pod.destroy().asCallback(callbackEach)
255 }, function (err) {
256 return callback(err, pods.length)
257 })
258 }
259 ], function (err, numberOfPodsRemoved) {
260 if (err) {
261 logger.error('Cannot remove bad pods.', { error: err })
262 } else if (numberOfPodsRemoved) {
263 logger.info('Removed %d pods.', numberOfPodsRemoved)
264 } else {
265 logger.info('No need to remove bad pods.')
266 }
267 })
268}
diff --git a/server/models/request-to-pod.js b/server/models/request-to-pod.js
index f42a53458..0e01a842e 100644
--- a/server/models/request-to-pod.js
+++ b/server/models/request-to-pod.js
@@ -17,7 +17,7 @@ module.exports = function (sequelize, DataTypes) {
17 } 17 }
18 ], 18 ],
19 classMethods: { 19 classMethods: {
20 removePodOf 20 removeByRequestIdsAndPod
21 } 21 }
22 }) 22 })
23 23
@@ -26,7 +26,7 @@ module.exports = function (sequelize, DataTypes) {
26 26
27// --------------------------------------------------------------------------- 27// ---------------------------------------------------------------------------
28 28
29function removePodOf (requestsIds, podId, callback) { 29function removeByRequestIdsAndPod (requestsIds, podId, callback) {
30 if (!callback) callback = function () {} 30 if (!callback) callback = function () {}
31 31
32 const query = { 32 const query = {
diff --git a/server/models/request-video-qadu.js b/server/models/request-video-qadu.js
new file mode 100644
index 000000000..7010fc992
--- /dev/null
+++ b/server/models/request-video-qadu.js
@@ -0,0 +1,154 @@
1'use strict'
2
3/*
4 Request Video for Quick And Dirty Updates like:
5 - views
6 - likes
7 - dislikes
8
9 We can't put it in the same system than basic requests for efficiency.
10 Moreover we don't want to slow down the basic requests with a lot of views/likes/dislikes requests.
11 So we put it an independant request scheduler.
12*/
13
14const values = require('lodash/values')
15
16const constants = require('../initializers/constants')
17
18// ---------------------------------------------------------------------------
19
20module.exports = function (sequelize, DataTypes) {
21 const RequestVideoQadu = sequelize.define('RequestVideoQadu',
22 {
23 type: {
24 type: DataTypes.ENUM(values(constants.REQUEST_VIDEO_QADU_TYPES)),
25 allowNull: false
26 }
27 },
28 {
29 timestamps: false,
30 indexes: [
31 {
32 fields: [ 'podId' ]
33 },
34 {
35 fields: [ 'videoId' ]
36 }
37 ],
38 classMethods: {
39 associate,
40
41 listWithLimitAndRandom,
42
43 countTotalRequests,
44 removeAll,
45 removeByRequestIdsAndPod
46 }
47 }
48 )
49
50 return RequestVideoQadu
51}
52
53// ------------------------------ STATICS ------------------------------
54
55function associate (models) {
56 this.belongsTo(models.Pod, {
57 foreignKey: {
58 name: 'podId',
59 allowNull: false
60 },
61 onDelete: 'CASCADE'
62 })
63
64 this.belongsTo(models.Video, {
65 foreignKey: {
66 name: 'videoId',
67 allowNull: false
68 },
69 onDelete: 'CASCADE'
70 })
71}
72
73function countTotalRequests (callback) {
74 const query = {
75 include: [ this.sequelize.models.Pod ]
76 }
77
78 return this.count(query).asCallback(callback)
79}
80
81function listWithLimitAndRandom (limitPods, limitRequestsPerPod, callback) {
82 const self = this
83 const Pod = this.sequelize.models.Pod
84
85 Pod.listRandomPodIdsWithRequest(limitPods, 'RequestVideoQadus', function (err, podIds) {
86 if (err) return callback(err)
87
88 // We don't have friends that have requests
89 if (podIds.length === 0) return callback(null, [])
90
91 const query = {
92 include: [
93 {
94 model: self.sequelize.models.Pod,
95 where: {
96 id: {
97 $in: podIds
98 }
99 }
100 },
101 {
102 model: self.sequelize.models.Video
103 }
104 ]
105 }
106
107 self.findAll(query).asCallback(function (err, requests) {
108 if (err) return callback(err)
109
110 const requestsGrouped = groupAndTruncateRequests(requests, limitRequestsPerPod)
111 return callback(err, requestsGrouped)
112 })
113 })
114}
115
116function removeByRequestIdsAndPod (ids, podId, callback) {
117 const query = {
118 where: {
119 id: {
120 $in: ids
121 },
122 podId
123 }
124 }
125
126 this.destroy(query).asCallback(callback)
127}
128
129function removeAll (callback) {
130 // Delete all requests
131 this.truncate({ cascade: true }).asCallback(callback)
132}
133
134// ---------------------------------------------------------------------------
135
136function groupAndTruncateRequests (requests, limitRequestsPerPod) {
137 const requestsGrouped = {}
138
139 requests.forEach(function (request) {
140 const pod = request.Pod
141
142 if (!requestsGrouped[pod.id]) requestsGrouped[pod.id] = []
143
144 if (requestsGrouped[pod.id].length < limitRequestsPerPod) {
145 requestsGrouped[pod.id].push({
146 request: request,
147 video: request.Video,
148 pod
149 })
150 }
151 })
152
153 return requestsGrouped
154}
diff --git a/server/models/request.js b/server/models/request.js
index ca616d130..de73501fc 100644
--- a/server/models/request.js
+++ b/server/models/request.js
@@ -1,11 +1,8 @@
1'use strict' 1'use strict'
2 2
3const each = require('async/each')
4const waterfall = require('async/waterfall')
5const values = require('lodash/values') 3const values = require('lodash/values')
6 4
7const constants = require('../initializers/constants') 5const constants = require('../initializers/constants')
8const logger = require('../helpers/logger')
9 6
10// --------------------------------------------------------------------------- 7// ---------------------------------------------------------------------------
11 8
@@ -28,8 +25,6 @@ module.exports = function (sequelize, DataTypes) {
28 listWithLimitAndRandom, 25 listWithLimitAndRandom,
29 26
30 countTotalRequests, 27 countTotalRequests,
31 removeBadPods,
32 updatePodsScore,
33 removeAll, 28 removeAll,
34 removeWithEmptyTo 29 removeWithEmptyTo
35 } 30 }
@@ -60,71 +55,17 @@ function countTotalRequests (callback) {
60 return this.count(query).asCallback(callback) 55 return this.count(query).asCallback(callback)
61} 56}
62 57
63// Remove pods with a score of 0 (too many requests where they were unreachable)
64function removeBadPods () {
65 const self = this
66
67 waterfall([
68 function findBadPods (callback) {
69 self.sequelize.models.Pod.listBadPods(function (err, pods) {
70 if (err) {
71 logger.error('Cannot find bad pods.', { error: err })
72 return callback(err)
73 }
74
75 return callback(null, pods)
76 })
77 },
78
79 function removeTheseBadPods (pods, callback) {
80 each(pods, function (pod, callbackEach) {
81 pod.destroy().asCallback(callbackEach)
82 }, function (err) {
83 return callback(err, pods.length)
84 })
85 }
86 ], function (err, numberOfPodsRemoved) {
87 if (err) {
88 logger.error('Cannot remove bad pods.', { error: err })
89 } else if (numberOfPodsRemoved) {
90 logger.info('Removed %d pods.', numberOfPodsRemoved)
91 } else {
92 logger.info('No need to remove bad pods.')
93 }
94 })
95}
96
97function updatePodsScore (goodPods, badPods) {
98 const self = this
99 const Pod = this.sequelize.models.Pod
100
101 logger.info('Updating %d good pods and %d bad pods scores.', goodPods.length, badPods.length)
102
103 if (goodPods.length !== 0) {
104 Pod.incrementScores(goodPods, constants.PODS_SCORE.BONUS, function (err) {
105 if (err) logger.error('Cannot increment scores of good pods.', { error: err })
106 })
107 }
108
109 if (badPods.length !== 0) {
110 Pod.incrementScores(badPods, constants.PODS_SCORE.MALUS, function (err) {
111 if (err) logger.error('Cannot decrement scores of bad pods.', { error: err })
112 removeBadPods.call(self)
113 })
114 }
115}
116
117function listWithLimitAndRandom (limitPods, limitRequestsPerPod, callback) { 58function listWithLimitAndRandom (limitPods, limitRequestsPerPod, callback) {
118 const self = this 59 const self = this
119 const Pod = this.sequelize.models.Pod 60 const Pod = this.sequelize.models.Pod
120 61
121 Pod.listRandomPodIdsWithRequest(limitPods, function (err, podIds) { 62 Pod.listRandomPodIdsWithRequest(limitPods, 'RequestToPods', function (err, podIds) {
122 if (err) return callback(err) 63 if (err) return callback(err)
123 64
124 // We don't have friends that have requests 65 // We don't have friends that have requests
125 if (podIds.length === 0) return callback(null, []) 66 if (podIds.length === 0) return callback(null, [])
126 67
127 // The the first x requests of these pods 68 // The first x requests of these pods
128 // It is very important to sort by id ASC to keep the requests order! 69 // It is very important to sort by id ASC to keep the requests order!
129 const query = { 70 const query = {
130 order: [ 71 order: [
diff --git a/server/models/video.js b/server/models/video.js
index d0fd61eb4..daa273845 100644
--- a/server/models/video.js
+++ b/server/models/video.js
@@ -80,6 +80,15 @@ module.exports = function (sequelize, DataTypes) {
80 if (res === false) throw new Error('Video duration is not valid.') 80 if (res === false) throw new Error('Video duration is not valid.')
81 } 81 }
82 } 82 }
83 },
84 views: {
85 type: DataTypes.INTEGER,
86 allowNull: false,
87 defaultValue: 0,
88 validate: {
89 min: 0,
90 isInt: true
91 }
83 } 92 }
84 }, 93 },
85 { 94 {
@@ -101,6 +110,9 @@ module.exports = function (sequelize, DataTypes) {
101 }, 110 },
102 { 111 {
103 fields: [ 'infoHash' ] 112 fields: [ 'infoHash' ]
113 },
114 {
115 fields: [ 'views' ]
104 } 116 }
105 ], 117 ],
106 classMethods: { 118 classMethods: {
@@ -336,6 +348,7 @@ function toFormatedJSON () {
336 magnetUri: this.generateMagnetUri(), 348 magnetUri: this.generateMagnetUri(),
337 author: this.Author.name, 349 author: this.Author.name,
338 duration: this.duration, 350 duration: this.duration,
351 views: this.views,
339 tags: map(this.Tags, 'name'), 352 tags: map(this.Tags, 'name'),
340 thumbnailPath: pathUtils.join(constants.STATIC_PATHS.THUMBNAILS, this.getThumbnailName()), 353 thumbnailPath: pathUtils.join(constants.STATIC_PATHS.THUMBNAILS, this.getThumbnailName()),
341 createdAt: this.createdAt, 354 createdAt: this.createdAt,