Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
3 / 3
CRAP
100.00% covered (success)
100.00%
1 / 1
WikimediaEventsRequestDetailsLookup
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
3 / 3
14
100.00% covered (success)
100.00%
1 / 1
 getEntryPoint
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
4
 getMWEntryPointConstant
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getPlatformDetails
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
9
1<?php
2
3namespace WikimediaEvents\Services;
4
5use MediaWiki\Context\RequestContext;
6
7/**
8 * Looks up information about the current request, such as the platform and entry point. Used to de-duplicate code.
9 */
10class WikimediaEventsRequestDetailsLookup {
11
12    /**
13     * @return string A string which represents the entry point (MW_ENTRY_POINT) for use in Prometheus labels
14     */
15    public function getEntryPoint(): string {
16        $mwEntryPoint = $this->getMWEntryPointConstant();
17        if ( $mwEntryPoint === 'index' ) {
18            // non-AJAX submission from user interface
19            // (for non-WMF this could also mean jobrunner, since jobs run post-send
20            // from index.php by default)
21            return 'index';
22        } elseif ( $mwEntryPoint === 'api' || $mwEntryPoint === 'rest' ) {
23            return 'api';
24        } else {
25            // jobrunner, maint/cli
26            return 'other';
27        }
28    }
29
30    /**
31     * @return string Returns the value of the MW_ENTRY_POINT constant. Mocked in PHPUnit tests.
32     */
33    protected function getMWEntryPointConstant(): string {
34        return MW_ENTRY_POINT;
35    }
36
37    /**
38     * Gets the platform name and whether the device is mobile, for use in Prometheus labels.
39     *
40     * @return string[]
41     */
42    public function getPlatformDetails(): array {
43        // Because ::getEntryPoint only can use details from the main request, we don't want to support a use-case
44        // which has a non-main request context.
45        $context = RequestContext::getMain();
46
47        // It's possible to use Minerva on a desktop device, or Vector on a mobile
48        // device, but defining Minerva usage as a proxy for "is mobile" is good enough
49        // for monitoring.
50        $isMobile = $context->getSkin()->getSkinName() === 'minerva' ? '1' : '0';
51
52        // Would make sense to gate the following lines behind $entry === 'api', but
53        // the entrypoint is hardcoded via MW_ENTRY_POINT, which can't be overridden in tests.
54
55        // Check if the request was Android/iOS/Commons app.
56        $userAgent = $context->getRequest()->getHeader( "User-agent" );
57        $isWikipediaApp = strpos( $userAgent, "WikipediaApp/" ) === 0;
58        $isCommonsApp = strpos( $userAgent, "Commons/" ) === 0;
59        if ( $isWikipediaApp || $isCommonsApp ) {
60            // Consider apps to be "mobile" for instrumentation purposes
61            $isMobile = '1';
62        }
63        if ( $isCommonsApp ) {
64            $platform = 'commons';
65        } elseif ( strpos( $userAgent, "Android" ) > 0 ) {
66            $platform = 'android';
67        } elseif ( strpos( $userAgent, "iOS" ) > 0 || strpos( $userAgent, "iPadOS" ) > 0 ) {
68            $platform = 'ios';
69        } elseif ( $this->getEntryPoint() === 'index' ) {
70            $platform = 'web';
71        } else {
72            $platform = 'unknown';
73        }
74
75        return [ 'platform' => $platform, 'isMobile' => $isMobile ];
76    }
77}