]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/lib/local-actor.ts
Merge branch 'master' into release/3.3.0
[github/Chocobozzz/PeerTube.git] / server / lib / local-actor.ts
1 import 'multer'
2 import { queue } from 'async'
3 import * as LRUCache from 'lru-cache'
4 import { join } from 'path'
5 import { getLowercaseExtension } from '@server/helpers/core-utils'
6 import { buildUUID } from '@server/helpers/uuid'
7 import { ActorModel } from '@server/models/actor/actor'
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 { deleteActorImageInstance, updateActorImageInstance } 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 updateLocalActorImageFile (
37 accountOrChannel: MAccountDefault | MChannelDefault,
38 imagePhysicalFile: Express.Multer.File,
39 type: ActorImageType
40 ) {
41 const imageSize = type === ActorImageType.AVATAR
42 ? ACTOR_IMAGES_SIZE.AVATARS
43 : ACTOR_IMAGES_SIZE.BANNERS
44
45 const extension = getLowercaseExtension(imagePhysicalFile.filename)
46
47 const imageName = buildUUID() + extension
48 const destination = join(CONFIG.STORAGE.ACTOR_IMAGES, imageName)
49 await processImage(imagePhysicalFile.path, destination, imageSize)
50
51 return retryTransactionWrapper(() => {
52 return sequelizeTypescript.transaction(async t => {
53 const actorImageInfo = {
54 name: imageName,
55 fileUrl: null,
56 height: imageSize.height,
57 width: imageSize.width,
58 onDisk: true
59 }
60
61 const updatedActor = await updateActorImageInstance(accountOrChannel.Actor, type, actorImageInfo, t)
62 await updatedActor.save({ transaction: t })
63
64 await sendUpdateActor(accountOrChannel, t)
65
66 return type === ActorImageType.AVATAR
67 ? updatedActor.Avatar
68 : updatedActor.Banner
69 })
70 })
71 }
72
73 async function deleteLocalActorImageFile (accountOrChannel: MAccountDefault | MChannelDefault, type: ActorImageType) {
74 return retryTransactionWrapper(() => {
75 return sequelizeTypescript.transaction(async t => {
76 const updatedActor = await deleteActorImageInstance(accountOrChannel.Actor, type, t)
77 await updatedActor.save({ transaction: t })
78
79 await sendUpdateActor(accountOrChannel, t)
80
81 return updatedActor.Avatar
82 })
83 })
84 }
85
86 type DownloadImageQueueTask = { fileUrl: string, filename: string, type: ActorImageType }
87
88 const downloadImageQueue = queue<DownloadImageQueueTask, Error>((task, cb) => {
89 const size = task.type === ActorImageType.AVATAR
90 ? ACTOR_IMAGES_SIZE.AVATARS
91 : ACTOR_IMAGES_SIZE.BANNERS
92
93 downloadImage(task.fileUrl, CONFIG.STORAGE.ACTOR_IMAGES, task.filename, size)
94 .then(() => cb())
95 .catch(err => cb(err))
96 }, QUEUE_CONCURRENCY.ACTOR_PROCESS_IMAGE)
97
98 function pushActorImageProcessInQueue (task: DownloadImageQueueTask) {
99 return new Promise<void>((res, rej) => {
100 downloadImageQueue.push(task, err => {
101 if (err) return rej(err)
102
103 return res()
104 })
105 })
106 }
107
108 // Unsafe so could returns paths that does not exist anymore
109 const actorImagePathUnsafeCache = new LRUCache<string, string>({ max: LRU_CACHE.ACTOR_IMAGE_STATIC.MAX_SIZE })
110
111 export {
112 actorImagePathUnsafeCache,
113 updateLocalActorImageFile,
114 deleteLocalActorImageFile,
115 pushActorImageProcessInQueue,
116 buildActorInstance
117 }