aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/controllers/api
diff options
context:
space:
mode:
Diffstat (limited to 'server/controllers/api')
-rw-r--r--server/controllers/api/server/follows.ts82
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
16import { AccountFollowInstance } from '../../../models/index' 16import { AccountFollowInstance } from '../../../models/index'
17import { sendFollow } from '../../../lib/index' 17import { sendFollow } from '../../../lib/index'
18import { sendUndoFollow } from '../../../lib/activitypub/send/send-undo' 18import { sendUndoFollow } from '../../../lib/activitypub/send/send-undo'
19import { AccountInstance } from '../../../models/account/account-interface'
20import { retryTransactionWrapper } from '../../../helpers/database-utils'
21import { saveAccountAndServerIfNotExist } from '../../../lib/activitypub/account'
19 22
20const serverFollowsRouter = express.Router() 23const 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
38serverFollowsRouter.delete('/following/:accountId', 41serverFollowsRouter.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
75async function follow (req: express.Request, res: express.Response, next: express.NextFunction) { 78async 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
113async 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
131async function removeFollow (req: express.Request, res: express.Response, next: express.NextFunction) { 147async 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()