diff options
author | Chocobozzz <me@florianbigard.com> | 2022-10-04 10:03:17 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2022-10-04 10:03:17 +0200 |
commit | cfd57d2ca0bb058087f7dc90fcc3e8442b0288e1 (patch) | |
tree | dc899a1504ecac588e5580553e02571e0f5d7e4b /server/lib/live/live-segment-sha-store.ts | |
parent | 9c0cdc5047918b959ebd5e075ddad81eb7fb93f0 (diff) | |
download | PeerTube-cfd57d2ca0bb058087f7dc90fcc3e8442b0288e1.tar.gz PeerTube-cfd57d2ca0bb058087f7dc90fcc3e8442b0288e1.tar.zst PeerTube-cfd57d2ca0bb058087f7dc90fcc3e8442b0288e1.zip |
Live supports object storage
* Sync live files (segments, master playlist, resolution playlist,
segment sha file) into object storage
* Automatically delete them when the live ends
* Segment sha file is now a file on disk, and not stored in memory
anymore
Diffstat (limited to 'server/lib/live/live-segment-sha-store.ts')
-rw-r--r-- | server/lib/live/live-segment-sha-store.ts | 75 |
1 files changed, 43 insertions, 32 deletions
diff --git a/server/lib/live/live-segment-sha-store.ts b/server/lib/live/live-segment-sha-store.ts index 4af6f3ebf..faf03dccf 100644 --- a/server/lib/live/live-segment-sha-store.ts +++ b/server/lib/live/live-segment-sha-store.ts | |||
@@ -1,62 +1,73 @@ | |||
1 | import { writeJson } from 'fs-extra' | ||
1 | import { basename } from 'path' | 2 | import { basename } from 'path' |
3 | import { mapToJSON } from '@server/helpers/core-utils' | ||
2 | import { logger, loggerTagsFactory } from '@server/helpers/logger' | 4 | import { logger, loggerTagsFactory } from '@server/helpers/logger' |
5 | import { MStreamingPlaylistVideo } from '@server/types/models' | ||
3 | import { buildSha256Segment } from '../hls' | 6 | import { buildSha256Segment } from '../hls' |
7 | import { storeHLSFileFromPath } from '../object-storage' | ||
4 | 8 | ||
5 | const lTags = loggerTagsFactory('live') | 9 | const lTags = loggerTagsFactory('live') |
6 | 10 | ||
7 | class LiveSegmentShaStore { | 11 | class LiveSegmentShaStore { |
8 | 12 | ||
9 | private static instance: LiveSegmentShaStore | 13 | private readonly segmentsSha256 = new Map<string, string>() |
10 | 14 | ||
11 | private readonly segmentsSha256 = new Map<string, Map<string, string>>() | 15 | private readonly videoUUID: string |
12 | 16 | private readonly sha256Path: string | |
13 | private constructor () { | 17 | private readonly streamingPlaylist: MStreamingPlaylistVideo |
18 | private readonly sendToObjectStorage: boolean | ||
19 | |||
20 | constructor (options: { | ||
21 | videoUUID: string | ||
22 | sha256Path: string | ||
23 | streamingPlaylist: MStreamingPlaylistVideo | ||
24 | sendToObjectStorage: boolean | ||
25 | }) { | ||
26 | this.videoUUID = options.videoUUID | ||
27 | this.sha256Path = options.sha256Path | ||
28 | this.streamingPlaylist = options.streamingPlaylist | ||
29 | this.sendToObjectStorage = options.sendToObjectStorage | ||
14 | } | 30 | } |
15 | 31 | ||
16 | getSegmentsSha256 (videoUUID: string) { | 32 | async addSegmentSha (segmentPath: string) { |
17 | return this.segmentsSha256.get(videoUUID) | 33 | logger.debug('Adding live sha segment %s.', segmentPath, lTags(this.videoUUID)) |
18 | } | ||
19 | |||
20 | async addSegmentSha (videoUUID: string, segmentPath: string) { | ||
21 | const segmentName = basename(segmentPath) | ||
22 | logger.debug('Adding live sha segment %s.', segmentPath, lTags(videoUUID)) | ||
23 | 34 | ||
24 | const shaResult = await buildSha256Segment(segmentPath) | 35 | const shaResult = await buildSha256Segment(segmentPath) |
25 | 36 | ||
26 | if (!this.segmentsSha256.has(videoUUID)) { | 37 | const segmentName = basename(segmentPath) |
27 | this.segmentsSha256.set(videoUUID, new Map()) | 38 | this.segmentsSha256.set(segmentName, shaResult) |
28 | } | ||
29 | 39 | ||
30 | const filesMap = this.segmentsSha256.get(videoUUID) | 40 | await this.writeToDisk() |
31 | filesMap.set(segmentName, shaResult) | ||
32 | } | 41 | } |
33 | 42 | ||
34 | removeSegmentSha (videoUUID: string, segmentPath: string) { | 43 | async removeSegmentSha (segmentPath: string) { |
35 | const segmentName = basename(segmentPath) | 44 | const segmentName = basename(segmentPath) |
36 | 45 | ||
37 | logger.debug('Removing live sha segment %s.', segmentPath, lTags(videoUUID)) | 46 | logger.debug('Removing live sha segment %s.', segmentPath, lTags(this.videoUUID)) |
38 | 47 | ||
39 | const filesMap = this.segmentsSha256.get(videoUUID) | 48 | if (!this.segmentsSha256.has(segmentName)) { |
40 | if (!filesMap) { | 49 | logger.warn('Unknown segment in files map for video %s and segment %s.', this.videoUUID, segmentPath, lTags(this.videoUUID)) |
41 | logger.warn('Unknown files map to remove sha for %s.', videoUUID, lTags(videoUUID)) | ||
42 | return | 50 | return |
43 | } | 51 | } |
44 | 52 | ||
45 | if (!filesMap.has(segmentName)) { | 53 | this.segmentsSha256.delete(segmentName) |
46 | logger.warn('Unknown segment in files map for video %s and segment %s.', videoUUID, segmentPath, lTags(videoUUID)) | ||
47 | return | ||
48 | } | ||
49 | 54 | ||
50 | filesMap.delete(segmentName) | 55 | await this.writeToDisk() |
51 | } | 56 | } |
52 | 57 | ||
53 | cleanupShaSegments (videoUUID: string) { | 58 | private async writeToDisk () { |
54 | this.segmentsSha256.delete(videoUUID) | 59 | await writeJson(this.sha256Path, mapToJSON(this.segmentsSha256)) |
55 | } | ||
56 | 60 | ||
57 | static get Instance () { | 61 | if (this.sendToObjectStorage) { |
58 | return this.instance || (this.instance = new this()) | 62 | const url = await storeHLSFileFromPath(this.streamingPlaylist, this.sha256Path) |
63 | |||
64 | if (this.streamingPlaylist.segmentsSha256Url !== url) { | ||
65 | this.streamingPlaylist.segmentsSha256Url = url | ||
66 | await this.streamingPlaylist.save() | ||
67 | } | ||
68 | } | ||
59 | } | 69 | } |
70 | |||
60 | } | 71 | } |
61 | 72 | ||
62 | export { | 73 | export { |