diff options
author | Chocobozzz <me@florianbigard.com> | 2018-04-18 15:32:40 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2018-04-18 15:32:40 +0200 |
commit | 5350fd8e5b2b2d017b16d97828893a8a4a40bd89 (patch) | |
tree | eddc20eeb19e1501ead0ad72b2fdaffc92708478 /server/controllers | |
parent | bf6e8e3e3dd6516a6125c9c2c12587e7bac8c107 (diff) | |
download | PeerTube-5350fd8e5b2b2d017b16d97828893a8a4a40bd89.tar.gz PeerTube-5350fd8e5b2b2d017b16d97828893a8a4a40bd89.tar.zst PeerTube-5350fd8e5b2b2d017b16d97828893a8a4a40bd89.zip |
Move server follow in the job queue
It helps to track follow errors
Diffstat (limited to 'server/controllers')
-rw-r--r-- | server/controllers/api/server/follows.ts | 78 |
1 files changed, 15 insertions, 63 deletions
diff --git a/server/controllers/api/server/follows.ts b/server/controllers/api/server/follows.ts index bb0063473..e78361c9a 100644 --- a/server/controllers/api/server/follows.ts +++ b/server/controllers/api/server/follows.ts | |||
@@ -1,20 +1,22 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import { UserRight } from '../../../../shared/models/users' | 2 | import { UserRight } from '../../../../shared/models/users' |
3 | import { sanitizeHost } from '../../../helpers/core-utils' | ||
4 | import { retryTransactionWrapper } from '../../../helpers/database-utils' | ||
5 | import { logger } from '../../../helpers/logger' | 3 | import { logger } from '../../../helpers/logger' |
6 | import { getFormattedObjects, getServerActor } from '../../../helpers/utils' | 4 | import { getFormattedObjects, getServerActor } from '../../../helpers/utils' |
7 | import { loadActorUrlOrGetFromWebfinger } from '../../../helpers/webfinger' | 5 | import { sequelizeTypescript } from '../../../initializers' |
8 | import { REMOTE_SCHEME, sequelizeTypescript, SERVER_ACTOR_NAME } from '../../../initializers' | 6 | import { sendUndoFollow } from '../../../lib/activitypub/send' |
9 | import { getOrCreateActorAndServerAndModel } from '../../../lib/activitypub/actor' | ||
10 | import { sendFollow, sendUndoFollow } from '../../../lib/activitypub/send' | ||
11 | import { | 7 | import { |
12 | asyncMiddleware, authenticate, ensureUserHasRight, paginationValidator, removeFollowingValidator, setBodyHostsPort, setDefaultSort, | 8 | asyncMiddleware, |
13 | setDefaultPagination | 9 | authenticate, |
10 | ensureUserHasRight, | ||
11 | paginationValidator, | ||
12 | removeFollowingValidator, | ||
13 | setBodyHostsPort, | ||
14 | setDefaultPagination, | ||
15 | setDefaultSort | ||
14 | } from '../../../middlewares' | 16 | } from '../../../middlewares' |
15 | import { followersSortValidator, followingSortValidator, followValidator } from '../../../middlewares/validators' | 17 | import { followersSortValidator, followingSortValidator, followValidator } from '../../../middlewares/validators' |
16 | import { ActorModel } from '../../../models/activitypub/actor' | ||
17 | import { ActorFollowModel } from '../../../models/activitypub/actor-follow' | 18 | import { ActorFollowModel } from '../../../models/activitypub/actor-follow' |
19 | import { JobQueue } from '../../../lib/job-queue' | ||
18 | 20 | ||
19 | const serverFollowsRouter = express.Router() | 21 | const serverFollowsRouter = express.Router() |
20 | serverFollowsRouter.get('/following', | 22 | serverFollowsRouter.get('/following', |
@@ -30,7 +32,7 @@ serverFollowsRouter.post('/following', | |||
30 | ensureUserHasRight(UserRight.MANAGE_SERVER_FOLLOW), | 32 | ensureUserHasRight(UserRight.MANAGE_SERVER_FOLLOW), |
31 | followValidator, | 33 | followValidator, |
32 | setBodyHostsPort, | 34 | setBodyHostsPort, |
33 | asyncMiddleware(followRetry) | 35 | asyncMiddleware(followInstance) |
34 | ) | 36 | ) |
35 | 37 | ||
36 | serverFollowsRouter.delete('/following/:host', | 38 | serverFollowsRouter.delete('/following/:host', |
@@ -70,67 +72,17 @@ async function listFollowers (req: express.Request, res: express.Response, next: | |||
70 | return res.json(getFormattedObjects(resultList.data, resultList.total)) | 72 | return res.json(getFormattedObjects(resultList.data, resultList.total)) |
71 | } | 73 | } |
72 | 74 | ||
73 | async function followRetry (req: express.Request, res: express.Response, next: express.NextFunction) { | 75 | async function followInstance (req: express.Request, res: express.Response, next: express.NextFunction) { |
74 | const hosts = req.body.hosts as string[] | 76 | const hosts = req.body.hosts as string[] |
75 | const fromActor = await getServerActor() | ||
76 | |||
77 | const tasks: Promise<any>[] = [] | ||
78 | const actorName = SERVER_ACTOR_NAME | ||
79 | 77 | ||
80 | for (const host of hosts) { | 78 | for (const host of hosts) { |
81 | const sanitizedHost = sanitizeHost(host, REMOTE_SCHEME.HTTP) | 79 | JobQueue.Instance.createJob({ type: 'activitypub-follow', payload: { host } }) |
82 | 80 | .catch(err => logger.error('Cannot create follow job for %s.', host, err)) | |
83 | // We process each host in a specific transaction | ||
84 | // First, we add the follow request in the database | ||
85 | // Then we send the follow request to other actor | ||
86 | const p = loadActorUrlOrGetFromWebfinger(actorName, sanitizedHost) | ||
87 | .then(actorUrl => getOrCreateActorAndServerAndModel(actorUrl)) | ||
88 | .then(targetActor => { | ||
89 | const options = { | ||
90 | arguments: [ fromActor, targetActor ], | ||
91 | errorMessage: 'Cannot follow with many retries.' | ||
92 | } | ||
93 | |||
94 | return retryTransactionWrapper(follow, options) | ||
95 | }) | ||
96 | .catch(err => logger.warn('Cannot follow server %s.', sanitizedHost, { err })) | ||
97 | |||
98 | tasks.push(p) | ||
99 | } | 81 | } |
100 | 82 | ||
101 | // Don't make the client wait the tasks | ||
102 | Promise.all(tasks) | ||
103 | .catch(err => logger.error('Error in follow.', { err })) | ||
104 | |||
105 | return res.status(204).end() | 83 | return res.status(204).end() |
106 | } | 84 | } |
107 | 85 | ||
108 | function follow (fromActor: ActorModel, targetActor: ActorModel) { | ||
109 | if (fromActor.id === targetActor.id) { | ||
110 | throw new Error('Follower is the same than target actor.') | ||
111 | } | ||
112 | |||
113 | return sequelizeTypescript.transaction(async t => { | ||
114 | const [ actorFollow ] = await ActorFollowModel.findOrCreate({ | ||
115 | where: { | ||
116 | actorId: fromActor.id, | ||
117 | targetActorId: targetActor.id | ||
118 | }, | ||
119 | defaults: { | ||
120 | state: 'pending', | ||
121 | actorId: fromActor.id, | ||
122 | targetActorId: targetActor.id | ||
123 | }, | ||
124 | transaction: t | ||
125 | }) | ||
126 | actorFollow.ActorFollowing = targetActor | ||
127 | actorFollow.ActorFollower = fromActor | ||
128 | |||
129 | // Send a notification to remote server | ||
130 | await sendFollow(actorFollow) | ||
131 | }) | ||
132 | } | ||
133 | |||
134 | async function removeFollow (req: express.Request, res: express.Response, next: express.NextFunction) { | 86 | async function removeFollow (req: express.Request, res: express.Response, next: express.NextFunction) { |
135 | const follow: ActorFollowModel = res.locals.follow | 87 | const follow: ActorFollowModel = res.locals.follow |
136 | 88 | ||