diff options
-rw-r--r-- | client/src/app/+admin/system/jobs/jobs.component.ts | 1 | ||||
-rw-r--r-- | scripts/simulate-many-viewers.ts | 89 | ||||
-rw-r--r-- | server/initializers/constants.ts | 5 | ||||
-rw-r--r-- | server/lib/activitypub/local-video-viewer.ts | 6 | ||||
-rw-r--r-- | server/lib/activitypub/send/send-view.ts | 2 | ||||
-rw-r--r-- | server/lib/activitypub/send/shared/audience-utils.ts | 6 | ||||
-rw-r--r-- | server/lib/activitypub/send/shared/send-utils.ts | 23 | ||||
-rw-r--r-- | server/lib/job-queue/job-queue.ts | 3 | ||||
-rw-r--r-- | server/lib/views/shared/video-viewer-counters.ts | 1 | ||||
-rw-r--r-- | server/models/actor/actor.ts | 61 | ||||
-rw-r--r-- | server/models/video/video-share.ts | 25 | ||||
-rw-r--r-- | shared/models/server/job.model.ts | 1 |
12 files changed, 154 insertions, 69 deletions
diff --git a/client/src/app/+admin/system/jobs/jobs.component.ts b/client/src/app/+admin/system/jobs/jobs.component.ts index f7e10fd04..42f503be6 100644 --- a/client/src/app/+admin/system/jobs/jobs.component.ts +++ b/client/src/app/+admin/system/jobs/jobs.component.ts | |||
@@ -25,6 +25,7 @@ export class JobsComponent extends RestTable implements OnInit { | |||
25 | 25 | ||
26 | 'activitypub-follow', | 26 | 'activitypub-follow', |
27 | 'activitypub-http-broadcast', | 27 | 'activitypub-http-broadcast', |
28 | 'activitypub-http-broadcast-parallel', | ||
28 | 'activitypub-http-fetcher', | 29 | 'activitypub-http-fetcher', |
29 | 'activitypub-http-unicast', | 30 | 'activitypub-http-unicast', |
30 | 'activitypub-refresher', | 31 | 'activitypub-refresher', |
diff --git a/scripts/simulate-many-viewers.ts b/scripts/simulate-many-viewers.ts new file mode 100644 index 000000000..fb666c318 --- /dev/null +++ b/scripts/simulate-many-viewers.ts | |||
@@ -0,0 +1,89 @@ | |||
1 | import Bluebird from 'bluebird' | ||
2 | import { wait } from '@shared/core-utils' | ||
3 | import { | ||
4 | createSingleServer, | ||
5 | doubleFollow, | ||
6 | killallServers, | ||
7 | PeerTubeServer, | ||
8 | setAccessTokensToServers, | ||
9 | waitJobs | ||
10 | } from '@shared/server-commands' | ||
11 | |||
12 | let servers: PeerTubeServer[] | ||
13 | const viewers: { xForwardedFor: string }[] = [] | ||
14 | let videoId: string | ||
15 | |||
16 | run() | ||
17 | .then(() => process.exit(0)) | ||
18 | .catch(err => console.error(err)) | ||
19 | .finally(() => killallServers(servers)) | ||
20 | |||
21 | async function run () { | ||
22 | await prepare() | ||
23 | |||
24 | while (true) { | ||
25 | await runViewers() | ||
26 | } | ||
27 | } | ||
28 | |||
29 | async function prepare () { | ||
30 | console.log('Preparing servers...') | ||
31 | |||
32 | const config = { | ||
33 | log: { | ||
34 | level: 'info' | ||
35 | }, | ||
36 | rates_limit: { | ||
37 | api: { | ||
38 | max: 5_000_000 | ||
39 | } | ||
40 | }, | ||
41 | views: { | ||
42 | videos: { | ||
43 | local_buffer_update_interval: '30 minutes', | ||
44 | ip_view_expiration: '1 hour' | ||
45 | } | ||
46 | } | ||
47 | } | ||
48 | |||
49 | servers = await Promise.all([ | ||
50 | createSingleServer(1, config, { nodeArgs: [ '--inspect' ] }), | ||
51 | createSingleServer(2, config), | ||
52 | createSingleServer(3, config) | ||
53 | ]) | ||
54 | |||
55 | await setAccessTokensToServers(servers) | ||
56 | await doubleFollow(servers[0], servers[1]) | ||
57 | await doubleFollow(servers[0], servers[2]) | ||
58 | |||
59 | const { uuid } = await servers[0].videos.quickUpload({ name: 'video' }) | ||
60 | videoId = uuid | ||
61 | |||
62 | await waitJobs(servers) | ||
63 | |||
64 | const THOUSAND_VIEWERS = 2 | ||
65 | |||
66 | for (let i = 2; i < 252; i++) { | ||
67 | for (let j = 2; j < 6; j++) { | ||
68 | for (let k = 2; k < THOUSAND_VIEWERS + 2; k++) { | ||
69 | viewers.push({ xForwardedFor: `0.${k}.${j}.${i},127.0.0.1` }) | ||
70 | } | ||
71 | } | ||
72 | } | ||
73 | |||
74 | console.log('Servers preparation finished.') | ||
75 | } | ||
76 | |||
77 | async function runViewers () { | ||
78 | console.log('Will run views of %d viewers.', viewers.length) | ||
79 | |||
80 | const before = new Date().getTime() | ||
81 | |||
82 | await Bluebird.map(viewers, viewer => { | ||
83 | return servers[0].views.simulateView({ id: videoId, xForwardedFor: viewer.xForwardedFor }) | ||
84 | }, { concurrency: 100 }) | ||
85 | |||
86 | console.log('Finished to run views in %d seconds.', (new Date().getTime() - before) / 1000) | ||
87 | |||
88 | await wait(5000) | ||
89 | } | ||
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index 2d324d1eb..75ccbc458 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts | |||
@@ -139,6 +139,7 @@ const REMOTE_SCHEME = { | |||
139 | 139 | ||
140 | const JOB_ATTEMPTS: { [id in JobType]: number } = { | 140 | const JOB_ATTEMPTS: { [id in JobType]: number } = { |
141 | 'activitypub-http-broadcast': 1, | 141 | 'activitypub-http-broadcast': 1, |
142 | 'activitypub-http-broadcast-parallel': 1, | ||
142 | 'activitypub-http-unicast': 1, | 143 | 'activitypub-http-unicast': 1, |
143 | 'activitypub-http-fetcher': 2, | 144 | 'activitypub-http-fetcher': 2, |
144 | 'activitypub-follow': 5, | 145 | 'activitypub-follow': 5, |
@@ -159,6 +160,7 @@ const JOB_ATTEMPTS: { [id in JobType]: number } = { | |||
159 | // Excluded keys are jobs that can be configured by admins | 160 | // Excluded keys are jobs that can be configured by admins |
160 | const JOB_CONCURRENCY: { [id in Exclude<JobType, 'video-transcoding' | 'video-import'>]: number } = { | 161 | const JOB_CONCURRENCY: { [id in Exclude<JobType, 'video-transcoding' | 'video-import'>]: number } = { |
161 | 'activitypub-http-broadcast': 1, | 162 | 'activitypub-http-broadcast': 1, |
163 | 'activitypub-http-broadcast-parallel': 30, | ||
162 | 'activitypub-http-unicast': 10, | 164 | 'activitypub-http-unicast': 10, |
163 | 'activitypub-http-fetcher': 3, | 165 | 'activitypub-http-fetcher': 3, |
164 | 'activitypub-cleaner': 1, | 166 | 'activitypub-cleaner': 1, |
@@ -176,6 +178,7 @@ const JOB_CONCURRENCY: { [id in Exclude<JobType, 'video-transcoding' | 'video-im | |||
176 | } | 178 | } |
177 | const JOB_TTL: { [id in JobType]: number } = { | 179 | const JOB_TTL: { [id in JobType]: number } = { |
178 | 'activitypub-http-broadcast': 60000 * 10, // 10 minutes | 180 | 'activitypub-http-broadcast': 60000 * 10, // 10 minutes |
181 | 'activitypub-http-broadcast-parallel': 60000 * 10, // 10 minutes | ||
179 | 'activitypub-http-unicast': 60000 * 10, // 10 minutes | 182 | 'activitypub-http-unicast': 60000 * 10, // 10 minutes |
180 | 'activitypub-http-fetcher': 1000 * 3600 * 10, // 10 hours | 183 | 'activitypub-http-fetcher': 1000 * 3600 * 10, // 10 hours |
181 | 'activitypub-follow': 60000 * 10, // 10 minutes | 184 | 'activitypub-follow': 60000 * 10, // 10 minutes |
@@ -371,7 +374,7 @@ const VIEW_LIFETIME = { | |||
371 | VIEWER_STATS: 60000 * 60 // 1 hour | 374 | VIEWER_STATS: 60000 * 60 // 1 hour |
372 | } | 375 | } |
373 | 376 | ||
374 | const MAX_LOCAL_VIEWER_WATCH_SECTIONS = 10 | 377 | const MAX_LOCAL_VIEWER_WATCH_SECTIONS = 100 |
375 | 378 | ||
376 | let CONTACT_FORM_LIFETIME = 60000 * 60 // 1 hour | 379 | let CONTACT_FORM_LIFETIME = 60000 * 60 // 1 hour |
377 | 380 | ||
diff --git a/server/lib/activitypub/local-video-viewer.ts b/server/lib/activitypub/local-video-viewer.ts index 738083adc..bdd746791 100644 --- a/server/lib/activitypub/local-video-viewer.ts +++ b/server/lib/activitypub/local-video-viewer.ts | |||
@@ -23,7 +23,7 @@ async function createOrUpdateLocalVideoViewer (watchAction: WatchActionObject, v | |||
23 | : null, | 23 | : null, |
24 | 24 | ||
25 | videoId: video.id | 25 | videoId: video.id |
26 | }) | 26 | }, { transaction: t }) |
27 | 27 | ||
28 | await LocalVideoViewerWatchSectionModel.bulkCreateSections({ | 28 | await LocalVideoViewerWatchSectionModel.bulkCreateSections({ |
29 | localVideoViewerId: localVideoViewer.id, | 29 | localVideoViewerId: localVideoViewer.id, |
@@ -31,7 +31,9 @@ async function createOrUpdateLocalVideoViewer (watchAction: WatchActionObject, v | |||
31 | watchSections: watchAction.watchSections.map(s => ({ | 31 | watchSections: watchAction.watchSections.map(s => ({ |
32 | start: s.startTimestamp, | 32 | start: s.startTimestamp, |
33 | end: s.endTimestamp | 33 | end: s.endTimestamp |
34 | })) | 34 | })), |
35 | |||
36 | transaction: t | ||
35 | }) | 37 | }) |
36 | } | 38 | } |
37 | 39 | ||
diff --git a/server/lib/activitypub/send/send-view.ts b/server/lib/activitypub/send/send-view.ts index 25a20ec6d..bf3451603 100644 --- a/server/lib/activitypub/send/send-view.ts +++ b/server/lib/activitypub/send/send-view.ts | |||
@@ -26,7 +26,7 @@ async function sendView (options: { | |||
26 | return buildViewActivity({ url, byActor, video, audience, type }) | 26 | return buildViewActivity({ url, byActor, video, audience, type }) |
27 | } | 27 | } |
28 | 28 | ||
29 | return sendVideoRelatedActivity(activityBuilder, { byActor, video, transaction, contextType: 'View' }) | 29 | return sendVideoRelatedActivity(activityBuilder, { byActor, video, transaction, contextType: 'View', parallelizable: true }) |
30 | } | 30 | } |
31 | 31 | ||
32 | // --------------------------------------------------------------------------- | 32 | // --------------------------------------------------------------------------- |
diff --git a/server/lib/activitypub/send/shared/audience-utils.ts b/server/lib/activitypub/send/shared/audience-utils.ts index ba4be487c..2f6b0741d 100644 --- a/server/lib/activitypub/send/shared/audience-utils.ts +++ b/server/lib/activitypub/send/shared/audience-utils.ts | |||
@@ -3,7 +3,7 @@ import { ACTIVITY_PUB } from '@server/initializers/constants' | |||
3 | import { ActorModel } from '@server/models/actor/actor' | 3 | import { ActorModel } from '@server/models/actor/actor' |
4 | import { VideoModel } from '@server/models/video/video' | 4 | import { VideoModel } from '@server/models/video/video' |
5 | import { VideoShareModel } from '@server/models/video/video-share' | 5 | import { VideoShareModel } from '@server/models/video/video-share' |
6 | import { MActorFollowersUrl, MActorLight, MActorUrl, MCommentOwner, MCommentOwnerVideo, MVideoId } from '@server/types/models' | 6 | import { MActorFollowersUrl, MActorUrl, MCommentOwner, MCommentOwnerVideo, MVideoId } from '@server/types/models' |
7 | import { ActivityAudience } from '@shared/models' | 7 | import { ActivityAudience } from '@shared/models' |
8 | 8 | ||
9 | function getOriginVideoAudience (accountActor: MActorUrl, actorsInvolvedInVideo: MActorFollowersUrl[] = []): ActivityAudience { | 9 | function getOriginVideoAudience (accountActor: MActorUrl, actorsInvolvedInVideo: MActorFollowersUrl[] = []): ActivityAudience { |
@@ -51,13 +51,13 @@ function getAudienceFromFollowersOf (actorsInvolvedInObject: MActorFollowersUrl[ | |||
51 | } | 51 | } |
52 | 52 | ||
53 | async function getActorsInvolvedInVideo (video: MVideoId, t: Transaction) { | 53 | async function getActorsInvolvedInVideo (video: MVideoId, t: Transaction) { |
54 | const actors: MActorLight[] = await VideoShareModel.loadActorsByShare(video.id, t) | 54 | const actors = await VideoShareModel.listActorIdsAndFollowerUrlsByShare(video.id, t) |
55 | 55 | ||
56 | const videoAll = video as VideoModel | 56 | const videoAll = video as VideoModel |
57 | 57 | ||
58 | const videoActor = videoAll.VideoChannel?.Account | 58 | const videoActor = videoAll.VideoChannel?.Account |
59 | ? videoAll.VideoChannel.Account.Actor | 59 | ? videoAll.VideoChannel.Account.Actor |
60 | : await ActorModel.loadFromAccountByVideoId(video.id, t) | 60 | : await ActorModel.loadAccountActorFollowerUrlByVideoId(video.id, t) |
61 | 61 | ||
62 | actors.push(videoActor) | 62 | actors.push(videoActor) |
63 | 63 | ||
diff --git a/server/lib/activitypub/send/shared/send-utils.ts b/server/lib/activitypub/send/shared/send-utils.ts index dbcde91ee..fcec63991 100644 --- a/server/lib/activitypub/send/shared/send-utils.ts +++ b/server/lib/activitypub/send/shared/send-utils.ts | |||
@@ -15,17 +15,18 @@ async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAud | |||
15 | byActor: MActorLight | 15 | byActor: MActorLight |
16 | video: MVideoImmutable | MVideoAccountLight | 16 | video: MVideoImmutable | MVideoAccountLight |
17 | contextType: ContextType | 17 | contextType: ContextType |
18 | parallelizable?: boolean | ||
18 | transaction?: Transaction | 19 | transaction?: Transaction |
19 | }) { | 20 | }) { |
20 | const { byActor, video, transaction, contextType } = options | 21 | const { byActor, video, transaction, contextType, parallelizable } = options |
21 | |||
22 | const actorsInvolvedInVideo = await getActorsInvolvedInVideo(video, transaction) | ||
23 | 22 | ||
24 | // Send to origin | 23 | // Send to origin |
25 | if (video.isOwned() === false) { | 24 | if (video.isOwned() === false) { |
26 | return sendVideoActivityToOrigin(activityBuilder, options) | 25 | return sendVideoActivityToOrigin(activityBuilder, options) |
27 | } | 26 | } |
28 | 27 | ||
28 | const actorsInvolvedInVideo = await getActorsInvolvedInVideo(video, transaction) | ||
29 | |||
29 | // Send to followers | 30 | // Send to followers |
30 | const audience = getAudienceFromFollowersOf(actorsInvolvedInVideo) | 31 | const audience = getAudienceFromFollowersOf(actorsInvolvedInVideo) |
31 | const activity = activityBuilder(audience) | 32 | const activity = activityBuilder(audience) |
@@ -38,6 +39,7 @@ async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAud | |||
38 | toFollowersOf: actorsInvolvedInVideo, | 39 | toFollowersOf: actorsInvolvedInVideo, |
39 | transaction, | 40 | transaction, |
40 | actorsException, | 41 | actorsException, |
42 | parallelizable, | ||
41 | contextType | 43 | contextType |
42 | }) | 44 | }) |
43 | } | 45 | } |
@@ -130,9 +132,10 @@ async function broadcastToFollowers (options: { | |||
130 | transaction: Transaction | 132 | transaction: Transaction |
131 | contextType: ContextType | 133 | contextType: ContextType |
132 | 134 | ||
135 | parallelizable?: boolean | ||
133 | actorsException?: MActorWithInboxes[] | 136 | actorsException?: MActorWithInboxes[] |
134 | }) { | 137 | }) { |
135 | const { data, byActor, toFollowersOf, transaction, contextType, actorsException = [] } = options | 138 | const { data, byActor, toFollowersOf, transaction, contextType, actorsException = [], parallelizable } = options |
136 | 139 | ||
137 | const uris = await computeFollowerUris(toFollowersOf, actorsException, transaction) | 140 | const uris = await computeFollowerUris(toFollowersOf, actorsException, transaction) |
138 | 141 | ||
@@ -141,6 +144,7 @@ async function broadcastToFollowers (options: { | |||
141 | uris, | 144 | uris, |
142 | data, | 145 | data, |
143 | byActor, | 146 | byActor, |
147 | parallelizable, | ||
144 | contextType | 148 | contextType |
145 | }) | 149 | }) |
146 | }) | 150 | }) |
@@ -173,8 +177,9 @@ function broadcastTo (options: { | |||
173 | data: any | 177 | data: any |
174 | byActor: MActorId | 178 | byActor: MActorId |
175 | contextType: ContextType | 179 | contextType: ContextType |
180 | parallelizable?: boolean // default to false | ||
176 | }) { | 181 | }) { |
177 | const { uris, data, byActor, contextType } = options | 182 | const { uris, data, byActor, contextType, parallelizable } = options |
178 | 183 | ||
179 | if (uris.length === 0) return undefined | 184 | if (uris.length === 0) return undefined |
180 | 185 | ||
@@ -200,7 +205,13 @@ function broadcastTo (options: { | |||
200 | contextType | 205 | contextType |
201 | } | 206 | } |
202 | 207 | ||
203 | JobQueue.Instance.createJob({ type: 'activitypub-http-broadcast', payload }) | 208 | JobQueue.Instance.createJob({ |
209 | type: parallelizable | ||
210 | ? 'activitypub-http-broadcast-parallel' | ||
211 | : 'activitypub-http-broadcast', | ||
212 | |||
213 | payload | ||
214 | }) | ||
204 | } | 215 | } |
205 | 216 | ||
206 | for (const unicastUri of unicastUris) { | 217 | for (const unicastUri of unicastUris) { |
diff --git a/server/lib/job-queue/job-queue.ts b/server/lib/job-queue/job-queue.ts index 61e41fb0f..ce24763f1 100644 --- a/server/lib/job-queue/job-queue.ts +++ b/server/lib/job-queue/job-queue.ts | |||
@@ -43,6 +43,7 @@ import { processVideosViewsStats } from './handlers/video-views-stats' | |||
43 | 43 | ||
44 | type CreateJobArgument = | 44 | type CreateJobArgument = |
45 | { type: 'activitypub-http-broadcast', payload: ActivitypubHttpBroadcastPayload } | | 45 | { type: 'activitypub-http-broadcast', payload: ActivitypubHttpBroadcastPayload } | |
46 | { type: 'activitypub-http-broadcast-parallel', payload: ActivitypubHttpBroadcastPayload } | | ||
46 | { type: 'activitypub-http-unicast', payload: ActivitypubHttpUnicastPayload } | | 47 | { type: 'activitypub-http-unicast', payload: ActivitypubHttpUnicastPayload } | |
47 | { type: 'activitypub-http-fetcher', payload: ActivitypubHttpFetcherPayload } | | 48 | { type: 'activitypub-http-fetcher', payload: ActivitypubHttpFetcherPayload } | |
48 | { type: 'activitypub-http-cleaner', payload: {} } | | 49 | { type: 'activitypub-http-cleaner', payload: {} } | |
@@ -68,6 +69,7 @@ export type CreateJobOptions = { | |||
68 | 69 | ||
69 | const handlers: { [id in JobType]: (job: Job) => Promise<any> } = { | 70 | const handlers: { [id in JobType]: (job: Job) => Promise<any> } = { |
70 | 'activitypub-http-broadcast': processActivityPubHttpBroadcast, | 71 | 'activitypub-http-broadcast': processActivityPubHttpBroadcast, |
72 | 'activitypub-http-broadcast-parallel': processActivityPubHttpBroadcast, | ||
71 | 'activitypub-http-unicast': processActivityPubHttpUnicast, | 73 | 'activitypub-http-unicast': processActivityPubHttpUnicast, |
72 | 'activitypub-http-fetcher': processActivityPubHttpFetcher, | 74 | 'activitypub-http-fetcher': processActivityPubHttpFetcher, |
73 | 'activitypub-cleaner': processActivityPubCleaner, | 75 | 'activitypub-cleaner': processActivityPubCleaner, |
@@ -93,6 +95,7 @@ const errorHandlers: { [id in JobType]?: (job: Job, err: any) => Promise<any> } | |||
93 | const jobTypes: JobType[] = [ | 95 | const jobTypes: JobType[] = [ |
94 | 'activitypub-follow', | 96 | 'activitypub-follow', |
95 | 'activitypub-http-broadcast', | 97 | 'activitypub-http-broadcast', |
98 | 'activitypub-http-broadcast-parallel', | ||
96 | 'activitypub-http-fetcher', | 99 | 'activitypub-http-fetcher', |
97 | 'activitypub-http-unicast', | 100 | 'activitypub-http-unicast', |
98 | 'activitypub-cleaner', | 101 | 'activitypub-cleaner', |
diff --git a/server/lib/views/shared/video-viewer-counters.ts b/server/lib/views/shared/video-viewer-counters.ts index 941b62ed7..999ab7d8d 100644 --- a/server/lib/views/shared/video-viewer-counters.ts +++ b/server/lib/views/shared/video-viewer-counters.ts | |||
@@ -1,4 +1,3 @@ | |||
1 | |||
2 | import { isTestInstance } from '@server/helpers/core-utils' | 1 | import { isTestInstance } from '@server/helpers/core-utils' |
3 | import { logger, loggerTagsFactory } from '@server/helpers/logger' | 2 | import { logger, loggerTagsFactory } from '@server/helpers/logger' |
4 | import { VIEW_LIFETIME } from '@server/initializers/constants' | 3 | import { VIEW_LIFETIME } from '@server/initializers/constants' |
diff --git a/server/models/actor/actor.ts b/server/models/actor/actor.ts index 93145b8ae..943b7364f 100644 --- a/server/models/actor/actor.ts +++ b/server/models/actor/actor.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import { values } from 'lodash' | 1 | import { values } from 'lodash' |
2 | import { literal, Op, Transaction } from 'sequelize' | 2 | import { literal, Op, QueryTypes, Transaction } from 'sequelize' |
3 | import { | 3 | import { |
4 | AllowNull, | 4 | AllowNull, |
5 | BelongsTo, | 5 | BelongsTo, |
@@ -43,15 +43,18 @@ import { | |||
43 | MActorAccountChannelId, | 43 | MActorAccountChannelId, |
44 | MActorAPAccount, | 44 | MActorAPAccount, |
45 | MActorAPChannel, | 45 | MActorAPChannel, |
46 | MActorFollowersUrl, | ||
46 | MActorFormattable, | 47 | MActorFormattable, |
47 | MActorFull, | 48 | MActorFull, |
48 | MActorHost, | 49 | MActorHost, |
50 | MActorId, | ||
49 | MActorServer, | 51 | MActorServer, |
50 | MActorSummaryFormattable, | 52 | MActorSummaryFormattable, |
51 | MActorUrl, | 53 | MActorUrl, |
52 | MActorWithInboxes | 54 | MActorWithInboxes |
53 | } from '../../types/models' | 55 | } from '../../types/models' |
54 | import { AccountModel } from '../account/account' | 56 | import { AccountModel } from '../account/account' |
57 | import { getServerActor } from '../application/application' | ||
55 | import { ServerModel } from '../server/server' | 58 | import { ServerModel } from '../server/server' |
56 | import { isOutdated, throwIfNotValid } from '../utils' | 59 | import { isOutdated, throwIfNotValid } from '../utils' |
57 | import { VideoModel } from '../video/video' | 60 | import { VideoModel } from '../video/video' |
@@ -304,7 +307,10 @@ export class ActorModel extends Model<Partial<AttributesOnly<ActorModel>>> { | |||
304 | }) | 307 | }) |
305 | VideoChannel: VideoChannelModel | 308 | VideoChannel: VideoChannelModel |
306 | 309 | ||
307 | static load (id: number): Promise<MActor> { | 310 | static async load (id: number): Promise<MActor> { |
311 | const actorServer = await getServerActor() | ||
312 | if (id === actorServer.id) return actorServer | ||
313 | |||
308 | return ActorModel.unscoped().findByPk(id) | 314 | return ActorModel.unscoped().findByPk(id) |
309 | } | 315 | } |
310 | 316 | ||
@@ -312,48 +318,21 @@ export class ActorModel extends Model<Partial<AttributesOnly<ActorModel>>> { | |||
312 | return ActorModel.scope(ScopeNames.FULL).findByPk(id) | 318 | return ActorModel.scope(ScopeNames.FULL).findByPk(id) |
313 | } | 319 | } |
314 | 320 | ||
315 | static loadFromAccountByVideoId (videoId: number, transaction: Transaction): Promise<MActor> { | 321 | static loadAccountActorFollowerUrlByVideoId (videoId: number, transaction: Transaction) { |
316 | const query = { | 322 | const query = `SELECT "actor"."id" AS "id", "actor"."followersUrl" AS "followersUrl" ` + |
317 | include: [ | 323 | `FROM "actor" ` + |
318 | { | 324 | `INNER JOIN "account" ON "actor"."id" = "account"."actorId" ` + |
319 | attributes: [ 'id' ], | 325 | `INNER JOIN "videoChannel" ON "videoChannel"."accountId" = "account"."id" ` + |
320 | model: AccountModel.unscoped(), | 326 | `INNER JOIN "video" ON "video"."channelId" = "videoChannel"."id" AND "video"."id" = :videoId` |
321 | required: true, | 327 | |
322 | include: [ | 328 | const options = { |
323 | { | 329 | type: QueryTypes.SELECT as QueryTypes.SELECT, |
324 | attributes: [ 'id' ], | 330 | replacements: { videoId }, |
325 | model: VideoChannelModel.unscoped(), | 331 | plain: true as true, |
326 | required: true, | ||
327 | include: [ | ||
328 | { | ||
329 | attributes: [ 'id' ], | ||
330 | model: VideoModel.unscoped(), | ||
331 | required: true, | ||
332 | where: { | ||
333 | id: videoId | ||
334 | } | ||
335 | } | ||
336 | ] | ||
337 | } | ||
338 | ] | ||
339 | } | ||
340 | ], | ||
341 | transaction | 332 | transaction |
342 | } | 333 | } |
343 | 334 | ||
344 | return ActorModel.unscoped().findOne(query) | 335 | return ActorModel.sequelize.query<MActorId & MActorFollowersUrl>(query, options) |
345 | } | ||
346 | |||
347 | static isActorUrlExist (url: string) { | ||
348 | const query = { | ||
349 | raw: true, | ||
350 | where: { | ||
351 | url | ||
352 | } | ||
353 | } | ||
354 | |||
355 | return ActorModel.unscoped().findOne(query) | ||
356 | .then(a => !!a) | ||
357 | } | 336 | } |
358 | 337 | ||
359 | static listByFollowersUrls (followersUrls: string[], transaction?: Transaction): Promise<MActorFull[]> { | 338 | static listByFollowersUrls (followersUrls: string[], transaction?: Transaction): Promise<MActorFull[]> { |
diff --git a/server/models/video/video-share.ts b/server/models/video/video-share.ts index ad95dec6e..ca63bb2d9 100644 --- a/server/models/video/video-share.ts +++ b/server/models/video/video-share.ts | |||
@@ -3,7 +3,7 @@ import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Is, Mode | |||
3 | import { AttributesOnly } from '@shared/typescript-utils' | 3 | import { AttributesOnly } from '@shared/typescript-utils' |
4 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' | 4 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' |
5 | import { CONSTRAINTS_FIELDS } from '../../initializers/constants' | 5 | import { CONSTRAINTS_FIELDS } from '../../initializers/constants' |
6 | import { MActorDefault } from '../../types/models' | 6 | import { MActorDefault, MActorFollowersUrl, MActorId } from '../../types/models' |
7 | import { MVideoShareActor, MVideoShareFull } from '../../types/models/video' | 7 | import { MVideoShareActor, MVideoShareFull } from '../../types/models/video' |
8 | import { ActorModel } from '../actor/actor' | 8 | import { ActorModel } from '../actor/actor' |
9 | import { buildLocalActorIdsIn, throwIfNotValid } from '../utils' | 9 | import { buildLocalActorIdsIn, throwIfNotValid } from '../utils' |
@@ -107,22 +107,19 @@ export class VideoShareModel extends Model<Partial<AttributesOnly<VideoShareMode | |||
107 | }) | 107 | }) |
108 | } | 108 | } |
109 | 109 | ||
110 | static loadActorsByShare (videoId: number, t: Transaction): Promise<MActorDefault[]> { | 110 | static listActorIdsAndFollowerUrlsByShare (videoId: number, t: Transaction) { |
111 | const query = { | 111 | const query = `SELECT "actor"."id" AS "id", "actor"."followersUrl" AS "followersUrl" ` + |
112 | where: { | 112 | `FROM "videoShare" ` + |
113 | videoId | 113 | `INNER JOIN "actor" ON "actor"."id" = "videoShare"."actorId" ` + |
114 | }, | 114 | `WHERE "videoShare"."videoId" = :videoId` |
115 | include: [ | 115 | |
116 | { | 116 | const options = { |
117 | model: ActorModel, | 117 | type: QueryTypes.SELECT as QueryTypes.SELECT, |
118 | required: true | 118 | replacements: { videoId }, |
119 | } | ||
120 | ], | ||
121 | transaction: t | 119 | transaction: t |
122 | } | 120 | } |
123 | 121 | ||
124 | return VideoShareModel.scope(ScopeNames.FULL).findAll(query) | 122 | return VideoShareModel.sequelize.query<MActorId & MActorFollowersUrl>(query, options) |
125 | .then((res: MVideoShareFull[]) => res.map(r => r.Actor)) | ||
126 | } | 123 | } |
127 | 124 | ||
128 | static loadActorsWhoSharedVideosOf (actorOwnerId: number, t: Transaction): Promise<MActorDefault[]> { | 125 | static loadActorsWhoSharedVideosOf (actorOwnerId: number, t: Transaction): Promise<MActorDefault[]> { |
diff --git a/shared/models/server/job.model.ts b/shared/models/server/job.model.ts index 073f15872..4633ab769 100644 --- a/shared/models/server/job.model.ts +++ b/shared/models/server/job.model.ts | |||
@@ -9,6 +9,7 @@ export type JobState = 'active' | 'completed' | 'failed' | 'waiting' | 'delayed' | |||
9 | export type JobType = | 9 | export type JobType = |
10 | | 'activitypub-http-unicast' | 10 | | 'activitypub-http-unicast' |
11 | | 'activitypub-http-broadcast' | 11 | | 'activitypub-http-broadcast' |
12 | | 'activitypub-http-broadcast-parallel' | ||
12 | | 'activitypub-http-fetcher' | 13 | | 'activitypub-http-fetcher' |
13 | | 'activitypub-cleaner' | 14 | | 'activitypub-cleaner' |
14 | | 'activitypub-follow' | 15 | | 'activitypub-follow' |