Server: improve requests scheduler
[oweals/peertube.git] / server / models / pod.js
1 'use strict'
2
3 const map = require('lodash/map')
4
5 const constants = require('../initializers/constants')
6 const customPodsValidators = require('../helpers/custom-validators').pods
7
8 // ---------------------------------------------------------------------------
9
10 module.exports = function (sequelize, DataTypes) {
11   const Pod = sequelize.define('Pod',
12     {
13       host: {
14         type: DataTypes.STRING,
15         allowNull: false,
16         validate: {
17           isHost: function (value) {
18             const res = customPodsValidators.isHostValid(value)
19             if (res === false) throw new Error('Host not valid.')
20           }
21         }
22       },
23       publicKey: {
24         type: DataTypes.STRING(5000),
25         allowNull: false
26       },
27       score: {
28         type: DataTypes.INTEGER,
29         defaultValue: constants.FRIEND_SCORE.BASE,
30         allowNull: false,
31         validate: {
32           isInt: true,
33           max: constants.FRIEND_SCORE.MAX
34         }
35       }
36     },
37     {
38       indexes: [
39         {
40           fields: [ 'host' ]
41         },
42         {
43           fields: [ 'score' ]
44         }
45       ],
46       classMethods: {
47         associate,
48
49         countAll,
50         incrementScores,
51         list,
52         listAllIds,
53         listRandomPodIdsWithRequest,
54         listBadPods,
55         load,
56         loadByHost,
57         removeAll
58       },
59       instanceMethods: {
60         toFormatedJSON
61       }
62     }
63   )
64
65   return Pod
66 }
67
68 // ------------------------------ METHODS ------------------------------
69
70 function toFormatedJSON () {
71   const json = {
72     id: this.id,
73     host: this.host,
74     score: this.score,
75     createdAt: this.createdAt
76   }
77
78   return json
79 }
80
81 // ------------------------------ Statics ------------------------------
82
83 function associate (models) {
84   this.belongsToMany(models.Request, {
85     foreignKey: 'podId',
86     through: models.RequestToPod,
87     onDelete: 'cascade'
88   })
89 }
90
91 function countAll (callback) {
92   return this.count().asCallback(callback)
93 }
94
95 function incrementScores (ids, value, callback) {
96   if (!callback) callback = function () {}
97
98   const update = {
99     score: this.sequelize.literal('score +' + value)
100   }
101
102   const options = {
103     where: {
104       id: {
105         $in: ids
106       }
107     },
108     // In this case score is a literal and not an integer so we do not validate it
109     validate: false
110   }
111
112   return this.update(update, options).asCallback(callback)
113 }
114
115 function list (callback) {
116   return this.findAll().asCallback(callback)
117 }
118
119 function listAllIds (transaction, callback) {
120   if (!callback) {
121     callback = transaction
122     transaction = null
123   }
124
125   const query = {
126     attributes: [ 'id' ]
127   }
128
129   if (transaction) query.transaction = transaction
130
131   return this.findAll(query).asCallback(function (err, pods) {
132     if (err) return callback(err)
133
134     return callback(null, map(pods, 'id'))
135   })
136 }
137
138 function listRandomPodIdsWithRequest (limit, callback) {
139   const self = this
140
141   self.count().asCallback(function (err, count) {
142     if (err) return callback(err)
143
144     // Optimization...
145     if (count === 0) return callback(null, [])
146
147     let start = Math.floor(Math.random() * count) - limit
148     if (start < 0) start = 0
149
150     const query = {
151       attributes: [ 'id' ],
152       order: [
153         [ 'id', 'ASC' ]
154       ],
155       offset: start,
156       limit: limit,
157       where: {
158         id: {
159           $in: [
160             this.sequelize.literal('SELECT "podId" FROM "RequestToPods"')
161           ]
162         }
163       }
164     }
165
166     return this.findAll(query).asCallback(function (err, pods) {
167       if (err) return callback(err)
168
169       return callback(null, map(pods, 'id'))
170     })
171   })
172 }
173
174 function listBadPods (callback) {
175   const query = {
176     where: {
177       score: { $lte: 0 }
178     }
179   }
180
181   return this.findAll(query).asCallback(callback)
182 }
183
184 function load (id, callback) {
185   return this.findById(id).asCallback(callback)
186 }
187
188 function loadByHost (host, callback) {
189   const query = {
190     where: {
191       host: host
192     }
193   }
194
195   return this.findOne(query).asCallback(callback)
196 }
197
198 function removeAll (callback) {
199   return this.destroy().asCallback(callback)
200 }