diff options
Diffstat (limited to 'server/controllers')
-rw-r--r-- | server/controllers/api/server/follows.ts | 82 |
1 files changed, 49 insertions, 33 deletions
diff --git a/server/controllers/api/server/follows.ts b/server/controllers/api/server/follows.ts index 8fc70f34f..c759824e0 100644 --- a/server/controllers/api/server/follows.ts +++ b/server/controllers/api/server/follows.ts | |||
@@ -16,6 +16,9 @@ import { followersSortValidator, followingSortValidator } from '../../../middlew | |||
16 | import { AccountFollowInstance } from '../../../models/index' | 16 | import { AccountFollowInstance } from '../../../models/index' |
17 | import { sendFollow } from '../../../lib/index' | 17 | import { sendFollow } from '../../../lib/index' |
18 | import { sendUndoFollow } from '../../../lib/activitypub/send/send-undo' | 18 | import { sendUndoFollow } from '../../../lib/activitypub/send/send-undo' |
19 | import { AccountInstance } from '../../../models/account/account-interface' | ||
20 | import { retryTransactionWrapper } from '../../../helpers/database-utils' | ||
21 | import { saveAccountAndServerIfNotExist } from '../../../lib/activitypub/account' | ||
19 | 22 | ||
20 | const serverFollowsRouter = express.Router() | 23 | const serverFollowsRouter = express.Router() |
21 | 24 | ||
@@ -32,7 +35,7 @@ serverFollowsRouter.post('/following', | |||
32 | ensureUserHasRight(UserRight.MANAGE_SERVER_FOLLOW), | 35 | ensureUserHasRight(UserRight.MANAGE_SERVER_FOLLOW), |
33 | followValidator, | 36 | followValidator, |
34 | setBodyHostsPort, | 37 | setBodyHostsPort, |
35 | asyncMiddleware(follow) | 38 | asyncMiddleware(followRetry) |
36 | ) | 39 | ) |
37 | 40 | ||
38 | serverFollowsRouter.delete('/following/:accountId', | 41 | serverFollowsRouter.delete('/following/:accountId', |
@@ -72,7 +75,7 @@ async function listFollowers (req: express.Request, res: express.Response, next: | |||
72 | return res.json(getFormattedObjects(resultList.data, resultList.total)) | 75 | return res.json(getFormattedObjects(resultList.data, resultList.total)) |
73 | } | 76 | } |
74 | 77 | ||
75 | async function follow (req: express.Request, res: express.Response, next: express.NextFunction) { | 78 | async function followRetry (req: express.Request, res: express.Response, next: express.NextFunction) { |
76 | const hosts = req.body.hosts as string[] | 79 | const hosts = req.body.hosts as string[] |
77 | const fromAccount = await getServerAccount() | 80 | const fromAccount = await getServerAccount() |
78 | 81 | ||
@@ -88,31 +91,12 @@ async function follow (req: express.Request, res: express.Response, next: expres | |||
88 | .then(accountResult => { | 91 | .then(accountResult => { |
89 | let targetAccount = accountResult.account | 92 | let targetAccount = accountResult.account |
90 | 93 | ||
91 | return db.sequelize.transaction(async t => { | 94 | const options = { |
92 | if (accountResult.loadedFromDB === false) { | 95 | arguments: [ fromAccount, targetAccount, accountResult.loadedFromDB ], |
93 | targetAccount = await targetAccount.save({ transaction: t }) | 96 | errorMessage: 'Cannot follow with many retries.' |
94 | } | 97 | } |
95 | 98 | ||
96 | const [ accountFollow ] = await db.AccountFollow.findOrCreate({ | 99 | return retryTransactionWrapper(follow, options) |
97 | where: { | ||
98 | accountId: fromAccount.id, | ||
99 | targetAccountId: targetAccount.id | ||
100 | }, | ||
101 | defaults: { | ||
102 | state: 'pending', | ||
103 | accountId: fromAccount.id, | ||
104 | targetAccountId: targetAccount.id | ||
105 | }, | ||
106 | transaction: t | ||
107 | }) | ||
108 | accountFollow.AccountFollowing = targetAccount | ||
109 | accountFollow.AccountFollower = fromAccount | ||
110 | |||
111 | // Send a notification to remote server | ||
112 | if (accountFollow.state === 'pending') { | ||
113 | await sendFollow(accountFollow, t) | ||
114 | } | ||
115 | }) | ||
116 | }) | 100 | }) |
117 | .catch(err => logger.warn('Cannot follow server %s.', `${accountName}@${host}`, err)) | 101 | .catch(err => logger.warn('Cannot follow server %s.', `${accountName}@${host}`, err)) |
118 | 102 | ||
@@ -121,19 +105,51 @@ async function follow (req: express.Request, res: express.Response, next: expres | |||
121 | 105 | ||
122 | // Don't make the client wait the tasks | 106 | // Don't make the client wait the tasks |
123 | Promise.all(tasks) | 107 | Promise.all(tasks) |
124 | .catch(err => { | 108 | .catch(err => logger.error('Error in follow.', err)) |
125 | logger.error('Error in follow.', err) | ||
126 | }) | ||
127 | 109 | ||
128 | return res.status(204).end() | 110 | return res.status(204).end() |
129 | } | 111 | } |
130 | 112 | ||
113 | async function follow (fromAccount: AccountInstance, targetAccount: AccountInstance, targetAlreadyInDB: boolean) { | ||
114 | try { | ||
115 | await db.sequelize.transaction(async t => { | ||
116 | if (targetAlreadyInDB === false) { | ||
117 | await saveAccountAndServerIfNotExist(targetAccount, t) | ||
118 | } | ||
119 | |||
120 | const [ accountFollow ] = await db.AccountFollow.findOrCreate({ | ||
121 | where: { | ||
122 | accountId: fromAccount.id, | ||
123 | targetAccountId: targetAccount.id | ||
124 | }, | ||
125 | defaults: { | ||
126 | state: 'pending', | ||
127 | accountId: fromAccount.id, | ||
128 | targetAccountId: targetAccount.id | ||
129 | }, | ||
130 | transaction: t | ||
131 | }) | ||
132 | accountFollow.AccountFollowing = targetAccount | ||
133 | accountFollow.AccountFollower = fromAccount | ||
134 | |||
135 | // Send a notification to remote server | ||
136 | if (accountFollow.state === 'pending') { | ||
137 | await sendFollow(accountFollow, t) | ||
138 | } | ||
139 | }) | ||
140 | } catch (err) { | ||
141 | // Reset target account | ||
142 | targetAccount.isNewRecord = !targetAlreadyInDB | ||
143 | throw err | ||
144 | } | ||
145 | } | ||
146 | |||
131 | async function removeFollow (req: express.Request, res: express.Response, next: express.NextFunction) { | 147 | async function removeFollow (req: express.Request, res: express.Response, next: express.NextFunction) { |
132 | const following: AccountFollowInstance = res.locals.following | 148 | const follow: AccountFollowInstance = res.locals.follow |
133 | 149 | ||
134 | await db.sequelize.transaction(async t => { | 150 | await db.sequelize.transaction(async t => { |
135 | await sendUndoFollow(following, t) | 151 | await sendUndoFollow(follow, t) |
136 | await following.destroy({ transaction: t }) | 152 | await follow.destroy({ transaction: t }) |
137 | }) | 153 | }) |
138 | 154 | ||
139 | return res.status(204).end() | 155 | return res.status(204).end() |