1 import { each, waterfall } from 'async'
2 import { map } from 'lodash'
3 import * as Sequelize from 'sequelize'
5 import { FRIEND_SCORE, PODS_SCORE } from '../initializers'
6 import { logger, isHostValid } from '../helpers'
8 import { addMethodsToModel } from './utils'
15 } from './pod-interface'
17 let Pod: Sequelize.Model<PodInstance, PodAttributes>
18 let toFormatedJSON: PodMethods.ToFormatedJSON
19 let countAll: PodMethods.CountAll
20 let incrementScores: PodMethods.IncrementScores
21 let list: PodMethods.List
22 let listAllIds: PodMethods.ListAllIds
23 let listRandomPodIdsWithRequest: PodMethods.ListRandomPodIdsWithRequest
24 let listBadPods: PodMethods.ListBadPods
25 let load: PodMethods.Load
26 let loadByHost: PodMethods.LoadByHost
27 let removeAll: PodMethods.RemoveAll
28 let updatePodsScore: PodMethods.UpdatePodsScore
30 export default function (sequelize, DataTypes) {
31 Pod = sequelize.define('Pod',
34 type: DataTypes.STRING,
37 isHost: function (value) {
38 const res = isHostValid(value)
39 if (res === false) throw new Error('Host not valid.')
44 type: DataTypes.STRING(5000),
48 type: DataTypes.INTEGER,
49 defaultValue: FRIEND_SCORE.BASE,
57 type: DataTypes.STRING(400),
77 const classMethods = [
84 listRandomPodIdsWithRequest,
91 const instanceMethods = [ toFormatedJSON ]
92 addMethodsToModel(Pod, classMethods, instanceMethods)
97 // ------------------------------ METHODS ------------------------------
99 toFormatedJSON = function () {
105 createdAt: this.createdAt
111 // ------------------------------ Statics ------------------------------
113 function associate (models) {
114 Pod.belongsToMany(models.Request, {
116 through: models.RequestToPod,
121 countAll = function (callback) {
122 return Pod.count().asCallback(callback)
125 incrementScores = function (ids, value, callback) {
126 if (!callback) callback = function () { /* empty */ }
129 score: Sequelize.literal('score +' + value)
138 // In this case score is a literal and not an integer so we do not validate it
142 return Pod.update(update, options).asCallback(callback)
145 list = function (callback) {
146 return Pod.findAll().asCallback(callback)
149 listAllIds = function (transaction, callback) {
151 callback = transaction
159 if (transaction) query.transaction = transaction
161 return Pod.findAll(query).asCallback(function (err, pods) {
162 if (err) return callback(err)
164 return callback(null, map(pods, 'id'))
168 listRandomPodIdsWithRequest = function (limit, tableWithPods, tableWithPodsJoins, callback) {
170 callback = tableWithPodsJoins
171 tableWithPodsJoins = ''
174 Pod.count().asCallback(function (err, count) {
175 if (err) return callback(err)
178 if (count === 0) return callback(null, [])
180 let start = Math.floor(Math.random() * count) - limit
181 if (start < 0) start = 0
184 attributes: [ 'id' ],
193 Sequelize.literal(`SELECT DISTINCT "${tableWithPods}"."podId" FROM "${tableWithPods}" ${tableWithPodsJoins}`)
199 return Pod.findAll(query).asCallback(function (err, pods) {
200 if (err) return callback(err)
202 return callback(null, map(pods, 'id'))
207 listBadPods = function (callback) {
214 return Pod.findAll(query).asCallback(callback)
217 load = function (id, callback) {
218 return Pod.findById(id).asCallback(callback)
221 loadByHost = function (host, callback) {
228 return Pod.findOne(query).asCallback(callback)
231 removeAll = function (callback) {
232 return Pod.destroy().asCallback(callback)
235 updatePodsScore = function (goodPods, badPods) {
236 logger.info('Updating %d good pods and %d bad pods scores.', goodPods.length, badPods.length)
238 if (goodPods.length !== 0) {
239 incrementScores(goodPods, PODS_SCORE.BONUS, function (err) {
240 if (err) logger.error('Cannot increment scores of good pods.', { error: err })
244 if (badPods.length !== 0) {
245 incrementScores(badPods, PODS_SCORE.MALUS, function (err) {
246 if (err) logger.error('Cannot decrement scores of bad pods.', { error: err })
252 // ---------------------------------------------------------------------------
254 // Remove pods with a score of 0 (too many requests where they were unreachable)
255 function removeBadPods () {
257 function findBadPods (callback) {
258 listBadPods(function (err, pods) {
260 logger.error('Cannot find bad pods.', { error: err })
264 return callback(null, pods)
268 function removeTheseBadPods (pods, callback) {
269 each(pods, function (pod: any, callbackEach) {
270 pod.destroy().asCallback(callbackEach)
272 return callback(err, pods.length)
275 ], function (err, numberOfPodsRemoved) {
277 logger.error('Cannot remove bad pods.', { error: err })
278 } else if (numberOfPodsRemoved) {
279 logger.info('Removed %d pods.', numberOfPodsRemoved)
281 logger.info('No need to remove bad pods.')