typo fix
[pykit.git] / Publisher.cc
1 // $Id$
2 //
3 // Copyright (C) 2010
4
5 /** \file
6     \brief InternalNetworkAccessManager non-inline non-template implementation */
7
8 #include "Publisher.hh"
9 //#include "Publisher.ih"
10
11 // Custom includes
12 #include <iostream>
13 #include <QNetworkProxy>
14 #include <QVariant>
15 #include "Publisher.hh"
16 #include <boost/python.hpp>
17
18 //#include "Publisher.mpp"
19 #define prefix_
20 ///////////////////////////////cc.p////////////////////////////////////////
21
22 ///////////////////////////////////////////////////////////////////////////
23 // pykit::detail::InternalServerReply
24
25 namespace pykit {
26 namespace detail {
27
28     class InternalServerReply
29         : public QNetworkReply
30     {
31         Q_OBJECT;
32     public:
33         InternalServerReply(QNetworkAccessManager::Operation operation,
34                             QNetworkRequest const & networkRequest,
35                             QIODevice * postData, Publisher * publisher);
36
37         // Forwarded to buffer
38         virtual bool atEnd() const;
39         virtual qint64 bytesAvailable() const;
40         virtual qint64 bytesToWrite() const;
41         virtual bool canReadLine() const;
42         virtual bool isSequential() const;
43         virtual qint64 pos() const;
44         virtual bool reset();
45         virtual bool seek(qint64 pos);
46         virtual qint64 size() const;
47         virtual bool waitForBytesWritten(int msecs);
48         virtual bool waitForReadyRead(int msecs);
49
50         virtual void abort();
51
52         using QNetworkReply::setHeader;
53         using QNetworkReply::setRawHeader;
54         using QNetworkReply::setAttribute;
55
56         void clearResponse();
57         QByteArray postData() const;
58         QString postContentType() const;
59
60     protected:
61         virtual qint64 readData(char * data, qint64 maxSize);
62         virtual qint64 writeData(char const * data, qint64 maxSize);
63
64     private slots:
65         void bufferPostData();
66         void postDataReadable();
67         void postDataComplete();
68         void processRequest();
69         void complete();
70
71     private:
72         bool readPostData();
73
74         Publisher * publisher_;
75         QIODevice * postDevice_;
76         QBuffer buffer_;
77         QBuffer postData_;
78     };
79
80 }}
81
82 prefix_ pykit::detail::InternalServerReply::
83 InternalServerReply(QNetworkAccessManager::Operation operation,
84                     QNetworkRequest const & networkRequest, QIODevice * postData,
85                     Publisher * publisher)
86     : publisher_ (publisher), postDevice_ (postData)
87 {
88     setRequest(networkRequest);
89     setOperation(operation);
90     setUrl(networkRequest.url());
91     open(ReadWrite | Unbuffered);
92     buffer_.open(ReadWrite | Unbuffered);
93
94     if (postDevice_)
95         QMetaObject::invokeMethod(this, "bufferPostData", Qt::QueuedConnection);
96     else
97         QMetaObject::invokeMethod(this, "processRequest", Qt::QueuedConnection);
98 }
99
100 prefix_ void pykit::detail::InternalServerReply::bufferPostData()
101 {
102     QVariant cl (request().header(QNetworkRequest::ContentLengthHeader));
103     connect(postDevice_, SIGNAL(readyRead()), this, SLOT(postDataReadable()));
104     connect(postDevice_, SIGNAL(readChannelFinished()), this, SLOT(postDataComplete()));
105     postData_.open(WriteOnly);
106     postDataReadable();
107 }
108
109 prefix_ bool pykit::detail::InternalServerReply::readPostData()
110 {
111     while (true) {
112         qint64 n (postDevice_->bytesAvailable());
113         if (n <= 0)
114             n = 2048;
115         QByteArray data;
116         data.resize(n);
117         n  = postDevice_->read(data.data(), n);
118         if (n < 0)
119             return true;
120         else {
121             data.resize(n);
122             postData_.write(data);
123         }
124         if (n == 0)
125             return false;
126     }
127 }
128
129 prefix_ void pykit::detail::InternalServerReply::postDataReadable()
130 {
131     if (readPostData()) {
132         disconnect(postDevice_, SIGNAL(readyRead()), this, SLOT(postDataReadable()));
133         disconnect(postDevice_, SIGNAL(readChannelFinished()), this, SLOT(postDataComplete()));
134         processRequest();
135     }
136 }
137
138 prefix_ void pykit::detail::InternalServerReply::postDataComplete()
139 {
140     readPostData();
141     disconnect(postDevice_, SIGNAL(readyRead()), this, SLOT(postDataReadable()));
142     disconnect(postDevice_, SIGNAL(readChannelFinished()), this, SLOT(postDataComplete()));
143     processRequest();
144 }
145
146 prefix_ void pykit::detail::InternalServerReply::processRequest()
147 {
148     Request request (*this);
149     publisher_->publish(request);
150
151     seek(0);
152     setHeader(QNetworkRequest::ContentLengthHeader, QVariant(size()));
153
154     QMetaObject::invokeMethod(this, "complete", Qt::QueuedConnection);
155 }
156
157 prefix_ void pykit::detail::InternalServerReply::complete()
158 {
159     emit readyRead();
160     emit finished();
161 }
162
163 prefix_ bool pykit::detail::InternalServerReply::atEnd()
164     const
165 { return buffer_.atEnd(); }
166
167 prefix_ qint64 pykit::detail::InternalServerReply::bytesAvailable()
168     const
169 { return buffer_.bytesAvailable(); }
170
171 prefix_ qint64 pykit::detail::InternalServerReply::bytesToWrite()
172     const
173 { return buffer_.bytesToWrite(); }
174
175 prefix_ bool pykit::detail::InternalServerReply::canReadLine()
176     const
177 { return buffer_.canReadLine(); }
178
179 prefix_ bool pykit::detail::InternalServerReply::isSequential()
180     const
181 { return buffer_.isSequential(); }
182
183 prefix_ qint64 pykit::detail::InternalServerReply::pos()
184     const
185 { return buffer_.pos(); }
186
187 prefix_ bool pykit::detail::InternalServerReply::reset()
188 { return buffer_.reset(); }
189
190 prefix_ bool pykit::detail::InternalServerReply::seek(qint64 pos)
191 { return buffer_.seek(pos); }
192
193 prefix_ qint64 pykit::detail::InternalServerReply::size()
194     const
195 { return buffer_.size(); }
196
197 prefix_ bool pykit::detail::InternalServerReply::waitForBytesWritten(int msecs)
198 { return buffer_.waitForBytesWritten(msecs); }
199
200 prefix_ bool pykit::detail::InternalServerReply::waitForReadyRead(int msecs)
201 { return buffer_.waitForReadyRead(msecs); }
202
203 prefix_ qint64 pykit::detail::InternalServerReply::readData(char * data, qint64 maxSize)
204 {
205     qint64 n (buffer_.read(data,maxSize));
206     if (buffer_.atEnd())
207         emit readChannelFinished();
208     return n;
209 }
210
211 prefix_ qint64 pykit::detail::InternalServerReply::writeData(char const * data, qint64 maxSize)
212 { return buffer_.write(data,maxSize); }
213
214 prefix_ void pykit::detail::InternalServerReply::abort()
215 {}
216
217 prefix_ void pykit::detail::InternalServerReply::clearResponse()
218 {
219     buffer_.buffer().clear();
220 }
221
222 prefix_ QByteArray pykit::detail::InternalServerReply::postData()
223     const
224 {
225     return postData_.buffer();
226 }
227
228 prefix_ QString pykit::detail::InternalServerReply::postContentType()
229     const
230 {
231     return request().header(QNetworkRequest::ContentTypeHeader).toString();
232 }
233
234 ///////////////////////////////////////////////////////////////////////////
235 // pykit::Request
236
237 prefix_ void pykit::Request::write(std::string const & data)
238 {
239     reply_.write(QByteArray(data.data(),data.size()));
240 }
241
242 prefix_ void pykit::Request::reset()
243 {
244     reply_.clearResponse();
245 }
246
247 prefix_ void pykit::Request::setContentType(std::string const & contentType)
248 {
249     reply_.setHeader(QNetworkRequest::ContentTypeHeader, QVariant(contentType.c_str()));
250 }
251
252 prefix_ void pykit::Request::setLocation(std::string const & location)
253 {
254     reply_.setHeader(QNetworkRequest::LocationHeader, QVariant(location.c_str()));
255 }
256
257 prefix_ void pykit::Request::setHeader(std::string const & header, std::string const & value)
258 {
259     reply_.setRawHeader(header.c_str(), value.c_str());
260 }
261
262 prefix_ void pykit::Request::setStatusCode(int code)
263 {
264     reply_.setAttribute(QNetworkRequest::HttpStatusCodeAttribute, code);
265 }
266
267 prefix_ QUrl pykit::Request::url()
268     const
269 {
270     return reply_.url();
271 }
272
273 prefix_ QByteArray pykit::Request::postData()
274     const
275 {
276     return reply_.postData();
277 }
278
279 prefix_ QByteArray pykit::Request::operation()
280     const
281 {
282     static char const * const operationNames[]
283         = { "", "HEAD", "GET", "PUT", "POST", "DELETE", "" };
284     return operationNames[reply_.operation()];
285 }
286
287 prefix_ QString pykit::Request::postContentType()
288     const
289 {
290     return reply_.postContentType();
291 }
292
293 prefix_ pykit::Request::Request(detail::InternalServerReply & reply)
294     : reply_ (reply)
295 {}
296
297 ///////////////////////////////////////////////////////////////////////////
298 // pykit::InternalNetworkAccessManager
299
300 prefix_ pykit::InternalNetworkAccessManager::
301 InternalNetworkAccessManager(QNetworkAccessManager * manager, QObject * parent,
302                              Publisher * publisher)
303     : QNetworkAccessManager(parent), publisher_ (publisher)
304 {
305     setCache(manager->cache());
306     setCookieJar(manager->cookieJar());
307     setProxy(manager->proxy());
308     setProxyFactory(manager->proxyFactory());
309 }
310
311 prefix_ QNetworkReply *
312 pykit::InternalNetworkAccessManager::createRequest(Operation operation,
313                                                         QNetworkRequest const & request,
314                                                         QIODevice * device)
315 {
316     if (request.url().host() != "pykit")
317         return QNetworkAccessManager::createRequest(operation, request, device);
318     return new detail::InternalServerReply(operation, request, device, publisher_);
319 }
320
321 #include "Publisher.moc"
322
323 ///////////////////////////////cc.e////////////////////////////////////////
324 #undef prefix_
325 //#include "Publisher.mpp"
326
327 \f
328 // Local Variables:
329 // mode: c++
330 // fill-column: 100
331 // comment-column: 40
332 // c-file-style: "j32"
333 // indent-tabs-mode: nil
334 // ispell-local-dictionary: "american"
335 // compile-command: "scons -U"
336 // End: