"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.sendVideoRelatedActivity = exports.forwardVideoRelatedActivity = exports.sendVideoActivityToOrigin = exports.broadcastToActors = exports.forwardActivity = exports.unicastTo = exports.broadcastToFollowers = void 0;
const tslib_1 = require("tslib");
const actor_follow_health_cache_1 = require("../../../actor-follow-health-cache");
const application_1 = require("../../../../models/application/application");
const database_utils_1 = require("../../../../helpers/database-utils");
const logger_1 = require("../../../../helpers/logger");
const actor_1 = require("../../../../models/actor/actor");
const actor_follow_1 = require("../../../../models/actor/actor-follow");
const job_queue_1 = require("../../../job-queue");
const audience_utils_1 = require("./audience-utils");
function sendVideoRelatedActivity(activityBuilder, options) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        const { byActor, video, transaction, contextType, parallelizable } = options;
        if (video.isOwned() === false) {
            return sendVideoActivityToOrigin(activityBuilder, options);
        }
        const actorsInvolvedInVideo = yield (0, audience_utils_1.getActorsInvolvedInVideo)(video, transaction);
        const audience = (0, audience_utils_1.getAudienceFromFollowersOf)(actorsInvolvedInVideo);
        const activity = activityBuilder(audience);
        const actorsException = [byActor];
        return broadcastToFollowers({
            data: activity,
            byActor,
            toFollowersOf: actorsInvolvedInVideo,
            transaction,
            actorsException,
            parallelizable,
            contextType
        });
    });
}
exports.sendVideoRelatedActivity = sendVideoRelatedActivity;
function sendVideoActivityToOrigin(activityBuilder, options) {
    var _a, _b;
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        const { byActor, video, actorsInvolvedInVideo, transaction, contextType } = options;
        if (video.isOwned())
            throw new Error('Cannot send activity to owned video origin ' + video.url);
        let accountActor = (_b = (_a = video.VideoChannel) === null || _a === void 0 ? void 0 : _a.Account) === null || _b === void 0 ? void 0 : _b.Actor;
        if (!accountActor)
            accountActor = yield actor_1.ActorModel.loadAccountActorByVideoId(video.id, transaction);
        const audience = (0, audience_utils_1.getOriginVideoAudience)(accountActor, actorsInvolvedInVideo);
        const activity = activityBuilder(audience);
        return (0, database_utils_1.afterCommitIfTransaction)(transaction, () => {
            return unicastTo({
                data: activity,
                byActor,
                toActorUrl: accountActor.getSharedInbox(),
                contextType
            });
        });
    });
}
exports.sendVideoActivityToOrigin = sendVideoActivityToOrigin;
function forwardVideoRelatedActivity(activity, t, followersException, video) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        const additionalActors = yield (0, audience_utils_1.getActorsInvolvedInVideo)(video, t);
        const additionalFollowerUrls = additionalActors.map(a => a.followersUrl);
        return forwardActivity(activity, t, followersException, additionalFollowerUrls);
    });
}
exports.forwardVideoRelatedActivity = forwardVideoRelatedActivity;
function forwardActivity(activity, t, followersException = [], additionalFollowerUrls = []) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        logger_1.logger.info('Forwarding activity %s.', activity.id);
        const to = activity.to || [];
        const cc = activity.cc || [];
        const followersUrls = additionalFollowerUrls;
        for (const dest of to.concat(cc)) {
            if (dest.endsWith('/followers')) {
                followersUrls.push(dest);
            }
        }
        const toActorFollowers = yield actor_1.ActorModel.listByFollowersUrls(followersUrls, t);
        const uris = yield computeFollowerUris(toActorFollowers, followersException, t);
        if (uris.length === 0) {
            logger_1.logger.info('0 followers for %s, no forwarding.', toActorFollowers.map(a => a.id).join(', '));
            return undefined;
        }
        logger_1.logger.debug('Creating forwarding job.', { uris });
        const payload = {
            uris,
            body: activity,
            contextType: null
        };
        return (0, database_utils_1.afterCommitIfTransaction)(t, () => job_queue_1.JobQueue.Instance.createJobAsync({ type: 'activitypub-http-broadcast', payload }));
    });
}
exports.forwardActivity = forwardActivity;
function broadcastToFollowers(options) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        const { data, byActor, toFollowersOf, transaction, contextType, actorsException = [], parallelizable } = options;
        const uris = yield computeFollowerUris(toFollowersOf, actorsException, transaction);
        return (0, database_utils_1.afterCommitIfTransaction)(transaction, () => {
            return broadcastTo({
                uris,
                data,
                byActor,
                parallelizable,
                contextType
            });
        });
    });
}
exports.broadcastToFollowers = broadcastToFollowers;
function broadcastToActors(options) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        const { data, byActor, toActors, transaction, contextType, actorsException = [] } = options;
        const uris = yield computeUris(toActors, actorsException);
        return (0, database_utils_1.afterCommitIfTransaction)(transaction, () => {
            return broadcastTo({
                uris,
                data,
                byActor,
                contextType
            });
        });
    });
}
exports.broadcastToActors = broadcastToActors;
function broadcastTo(options) {
    const { uris, data, byActor, contextType, parallelizable } = options;
    if (uris.length === 0)
        return undefined;
    const broadcastUris = [];
    const unicastUris = [];
    for (const uri of uris) {
        if (actor_follow_health_cache_1.ActorFollowHealthCache.Instance.isBadInbox(uri)) {
            unicastUris.push(uri);
        }
        else {
            broadcastUris.push(uri);
        }
    }
    logger_1.logger.debug('Creating broadcast job.', { broadcastUris, unicastUris });
    if (broadcastUris.length !== 0) {
        const payload = {
            uris: broadcastUris,
            signatureActorId: byActor.id,
            body: data,
            contextType
        };
        job_queue_1.JobQueue.Instance.createJobAsync({
            type: parallelizable
                ? 'activitypub-http-broadcast-parallel'
                : 'activitypub-http-broadcast',
            payload
        });
    }
    for (const unicastUri of unicastUris) {
        const payload = {
            uri: unicastUri,
            signatureActorId: byActor.id,
            body: data,
            contextType
        };
        job_queue_1.JobQueue.Instance.createJobAsync({ type: 'activitypub-http-unicast', payload });
    }
}
function unicastTo(options) {
    const { data, byActor, toActorUrl, contextType } = options;
    logger_1.logger.debug('Creating unicast job.', { uri: toActorUrl });
    const payload = {
        uri: toActorUrl,
        signatureActorId: byActor.id,
        body: data,
        contextType
    };
    job_queue_1.JobQueue.Instance.createJobAsync({ type: 'activitypub-http-unicast', payload });
}
exports.unicastTo = unicastTo;
function computeFollowerUris(toFollowersOf, actorsException, t) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        const toActorFollowerIds = toFollowersOf.map(a => a.id);
        const result = yield actor_follow_1.ActorFollowModel.listAcceptedFollowerSharedInboxUrls(toActorFollowerIds, t);
        const sharedInboxesException = yield buildSharedInboxesException(actorsException);
        return result.data.filter(sharedInbox => sharedInboxesException.includes(sharedInbox) === false);
    });
}
function computeUris(toActors, actorsException = []) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        const serverActor = yield (0, application_1.getServerActor)();
        const targetUrls = toActors
            .filter(a => a.id !== serverActor.id)
            .map(a => a.getSharedInbox());
        const toActorSharedInboxesSet = new Set(targetUrls);
        const sharedInboxesException = yield buildSharedInboxesException(actorsException);
        return Array.from(toActorSharedInboxesSet)
            .filter(sharedInbox => sharedInboxesException.includes(sharedInbox) === false);
    });
}
function buildSharedInboxesException(actorsException) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        const serverActor = yield (0, application_1.getServerActor)();
        return actorsException
            .map(f => f.getSharedInbox())
            .concat([serverActor.sharedInboxUrl]);
    });
}
//# sourceMappingURL=send-utils.js.map