aboutsummaryrefslogtreecommitdiffhomepage
path: root/server
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2023-05-22 15:52:59 +0200
committerChocobozzz <me@florianbigard.com>2023-05-22 15:52:59 +0200
commit3f0ceab06e5320f62f593c49daa30d963dbc36f9 (patch)
treec041455a11c55617251def4b7b35eff8d530a97a /server
parentfa3da7a623fdb25be52ebff14e066a99ea9fb0cf (diff)
downloadPeerTube-3f0ceab06e5320f62f593c49daa30d963dbc36f9.tar.gz
PeerTube-3f0ceab06e5320f62f593c49daa30d963dbc36f9.tar.zst
PeerTube-3f0ceab06e5320f62f593c49daa30d963dbc36f9.zip
More robust quota check
Avoid concurrency issues with permanent lives
Diffstat (limited to 'server')
-rw-r--r--server/lib/live/live-manager.ts4
-rw-r--r--server/lib/live/live-quota-store.ts14
-rw-r--r--server/lib/live/shared/muxing-session.ts2
-rw-r--r--server/tests/api/live/live-constraints.ts12
4 files changed, 19 insertions, 13 deletions
diff --git a/server/lib/live/live-manager.ts b/server/lib/live/live-manager.ts
index f062e2fd3..5c6e69806 100644
--- a/server/lib/live/live-manager.ts
+++ b/server/lib/live/live-manager.ts
@@ -313,7 +313,7 @@ class LiveManager {
313 const liveSession = await this.saveStartingSession(videoLive) 313 const liveSession = await this.saveStartingSession(videoLive)
314 314
315 const user = await UserModel.loadByLiveId(videoLive.id) 315 const user = await UserModel.loadByLiveId(videoLive.id)
316 LiveQuotaStore.Instance.addNewLive(user.id, videoLive.id) 316 LiveQuotaStore.Instance.addNewLive(user.id, sessionId)
317 317
318 const muxingSession = new MuxingSession({ 318 const muxingSession = new MuxingSession({
319 context: this.getContext(), 319 context: this.getContext(),
@@ -359,7 +359,7 @@ class LiveManager {
359 muxingSession.on('after-cleanup', ({ videoUUID }) => { 359 muxingSession.on('after-cleanup', ({ videoUUID }) => {
360 this.muxingSessions.delete(sessionId) 360 this.muxingSessions.delete(sessionId)
361 361
362 LiveQuotaStore.Instance.removeLive(user.id, videoLive.id) 362 LiveQuotaStore.Instance.removeLive(user.id, sessionId)
363 363
364 muxingSession.destroy() 364 muxingSession.destroy()
365 365
diff --git a/server/lib/live/live-quota-store.ts b/server/lib/live/live-quota-store.ts
index 8ceccde98..44539faaa 100644
--- a/server/lib/live/live-quota-store.ts
+++ b/server/lib/live/live-quota-store.ts
@@ -2,31 +2,31 @@ class LiveQuotaStore {
2 2
3 private static instance: LiveQuotaStore 3 private static instance: LiveQuotaStore
4 4
5 private readonly livesPerUser = new Map<number, { liveId: number, size: number }[]>() 5 private readonly livesPerUser = new Map<number, { sessionId: string, size: number }[]>()
6 6
7 private constructor () { 7 private constructor () {
8 } 8 }
9 9
10 addNewLive (userId: number, liveId: number) { 10 addNewLive (userId: number, sessionId: string) {
11 if (!this.livesPerUser.has(userId)) { 11 if (!this.livesPerUser.has(userId)) {
12 this.livesPerUser.set(userId, []) 12 this.livesPerUser.set(userId, [])
13 } 13 }
14 14
15 const currentUserLive = { liveId, size: 0 } 15 const currentUserLive = { sessionId, size: 0 }
16 const livesOfUser = this.livesPerUser.get(userId) 16 const livesOfUser = this.livesPerUser.get(userId)
17 livesOfUser.push(currentUserLive) 17 livesOfUser.push(currentUserLive)
18 } 18 }
19 19
20 removeLive (userId: number, liveId: number) { 20 removeLive (userId: number, sessionId: string) {
21 const newLivesPerUser = this.livesPerUser.get(userId) 21 const newLivesPerUser = this.livesPerUser.get(userId)
22 .filter(o => o.liveId !== liveId) 22 .filter(o => o.sessionId !== sessionId)
23 23
24 this.livesPerUser.set(userId, newLivesPerUser) 24 this.livesPerUser.set(userId, newLivesPerUser)
25 } 25 }
26 26
27 addQuotaTo (userId: number, liveId: number, size: number) { 27 addQuotaTo (userId: number, sessionId: string, size: number) {
28 const lives = this.livesPerUser.get(userId) 28 const lives = this.livesPerUser.get(userId)
29 const live = lives.find(l => l.liveId === liveId) 29 const live = lives.find(l => l.sessionId === sessionId)
30 30
31 live.size += size 31 live.size += size
32 } 32 }
diff --git a/server/lib/live/shared/muxing-session.ts b/server/lib/live/shared/muxing-session.ts
index c672ec4d6..434b308e6 100644
--- a/server/lib/live/shared/muxing-session.ts
+++ b/server/lib/live/shared/muxing-session.ts
@@ -271,7 +271,7 @@ class MuxingSession extends EventEmitter {
271 try { 271 try {
272 const segmentStat = await stat(segmentPath) 272 const segmentStat = await stat(segmentPath)
273 273
274 LiveQuotaStore.Instance.addQuotaTo(this.user.id, this.videoLive.id, segmentStat.size) 274 LiveQuotaStore.Instance.addQuotaTo(this.user.id, this.sessionId, segmentStat.size)
275 275
276 const canUpload = await this.isAbleToUploadVideoWithCache(this.user.id) 276 const canUpload = await this.isAbleToUploadVideoWithCache(this.user.id)
277 277
diff --git a/server/tests/api/live/live-constraints.ts b/server/tests/api/live/live-constraints.ts
index 168241b79..7af6af193 100644
--- a/server/tests/api/live/live-constraints.ts
+++ b/server/tests/api/live/live-constraints.ts
@@ -2,7 +2,7 @@
2 2
3import { expect } from 'chai' 3import { expect } from 'chai'
4import { wait } from '@shared/core-utils' 4import { wait } from '@shared/core-utils'
5import { LiveVideoError, VideoPrivacy } from '@shared/models' 5import { LiveVideoError, UserVideoQuota, VideoPrivacy } from '@shared/models'
6import { 6import {
7 cleanupTests, 7 cleanupTests,
8 ConfigCommand, 8 ConfigCommand,
@@ -172,12 +172,18 @@ describe('Test live constraints', function () {
172 const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ token: userAccessToken, videoId: userVideoLiveoId }) 172 const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ token: userAccessToken, videoId: userVideoLiveoId })
173 173
174 await servers[0].live.waitUntilPublished({ videoId: userVideoLiveoId }) 174 await servers[0].live.waitUntilPublished({ videoId: userVideoLiveoId })
175 // Wait previous live cleanups
176 await wait(3000)
175 177
176 const baseQuota = await servers[0].users.getMyQuotaUsed({ token: userAccessToken }) 178 const baseQuota = await servers[0].users.getMyQuotaUsed({ token: userAccessToken })
177 179
178 await wait(3000) 180 let quotaUser: UserVideoQuota
181
182 do {
183 await wait(500)
179 184
180 const quotaUser = await servers[0].users.getMyQuotaUsed({ token: userAccessToken }) 185 quotaUser = await servers[0].users.getMyQuotaUsed({ token: userAccessToken })
186 } while (quotaUser.videoQuotaUsed < baseQuota.videoQuotaUsed)
181 187
182 const { data } = await servers[0].users.list() 188 const { data } = await servers[0].users.list()
183 const quotaAdmin = data.find(u => u.username === 'user1') 189 const quotaAdmin = data.find(u => u.username === 'user1')