Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
75.00% covered (warning)
75.00%
21 / 28
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
EventBusBridge
75.00% covered (warning)
75.00%
21 / 28
0.00% covered (danger)
0.00%
0 / 3
10.27
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 factory
80.00% covered (warning)
80.00%
8 / 10
0.00% covered (danger)
0.00%
0 / 1
4.13
 onLinksUpdateComplete
92.86% covered (success)
92.86%
13 / 14
0.00% covered (danger)
0.00%
0 / 1
4.01
1<?php
2
3namespace CirrusSearch\Event;
4
5use CirrusSearch\CirrusConfigNames;
6use CirrusSearch\CirrusSearch;
7use CirrusSearch\PageChangeTracker;
8use MediaWiki\Config\Config;
9use MediaWiki\Config\ConfigFactory;
10use MediaWiki\Deferred\DeferredUpdates;
11use MediaWiki\Extension\EventBus\EventBusFactory;
12use MediaWiki\Extension\EventBus\StreamNameMapper;
13use MediaWiki\Page\PageLookup;
14use MediaWiki\Request\WebRequest;
15use MediaWiki\Title\TitleFormatter;
16use Wikimedia\UUID\GlobalIdGenerator;
17
18/**
19 * Hook handler responsible for bridging internal MW events to dedicated event streams.
20 */
21class EventBusBridge extends PageChangeTracker implements EventBridge {
22    private EventBusFactory $eventBusFactory;
23    private PageLookup $pageLookup;
24    private PageRerenderSerializer $pageRerenderSerializer;
25
26    /**
27     * @param EventBusFactory $eventBusFactory
28     * @param PageLookup $pageLookup
29     * @param PageRerenderSerializer $pageRerenderSerializer
30     */
31    public function __construct(
32        EventBusFactory $eventBusFactory,
33        PageLookup $pageLookup,
34        PageRerenderSerializer $pageRerenderSerializer,
35        int $maxStateSize = 512
36    ) {
37        parent::__construct( $maxStateSize );
38        $this->eventBusFactory = $eventBusFactory;
39        $this->pageLookup = $pageLookup;
40        $this->pageRerenderSerializer = $pageRerenderSerializer;
41    }
42
43    /**
44     * @param ConfigFactory $configFactory
45     * @param Config $mainConfig
46     * @param GlobalIdGenerator $globalIdGenerator
47     * @param TitleFormatter $titleFormatter
48     * @param PageLookup $pageLookup
49     * @param EventBusFactory|null $eventBusFactory
50     * @return EventBridge
51     */
52    public static function factory(
53        ConfigFactory $configFactory,
54        Config $mainConfig,
55        GlobalIdGenerator $globalIdGenerator,
56        TitleFormatter $titleFormatter,
57        PageLookup $pageLookup,
58        ?EventBusFactory $eventBusFactory = null,
59        ?StreamNameMapper $streamNameMapper = null
60    ): EventBridge {
61        $config = $configFactory->makeConfig( CirrusSearch::NAME );
62        '@phan-var \CirrusSearch\SearchConfig $config';
63        if ( $eventBusFactory !== null && $config->get( CirrusConfigNames::UseEventBusBridge ) ) {
64            if ( $streamNameMapper === null ) {
65                throw new \RuntimeException( 'EventBusFactory provided without StreamNameMapper' );
66            }
67            $pageRerenderSerializer = new PageRerenderSerializer( $mainConfig, $titleFormatter,
68                $config, $globalIdGenerator, $streamNameMapper );
69            return new self( $eventBusFactory, $pageLookup, $pageRerenderSerializer );
70        }
71        return new class() implements EventBridge {
72            /**
73             * @inheritDoc
74             */
75            public function onLinksUpdateComplete( $linksUpdate, $ticket ) {
76            }
77        };
78    }
79
80    /**
81     * @inheritDoc
82     */
83    public function onLinksUpdateComplete( $linksUpdate, $ticket ) {
84        DeferredUpdates::addCallableUpdate( function () use ( $linksUpdate ) {
85            if ( $this->isPageChange( $linksUpdate->getPageId() ) ) {
86                // Page changes are handled via the page-change stream
87                return;
88            }
89            $page = $this->pageLookup->getPageById( $linksUpdate->getPageId() );
90            if ( $page === null ) {
91                // the page no longer exists
92                return;
93            }
94            if ( $page->isRedirect() ) {
95                // We are not really interested in redirects at this point
96                // since we would ultimately refresh the target of this redirect we assume
97                // that a LinksUpdate for the redirect does not imply that the target page has
98                // to re-render as well.
99                return;
100            }
101            $event = $this->pageRerenderSerializer->eventDataForPage( $page,
102                PageRerenderSerializer::LINKS_UPDATE_REASON, WebRequest::getRequestId() );
103            // Fire and forget, we do not check the return value, problems should be already logged by
104            // EventBus
105            $this->eventBusFactory
106                ->getInstanceForStream( $event['meta']['stream'] )
107                ->send( [ $event ] );
108        } );
109    }
110}