]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/models/pod/pod.ts
Formated -> Formatted
[github/Chocobozzz/PeerTube.git] / server / models / pod / pod.ts
CommitLineData
65fcc311 1import { map } from 'lodash'
e02643f3 2import * as Sequelize from 'sequelize'
9f10b292 3
74889a71
C
4import { FRIEND_SCORE, PODS_SCORE } from '../../initializers'
5import { logger, isHostValid } from '../../helpers'
9f10b292 6
74889a71 7import { addMethodsToModel } from '../utils'
e02643f3 8import {
e02643f3
C
9 PodInstance,
10 PodAttributes,
11
12 PodMethods
13} from './pod-interface'
14
15let Pod: Sequelize.Model<PodInstance, PodAttributes>
0aef76c4 16let toFormattedJSON: PodMethods.ToFormattedJSON
e02643f3
C
17let countAll: PodMethods.CountAll
18let incrementScores: PodMethods.IncrementScores
19let list: PodMethods.List
20let listAllIds: PodMethods.ListAllIds
21let listRandomPodIdsWithRequest: PodMethods.ListRandomPodIdsWithRequest
22let listBadPods: PodMethods.ListBadPods
23let load: PodMethods.Load
24let loadByHost: PodMethods.LoadByHost
25let removeAll: PodMethods.RemoveAll
26let updatePodsScore: PodMethods.UpdatePodsScore
27
127944aa
C
28export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) {
29 Pod = sequelize.define<PodInstance, PodAttributes>('Pod',
feb4bdfd
C
30 {
31 host: {
67bf9b96
C
32 type: DataTypes.STRING,
33 allowNull: false,
34 validate: {
075f16ca 35 isHost: value => {
65fcc311 36 const res = isHostValid(value)
67bf9b96
C
37 if (res === false) throw new Error('Host not valid.')
38 }
39 }
feb4bdfd
C
40 },
41 publicKey: {
67bf9b96
C
42 type: DataTypes.STRING(5000),
43 allowNull: false
feb4bdfd
C
44 },
45 score: {
46 type: DataTypes.INTEGER,
65fcc311 47 defaultValue: FRIEND_SCORE.BASE,
67bf9b96
C
48 allowNull: false,
49 validate: {
50 isInt: true,
65fcc311 51 max: FRIEND_SCORE.MAX
67bf9b96 52 }
4793c343
C
53 },
54 email: {
55 type: DataTypes.STRING(400),
ad4a8a1c
C
56 allowNull: false,
57 validate: {
58 isEmail: true
59 }
feb4bdfd 60 }
feb4bdfd
C
61 },
62 {
319d072e
C
63 indexes: [
64 {
5d67f289
C
65 fields: [ 'host' ],
66 unique: true
319d072e
C
67 },
68 {
69 fields: [ 'score' ]
70 }
e02643f3 71 ]
feb4bdfd
C
72 }
73 )
74
e02643f3
C
75 const classMethods = [
76 associate,
77
78 countAll,
79 incrementScores,
80 list,
81 listAllIds,
82 listRandomPodIdsWithRequest,
83 listBadPods,
84 load,
85 loadByHost,
86 updatePodsScore,
87 removeAll
88 ]
0aef76c4 89 const instanceMethods = [ toFormattedJSON ]
e02643f3
C
90 addMethodsToModel(Pod, classMethods, instanceMethods)
91
feb4bdfd 92 return Pod
53572423
C
93}
94
53572423
C
95// ------------------------------ METHODS ------------------------------
96
0aef76c4 97toFormattedJSON = function (this: PodInstance) {
53572423 98 const json = {
feb4bdfd 99 id: this.id,
49abbbbe 100 host: this.host,
4793c343 101 email: this.email,
70c065d6 102 score: this.score as number,
feb4bdfd 103 createdAt: this.createdAt
53572423
C
104 }
105
106 return json
107}
108
a3ee6fa2
C
109// ------------------------------ Statics ------------------------------
110
feb4bdfd 111function associate (models) {
e02643f3 112 Pod.belongsToMany(models.Request, {
feb4bdfd
C
113 foreignKey: 'podId',
114 through: models.RequestToPod,
7920c273 115 onDelete: 'cascade'
feb4bdfd
C
116 })
117}
118
6fcd19ba
C
119countAll = function () {
120 return Pod.count()
9f10b292 121}
45239549 122
6fcd19ba 123incrementScores = function (ids: number[], value: number) {
feb4bdfd 124 const update = {
e02643f3 125 score: Sequelize.literal('score +' + value)
feb4bdfd
C
126 }
127
67bf9b96 128 const options = {
feb4bdfd
C
129 where: {
130 id: {
131 $in: ids
132 }
67bf9b96
C
133 },
134 // In this case score is a literal and not an integer so we do not validate it
135 validate: false
feb4bdfd
C
136 }
137
6fcd19ba 138 return Pod.update(update, options)
9f10b292 139}
45239549 140
6fcd19ba
C
141list = function () {
142 return Pod.findAll()
9f10b292 143}
8c308c2b 144
6fcd19ba
C
145listAllIds = function (transaction: Sequelize.Transaction) {
146 const query: Sequelize.FindOptions = {
147 attributes: [ 'id' ],
148 transaction
feb4bdfd
C
149 }
150
6fcd19ba
C
151 return Pod.findAll(query).then(pods => {
152 return map(pods, 'id')
00057e85 153 })
528a9efa
C
154}
155
6fcd19ba
C
156listRandomPodIdsWithRequest = function (limit: number, tableWithPods: string, tableWithPodsJoins: string) {
157 return Pod.count().then(count => {
bd14d16a 158 // Optimization...
6fcd19ba 159 if (count === 0) return []
bd14d16a
C
160
161 let start = Math.floor(Math.random() * count) - limit
162 if (start < 0) start = 0
163
164 const query = {
165 attributes: [ 'id' ],
166 order: [
167 [ 'id', 'ASC' ]
168 ],
169 offset: start,
170 limit: limit,
171 where: {
172 id: {
173 $in: [
e02643f3 174 Sequelize.literal(`SELECT DISTINCT "${tableWithPods}"."podId" FROM "${tableWithPods}" ${tableWithPodsJoins}`)
bd14d16a
C
175 ]
176 }
177 }
178 }
179
6fcd19ba
C
180 return Pod.findAll(query).then(pods => {
181 return map(pods, 'id')
bd14d16a
C
182 })
183 })
184}
185
6fcd19ba 186listBadPods = function () {
feb4bdfd
C
187 const query = {
188 where: {
189 score: { $lte: 0 }
190 }
191 }
192
6fcd19ba 193 return Pod.findAll(query)
9f10b292 194}
8c308c2b 195
6fcd19ba
C
196load = function (id: number) {
197 return Pod.findById(id)
9f10b292 198}
c45f7f84 199
6fcd19ba 200loadByHost = function (host: string) {
feb4bdfd
C
201 const query = {
202 where: {
203 host: host
204 }
205 }
206
6fcd19ba 207 return Pod.findOne(query)
9f10b292 208}
c45f7f84 209
6fcd19ba
C
210removeAll = function () {
211 return Pod.destroy()
a3ee6fa2 212}
9e167724 213
69818c93 214updatePodsScore = function (goodPods: number[], badPods: number[]) {
9e167724
C
215 logger.info('Updating %d good pods and %d bad pods scores.', goodPods.length, badPods.length)
216
217 if (goodPods.length !== 0) {
6fcd19ba 218 incrementScores(goodPods, PODS_SCORE.BONUS).catch(err => {
ad0997ad 219 logger.error('Cannot increment scores of good pods.', err)
9e167724
C
220 })
221 }
222
223 if (badPods.length !== 0) {
6fcd19ba
C
224 incrementScores(badPods, PODS_SCORE.MALUS)
225 .then(() => removeBadPods())
226 .catch(err => {
ad0997ad 227 if (err) logger.error('Cannot decrement scores of bad pods.', err)
6fcd19ba 228 })
9e167724
C
229 }
230}
231
232// ---------------------------------------------------------------------------
233
234// Remove pods with a score of 0 (too many requests where they were unreachable)
235function removeBadPods () {
6fcd19ba
C
236 return listBadPods()
237 .then(pods => {
238 const podsRemovePromises = pods.map(pod => pod.destroy())
239 return Promise.all(podsRemovePromises).then(() => pods.length)
240 })
241 .then(numberOfPodsRemoved => {
242 if (numberOfPodsRemoved) {
243 logger.info('Removed %d pods.', numberOfPodsRemoved)
244 } else {
245 logger.info('No need to remove bad pods.')
246 }
247 })
248 .catch(err => {
ad0997ad 249 logger.error('Cannot remove bad pods.', err)
6fcd19ba 250 })
9e167724 251}