Don't refresh videos when processing views
authorChocobozzz <me@florianbigard.com>
Tue, 4 Feb 2020 14:45:41 +0000 (15:45 +0100)
committerChocobozzz <me@florianbigard.com>
Tue, 4 Feb 2020 14:58:59 +0000 (15:58 +0100)
It allows us to use a cache

server/helpers/video.ts
server/lib/activitypub/audience.ts
server/lib/activitypub/process/process-view.ts
server/lib/activitypub/send/utils.ts
server/lib/activitypub/videos.ts
server/middlewares/validators/videos/videos.ts
server/models/model-cache.ts
server/models/video/video.ts
server/typings/models/video/video.ts

index 907564703b7f4a9097b216dd15ef39449da8ff97..4fe2a60f0d57ca925bbee339c373cc063919f0a4 100644 (file)
@@ -38,14 +38,23 @@ function fetchVideo (
   if (fetchType === 'id' || fetchType === 'none') return VideoModel.loadOnlyId(id)
 }
 
-type VideoFetchByUrlType = 'all' | 'only-video'
+type VideoFetchByUrlType = 'all' | 'only-video' | 'only-immutable-attributes'
 
 function fetchVideoByUrl (url: string, fetchType: 'all'): Bluebird<MVideoAccountLightBlacklistAllFiles>
+function fetchVideoByUrl (url: string, fetchType: 'only-immutable-attributes'): Bluebird<MVideoImmutable>
 function fetchVideoByUrl (url: string, fetchType: 'only-video'): Bluebird<MVideoThumbnail>
