import * as uuidv4 from 'uuid/v4'
import * as RateLimit from 'express-rate-limit'
import { UserCreate, UserRight, UserRole, UserUpdate, UserUpdateMe, UserVideoRate as FormattedUserVideoRate } from '../../../shared'
-import { retryTransactionWrapper } from '../../helpers/database-utils'
import { processImage } from '../../helpers/image-utils'
import { logger } from '../../helpers/logger'
import { getFormattedObjects } from '../../helpers/utils'
import { createUserAccountAndChannel } from '../../lib/user'
import {
asyncMiddleware,
+ asyncRetryTransactionMiddleware,
authenticate,
ensureUserHasRight,
ensureUserRegistrationAllowed,
authenticate,
ensureUserHasRight(UserRight.MANAGE_USERS),
asyncMiddleware(usersAddValidator),
- asyncMiddleware(createUserRetryWrapper)
+ asyncRetryTransactionMiddleware(createUser)
)
usersRouter.post('/register',
asyncMiddleware(ensureUserRegistrationAllowed),
ensureUserRegistrationAllowedForIP,
asyncMiddleware(usersRegisterValidator),
- asyncMiddleware(registerUserRetryWrapper)
+ asyncRetryTransactionMiddleware(registerUser)
)
usersRouter.put('/me',
return res.json(getFormattedObjects(resultList.data, resultList.total, { additionalAttributes }))
}
-async function createUserRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
- const options = {
- arguments: [ req ],
- errorMessage: 'Cannot insert the user with many retries.'
- }
-
- const { user, account } = await retryTransactionWrapper(createUser, options)
-
- return res.json({
- user: {
- id: user.id,
- account: {
- id: account.id,
- uuid: account.Actor.uuid
- }
- }
- }).end()
-}
-
-async function createUser (req: express.Request) {
+async function createUser (req: express.Request, res: express.Response) {
const body: UserCreate = req.body
const userToCreate = new UserModel({
username: body.username,
logger.info('User %s with its channel and account created.', body.username)
- return { user, account }
-}
-
-async function registerUserRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
- const options = {
- arguments: [ req ],
- errorMessage: 'Cannot insert the user with many retries.'
- }
-
- await retryTransactionWrapper(registerUser, options)
-
- return res.type('json').status(204).end()
+ return res.json({
+ user: {
+ id: user.id,
+ account: {
+ id: account.id,
+ uuid: account.Actor.uuid
+ }
+ }
+ }).end()
}
-async function registerUser (req: express.Request) {
+async function registerUser (req: express.Request, res: express.Response) {
const body: UserCreate = req.body
const user = new UserModel({
await createUserAccountAndChannel(user)
logger.info('User %s with its channel and account registered.', body.username)
+
+ return res.type('json').status(204).end()
}
async function getUserInformation (req: express.Request, res: express.Response, next: express.NextFunction) {
import { getFormattedObjects, resetSequelizeInstance } from '../../helpers/utils'
import {
asyncMiddleware,
+ asyncRetryTransactionMiddleware,
authenticate,
optionalAuthenticate,
paginationValidator,
import { createVideoChannel } from '../../lib/video-channel'
import { isNSFWHidden } from '../../helpers/express-utils'
import { setAsyncActorKeys } from '../../lib/activitypub'
-import { retryTransactionWrapper } from '../../helpers/database-utils'
import { AccountModel } from '../../models/account/account'
import { sequelizeTypescript } from '../../initializers'
import { logger } from '../../helpers/logger'
videoChannelRouter.post('/',
authenticate,
videoChannelsAddValidator,
- asyncMiddleware(addVideoChannelRetryWrapper)
+ asyncRetryTransactionMiddleware(addVideoChannel)
)
videoChannelRouter.put('/:id',
authenticate,
asyncMiddleware(videoChannelsUpdateValidator),
- updateVideoChannelRetryWrapper
+ asyncRetryTransactionMiddleware(updateVideoChannel)
)
videoChannelRouter.delete('/:id',
authenticate,
asyncMiddleware(videoChannelsRemoveValidator),
- asyncMiddleware(removeVideoChannelRetryWrapper)
+ asyncRetryTransactionMiddleware(removeVideoChannel)
)
videoChannelRouter.get('/:id',
return res.json(getFormattedObjects(resultList.data, resultList.total))
}
-// Wrapper to video channel add that retry the async function if there is a database error
-// We need this because we run the transaction in SERIALIZABLE isolation that can fail
-async function addVideoChannelRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
- const options = {
- arguments: [ req, res ],
- errorMessage: 'Cannot insert the video video channel with many retries.'
- }
-
- const videoChannel = await retryTransactionWrapper(addVideoChannel, options)
- return res.json({
- videoChannel: {
- id: videoChannel.id,
- uuid: videoChannel.Actor.uuid
- }
- }).end()
-}
-
async function addVideoChannel (req: express.Request, res: express.Response) {
const videoChannelInfo: VideoChannelCreate = req.body
const account: AccountModel = res.locals.oauth.token.User.Account
logger.info('Video channel with uuid %s created.', videoChannelCreated.Actor.uuid)
- return videoChannelCreated
-}
-
-async function updateVideoChannelRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
- const options = {
- arguments: [ req, res ],
- errorMessage: 'Cannot update the video with many retries.'
- }
-
- await retryTransactionWrapper(updateVideoChannel, options)
-
- return res.type('json').status(204).end()
+ return res.json({
+ videoChannel: {
+ id: videoChannelCreated.id,
+ uuid: videoChannelCreated.Actor.uuid
+ }
+ }).end()
}
async function updateVideoChannel (req: express.Request, res: express.Response) {
throw err
}
-}
-
-async function removeVideoChannelRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
- const options = {
- arguments: [ req, res ],
- errorMessage: 'Cannot remove the video channel with many retries.'
- }
-
- await retryTransactionWrapper(removeVideoChannel, options)
return res.type('json').status(204).end()
}
async function removeVideoChannel (req: express.Request, res: express.Response) {
const videoChannelInstance: VideoChannelModel = res.locals.videoChannel
- return sequelizeTypescript.transaction(async t => {
+ await sequelizeTypescript.transaction(async t => {
await videoChannelInstance.destroy({ transaction: t })
logger.info('Video channel with name %s and uuid %s deleted.', videoChannelInstance.name, videoChannelInstance.Actor.uuid)
})
+ return res.type('json').status(204).end()
}
async function getVideoChannel (req: express.Request, res: express.Response, next: express.NextFunction) {
import * as express from 'express'
import { UserRight, VideoAbuseCreate } from '../../../../shared'
-import { retryTransactionWrapper } from '../../../helpers/database-utils'
import { logger } from '../../../helpers/logger'
import { getFormattedObjects } from '../../../helpers/utils'
import { sequelizeTypescript } from '../../../initializers'
import { sendVideoAbuse } from '../../../lib/activitypub/send'
import {
- asyncMiddleware, authenticate, ensureUserHasRight, paginationValidator, setDefaultSort, setDefaultPagination, videoAbuseReportValidator,
+ asyncMiddleware,
+ asyncRetryTransactionMiddleware,
+ authenticate,
+ ensureUserHasRight,
+ paginationValidator,
+ setDefaultPagination,
+ setDefaultSort,
+ videoAbuseReportValidator,
videoAbusesSortValidator
} from '../../../middlewares'
import { AccountModel } from '../../../models/account/account'
abuseVideoRouter.post('/:id/abuse',
authenticate,
asyncMiddleware(videoAbuseReportValidator),
- asyncMiddleware(reportVideoAbuseRetryWrapper)
+ asyncRetryTransactionMiddleware(reportVideoAbuse)
)
// ---------------------------------------------------------------------------
return res.json(getFormattedObjects(resultList.data, resultList.total))
}
-async function reportVideoAbuseRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
- const options = {
- arguments: [ req, res ],
- errorMessage: 'Cannot report abuse to the video with many retries.'
- }
-
- await retryTransactionWrapper(reportVideoAbuse, options)
-
- return res.type('json').status(204).end()
-}
-
async function reportVideoAbuse (req: express.Request, res: express.Response) {
const videoInstance = res.locals.video as VideoModel
const reporterAccount = res.locals.oauth.token.User.Account as AccountModel
})
logger.info('Abuse report for video %s created.', videoInstance.name)
+
+ return res.type('json').status(204).end()
}
import * as express from 'express'
import { ResultList } from '../../../../shared/models'
import { VideoCommentCreate } from '../../../../shared/models/videos/video-comment.model'
-import { retryTransactionWrapper } from '../../../helpers/database-utils'
import { logger } from '../../../helpers/logger'
import { getFormattedObjects } from '../../../helpers/utils'
import { sequelizeTypescript } from '../../../initializers'
import { buildFormattedCommentTree, createVideoComment } from '../../../lib/video-comment'
-import { asyncMiddleware, authenticate, paginationValidator, setDefaultSort, setDefaultPagination } from '../../../middlewares'
+import {
+ asyncMiddleware,
+ asyncRetryTransactionMiddleware,
+ authenticate,
+ paginationValidator,
+ setDefaultPagination,
+ setDefaultSort
+} from '../../../middlewares'
import { videoCommentThreadsSortValidator } from '../../../middlewares/validators'
import {
- addVideoCommentReplyValidator, addVideoCommentThreadValidator, listVideoCommentThreadsValidator, listVideoThreadCommentsValidator,
+ addVideoCommentReplyValidator,
+ addVideoCommentThreadValidator,
+ listVideoCommentThreadsValidator,
+ listVideoThreadCommentsValidator,
removeVideoCommentValidator
} from '../../../middlewares/validators/video-comments'
import { VideoModel } from '../../../models/video/video'
videoCommentRouter.post('/:videoId/comment-threads',
authenticate,
asyncMiddleware(addVideoCommentThreadValidator),
- asyncMiddleware(addVideoCommentThreadRetryWrapper)
+ asyncRetryTransactionMiddleware(addVideoCommentThread)
)
videoCommentRouter.post('/:videoId/comments/:commentId',
authenticate,
asyncMiddleware(addVideoCommentReplyValidator),
- asyncMiddleware(addVideoCommentReplyRetryWrapper)
+ asyncRetryTransactionMiddleware(addVideoCommentReply)
)
videoCommentRouter.delete('/:videoId/comments/:commentId',
authenticate,
asyncMiddleware(removeVideoCommentValidator),
- asyncMiddleware(removeVideoCommentRetryWrapper)
+ asyncRetryTransactionMiddleware(removeVideoComment)
)
// ---------------------------------------------------------------------------
return res.json(buildFormattedCommentTree(resultList))
}
-async function addVideoCommentThreadRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
- const options = {
- arguments: [ req, res ],
- errorMessage: 'Cannot insert the video comment thread with many retries.'
- }
-
- const comment = await retryTransactionWrapper(addVideoCommentThread, options)
-
- res.json({
- comment: comment.toFormattedJSON()
- }).end()
-}
-
-function addVideoCommentThread (req: express.Request, res: express.Response) {
+async function addVideoCommentThread (req: express.Request, res: express.Response) {
const videoCommentInfo: VideoCommentCreate = req.body
- return sequelizeTypescript.transaction(async t => {
+ const comment = await sequelizeTypescript.transaction(async t => {
return createVideoComment({
text: videoCommentInfo.text,
inReplyToComment: null,
account: res.locals.oauth.token.User.Account
}, t)
})
-}
-async function addVideoCommentReplyRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
- const options = {
- arguments: [ req, res ],
- errorMessage: 'Cannot insert the video comment reply with many retries.'
- }
-
- const comment = await retryTransactionWrapper(addVideoCommentReply, options)
-
- res.json({
+ return res.json({
comment: comment.toFormattedJSON()
}).end()
}
-function addVideoCommentReply (req: express.Request, res: express.Response, next: express.NextFunction) {
+async function addVideoCommentReply (req: express.Request, res: express.Response) {
const videoCommentInfo: VideoCommentCreate = req.body
- return sequelizeTypescript.transaction(async t => {
+ const comment = await sequelizeTypescript.transaction(async t => {
return createVideoComment({
text: videoCommentInfo.text,
inReplyToComment: res.locals.videoComment,
account: res.locals.oauth.token.User.Account
}, t)
})
-}
-
-async function removeVideoCommentRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
- const options = {
- arguments: [ req, res ],
- errorMessage: 'Cannot remove the video comment with many retries.'
- }
- await retryTransactionWrapper(removeVideoComment, options)
-
- return res.type('json').status(204).end()
+ return res.json({
+ comment: comment.toFormattedJSON()
+ }).end()
}
async function removeVideoComment (req: express.Request, res: express.Response) {
})
logger.info('Video comment %d deleted.', videoCommentInstance.id)
+
+ return res.type('json').status(204).end()
}
import { extname, join } from 'path'
import { VideoCreate, VideoPrivacy, VideoState, VideoUpdate } from '../../../../shared'
import { renamePromise } from '../../../helpers/core-utils'
-import { retryTransactionWrapper } from '../../../helpers/database-utils'
import { getVideoFileResolution } from '../../../helpers/ffmpeg-utils'
import { processImage } from '../../../helpers/image-utils'
import { logger } from '../../../helpers/logger'
import { Redis } from '../../../lib/redis'
import {
asyncMiddleware,
+ asyncRetryTransactionMiddleware,
authenticate,
optionalAuthenticate,
paginationValidator,
authenticate,
reqVideoFileUpdate,
asyncMiddleware(videosUpdateValidator),
- asyncMiddleware(updateVideoRetryWrapper)
+ asyncRetryTransactionMiddleware(updateVideo)
)
videosRouter.post('/upload',
authenticate,
reqVideoFileAdd,
asyncMiddleware(videosAddValidator),
- asyncMiddleware(addVideoRetryWrapper)
+ asyncRetryTransactionMiddleware(addVideo)
)
videosRouter.get('/:id/description',
videosRouter.delete('/:id',
authenticate,
asyncMiddleware(videosRemoveValidator),
- asyncMiddleware(removeVideoRetryWrapper)
+ asyncRetryTransactionMiddleware(removeVideo)
)
// ---------------------------------------------------------------------------
res.json(VIDEO_PRIVACIES)
}
-// Wrapper to video add that retry the function if there is a database error
-// We need this because we run the transaction in SERIALIZABLE isolation that can fail
-async function addVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
- const options = {
- arguments: [ req, res, req.files['videofile'][0] ],
- errorMessage: 'Cannot insert the video with many retries.'
- }
-
- const video = await retryTransactionWrapper(addVideo, options)
-
- res.json({
- video: {
- id: video.id,
- uuid: video.uuid
- }
- }).end()
-}
-
-async function addVideo (req: express.Request, res: express.Response, videoPhysicalFile: Express.Multer.File) {
+async function addVideo (req: express.Request, res: express.Response) {
+ const videoPhysicalFile = req.files['videofile'][0]
const videoInfo: VideoCreate = req.body
// Prepare data so we don't block the transaction
await JobQueue.Instance.createJob({ type: 'video-file', payload: dataInput })
}
- return videoCreated
-}
-
-async function updateVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
- const options = {
- arguments: [ req, res ],
- errorMessage: 'Cannot update the video with many retries.'
- }
-
- await retryTransactionWrapper(updateVideo, options)
-
- return res.type('json').status(204).end()
+ return res.json({
+ video: {
+ id: videoCreated.id,
+ uuid: videoCreated.uuid
+ }
+ }).end()
}
async function updateVideo (req: express.Request, res: express.Response) {
throw err
}
+
+ return res.type('json').status(204).end()
}
function getVideo (req: express.Request, res: express.Response) {
return res.json(getFormattedObjects(resultList.data, resultList.total))
}
-async function removeVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
- const options = {
- arguments: [ req, res ],
- errorMessage: 'Cannot remove the video with many retries.'
- }
-
- await retryTransactionWrapper(removeVideo, options)
-
- return res.type('json').status(204).end()
-}
-
async function removeVideo (req: express.Request, res: express.Response) {
const videoInstance: VideoModel = res.locals.video
})
logger.info('Video with name %s and uuid %s deleted.', videoInstance.name, videoInstance.uuid)
+
+ return res.type('json').status(204).end()
}
async function searchVideos (req: express.Request, res: express.Response, next: express.NextFunction) {
import * as express from 'express'
import { UserVideoRateUpdate } from '../../../../shared'
-import { retryTransactionWrapper } from '../../../helpers/database-utils'
import { logger } from '../../../helpers/logger'
import { sequelizeTypescript, VIDEO_RATE_TYPES } from '../../../initializers'
import { sendVideoRateChange } from '../../../lib/activitypub'
-import { asyncMiddleware, authenticate, videoRateValidator } from '../../../middlewares'
+import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate, videoRateValidator } from '../../../middlewares'
import { AccountModel } from '../../../models/account/account'
import { AccountVideoRateModel } from '../../../models/account/account-video-rate'
import { VideoModel } from '../../../models/video/video'
rateVideoRouter.put('/:id/rate',
authenticate,
asyncMiddleware(videoRateValidator),
- asyncMiddleware(rateVideoRetryWrapper)
+ asyncRetryTransactionMiddleware(rateVideo)
)
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
-async function rateVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
- const options = {
- arguments: [ req, res ],
- errorMessage: 'Cannot update the user video rate.'
- }
-
- await retryTransactionWrapper(rateVideo, options)
-
- return res.type('json').status(204).end()
-}
-
async function rateVideo (req: express.Request, res: express.Response) {
const body: UserVideoRateUpdate = req.body
const rateType = body.rating
})
logger.info('Account video rate for video %s of account %s updated.', videoInstance.name, accountInstance.name)
+
+ return res.type('json').status(204).end()
}
import { Model } from 'sequelize-typescript'
import { logger } from './logger'
-type RetryTransactionWrapperOptions = { errorMessage: string, arguments?: any[] }
+function retryTransactionWrapper <T, A, B, C> (
+ functionToRetry: (arg1: A, arg2: B, arg3: C) => Promise<T> | Bluebird<T>,
+ arg1: A,
+ arg2: B,
+ arg3: C
+): Promise<T>
+
+function retryTransactionWrapper <T, A, B> (
+ functionToRetry: (arg1: A, arg2: B) => Promise<T> | Bluebird<T>,
+ arg1: A,
+ arg2: B
+): Promise<T>
+
+function retryTransactionWrapper <T, A> (
+ functionToRetry: (arg1: A) => Promise<T> | Bluebird<T>,
+ arg1: A
+): Promise<T>
+
function retryTransactionWrapper <T> (
- functionToRetry: (...args) => Promise<T> | Bluebird<T>,
- options: RetryTransactionWrapperOptions
+ functionToRetry: (...args: any[]) => Promise<T> | Bluebird<T>,
+ ...args: any[]
): Promise<T> {
- const args = options.arguments ? options.arguments : []
-
return transactionRetryer<T>(callback => {
functionToRetry.apply(this, args)
.then((result: T) => callback(null, result))
.catch(err => callback(err))
})
.catch(err => {
- logger.error(options.errorMessage, { err })
+ logger.error('Cannot execute %s with many retries.', functionToRetry.toString(), { err })
throw err
})
}
function transactionRetryer <T> (func: (err: any, data: T) => any) {
return new Promise<T>((res, rej) => {
- retry({
- times: 5,
-
- errorFilter: err => {
- const willRetry = (err.name === 'SequelizeDatabaseError')
- logger.debug('Maybe retrying the transaction function.', { willRetry, err })
- return willRetry
- }
- }, func, (err, data) => err ? rej(err) : res(data))
+ retry(
+ {
+ times: 5,
+
+ errorFilter: err => {
+ const willRetry = (err.name === 'SequelizeDatabaseError')
+ logger.debug('Maybe retrying the transaction function.', { willRetry, err })
+ return willRetry
+ }
+ },
+ func,
+ (err, data) => err ? rej(err) : res(data)
+ )
})
}
}
}
- const options = {
- arguments: [ result, ownerActor ],
- errorMessage: 'Cannot save actor and server with many retries.'
- }
- actor = await retryTransactionWrapper(saveActorAndServerAndModelIfNotExist, options)
+ actor = await retryTransactionWrapper(saveActorAndServerAndModelIfNotExist, result, ownerActor)
}
- const options = {
- arguments: [ actor ],
- errorMessage: 'Cannot refresh actor if needed with many retries.'
- }
- return retryTransactionWrapper(refreshActorIfNeeded, options)
+ return retryTransactionWrapper(refreshActorIfNeeded, actor)
}
function buildActorInstance (type: ActivityPubActorType, url: string, preferredUsername: string, uuid?: string) {
async function processAnnounceActivity (activity: ActivityAnnounce) {
const actorAnnouncer = await getOrCreateActorAndServerAndModel(activity.actor)
- return processVideoShare(actorAnnouncer, activity)
+ return retryTransactionWrapper(processVideoShare, actorAnnouncer, activity)
}
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
-function processVideoShare (actorAnnouncer: ActorModel, activity: ActivityAnnounce) {
- const options = {
- arguments: [ actorAnnouncer, activity ],
- errorMessage: 'Cannot share the video activity with many retries.'
- }
-
- return retryTransactionWrapper(shareVideo, options)
-}
-
-async function shareVideo (actorAnnouncer: ActorModel, activity: ActivityAnnounce) {
+async function processVideoShare (actorAnnouncer: ActorModel, activity: ActivityAnnounce) {
const objectUri = typeof activity.object === 'string' ? activity.object : activity.object.id
let video: VideoModel
if (activityType === 'View') {
return processCreateView(actor, activity)
} else if (activityType === 'Dislike') {
- return processCreateDislike(actor, activity)
+ return retryTransactionWrapper(processCreateDislike, actor, activity)
} else if (activityType === 'Video') {
return processCreateVideo(actor, activity)
} else if (activityType === 'Flag') {
- return processCreateVideoAbuse(actor, activityObject as VideoAbuseObject)
+ return retryTransactionWrapper(processCreateVideoAbuse, actor, activityObject as VideoAbuseObject)
} else if (activityType === 'Note') {
- return processCreateVideoComment(actor, activity)
+ return retryTransactionWrapper(processCreateVideoComment, actor, activity)
}
logger.warn('Unknown activity object type %s when creating activity.', activityType, { activity: activity.id })
}
async function processCreateDislike (byActor: ActorModel, activity: ActivityCreate) {
- const options = {
- arguments: [ byActor, activity ],
- errorMessage: 'Cannot dislike the video with many retries.'
- }
-
- return retryTransactionWrapper(createVideoDislike, options)
-}
-
-async function createVideoDislike (byActor: ActorModel, activity: ActivityCreate) {
const dislike = activity.object as DislikeObject
const byAccount = byActor.Account
}
}
-function processCreateVideoAbuse (actor: ActorModel, videoAbuseToCreateData: VideoAbuseObject) {
- const options = {
- arguments: [ actor, videoAbuseToCreateData ],
- errorMessage: 'Cannot insert the remote video abuse with many retries.'
- }
-
- return retryTransactionWrapper(addRemoteVideoAbuse, options)
-}
-
-async function addRemoteVideoAbuse (actor: ActorModel, videoAbuseToCreateData: VideoAbuseObject) {
+async function processCreateVideoAbuse (actor: ActorModel, videoAbuseToCreateData: VideoAbuseObject) {
logger.debug('Reporting remote abuse for video %s.', videoAbuseToCreateData.object)
const account = actor.Account
})
}
-function processCreateVideoComment (byActor: ActorModel, activity: ActivityCreate) {
- const options = {
- arguments: [ byActor, activity ],
- errorMessage: 'Cannot create video comment with many retries.'
- }
-
- return retryTransactionWrapper(createVideoComment, options)
-}
-
-async function createVideoComment (byActor: ActorModel, activity: ActivityCreate) {
+async function processCreateVideoComment (byActor: ActorModel, activity: ActivityCreate) {
const comment = activity.object as VideoCommentObject
const byAccount = byActor.Account
if (!actor.Account) throw new Error('Actor ' + actor.url + ' is a person but we cannot find it in database.')
actor.Account.Actor = await actor.Account.$get('Actor') as ActorModel
- return processDeleteAccount(actor.Account)
+ return retryTransactionWrapper(processDeleteAccount, actor.Account)
} else if (actor.type === 'Group') {
if (!actor.VideoChannel) throw new Error('Actor ' + actor.url + ' is a group but we cannot find it in database.')
actor.VideoChannel.Actor = await actor.VideoChannel.$get('Actor') as ActorModel
- return processDeleteVideoChannel(actor.VideoChannel)
+ return retryTransactionWrapper(processDeleteVideoChannel, actor.VideoChannel)
}
}
{
const videoCommentInstance = await VideoCommentModel.loadByUrlAndPopulateAccount(objectUrl)
if (videoCommentInstance) {
- return processDeleteVideoComment(actor, videoCommentInstance, activity)
+ return retryTransactionWrapper(processDeleteVideoComment, actor, videoCommentInstance, activity)
}
}
{
const videoInstance = await VideoModel.loadByUrlAndPopulateAccount(objectUrl)
if (videoInstance) {
- return processDeleteVideo(actor, videoInstance)
+ return retryTransactionWrapper(processDeleteVideo, actor, videoInstance)
}
}
// ---------------------------------------------------------------------------
async function processDeleteVideo (actor: ActorModel, videoToDelete: VideoModel) {
- const options = {
- arguments: [ actor, videoToDelete ],
- errorMessage: 'Cannot remove the remote video with many retries.'
- }
-
- await retryTransactionWrapper(deleteRemoteVideo, options)
-}
-
-async function deleteRemoteVideo (actor: ActorModel, videoToDelete: VideoModel) {
logger.debug('Removing remote video "%s".', videoToDelete.uuid)
await sequelizeTypescript.transaction(async t => {
}
async function processDeleteAccount (accountToRemove: AccountModel) {
- const options = {
- arguments: [ accountToRemove ],
- errorMessage: 'Cannot remove the remote account with many retries.'
- }
-
- await retryTransactionWrapper(deleteRemoteAccount, options)
-}
-
-async function deleteRemoteAccount (accountToRemove: AccountModel) {
logger.debug('Removing remote account "%s".', accountToRemove.Actor.uuid)
await sequelizeTypescript.transaction(async t => {
}
async function processDeleteVideoChannel (videoChannelToRemove: VideoChannelModel) {
- const options = {
- arguments: [ videoChannelToRemove ],
- errorMessage: 'Cannot remove the remote video channel with many retries.'
- }
-
- await retryTransactionWrapper(deleteRemoteVideoChannel, options)
-}
-
-async function deleteRemoteVideoChannel (videoChannelToRemove: VideoChannelModel) {
logger.debug('Removing remote video channel "%s".', videoChannelToRemove.Actor.uuid)
await sequelizeTypescript.transaction(async t => {
logger.info('Remote video channel with uuid %s removed.', videoChannelToRemove.Actor.uuid)
}
-async function processDeleteVideoComment (byActor: ActorModel, videoComment: VideoCommentModel, activity: ActivityDelete) {
- const options = {
- arguments: [ byActor, videoComment, activity ],
- errorMessage: 'Cannot remove the remote video comment with many retries.'
- }
-
- await retryTransactionWrapper(deleteRemoteVideoComment, options)
-}
-
-function deleteRemoteVideoComment (byActor: ActorModel, videoComment: VideoCommentModel, activity: ActivityDelete) {
+function processDeleteVideoComment (byActor: ActorModel, videoComment: VideoCommentModel, activity: ActivityDelete) {
logger.debug('Removing remote video comment "%s".', videoComment.url)
return sequelizeTypescript.transaction(async t => {
const activityObject = activity.object
const actor = await getOrCreateActorAndServerAndModel(activity.actor)
- return processFollow(actor, activityObject)
+ return retryTransactionWrapper(processFollow, actor, activityObject)
}
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
-function processFollow (actor: ActorModel, targetActorURL: string) {
- const options = {
- arguments: [ actor, targetActorURL ],
- errorMessage: 'Cannot follow with many retries.'
- }
-
- return retryTransactionWrapper(follow, options)
-}
-
-async function follow (actor: ActorModel, targetActorURL: string) {
+async function processFollow (actor: ActorModel, targetActorURL: string) {
await sequelizeTypescript.transaction(async t => {
const targetActor = await ActorModel.loadByUrl(targetActorURL, t)
import { AccountVideoRateModel } from '../../../models/account/account-video-rate'
import { ActorModel } from '../../../models/activitypub/actor'
import { getOrCreateActorAndServerAndModel } from '../actor'
-import { forwardActivity, forwardVideoRelatedActivity } from '../send/utils'
+import { forwardVideoRelatedActivity } from '../send/utils'
import { getOrCreateAccountAndVideoAndChannel } from '../videos'
-import { getActorsInvolvedInVideo } from '../audience'
async function processLikeActivity (activity: ActivityLike) {
const actor = await getOrCreateActorAndServerAndModel(activity.actor)
- return processLikeVideo(actor, activity)
+ return retryTransactionWrapper(processLikeVideo, actor, activity)
}
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
-async function processLikeVideo (actor: ActorModel, activity: ActivityLike) {
- const options = {
- arguments: [ actor, activity ],
- errorMessage: 'Cannot like the video with many retries.'
- }
-
- return retryTransactionWrapper(createVideoLike, options)
-}
-
-async function createVideoLike (byActor: ActorModel, activity: ActivityLike) {
+async function processLikeVideo (byActor: ActorModel, activity: ActivityLike) {
const videoUrl = activity.object
const byAccount = byActor.Account
const actorUrl = getActorUrl(activity.actor)
if (activityToUndo.type === 'Like') {
- return processUndoLike(actorUrl, activity)
+ return retryTransactionWrapper(processUndoLike, actorUrl, activity)
} else if (activityToUndo.type === 'Create' && activityToUndo.object.type === 'Dislike') {
- return processUndoDislike(actorUrl, activity)
+ return retryTransactionWrapper(processUndoDislike, actorUrl, activity)
} else if (activityToUndo.type === 'Follow') {
- return processUndoFollow(actorUrl, activityToUndo)
+ return retryTransactionWrapper(processUndoFollow, actorUrl, activityToUndo)
} else if (activityToUndo.type === 'Announce') {
- return processUndoAnnounce(actorUrl, activityToUndo)
+ return retryTransactionWrapper(processUndoAnnounce, actorUrl, activityToUndo)
}
logger.warn('Unknown activity object type %s -> %s when undo activity.', activityToUndo.type, { activity: activity.id })
// ---------------------------------------------------------------------------
-function processUndoLike (actorUrl: string, activity: ActivityUndo) {
- const options = {
- arguments: [ actorUrl, activity ],
- errorMessage: 'Cannot undo like with many retries.'
- }
-
- return retryTransactionWrapper(undoLike, options)
-}
-
-async function undoLike (actorUrl: string, activity: ActivityUndo) {
+async function processUndoLike (actorUrl: string, activity: ActivityUndo) {
const likeActivity = activity.object as ActivityLike
const { video } = await getOrCreateAccountAndVideoAndChannel(likeActivity.object)
})
}
-function processUndoDislike (actorUrl: string, activity: ActivityUndo) {
- const options = {
- arguments: [ actorUrl, activity ],
- errorMessage: 'Cannot undo dislike with many retries.'
- }
-
- return retryTransactionWrapper(undoDislike, options)
-}
-
-async function undoDislike (actorUrl: string, activity: ActivityUndo) {
+async function processUndoDislike (actorUrl: string, activity: ActivityUndo) {
const dislike = activity.object.object as DislikeObject
const { video } = await getOrCreateAccountAndVideoAndChannel(dislike.object)
}
function processUndoFollow (actorUrl: string, followActivity: ActivityFollow) {
- const options = {
- arguments: [ actorUrl, followActivity ],
- errorMessage: 'Cannot undo follow with many retries.'
- }
-
- return retryTransactionWrapper(undoFollow, options)
-}
-
-function undoFollow (actorUrl: string, followActivity: ActivityFollow) {
return sequelizeTypescript.transaction(async t => {
const follower = await ActorModel.loadByUrl(actorUrl, t)
const following = await ActorModel.loadByUrl(followActivity.object, t)
}
function processUndoAnnounce (actorUrl: string, announceActivity: ActivityAnnounce) {
- const options = {
- arguments: [ actorUrl, announceActivity ],
- errorMessage: 'Cannot undo announce with many retries.'
- }
-
- return retryTransactionWrapper(undoAnnounce, options)
-}
-
-function undoAnnounce (actorUrl: string, announceActivity: ActivityAnnounce) {
return sequelizeTypescript.transaction(async t => {
const byAccount = await AccountModel.loadByUrl(actorUrl, t)
if (!byAccount) throw new Error('Unknown account ' + actorUrl)
const objectType = activity.object.type
if (objectType === 'Video') {
- return processUpdateVideo(actor, activity)
+ return retryTransactionWrapper(processUpdateVideo, actor, activity)
} else if (objectType === 'Person' || objectType === 'Application' || objectType === 'Group') {
- return processUpdateActor(actor, activity)
+ return retryTransactionWrapper(processUpdateActor, actor, activity)
}
return undefined
// ---------------------------------------------------------------------------
-function processUpdateVideo (actor: ActorModel, activity: ActivityUpdate) {
- const options = {
- arguments: [ actor, activity ],
- errorMessage: 'Cannot update the remote video with many retries'
- }
-
- return retryTransactionWrapper(updateRemoteVideo, options)
-}
-
-async function updateRemoteVideo (actor: ActorModel, activity: ActivityUpdate) {
+async function processUpdateVideo (actor: ActorModel, activity: ActivityUpdate) {
const videoObject = activity.object as VideoTorrentObject
if (sanitizeAndCheckVideoTorrentObject(videoObject) === false) {
}
}
-function processUpdateActor (actor: ActorModel, activity: ActivityUpdate) {
- const options = {
- arguments: [ actor, activity ],
- errorMessage: 'Cannot update the remote actor with many retries'
- }
-
- return retryTransactionWrapper(updateRemoteActor, options)
-}
-
-async function updateRemoteActor (actor: ActorModel, activity: ActivityUpdate) {
+async function processUpdateActor (actor: ActorModel, activity: ActivityUpdate) {
const actorAttributesToUpdate = activity.object as ActivityPubActor
logger.debug('Updating remote account "%s".', actorAttributesToUpdate.uuid)
const channelActor = await getOrCreateVideoChannel(videoObject)
- const options = {
- arguments: [ videoObject, channelActor ],
- errorMessage: 'Cannot insert the remote video with many retries.'
- }
-
- const video = await retryTransactionWrapper(getOrCreateVideo, options)
+ const video = await retryTransactionWrapper(getOrCreateVideo, videoObject, channelActor)
// Process outside the transaction because we could fetch remote data
logger.info('Adding likes of video %s.', video.uuid)
const targetActor = await getOrCreateActorAndServerAndModel(actorUrl)
const fromActor = await getServerActor()
- const options = {
- arguments: [ fromActor, targetActor ],
- errorMessage: 'Cannot follow with many retries.'
- }
- return retryTransactionWrapper(follow, options)
+ return retryTransactionWrapper(follow, fromActor, targetActor)
}
// ---------------------------------------------------------------------------
if (payload.resolution) {
await video.transcodeOriginalVideofile(payload.resolution, payload.isPortraitMode)
- const options = {
- arguments: [ video ],
- errorMessage: 'Cannot execute onVideoFileTranscoderOrImportSuccess with many retries.'
- }
- await retryTransactionWrapper(onVideoFileTranscoderOrImportSuccess, options)
+ await retryTransactionWrapper(onVideoFileTranscoderOrImportSuccess, video)
} else {
await video.optimizeOriginalVideofile()
- const options = {
- arguments: [ video, payload.isNewVideo ],
- errorMessage: 'Cannot execute onVideoFileOptimizerSuccess with many retries.'
- }
- await retryTransactionWrapper(onVideoFileOptimizerSuccess, options)
+ await retryTransactionWrapper(onVideoFileOptimizerSuccess, video, payload.isNewVideo)
}
return video
import { eachSeries } from 'async'
import { NextFunction, Request, RequestHandler, Response } from 'express'
+import { retryTransactionWrapper } from '../helpers/database-utils'
// Syntactic sugar to avoid try/catch in express controllers
// Thanks: https://medium.com/@Abazhenov/using-async-await-in-express-with-node-8-b8af872c0016
}
}
+function asyncRetryTransactionMiddleware (fun: RequestPromiseHandler) {
+ return (req: Request, res: Response, next: NextFunction) => {
+ return Promise.resolve(
+ retryTransactionWrapper(fun, req, res, next)
+ ).catch(err => next(err))
+ }
+}
+
// ---------------------------------------------------------------------------
export {
- asyncMiddleware
+ asyncMiddleware,
+ asyncRetryTransactionMiddleware
}