Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
31.91% covered (danger)
31.91%
15 / 47
71.43% covered (warning)
71.43%
5 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
ORESService
31.91% covered (danger)
31.91%
15 / 47
71.43% covered (warning)
71.43%
5 / 7
108.21
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getWikiID
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 getBaseUrl
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getFrontendBaseUrl
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 getUrl
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 request
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 1
42
 getMWHttpRequestOptions
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2/**
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15 */
16
17namespace ORES;
18
19use FormatJson;
20use MediaWiki\Http\HttpRequestFactory;
21use MediaWiki\Request\WebRequest;
22use MediaWiki\Status\Status;
23use MediaWiki\WikiMap\WikiMap;
24use Psr\Log\LoggerInterface;
25use RequestContext;
26use RuntimeException;
27
28/**
29 * Common methods for accessing an ORES server.
30 */
31class ORESService {
32
33    public const API_VERSION = 3;
34
35    /**
36     * @var LoggerInterface
37     */
38    protected $logger;
39
40    /**
41     * @var HttpRequestFactory
42     */
43    protected $httpRequestFactory;
44
45    /**
46     * @param LoggerInterface $logger
47     * @param HttpRequestFactory $httpRequestFactory
48     */
49    public function __construct(
50        LoggerInterface $logger,
51        HttpRequestFactory $httpRequestFactory
52    ) {
53        $this->logger = $logger;
54        $this->httpRequestFactory = $httpRequestFactory;
55    }
56
57    /**
58     * @return string Wiki ID used by ORES.
59     */
60    public static function getWikiID() {
61        global $wgOresWikiId;
62        if ( $wgOresWikiId ) {
63            $wikiId = $wgOresWikiId;
64        } else {
65            $wikiId = WikiMap::getCurrentWikiId();
66        }
67
68        return $wikiId;
69    }
70
71    /**
72     * @return string Base URL of ORES service
73     */
74    public static function getBaseUrl() {
75        global $wgOresBaseUrl;
76
77        return $wgOresBaseUrl;
78    }
79
80    /**
81     * @return string Base URL of ORES service being used externally
82     */
83    public static function getFrontendBaseUrl() {
84        global $wgOresFrontendBaseUrl, $wgOresBaseUrl;
85
86        if ( $wgOresFrontendBaseUrl === null ) {
87            return $wgOresBaseUrl;
88        }
89
90        return $wgOresFrontendBaseUrl;
91    }
92
93    /**
94     * @param string|null $model
95     * @return string Base URL plus your wiki's `scores` API path.
96     */
97    public function getUrl( $model = null ) {
98        $wikiId = self::getWikiID();
99        $prefix = 'v' . self::API_VERSION;
100        $baseUrl = self::getBaseUrl();
101        $url = "{$baseUrl}{$prefix}/scores/{$wikiId}/";
102        return $url;
103    }
104
105    /**
106     * Make an ORES API request and return the decoded result.
107     *
108     * @param array $params
109     * @param WebRequest|string[]|null $originalRequest See MwHttpRequest::setOriginalRequest()
110     *
111     * @return array Decoded response
112     */
113    public function request(
114        array $params,
115        $originalRequest = null
116    ) {
117        $url = $this->getUrl();
118        $params['format'] = 'json';
119        $url = wfAppendQuery( $url, $params );
120        $this->logger->debug( "Requesting: {$url}" );
121        $req = $this->httpRequestFactory->create(
122            $url,
123            $this->getMWHttpRequestOptions( $originalRequest ),
124            __METHOD__
125        );
126        $status = $req->execute();
127        if ( !$status->isOK() ) {
128            $message = "Failed to make ORES request to [{$url}], " .
129                Status::wrap( $status )->getMessage()->inLanguage( 'en' )->text();
130
131            // Server time out, try again once
132            if ( $req->getStatus() === 504 ) {
133                $req = $this->httpRequestFactory->create(
134                    $url,
135                    $this->getMWHttpRequestOptions( $originalRequest ),
136                    __METHOD__
137                );
138                $status = $req->execute();
139                if ( !$status->isOK() ) {
140                    throw new RuntimeException( $message );
141                }
142            } else {
143                throw new RuntimeException( $message );
144            }
145        }
146        $json = $req->getContent();
147        $this->logger->debug( "Raw response: {$json}" );
148        $data = FormatJson::decode( $json, true );
149        if ( !$data || !empty( $data['error'] ) ) {
150            throw new RuntimeException( "Bad response from ORES endpoint [{$url}]: {$json}" );
151        }
152        return $data;
153    }
154
155    /**
156     * @param WebRequest|string[]|null $originalRequest {@see MWHttpRequest::setOriginalRequest}
157     *
158     * @return array
159     */
160    protected function getMWHttpRequestOptions( $originalRequest ) {
161        if ( $originalRequest === null && MW_ENTRY_POINT !== 'cli' ) {
162            $originalRequest = RequestContext::getMain()->getRequest();
163        }
164
165        return $originalRequest ? [ 'originalRequest' => $originalRequest ] : [];
166    }
167
168}