diff options
author | Chocobozzz <me@florianbigard.com> | 2022-03-24 13:36:47 +0100 |
---|---|---|
committer | Chocobozzz <chocobozzz@cpy.re> | 2022-04-15 09:49:35 +0200 |
commit | b211106695bb82f6c32e53306081b5262c3d109d (patch) | |
tree | fa187de1c33b0956665f5362e29af6b0f6d8bb57 /server/lib/redis.ts | |
parent | 69d48ee30c9d47cddf0c3c047dc99a99dcb6e894 (diff) | |
download | PeerTube-b211106695bb82f6c32e53306081b5262c3d109d.tar.gz PeerTube-b211106695bb82f6c32e53306081b5262c3d109d.tar.zst PeerTube-b211106695bb82f6c32e53306081b5262c3d109d.zip |
Support video views/viewers stats in server
* Add "currentTime" and "event" body params to view endpoint
* Merge watching and view endpoints
* Introduce WatchAction AP activity
* Add tables to store viewer information of local videos
* Add endpoints to fetch video views/viewers stats of local videos
* Refactor views/viewers handlers
* Support "views" and "viewers" counters for both VOD and live videos
Diffstat (limited to 'server/lib/redis.ts')
-rw-r--r-- | server/lib/redis.ts | 68 |
1 files changed, 65 insertions, 3 deletions
diff --git a/server/lib/redis.ts b/server/lib/redis.ts index c4c1fa443..b86aefa0e 100644 --- a/server/lib/redis.ts +++ b/server/lib/redis.ts | |||
@@ -249,6 +249,45 @@ class Redis { | |||
249 | ]) | 249 | ]) |
250 | } | 250 | } |
251 | 251 | ||
252 | /* ************ Video viewers stats ************ */ | ||
253 | |||
254 | getLocalVideoViewer (options: { | ||
255 | key?: string | ||
256 | // Or | ||
257 | ip?: string | ||
258 | videoId?: number | ||
259 | }) { | ||
260 | if (options.key) return this.getObject(options.key) | ||
261 | |||
262 | const { viewerKey } = this.generateLocalVideoViewerKeys(options.ip, options.videoId) | ||
263 | |||
264 | return this.getObject(viewerKey) | ||
265 | } | ||
266 | |||
267 | setLocalVideoViewer (ip: string, videoId: number, object: any) { | ||
268 | const { setKey, viewerKey } = this.generateLocalVideoViewerKeys(ip, videoId) | ||
269 | |||
270 | return Promise.all([ | ||
271 | this.addToSet(setKey, viewerKey), | ||
272 | this.setObject(viewerKey, object) | ||
273 | ]) | ||
274 | } | ||
275 | |||
276 | listLocalVideoViewerKeys () { | ||
277 | const { setKey } = this.generateLocalVideoViewerKeys() | ||
278 | |||
279 | return this.getSet(setKey) | ||
280 | } | ||
281 | |||
282 | deleteLocalVideoViewersKeys (key: string) { | ||
283 | const { setKey } = this.generateLocalVideoViewerKeys() | ||
284 | |||
285 | return Promise.all([ | ||
286 | this.deleteFromSet(setKey, key), | ||
287 | this.deleteKey(key) | ||
288 | ]) | ||
289 | } | ||
290 | |||
252 | /* ************ Resumable uploads final responses ************ */ | 291 | /* ************ Resumable uploads final responses ************ */ |
253 | 292 | ||
254 | setUploadSession (uploadId: string, response?: { video: { id: number, shortUUID: string, uuid: string } }) { | 293 | setUploadSession (uploadId: string, response?: { video: { id: number, shortUUID: string, uuid: string } }) { |
@@ -290,10 +329,18 @@ class Redis { | |||
290 | 329 | ||
291 | /* ************ Keys generation ************ */ | 330 | /* ************ Keys generation ************ */ |
292 | 331 | ||
293 | private generateLocalVideoViewsKeys (videoId?: Number) { | 332 | private generateLocalVideoViewsKeys (videoId: number): { setKey: string, videoKey: string } |
333 | private generateLocalVideoViewsKeys (): { setKey: string } | ||
334 | private generateLocalVideoViewsKeys (videoId?: number) { | ||
294 | return { setKey: `local-video-views-buffer`, videoKey: `local-video-views-buffer-${videoId}` } | 335 | return { setKey: `local-video-views-buffer`, videoKey: `local-video-views-buffer-${videoId}` } |
295 | } | 336 | } |
296 | 337 | ||
338 | private generateLocalVideoViewerKeys (ip: string, videoId: number): { setKey: string, viewerKey: string } | ||
339 | private generateLocalVideoViewerKeys (): { setKey: string } | ||
340 | private generateLocalVideoViewerKeys (ip?: string, videoId?: number) { | ||
341 | return { setKey: `local-video-viewer-stats-keys`, viewerKey: `local-video-viewer-stats-${ip}-${videoId}` } | ||
342 | } | ||
343 | |||
297 | private generateVideoViewStatsKeys (options: { videoId?: number, hour?: number }) { | 344 | private generateVideoViewStatsKeys (options: { videoId?: number, hour?: number }) { |
298 | const hour = exists(options.hour) | 345 | const hour = exists(options.hour) |
299 | ? options.hour | 346 | ? options.hour |
@@ -352,8 +399,23 @@ class Redis { | |||
352 | return this.client.del(this.prefix + key) | 399 | return this.client.del(this.prefix + key) |
353 | } | 400 | } |
354 | 401 | ||
355 | private async setValue (key: string, value: string, expirationMilliseconds: number) { | 402 | private async getObject (key: string) { |
356 | const result = await this.client.set(this.prefix + key, value, { PX: expirationMilliseconds }) | 403 | const value = await this.getValue(key) |
404 | if (!value) return null | ||
405 | |||
406 | return JSON.parse(value) | ||
407 | } | ||
408 | |||
409 | private setObject (key: string, value: { [ id: string ]: number | string }) { | ||
410 | return this.setValue(key, JSON.stringify(value)) | ||
411 | } | ||
412 | |||
413 | private async setValue (key: string, value: string, expirationMilliseconds?: number) { | ||
414 | const options = expirationMilliseconds | ||
415 | ? { PX: expirationMilliseconds } | ||
416 | : {} | ||
417 | |||
418 | const result = await this.client.set(this.prefix + key, value, options) | ||
357 | 419 | ||
358 | if (result !== 'OK') throw new Error('Redis set result is not OK.') | 420 | if (result !== 'OK') throw new Error('Redis set result is not OK.') |
359 | } | 421 | } |