Make it compile at least
authorChocobozzz <florian.bigard@gmail.com>
Fri, 10 Nov 2017 16:27:49 +0000 (17:27 +0100)
committerChocobozzz <florian.bigard@gmail.com>
Mon, 27 Nov 2017 18:40:51 +0000 (19:40 +0100)
53 files changed:
package.json
scripts/update-host.ts
server.ts
server/controllers/activitypub/index.ts
server/controllers/api/index.ts
server/controllers/api/pods.ts
server/controllers/api/request-schedulers.ts [deleted file]
server/controllers/api/users.ts
server/controllers/api/videos/abuse.ts
server/controllers/api/videos/channel.ts
server/controllers/api/videos/index.ts
server/controllers/api/videos/rate.ts
server/helpers/activitypub.ts
server/helpers/requests.ts
server/helpers/webfinger.ts
server/initializers/constants.ts
server/initializers/database.ts
server/initializers/installer.ts
server/initializers/migrations/0075-video-resolutions.ts
server/lib/activitypub/index.ts
server/lib/activitypub/misc.ts
server/lib/activitypub/process-flag.ts
server/lib/activitypub/send-request.ts
server/lib/cache/videos-preview-cache.ts
server/lib/index.ts
server/lib/jobs/http-request-job-scheduler/http-request-broadcast-handler.ts
server/lib/jobs/http-request-job-scheduler/http-request-job-scheduler.ts
server/lib/jobs/http-request-job-scheduler/http-request-unicast-handler.ts
server/lib/jobs/job-scheduler.ts
server/lib/jobs/transcoding-job-scheduler/transcoding-job-scheduler.ts
server/lib/jobs/transcoding-job-scheduler/video-file-optimizer-handler.ts
server/lib/jobs/transcoding-job-scheduler/video-file-transcoder-handler.ts
server/lib/request/abstract-request-scheduler.ts [deleted file]
server/lib/request/index.ts [deleted file]
server/lib/request/request-scheduler.ts [deleted file]
server/lib/request/request-video-event-scheduler.ts [deleted file]
server/lib/request/request-video-qadu-scheduler.ts [deleted file]
server/lib/user.ts
server/lib/video-channel.ts
server/middlewares/validators/activitypub/index.ts
server/middlewares/validators/activitypub/pods.ts [deleted file]
server/middlewares/validators/index.ts
server/middlewares/validators/pods.ts [deleted file]
server/models/account/account-interface.ts
server/models/account/account.ts
server/models/job/job-interface.ts
server/models/video/video-channel.ts
server/models/video/video.ts
server/tests/api/video-channels.ts
shared/models/activitypub/activity.ts
shared/models/pods/pod.model.ts
shared/models/users/user.model.ts
yarn.lock

index a49b4d800702529c9f356831dda0eb61fe94e857..68df1cb9bbd2f82d23395ce054ed7b0635fd2991 100644 (file)
@@ -77,7 +77,6 @@
     "pg": "^6.4.2",
     "pg-hstore": "^2.3.2",
     "request": "^2.81.0",
-    "request-replay": "^1.0.2",
     "rimraf": "^2.5.4",
     "safe-buffer": "^5.0.1",
     "scripty": "^1.5.0",
index 06d84a658ca416107372efec502ac8424b62525c..7c46dc52b17d0f3a6a76864262680fea6c6e6605 100755 (executable)
@@ -1,11 +1,11 @@
-import * as Promise from 'bluebird'
-
 import { database as db } from '../server/initializers/database'