-function fetchVideoByUrl (url: string, fetchType: VideoFetchByUrlType): Bluebird<MVideoAccountLightBlacklistAllFiles | MVideoThumbnail>
-function fetchVideoByUrl (url: string, fetchType: VideoFetchByUrlType): Bluebird<MVideoAccountLightBlacklistAllFiles | MVideoThumbnail> {
+function fetchVideoByUrl (
+  url: string,
+  fetchType: VideoFetchByUrlType
+): Bluebird<MVideoAccountLightBlacklistAllFiles | MVideoThumbnail | MVideoImmutable>
+function fetchVideoByUrl (
+  url: string,
+  fetchType: VideoFetchByUrlType
+): Bluebird<MVideoAccountLightBlacklistAllFiles | MVideoThumbnail | MVideoImmutable> {
   if (fetchType === 'all') return VideoModel.loadByUrlAndPopulateAccount(url)
 
+  if (fetchType === 'only-immutable-attributes') return VideoModel.loadByUrlImmutableAttributes(url)
+
   if (fetchType === 'only-video') return VideoModel.loadByUrl(url)
 }
 
index f2ab54cf7fd1895c4a866c81b343512f11aeae17..39caeef7b78fc7a1f390f15310350695864fae14 100644 (file)
@@ -4,7 +4,15 @@ import { ACTIVITY_PUB } from '../../initializers/constants'
 import { ActorModel } from '../../models/activitypub/actor'
 import { VideoModel } from '../../models/video/video'
 import { VideoShareModel } from '../../models/video/video-share'
-import { MActorFollowersUrl, MActorLight, MCommentOwner, MCommentOwnerVideo, MVideo, MVideoAccountLight } from '../../typings/models'
+import {
+  MActorFollowersUrl,
+  MActorLight,
+  MCommentOwner,
+  MCommentOwnerVideo,
+  MVideo,
+  MVideoAccountLight,
+  MVideoId
+} from '../../typings/models'
 
 function getRemoteVideoAudience (video: MVideoAccountLight, actorsInvolvedInVideo: MActorFollowersUrl[]): ActivityAudience {
   return {
@@ -48,7 +56,7 @@ function getAudienceFromFollowersOf (actorsInvolvedInObject: MActorFollowersUrl[
   }
 }
 
-async function getActorsInvolvedInVideo (video: MVideo, t: Transaction) {
+async function getActorsInvolvedInVideo (video: MVideoId, t: Transaction) {
   const actors: MActorLight[] = await VideoShareModel.loadActorsByShare(video.id, t)
 
   const videoAll = video as VideoModel
index df29ee968b85fe7c22fd20c6eed427683fa1a2e8..b3b6c933dd9e5b1400d1e8049dd0014d5403298f 100644 (file)
@@ -23,7 +23,8 @@ async function processCreateView (activity: ActivityView | ActivityCreate, byAct
 
   const options = {
     videoObject,
-    fetchType: 'only-video' as 'only-video'
+    fetchType: 'only-immutable-attributes' as 'only-immutable-attributes',
+    allowRefresh: false as false
   }
   const { video } = await getOrCreateVideoAndAccountAndChannel(options)
 
index 0d67bb3d6348926d687e40b55233c8ba3cb9e45e..9436daf1713aad59ae062a2d1f96824477c59b6c 100644 (file)
@@ -7,7 +7,7 @@ import { JobQueue } from '../../job-queue'
 import { getActorsInvolvedInVideo, getAudienceFromFollowersOf, getRemoteVideoAudience } from '../audience'
 import { getServerActor } from '../../../helpers/utils'
 import { afterCommitIfTransaction } from '../../../helpers/database-utils'
-import { MActorWithInboxes, MActor, MActorId, MActorLight, MVideo, MVideoAccountLight } from '../../../typings/models'
+import { MActorWithInboxes, MActor, MActorId, MActorLight, MVideo, MVideoAccountLight, MVideoId } from '../../../typings/models'
 import { ContextType } from '@server/helpers/activitypub'
 
 async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAudience) => Activity, options: {
@@ -43,7 +43,7 @@ async function forwardVideoRelatedActivity (
   activity: Activity,
   t: Transaction,
   followersException: MActorWithInboxes[] = [],
-  video: MVideo
+  video: MVideoId
 ) {
   // Mastodon does not add our announces in audience, so we forward to them manually
   const additionalActors = await getActorsInvolvedInVideo(video, t)
index 9e43caa204d26d3d10345c1196a191579a9a2240..7d8296e45e75b38267c02eec29616178feb62aea 100644 (file)
@@ -68,7 +68,7 @@ import {
   MVideoAPWithoutCaption,
   MVideoFile,
   MVideoFullLight,
-  MVideoId,
+  MVideoId, MVideoImmutable,
   MVideoThumbnail
 } from '../../typings/models'
 import { MThumbnail } from '../../typings/models/video/thumbnail'
@@ -200,24 +200,41 @@ async function syncVideoExternalAttributes (video: MVideo, fetchedVideo: VideoTo
   await Bluebird.map(jobPayloads, payload => JobQueue.Instance.createJobWithPromise({ type: 'activitypub-http-fetcher', payload }))
 }
 
-function getOrCreateVideoAndAccountAndChannel (options: {
+type GetVideoResult <T> = Promise<{
+  video: T
+  created: boolean
+  autoBlacklisted?: boolean
+}>
+
+type GetVideoParamAll = {
   videoObject: { id: string } | string
   syncParam?: SyncParam
   fetchType?: 'all'
   allowRefresh?: boolean
-}): Promise<{ video: MVideoAccountLightBlacklistAllFiles, created: boolean, autoBlacklisted?: boolean }>
-function getOrCreateVideoAndAccountAndChannel (options: {
+}
+
+type GetVideoParamImmutable = {
   videoObject: { id: string } | string
   syncParam?: SyncParam
-  fetchType?: VideoFetchByUrlType
-  allowRefresh?: boolean
-}): Promise<{ video: MVideoAccountLightBlacklistAllFiles | MVideoThumbnail, created: boolean, autoBlacklisted?: boolean }>
-async function getOrCreateVideoAndAccountAndChannel (options: {
+  fetchType: 'only-immutable-attributes'
+  allowRefresh: false
+}
+
+type GetVideoParamOther = {
   videoObject: { id: string } | string
   syncParam?: SyncParam
-  fetchType?: VideoFetchByUrlType
-  allowRefresh?: boolean // true by default
-}): Promise<{ video: MVideoAccountLightBlacklistAllFiles | MVideoThumbnail, created: boolean, autoBlacklisted?: boolean }> {
+  fetchType?: 'all' | 'only-video'
+  allowRefresh?: boolean
+}
+
+function getOrCreateVideoAndAccountAndChannel (options: GetVideoParamAll): GetVideoResult<MVideoAccountLightBlacklistAllFiles>
+function getOrCreateVideoAndAccountAndChannel (options: GetVideoParamImmutable): GetVideoResult<MVideoImmutable>
+function getOrCreateVideoAndAccountAndChannel (
+  options: GetVideoParamOther
+): GetVideoResult<MVideoAccountLightBlacklistAllFiles | MVideoThumbnail>
+async function getOrCreateVideoAndAccountAndChannel (
+  options: GetVideoParamAll | GetVideoParamImmutable | GetVideoParamOther
+): GetVideoResult<MVideoAccountLightBlacklistAllFiles | MVideoThumbnail | MVideoImmutable> {
   // Default params
   const syncParam = options.syncParam || { likes: true, dislikes: true, shares: true, comments: true, thumbnail: true, refreshVideo: false }
   const fetchType = options.fetchType || 'all'
@@ -225,12 +242,13 @@ async function getOrCreateVideoAndAccountAndChannel (options: {
 
   // Get video url
   const videoUrl = getAPId(options.videoObject)
-
   let videoFromDatabase = await fetchVideoByUrl(videoUrl, fetchType)
+
   if (videoFromDatabase) {
-    if (videoFromDatabase.isOutdated() && allowRefresh === true) {
+    // If allowRefresh is true, we could not call this function using 'only-immutable-attributes' fetch type
+    if (allowRefresh === true && (videoFromDatabase as MVideoThumbnail).isOutdated()) {
       const refreshOptions = {
-        video: videoFromDatabase,
+        video: videoFromDatabase as MVideoThumbnail,
         fetchedType: fetchType,
         syncParam
       }
index c14184b35da7c4d3ebf94851445b52a380f5899d..a027c4840ef3861643b20ae6355170075fc3d197 100644 (file)
@@ -160,6 +160,9 @@ const videosCustomGetValidator = (
       if (areValidationErrors(req, res)) return
       if (!await doesVideoExist(req.params.id, res, fetchType)) return
 
+      // Controllers does not need to check video rights
+      if (fetchType === 'only-immutable-attributes') return next()
+
       const video = getVideoWithAttributes(res)
       const videoAll = video as MVideoFullLight
 
index 8afe3834fb755c8d6e47324d7ba8423d601396a4..a87f99aa2adea5ab591a64d897047dd6978eb39f 100644 (file)
@@ -6,7 +6,8 @@ type ModelCacheType =
   'local-account-name'
   | 'local-actor-name'
   | 'local-actor-url'
-  | 'video-immutable'
+  | 'load-video-immutable-id'
+  | 'load-video-immutable-url'
 
 type DeleteKey =
   'video'
@@ -19,7 +20,8 @@ class ModelCache {
     'local-account-name': new Map(),
     'local-actor-name': new Map(),
     'local-actor-url': new Map(),
-    'video-immutable': new Map()
+    'load-video-immutable-id': new Map(),
+    'load-video-immutable-url': new Map()
   }
 
   private readonly deleteIds: {
index 9e02d163f5f52ddf3b39f962ac7fdd8639d3800e..5964526a997061c2503d361043d77935e10dc40b 100644 (file)
@@ -145,6 +145,7 @@ export enum ScopeNames {
   WITH_USER_HISTORY = 'WITH_USER_HISTORY',
   WITH_STREAMING_PLAYLISTS = 'WITH_STREAMING_PLAYLISTS',
   WITH_USER_ID = 'WITH_USER_ID',
+  WITH_IMMUTABLE_ATTRIBUTES = 'WITH_IMMUTABLE_ATTRIBUTES',
   WITH_THUMBNAILS = 'WITH_THUMBNAILS'
 }
 
@@ -188,6 +189,9 @@ export type AvailableForListIDsOptions = {
 }
 
 @Scopes(() => ({
+  [ScopeNames.WITH_IMMUTABLE_ATTRIBUTES]: {
+    attributes: [ 'id', 'url', 'uuid', 'remote' ]
+  },
   [ScopeNames.FOR_API]: (options: ForAPIOptions) => {
     const query: FindOptions = {
       include: [
@@ -1476,20 +1480,16 @@ export class VideoModel extends Model<VideoModel> {
 
   static loadImmutableAttributes (id: number | string, t?: Transaction): Bluebird<MVideoImmutable> {
     const fun = () => {
-      const where = buildWhereIdOrUUID(id)
-      const options = {
-        attributes: [
-          'id', 'url', 'uuid'
-        ],
-        where,
+      const query = {
+        where: buildWhereIdOrUUID(id),
         transaction: t
       }
 
-      return VideoModel.unscoped().findOne(options)
+      return VideoModel.scope(ScopeNames.WITH_IMMUTABLE_ATTRIBUTES).findOne(query)
     }
 
     return ModelCache.Instance.doCache({
-      cacheType: 'video-immutable',
+      cacheType: 'load-video-immutable-id',
       key: '' + id,
       deleteKey: 'video',
       fun
@@ -1559,6 +1559,26 @@ export class VideoModel extends Model<VideoModel> {
     return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(query)
   }
 
+  static loadByUrlImmutableAttributes (url: string, transaction?: Transaction): Bluebird<MVideoImmutable> {
+    const fun = () => {
+      const query: FindOptions = {
+        where: {
+          url
+        },
+        transaction
+      }
+
+      return VideoModel.scope(ScopeNames.WITH_IMMUTABLE_ATTRIBUTES).findOne(query)
+    }
+
+    return ModelCache.Instance.doCache({
+      cacheType: 'load-video-immutable-url',
+      key: url,
+      deleteKey: 'video',
+      fun
+    })
+  }
+
   static loadByUrlAndPopulateAccount (url: string, transaction?: Transaction): Bluebird<MVideoAccountLightBlacklistAllFiles> {
     const query: FindOptions = {
       where: {
index 3ebb5a76282247c18402e481c1fac37019ef8e07..022a9566d50d3f8267df2af29566c504f8cf5a54 100644 (file)
@@ -37,7 +37,7 @@ export type MVideoId = Pick<MVideo, 'id'>
 export type MVideoUrl = Pick<MVideo, 'url'>
 export type MVideoUUID = Pick<MVideo, 'uuid'>
 
-export type MVideoImmutable = Pick<MVideo, 'id' | 'url' | 'uuid'>
+export type MVideoImmutable = Pick<MVideo, 'id' | 'url' | 'uuid' | 'remote' | 'isOwned'>
 export type MVideoIdUrl = MVideoId & MVideoUrl
 export type MVideoFeed = Pick<MVideo, 'name' | 'uuid'>