Compile with QT_STRICT_ITERATORS definition.
[kdenetwork.git] / kget / transfer-plugins / multisegmentkio / segmentfactory.cpp
blob8dea13c1add2c7e7101890ce363819f614228095
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 "segmentfactory.h"
12 #include "multisegkiosettings.h"
13 #include "../../settings.h"
15 #include <QtCore/QTimer>
17 SegData::SegData ()
19 offset = 0;
20 bytes = (KIO::filesize_t) 0;
23 Segment::Segment (QObject* parent)
24 :QObject(parent)
25 , m_status(Stopped)
26 , m_bytesWritten(0)
27 , m_getJob(0)
28 , m_canResume(true)
32 bool Segment::createTransfer ( const KUrl &src )
34 kDebug(5001) << " -- " << src;
35 if ( m_getJob )
36 return false;
37 m_getJob = KIO::get(src, KIO::NoReload, KIO::HideProgressInfo);
38 m_getJob->suspend();
39 m_getJob->addMetaData( "errorPage", "false" );
40 m_getJob->addMetaData( "AllowCompressedPage", "false" );
41 if ( m_segData.offset )
43 m_canResume = false;
44 m_getJob->addMetaData( "resume", KIO::number(m_segData.offset) );
45 connect(m_getJob, SIGNAL(canResume(KIO::Job *, KIO::filesize_t)),
46 SLOT( slotCanResume(KIO::Job *, KIO::filesize_t)));
48 #if 0 //TODO: we disable that code till it's implemented in kdelibs, also we need to think, which settings we should use
49 if(Settings::speedLimit())
51 m_getJob->addMetaData( "speed-limit", KIO::number(Settings::transferSpeedLimit() * 1024) );
53 #endif
54 connect( m_getJob, SIGNAL(data(KIO::Job *, const QByteArray&)),
55 SLOT( slotData(KIO::Job *, const QByteArray&)));
56 connect( m_getJob, SIGNAL(result(KJob *)), SLOT(slotResult( KJob *)));
58 return true;
61 void Segment::slotCanResume( KIO::Job* job, KIO::filesize_t offset )
63 Q_UNUSED(job);
64 Q_UNUSED(offset);
65 kDebug(5001);
66 m_canResume = true;
69 bool Segment::startTransfer ()
71 kDebug(5001);
72 if( m_getJob && m_status != Running )
74 setStatus( Running, false );
75 m_getJob->resume();
76 return true;
78 return false;
81 bool Segment::stopTransfer ()
83 kDebug(5001);
84 if( m_getJob && m_status == Running )
86 setStatus( Stopped, false );
87 m_getJob->suspend();
88 if ( !m_buffer.isEmpty() )
90 writeBuffer();
92 if (m_getJob)
93 m_getJob->kill( KJob::EmitResult );
94 return true;
96 return false;
99 bool Segment::restartTransfer ( const KUrl &url )
101 bool rest;
102 rest = createTransfer( url );
103 rest |= startTransfer();
104 return rest;
107 void Segment::slotResult( KJob *job )
109 kDebug(5001) << "job: " << job;
110 m_getJob = 0;
111 if ( !m_buffer.isEmpty() )
113 kDebug(5001) << "Looping until write the buffer ...";
114 while(writeBuffer()) ;
116 if( !m_segData.bytes )
118 setStatus(Finished);
119 deleteLater();
120 return;
122 if( m_status == Killed )
124 deleteLater();
125 return;
127 if( m_status == Running )
129 kDebug(5001) << "Conection broken " << job << " --restarting--";
130 setStatus(Timeout);
134 void Segment::slotData(KIO::Job *, const QByteArray& _data)
136 // kDebug(5001) << "Segment::slotData()";
138 // Check if the transfer allow resuming...
139 if ( m_segData.offset && !m_canResume)
141 kDebug(5001) << "the remote site does not allow resuming ...";
142 stopTransfer();
143 setStatus(Killed, false );
144 return;
147 m_buffer.append(_data);
148 if ( (uint)m_buffer.size() > m_segData.bytes )
150 // kDebug(5001) << "Segment::slotData() buffer full. stoping transfer...";
151 m_buffer.truncate( m_segData.bytes );
152 m_getJob->suspend();
153 m_getJob->kill( KJob::EmitResult );
154 writeBuffer();
156 else
159 write to the local file only if the buffer has more than 8kbytes
160 this hack try to avoid too much cpu usage. it seems to be due KIO::Filejob
161 so remove it when it works property
163 if ( m_buffer.size() > 8*1024)
164 writeBuffer();
168 bool Segment::writeBuffer()
170 // kDebug(5001) << "Segment::writeBuffer() sending: " << m_buffer.size() << " from job: "<< m_getJob;
171 if ( m_buffer.isEmpty() )
173 return false;
175 bool rest;
176 emit data( this, m_buffer, rest);
177 if ( rest )
179 m_segData.bytes -= m_buffer.size();
180 m_segData.offset += m_buffer.size();
181 m_bytesWritten += m_buffer.size();
182 m_buffer = QByteArray();
183 // kDebug(5001) << "Segment::writeBuffer() updating segment record of job: " << m_getJob << " -- " << m_segData.bytes <<" bytes left";
185 if (!m_segData.bytes)
187 kDebug(5001) << "Closing transfer ...";
188 if( m_getJob )
189 m_getJob->kill( KJob::EmitResult );
190 emit updateSegmentData();
192 return rest;
195 void Segment::setStatus(Status stat, bool doEmit)
197 m_status = stat;
198 if (doEmit)
199 emit statusChanged(this);
202 SegmentFactory::SegmentFactory(uint n, const QList<KUrl> Urls)
203 : m_segments( n ), m_Urls( Urls ), m_split(true)
206 kDebug(5001);
207 it_Urls = m_Urls.constBegin();
210 SegmentFactory::SegmentFactory()
212 kDebug(5001);
215 SegmentFactory::~SegmentFactory()
217 kDebug(5001);
218 QList<Segment *>::iterator it = m_Segments.begin();
219 QList<Segment *>::iterator itEnd = m_Segments.end();
220 for ( ; it!=itEnd ; ++it )
222 if( (*it)->status() == Segment::Running )
223 (*it)->stopTransfer();
224 (*it)->deleteLater();
228 bool SegmentFactory::startTransfer()
230 kDebug(5001);
231 bool rest = false;
232 QList<Segment *>::iterator it = m_Segments.begin();
233 QList<Segment *>::iterator itEnd = m_Segments.end();
234 for ( ; it!=itEnd ; ++it )
236 rest |= (*it)->startTransfer();
238 return rest;
241 bool SegmentFactory::stopTransfer()
243 kDebug(5001);
244 bool rest = false;
245 QList<Segment *>::iterator it = m_Segments.begin();
246 QList<Segment *>::iterator itEnd = m_Segments.end();
247 for ( ; it!=itEnd ; ++it )
249 rest |= (*it)->stopTransfer();
251 return rest;
254 QList<SegData> SegmentFactory::SegmentsData()
256 kDebug(5001);
257 QList<SegData> tdata;
258 QList<Segment *>::iterator it = m_Segments.begin();
259 QList<Segment *>::iterator itEnd = m_Segments.end();
260 for ( ; it!=itEnd ; ++it )
262 if( (*it)->data().bytes )
263 tdata << (*it)->data();
265 return tdata;
268 QList<Segment *> SegmentFactory::splitSegment( Segment *Seg, int n)
270 kDebug(5001) << "Spliting " << Seg << "in " << n;
271 QList<Segment *> Segments;
273 KIO::TransferJob *Job = Seg->job();
274 if(Job)
276 Job->suspend();
277 kDebug(5001) << "job Suspended...";
280 KIO::filesize_t bytes = Seg->data().bytes;
281 KIO::filesize_t offset = Seg->data().offset;
283 uint splitSize = 50;
284 if( MultiSegKioSettings::splitSize() )
286 splitSize = MultiSegKioSettings::splitSize();
288 int min = bytes/(splitSize*1024);
290 if( min < n )
292 n = min;
295 if( n == 0 )
297 kDebug(5001) << "Segment can't be splited.";
298 if(Job)
300 Job->resume();
301 kDebug(5001) << "Resuming Job...";
303 return Segments;
306 KIO::filesize_t segment = bytes/n;
308 kDebug(5001) << "spliting: " << Seg->data().bytes <<" in "<< n << " and got: " << segment;
310 KIO::fileoffset_t rest_size = segment + ( bytes%n );
311 Seg->setBytes( segment );
312 kDebug(5001) << "Now the segment has: " << Seg->data().bytes <<" bytes.";
314 SegData data;
315 for(int i = 1; i < n; i++)
317 if(i == n - 1)
319 data.offset = i*segment + offset;
320 data.bytes = rest_size;
322 else
324 data.offset = i*segment + offset;
325 data.bytes = segment;
327 Segments << createSegment(data, nextUrl());
328 kDebug(5001) << "Segment created at offset: "<< data.offset <<" with "<< data.bytes << " bytes.";
331 if(Job)
333 Job->resume();
334 kDebug(5001) << "Resuming Job...";
337 return Segments;
340 Segment *SegmentFactory::createSegment( SegData data, const KUrl &src )
342 kDebug(5001);
343 Segment *seg = new Segment(this);
344 connect( seg, SIGNAL(statusChanged( Segment *)),
345 SLOT(slotStatusChanged( Segment *)));
346 seg->setData(data);
347 seg->createTransfer( src );
348 m_Segments.append(seg);
349 emit createdSegment(seg);
350 return seg;
353 void SegmentFactory::deleteSegment(Segment *seg)
355 m_Segments.removeAll(seg);
356 kDebug(5001) << m_Segments.size() << " segments left.";
359 void SegmentFactory::slotStatusChanged( Segment *seg)
361 kDebug(5001) << seg->status();
362 switch (seg->status())
364 case Segment::Killed :
365 //this site does not allow resuming. so its useless for multiseg
366 if ( !DeleteUrl( seg->job()->url() ) )
368 //TODO: notify that we cant resume or manage this transfer
370 break;
371 case Segment::Timeout :
372 kDebug(5001) << "Restarting Segment in 5 seg... ";
373 m_TimeOutSegments << seg;
374 QTimer::singleShot(5000, this, SLOT(slotSegmentTimeOut()));
375 break;
376 case Segment::Finished :
377 deleteSegment(seg);
378 if( !m_Segments.isEmpty() )
380 Segment* longSeg = takeLongest();
381 if( longSeg == 0)
382 break;
383 QList<Segment*> segl = splitSegment( longSeg, 2);
384 if( !segl.isEmpty() )
385 segl.takeFirst()->startTransfer();
387 break;
388 default:
389 break;
393 void SegmentFactory::slotSegmentTimeOut()
395 kDebug(5001) << m_TimeOutSegments.size();
396 if(m_TimeOutSegments.isEmpty())
397 return;
398 QList<Segment*>::const_iterator it = m_TimeOutSegments.constBegin();
399 QList<Segment*>::const_iterator itEnd = m_TimeOutSegments.constEnd();
400 for ( ; it!=itEnd ; ++it )
402 (*it)->restartTransfer( nextUrl() );
406 Segment *SegmentFactory::takeLongest()
408 kDebug(5001);
410 Segment *longest = 0;
411 KIO::filesize_t bytes = MultiSegKioSettings::splitSize()*1024;
413 QList<Segment*>::const_iterator it = m_Segments.constBegin();
414 QList<Segment*>::const_iterator itEnd = m_Segments.constEnd();
415 for ( ; it!=itEnd ; ++it )
417 if((*it)->data().bytes > bytes)
419 longest = (*it);
420 bytes = (*it)->data().bytes;
424 if(longest)
425 kDebug(5001) << "the longest segment has: " << longest->data().bytes;
427 return longest;
430 const KUrl SegmentFactory::nextUrl()
432 kDebug(5001);
433 if ( it_Urls >= m_Urls.constEnd() )
435 it_Urls = m_Urls.constBegin();
437 KUrl url(*it_Urls);
438 it_Urls++;
439 return url;
442 bool SegmentFactory::DeleteUrl(const KUrl &url)
444 if ( m_Urls.count() == 1 )
446 return false;
448 if ( m_Urls.contains( url ) )
450 m_Urls.removeAll( url );
451 return true;
453 return false;
456 #include "segmentfactory.moc"