-import { hasFriends } from '../server/lib/friends'
+// import { hasFriends } from '../server/lib/friends'
 
 db.init(true)
   .then(() => {
-    return hasFriends()
+    // FIXME: check if has followers
+    // return hasFriends()
+    return true
   })
   .then(itHasFriends => {
     if (itHasFriends === true) {
index f50e5bad4b77c9a6c655e129f9a206b3b35123d4..0878fe757e8af06c96f2723c59524bb7c197cc9f 100644 (file)
--- a/server.ts
+++ b/server.ts
@@ -46,7 +46,7 @@ db.init(false).then(() => onDatabaseInitDone())
 
 // ----------- PeerTube modules -----------
 import { migrate, installApplication } from './server/initializers'
-import { JobScheduler, activateSchedulers, VideosPreviewCache } from './server/lib'
+import { httpRequestJobScheduler, transcodingJobScheduler, VideosPreviewCache } from './server/lib'
 import { apiRouter, clientsRouter, staticRouter, servicesRouter } from './server/controllers'
 
 // ----------- Command line -----------
@@ -146,19 +146,13 @@ function onDatabaseInitDone () {
   const port = CONFIG.LISTEN.PORT
     // Run the migration scripts if needed
   migrate()
-    .then(() => {
-      return installApplication()
-    })
+    .then(() => installApplication())
     .then(() => {
       // ----------- Make the server listening -----------
-      server.listen(port, function () {
-        // Activate the communication with friends
-        activateSchedulers()
-
-        // Activate job scheduler
-        JobScheduler.Instance.activate()
-
+      server.listen(port, () => {
         VideosPreviewCache.Instance.init(CONFIG.CACHE.PREVIEWS.SIZE)
+        httpRequestJobScheduler.activate()
+        transcodingJobScheduler.activate()
 
         logger.info('Server listening on port %d', port)
         logger.info('Web server: %s', CONFIG.WEBSERVER.URL)
index 7a4602b377b743d43df58bf795430ae2f565ea22..2b0e2a4896234ff969117973b4536eba673fc113 100644 (file)
@@ -2,10 +2,12 @@ import * as express from 'express'
 
 import { badRequest } from '../../helpers'
 import { inboxRouter } from './inbox'
+import { activityPubClientRouter } from './client'
 
 const remoteRouter = express.Router()
 
 remoteRouter.use('/inbox', inboxRouter)
+remoteRouter.use('/', activityPubClientRouter)
 remoteRouter.use('/*', badRequest)
 
 // ---------------------------------------------------------------------------
index a9205b33c6581a9dabfb089bde2a270b9dd23b2a..2e949d5319370de13a124196d41d49ae16bb7427 100644 (file)
@@ -5,8 +5,6 @@ import { badRequest } from '../../helpers'
 import { oauthClientsRouter } from './oauth-clients'
 import { configRouter } from './config'
 import { podsRouter } from './pods'
-import { remoteRouter } from './remote'
-import { requestSchedulerRouter } from './request-schedulers'
 import { usersRouter } from './users'
 import { videosRouter } from './videos'
 
@@ -15,8 +13,6 @@ const apiRouter = express.Router()
 apiRouter.use('/oauth-clients', oauthClientsRouter)
 apiRouter.use('/config', configRouter)
 apiRouter.use('/pods', podsRouter)
-apiRouter.use('/remote', remoteRouter)
-apiRouter.use('/request-schedulers', requestSchedulerRouter)
 apiRouter.use('/users', usersRouter)
 apiRouter.use('/videos', videosRouter)
 apiRouter.use('/ping', pong)
index b44cd6b8301d7945fed201704924b656c4433186..43df3f66f3b79e21d225e3f306f1239f85de8423 100644 (file)
@@ -1,26 +1,7 @@
 import * as express from 'express'
-
+import { getFormattedObjects } from '../../helpers'
 import { database as db } from '../../initializers/database'
-import { logger, getFormattedObjects } from '../../helpers'
-import {
-  makeFriends,
-  quitFriends,
-  removeFriend
-} from '../../lib'
-import {
-  authenticate,
-  ensureUserHasRight,
-  makeFriendsValidator,
-  setBodyHostsPort,
-  podRemoveValidator,
-  paginationValidator,
-  setPagination,
-  setPodsSort,
-  podsSortValidator,
-  asyncMiddleware
-} from '../../middlewares'
-import { PodInstance } from '../../models'
-import { UserRight } from '../../../shared'
+import { asyncMiddleware, paginationValidator, podsSortValidator, setPagination, setPodsSort } from '../../middlewares'
 
 const podsRouter = express.Router()
 
@@ -31,24 +12,6 @@ podsRouter.get('/',
   setPagination,
   asyncMiddleware(listPods)
 )
-podsRouter.post('/make-friends',
-  authenticate,
-  ensureUserHasRight(UserRight.MANAGE_PODS),
-  makeFriendsValidator,
-  setBodyHostsPort,
-  asyncMiddleware(makeFriendsController)
-)
-podsRouter.get('/quit-friends',
-  authenticate,
-  ensureUserHasRight(UserRight.MANAGE_PODS),
-  asyncMiddleware(quitFriendsController)
-)
-podsRouter.delete('/:id',
-  authenticate,
-  ensureUserHasRight(UserRight.MANAGE_PODS),
-  podRemoveValidator,
-  asyncMiddleware(removeFriendController)
-)
 
 // ---------------------------------------------------------------------------
 
@@ -63,28 +26,3 @@ async function listPods (req: express.Request, res: express.Response, next: expr
 
   return res.json(getFormattedObjects(resultList.data, resultList.total))
 }
-
-async function makeFriendsController (req: express.Request, res: express.Response, next: express.NextFunction) {
-  const hosts = req.body.hosts as string[]
-
-  // Don't wait the process that could be long
-  makeFriends(hosts)
-    .then(() => logger.info('Made friends!'))
-    .catch(err => logger.error('Could not make friends.', err))
-
-  return res.type('json').status(204).end()
-}
-
-async function quitFriendsController (req: express.Request, res: express.Response, next: express.NextFunction) {
-  await quitFriends()
-
-  return res.type('json').status(204).end()
-}
-
-async function removeFriendController (req: express.Request, res: express.Response, next: express.NextFunction) {
-  const pod = res.locals.pod as PodInstance
-
-  await removeFriend(pod)
-
-  return res.type('json').status(204).end()
-}
diff --git a/server/controllers/api/request-schedulers.ts b/server/controllers/api/request-schedulers.ts
deleted file mode 100644 (file)
index 4c8fbe1..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-import * as express from 'express'
-import * as Bluebird from 'bluebird'
-
-import {
-  AbstractRequestScheduler,
-  getRequestScheduler,
-  getRequestVideoQaduScheduler,
-  getRequestVideoEventScheduler
-} from '../../lib'
-import { authenticate, ensureUserHasRight, asyncMiddleware } from '../../middlewares'
-import { RequestSchedulerStatsAttributes, UserRight } from '../../../shared'
-
-const requestSchedulerRouter = express.Router()
-
-requestSchedulerRouter.get('/stats',
-  authenticate,
-  ensureUserHasRight(UserRight.MANAGE_REQUEST_SCHEDULERS),
-  asyncMiddleware(getRequestSchedulersStats)
-)
-
-// ---------------------------------------------------------------------------
-
-export {
-  requestSchedulerRouter
-}
-
-// ---------------------------------------------------------------------------
-
-async function getRequestSchedulersStats (req: express.Request, res: express.Response, next: express.NextFunction) {
-  const result = await Bluebird.props({
-    requestScheduler: buildRequestSchedulerStats(getRequestScheduler()),
-    requestVideoQaduScheduler: buildRequestSchedulerStats(getRequestVideoQaduScheduler()),
-    requestVideoEventScheduler: buildRequestSchedulerStats(getRequestVideoEventScheduler())
-  })
-
-  return res.json(result)
-}
-
-// ---------------------------------------------------------------------------
-
-async function buildRequestSchedulerStats (requestScheduler: AbstractRequestScheduler<any>) {
-  const count = await requestScheduler.remainingRequestsCount()
-
-  const result: RequestSchedulerStatsAttributes = {
-    totalRequests: count,
-    requestsLimitPods: requestScheduler.limitPods,
-    requestsLimitPerPod: requestScheduler.limitPerPod,
-    remainingMilliSeconds: requestScheduler.remainingMilliSeconds(),
-    milliSecondsInterval: requestScheduler.requestInterval
-  }
-
-  return result
-}
index 9ec6feb572acc6ec6dde19bc93bf7578f806e18b..41ffb64cb202868e878188f49d86ce562032b803 100644 (file)
@@ -1,37 +1,29 @@
 import * as express from 'express'
-
-import { database as db, CONFIG } from '../../initializers'
-import { logger, getFormattedObjects, retryTransactionWrapper } from '../../helpers'
+import { UserCreate, UserRight, UserRole, UserUpdate, UserUpdateMe, UserVideoRate as FormattedUserVideoRate } from '../../../shared'
+import { getFormattedObjects, logger, retryTransactionWrapper } from '../../helpers'
+import { CONFIG, database as db } from '../../initializers'
+import { createUserAccountAndChannel } from '../../lib'
 import {
+  asyncMiddleware,
   authenticate,
   ensureUserHasRight,
   ensureUserRegistrationAllowed,
-  usersAddValidator,
-  usersRegisterValidator,
-  usersUpdateValidator,
-  usersUpdateMeValidator,
-  usersRemoveValidator,
-  usersVideoRatingValidator,
-  usersGetValidator,
   paginationValidator,
   setPagination,
-  usersSortValidator,
   setUsersSort,
   token,
-  asyncMiddleware
+  usersAddValidator,
+  usersGetValidator,
+  usersRegisterValidator,
+  usersRemoveValidator,
+  usersSortValidator,
+  usersUpdateMeValidator,
+  usersUpdateValidator,
+  usersVideoRatingValidator
 } from '../../middlewares'
-import {
-  UserVideoRate as FormattedUserVideoRate,
-  UserCreate,
-  UserUpdate,
-  UserUpdateMe,
-  UserRole,
-  UserRight
-} from '../../../shared'
-import { createUserAccountAndChannel } from '../../lib'
-import { UserInstance } from '../../models'
-import { videosSortValidator } from '../../middlewares/validators/sort'
 import { setVideosSort } from '../../middlewares/sort'
+import { videosSortValidator } from '../../middlewares/validators/sort'
+import { UserInstance } from '../../models'
 
 const usersRouter = express.Router()
 
@@ -176,9 +168,9 @@ function getUser (req: express.Request, res: express.Response, next: express.Nex
 
 async function getUserVideoRating (req: express.Request, res: express.Response, next: express.NextFunction) {
   const videoId = +req.params.videoId
-  const userId = +res.locals.oauth.token.User.id
+  const accountId = +res.locals.oauth.token.User.Account.id
 
-  const ratingObj = await db.UserVideoRate.load(userId, videoId, null)
+  const ratingObj = await db.AccountVideoRate.load(accountId, videoId, null)
   const rating = ratingObj ? ratingObj.type : 'none'
 
   const json: FormattedUserVideoRate = {
index 04349042b02b1cb6535b3a354fe37c1ae022186d..7a3471116f6f246f81c3f57f5e0aad69144f2163 100644 (file)
@@ -1,7 +1,6 @@
 import * as express from 'express'
 
 import { database as db } from '../../../initializers/database'
-import * as friends from '../../../lib/friends'
 import {
   logger,
   getFormattedObjects,
@@ -84,7 +83,8 @@ async function reportVideoAbuse (req: express.Request, res: express.Response) {
         videoUUID: videoInstance.uuid
       }
 
-      await friends.reportAbuseVideoToFriend(reportData, videoInstance, t)
+      // await friends.reportAbuseVideoToFriend(reportData, videoInstance, t)
+      // TODO: send abuse to origin pod
     }
   })
 
index 4d1f03903776e91e61e0ed64ec320051f03dc48d..656bc31298ae1663b8722b82c69458ebc7f852c7 100644 (file)
@@ -1,31 +1,23 @@
 import * as express from 'express'
-
+import { VideoChannelCreate, VideoChannelUpdate } from '../../../../shared'
+import { getFormattedObjects, logger, resetSequelizeInstance, retryTransactionWrapper } from '../../../helpers'
 import { database as db } from '../../../initializers'
+import { createVideoChannel } from '../../../lib'
 import {
-  logger,
-  getFormattedObjects,
-  retryTransactionWrapper,
-  resetSequelizeInstance
-} from '../../../helpers'
-import {
+  asyncMiddleware,
   authenticate,
+  listVideoAccountChannelsValidator,
   paginationValidator,
-  videoChannelsSortValidator,
-  videoChannelsAddValidator,
-  setVideoChannelsSort,
   setPagination,
-  videoChannelsRemoveValidator,
+  setVideoChannelsSort,
   videoChannelGetValidator,
-  videoChannelsUpdateValidator,
-  listVideoAccountChannelsValidator,
-  asyncMiddleware
+  videoChannelsAddValidator,
+  videoChannelsRemoveValidator,
+  videoChannelsSortValidator,
+  videoChannelsUpdateValidator
 } from '../../../middlewares'
-import {
-  createVideoChannel,
-  updateVideoChannelToFriends
-} from '../../../lib'
-import { VideoChannelInstance, AccountInstance } from '../../../models'
-import { VideoChannelCreate, VideoChannelUpdate } from '../../../../shared'
+import { AccountInstance, VideoChannelInstance } from '../../../models'
+import { sendUpdateVideoChannel } from '../../../lib/activitypub/send-request'
 
 const videoChannelRouter = express.Router()
 
@@ -137,11 +129,8 @@ async function updateVideoChannel (req: express.Request, res: express.Response)
       if (videoChannelInfoToUpdate.description !== undefined) videoChannelInstance.set('description', videoChannelInfoToUpdate.description)
 
       await videoChannelInstance.save(sequelizeOptions)
-      const json = videoChannelInstance.toUpdateRemoteJSON()
-
-      // Now we'll update the video channel's meta data to our friends
-      return updateVideoChannelToFriends(json, t)
 
+      await sendUpdateVideoChannel(videoChannelInstance, t)
     })
 
     logger.info('Video channel with name %s and uuid %s updated.', videoChannelInstance.name, videoChannelInstance.uuid)
index 9ad84609f212986c94735b1d8217c79a4d227c7d..06383922355988ab83a3f6a52d6322a638a69db4 100644 (file)
@@ -1,57 +1,41 @@
 import * as express from 'express'
 import * as multer from 'multer'
 import { extname, join } from 'path'
-
-import { database as db } from '../../../initializers/database'
+import { VideoCreate, VideoPrivacy, VideoUpdate } from '../../../../shared'
 import {
-  CONFIG,
-  REQUEST_VIDEO_QADU_TYPES,
-  REQUEST_VIDEO_EVENT_TYPES,
-  VIDEO_CATEGORIES,
-  VIDEO_LICENCES,
-  VIDEO_LANGUAGES,
-  VIDEO_PRIVACIES,
-  VIDEO_MIMETYPE_EXT
-} from '../../../initializers'
-import {
-  addEventToRemoteVideo,
-  quickAndDirtyUpdateVideoToFriends,
-  addVideoToFriends,
-  updateVideoToFriends,
-  JobScheduler,
-  fetchRemoteDescription
-} from '../../../lib'
+  fetchRemoteVideoDescription,
+  generateRandomString,
+  getFormattedObjects,
+  getVideoFileHeight,
+  logger,
+  renamePromise,
+  resetSequelizeInstance,
+  retryTransactionWrapper
+} from '../../../helpers'
+import { getActivityPubUrl } from '../../../helpers/activitypub'
+import { CONFIG, VIDEO_CATEGORIES, VIDEO_LANGUAGES, VIDEO_LICENCES, VIDEO_MIMETYPE_EXT, VIDEO_PRIVACIES } from '../../../initializers'
+import { database as db } from '../../../initializers/database'
+import { sendAddVideo, sendUpdateVideoChannel } from '../../../lib/activitypub/send-request'
+import { transcodingJobScheduler } from '../../../lib/jobs/transcoding-job-scheduler/transcoding-job-scheduler'
 import {
+  asyncMiddleware,
   authenticate,
   paginationValidator,
-  videosSortValidator,
-  setVideosSort,
   setPagination,
   setVideosSearch,
-  videosUpdateValidator,
-  videosSearchValidator,
+  setVideosSort,
   videosAddValidator,
   videosGetValidator,
   videosRemoveValidator,
-  asyncMiddleware
+  videosSearchValidator,
+  videosSortValidator,
+  videosUpdateValidator
 } from '../../../middlewares'
-import {
-  logger,
-  retryTransactionWrapper,
-  generateRandomString,
-  getFormattedObjects,
-  renamePromise,
-  getVideoFileHeight,
-  resetSequelizeInstance
-} from '../../../helpers'
 import { VideoInstance } from '../../../models'
-import { VideoCreate, VideoUpdate, VideoPrivacy } from '../../../../shared'
-
 import { abuseVideoRouter } from './abuse'
 import { blacklistRouter } from './blacklist'
-import { rateVideoRouter } from './rate'
 import { videoChannelRouter } from './channel'
-import { getActivityPubUrl } from '../../../helpers/activitypub'
+import { rateVideoRouter } from './rate'
 
 const videosRouter = express.Router()
 
@@ -225,7 +209,7 @@ async function addVideo (req: express.Request, res: express.Response, videoPhysi
       }
 
       tasks.push(
-        JobScheduler.Instance.createJob(t, 'videoFileOptimizer', dataInput)
+        transcodingJobScheduler.createJob(t, 'videoFileOptimizer', dataInput)
       )
     }
     await Promise.all(tasks)
@@ -252,9 +236,7 @@ async function addVideo (req: express.Request, res: express.Response, videoPhysi
     // Don't send video to remote pods, it is private
     if (video.privacy === VideoPrivacy.PRIVATE) return undefined
 
-    const remoteVideo = await video.toAddRemoteJSON()
-    // Now we'll add the video's meta data to our friends
-    return addVideoToFriends(remoteVideo, t)
+    await sendAddVideo(video, t)
   })
 
   logger.info('Video with name %s and uuid %s created.', videoInfo.name, videoUUID)
@@ -302,14 +284,12 @@ async function updateVideo (req: express.Request, res: express.Response) {
 
       // Now we'll update the video's meta data to our friends
       if (wasPrivateVideo === false) {
-        const json = videoInstance.toUpdateRemoteJSON()
-        return updateVideoToFriends(json, t)
+        await sendUpdateVideoChannel(videoInstance, t)
       }
 
       // Video is not private anymore, send a create action to remote pods
       if (wasPrivateVideo === true && videoInstance.privacy !== VideoPrivacy.PRIVATE) {
-        const remoteVideo = await videoInstance.toAddRemoteJSON()
-        return addVideoToFriends(remoteVideo, t)
+        await sendAddVideo(videoInstance, t)
       }
     })
 
@@ -324,7 +304,7 @@ async function updateVideo (req: express.Request, res: express.Response) {
   }
 }
 
-function getVideo (req: express.Request, res: express.Response) {
+async function getVideo (req: express.Request, res: express.Response) {
   const videoInstance = res.locals.video
 
   if (videoInstance.isOwned()) {
@@ -333,21 +313,11 @@ function getVideo (req: express.Request, res: express.Response) {
     // For example, only add a view when a user watch a video during 30s etc
     videoInstance.increment('views')
       .then(() => {
-        const qaduParams = {
-          videoId: videoInstance.id,
-          type: REQUEST_VIDEO_QADU_TYPES.VIEWS
-        }
-        return quickAndDirtyUpdateVideoToFriends(qaduParams)
+        // TODO: send to followers a notification
       })
       .catch(err => logger.error('Cannot add view to video %s.', videoInstance.uuid, err))
   } else {
-    // Just send the event to our friends
-    const eventParams = {
-      videoId: videoInstance.id,
-      type: REQUEST_VIDEO_EVENT_TYPES.VIEWS
-    }
-    addEventToRemoteVideo(eventParams)
-      .catch(err => logger.error('Cannot add event to remote video %s.', videoInstance.uuid, err))
+    // TODO: send view event to followers
   }
 
   // Do not wait the view system
@@ -361,7 +331,7 @@ async function getVideoDescription (req: express.Request, res: express.Response)
   if (videoInstance.isOwned()) {
     description = videoInstance.description
   } else {
-    description = await fetchRemoteDescription(videoInstance)
+    description = await fetchRemoteVideoDescription(videoInstance)
   }
 
   return res.json({ description })
index 727984506158d5731893237656b48788405aa7ad..955277d2573f32220c23019d9dbfb6fc013adda6 100644 (file)
@@ -1,25 +1,11 @@
 import * as express from 'express'
-
-import { database as db } from '../../../initializers/database'
-import {
-  logger,
-  retryTransactionWrapper
-} from '../../../helpers'
-import {
-  VIDEO_RATE_TYPES,
-  REQUEST_VIDEO_EVENT_TYPES,
-  REQUEST_VIDEO_QADU_TYPES
-} from '../../../initializers'
-import {
-  addEventsToRemoteVideo,
-  quickAndDirtyUpdatesVideoToFriends
-} from '../../../lib'
-import {
-  authenticate,
-  videoRateValidator,
-  asyncMiddleware
-} from '../../../middlewares'
 import { UserVideoRateUpdate } from '../../../../shared'
+import { logger, retryTransactionWrapper } from '../../../helpers'
+import { VIDEO_RATE_TYPES } from '../../../initializers'
+import { database as db } from '../../../initializers/database'
+import { asyncMiddleware, authenticate, videoRateValidator } from '../../../middlewares'
+import { AccountInstance } from '../../../models/account/account-interface'
+import { VideoInstance } from '../../../models/video/video-interface'
 
 const rateVideoRouter = express.Router()
 
@@ -51,12 +37,12 @@ async function rateVideoRetryWrapper (req: express.Request, res: express.Respons
 async function rateVideo (req: express.Request, res: express.Response) {
   const body: UserVideoRateUpdate = req.body
   const rateType = body.rating
-  const videoInstance = res.locals.video
-  const userInstance = res.locals.oauth.token.User
+  const videoInstance: VideoInstance = res.locals.video
+  const accountInstance: AccountInstance = res.locals.oauth.token.User.Account
 
   await db.sequelize.transaction(async t => {
     const sequelizeOptions = { transaction: t }
-    const previousRate = await db.UserVideoRate.load(userInstance.id, videoInstance.id, t)
+    const previousRate = await db.AccountVideoRate.load(accountInstance.id, videoInstance.id, t)
 
     let likesToIncrement = 0
     let dislikesToIncrement = 0
@@ -79,12 +65,12 @@ async function rateVideo (req: express.Request, res: express.Response) {
       }
     } else if (rateType !== 'none') { // There was not a previous rate, insert a new one if there is a rate
       const query = {
-        userId: userInstance.id,
+        accountId: accountInstance.id,
         videoId: videoInstance.id,
         type: rateType
       }
 
-      await db.UserVideoRate.create(query, sequelizeOptions)
+      await db.AccountVideoRate.create(query, sequelizeOptions)
     }
 
     const incrementQuery = {
@@ -96,48 +82,12 @@ async function rateVideo (req: express.Request, res: express.Response) {
     // It is useful for the user to have a feedback
     await videoInstance.increment(incrementQuery, sequelizeOptions)
 
-    // Send a event to original pod
     if (videoInstance.isOwned() === false) {
-
-      const eventsParams = []
-
-      if (likesToIncrement !== 0) {
-        eventsParams.push({
-          videoId: videoInstance.id,
-          type: REQUEST_VIDEO_EVENT_TYPES.LIKES,
-          count: likesToIncrement
-        })
-      }
-
-      if (dislikesToIncrement !== 0) {
-        eventsParams.push({
-          videoId: videoInstance.id,
-          type: REQUEST_VIDEO_EVENT_TYPES.DISLIKES,
-          count: dislikesToIncrement
-        })
-      }
-
-      await addEventsToRemoteVideo(eventsParams, t)
-    } else { // We own the video, we need to send a quick and dirty update to friends to notify the counts changed
-      const qadusParams = []
-
-      if (likesToIncrement !== 0) {
-        qadusParams.push({
-          videoId: videoInstance.id,
-          type: REQUEST_VIDEO_QADU_TYPES.LIKES
-        })
-      }
-
-      if (dislikesToIncrement !== 0) {
-        qadusParams.push({
-          videoId: videoInstance.id,
-          type: REQUEST_VIDEO_QADU_TYPES.DISLIKES
-        })
-      }
-
-      await quickAndDirtyUpdatesVideoToFriends(qadusParams, t)
+      // TODO: Send a event to original pod
+    } else {
+      // TODO: Send update to followers
     }
   })
 
-  logger.info('User video rate for video %s of user %s updated.', videoInstance.name, userInstance.username)
+  logger.info('Account video rate for video %s of account %s updated.', videoInstance.name, accountInstance.name)
 }
index 75de2278c208f7c1c025c9fc25ca4f5b97d1c64c..a1493e5c13873bb0021f753c0aa2a7266c172b4e 100644 (file)
@@ -1,15 +1,15 @@
+import { join } from 'path'
+import * as request from 'request'
 import * as url from 'url'
-
-import { database as db } from '../initializers'
-import { logger } from './logger'
-import { doRequest, doRequestAndSaveToFile } from './requests'
-import { isRemoteAccountValid } from './custom-validators'
+import { ActivityIconObject } from '../../shared/index'
 import { ActivityPubActor } from '../../shared/models/activitypub/activitypub-actor'
 import { ResultList } from '../../shared/models/result-list.model'
-import { CONFIG } from '../initializers/constants'
+import { database as db, REMOTE_SCHEME } from '../initializers'
+import { CONFIG, STATIC_PATHS } from '../initializers/constants'
 import { VideoInstance } from '../models/video/video-interface'
-import { ActivityIconObject } from '../../shared/index'
-import { join } from 'path'
+import { isRemoteAccountValid } from './custom-validators'
+import { logger } from './logger'
+import { doRequest, doRequestAndSaveToFile } from './requests'
 
 function generateThumbnailFromUrl (video: VideoInstance, icon: ActivityIconObject) {
   const thumbnailName = video.getThumbnailName()
@@ -22,9 +22,10 @@ function generateThumbnailFromUrl (video: VideoInstance, icon: ActivityIconObjec
   return doRequestAndSaveToFile(options, thumbnailPath)
 }
 
-function getActivityPubUrl (type: 'video' | 'videoChannel', uuid: string) {
-  if (type === 'video') return CONFIG.WEBSERVER.URL + '/videos/watch/' + uuid
-  else if (type === 'videoChannel') return CONFIG.WEBSERVER.URL + '/video-channels/' + uuid
+function getActivityPubUrl (type: 'video' | 'videoChannel' | 'account', id: string) {
+  if (type === 'video') return CONFIG.WEBSERVER.URL + '/videos/watch/' + id
+  else if (type === 'videoChannel') return CONFIG.WEBSERVER.URL + '/video-channels/' + id
+  else if (type === 'account') return CONFIG.WEBSERVER.URL + '/account/' + id
 
   return ''
 }
@@ -94,7 +95,24 @@ async function fetchRemoteAccountAndCreatePod (accountUrl: string) {
   return { account, pod }
 }
 
-function activityPubContextify (data: object) {
+function fetchRemoteVideoPreview (video: VideoInstance) {
+  // FIXME: use url
+  const host = video.VideoChannel.Account.Pod.host
+  const path = join(STATIC_PATHS.PREVIEWS, video.getPreviewName())
+
+  return request.get(REMOTE_SCHEME.HTTP + '://' + host + path)
+}
+
+async function fetchRemoteVideoDescription (video: VideoInstance) {
+  const options = {
+    uri: video.url
+  }
+
+  const { body } = await doRequest(options)
+  return body.description ? body.description : ''
+}
+
+function activityPubContextify <T> (data: T) {
   return Object.assign(data,{
     '@context': [
       'https://www.w3.org/ns/activitystreams',
@@ -141,7 +159,9 @@ export {
   activityPubCollectionPagination,
   getActivityPubUrl,
   generateThumbnailFromUrl,
-  getOrCreateAccount
+  getOrCreateAccount,
+  fetchRemoteVideoPreview,
+  fetchRemoteVideoDescription
 }
 
 // ---------------------------------------------------------------------------
index 31cedd7689c6386d54a74519924df6eb9c0e2680..4b1deeadce1fb0772378ea9690d54bd042668343 100644 (file)
@@ -1,16 +1,6 @@
-import * as replay from 'request-replay'
-import * as request from 'request'
 import * as Promise from 'bluebird'
-
-import {
-  RETRY_REQUESTS,
-  REMOTE_SCHEME,
-  CONFIG
-} from '../initializers'
-import { PodInstance } from '../models'
-import { PodSignature } from '../../shared'
-import { signObject } from './peertube-crypto'
 import { createWriteStream } from 'fs'
+import * as request from 'request'
 
 function doRequest (requestOptions: request.CoreOptions & request.UriOptions) {
   return new Promise<{ response: request.RequestResponse, body: any }>((res, rej) => {
@@ -27,78 +17,9 @@ function doRequestAndSaveToFile (requestOptions: request.CoreOptions & request.U
   })
 }
 
-type MakeRetryRequestParams = {
-  url: string,
-  method: 'GET' | 'POST',
-  json: Object
-}
-function makeRetryRequest (params: MakeRetryRequestParams) {
-  return new Promise<{ response: request.RequestResponse, body: any }>((res, rej) => {
-    replay(
-      request(params, (err, response, body) => err ? rej(err) : res({ response, body })),
-      {
-        retries: RETRY_REQUESTS,
-        factor: 3,
-        maxTimeout: Infinity,
-        errorCodes: [ 'EADDRINFO', 'ETIMEDOUT', 'ECONNRESET', 'ESOCKETTIMEDOUT', 'ENOTFOUND', 'ECONNREFUSED' ]
-      }
-    )
-  })
-}
-
-type MakeSecureRequestParams = {
-  toPod: PodInstance
-  path: string
-  data?: Object
-}
-function makeSecureRequest (params: MakeSecureRequestParams) {
-  const requestParams: {
-    method: 'POST',
-    uri: string,
-    json: {
-      signature: PodSignature,
-      data: any
-    }
-  } = {
-    method: 'POST',
-    uri: REMOTE_SCHEME.HTTP + '://' + params.toPod.host + params.path,
-    json: {
-      signature: null,
-      data: null
-    }
-  }
-
-  const host = CONFIG.WEBSERVER.HOST
-
-  let dataToSign
-  if (params.data) {
-    dataToSign = params.data
-  } else {
-    // We do not have data to sign so we just take our host
-    // It is not ideal but the connection should be in HTTPS
-    dataToSign = host
-  }
-
-  sign(dataToSign).then(signature => {
-    requestParams.json.signature = {
-      host, // Which host we pretend to be
-      signature
-    }
-
-    // If there are data information
-    if (params.data) {
-      requestParams.json.data = params.data
-    }
-
-    return doRequest(requestParams)
-  })
-}
-
 // ---------------------------------------------------------------------------
 
 export {
   doRequest,
-  doRequestAndSaveToFile,
-  makeRetryRequest,
-  makeSecureRequest
+  doRequestAndSaveToFile
 }
index 9586fa5624b568c1eb2052ef8eec54028bf3f978..164ae4951697cf65c298a038792f96e4ffe10df1 100644 (file)
@@ -35,7 +35,7 @@ export {
 
 function webfingerLookup (url: string) {
   return new Promise<WebFingerData>((res, rej) => {
-    webfinger.lookup('nick@silverbucket.net', (err, p) => {
+    webfinger.lookup(url, (err, p) => {
       if (err) return rej(err)
 
       return p
index e6fda88c271ad679c8fac3b04bff6433f475dc12..2d61094bd471f0306f604634cd009dbc3fc69797 100644 (file)
@@ -361,12 +361,6 @@ export {
   PODS_SCORE,
   PREVIEWS_SIZE,
   REMOTE_SCHEME,
-  REQUEST_ENDPOINT_ACTIONS,
-  REQUEST_ENDPOINTS,
-  REQUEST_VIDEO_EVENT_ENDPOINT,
-  REQUEST_VIDEO_EVENT_TYPES,
-  REQUEST_VIDEO_QADU_ENDPOINT,
-  REQUEST_VIDEO_QADU_TYPES,
   REQUESTS_IN_PARALLEL,
   REQUESTS_INTERVAL,
   REQUESTS_LIMIT_PER_POD,
index aefb6da3a020708128fcd0ce9ae8c876e5ca1b07..1383bb33ba29e451e0b87753f1feda176942e46b 100644 (file)
@@ -2,7 +2,6 @@ import { join } from 'path'
 import { flattenDepth } from 'lodash'
 require('pg').defaults.parseInt8 = true // Avoid BIGINT to be converted to string
 import * as Sequelize from 'sequelize'
-import * as Bluebird from 'bluebird'
 
 import { CONFIG } from './constants'
 // Do not use barrel, we need to load database first
@@ -19,10 +18,6 @@ import { UserModel } from '../models/account/user-interface'
 import { AccountVideoRateModel } from '../models/account/account-video-rate-interface'
 import { AccountFollowModel } from '../models/account/account-follow-interface'
 import { TagModel } from './../models/video/tag-interface'
-import { RequestModel } from './../models/request/request-interface'
-import { RequestVideoQaduModel } from './../models/request/request-video-qadu-interface'
-import { RequestVideoEventModel } from './../models/request/request-video-event-interface'
-import { RequestToPodModel } from './../models/request/request-to-pod-interface'
 import { PodModel } from './../models/pod/pod-interface'
 import { OAuthTokenModel } from './../models/oauth/oauth-token-interface'
 import { OAuthClientModel } from './../models/oauth/oauth-client-interface'
index c8f6b3bc27c24831675a3b2fd49b19e088a8e2ae..c617b16c9dc4e1576e85a64636770f2eb110cfa7 100644 (file)
@@ -1,20 +1,21 @@
 import * as passwordGenerator from 'password-generator'
-import * as Bluebird from 'bluebird'
+import { UserRole } from '../../shared'
+import { logger, mkdirpPromise, rimrafPromise } from '../helpers'
+import { createPrivateAndPublicKeys } from '../helpers/peertube-crypto'
+import { createUserAccountAndChannel } from '../lib'
+import { clientsExist, usersExist } from './checker'
+import { CACHE, CONFIG, LAST_MIGRATION_VERSION } from './constants'
 
 import { database as db } from './database'
-import { CONFIG, LAST_MIGRATION_VERSION, CACHE } from './constants'
-import { clientsExist, usersExist } from './checker'
-import { logger, createCertsIfNotExist, mkdirpPromise, rimrafPromise } from '../helpers'
-import { createUserAccountAndChannel } from '../lib'
-import { UserRole } from '../../shared'
+import { createLocalAccount } from '../lib/user'
 
 async function installApplication () {
   await db.sequelize.sync()
   await removeCacheDirectories()
   await createDirectoriesIfNotExist()
-  await createCertsIfNotExist()
   await createOAuthClientIfNotExist()
   await createOAuthAdminIfNotExist()
+  await createApplicationIfNotExist()
 }
 
 // ---------------------------------------------------------------------------
@@ -28,7 +29,7 @@ export {
 function removeCacheDirectories () {
   const cacheDirectories = CACHE.DIRECTORIES
 
-  const tasks: Bluebird<any>[] = []
+  const tasks: Promise<any>[] = []
 
   // Cache directories
   for (const key of Object.keys(cacheDirectories)) {
@@ -120,7 +121,12 @@ async function createOAuthAdminIfNotExist () {
   await createUserAccountAndChannel(user, validatePassword)
   logger.info('Username: ' + username)
   logger.info('User password: ' + password)
+}
 
+async function createApplicationIfNotExist () {
   logger.info('Creating Application table.')
-  await db.Application.create({ migrationVersion: LAST_MIGRATION_VERSION })
+  const applicationInstance = await db.Application.create({ migrationVersion: LAST_MIGRATION_VERSION })
+
+  logger.info('Creating application account.')
+  return createLocalAccount('peertube', null, applicationInstance.id, undefined)
 }
index e1d9fdacbd27579f2e7a72421ddb859de6ee211a..e7d8a287609dc8e8ebf893d13c872652d5439c95 100644 (file)
@@ -1,5 +1,4 @@
 import * as Sequelize from 'sequelize'
-import * as Promise from 'bluebird'
 import { join } from 'path'
 
 import { readdirPromise, renamePromise } from '../../helpers/core-utils'
index 7408006067c0c6fe274195dcf9deb711e18c1375..f8d56528a2f07f4ef3810b5671d3edfe3904ec75 100644 (file)
@@ -1,3 +1,4 @@
 export * from './process-create'
 export * from './process-flag'
 export * from './process-update'
+export * from './send-request'
index 05e77ebc35c0c971785f58421105dff815dddddf..2cf0c4fd172e31694b2b90605b839b750ce76266 100644 (file)
@@ -8,7 +8,11 @@ import { VideoChannelInstance } from '../../models/video/video-channel-interface
 import { VideoFileAttributes } from '../../models/video/video-file-interface'
 import { VideoAttributes, VideoInstance } from '../../models/video/video-interface'
 
-async function videoActivityObjectToDBAttributes (videoChannel: VideoChannelInstance, videoObject: VideoTorrentObject, t: Sequelize.Transaction) {
+async function videoActivityObjectToDBAttributes (
+  videoChannel: VideoChannelInstance,
+  videoObject: VideoTorrentObject,
+  t: Sequelize.Transaction
+) {
   const videoFromDatabase = await db.Video.loadByUUIDOrURL(videoObject.uuid, videoObject.id, t)
   if (videoFromDatabase) throw new Error('Video with this UUID/Url already exists.')
 
index 6fa862ee96c0dc68cc94fa4e94e3197cbf3ba597..b562dce4d572b8523e76a527b118619a4c78de00 100644 (file)
@@ -5,7 +5,7 @@ import {
 } from '../../../shared'
 
 function processFlagActivity (activity: ActivityCreate) {
-  // empty
+  return Promise.resolve(undefined)
 }
 
 // ---------------------------------------------------------------------------
index 6a31c226d5ebf2c3546280d36dacf4689bede128..91101f5ad362f0bfb2e975f1f03a96a94d131707 100644 (file)
@@ -1,5 +1,6 @@
 import * as Sequelize from 'sequelize'
 
+import { database as db } from '../../initializers'
 import {
   AccountInstance,
   VideoInstance,
@@ -13,54 +14,66 @@ function sendCreateVideoChannel (videoChannel: VideoChannelInstance, t: Sequeliz
   const videoChannelObject = videoChannel.toActivityPubObject()
   const data = createActivityData(videoChannel.url, videoChannel.Account, videoChannelObject)
 
-  return broadcastToFollowers(data, t)
+  return broadcastToFollowers(data, videoChannel.Account, t)
 }
 
 function sendUpdateVideoChannel (videoChannel: VideoChannelInstance, t: Sequelize.Transaction) {
   const videoChannelObject = videoChannel.toActivityPubObject()
   const data = updateActivityData(videoChannel.url, videoChannel.Account, videoChannelObject)
 
-  return broadcastToFollowers(data, t)
+  return broadcastToFollowers(data, videoChannel.Account, t)
 }
 
 function sendDeleteVideoChannel (videoChannel: VideoChannelInstance, t: Sequelize.Transaction) {
   const videoChannelObject = videoChannel.toActivityPubObject()
   const data = deleteActivityData(videoChannel.url, videoChannel.Account, videoChannelObject)
 
-  return broadcastToFollowers(data, t)
+  return broadcastToFollowers(data, videoChannel.Account, t)
 }
 
 function sendAddVideo (video: VideoInstance, t: Sequelize.Transaction) {
   const videoObject = video.toActivityPubObject()
   const data = addActivityData(video.url, video.VideoChannel.Account, video.VideoChannel.url, videoObject)
 
-  return broadcastToFollowers(data, t)
+  return broadcastToFollowers(data, video.VideoChannel.Account, t)
 }
 
 function sendUpdateVideo (video: VideoInstance, t: Sequelize.Transaction) {
   const videoObject = video.toActivityPubObject()
   const data = updateActivityData(video.url, video.VideoChannel.Account, videoObject)
 
-  return broadcastToFollowers(data, t)
+  return broadcastToFollowers(data, video.VideoChannel.Account, t)
 }
 
 function sendDeleteVideo (video: VideoInstance, t: Sequelize.Transaction) {
   const videoObject = video.toActivityPubObject()
   const data = deleteActivityData(video.url, video.VideoChannel.Account, videoObject)
 
-  return broadcastToFollowers(data, t)
+  return broadcastToFollowers(data, video.VideoChannel.Account, t)
 }
 
 // ---------------------------------------------------------------------------
 
 export {
-
+  sendCreateVideoChannel,
+  sendUpdateVideoChannel,
+  sendDeleteVideoChannel,
+  sendAddVideo,
+  sendUpdateVideo,
+  sendDeleteVideo
 }
 
 // ---------------------------------------------------------------------------
 
-function broadcastToFollowers (data: any, t: Sequelize.Transaction) {
-  return httpRequestJobScheduler.createJob(t, 'http-request', 'httpRequestBroadcastHandler', data)
+async function broadcastToFollowers (data: any, fromAccount: AccountInstance, t: Sequelize.Transaction) {
+  const result = await db.Account.listFollowerUrlsForApi(fromAccount.name, 0)
+
+  const jobPayload = {
+    uris: result.data,
+    body: data
+  }
+
+  return httpRequestJobScheduler.createJob(t, 'httpRequestBroadcastHandler', jobPayload)
 }
 
 function buildSignedActivity (byAccount: AccountInstance, data: Object) {
index 791ad1cbf77f0735af2fa0e3ef35f7ae26900e07..776f647a048ba1e45ee7ec74edd8da8e9d74ed59 100644 (file)
@@ -3,9 +3,8 @@ import { join } from 'path'
 import { createWriteStream } from 'fs'
 
 import { database as db, CONFIG, CACHE } from '../../initializers'
-import { logger, unlinkPromise } from '../../helpers'
+import { logger, unlinkPromise, fetchRemoteVideoPreview } from '../../helpers'
 import { VideoInstance } from '../../models'
-import { fetchRemotePreview } from '../../lib'
 
 class VideosPreviewCache {
 
@@ -54,7 +53,7 @@ class VideosPreviewCache {
   }
 
   private saveRemotePreviewAndReturnPath (video: VideoInstance) {
-    const req = fetchRemotePreview(video)
+    const req = fetchRemoteVideoPreview(video)
 
     return new Promise<string>((res, rej) => {
       const path = join(CACHE.DIRECTORIES.PREVIEWS, video.getPreviewName())
index bfb415ad21731470e29026794e1ddba18257fc2b..d22ecb665859b2d2e0669bd49bd90520a9ab7eb5 100644 (file)
@@ -1,8 +1,6 @@
 export * from './activitypub'
 export * from './cache'
 export * from './jobs'
-export * from './request'
-export * from './friends'
 export * from './oauth-model'
 export * from './user'
 export * from './video-channel'
index 6b6946d02c0410f54fa7b2f557830f8264d92361..799b86e1c08fbba25f595b062fca95cb0ac58312 100644 (file)
@@ -1,19 +1,28 @@
-import * as Bluebird from 'bluebird'
-
-import { database as db } from '../../../initializers/database'
 import { logger } from '../../../helpers'
+import { doRequest } from '../../../helpers/requests'
+import { HTTPRequestPayload } from './http-request-job-scheduler'
+
+async function process (payload: HTTPRequestPayload, jobId: number) {
+  logger.info('Processing broadcast in job %d.', jobId)
 
-async function process (data: { videoUUID: string }, jobId: number) {
+  const options = {
+    uri: '',
+    json: payload.body
+  }
 
+  for (const uri of payload.uris) {
+    options.uri = uri
+    await doRequest(options)
+  }
 }
 
 function onError (err: Error, jobId: number) {
-  logger.error('Error when optimized video file in job %d.', jobId, err)
+  logger.error('Error when broadcasting request in job %d.', jobId, err)
   return Promise.resolve()
 }
 
 async function onSuccess (jobId: number) {
-
+  logger.info('Job %d is a success.', jobId)
 }
 
 // ---------------------------------------------------------------------------
index 42cb9139ca152b19caa54e8cd1ae44562111adb8..ad33498667fcf69203ee6b3ff9cbe4182c06b4b9 100644 (file)
@@ -4,7 +4,11 @@ import * as httpRequestBroadcastHandler from './http-request-broadcast-handler'
 import * as httpRequestUnicastHandler from './http-request-unicast-handler'
 import { JobCategory } from '../../../../shared'
 
-const jobHandlers: { [ handlerName: string ]: JobHandler<any> } = {
+type HTTPRequestPayload = {
+  uris: string[]
+  body: any
+}
+const jobHandlers: { [ handlerName: string ]: JobHandler<HTTPRequestPayload, void> } = {
   httpRequestBroadcastHandler,
   httpRequestUnicastHandler
 }
@@ -13,5 +17,6 @@ const jobCategory: JobCategory = 'http-request'
 const httpRequestJobScheduler = new JobScheduler(jobCategory, jobHandlers)
 
 export {
+  HTTPRequestPayload,
   httpRequestJobScheduler
 }
index 6b6946d02c0410f54fa7b2f557830f8264d92361..13451f042d50840eadc62fb8ff39802b90cc2dc3 100644 (file)
@@ -1,19 +1,26 @@
-import * as Bluebird from 'bluebird'
-
-import { database as db } from '../../../initializers/database'
 import { logger } from '../../../helpers'
+import { doRequest } from '../../../helpers/requests'
+import { HTTPRequestPayload } from './http-request-job-scheduler'
+
+async function process (payload: HTTPRequestPayload, jobId: number) {
+  logger.info('Processing unicast in job %d.', jobId)
 
-async function process (data: { videoUUID: string }, jobId: number) {
+  const uri = payload.uris[0]
+  const options = {
+    uri,
+    json: payload.body
+  }
 
+  await doRequest(options)
 }
 
 function onError (err: Error, jobId: number) {
-  logger.error('Error when optimized video file in job %d.', jobId, err)
+  logger.error('Error when sending request in job %d.', jobId, err)
   return Promise.resolve()
 }
 
 async function onSuccess (jobId: number) {
-
+  logger.info('Job %d is a success.', jobId)
 }
 
 // ---------------------------------------------------------------------------
index 89a4bca8821f4fc1767512f3279821729f3f9ebf..f10f745b3f53e3742bae46dc8645dfd2fbf3727b 100644 (file)
@@ -1,28 +1,22 @@
 import { AsyncQueue, forever, queue } from 'async'
 import * as Sequelize from 'sequelize'
-
-import {
-  database as db,
-  JOBS_FETCHING_INTERVAL,
-  JOBS_FETCH_LIMIT_PER_CYCLE,
-  JOB_STATES
-} from '../../initializers'
+import { JobCategory } from '../../../shared'
 import { logger } from '../../helpers'
+import { database as db, JOB_STATES, JOBS_FETCH_LIMIT_PER_CYCLE, JOBS_FETCHING_INTERVAL } from '../../initializers'
 import { JobInstance } from '../../models'
-import { JobCategory } from '../../../shared'
 
-export interface JobHandler<T> {
-  process (data: object, jobId: number): T
+export interface JobHandler<P, T> {
+  process (data: object, jobId: number): Promise<T>
   onError (err: Error, jobId: number)
-  onSuccess (jobId: number, jobResult: T)
+  onSuccess (jobId: number, jobResult: T, jobScheduler: JobScheduler<P, T>)
 }
 type JobQueueCallback = (err: Error) => void
 
-class JobScheduler<T> {
+class JobScheduler<P, T> {
 
   constructor (
     private jobCategory: JobCategory,
-    private jobHandlers: { [ id: string ]: JobHandler<T> }
+    private jobHandlers: { [ id: string ]: JobHandler<P, T> }
   ) {}
 
   async activate () {
@@ -66,13 +60,14 @@ class JobScheduler<T> {
     )
   }
 
-  createJob (transaction: Sequelize.Transaction, category: JobCategory, handlerName: string, handlerInputData: object) {
+  createJob (transaction: Sequelize.Transaction, handlerName: string, handlerInputData: P) {
     const createQuery = {
       state: JOB_STATES.PENDING,
-      category,
+      category: this.jobCategory,
       handlerName,
       handlerInputData
     }
+
     const options = { transaction }
 
     return db.Job.create(createQuery, options)
@@ -95,7 +90,7 @@ class JobScheduler<T> {
     await job.save()
 
     try {
-      const result = await jobHandler.process(job.handlerInputData, job.id)
+      const result: T = await jobHandler.process(job.handlerInputData, job.id)
       await this.onJobSuccess(jobHandler, job, result)
     } catch (err) {
       logger.error('Error in job handler %s.', job.handlerName, err)
@@ -111,7 +106,7 @@ class JobScheduler<T> {
     callback(null)
   }
 
-  private async onJobError (jobHandler: JobHandler<any>, job: JobInstance, err: Error) {
+  private async onJobError (jobHandler: JobHandler<P, T>, job: JobInstance, err: Error) {
     job.state = JOB_STATES.ERROR
 
     try {
@@ -122,12 +117,12 @@ class JobScheduler<T> {
     }
   }
 
-  private async onJobSuccess (jobHandler: JobHandler<any>, job: JobInstance, jobResult: any) {
+  private async onJobSuccess (jobHandler: JobHandler<P, T>, job: JobInstance, jobResult: T) {
     job.state = JOB_STATES.SUCCESS
 
     try {
       await job.save()
-      jobHandler.onSuccess(job.id, jobResult)
+      jobHandler.onSuccess(job.id, jobResult, this)
     } catch (err) {
       this.cannotSaveJobError(err)
     }
index d7c614fb8873744b2e1da20e3c964b06d36fb1e6..c5efe8eeb174e0fe9977872342a4cac033cbb61d 100644 (file)
@@ -1,10 +1,14 @@
-import { JobScheduler, JobHandler } from '../job-scheduler'
-
+import { JobCategory } from '../../../../shared'
+import { JobHandler, JobScheduler } from '../job-scheduler'
 import * as videoFileOptimizer from './video-file-optimizer-handler'
 import * as videoFileTranscoder from './video-file-transcoder-handler'
-import { JobCategory } from '../../../../shared'
+import { VideoInstance } from '../../../models/video/video-interface'
 
-const jobHandlers: { [ handlerName: string ]: JobHandler<any> } = {
+type TranscodingJobPayload = {
+  videoUUID: string
+  resolution?: number
+}
+const jobHandlers: { [ handlerName: string ]: JobHandler<TranscodingJobPayload, VideoInstance> } = {
   videoFileOptimizer,
   videoFileTranscoder
 }
@@ -13,5 +17,6 @@ const jobCategory: JobCategory = 'transcoding'
 const transcodingJobScheduler = new JobScheduler(jobCategory, jobHandlers)
 
 export {
+  TranscodingJobPayload,
   transcodingJobScheduler
 }
index f019c28bc8d168a0ee22f80dc58828bb73fab2d2..47603a66c527a4e44fac0c1d12e5a2c73028a36c 100644 (file)
@@ -1,12 +1,13 @@
 import * as Bluebird from 'bluebird'
+import { computeResolutionsToTranscode, logger } from '../../../helpers'
 
 import { database as db } from '../../../initializers/database'
-import { logger, computeResolutionsToTranscode } from '../../../helpers'
 import { VideoInstance } from '../../../models'
-import { addVideoToFriends } from '../../friends'
+import { sendAddVideo } from '../../activitypub/send-request'
 import { JobScheduler } from '../job-scheduler'
+import { TranscodingJobPayload } from './transcoding-job-scheduler'
 
-async function process (data: { videoUUID: string }, jobId: number) {
+async function process (data: TranscodingJobPayload, jobId: number) {
   const video = await db.Video.loadByUUIDAndPopulateAccountAndPodAndTags(data.videoUUID)
   // No video, maybe deleted?
   if (!video) {
@@ -24,7 +25,7 @@ function onError (err: Error, jobId: number) {
   return Promise.resolve()
 }
 
-async function onSuccess (jobId: number, video: VideoInstance) {
+async function onSuccess (jobId: number, video: VideoInstance, jobScheduler: JobScheduler<TranscodingJobPayload, VideoInstance>) {
   if (video === undefined) return undefined
 
   logger.info('Job %d is a success.', jobId)
@@ -34,10 +35,8 @@ async function onSuccess (jobId: number, video: VideoInstance) {
   // Video does not exist anymore
   if (!videoDatabase) return undefined
 
-  const remoteVideo = await videoDatabase.toAddRemoteJSON()
-
-  // Now we'll add the video's meta data to our friends
-  await addVideoToFriends(remoteVideo, null)
+  // Now we'll add the video's meta data to our followers
+  await sendAddVideo(video, undefined)
 
   const originalFileHeight = await videoDatabase.getOriginalFileHeight()
   // Create transcoding jobs if there are enabled resolutions
@@ -59,7 +58,7 @@ async function onSuccess (jobId: number, video: VideoInstance) {
             resolution
           }
 
-          const p = JobScheduler.Instance.createJob(t, 'videoFileTranscoder', dataInput)
+          const p = jobScheduler.createJob(t, 'videoFileTranscoder', dataInput)
           tasks.push(p)
         }
 
index 397b95795d9965765fa641502aca21e9913c93e7..77e5d9f7f744cb73d13fa052d64dc79d649a0be5 100644 (file)
@@ -1,8 +1,8 @@
-import { database as db } from '../../../initializers/database'
-import { updateVideoToFriends } from '../../friends'
+import { VideoResolution } from '../../../../shared'
 import { logger } from '../../../helpers'
+import { database as db } from '../../../initializers/database'
 import { VideoInstance } from '../../../models'
-import { VideoResolution } from '../../../../shared'
+import { sendUpdateVideo } from '../../activitypub/send-request'
 
 async function process (data: { videoUUID: string, resolution: VideoResolution }, jobId: number) {
   const video = await db.Video.loadByUUIDAndPopulateAccountAndPodAndTags(data.videoUUID)
@@ -32,10 +32,7 @@ async function onSuccess (jobId: number, video: VideoInstance) {
   // Video does not exist anymore
   if (!videoDatabase) return undefined
 
-  const remoteVideo = videoDatabase.toUpdateRemoteJSON()
-
-  // Now we'll add the video's meta data to our friends
-  await updateVideoToFriends(remoteVideo, null)
+  await sendUpdateVideo(video, undefined)
 
   return undefined
 }
diff --git a/server/lib/request/abstract-request-scheduler.ts b/server/lib/request/abstract-request-scheduler.ts
deleted file mode 100644 (file)
index f838c47..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-import { isEmpty } from 'lodash'
-import * as Bluebird from 'bluebird'
-
-import { database as db } from '../../initializers/database'
-import { logger, makeSecureRequest } from '../../helpers'
-import { AbstractRequestClass, AbstractRequestToPodClass, PodInstance } from '../../models'
-import {
-  API_VERSION,
-  REQUESTS_IN_PARALLEL,
-  REQUESTS_INTERVAL
-} from '../../initializers'
-
-interface RequestsObjects<U> {
-  [ id: string ]: {
-    toPod: PodInstance
-    endpoint: string
-    ids: number[] // ids
-    datas: U[]
-  }
-}
-
-abstract class AbstractRequestScheduler <T> {
-  requestInterval: number
-  limitPods: number
-  limitPerPod: number
-
-  protected lastRequestTimestamp: number
-  protected timer: NodeJS.Timer
-  protected description: string
-
-  constructor () {
-    this.lastRequestTimestamp = 0
-    this.timer = null
-    this.requestInterval = REQUESTS_INTERVAL
-  }
-
-  abstract getRequestModel (): AbstractRequestClass<T>
-  abstract getRequestToPodModel (): AbstractRequestToPodClass
-  abstract buildRequestsObjects (requestsGrouped: T): RequestsObjects<any>
-
-  activate () {
-    logger.info('Requests scheduler activated.')
-    this.lastRequestTimestamp = Date.now()
-
-    this.timer = setInterval(() => {
-      this.lastRequestTimestamp = Date.now()
-      this.makeRequests()
-    }, this.requestInterval)
-  }
-
-  deactivate () {
-    logger.info('Requests scheduler deactivated.')
-    clearInterval(this.timer)
-    this.timer = null
-  }
-
-  forceSend () {
-    logger.info('Force requests scheduler sending.')
-    this.makeRequests()
-  }
-
-  remainingMilliSeconds () {
-    if (this.timer === null) return -1
-
-    return REQUESTS_INTERVAL - (Date.now() - this.lastRequestTimestamp)
-  }
-
-  remainingRequestsCount () {
-    return this.getRequestModel().countTotalRequests()
-  }
-
-  flush () {
-    return this.getRequestModel().removeAll()
-  }
-
-  // ---------------------------------------------------------------------------
-
-  // Make a requests to friends of a certain type
-  protected async makeRequest (toPod: PodInstance, requestEndpoint: string, requestsToMake: any) {
-    const params = {
-      toPod: toPod,
-      method: 'POST' as 'POST',
-      path: '/api/' + API_VERSION + '/remote/' + requestEndpoint,
-      data: requestsToMake // Requests we need to make
-    }
-
-    // Make multiple retry requests to all of pods
-    // The function fire some useful callbacks
-    try {
-      const { response } = await makeSecureRequest(params)
-
-      // 400 because if the other pod is not up to date, it may not understand our request
-      if ([ 200, 201, 204, 400 ].indexOf(response.statusCode) === -1) {
-        throw new Error('Status code not 20x or 400 : ' + response.statusCode)
-      }
-    } catch (err) {
-      logger.error('Error sending secure request to %s pod.', toPod.host, err)
-
-      throw err
-    }
-  }
-
-    // Make all the requests of the scheduler
-  protected async makeRequests () {
-    let requestsGrouped: T
-
-    try {
-      requestsGrouped = await this.getRequestModel().listWithLimitAndRandom(this.limitPods, this.limitPerPod)
-    } catch (err) {
-      logger.error('Cannot get the list of "%s".', this.description, { error: err.stack })
-      throw err
-    }
-
-    // We want to group requests by destinations pod and endpoint
-    const requestsToMake = this.buildRequestsObjects(requestsGrouped)
-
-    // If there are no requests, abort
-    if (isEmpty(requestsToMake) === true) {
-      logger.info('No "%s" to make.', this.description)
-      return { goodPods: [], badPods: [] }
-    }
-
-    logger.info('Making "%s" to friends.', this.description)
-
-    const goodPods: number[] = []
-    const badPods: number[] = []
-
-    await Bluebird.map(Object.keys(requestsToMake), async hashKey => {
-      const requestToMake = requestsToMake[hashKey]
-      const toPod: PodInstance = requestToMake.toPod
-
-      try {
-        await this.makeRequest(toPod, requestToMake.endpoint, requestToMake.datas)
-        logger.debug('Removing requests for pod %s.', requestToMake.toPod.id, { requestsIds: requestToMake.ids })
-        goodPods.push(requestToMake.toPod.id)
-
-        this.afterRequestHook()
-
-        // Remove the pod id of these request ids
-        await this.getRequestToPodModel()
-          .removeByRequestIdsAndPod(requestToMake.ids, requestToMake.toPod.id)
-      } catch (err) {
-        badPods.push(requestToMake.toPod.id)
-        logger.info('Cannot make request to %s.', toPod.host, err)
-      }
-    }, { concurrency: REQUESTS_IN_PARALLEL })
-
-    this.afterRequestsHook()
-
-    // All the requests were made, we update the pods score
-    db.Pod.updatePodsScore(goodPods, badPods)
-  }
-
-  protected afterRequestHook () {
-   // Nothing to do, let children re-implement it
-  }
-
-  protected afterRequestsHook () {
-   // Nothing to do, let children re-implement it
-  }
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  AbstractRequestScheduler,
-  RequestsObjects
-}
diff --git a/server/lib/request/index.ts b/server/lib/request/index.ts
deleted file mode 100644 (file)
index 47d60e5..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-export * from './abstract-request-scheduler'
-export * from './request-scheduler'
-export * from './request-video-event-scheduler'
-export * from './request-video-qadu-scheduler'
diff --git a/server/lib/request/request-scheduler.ts b/server/lib/request/request-scheduler.ts
deleted file mode 100644 (file)
index c3f7f64..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-import * as Sequelize from 'sequelize'
-
-import { database as db } from '../../initializers/database'
-import { AbstractRequestScheduler, RequestsObjects } from './abstract-request-scheduler'
-import { logger } from '../../helpers'
-import { REQUESTS_LIMIT_PODS, REQUESTS_LIMIT_PER_POD } from '../../initializers'
-import { RequestsGrouped } from '../../models'
-import { RequestEndpoint, RemoteVideoRequest } from '../../../shared'
-
-export type RequestSchedulerOptions = {
-  type: string
-  endpoint: RequestEndpoint
-  data: Object
-  toIds: number[]
-  transaction: Sequelize.Transaction
-}
-
-class RequestScheduler extends AbstractRequestScheduler<RequestsGrouped> {
-  constructor () {
-    super()
-
-    // We limit the size of the requests
-    this.limitPods = REQUESTS_LIMIT_PODS
-    this.limitPerPod = REQUESTS_LIMIT_PER_POD
-
-    this.description = 'requests'
-  }
-
-  getRequestModel () {
-    return db.Request
-  }
-
-  getRequestToPodModel () {
-    return db.RequestToPod
-  }
-
-  buildRequestsObjects (requestsGrouped: RequestsGrouped) {
-    const requestsToMakeGrouped: RequestsObjects<RemoteVideoRequest> = {}
-
-    for (const toPodId of Object.keys(requestsGrouped)) {
-      for (const data of requestsGrouped[toPodId]) {
-        const request = data.request
-        const pod = data.pod
-        const hashKey = toPodId + request.endpoint
-
-        if (!requestsToMakeGrouped[hashKey]) {
-          requestsToMakeGrouped[hashKey] = {
-            toPod: pod,
-            endpoint: request.endpoint,
-            ids: [], // request ids, to delete them from the DB in the future
-            datas: [] // requests data,
-          }
-        }
-
-        requestsToMakeGrouped[hashKey].ids.push(request.id)
-        requestsToMakeGrouped[hashKey].datas.push(request.request)
-      }
-    }
-
-    return requestsToMakeGrouped
-  }
-
-  async createRequest ({ type, endpoint, data, toIds, transaction }: RequestSchedulerOptions) {
-    // If there are no destination pods abort
-    if (toIds.length === 0) return undefined
-
-    const createQuery = {
-      endpoint,
-      request: {
-        type: type,
-        data: data
-      }
-    }
-
-    const dbRequestOptions: Sequelize.CreateOptions = {
-      transaction
-    }
-
-    const request = await db.Request.create(createQuery, dbRequestOptions)
-    await request.setPods(toIds, dbRequestOptions)
-  }
-
-  // ---------------------------------------------------------------------------
-
-  afterRequestsHook () {
-    // Flush requests with no pod
-    this.getRequestModel().removeWithEmptyTo()
-      .catch(err => logger.error('Error when removing requests with no pods.', err))
-  }
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  RequestScheduler
-}
diff --git a/server/lib/request/request-video-event-scheduler.ts b/server/lib/request/request-video-event-scheduler.ts
deleted file mode 100644 (file)
index 5f21287..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-import * as Sequelize from 'sequelize'
-
-import { database as db } from '../../initializers/database'
-import { AbstractRequestScheduler, RequestsObjects } from './abstract-request-scheduler'
-import {
-  REQUESTS_VIDEO_EVENT_LIMIT_PODS,
-  REQUESTS_VIDEO_EVENT_LIMIT_PER_POD,
-  REQUEST_VIDEO_EVENT_ENDPOINT
-} from '../../initializers'
-import { RequestsVideoEventGrouped } from '../../models'
-import { RequestVideoEventType, RemoteVideoEventRequest, RemoteVideoEventType } from '../../../shared'
-
-export type RequestVideoEventSchedulerOptions = {
-  type: RequestVideoEventType
-  videoId: number
-  count?: number
-  transaction?: Sequelize.Transaction
-}
-
-class RequestVideoEventScheduler extends AbstractRequestScheduler<RequestsVideoEventGrouped> {
-  constructor () {
-    super()
-
-    // We limit the size of the requests
-    this.limitPods = REQUESTS_VIDEO_EVENT_LIMIT_PODS
-    this.limitPerPod = REQUESTS_VIDEO_EVENT_LIMIT_PER_POD
-
-    this.description = 'video event requests'
-  }
-
-  getRequestModel () {
-    return db.RequestVideoEvent
-  }
-
-  getRequestToPodModel () {
-    return db.RequestVideoEvent
-  }
-
-  buildRequestsObjects (eventRequests: RequestsVideoEventGrouped) {
-    const requestsToMakeGrouped: RequestsObjects<RemoteVideoEventRequest> = {}
-
-    /* Example:
-        {
-          pod1: {
-            video1: { views: 4, likes: 5 },
-            video2: { likes: 5 }
-          }
-        }
-    */
-    const eventsPerVideoPerPod: {
-      [ podId: string ]: {
-        [ videoUUID: string ]: {
-          views?: number
-          likes?: number
-          dislikes?: number
-        }
-      }
-    } = {}
-
-    // We group video events per video and per pod
-    // We add the counts of the same event types
-    for (const toPodId of Object.keys(eventRequests)) {
-      for (const eventToProcess of eventRequests[toPodId]) {
-        if (!eventsPerVideoPerPod[toPodId]) eventsPerVideoPerPod[toPodId] = {}
-
-        if (!requestsToMakeGrouped[toPodId]) {
-          requestsToMakeGrouped[toPodId] = {
-            toPod: eventToProcess.pod,
-            endpoint: REQUEST_VIDEO_EVENT_ENDPOINT,
-            ids: [], // request ids, to delete them from the DB in the future
-            datas: [] // requests data
-          }
-        }
-        requestsToMakeGrouped[toPodId].ids.push(eventToProcess.id)
-
-        const eventsPerVideo = eventsPerVideoPerPod[toPodId]
-        const uuid = eventToProcess.video.uuid
-        if (!eventsPerVideo[uuid]) eventsPerVideo[uuid] = {}
-
-        const events = eventsPerVideo[uuid]
-        if (!events[eventToProcess.type]) events[eventToProcess.type] = 0
-
-        events[eventToProcess.type] += eventToProcess.count
-      }
-    }
-
-    // Now we build our requests array per pod
-    for (const toPodId of Object.keys(eventsPerVideoPerPod)) {
-      const eventsForPod = eventsPerVideoPerPod[toPodId]
-
-      for (const uuid of Object.keys(eventsForPod)) {
-        const eventsForVideo = eventsForPod[uuid]
-
-        for (const eventType of Object.keys(eventsForVideo)) {
-          requestsToMakeGrouped[toPodId].datas.push({
-            data: {
-              uuid,
-              eventType: eventType as RemoteVideoEventType,
-              count: +eventsForVideo[eventType]
-            }
-          })
-        }
-      }
-    }
-
-    return requestsToMakeGrouped
-  }
-
-  createRequest ({ type, videoId, count, transaction }: RequestVideoEventSchedulerOptions) {
-    if (count === undefined) count = 1
-
-    const dbRequestOptions: Sequelize.CreateOptions = {}
-    if (transaction) dbRequestOptions.transaction = transaction
-
-    const createQuery = {
-      type,
-      count,
-      videoId
-    }
-
-    return db.RequestVideoEvent.create(createQuery, dbRequestOptions)
-  }
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  RequestVideoEventScheduler
-}
diff --git a/server/lib/request/request-video-qadu-scheduler.ts b/server/lib/request/request-video-qadu-scheduler.ts
deleted file mode 100644 (file)
index 24ee59d..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-import * as Sequelize from 'sequelize'
-
-import { database as db } from '../../initializers/database'
-import { AbstractRequestScheduler, RequestsObjects } from './abstract-request-scheduler'
-import { logger } from '../../helpers'
-import {
-  REQUESTS_VIDEO_QADU_LIMIT_PODS,
-  REQUESTS_VIDEO_QADU_LIMIT_PER_POD,
-  REQUEST_VIDEO_QADU_ENDPOINT,
-  REQUEST_VIDEO_QADU_TYPES
-} from '../../initializers'
-import { RequestsVideoQaduGrouped, PodInstance } from '../../models'
-import { RemoteQaduVideoRequest, RequestVideoQaduType } from '../../../shared'
-
-// We create a custom interface because we need "videos" attribute for our computations
-interface RequestsObjectsCustom<U> extends RequestsObjects<U> {
-  [ id: string ]: {
-    toPod: PodInstance
-    endpoint: string
-    ids: number[] // ids
-    datas: U[]
-
-    videos: {
-      [ uuid: string ]: {
-        uuid: string
-        likes?: number
-        dislikes?: number
-        views?: number
-      }
-    }
-  }
-}
-
-export type RequestVideoQaduSchedulerOptions = {
-  type: RequestVideoQaduType
-  videoId: number
-  transaction?: Sequelize.Transaction
-}
-
-class RequestVideoQaduScheduler extends AbstractRequestScheduler<RequestsVideoQaduGrouped> {
-  constructor () {
-    super()
-
-    // We limit the size of the requests
-    this.limitPods = REQUESTS_VIDEO_QADU_LIMIT_PODS
-    this.limitPerPod = REQUESTS_VIDEO_QADU_LIMIT_PER_POD
-
-    this.description = 'video QADU requests'
-  }
-
-  getRequestModel () {
-    return db.RequestVideoQadu
-  }
-
-  getRequestToPodModel () {
-    return db.RequestVideoQadu
-  }
-
-  buildRequestsObjects (requests: RequestsVideoQaduGrouped) {
-    const requestsToMakeGrouped: RequestsObjectsCustom<RemoteQaduVideoRequest> = {}
-
-    for (const toPodId of Object.keys(requests)) {
-      for (const data of requests[toPodId]) {
-        const request = data.request
-        const video = data.video
-        const pod = data.pod
-        const hashKey = toPodId
-
-        if (!requestsToMakeGrouped[hashKey]) {
-          requestsToMakeGrouped[hashKey] = {
-            toPod: pod,
-            endpoint: REQUEST_VIDEO_QADU_ENDPOINT,
-            ids: [], // request ids, to delete them from the DB in the future
-            datas: [], // requests data
-            videos: {}
-          }
-        }
-
-        // Maybe another attribute was filled for this video
-        let videoData = requestsToMakeGrouped[hashKey].videos[video.id]
-        if (!videoData) videoData = { uuid: null }
-
-        switch (request.type) {
-        case REQUEST_VIDEO_QADU_TYPES.LIKES:
-          videoData.likes = video.likes
-          break
-
-        case REQUEST_VIDEO_QADU_TYPES.DISLIKES:
-          videoData.dislikes = video.dislikes
-          break
-
-        case REQUEST_VIDEO_QADU_TYPES.VIEWS:
-          videoData.views = video.views
-          break
-
-        default:
-          logger.error('Unknown request video QADU type %s.', request.type)
-          return undefined
-        }
-
-        // Do not forget the uuid so the remote pod can identify the video
-        videoData.uuid = video.uuid
-        requestsToMakeGrouped[hashKey].ids.push(request.id)
-
-        // Maybe there are multiple quick and dirty update for the same video
-        // We use this hash map to dedupe them
-        requestsToMakeGrouped[hashKey].videos[video.id] = videoData
-      }
-    }
-
-    // Now we deduped similar quick and dirty updates, we can build our requests data
-    for (const hashKey of Object.keys(requestsToMakeGrouped)) {
-      for (const videoUUID of Object.keys(requestsToMakeGrouped[hashKey].videos)) {
-        const videoData = requestsToMakeGrouped[hashKey].videos[videoUUID]
-
-        requestsToMakeGrouped[hashKey].datas.push({
-          data: videoData
-        })
-      }
-
-      // We don't need it anymore, it was just to build our data array
-      delete requestsToMakeGrouped[hashKey].videos
-    }
-
-    return requestsToMakeGrouped
-  }
-
-  async createRequest ({ type, videoId, transaction }: RequestVideoQaduSchedulerOptions) {
-    const dbRequestOptions: Sequelize.BulkCreateOptions = {}
-    if (transaction) dbRequestOptions.transaction = transaction
-
-    // Send the update to all our friends
-    const podIds = await db.Pod.listAllIds(transaction)
-    const queries = []
-    for (const podId of podIds) {
-      queries.push({ type, videoId, podId })
-    }
-
-    await db.RequestVideoQadu.bulkCreate(queries, dbRequestOptions)
-    return undefined
-  }
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  RequestVideoQaduScheduler
-}
index 57c653e5570010262ccf9d56371c8511729a2a9b..1094c2401de8b6a2dd9a423f937d2efe64ff55fd 100644 (file)
@@ -1,6 +1,9 @@
+import * as Sequelize from 'sequelize'
+import { getActivityPubUrl } from '../helpers/activitypub'
+import { createPrivateAndPublicKeys } from '../helpers/peertube-crypto'
 import { database as db } from '../initializers'
+import { CONFIG } from '../initializers/constants'
 import { UserInstance } from '../models'
-import { addVideoAccountToFriends } from './friends'
 import { createVideoChannel } from './video-channel'
 
 async function createUserAccountAndChannel (user: UserInstance, validateUser = true) {
@@ -11,32 +14,46 @@ async function createUserAccountAndChannel (user: UserInstance, validateUser = t
     }
 
     const userCreated = await user.save(userOptions)
-    const accountInstance = db.Account.build({
-      name: userCreated.username,
-      podId: null, // It is our pod
-      userId: userCreated.id
-    })
-
-    const accountCreated = await accountInstance.save({ transaction: t })
-
-    const remoteVideoAccount = accountCreated.toAddRemoteJSON()
-
-    // Now we'll add the video channel's meta data to our friends
-    const account = await addVideoAccountToFriends(remoteVideoAccount, t)
+    const accountCreated = await createLocalAccount(user.username, user.id, null, t)
 
     const videoChannelInfo = {
       name: `Default ${userCreated.username} channel`
     }
     const videoChannel = await createVideoChannel(videoChannelInfo, accountCreated, t)
 
-    return { account, videoChannel }
+    return { account: accountCreated, videoChannel }
   })
 
   return res
 }
 
+async function createLocalAccount (name: string, userId: number, applicationId: number, t: Sequelize.Transaction) {
+  const { publicKey, privateKey } = await createPrivateAndPublicKeys()
+  const url = getActivityPubUrl('account', name)
+
+  const accountInstance = db.Account.build({
+    name,
+    url,
+    publicKey,
+    privateKey,
+    followersCount: 0,
+    followingCount: 0,
+    inboxUrl: url + '/inbox',
+    outboxUrl: url + '/outbox',
+    sharedInboxUrl: CONFIG.WEBSERVER.URL + '/inbox',
+    followersUrl: url + '/followers',
+    followingUrl: url + '/following',
+    userId,
+    applicationId,
+    podId: null // It is our pod
+  })
+
+  return accountInstance.save({ transaction: t })
+}
+
 // ---------------------------------------------------------------------------
 
 export {
-  createUserAccountAndChannel
+  createUserAccountAndChannel,
+  createLocalAccount
 }
index f81383ce86340dbdc095eca1b0a53e646a063b20..459d9d4a8456cf7bb7b3dc8a56137cb475949b9d 100644 (file)
@@ -1,10 +1,10 @@
 import * as Sequelize from 'sequelize'
 
-import { addVideoChannelToFriends } from './friends'
 import { database as db } from '../initializers'
 import { logger } from '../helpers'
 import { AccountInstance } from '../models'
 import { VideoChannelCreate } from '../../shared/models'
+import { sendCreateVideoChannel } from './activitypub/send-request'
 
 async function createVideoChannel (videoChannelInfo: VideoChannelCreate, account: AccountInstance, t: Sequelize.Transaction) {
   const videoChannelData = {
@@ -22,10 +22,7 @@ async function createVideoChannel (videoChannelInfo: VideoChannelCreate, account
   // Do not forget to add Account information to the created video channel
   videoChannelCreated.Account = account
 
-  const remoteVideoChannel = videoChannelCreated.toAddRemoteJSON()
-
-  // Now we'll add the video channel's meta data to our friends
-  await addVideoChannelToFriends(remoteVideoChannel, t)
+  sendCreateVideoChannel(videoChannelCreated, t)
 
   return videoChannelCreated
 }
index f1f26043e8df406dcd4e5dc2f88fedd5544926d1..84d1107fcd047c4ee3f6e74531717c5da16d3376 100644 (file)
@@ -1,3 +1,2 @@
-export * from './pods'
+export * from './activity'
 export * from './signature'
-export * from './videos'
diff --git a/server/middlewares/validators/activitypub/pods.ts b/server/middlewares/validators/activitypub/pods.ts
deleted file mode 100644 (file)
index f917b61..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-import { body } from 'express-validator/check'
-import * as express from 'express'
-
-import { database as db } from '../../../initializers'
-import { isHostValid, logger } from '../../../helpers'
-import { checkErrors } from '../utils'
-
-const remotePodsAddValidator = [
-  body('host').custom(isHostValid).withMessage('Should have a host'),
-  body('email').isEmail().withMessage('Should have an email'),
-  body('publicKey').not().isEmpty().withMessage('Should have a public key'),
-
-  (req: express.Request, res: express.Response, next: express.NextFunction) => {
-    logger.debug('Checking podsAdd parameters', { parameters: req.body })
-
-    checkErrors(req, res, () => {
-      db.Pod.loadByHost(req.body.host)
-        .then(pod => {
-          // Pod with this host already exists
-          if (pod) {
-            return res.sendStatus(409)
-          }
-
-          return next()
-        })
-        .catch(err => {
-          logger.error('Cannot load pod by host.', err)
-          res.sendStatus(500)
-        })
-    })
-  }
-]
-
-// ---------------------------------------------------------------------------
-
-export {
-  remotePodsAddValidator
-}
index 46c00d679e998ebdc9c5a95aaf4bb6ace1baa0a7..0b7573d4fac1caae17d221e66e3381281c270ce0 100644 (file)
@@ -2,7 +2,6 @@ export * from './account'
 export * from './oembed'
 export * from './activitypub'
 export * from './pagination'
-export * from './pods'
 export * from './sort'
 export * from './users'
 export * from './videos'
diff --git a/server/middlewares/validators/pods.ts b/server/middlewares/validators/pods.ts
deleted file mode 100644 (file)
index 8465fea..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-import { body, param } from 'express-validator/check'
-import * as express from 'express'
-
-import { database as db } from '../../initializers/database'
-import { checkErrors } from './utils'
-import { logger, isEachUniqueHostValid, isTestInstance } from '../../helpers'
-import { CONFIG } from '../../initializers'
-import { hasFriends } from '../../lib'
-
-const makeFriendsValidator = [
-  body('hosts').custom(isEachUniqueHostValid).withMessage('Should have an array of unique hosts'),
-
-  (req: express.Request, res: express.Response, next: express.NextFunction) => {
-    // Force https if the administrator wants to make friends
-    if (isTestInstance() === false && CONFIG.WEBSERVER.SCHEME === 'http') {
-      return res.status(400)
-                .json({
-                  error: 'Cannot make friends with a non HTTPS web server.'
-                })
-                .end()
-    }
-
-    logger.debug('Checking makeFriends parameters', { parameters: req.body })
-
-    checkErrors(req, res, () => {
-      hasFriends()
-        .then(heHasFriends => {
-          if (heHasFriends === true) {
-            // We need to quit our friends before make new ones
-            return res.sendStatus(409)
-          }
-
-          return next()
-        })
-        .catch(err => {
-          logger.error('Cannot know if we have friends.', err)
-          res.sendStatus(500)
-        })
-    })
-  }
-]
-
-const podRemoveValidator = [
-  param('id').isNumeric().not().isEmpty().withMessage('Should have a valid id'),
-
-  (req: express.Request, res: express.Response, next: express.NextFunction) => {
-    logger.debug('Checking podRemoveValidator parameters', { parameters: req.params })
-
-    checkErrors(req, res, () => {
-      db.Pod.load(req.params.id)
-        .then(pod => {
-          if (!pod) {
-            logger.error('Cannot find pod %d.', req.params.id)
-            return res.sendStatus(404)
-          }
-
-          res.locals.pod = pod
-          return next()
-        })
-        .catch(err => {
-          logger.error('Cannot load pod %d.', req.params.id, err)
-          res.sendStatus(500)
-        })
-    })
-  }
-]
-
-// ---------------------------------------------------------------------------
-
-export {
-  makeFriendsValidator,
-  podRemoveValidator
-}
index 2ef3e2246c53221ee7e5030e7eb43e5797244223..a662eb99269bc26eb9ef257a53d9c63988c425f9 100644 (file)
@@ -13,8 +13,8 @@ export namespace AccountMethods {
   export type LoadAccountByPodAndUUID = (uuid: string, podId: number, transaction: Sequelize.Transaction) => Bluebird<AccountInstance>
   export type LoadLocalAccountByName = (name: string) => Bluebird<AccountInstance>
   export type ListOwned = () => Bluebird<AccountInstance[]>
-  export type ListFollowerUrlsForApi = (name: string, start: number, count: number) => Promise< ResultList<string> >
-  export type ListFollowingUrlsForApi = (name: string, start: number, count: number) => Promise< ResultList<string> >
+  export type ListFollowerUrlsForApi = (name: string, start: number, count?: number) => Promise< ResultList<string> >
+  export type ListFollowingUrlsForApi = (name: string, start: number, count?: number) => Promise< ResultList<string> >
 
   export type ToActivityPubObject = (this: AccountInstance) => ActivityPubActor
   export type IsOwned = (this: AccountInstance) => boolean
index 00c0aefd4627760b5cde6f3e3db926e4ccde7ffd..a79e13880f0f854e908fe8848e3060d49139b7f3 100644 (file)
@@ -268,14 +268,15 @@ function afterDestroy (account: AccountInstance) {
       uuid: account.uuid
     }
 
-    return removeVideoAccountToFriends(removeVideoAccountToFriendsParams)
+    // FIXME: remove account in followers
+    // return removeVideoAccountToFriends(removeVideoAccountToFriendsParams)
   }
 
   return undefined
 }
 
 toActivityPubObject = function (this: AccountInstance) {
-  const type = this.podId ? 'Application' : 'Person'
+  const type = this.podId ? 'Application' as 'Application' : 'Person' as 'Person'
 
   const json = {
     type,
@@ -346,11 +347,11 @@ listOwned = function () {
   return Account.findAll(query)
 }
 
-listFollowerUrlsForApi = function (name: string, start: number, count: number) {
+listFollowerUrlsForApi = function (name: string, start: number, count?: number) {
   return createListFollowForApiQuery('followers', name, start, count)
 }
 
-listFollowingUrlsForApi = function (name: string, start: number, count: number) {
+listFollowingUrlsForApi = function (name: string, start: number, count?: number) {
   return createListFollowForApiQuery('following', name, start, count)
 }
 
@@ -405,7 +406,7 @@ loadAccountByPodAndUUID = function (uuid: string, podId: number, transaction: Se
 
 // ------------------------------ UTILS ------------------------------
 
-async function createListFollowForApiQuery (type: 'followers' | 'following', name: string, start: number, count: number) {
+async function createListFollowForApiQuery (type: 'followers' | 'following', name: string, start: number, count?: number) {
   let firstJoin: string
   let secondJoin: string
 
@@ -421,11 +422,13 @@ async function createListFollowForApiQuery (type: 'followers' | 'following', nam
   const tasks: Promise<any>[] = []
 
   for (const selection of selections) {
-    const query = 'SELECT ' + selection + ' FROM "Account" ' +
+    let query = 'SELECT ' + selection + ' FROM "Account" ' +
       'INNER JOIN "AccountFollower" ON "AccountFollower"."' + firstJoin + '" = "Account"."id" ' +
       'INNER JOIN "Account" AS "Followers" ON "Followers"."id" = "AccountFollower"."' + secondJoin + '" ' +
       'WHERE "Account"."name" = \'$name\' ' +
-      'LIMIT ' + start + ', ' + count
+      'LIMIT ' + start
+
+    if (count !== undefined) query += ', ' + count
 
     const options = {
       bind: { name },
index 163930a4f93335f7b006470cdbf33adf84c2b8ce..411a05029e56fa2fe7e95da66f362177180a7594 100644 (file)
@@ -14,7 +14,7 @@ export interface JobClass {
 export interface JobAttributes {
   state: JobState
   handlerName: string
-  handlerInputData: object
+  handlerInputData: any
 }
 
 export interface JobInstance extends JobClass, JobAttributes, Sequelize.Instance<JobAttributes> {
index 93a611fa03373154736a528beae477c30d760394..183ff34368b05425b8792ed04f41f518bcfb2599 100644 (file)
@@ -1,7 +1,6 @@
 import * as Sequelize from 'sequelize'
 
 import { isVideoChannelNameValid, isVideoChannelDescriptionValid } from '../../helpers'
-import { removeVideoChannelToFriends } from '../../lib'
 
 import { addMethodsToModel, getSort } from '../utils'
 import {
@@ -143,12 +142,13 @@ toFormattedJSON = function (this: VideoChannelInstance) {
 
 toActivityPubObject = function (this: VideoChannelInstance) {
   const json = {
+    type: 'VideoChannel' as 'VideoChannel',
+    id: this.url,
     uuid: this.uuid,
+    content: this.description,
     name: this.name,
-    description: this.description,
-    createdAt: this.createdAt,
-    updatedAt: this.updatedAt,
-    ownerUUID: this.Account.uuid
+    published: this.createdAt,
+    updated: this.updatedAt
   }
 
   return json
@@ -180,7 +180,7 @@ function afterDestroy (videoChannel: VideoChannelInstance) {
       uuid: videoChannel.uuid
     }
 
-    return removeVideoChannelToFriends(removeVideoChannelToFriendsParams)
+    // FIXME: send remove event to followers
   }
 
   return undefined
@@ -277,7 +277,7 @@ loadByUUIDOrUrl = function (uuid: string, url: string, t?: Sequelize.Transaction
         { uuid },
         { url }
       ]
-    },
+    }
   }
 
   if (t !== undefined) query.transaction = t
index b5d33334731d16728f13fbceae80b45304c24414..10ae5097c3cfbd1f008e56e078252b8b5aec2c82 100644 (file)
@@ -1,58 +1,52 @@
-import * as safeBuffer from 'safe-buffer'
-const Buffer = safeBuffer.Buffer
-import * as magnetUtil from 'magnet-uri'
 import { map, maxBy, truncate } from 'lodash'
+import * as magnetUtil from 'magnet-uri'
 import * as parseTorrent from 'parse-torrent'
 import { join } from 'path'
+import * as safeBuffer from 'safe-buffer'
 import * as Sequelize from 'sequelize'
-
-import { TagInstance } from './tag-interface'
+import { VideoPrivacy, VideoResolution } from '../../../shared'
+import { VideoTorrentObject } from '../../../shared/models/activitypub/objects/video-torrent-object'
 import {
-  logger,
-  isVideoNameValid,
+  createTorrentPromise,
+  generateImageFromVideoFile,
+  getActivityPubUrl,
+  getVideoFileHeight,
   isVideoCategoryValid,
-  isVideoLicenceValid,
-  isVideoLanguageValid,
-  isVideoNSFWValid,
   isVideoDescriptionValid,
   isVideoDurationValid,
+  isVideoLanguageValid,
+  isVideoLicenceValid,
+  isVideoNameValid,
+  isVideoNSFWValid,
   isVideoPrivacyValid,
-  readFileBufferPromise,
-  unlinkPromise,
+  logger,
   renamePromise,
-  writeFilePromise,
-  createTorrentPromise,
   statPromise,
-  generateImageFromVideoFile,
   transcode,
-  getVideoFileHeight,
-  getActivityPubUrl
+  unlinkPromise,
+  writeFilePromise
 } from '../../helpers'
 import {
+  API_VERSION,
   CONFIG,
+  CONSTRAINTS_FIELDS,
+  PREVIEWS_SIZE,
   REMOTE_SCHEME,
   STATIC_PATHS,
+  THUMBNAILS_SIZE,
   VIDEO_CATEGORIES,
-  VIDEO_LICENCES,
   VIDEO_LANGUAGES,
-  THUMBNAILS_SIZE,
-  PREVIEWS_SIZE,
-  CONSTRAINTS_FIELDS,
-  API_VERSION,
+  VIDEO_LICENCES,
   VIDEO_PRIVACIES
 } from '../../initializers'
-import { removeVideoToFriends } from '../../lib'
-import { VideoResolution, VideoPrivacy } from '../../../shared'
-import { VideoFileInstance, VideoFileModel } from './video-file-interface'
 
 import { addMethodsToModel, getSort } from '../utils'
-import {
-  VideoInstance,
-  VideoAttributes,
 
-  VideoMethods
-} from './video-interface'
-import { VideoTorrentObject } from '../../../shared/models/activitypub/objects/video-torrent-object'
+import { TagInstance } from './tag-interface'
+import { VideoFileInstance, VideoFileModel } from './video-file-interface'
+import { VideoAttributes, VideoInstance, VideoMethods } from './video-interface'
+
+const Buffer = safeBuffer.Buffer
 
 let Video: Sequelize.Model<VideoInstance, VideoAttributes>
 let getOriginalFile: VideoMethods.GetOriginalFile
@@ -374,8 +368,8 @@ function afterDestroy (video: VideoInstance) {
     }
 
     tasks.push(
-      video.removePreview(),
-      removeVideoToFriends(removeVideoToFriendsParams)
+      video.removePreview()
+      // FIXME: remove video for followers
     )
 
     // Remove physical files and torrents
@@ -566,7 +560,7 @@ toActivityPubObject = function (this: VideoInstance) {
   const { baseUrlHttp, baseUrlWs } = getBaseUrls(this)
 
   const tag = this.Tags.map(t => ({
-    type: 'Hashtag',
+    type: 'Hashtag' as 'Hashtag',
     name: t.name
   }))
 
@@ -596,7 +590,7 @@ toActivityPubObject = function (this: VideoInstance) {
   }
 
   const videoObject: VideoTorrentObject = {
-    type: 'Video',
+    type: 'Video' as 'Video',
     id: getActivityPubUrl('video', this.uuid),
     name: this.name,
     // https://www.w3.org/TR/activitystreams-vocabulary/#dfn-duration
@@ -604,15 +598,15 @@ toActivityPubObject = function (this: VideoInstance) {
     uuid: this.uuid,
     tag,
     category: {
-      id: this.category,
-      label: this.getCategoryLabel()
+      identifier: this.category + '',
+      name: this.getCategoryLabel()
     },
     licence: {
-      id: this.licence,
+      identifier: this.licence + '',
       name: this.getLicenceLabel()
     },
     language: {
-      id: this.language,
+      identifier: this.language + '',
       name: this.getLanguageLabel()
     },
     views: this.views,
index 601b527ef7a544b18ba910aa0e310f20365e9a71..b851d7185fdfc3e199d127fc6e8092c9b2c81ebc 100644 (file)
@@ -65,7 +65,7 @@ describe('Test a video channels', function () {
   })
 
   it('Should have two video channels when getting author channels', async () => {
-    const res = await getAuthorVideoChannelsList(server.url, userInfo.author.uuid)
+    const res = await getAuthorVideoChannelsList(server.url, userInfo.account.uuid)
 
     expect(res.body.total).to.equal(2)
     expect(res.body.data).to.be.an('array')
index dc562c00a4c366e86054dff81783c1d496827fcf..a2494da25af9a910be058725fc2bd0154e26d27f 100644 (file)
@@ -4,7 +4,7 @@ import {
 } from './objects'
 import { ActivityPubSignature } from './activitypub-signature'
 
-export type Activity = ActivityCreate | ActivityUpdate | ActivityFlag
+export type Activity = ActivityCreate | ActivityAdd | ActivityUpdate | ActivityFlag
 
 // Flag -> report abuse
 export type ActivityType = 'Create' | 'Add' | 'Update' | 'Flag'
index d254219364a6d8fa920562be65b5946fe85fde0f..ff9e8f2f5408e1c21a200645a2fb010d0e25f8d4 100644 (file)
@@ -1,7 +1,6 @@
 export interface Pod {
   id: number,
   host: string,
-  email: string,
   score: number,
   createdAt: Date
 }
index ee21475900bc054c17bfd46039573277792d03bb..a8012734ce33e5dd85fbbcb744a5a9e4dc2df3c9 100644 (file)
@@ -9,7 +9,7 @@ export interface User {
   role: UserRole
   videoQuota: number
   createdAt: Date,
-  author: {
+  account: {
     id: number
     uuid: string
   }
index 52685a8ccd27c2f9612483d51d3800e97cc5c478..773ff73500226a54d5719870c27710c51784d5d8 100644 (file)
--- a/yarn.lock
+++ b/yarn.lock
@@ -3473,12 +3473,6 @@ repeat-string@^1.5.2:
   version "1.6.1"
   resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
 
-request-replay@^1.0.2:
-  version "1.0.4"
-  resolved "https://registry.yarnpkg.com/request-replay/-/request-replay-1.0.4.tgz#b6e5953a7eb39fc8a48e8111c277d35355adfe06"
-  dependencies:
-    retry "^0.10.0"
-
 request@2.81.0:
   version "2.81.0"
   resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0"
@@ -3564,10 +3558,6 @@ retry-as-promised@^2.3.1:
     bluebird "^3.4.6"
     debug "^2.6.9"
 
-retry@^0.10.0:
-  version "0.10.1"
-  resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4"
-
 rimraf@2, rimraf@^2.2.8, rimraf@^2.4.2, rimraf@^2.5.1, rimraf@^2.5.4, rimraf@^2.6.1:
   version "2.6.2"
   resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36"