X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=server%2Flib%2Favatar.ts;h=86f1e7bdb06e2a87a988b05acf188cd9645a1d10;hb=fae6e4da8f516a9d6c3bad9bf6f35811ccacbad8;hp=7fdef008c45502dabec9bb298166ccd823b21ae7;hpb=4bbfc6c606c8d3794bae25c64c516120af41f4eb;p=github%2FChocobozzz%2FPeerTube.git diff --git a/server/lib/avatar.ts b/server/lib/avatar.ts index 7fdef008c..86f1e7bdb 100644 --- a/server/lib/avatar.ts +++ b/server/lib/avatar.ts @@ -1,34 +1,85 @@ import 'multer' -import * as uuidv4 from 'uuid' import { sendUpdateActor } from './activitypub/send' -import { AVATARS_SIZE, CONFIG, sequelizeTypescript } from '../initializers' -import { updateActorAvatarInstance } from './activitypub' +import { AVATARS_SIZE, LRU_CACHE, QUEUE_CONCURRENCY } from '../initializers/constants' +import { updateActorAvatarInstance, deleteActorAvatarInstance } from './activitypub/actor' import { processImage } from '../helpers/image-utils' -import { ActorModel } from '../models/activitypub/actor' -import { AccountModel } from '../models/account/account' -import { VideoChannelModel } from '../models/video/video-channel' import { extname, join } from 'path' +import { retryTransactionWrapper } from '../helpers/database-utils' +import { v4 as uuidv4 } from 'uuid' +import { CONFIG } from '../initializers/config' +import { sequelizeTypescript } from '../initializers/database' +import * as LRUCache from 'lru-cache' +import { queue } from 'async' +import { downloadImage } from '../helpers/requests' +import { MAccountDefault, MChannelDefault } from '../types/models' -async function updateActorAvatarFile ( - avatarPhysicalFile: Express.Multer.File, - actor: ActorModel, - accountOrChannel: AccountModel | VideoChannelModel +async function updateLocalActorAvatarFile ( + accountOrChannel: MAccountDefault | MChannelDefault, + avatarPhysicalFile: Express.Multer.File ) { const extension = extname(avatarPhysicalFile.filename) + const avatarName = uuidv4() + extension const destination = join(CONFIG.STORAGE.AVATARS_DIR, avatarName) - await processImage(avatarPhysicalFile, destination, AVATARS_SIZE) + await processImage(avatarPhysicalFile.path, destination, AVATARS_SIZE) + + return retryTransactionWrapper(() => { + return sequelizeTypescript.transaction(async t => { + const avatarInfo = { + name: avatarName, + fileUrl: null, + onDisk: true + } + + const updatedActor = await updateActorAvatarInstance(accountOrChannel.Actor, avatarInfo, t) + await updatedActor.save({ transaction: t }) + + await sendUpdateActor(accountOrChannel, t) - return sequelizeTypescript.transaction(async t => { - const updatedActor = await updateActorAvatarInstance(actor, avatarName, t) - await updatedActor.save({ transaction: t }) + return updatedActor.Avatar + }) + }) +} + +async function deleteLocalActorAvatarFile ( + accountOrChannel: MAccountDefault | MChannelDefault +) { + return retryTransactionWrapper(() => { + return sequelizeTypescript.transaction(async t => { + const updatedActor = await deleteActorAvatarInstance(accountOrChannel.Actor, t) + await updatedActor.save({ transaction: t }) - await sendUpdateActor(accountOrChannel, t) + await sendUpdateActor(accountOrChannel, t) - return updatedActor.Avatar + return updatedActor.Avatar + }) }) } +type DownloadImageQueueTask = { fileUrl: string, filename: string } + +const downloadImageQueue = queue((task, cb) => { + downloadImage(task.fileUrl, CONFIG.STORAGE.AVATARS_DIR, task.filename, AVATARS_SIZE) + .then(() => cb()) + .catch(err => cb(err)) +}, QUEUE_CONCURRENCY.AVATAR_PROCESS_IMAGE) + +function pushAvatarProcessInQueue (task: DownloadImageQueueTask) { + return new Promise((res, rej) => { + downloadImageQueue.push(task, err => { + if (err) return rej(err) + + return res() + }) + }) +} + +// Unsafe so could returns paths that does not exist anymore +const avatarPathUnsafeCache = new LRUCache({ max: LRU_CACHE.AVATAR_STATIC.MAX_SIZE }) + export { - updateActorAvatarFile + avatarPathUnsafeCache, + updateLocalActorAvatarFile, + deleteLocalActorAvatarFile, + pushAvatarProcessInQueue }