Remove max duration/filesize constraints
[oweals/peertube.git] / server / models / server / server.ts
1 import * as Sequelize from 'sequelize'
2 import { isHostValid, logger } from '../../helpers'
3 import { SERVERS_SCORE } from '../../initializers'
4 import { addMethodsToModel } from '../utils'
5 import { ServerAttributes, ServerInstance, ServerMethods } from './server-interface'
6
7 let Server: Sequelize.Model<ServerInstance, ServerAttributes>
8 let updateServersScoreAndRemoveBadOnes: ServerMethods.UpdateServersScoreAndRemoveBadOnes
9
10 export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) {
11   Server = sequelize.define<ServerInstance, ServerAttributes>('Server',
12     {
13       host: {
14         type: DataTypes.STRING,
15         allowNull: false,
16         validate: {
17           isHost: value => {
18             const res = isHostValid(value)
19             if (res === false) throw new Error('Host not valid.')
20           }
21         }
22       },
23       score: {
24         type: DataTypes.INTEGER,
25         defaultValue: SERVERS_SCORE.BASE,
26         allowNull: false,
27         validate: {
28           isInt: true,
29           max: SERVERS_SCORE.MAX
30         }
31       }
32     },
33     {
34       indexes: [
35         {
36           fields: [ 'host' ],
37           unique: true
38         },
39         {
40           fields: [ 'score' ]
41         }
42       ]
43     }
44   )
45
46   const classMethods = [
47     updateServersScoreAndRemoveBadOnes
48   ]
49   addMethodsToModel(Server, classMethods)
50
51   return Server
52 }
53
54 // ------------------------------ Statics ------------------------------
55
56 updateServersScoreAndRemoveBadOnes = function (goodServers: number[], badServers: number[]) {
57   logger.info('Updating %d good servers and %d bad servers scores.', goodServers.length, badServers.length)
58
59   if (goodServers.length !== 0) {
60     incrementScores(goodServers, SERVERS_SCORE.BONUS).catch(err => {
61       logger.error('Cannot increment scores of good servers.', err)
62     })
63   }
64
65   if (badServers.length !== 0) {
66     incrementScores(badServers, SERVERS_SCORE.PENALTY)
67       .then(() => removeBadServers())
68       .catch(err => {
69         if (err) logger.error('Cannot decrement scores of bad servers.', err)
70       })
71   }
72 }
73
74 // ---------------------------------------------------------------------------
75
76 // Remove servers with a score of 0 (too many requests where they were unreachable)
77 async function removeBadServers () {
78   try {
79     const servers = await listBadServers()
80
81     const serversRemovePromises = servers.map(server => server.destroy())
82     await Promise.all(serversRemovePromises)
83
84     const numberOfServersRemoved = servers.length
85
86     if (numberOfServersRemoved) {
87       logger.info('Removed %d servers.', numberOfServersRemoved)
88     } else {
89       logger.info('No need to remove bad servers.')
90     }
91   } catch (err) {
92     logger.error('Cannot remove bad servers.', err)
93   }
94 }
95
96 function incrementScores (ids: number[], value: number) {
97   const update = {
98     score: Sequelize.literal('score +' + value)
99   }
100
101   const options = {
102     where: {
103       id: {
104         [Sequelize.Op.in]: ids
105       }
106     },
107     // In this case score is a literal and not an integer so we do not validate it
108     validate: false
109   }
110
111   return Server.update(update, options)
112 }
113
114 function listBadServers () {
115   const query = {
116     where: {
117       score: {
118         [Sequelize.Op.lte]: 0
119       }
120     }
121   }
122
123   return Server.findAll(query)
124 }