]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/lib/local-actor.ts
Remove uneeded memoize
[github/Chocobozzz/PeerTube.git] / server / lib / local-actor.ts
1 import { queue } from 'async'
2 import { remove } from 'fs-extra'
3 import LRUCache from 'lru-cache'
4 import { join } from 'path'
5 import { ActorModel } from '@server/models/actor/actor'
6 import { getLowercaseExtension } from '@shared/core-utils'
7 import { buildUUID } from '@shared/extra-utils'
8 import { ActivityPubActorType, ActorImageType } from '@shared/models'
9 import { retryTransactionWrapper } from '../helpers/database-utils'
10 import { processImage } from '../helpers/image-utils'
11 import { downloadImage } from '../helpers/requests'
12 import { CONFIG } from '../initializers/config'
13 import { ACTOR_IMAGES_SIZE, LRU_CACHE, QUEUE_CONCURRENCY, WEBSERVER } from '../initializers/constants'
14 import { sequelizeTypescript } from '../initializers/database'
15 import { MAccountDefault, MActor, MChannelDefault } from '../types/models'
16 import { deleteActorImages, updateActorImages } from './activitypub/actors'
17 import { sendUpdateActor } from './activitypub/send'
18
19 function buildActorInstance (type: ActivityPubActorType, url: string, preferredUsername: string) {
20 return new ActorModel({
21 type,
22 url,
23 preferredUsername,
24 publicKey: null,
25 privateKey: null,
26 followersCount: 0,
27 followingCount: 0,
28 inboxUrl: url + '/inbox',
29 outboxUrl: url + '/outbox',
30 sharedInboxUrl: WEBSERVER.URL + '/inbox',
31 followersUrl: url + '/followers',
32 followingUrl: url + '/following'
33 }) as MActor
34 }
35
36 async function updateLocalActorImageFiles (
37 accountOrChannel: MAccountDefault | MChannelDefault,
38 imagePhysicalFile: Express.Multer.File,
39 type: ActorImageType
40 ) {
41 const processImageSize = async (imageSize: { width: number, height: number }) => {
42 const extension = getLowercaseExtension(imagePhysicalFile.filename)
43
44 const imageName = buildUUID() + extension
45 const destination = join(CONFIG.STORAGE.ACTOR_IMAGES, imageName)
46 await processImage(imagePhysicalFile.path, destination, imageSize, true)
47
48 return {
49 imageName,
50 imageSize
51 }
52 }
53
54 const processedImages = await Promise.all(ACTOR_IMAGES_SIZE[type].map(processImageSize))
55 await remove(imagePhysicalFile.path)
56
57 return retryTransactionWrapper(() => sequelizeTypescript.transaction(async t => {
58 const actorImagesInfo = processedImages.map(({ imageName, imageSize }) => ({
59 name: imageName,
60 fileUrl: null,
61 height: imageSize.height,
62 width: imageSize.width,
63 onDisk: true
64 }))
65
66 const updatedActor = await updateActorImages(accountOrChannel.Actor, type, actorImagesInfo, t)
67 await updatedActor.save({ transaction: t })
68
69 await sendUpdateActor(accountOrChannel, t)
70
71 return type === ActorImageType.AVATAR
72 ? updatedActor.Avatars
73 : updatedActor.Banners
74 }))
75 }
76
77 async function deleteLocalActorImageFile (accountOrChannel: MAccountDefault | MChannelDefault, type: ActorImageType) {
78 return retryTransactionWrapper(() => {
79 return sequelizeTypescript.transaction(async t => {
80 const updatedActor = await deleteActorImages(accountOrChannel.Actor, type, t)
81 await updatedActor.save({ transaction: t })
82
83 await sendUpdateActor(accountOrChannel, t)
84
85 return updatedActor.Avatars
86 })
87 })
88 }
89
90 type DownloadImageQueueTask = {
91 fileUrl: string
92 filename: string
93 type: ActorImageType
94 size: typeof ACTOR_IMAGES_SIZE[ActorImageType][0]
95 }
96
97 const downloadImageQueue = queue<DownloadImageQueueTask, Error>((task, cb) => {
98 downloadImage(task.fileUrl, CONFIG.STORAGE.ACTOR_IMAGES, task.filename, task.size)
99 .then(() => cb())
100 .catch(err => cb(err))
101 }, QUEUE_CONCURRENCY.ACTOR_PROCESS_IMAGE)
102
103 function pushActorImageProcessInQueue (task: DownloadImageQueueTask) {
104 return new Promise<void>((res, rej) => {
105 downloadImageQueue.push(task, err => {
106 if (err) return rej(err)
107
108 return res()
109 })
110 })
111 }
112
113 // Unsafe so could returns paths that does not exist anymore
114 const actorImagePathUnsafeCache = new LRUCache<string, string>({ max: LRU_CACHE.ACTOR_IMAGE_STATIC.MAX_SIZE })
115
116 export {
117 actorImagePathUnsafeCache,
118 updateLocalActorImageFiles,
119 deleteLocalActorImageFile,
120 pushActorImageProcessInQueue,
121 buildActorInstance
122 }