diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/controllers/api/server/follows.ts | 5 | ||||
-rw-r--r-- | server/controllers/api/server/redundancy.ts | 6 | ||||
-rw-r--r-- | server/lib/redundancy.ts | 9 | ||||
-rw-r--r-- | server/models/redundancy/video-redundancy.ts | 41 | ||||
-rw-r--r-- | server/tests/api/server/redundancy.ts | 69 |
5 files changed, 114 insertions, 16 deletions
diff --git a/server/controllers/api/server/follows.ts b/server/controllers/api/server/follows.ts index a4eae6b45..d62400e42 100644 --- a/server/controllers/api/server/follows.ts +++ b/server/controllers/api/server/follows.ts | |||
@@ -17,6 +17,7 @@ import { | |||
17 | import { followersSortValidator, followingSortValidator, followValidator } from '../../../middlewares/validators' | 17 | import { followersSortValidator, followingSortValidator, followValidator } from '../../../middlewares/validators' |
18 | import { ActorFollowModel } from '../../../models/activitypub/actor-follow' | 18 | import { ActorFollowModel } from '../../../models/activitypub/actor-follow' |
19 | import { JobQueue } from '../../../lib/job-queue' | 19 | import { JobQueue } from '../../../lib/job-queue' |
20 | import { removeRedundancyOf } from '../../../lib/redundancy' | ||
20 | 21 | ||
21 | const serverFollowsRouter = express.Router() | 22 | const serverFollowsRouter = express.Router() |
22 | serverFollowsRouter.get('/following', | 23 | serverFollowsRouter.get('/following', |
@@ -101,6 +102,10 @@ async function removeFollow (req: express.Request, res: express.Response, next: | |||
101 | server.redundancyAllowed = false | 102 | server.redundancyAllowed = false |
102 | await server.save({ transaction: t }) | 103 | await server.save({ transaction: t }) |
103 | 104 | ||
105 | // Async, could be long | ||
106 | removeRedundancyOf(server.id) | ||
107 | .catch(err => logger.error('Cannot remove redundancy of %s.', server.host, err)) | ||
108 | |||
104 | await follow.destroy({ transaction: t }) | 109 | await follow.destroy({ transaction: t }) |
105 | }) | 110 | }) |
106 | 111 | ||
diff --git a/server/controllers/api/server/redundancy.ts b/server/controllers/api/server/redundancy.ts index 4216b9e35..4140c4991 100644 --- a/server/controllers/api/server/redundancy.ts +++ b/server/controllers/api/server/redundancy.ts | |||
@@ -3,6 +3,8 @@ import { UserRight } from '../../../../shared/models/users' | |||
3 | import { asyncMiddleware, authenticate, ensureUserHasRight } from '../../../middlewares' | 3 | import { asyncMiddleware, authenticate, ensureUserHasRight } from '../../../middlewares' |
4 | import { updateServerRedundancyValidator } from '../../../middlewares/validators/redundancy' | 4 | import { updateServerRedundancyValidator } from '../../../middlewares/validators/redundancy' |
5 | import { ServerModel } from '../../../models/server/server' | 5 | import { ServerModel } from '../../../models/server/server' |
6 | import { removeRedundancyOf } from '../../../lib/redundancy' | ||
7 | import { logger } from '../../../helpers/logger' | ||
6 | 8 | ||
7 | const serverRedundancyRouter = express.Router() | 9 | const serverRedundancyRouter = express.Router() |
8 | 10 | ||
@@ -28,5 +30,9 @@ async function updateRedundancy (req: express.Request, res: express.Response, ne | |||
28 | 30 | ||
29 | await server.save() | 31 | await server.save() |
30 | 32 | ||
33 | // Async, could be long | ||
34 | removeRedundancyOf(server.id) | ||
35 | .catch(err => logger.error('Cannot remove redundancy of %s.', server.host, err)) | ||
36 | |||
31 | return res.sendStatus(204) | 37 | return res.sendStatus(204) |
32 | } | 38 | } |
diff --git a/server/lib/redundancy.ts b/server/lib/redundancy.ts index 16b122658..04d3ded8f 100644 --- a/server/lib/redundancy.ts +++ b/server/lib/redundancy.ts | |||
@@ -12,8 +12,17 @@ async function removeVideoRedundancy (videoRedundancy: VideoRedundancyModel, t?: | |||
12 | await videoRedundancy.destroy({ transaction: t }) | 12 | await videoRedundancy.destroy({ transaction: t }) |
13 | } | 13 | } |
14 | 14 | ||
15 | async function removeRedundancyOf (serverId: number) { | ||
16 | const videosRedundancy = await VideoRedundancyModel.listLocalOfServer(serverId) | ||
17 | |||
18 | for (const redundancy of videosRedundancy) { | ||
19 | await removeVideoRedundancy(redundancy) | ||
20 | } | ||
21 | } | ||
22 | |||
15 | // --------------------------------------------------------------------------- | 23 | // --------------------------------------------------------------------------- |
16 | 24 | ||
17 | export { | 25 | export { |
26 | removeRedundancyOf, | ||
18 | removeVideoRedundancy | 27 | removeVideoRedundancy |
19 | } | 28 | } |
diff --git a/server/models/redundancy/video-redundancy.ts b/server/models/redundancy/video-redundancy.ts index 3c87ec2c1..e67164802 100644 --- a/server/models/redundancy/video-redundancy.ts +++ b/server/models/redundancy/video-redundancy.ts | |||
@@ -286,6 +286,47 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
286 | return VideoRedundancyModel.scope([ ScopeNames.WITH_VIDEO ]).findAll(query) | 286 | return VideoRedundancyModel.scope([ ScopeNames.WITH_VIDEO ]).findAll(query) |
287 | } | 287 | } |
288 | 288 | ||
289 | static async listLocalOfServer (serverId: number) { | ||
290 | const actor = await getServerActor() | ||
291 | |||
292 | const query = { | ||
293 | where: { | ||
294 | actorId: actor.id | ||
295 | }, | ||
296 | include: [ | ||
297 | { | ||
298 | model: VideoFileModel, | ||
299 | required: true, | ||
300 | include: [ | ||
301 | { | ||
302 | model: VideoModel, | ||
303 | required: true, | ||
304 | include: [ | ||
305 | { | ||
306 | attributes: [], | ||
307 | model: VideoChannelModel.unscoped(), | ||
308 | required: true, | ||
309 | include: [ | ||
310 | { | ||
311 | attributes: [], | ||
312 | model: ActorModel.unscoped(), | ||
313 | required: true, | ||
314 | where: { | ||
315 | serverId | ||
316 | } | ||
317 | } | ||
318 | ] | ||
319 | } | ||
320 | ] | ||
321 | } | ||
322 | ] | ||
323 | } | ||
324 | ] | ||
325 | } | ||
326 | |||
327 | return VideoRedundancyModel.findAll(query) | ||
328 | } | ||
329 | |||
289 | static async getStats (strategy: VideoRedundancyStrategy) { | 330 | static async getStats (strategy: VideoRedundancyStrategy) { |
290 | const actor = await getServerActor() | 331 | const actor = await getServerActor() |
291 | 332 | ||
diff --git a/server/tests/api/server/redundancy.ts b/server/tests/api/server/redundancy.ts index 9b3b1b4ad..e1709891d 100644 --- a/server/tests/api/server/redundancy.ts +++ b/server/tests/api/server/redundancy.ts | |||
@@ -12,7 +12,7 @@ import { | |||
12 | killallServers, makeGetRequest, | 12 | killallServers, makeGetRequest, |
13 | root, | 13 | root, |
14 | ServerInfo, | 14 | ServerInfo, |
15 | setAccessTokensToServers, | 15 | setAccessTokensToServers, unfollow, |
16 | uploadVideo, | 16 | uploadVideo, |
17 | viewVideo, | 17 | viewVideo, |
18 | wait | 18 | wait |
@@ -39,6 +39,8 @@ function checkMagnetWebseeds (file: { magnetUri: string, resolution: { id: numbe | |||
39 | const found = parsed.urlList.find(url => url === `${ws}-${file.resolution.id}.mp4`) | 39 | const found = parsed.urlList.find(url => url === `${ws}-${file.resolution.id}.mp4`) |
40 | expect(found, `Webseed ${ws} not found in ${file.magnetUri} on server ${server.url}`).to.not.be.undefined | 40 | expect(found, `Webseed ${ws} not found in ${file.magnetUri} on server ${server.url}`).to.not.be.undefined |
41 | } | 41 | } |
42 | |||
43 | expect(parsed.urlList).to.have.lengthOf(baseWebseeds.length) | ||
42 | } | 44 | } |
43 | 45 | ||
44 | async function runServers (strategy: VideoRedundancyStrategy, additionalParams: any = {}) { | 46 | async function runServers (strategy: VideoRedundancyStrategy, additionalParams: any = {}) { |
@@ -136,23 +138,21 @@ async function check2Webseeds (strategy: VideoRedundancyStrategy, videoUUID?: st | |||
136 | ] | 138 | ] |
137 | 139 | ||
138 | for (const server of servers) { | 140 | for (const server of servers) { |
139 | { | 141 | const res = await getVideo(server.url, videoUUID) |
140 | const res = await getVideo(server.url, videoUUID) | ||
141 | 142 | ||
142 | const video: VideoDetails = res.body | 143 | const video: VideoDetails = res.body |
143 | 144 | ||
144 | for (const file of video.files) { | 145 | for (const file of video.files) { |
145 | checkMagnetWebseeds(file, webseeds, server) | 146 | checkMagnetWebseeds(file, webseeds, server) |
146 | 147 | ||
147 | // Only servers 1 and 2 have the video | 148 | // Only servers 1 and 2 have the video |
148 | if (server.serverNumber !== 3) { | 149 | if (server.serverNumber !== 3) { |
149 | await makeGetRequest({ | 150 | await makeGetRequest({ |
150 | url: server.url, | 151 | url: server.url, |
151 | statusCodeExpected: 200, | 152 | statusCodeExpected: 200, |
152 | path: '/static/webseed/' + `${videoUUID}-${file.resolution.id}.mp4`, | 153 | path: '/static/webseed/' + `${videoUUID}-${file.resolution.id}.mp4`, |
153 | contentType: null | 154 | contentType: null |
154 | }) | 155 | }) |
155 | } | ||
156 | } | 156 | } |
157 | } | 157 | } |
158 | } | 158 | } |
@@ -182,6 +182,21 @@ async function enableRedundancyOnServer1 () { | |||
182 | expect(server2.following.hostRedundancyAllowed).to.be.true | 182 | expect(server2.following.hostRedundancyAllowed).to.be.true |
183 | } | 183 | } |
184 | 184 | ||
185 | async function disableRedundancyOnServer1 () { | ||
186 | await updateRedundancy(servers[ 0 ].url, servers[ 0 ].accessToken, servers[ 1 ].host, false) | ||
187 | |||
188 | const res = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 5, '-createdAt') | ||
189 | const follows: ActorFollow[] = res.body.data | ||
190 | const server2 = follows.find(f => f.following.host === 'localhost:9002') | ||
191 | const server3 = follows.find(f => f.following.host === 'localhost:9003') | ||
192 | |||
193 | expect(server3).to.not.be.undefined | ||
194 | expect(server3.following.hostRedundancyAllowed).to.be.false | ||
195 | |||
196 | expect(server2).to.not.be.undefined | ||
197 | expect(server2.following.hostRedundancyAllowed).to.be.false | ||
198 | } | ||
199 | |||
185 | async function cleanServers () { | 200 | async function cleanServers () { |
186 | killallServers(servers) | 201 | killallServers(servers) |
187 | } | 202 | } |
@@ -217,6 +232,17 @@ describe('Test videos redundancy', function () { | |||
217 | await checkStatsWith2Webseed(strategy) | 232 | await checkStatsWith2Webseed(strategy) |
218 | }) | 233 | }) |
219 | 234 | ||
235 | it('Should undo redundancy on server 1 and remove duplicated videos', async function () { | ||
236 | this.timeout(40000) | ||
237 | |||
238 | await disableRedundancyOnServer1() | ||
239 | |||
240 | await waitJobs(servers) | ||
241 | await wait(5000) | ||
242 | |||
243 | await check1WebSeed(strategy) | ||
244 | }) | ||
245 | |||
220 | after(function () { | 246 | after(function () { |
221 | return cleanServers() | 247 | return cleanServers() |
222 | }) | 248 | }) |
@@ -251,6 +277,17 @@ describe('Test videos redundancy', function () { | |||
251 | await checkStatsWith2Webseed(strategy) | 277 | await checkStatsWith2Webseed(strategy) |
252 | }) | 278 | }) |
253 | 279 | ||
280 | it('Should unfollow on server 1 and remove duplicated videos', async function () { | ||
281 | this.timeout(40000) | ||
282 | |||
283 | await unfollow(servers[0].url, servers[0].accessToken, servers[1]) | ||
284 | |||
285 | await waitJobs(servers) | ||
286 | await wait(5000) | ||
287 | |||
288 | await check1WebSeed(strategy) | ||
289 | }) | ||
290 | |||
254 | after(function () { | 291 | after(function () { |
255 | return cleanServers() | 292 | return cleanServers() |
256 | }) | 293 | }) |