diff options
Diffstat (limited to 'server/models/pod')
-rw-r--r-- | server/models/pod/index.ts | 1 | ||||
-rw-r--r-- | server/models/pod/pod-interface.ts | 61 | ||||
-rw-r--r-- | server/models/pod/pod.ts | 248 |
3 files changed, 0 insertions, 310 deletions
diff --git a/server/models/pod/index.ts b/server/models/pod/index.ts deleted file mode 100644 index d2bf50d4d..000000000 --- a/server/models/pod/index.ts +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | export * from './pod-interface' | ||
diff --git a/server/models/pod/pod-interface.ts b/server/models/pod/pod-interface.ts deleted file mode 100644 index 6c5aab3fa..000000000 --- a/server/models/pod/pod-interface.ts +++ /dev/null | |||
@@ -1,61 +0,0 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | import * as Promise from 'bluebird' | ||
3 | |||
4 | // Don't use barrel, import just what we need | ||
5 | import { Pod as FormattedPod } from '../../../shared/models/pods/pod.model' | ||
6 | import { ResultList } from '../../../shared/models/result-list.model' | ||
7 | |||
8 | export namespace PodMethods { | ||
9 | export type ToFormattedJSON = (this: PodInstance) => FormattedPod | ||
10 | |||
11 | export type CountAll = () => Promise<number> | ||
12 | |||
13 | export type IncrementScores = (ids: number[], value: number) => Promise<[ number, PodInstance[] ]> | ||
14 | |||
15 | export type List = () => Promise<PodInstance[]> | ||
16 | |||
17 | export type ListForApi = (start: number, count: number, sort: string) => Promise< ResultList<PodInstance> > | ||
18 | |||
19 | export type ListAllIds = (transaction: Sequelize.Transaction) => Promise<number[]> | ||
20 | |||
21 | export type ListRandomPodIdsWithRequest = (limit: number, tableWithPods: string, tableWithPodsJoins: string) => Promise<number[]> | ||
22 | |||
23 | export type ListBadPods = () => Promise<PodInstance[]> | ||
24 | |||
25 | export type Load = (id: number) => Promise<PodInstance> | ||
26 | |||
27 | export type LoadByHost = (host: string) => Promise<PodInstance> | ||
28 | |||
29 | export type RemoveAll = () => Promise<number> | ||
30 | |||
31 | export type UpdatePodsScore = (goodPods: number[], badPods: number[]) => void | ||
32 | } | ||
33 | |||
34 | export interface PodClass { | ||
35 | countAll: PodMethods.CountAll | ||
36 | incrementScores: PodMethods.IncrementScores | ||
37 | list: PodMethods.List | ||
38 | listForApi: PodMethods.ListForApi | ||
39 | listAllIds: PodMethods.ListAllIds | ||
40 | listRandomPodIdsWithRequest: PodMethods.ListRandomPodIdsWithRequest | ||
41 | listBadPods: PodMethods.ListBadPods | ||
42 | load: PodMethods.Load | ||
43 | loadByHost: PodMethods.LoadByHost | ||
44 | removeAll: PodMethods.RemoveAll | ||
45 | updatePodsScore: PodMethods.UpdatePodsScore | ||
46 | } | ||
47 | |||
48 | export interface PodAttributes { | ||
49 | id?: number | ||
50 | host?: string | ||
51 | score?: number | Sequelize.literal // Sequelize literal for 'score +' + value | ||
52 | } | ||
53 | |||
54 | export interface PodInstance extends PodClass, PodAttributes, Sequelize.Instance<PodAttributes> { | ||
55 | createdAt: Date | ||
56 | updatedAt: Date | ||
57 | |||
58 | toFormattedJSON: PodMethods.ToFormattedJSON, | ||
59 | } | ||
60 | |||
61 | export interface PodModel extends PodClass, Sequelize.Model<PodInstance, PodAttributes> {} | ||
diff --git a/server/models/pod/pod.ts b/server/models/pod/pod.ts deleted file mode 100644 index 6d270ad7f..000000000 --- a/server/models/pod/pod.ts +++ /dev/null | |||
@@ -1,248 +0,0 @@ | |||
1 | import { map } from 'lodash' | ||
2 | import * as Sequelize from 'sequelize' | ||
3 | |||
4 | import { FRIEND_SCORE, PODS_SCORE } from '../../initializers' | ||
5 | import { logger, isHostValid } from '../../helpers' | ||
6 | |||
7 | import { addMethodsToModel, getSort } from '../utils' | ||
8 | import { | ||
9 | PodInstance, | ||
10 | PodAttributes, | ||
11 | |||
12 | PodMethods | ||
13 | } from './pod-interface' | ||
14 | |||
15 | let Pod: Sequelize.Model<PodInstance, PodAttributes> | ||
16 | let toFormattedJSON: PodMethods.ToFormattedJSON | ||
17 | let countAll: PodMethods.CountAll | ||
18 | let incrementScores: PodMethods.IncrementScores | ||
19 | let list: PodMethods.List | ||
20 | let listForApi: PodMethods.ListForApi | ||
21 | let listAllIds: PodMethods.ListAllIds | ||
22 | let listRandomPodIdsWithRequest: PodMethods.ListRandomPodIdsWithRequest | ||
23 | let listBadPods: PodMethods.ListBadPods | ||
24 | let load: PodMethods.Load | ||
25 | let loadByHost: PodMethods.LoadByHost | ||
26 | let removeAll: PodMethods.RemoveAll | ||
27 | let updatePodsScore: PodMethods.UpdatePodsScore | ||
28 | |||
29 | export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) { | ||
30 | Pod = sequelize.define<PodInstance, PodAttributes>('Pod', | ||
31 | { | ||
32 | host: { | ||
33 | type: DataTypes.STRING, | ||
34 | allowNull: false, | ||
35 | validate: { | ||
36 | isHost: value => { | ||
37 | const res = isHostValid(value) | ||
38 | if (res === false) throw new Error('Host not valid.') | ||
39 | } | ||
40 | } | ||
41 | }, | ||
42 | score: { | ||
43 | type: DataTypes.INTEGER, | ||
44 | defaultValue: FRIEND_SCORE.BASE, | ||
45 | allowNull: false, | ||
46 | validate: { | ||
47 | isInt: true, | ||
48 | max: FRIEND_SCORE.MAX | ||
49 | } | ||
50 | } | ||
51 | }, | ||
52 | { | ||
53 | indexes: [ | ||
54 | { | ||
55 | fields: [ 'host' ], | ||
56 | unique: true | ||
57 | }, | ||
58 | { | ||
59 | fields: [ 'score' ] | ||
60 | } | ||
61 | ] | ||
62 | } | ||
63 | ) | ||
64 | |||
65 | const classMethods = [ | ||
66 | countAll, | ||
67 | incrementScores, | ||
68 | list, | ||
69 | listForApi, | ||
70 | listAllIds, | ||
71 | listRandomPodIdsWithRequest, | ||
72 | listBadPods, | ||
73 | load, | ||
74 | loadByHost, | ||
75 | updatePodsScore, | ||
76 | removeAll | ||
77 | ] | ||
78 | const instanceMethods = [ toFormattedJSON ] | ||
79 | addMethodsToModel(Pod, classMethods, instanceMethods) | ||
80 | |||
81 | return Pod | ||
82 | } | ||
83 | |||
84 | // ------------------------------ METHODS ------------------------------ | ||
85 | |||
86 | toFormattedJSON = function (this: PodInstance) { | ||
87 | const json = { | ||
88 | id: this.id, | ||
89 | host: this.host, | ||
90 | score: this.score as number, | ||
91 | createdAt: this.createdAt | ||
92 | } | ||
93 | |||
94 | return json | ||
95 | } | ||
96 | |||
97 | // ------------------------------ Statics ------------------------------ | ||
98 | |||
99 | countAll = function () { | ||
100 | return Pod.count() | ||
101 | } | ||
102 | |||
103 | incrementScores = function (ids: number[], value: number) { | ||
104 | const update = { | ||
105 | score: Sequelize.literal('score +' + value) | ||
106 | } | ||
107 | |||
108 | const options = { | ||
109 | where: { | ||
110 | id: { | ||
111 | [Sequelize.Op.in]: ids | ||
112 | } | ||
113 | }, | ||
114 | // In this case score is a literal and not an integer so we do not validate it | ||
115 | validate: false | ||
116 | } | ||
117 | |||
118 | return Pod.update(update, options) | ||
119 | } | ||
120 | |||
121 | list = function () { | ||
122 | return Pod.findAll() | ||
123 | } | ||
124 | |||
125 | listForApi = function (start: number, count: number, sort: string) { | ||
126 | const query = { | ||
127 | offset: start, | ||
128 | limit: count, | ||
129 | order: [ getSort(sort) ] | ||
130 | } | ||
131 | |||
132 | return Pod.findAndCountAll(query).then(({ rows, count }) => { | ||
133 | return { | ||
134 | data: rows, | ||
135 | total: count | ||
136 | } | ||
137 | }) | ||
138 | } | ||
139 | |||
140 | listAllIds = function (transaction: Sequelize.Transaction) { | ||
141 | const query = { | ||
142 | attributes: [ 'id' ], | ||
143 | transaction | ||
144 | } | ||
145 | |||
146 | return Pod.findAll(query).then(pods => { | ||
147 | return map(pods, 'id') | ||
148 | }) | ||
149 | } | ||
150 | |||
151 | listRandomPodIdsWithRequest = function (limit: number, tableWithPods: string, tableWithPodsJoins: string) { | ||
152 | return Pod.count().then(count => { | ||
153 | // Optimization... | ||
154 | if (count === 0) return [] | ||
155 | |||
156 | let start = Math.floor(Math.random() * count) - limit | ||
157 | if (start < 0) start = 0 | ||
158 | |||
159 | const subQuery = `(SELECT DISTINCT "${tableWithPods}"."podId" FROM "${tableWithPods}" ${tableWithPodsJoins})` | ||
160 | const query = { | ||
161 | attributes: [ 'id' ], | ||
162 | order: [ | ||
163 | [ 'id', 'ASC' ] | ||
164 | ], | ||
165 | offset: start, | ||
166 | limit: limit, | ||
167 | where: { | ||
168 | id: { | ||
169 | [Sequelize.Op.in]: Sequelize.literal(subQuery) | ||
170 | } | ||
171 | } | ||
172 | } | ||
173 | |||
174 | return Pod.findAll(query).then(pods => { | ||
175 | return map(pods, 'id') | ||
176 | }) | ||
177 | }) | ||
178 | } | ||
179 | |||
180 | listBadPods = function () { | ||
181 | const query = { | ||
182 | where: { | ||
183 | score: { | ||
184 | [Sequelize.Op.lte]: 0 | ||
185 | } | ||
186 | } | ||
187 | } | ||
188 | |||
189 | return Pod.findAll(query) | ||
190 | } | ||
191 | |||
192 | load = function (id: number) { | ||
193 | return Pod.findById(id) | ||
194 | } | ||
195 | |||
196 | loadByHost = function (host: string) { | ||
197 | const query = { | ||
198 | where: { | ||
199 | host: host | ||
200 | } | ||
201 | } | ||
202 | |||
203 | return Pod.findOne(query) | ||
204 | } | ||
205 | |||
206 | removeAll = function () { | ||
207 | return Pod.destroy() | ||
208 | } | ||
209 | |||
210 | updatePodsScore = function (goodPods: number[], badPods: number[]) { | ||
211 | logger.info('Updating %d good pods and %d bad pods scores.', goodPods.length, badPods.length) | ||
212 | |||
213 | if (goodPods.length !== 0) { | ||
214 | incrementScores(goodPods, PODS_SCORE.BONUS).catch(err => { | ||
215 | logger.error('Cannot increment scores of good pods.', err) | ||
216 | }) | ||
217 | } | ||
218 | |||
219 | if (badPods.length !== 0) { | ||
220 | incrementScores(badPods, PODS_SCORE.PENALTY) | ||
221 | .then(() => removeBadPods()) | ||
222 | .catch(err => { | ||
223 | if (err) logger.error('Cannot decrement scores of bad pods.', err) | ||
224 | }) | ||
225 | } | ||
226 | } | ||
227 | |||
228 | // --------------------------------------------------------------------------- | ||
229 | |||
230 | // Remove pods with a score of 0 (too many requests where they were unreachable) | ||
231 | async function removeBadPods () { | ||
232 | try { | ||
233 | const pods = await listBadPods() | ||
234 | |||
235 | const podsRemovePromises = pods.map(pod => pod.destroy()) | ||
236 | await Promise.all(podsRemovePromises) | ||
237 | |||
238 | const numberOfPodsRemoved = pods.length | ||
239 | |||
240 | if (numberOfPodsRemoved) { | ||
241 | logger.info('Removed %d pods.', numberOfPodsRemoved) | ||
242 | } else { | ||
243 | logger.info('No need to remove bad pods.') | ||
244 | } | ||
245 | } catch (err) { | ||
246 | logger.error('Cannot remove bad pods.', err) | ||
247 | } | ||
248 | } | ||