Compile with QT_STRICT_ITERATORS definition.
[kdenetwork.git] / kget / transfer-plugins / multisegmentkio / multisegkio.cpp
blobddf6483615bc3ca70796e95e6af6365e32caaf15
1 /* This file is part of the KDE project
3 Copyright (C) 2006 Manolo Valdes <nolis71cu@gmail.com>
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9 */
11 #include "multisegkio.h"
12 #include "multisegkiosettings.h"
14 #include "core/kget.h"
16 #include <kde_file.h>
18 #include <QFile>
19 #include <QTimer>
21 #include <sys/time.h>
22 #include <fcntl.h>
24 static const unsigned int max_nums = 8;
25 class MultiSegmentCopyJob::MultiSegmentCopyJobPrivate
27 public:
28 MultiSegmentCopyJobPrivate() {
29 start_time.tv_sec = 0;
30 start_time.tv_usec = 0;
31 last_time = 0;
32 nums = 0;
33 bytes = 0;
35 struct timeval start_time;
36 uint nums;
37 long times[max_nums];
38 KIO::filesize_t sizes[max_nums];
39 size_t last_time;
40 KIO::filesize_t bytes;
42 QTimer speed_timer;
46 /**
47 * class MultiSegmentCopyJob
49 MultiSegmentCopyJob::MultiSegmentCopyJob( const QList<KUrl> Urls, const KUrl& dest, int permissions, uint segments)
50 :KJob(0), d(new MultiSegmentCopyJobPrivate),
51 m_dest(dest),
52 m_permissions(permissions),
53 m_writeBlocked(false),
54 m_segSplited(false),
55 m_chunkSize(0)
57 kDebug(5001);
58 SegFactory = new SegmentFactory( segments, Urls );
59 connect(SegFactory, SIGNAL(createdSegment(Segment *)), SLOT(slotConnectSegment( Segment *)));
61 m_putJob = 0;
62 connect(&d->speed_timer, SIGNAL(timeout()), SLOT(calcSpeed()));
63 QTimer::singleShot(0, this, SLOT(slotStart()));
66 MultiSegmentCopyJob::MultiSegmentCopyJob(
67 const QList<KUrl> Urls,
68 const KUrl& dest,
69 int permissions,
70 qulonglong ProcessedSize,
71 KIO::filesize_t totalSize,
72 QList<SegData> SegmentsData,
73 uint segments)
75 :KJob(0), d(new MultiSegmentCopyJobPrivate),
76 m_dest(dest),
77 m_permissions(permissions),
78 m_writeBlocked(false),
79 m_segSplited(false)
81 kDebug(5001);
82 SegFactory = new SegmentFactory( segments, Urls );
83 connect(SegFactory, SIGNAL(createdSegment(Segment *)), SLOT(slotConnectSegment( Segment *)));
85 if ( !SegmentsData.isEmpty() )
87 QList<SegData>::const_iterator it = SegmentsData.constBegin();
88 QList<SegData>::const_iterator itEnd = SegmentsData.constEnd();
89 for ( ; it!=itEnd ; ++it )
91 SegFactory->createSegment( (*it), SegFactory->nextUrl() );
95 m_putJob = 0;
96 connect(&d->speed_timer, SIGNAL(timeout()), SLOT(calcSpeed()));
97 setProcessedAmount(Bytes, ProcessedSize);
98 setTotalAmount(Bytes, totalSize);
99 QTimer::singleShot(0, this, SLOT(slotStart()));
102 MultiSegmentCopyJob::~MultiSegmentCopyJob()
104 kDebug(5001);
105 SegFactory->deleteLater();
106 delete d;
109 QList<SegData> MultiSegmentCopyJob::SegmentsData()
111 return SegFactory->SegmentsData();
114 void MultiSegmentCopyJob::stop()
116 kDebug(5001);
117 setError(KIO::ERR_USER_CANCELED);
118 if (SegFactory)
119 SegFactory->stopTransfer();
120 if (m_putJob)
121 m_putJob->close();
124 void MultiSegmentCopyJob::slotUrls(QList<KUrl>& Urls)
126 SegFactory->setUrls(Urls);
127 slotSplitSegment();
130 void MultiSegmentCopyJob::slotStart()
132 kDebug(5001);
133 if( !checkLocalFile() )
134 emitResult();
136 kDebug(5001) << " opening: " << m_dest_part;
137 m_putJob = KIO::open(m_dest_part, QIODevice::WriteOnly | QIODevice::ReadOnly);
138 connect( m_putJob, SIGNAL(open(KIO::Job *)), SLOT(slotOpen(KIO::Job *)));
139 connect(m_putJob, SIGNAL(close(KIO::Job *)), SLOT(slotClose(KIO::Job *)));
140 connect( m_putJob, SIGNAL(written(KIO::Job * ,KIO::filesize_t )), SLOT(slotWritten( KIO::Job * ,KIO::filesize_t )));
141 connect( m_putJob, SIGNAL(result(KJob *)), SLOT(slotResult( KJob *)));
143 emit description(this, "multiSegmentCopyJob",
144 qMakePair(QString("source"), SegFactory->Urls().at(0).url()),
145 qMakePair(QString("destination"), m_dest.url()));
148 void MultiSegmentCopyJob::slotOpen( KIO::Job * job)
150 Q_UNUSED(job);
152 kDebug(5001);
153 if( SegFactory->startTransfer() )
156 gettimeofday(&d->start_time, 0);
157 d->last_time = 0;
158 d->sizes[0] = processedAmount(Bytes) - d->bytes;
159 d->times[0] = 0;
160 d->nums = 1;
161 d->speed_timer.start(1000);
163 return;
166 SegData data;
167 m_firstSeg = SegFactory->createSegment(data, SegFactory->nextUrl() );
168 connect( m_firstSeg->job(), SIGNAL(totalSize( KJob *, qulonglong )),
169 SLOT(slotTotalSize( KJob *, qulonglong )));
170 m_firstSeg->startTransfer();
172 if( MultiSegKioSettings::useSearchEngines() && !(SegFactory->Urls().size() > 1) )
174 kDebug(5001) << "waiting 30 seg for the mirror search result...";
175 QTimer::singleShot(30000, this, SLOT(slotSplitSegment()));
179 void MultiSegmentCopyJob::slotWritten( KIO::Job * ,KIO::filesize_t bytesWritten)
181 // kDebug(5001) << "MultiSegmentCopyJob::slotWritten() " << bytesWritten;
182 m_writeBlocked = false;
183 setProcessedAmount(Bytes, processedAmount(Bytes)+bytesWritten);
184 if( processedAmount(Bytes) == totalAmount(Bytes) )
185 m_putJob->close();
188 void MultiSegmentCopyJob::slotClose( KIO::Job * )
190 kDebug(5001) << " putjob";
191 if( processedAmount(Bytes) == totalAmount(Bytes) )
193 kDebug(5001) << "Renaming local file.";
194 QString dest_orig = m_dest.path();
195 QString dest_part = m_dest_part.path();
196 if ( QFile::exists (dest_orig) )
198 QFile::remove (dest_orig);
200 QFile::rename ( dest_part, dest_orig );
202 emit updateSegmentsData();
205 // tooked from SlaveInterface.cpp
206 void MultiSegmentCopyJob::calcSpeed()
208 struct timeval tv;
209 gettimeofday(&tv, 0);
211 long diff = ((tv.tv_sec - d->start_time.tv_sec) * 1000000 +
212 tv.tv_usec - d->start_time.tv_usec) / 1000;
213 if (diff - d->last_time >= 900) {
214 d->last_time = diff;
215 if (d->nums == max_nums) {
216 // let's hope gcc can optimize that well enough
217 // otherwise I'd try memcpy :)
218 for (unsigned int i = 1; i < max_nums; ++i) {
219 d->times[i-1] = d->times[i];
220 d->sizes[i-1] = d->sizes[i];
222 d->nums--;
224 d->times[d->nums] = diff;
225 d->sizes[d->nums++] = processedAmount(Bytes) - d->bytes;
227 KIO::filesize_t lspeed = 1000 * (d->sizes[d->nums-1] - d->sizes[0]) / (d->times[d->nums-1] - d->times[0]);
229 if (!lspeed) {
230 d->nums = 1;
231 d->times[0] = diff;
232 d->sizes[0] = processedAmount(Bytes) - d->bytes;
234 emit speed(this, lspeed);
238 void MultiSegmentCopyJob::slotConnectSegment( Segment *seg)
240 kDebug(5001);
241 connect( seg, SIGNAL(data( Segment*, const QByteArray&, bool &)),
242 SLOT(slotDataReq( Segment *, const QByteArray&, bool &)));
243 connect( seg->job(), SIGNAL(speed( KJob*, unsigned long )),
244 SLOT(slotSpeed( KJob*, unsigned long )));
245 connect( seg, SIGNAL(updateSegmentData()),
246 SIGNAL(updateSegmentsData()));
249 void MultiSegmentCopyJob::slotSplitSegment()
251 if(m_segSplited)
252 return;
253 if(!m_firstSeg->data().bytes)
255 QTimer::singleShot(10000, this, SLOT(slotSplitSegment()));
256 return;
258 QList<Segment *> segments = SegFactory->splitSegment( m_firstSeg ,SegFactory->nunOfSegments() );
259 if(segments.isEmpty())
260 return;
261 QList<Segment *>::iterator it = segments.begin();
262 QList<Segment *>::iterator itEnd = segments.end();
263 for ( ; it!=itEnd ; ++it )
265 (*it)->startTransfer();
267 m_segSplited = true;
270 void MultiSegmentCopyJob::slotDataReq( Segment *seg, const QByteArray &data, bool &result)
272 // kDebug(5001) << "MultiSegmentCopyJob::slotDataReq() ";
273 if ( m_writeBlocked )
275 result = false;
276 return;
278 m_writeBlocked = true;
279 m_putJob->seek(seg->offset());
280 m_putJob->write(data);
281 result = true;
283 m_chunkSize += data.size();
284 if( m_chunkSize > (uint)MultiSegKioSettings::saveSegSize() * 1024)
286 emit updateSegmentsData();
287 m_chunkSize = 0;
291 void MultiSegmentCopyJob::slotResult( KJob *job )
293 kDebug(5001) << job;
295 if( job->error() )
297 setError( job->error() );
298 setErrorText( job->errorText() );
301 if (job == m_putJob )
303 kDebug(5001) << "m_putJob finished";
304 m_putJob = 0;
305 emitResult();
309 void MultiSegmentCopyJob::slotTotalSize( KJob *job, qulonglong size )
311 kDebug(5001) << " from job: " << job << " -- " << size;
312 setTotalAmount (Bytes, size);
313 Q_ASSERT( m_firstSeg );
314 m_firstSeg->setBytes( size - m_firstSeg->BytesWritten() );
315 gettimeofday(&d->start_time, 0);
316 d->last_time = 0;
317 d->sizes[0] = processedAmount(Bytes) - d->bytes;
318 d->times[0] = 0;
319 d->nums = 1;
320 d->speed_timer.start(1000);
322 if(!MultiSegKioSettings::useSearchEngines() || (SegFactory->Urls().size() > 1))
324 kDebug(5001) << "slotSplitSegment() now";
325 slotSplitSegment();
329 void MultiSegmentCopyJob::slotPercent( KJob *job, unsigned long pct )
331 Q_UNUSED(job);
332 Q_UNUSED(pct);
335 void MultiSegmentCopyJob::slotSpeed( KJob* job, unsigned long bytes_per_second )
337 Q_UNUSED(job);
338 Q_UNUSED(bytes_per_second);
341 bool MultiSegmentCopyJob::checkLocalFile()
343 QString dest_orig = m_dest.path();
344 QString dest_part( dest_orig );
345 dest_part += QLatin1String(".part");
346 QByteArray _dest_part( QFile::encodeName(dest_part));
348 KDE_struct_stat buff_part;
349 bool bPartExists = (KDE_stat( _dest_part.data(), &buff_part ) != -1);
350 if(!bPartExists)
352 QByteArray _dest = QFile::encodeName(dest_part);
353 int fd = -1;
354 mode_t initialMode;
355 if (m_permissions != -1)
356 initialMode = m_permissions | S_IWUSR | S_IRUSR;
357 else
358 initialMode = 0666;
360 fd = KDE_open(_dest.data(), O_CREAT | O_TRUNC | O_WRONLY, initialMode);
361 if ( fd < 0 )
363 kDebug(5001) << " error";
364 /* if ( errno == EACCES )
365 error( ERR_WRITE_ACCESS_DENIED, dest_part );
366 else
367 error( ERR_CANNOT_OPEN_FOR_WRITING, dest_part );*/
368 return false;
370 else
372 close(fd);
375 m_dest_part = m_dest;
376 m_dest_part.setPath(dest_part);
377 kDebug(5001) << "success";
378 return true;
381 MultiSegmentCopyJob *MultiSegfile_copy( const QList<KUrl> Urls, const KUrl& dest, int permissions, uint segments)
383 return new MultiSegmentCopyJob( Urls, dest, permissions, segments);
386 MultiSegmentCopyJob *MultiSegfile_copy(
387 const QList<KUrl> Urls,
388 const KUrl& dest,
389 int permissions,
390 qulonglong ProcessedSize,
391 KIO::filesize_t totalSize,
392 QList<SegData> SegmentsData,
393 uint segments)
395 return new MultiSegmentCopyJob( Urls, dest, permissions, ProcessedSize, totalSize,SegmentsData , segments);
398 #include "multisegkio.moc"