Propagate old comment on new follow
[oweals/peertube.git] / server / models / server / server.ts
1 import * as Sequelize from 'sequelize'
2 import { AllowNull, Column, CreatedAt, Default, Is, IsInt, Max, Model, Table, UpdatedAt } from 'sequelize-typescript'
3 import { isHostValid } from '../../helpers/custom-validators/servers'
4 import { logger } from '../../helpers/logger'
5 import { SERVERS_SCORE } from '../../initializers'
6 import { throwIfNotValid } from '../utils'
7
8 @Table({
9   tableName: 'server',
10   indexes: [
11     {
12       fields: [ 'host' ],
13       unique: true
14     },
15     {
16       fields: [ 'score' ]
17     }
18   ]
19 })
20 export class ServerModel extends Model<ServerModel> {
21
22   @AllowNull(false)
23   @Is('Host', value => throwIfNotValid(value, isHostValid, 'valid host'))
24   @Column
25   host: string
26
27   @AllowNull(false)
28   @Default(SERVERS_SCORE.BASE)
29   @IsInt
30   @Max(SERVERS_SCORE.MAX)
31   @Column
32   score: number
33
34   @CreatedAt
35   createdAt: Date
36
37   @UpdatedAt
38   updatedAt: Date
39
40   static updateServersScoreAndRemoveBadOnes (goodServers: number[], badServers: number[]) {
41     logger.info('Updating %d good servers and %d bad servers scores.', goodServers.length, badServers.length)
42
43     if (goodServers.length !== 0) {
44       ServerModel.incrementScores(goodServers, SERVERS_SCORE.BONUS)
45         .catch(err => {
46           logger.error('Cannot increment scores of good servers.', err)
47         })
48     }
49
50     if (badServers.length !== 0) {
51       ServerModel.incrementScores(badServers, SERVERS_SCORE.PENALTY)
52         .then(() => ServerModel.removeBadServers())
53         .catch(err => {
54           if (err) logger.error('Cannot decrement scores of bad servers.', err)
55         })
56
57     }
58   }
59
60   // Remove servers with a score of 0 (too many requests where they were unreachable)
61   private static async removeBadServers () {
62     try {
63       const servers = await ServerModel.listBadServers()
64
65       const serversRemovePromises = servers.map(server => server.destroy())
66       await Promise.all(serversRemovePromises)
67
68       const numberOfServersRemoved = servers.length
69
70       if (numberOfServersRemoved) {
71         logger.info('Removed %d servers.', numberOfServersRemoved)
72       } else {
73         logger.info('No need to remove bad servers.')
74       }
75     } catch (err) {
76       logger.error('Cannot remove bad servers.', err)
77     }
78   }
79
80   private static incrementScores (ids: number[], value: number) {
81     const update = {
82       score: Sequelize.literal('score +' + value)
83     }
84
85     const options = {
86       where: {
87         id: {
88           [Sequelize.Op.in]: ids
89         }
90       },
91       // In this case score is a literal and not an integer so we do not validate it
92       validate: false
93     }
94
95     return ServerModel.update(update, options)
96   }
97
98   private static listBadServers () {
99     const query = {
100       where: {
101         score: {
102           [Sequelize.Op.lte]: 0
103         }
104       }
105     }
106
107     return ServerModel.findAll(query)
108   }
109 }