]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/lib/live/live-segment-sha-store.ts
Fix log
[github/Chocobozzz/PeerTube.git] / server / lib / live / live-segment-sha-store.ts
CommitLineData
49b80bd9 1import { rename, writeJson } from 'fs-extra'
be3ec61a 2import PQueue from 'p-queue'
8ebf2a5d 3import { basename } from 'path'
cfd57d2c 4import { mapToJSON } from '@server/helpers/core-utils'
8ebf2a5d 5import { logger, loggerTagsFactory } from '@server/helpers/logger'
cfd57d2c 6import { MStreamingPlaylistVideo } from '@server/types/models'
8ebf2a5d 7import { buildSha256Segment } from '../hls'
cfd57d2c 8import { storeHLSFileFromPath } from '../object-storage'
8ebf2a5d
C
9
10const lTags = loggerTagsFactory('live')
11
12class LiveSegmentShaStore {
13
cfd57d2c
C
14 private readonly segmentsSha256 = new Map<string, string>()
15
16 private readonly videoUUID: string
be3ec61a 17
cfd57d2c 18 private readonly sha256Path: string
be3ec61a
C
19 private readonly sha256PathTMP: string
20
cfd57d2c
C
21 private readonly streamingPlaylist: MStreamingPlaylistVideo
22 private readonly sendToObjectStorage: boolean
9ab330b9 23 private readonly writeQueue = new PQueue({ concurrency: 1 })
cfd57d2c
C
24
25 constructor (options: {
26 videoUUID: string
27 sha256Path: string
28 streamingPlaylist: MStreamingPlaylistVideo
29 sendToObjectStorage: boolean
30 }) {
31 this.videoUUID = options.videoUUID
be3ec61a 32
cfd57d2c 33 this.sha256Path = options.sha256Path
be3ec61a
C
34 this.sha256PathTMP = options.sha256Path + '.tmp'
35
cfd57d2c
C
36 this.streamingPlaylist = options.streamingPlaylist
37 this.sendToObjectStorage = options.sendToObjectStorage
8ebf2a5d
C
38 }
39
cfd57d2c
C
40 async addSegmentSha (segmentPath: string) {
41 logger.debug('Adding live sha segment %s.', segmentPath, lTags(this.videoUUID))
8ebf2a5d
C
42
43 const shaResult = await buildSha256Segment(segmentPath)
44
cfd57d2c
C
45 const segmentName = basename(segmentPath)
46 this.segmentsSha256.set(segmentName, shaResult)
8ebf2a5d 47
9ab330b9
C
48 try {
49 await this.writeToDisk()
50 } catch (err) {
51 logger.error('Cannot write sha segments to disk.', { err })
52 }
8ebf2a5d
C
53 }
54
cfd57d2c 55 async removeSegmentSha (segmentPath: string) {
8ebf2a5d
C
56 const segmentName = basename(segmentPath)
57
cfd57d2c 58 logger.debug('Removing live sha segment %s.', segmentPath, lTags(this.videoUUID))
8ebf2a5d 59
cfd57d2c 60 if (!this.segmentsSha256.has(segmentName)) {
0c9668f7
C
61 logger.warn(
62 'Unknown segment in live segment hash store for video %s and segment %s.',
63 this.videoUUID, segmentPath, lTags(this.videoUUID)
64 )
8ebf2a5d
C
65 return
66 }
67
cfd57d2c 68 this.segmentsSha256.delete(segmentName)
8ebf2a5d 69
cfd57d2c 70 await this.writeToDisk()
8ebf2a5d
C
71 }
72
9ab330b9
C
73 private writeToDisk () {
74 return this.writeQueue.add(async () => {
31b9518a 75 logger.debug(`Writing segment sha JSON ${this.sha256Path} of ${this.videoUUID} on disk.`, lTags(this.videoUUID))
6a9b3151 76
49b80bd9 77 // Atomic write: use rename instead of move that is not atomic
be3ec61a 78 await writeJson(this.sha256PathTMP, mapToJSON(this.segmentsSha256))
49b80bd9 79 await rename(this.sha256PathTMP, this.sha256Path)
8ebf2a5d 80
9ab330b9
C
81 if (this.sendToObjectStorage) {
82 const url = await storeHLSFileFromPath(this.streamingPlaylist, this.sha256Path)
cfd57d2c 83
9ab330b9
C
84 if (this.streamingPlaylist.segmentsSha256Url !== url) {
85 this.streamingPlaylist.segmentsSha256Url = url
86 await this.streamingPlaylist.save()
87 }
cfd57d2c 88 }
9ab330b9 89 })
8ebf2a5d
C
90 }
91}
92
93export {
94 LiveSegmentShaStore
95}