Changeset View
Changeset View
Standalone View
Standalone View
runners/mediawiki/mediawiki.cpp
Show All 14 Lines | |||||
15 | * You should have received a copy of the GNU Library General Public | 15 | * You should have received a copy of the GNU Library General Public | ||
16 | * License along with this program; if not, write to the | 16 | * License along with this program; if not, write to the | ||
17 | * Free Software Foundation, Inc., | 17 | * Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
19 | */ | 19 | */ | ||
20 | 20 | | |||
21 | #include "mediawiki.h" | 21 | #include "mediawiki.h" | ||
22 | 22 | | |||
23 | // KF | ||||
24 | #include <KRunner/RunnerContext> | ||||
25 | // Qt | ||||
23 | #include <QNetworkAccessManager> | 26 | #include <QNetworkAccessManager> | ||
24 | #include <QNetworkRequest> | 27 | #include <QNetworkRequest> | ||
25 | #include <QNetworkReply> | 28 | #include <QNetworkReply> | ||
26 | #include <QXmlStreamReader> | 29 | #include <QXmlStreamReader> | ||
27 | #include <QTimer> | 30 | #include <QTimer> | ||
28 | 31 | #include <QUrlQuery> | |||
29 | #include <KDebug> | | |||
30 | #include <KIO/AccessManager> | | |||
31 | | ||||
32 | #include <Plasma/RunnerContext> | | |||
33 | 32 | | |||
34 | enum State { | 33 | enum State { | ||
35 | StateApiChanged, | 34 | StateApiChanged, | ||
36 | StateApiUpdating, | 35 | StateApiUpdating, | ||
37 | StateReady | 36 | StateReady | ||
38 | }; | 37 | }; | ||
39 | 38 | | |||
40 | struct MediaWikiPrivate { | 39 | struct MediaWikiPrivate { | ||
Show All 10 Lines | |||||
51 | }; | 50 | }; | ||
52 | 51 | | |||
53 | MediaWiki::MediaWiki( QObject *parent ) | 52 | MediaWiki::MediaWiki( QObject *parent ) | ||
54 | : QObject( parent ), | 53 | : QObject( parent ), | ||
55 | d( new MediaWikiPrivate ) | 54 | d( new MediaWikiPrivate ) | ||
56 | { | 55 | { | ||
57 | d->state = StateApiChanged; | 56 | d->state = StateApiChanged; | ||
58 | // should be overwritten by the user | 57 | // should be overwritten by the user | ||
59 | d->apiUrl = QUrl("http://en.wikipedia.org/w/api.php"); | 58 | d->apiUrl = QUrl(QStringLiteral("https://en.wikipedia.org/w/api.php")); | ||
60 | //FIXME: at the moment KIO doesn't seem to work in threads | 59 | //FIXME: at the moment KIO doesn't seem to work in threads | ||
61 | d->manager = new QNetworkAccessManager( this ); | 60 | d->manager = new QNetworkAccessManager( this ); | ||
61 | d->manager->setRedirectPolicy(QNetworkRequest::NoLessSafeRedirectPolicy); | ||||
broulik: Make sure to enable `QNetworkAccessManager` auto-redirect or else Ben will get mad at you | |||||
62 | //d->manager = new KIO::AccessManager( this ); | 62 | //d->manager = new KIO::AccessManager( this ); | ||
63 | d->maxItems = 10; | 63 | d->maxItems = 10; | ||
64 | d->timeout = 30 * 1000; // 30 second | 64 | d->timeout = 30 * 1000; // 30 second | ||
65 | d->reply = 0; | 65 | d->reply = nullptr; | ||
66 | d->userAgent = QByteArray("KDE Plasma Silk; MediaWikiRunner; 1.0"); | 66 | d->userAgent = QByteArray("KDE Plasma Silk; MediaWikiRunner; 1.0"); | ||
67 | 67 | | |||
68 | connect( d->manager, SIGNAL(finished(QNetworkReply*)), SLOT(finished(QNetworkReply*)) ); | 68 | connect(d->manager, &QNetworkAccessManager::finished, this, &MediaWiki::onNetworkRequestFinished); | ||
69 | } | 69 | } | ||
70 | 70 | | |||
71 | MediaWiki::~MediaWiki() | 71 | MediaWiki::~MediaWiki() | ||
72 | { | 72 | { | ||
73 | delete d; | 73 | delete d; | ||
74 | } | 74 | } | ||
75 | 75 | | |||
76 | QList<MediaWiki::Result> MediaWiki::results() const | 76 | QList<MediaWiki::Result> MediaWiki::results() const | ||
Show All 36 Lines | |||||
113 | } | 113 | } | ||
114 | 114 | | |||
115 | void MediaWiki::abort() | 115 | void MediaWiki::abort() | ||
116 | { | 116 | { | ||
117 | if ( !d->reply ) | 117 | if ( !d->reply ) | ||
118 | return; | 118 | return; | ||
119 | 119 | | |||
120 | d->reply->abort(); | 120 | d->reply->abort(); | ||
121 | d->reply = 0; | 121 | d->reply = nullptr; | ||
122 | } | 122 | } | ||
123 | 123 | | |||
124 | void MediaWiki::search( const QString &searchTerm ) | 124 | void MediaWiki::search( const QString &searchTerm ) | ||
125 | { | 125 | { | ||
126 | QUrl url = d->apiUrl; | 126 | QUrl url = d->apiUrl; | ||
127 | url.addQueryItem( QString("action"), QString("query") ); | 127 | QUrlQuery urlQuery(url); | ||
128 | url.addQueryItem( QString("format"), QString("xml") ); | 128 | urlQuery.addQueryItem(QStringLiteral("action"), QStringLiteral("query")); | ||
129 | url.addQueryItem( QString("list"), QString("search") ); | 129 | urlQuery.addQueryItem(QStringLiteral("format"), QStringLiteral("xml")); | ||
130 | url.addQueryItem( QString("srsearch"), searchTerm ); | 130 | urlQuery.addQueryItem(QStringLiteral("list"), QStringLiteral("search")); | ||
131 | url.addQueryItem( QString("srlimit"), QString::number(d->maxItems) ); | 131 | urlQuery.addQueryItem(QStringLiteral("srsearch"), searchTerm ); | ||
132 | urlQuery.addQueryItem(QStringLiteral("srlimit"), QString::number(d->maxItems)); | ||||
133 | url.setQuery(urlQuery); | ||||
132 | 134 | | |||
133 | kDebug() << "Constructed search URL" << url; | 135 | qDebug() << "Constructed search URL" << url; | ||
broulik: Categorized logging, perhaps? | |||||
Yes, though I plan to do this later in one concentrated go for all of kdeplasma-addons, so things will be consistent and complete. kossebau: Yes, though I plan to do this later in one concentrated go for all of kdeplasma-addons, so… | |||||
134 | 136 | | |||
135 | if ( d->state == StateReady ) { | 137 | if ( d->state == StateReady ) { | ||
136 | QNetworkRequest req(url); | 138 | QNetworkRequest req(url); | ||
137 | req.setRawHeader( QByteArray("User-Agent"), d->userAgent ); | 139 | req.setRawHeader( QByteArray("User-Agent"), d->userAgent ); | ||
138 | kDebug() << "mediawiki User-Agent" << req.rawHeader(QByteArray("UserAgent")); | 140 | qDebug() << "mediawiki User-Agent" << req.rawHeader(QByteArray("UserAgent")); | ||
139 | 141 | | |||
140 | d->reply = d->manager->get( req ); | 142 | d->reply = d->manager->get( req ); | ||
141 | QTimer::singleShot( d->timeout, this, SLOT(abort()) ); | 143 | QTimer::singleShot( d->timeout, this, SLOT(abort()) ); | ||
142 | } else if ( d->state == StateApiChanged ) { | 144 | } else if ( d->state == StateApiChanged ) { | ||
143 | d->query = url; | 145 | d->query = url; | ||
144 | findBase(); | 146 | findBase(); | ||
145 | } | 147 | } | ||
146 | } | 148 | } | ||
147 | 149 | | |||
148 | void MediaWiki::findBase() | 150 | void MediaWiki::findBase() | ||
149 | { | 151 | { | ||
150 | // http://en.wikipedia.org/w/api.php?action=query&meta=siteinfo | 152 | // http://en.wikipedia.org/w/api.php?action=query&meta=siteinfo | ||
151 | QUrl url = d->apiUrl; | 153 | QUrl url = d->apiUrl; | ||
152 | url.addQueryItem( QString("action"), QString("query") ); | 154 | QUrlQuery urlQuery(url); | ||
153 | url.addQueryItem( QString("format"), QString("xml") ); | 155 | urlQuery.addQueryItem(QStringLiteral("action"), QStringLiteral("query")); | ||
154 | url.addQueryItem( QString("meta"), QString("siteinfo") ); | 156 | urlQuery.addQueryItem(QStringLiteral("format"), QStringLiteral("xml")); | ||
157 | urlQuery.addQueryItem(QStringLiteral("meta"), QStringLiteral("siteinfo")); | ||||
158 | url.setQuery(urlQuery); | ||||
155 | 159 | | |||
156 | kDebug() << "Constructed base query URL" << url; | 160 | qDebug() << "Constructed base query URL" << url; | ||
157 | QNetworkRequest req(url); | 161 | QNetworkRequest req(url); | ||
158 | req.setRawHeader( QByteArray("User-Agent"), d->userAgent ); | 162 | req.setRawHeader( QByteArray("User-Agent"), d->userAgent ); | ||
159 | 163 | | |||
160 | d->reply = d->manager->get( req ); | 164 | d->reply = d->manager->get( req ); | ||
161 | d->state = StateApiUpdating; | 165 | d->state = StateApiUpdating; | ||
162 | } | 166 | } | ||
163 | 167 | | |||
164 | void MediaWiki::finished( QNetworkReply *reply ) | 168 | void MediaWiki::onNetworkRequestFinished(QNetworkReply *reply) | ||
165 | { | 169 | { | ||
166 | if ( reply->error() != QNetworkReply::NoError ) { | 170 | if ( reply->error() != QNetworkReply::NoError ) { | ||
167 | kDebug() << "Request failed, " << reply->errorString(); | 171 | qDebug() << "Request failed, " << reply->errorString(); | ||
168 | emit finished(false); | 172 | emit finished(false); | ||
169 | return; | 173 | return; | ||
170 | } | 174 | } | ||
171 | 175 | | |||
172 | kDebug() << "Request succeeded" << d->apiUrl; | 176 | qDebug() << "Request succeeded" << d->apiUrl; | ||
173 | 177 | | |||
174 | if ( d->state == StateApiUpdating ) { | 178 | if ( d->state == StateApiUpdating ) { | ||
175 | bool ok = processBaseResult( reply ); | 179 | bool ok = processBaseResult( reply ); | ||
176 | Q_UNUSED ( ok ); | 180 | Q_UNUSED ( ok ); | ||
177 | reply->deleteLater(); | 181 | reply->deleteLater(); | ||
178 | reply= 0; | 182 | reply= nullptr; | ||
179 | d->state = StateReady; | 183 | d->state = StateReady; | ||
180 | 184 | | |||
181 | QNetworkRequest req(d->query); | 185 | QNetworkRequest req(d->query); | ||
182 | req.setRawHeader( QByteArray("User-Agent"), d->userAgent ); | 186 | req.setRawHeader( QByteArray("User-Agent"), d->userAgent ); | ||
183 | d->reply = d->manager->get( req ); | 187 | d->reply = d->manager->get( req ); | ||
184 | QTimer::singleShot( d->timeout, this, SLOT(abort()) ); | 188 | QTimer::singleShot( d->timeout, this, SLOT(abort()) ); | ||
185 | } else { | 189 | } else { | ||
186 | bool ok = processSearchResult( reply ); | 190 | bool ok = processSearchResult( reply ); | ||
187 | 191 | | |||
188 | emit finished( ok ); | 192 | emit finished( ok ); | ||
189 | d->reply->deleteLater(); | 193 | d->reply->deleteLater(); | ||
190 | d->reply = 0; | 194 | d->reply = nullptr; | ||
191 | } | 195 | } | ||
192 | } | 196 | } | ||
193 | 197 | | |||
194 | bool MediaWiki::processBaseResult( QIODevice *source ) | 198 | bool MediaWiki::processBaseResult( QIODevice *source ) | ||
195 | { | 199 | { | ||
196 | QXmlStreamReader reader( source ); | 200 | QXmlStreamReader reader( source ); | ||
197 | 201 | | |||
198 | while ( !reader.atEnd() ) { | 202 | while ( !reader.atEnd() ) { | ||
199 | QXmlStreamReader::TokenType tokenType = reader.readNext(); | 203 | QXmlStreamReader::TokenType tokenType = reader.readNext(); | ||
200 | // kDebug() << "Token" << int(tokenType); | 204 | // qDebug() << "Token" << int(tokenType); | ||
201 | if ( tokenType == QXmlStreamReader::StartElement ) { | 205 | if ( tokenType == QXmlStreamReader::StartElement ) { | ||
202 | if ( reader.name() == QString("general") ) { | 206 | if (reader.name() == QLatin1String("general")) { | ||
203 | QXmlStreamAttributes attrs = reader.attributes(); | 207 | QXmlStreamAttributes attrs = reader.attributes(); | ||
204 | 208 | | |||
205 | d->baseUrl = QUrl( attrs.value( QString("base") ).toString() ); | 209 | d->baseUrl = QUrl(attrs.value(QStringLiteral("base")).toString()); | ||
206 | return true; | 210 | return true; | ||
207 | } | 211 | } | ||
208 | } else if ( tokenType == QXmlStreamReader::Invalid ) | 212 | } else if ( tokenType == QXmlStreamReader::Invalid ) | ||
209 | return false; | 213 | return false; | ||
210 | } | 214 | } | ||
211 | 215 | | |||
212 | return true; | 216 | return true; | ||
213 | } | 217 | } | ||
214 | 218 | | |||
215 | bool MediaWiki::processSearchResult( QIODevice *source ) | 219 | bool MediaWiki::processSearchResult( QIODevice *source ) | ||
216 | { | 220 | { | ||
217 | d->results.clear(); | 221 | d->results.clear(); | ||
218 | 222 | | |||
219 | QXmlStreamReader reader( source ); | 223 | QXmlStreamReader reader( source ); | ||
220 | while ( !reader.atEnd() ) { | 224 | while ( !reader.atEnd() ) { | ||
221 | QXmlStreamReader::TokenType tokenType = reader.readNext(); | 225 | QXmlStreamReader::TokenType tokenType = reader.readNext(); | ||
222 | // kDebug() << "Token" << int(tokenType); | 226 | // qDebug() << "Token" << int(tokenType); | ||
223 | if ( tokenType == QXmlStreamReader::StartElement ) { | 227 | if ( tokenType == QXmlStreamReader::StartElement ) { | ||
224 | if ( reader.name() == QString("p") ) { | 228 | if (reader.name() == QLatin1String("p")) { | ||
225 | QXmlStreamAttributes attrs = reader.attributes(); | 229 | QXmlStreamAttributes attrs = reader.attributes(); | ||
226 | 230 | | |||
227 | Result r; | 231 | Result r; | ||
228 | r.url = d->baseUrl.resolved( attrs.value( QString("title") ).toString() ); | 232 | r.title = attrs.value(QStringLiteral("title")).toString(); | ||
229 | r.title = attrs.value( QString("title") ).toString(); | 233 | r.url = d->baseUrl.resolved(QUrl(r.title)); | ||
230 | 234 | | |||
231 | kDebug() << "Got result: url=" << r.url << "title=" << r.title; | 235 | qDebug() << "Got result: url=" << r.url << "title=" << r.title; | ||
232 | 236 | | |||
233 | d->results.prepend( r ); | 237 | d->results.prepend( r ); | ||
234 | } | 238 | } | ||
235 | } else if ( tokenType == QXmlStreamReader::Invalid ) { | 239 | } else if ( tokenType == QXmlStreamReader::Invalid ) { | ||
236 | return false; | 240 | return false; | ||
237 | } | 241 | } | ||
238 | } | 242 | } | ||
239 | return true; | 243 | return true; | ||
240 | } | 244 | } | ||
241 | | ||||
242 | |
Make sure to enable QNetworkAccessManager auto-redirect or else Ben will get mad at you