]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blobdiff - server/models/server/server.ts
Fix tests
[github/Chocobozzz/PeerTube.git] / server / models / server / server.ts
index 26fa8755095934df7eed66f8ea191e68e280cfb6..ef42de09063b0f5ed7bf9d511e7d7d01c4fe65cf 100644 (file)
-import { map } from 'lodash'
-import * as Sequelize from 'sequelize'
-
-import { FRIEND_SCORE, SERVERS_SCORE } from '../../initializers'
-import { logger, isHostValid } from '../../helpers'
-
-import { addMethodsToModel, getSort } from '../utils'
-import {
-  ServerInstance,
-  ServerAttributes,
-
-  ServerMethods
-} from './server-interface'
-
-let Server: Sequelize.Model<ServerInstance, ServerAttributes>
-let countAll: ServerMethods.CountAll
-let incrementScores: ServerMethods.IncrementScores
-let list: ServerMethods.List
-let listForApi: ServerMethods.ListForApi
-let listAllIds: ServerMethods.ListAllIds
-let listRandomServerIdsWithRequest: ServerMethods.ListRandomServerIdsWithRequest
-let listBadServers: ServerMethods.ListBadServers
-let load: ServerMethods.Load
-let loadByHost: ServerMethods.LoadByHost
-let removeAll: ServerMethods.RemoveAll
-let updateServersScore: ServerMethods.UpdateServersScore
-
-export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) {
-  Server = sequelize.define<ServerInstance, ServerAttributes>('Server',
-    {
-      host: {
-        type: DataTypes.STRING,
-        allowNull: false,
-        validate: {
-          isHost: value => {
-            const res = isHostValid(value)
-            if (res === false) throw new Error('Host not valid.')
-          }
-        }
-      },
-      score: {
-        type: DataTypes.INTEGER,
-        defaultValue: FRIEND_SCORE.BASE,
-        allowNull: false,
-        validate: {
-          isInt: true,
-          max: FRIEND_SCORE.MAX
-        }
-      }
-    },
+import { Transaction } from 'sequelize'
+import { AllowNull, Column, CreatedAt, Default, HasMany, Is, Model, Table, UpdatedAt } from 'sequelize-typescript'
+import { MServer, MServerFormattable } from '@server/types/models/server'
+import { AttributesOnly } from '@shared/typescript-utils'
+import { isHostValid } from '../../helpers/custom-validators/servers'
+import { ActorModel } from '../actor/actor'
+import { throwIfNotValid } from '../utils'
+import { ServerBlocklistModel } from './server-blocklist'
+
+@Table({
+  tableName: 'server',
+  indexes: [
     {
-      indexes: [
-        {
-          fields: [ 'host' ],
-          unique: true
-        },
-        {
-          fields: [ 'score' ]
-        }
-      ]
+      fields: [ 'host' ],
+      unique: true
     }
-  )
-
-  const classMethods = [
-    countAll,
-    incrementScores,
-    list,
-    listForApi,
-    listAllIds,
-    listRandomServerIdsWithRequest,
-    listBadServers,
-    load,
-    loadByHost,
-    updateServersScore,
-    removeAll
   ]
-  addMethodsToModel(Server, classMethods)
+})
+export class ServerModel extends Model<Partial<AttributesOnly<ServerModel>>> {
 
-  return Server
-}
+  @AllowNull(false)
+  @Is('Host', value => throwIfNotValid(value, isHostValid, 'valid host'))
+  @Column
+  host: string
 
-// ------------------------------ Statics ------------------------------
+  @AllowNull(false)
+  @Default(false)
+  @Column
+  redundancyAllowed: boolean
 
-countAll = function () {
-  return Server.count()
-}
+  @CreatedAt
+  createdAt: Date
 
-incrementScores = function (ids: number[], value: number) {
-  const update = {
-    score: Sequelize.literal('score +' + value)
-  }
+  @UpdatedAt
+  updatedAt: Date
 
-  const options = {
-    where: {
-      id: {
-        [Sequelize.Op.in]: ids
-      }
+  @HasMany(() => ActorModel, {
+    foreignKey: {
+      name: 'serverId',
+      allowNull: true
     },
-    // In this case score is a literal and not an integer so we do not validate it
-    validate: false
-  }
-
-  return Server.update(update, options)
-}
-
-list = function () {
-  return Server.findAll()
-}
-
-listForApi = function (start: number, count: number, sort: string) {
-  const query = {
-    offset: start,
-    limit: count,
-    order: [ getSort(sort) ]
-  }
-
-  return Server.findAndCountAll(query).then(({ rows, count }) => {
-    return {
-      data: rows,
-      total: count
-    }
+    onDelete: 'CASCADE',
+    hooks: true
   })
-}
-
-listAllIds = function (transaction: Sequelize.Transaction) {
-  const query = {
-    attributes: [ 'id' ],
-    transaction
-  }
+  Actors: ActorModel[]
 
-  return Server.findAll(query).then(servers => {
-    return map(servers, 'id')
+  @HasMany(() => ServerBlocklistModel, {
+    foreignKey: {
+      allowNull: false
+    },
+    onDelete: 'CASCADE'
   })
-}
-
-listRandomServerIdsWithRequest = function (limit: number, tableWithServers: string, tableWithServersJoins: string) {
-  return Server.count().then(count => {
-    // Optimization...
-    if (count === 0) return []
-
-    let start = Math.floor(Math.random() * count) - limit
-    if (start < 0) start = 0
+  BlockedBy: ServerBlocklistModel[]
 
-    const subQuery = `(SELECT DISTINCT "${tableWithServers}"."serverId" FROM "${tableWithServers}" ${tableWithServersJoins})`
+  static load (id: number, transaction?: Transaction): Promise<MServer> {
     const query = {
-      attributes: [ 'id' ],
-      order: [
-        [ 'id', 'ASC' ]
-      ],
-      offset: start,
-      limit: limit,
       where: {
-        id: {
-          [Sequelize.Op.in]: Sequelize.literal(subQuery)
-        }
-      }
+        id
+      },
+      transaction
     }
 
-    return Server.findAll(query).then(servers => {
-      return map(servers, 'id')
-    })
-  })
-}
+    return ServerModel.findOne(query)
+  }
 
-listBadServers = function () {
-  const query = {
-    where: {
-      score: {
-        [Sequelize.Op.lte]: 0
+  static loadByHost (host: string): Promise<MServer> {
+    const query = {
+      where: {
+        host
       }
     }
-  }
-
-  return Server.findAll(query)
-}
 
-load = function (id: number) {
-  return Server.findById(id)
-}
-
-loadByHost = function (host: string) {
-  const query = {
-    where: {
-      host: host
-    }
+    return ServerModel.findOne(query)
   }
 
-  return Server.findOne(query)
-}
-
-removeAll = function () {
-  return Server.destroy()
-}
-
-updateServersScore = function (goodServers: number[], badServers: number[]) {
-  logger.info('Updating %d good servers and %d bad servers scores.', goodServers.length, badServers.length)
+  static async loadOrCreateByHost (host: string) {
+    let server = await ServerModel.loadByHost(host)
+    if (!server) server = await ServerModel.create({ host })
 
-  if (goodServers.length !== 0) {
-    incrementScores(goodServers, SERVERS_SCORE.BONUS).catch(err => {
-      logger.error('Cannot increment scores of good servers.', err)
-    })
+    return server
   }
 
-  if (badServers.length !== 0) {
-    incrementScores(badServers, SERVERS_SCORE.PENALTY)
-      .then(() => removeBadServers())
-      .catch(err => {
-        if (err) logger.error('Cannot decrement scores of bad servers.', err)
-      })
+  isBlocked () {
+    return this.BlockedBy && this.BlockedBy.length !== 0
   }
-}
-
-// ---------------------------------------------------------------------------
-
-// Remove servers with a score of 0 (too many requests where they were unreachable)
-async function removeBadServers () {
-  try {
-    const servers = await listBadServers()
 
-    const serversRemovePromises = servers.map(server => server.destroy())
-    await Promise.all(serversRemovePromises)
-
-    const numberOfServersRemoved = servers.length
-
-    if (numberOfServersRemoved) {
-      logger.info('Removed %d servers.', numberOfServersRemoved)
-    } else {
-      logger.info('No need to remove bad servers.')
+  toFormattedJSON (this: MServerFormattable) {
+    return {
+      host: this.host
     }
-  } catch (err) {
-    logger.error('Cannot remove bad servers.', err)
   }
 }