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.
11 #include "segmentfactory.h"
12 #include "multisegkiosettings.h"
13 #include "../../settings.h"
15 #include <QtCore/QTimer>
20 bytes
= (KIO::filesize_t
) 0;
23 Segment::Segment (QObject
* parent
)
32 bool Segment::createTransfer ( const KUrl
&src
)
34 kDebug(5001) << " -- " << src
;
37 m_getJob
= KIO::get(src
, KIO::NoReload
, KIO::HideProgressInfo
);
39 m_getJob
->addMetaData( "errorPage", "false" );
40 m_getJob
->addMetaData( "AllowCompressedPage", "false" );
41 if ( m_segData
.offset
)
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) );
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
*)));
61 void Segment::slotCanResume( KIO::Job
* job
, KIO::filesize_t offset
)
69 bool Segment::startTransfer ()
72 if( m_getJob
&& m_status
!= Running
)
74 setStatus( Running
, false );
81 bool Segment::stopTransfer ()
84 if( m_getJob
&& m_status
== Running
)
86 setStatus( Stopped
, false );
88 if ( !m_buffer
.isEmpty() )
93 m_getJob
->kill( KJob::EmitResult
);
99 bool Segment::restartTransfer ( const KUrl
&url
)
102 rest
= createTransfer( url
);
103 rest
|= startTransfer();
107 void Segment::slotResult( KJob
*job
)
109 kDebug(5001) << "job: " << job
;
111 if ( !m_buffer
.isEmpty() )
113 kDebug(5001) << "Looping until write the buffer ...";
114 while(writeBuffer()) ;
116 if( !m_segData
.bytes
)
122 if( m_status
== Killed
)
127 if( m_status
== Running
)
129 kDebug(5001) << "Conection broken " << job
<< " --restarting--";
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 ...";
143 setStatus(Killed
, false );
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
);
153 m_getJob
->kill( KJob::EmitResult
);
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)
168 bool Segment::writeBuffer()
170 // kDebug(5001) << "Segment::writeBuffer() sending: " << m_buffer.size() << " from job: "<< m_getJob;
171 if ( m_buffer
.isEmpty() )
176 emit
data( this, m_buffer
, 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 ...";
189 m_getJob
->kill( KJob::EmitResult
);
190 emit
updateSegmentData();
195 void Segment::setStatus(Status stat
, bool doEmit
)
199 emit
statusChanged(this);
202 SegmentFactory::SegmentFactory(uint n
, const QList
<KUrl
> Urls
)
203 : m_segments( n
), m_Urls( Urls
), m_split(true)
207 it_Urls
= m_Urls
.constBegin();
210 SegmentFactory::SegmentFactory()
215 SegmentFactory::~SegmentFactory()
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()
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();
241 bool SegmentFactory::stopTransfer()
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();
254 QList
<SegData
> SegmentFactory::SegmentsData()
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();
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();
277 kDebug(5001) << "job Suspended...";
280 KIO::filesize_t bytes
= Seg
->data().bytes
;
281 KIO::filesize_t offset
= Seg
->data().offset
;
284 if( MultiSegKioSettings::splitSize() )
286 splitSize
= MultiSegKioSettings::splitSize();
288 int min
= bytes
/(splitSize
*1024);
297 kDebug(5001) << "Segment can't be splited.";
301 kDebug(5001) << "Resuming Job...";
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.";
315 for(int i
= 1; i
< n
; i
++)
319 data
.offset
= i
*segment
+ offset
;
320 data
.bytes
= rest_size
;
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.";
334 kDebug(5001) << "Resuming Job...";
340 Segment
*SegmentFactory::createSegment( SegData data
, const KUrl
&src
)
343 Segment
*seg
= new Segment(this);
344 connect( seg
, SIGNAL(statusChanged( Segment
*)),
345 SLOT(slotStatusChanged( Segment
*)));
347 seg
->createTransfer( src
);
348 m_Segments
.append(seg
);
349 emit
createdSegment(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
371 case Segment::Timeout
:
372 kDebug(5001) << "Restarting Segment in 5 seg... ";
373 m_TimeOutSegments
<< seg
;
374 QTimer::singleShot(5000, this, SLOT(slotSegmentTimeOut()));
376 case Segment::Finished
:
378 if( !m_Segments
.isEmpty() )
380 Segment
* longSeg
= takeLongest();
383 QList
<Segment
*> segl
= splitSegment( longSeg
, 2);
384 if( !segl
.isEmpty() )
385 segl
.takeFirst()->startTransfer();
393 void SegmentFactory::slotSegmentTimeOut()
395 kDebug(5001) << m_TimeOutSegments
.size();
396 if(m_TimeOutSegments
.isEmpty())
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()
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
)
420 bytes
= (*it
)->data().bytes
;
425 kDebug(5001) << "the longest segment has: " << longest
->data().bytes
;
430 const KUrl
SegmentFactory::nextUrl()
433 if ( it_Urls
>= m_Urls
.constEnd() )
435 it_Urls
= m_Urls
.constBegin();
442 bool SegmentFactory::DeleteUrl(const KUrl
&url
)
444 if ( m_Urls
.count() == 1 )
448 if ( m_Urls
.contains( url
) )
450 m_Urls
.removeAll( url
);
456 #include "segmentfactory.moc"