]>
Commit | Line | Data |
---|---|---|
cfd57d2c | 1 | import { writeJson } from 'fs-extra' |
8ebf2a5d | 2 | import { basename } from 'path' |
cfd57d2c | 3 | import { mapToJSON } from '@server/helpers/core-utils' |
8ebf2a5d | 4 | import { logger, loggerTagsFactory } from '@server/helpers/logger' |
cfd57d2c | 5 | import { MStreamingPlaylistVideo } from '@server/types/models' |
8ebf2a5d | 6 | import { buildSha256Segment } from '../hls' |
cfd57d2c | 7 | import { storeHLSFileFromPath } from '../object-storage' |
9ab330b9 | 8 | import PQueue from 'p-queue' |
8ebf2a5d C |
9 | |
10 | const lTags = loggerTagsFactory('live') | |
11 | ||
12 | class LiveSegmentShaStore { | |
13 | ||
cfd57d2c C |
14 | private readonly segmentsSha256 = new Map<string, string>() |
15 | ||
16 | private readonly videoUUID: string | |
17 | private readonly sha256Path: string | |
18 | private readonly streamingPlaylist: MStreamingPlaylistVideo | |
19 | private readonly sendToObjectStorage: boolean | |
9ab330b9 | 20 | private readonly writeQueue = new PQueue({ concurrency: 1 }) |
cfd57d2c C |
21 | |
22 | constructor (options: { | |
23 | videoUUID: string | |
24 | sha256Path: string | |
25 | streamingPlaylist: MStreamingPlaylistVideo | |
26 | sendToObjectStorage: boolean | |
27 | }) { | |
28 | this.videoUUID = options.videoUUID | |
29 | this.sha256Path = options.sha256Path | |
30 | this.streamingPlaylist = options.streamingPlaylist | |
31 | this.sendToObjectStorage = options.sendToObjectStorage | |
8ebf2a5d C |
32 | } |
33 | ||
cfd57d2c C |
34 | async addSegmentSha (segmentPath: string) { |
35 | logger.debug('Adding live sha segment %s.', segmentPath, lTags(this.videoUUID)) | |
8ebf2a5d C |
36 | |
37 | const shaResult = await buildSha256Segment(segmentPath) | |
38 | ||
cfd57d2c C |
39 | const segmentName = basename(segmentPath) |
40 | this.segmentsSha256.set(segmentName, shaResult) | |
8ebf2a5d | 41 | |
9ab330b9 C |
42 | try { |
43 | await this.writeToDisk() | |
44 | } catch (err) { | |
45 | logger.error('Cannot write sha segments to disk.', { err }) | |
46 | } | |
8ebf2a5d C |
47 | } |
48 | ||
cfd57d2c | 49 | async removeSegmentSha (segmentPath: string) { |
8ebf2a5d C |
50 | const segmentName = basename(segmentPath) |
51 | ||
cfd57d2c | 52 | logger.debug('Removing live sha segment %s.', segmentPath, lTags(this.videoUUID)) |
8ebf2a5d | 53 | |
cfd57d2c | 54 | if (!this.segmentsSha256.has(segmentName)) { |
0c9668f7 C |
55 | logger.warn( |
56 | 'Unknown segment in live segment hash store for video %s and segment %s.', | |
57 | this.videoUUID, segmentPath, lTags(this.videoUUID) | |
58 | ) | |
8ebf2a5d C |
59 | return |
60 | } | |
61 | ||
cfd57d2c | 62 | this.segmentsSha256.delete(segmentName) |
8ebf2a5d | 63 | |
cfd57d2c | 64 | await this.writeToDisk() |
8ebf2a5d C |
65 | } |
66 | ||
9ab330b9 C |
67 | private writeToDisk () { |
68 | return this.writeQueue.add(async () => { | |
69 | await writeJson(this.sha256Path, mapToJSON(this.segmentsSha256)) | |
8ebf2a5d | 70 | |
9ab330b9 C |
71 | if (this.sendToObjectStorage) { |
72 | const url = await storeHLSFileFromPath(this.streamingPlaylist, this.sha256Path) | |
cfd57d2c | 73 | |
9ab330b9 C |
74 | if (this.streamingPlaylist.segmentsSha256Url !== url) { |
75 | this.streamingPlaylist.segmentsSha256Url = url | |
76 | await this.streamingPlaylist.save() | |
77 | } | |
cfd57d2c | 78 | } |
9ab330b9 | 79 | }) |
8ebf2a5d C |
80 | } |
81 | } | |
82 | ||
83 | export { | |
84 | LiveSegmentShaStore | |
85 | } |