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;
172 emit
data( this, m_buffer
, rest
);
175 m_segData
.bytes
-= m_buffer
.size();
176 m_segData
.offset
+= m_buffer
.size();
177 m_bytesWritten
+= m_buffer
.size();
178 m_buffer
= QByteArray();
179 // kDebug(5001) << "Segment::writeBuffer() updating segment record of job: " << m_getJob << " -- " << m_segData.bytes <<" bytes left";
181 if (!m_segData
.bytes
)
183 kDebug(5001) << "Closing transfer ...";
185 m_getJob
->kill( KJob::EmitResult
);
186 emit
updateSegmentData();
191 void Segment::setStatus(Status stat
, bool doEmit
)
195 emit
statusChanged(this);
198 SegmentFactory::SegmentFactory(uint n
, const QList
<KUrl
> Urls
)
199 : m_segments( n
), m_Urls( Urls
), m_split(true)
203 it_Urls
= m_Urls
.begin();
206 SegmentFactory::SegmentFactory()
211 SegmentFactory::~SegmentFactory()
214 QList
<Segment
*>::iterator it
= m_Segments
.begin();
215 QList
<Segment
*>::iterator itEnd
= m_Segments
.end();
216 for ( ; it
!=itEnd
; ++it
)
218 if( (*it
)->status() == Segment::Running
)
219 (*it
)->stopTransfer();
220 (*it
)->deleteLater();
224 bool SegmentFactory::startTransfer()
228 QList
<Segment
*>::iterator it
= m_Segments
.begin();
229 QList
<Segment
*>::iterator itEnd
= m_Segments
.end();
230 for ( ; it
!=itEnd
; ++it
)
232 rest
|= (*it
)->startTransfer();
237 bool SegmentFactory::stopTransfer()
241 QList
<Segment
*>::iterator it
= m_Segments
.begin();
242 QList
<Segment
*>::iterator itEnd
= m_Segments
.end();
243 for ( ; it
!=itEnd
; ++it
)
245 rest
|= (*it
)->stopTransfer();
250 QList
<SegData
> SegmentFactory::SegmentsData()
253 QList
<SegData
> tdata
;
254 QList
<Segment
*>::iterator it
= m_Segments
.begin();
255 QList
<Segment
*>::iterator itEnd
= m_Segments
.end();
256 for ( ; it
!=itEnd
; ++it
)
258 if( (*it
)->data().bytes
)
259 tdata
<< (*it
)->data();
264 QList
<Segment
*> SegmentFactory::splitSegment( Segment
*Seg
, int n
)
266 kDebug(5001) << "Spliting " << Seg
<< "in " << n
;
267 QList
<Segment
*> Segments
;
269 KIO::TransferJob
*Job
= Seg
->job();
273 kDebug(5001) << "job Suspended...";
276 KIO::filesize_t bytes
= Seg
->data().bytes
;
277 KIO::filesize_t offset
= Seg
->data().offset
;
280 if( MultiSegKioSettings::splitSize() )
282 splitSize
= MultiSegKioSettings::splitSize();
284 int min
= bytes
/(splitSize
*1024);
293 kDebug(5001) << "Segment can't be splited.";
297 kDebug(5001) << "Resuming Job...";
302 KIO::filesize_t segment
= bytes
/n
;
304 kDebug(5001) << "spliting: " << Seg
->data().bytes
<<" in "<< n
<< " and got: " << segment
;
306 KIO::fileoffset_t rest_size
= segment
+ ( bytes
%n
);
307 Seg
->setBytes( segment
);
308 kDebug(5001) << "Now the segment has: " << Seg
->data().bytes
<<" bytes.";
313 kDebug(5001) << "Resuming Job...";
317 for(int i
= 1; i
< n
; i
++)
321 data
.offset
= i
*segment
+ offset
;
322 data
.bytes
= rest_size
;
323 Segments
<< createSegment(data
, nextUrl());
324 kDebug(5001) << "Segment created at offset: "<< data
.offset
<<" with "<< data
.bytes
<< " bytes.";
327 data
.offset
= i
*segment
+ offset
;
328 data
.bytes
= segment
;
329 Segments
<< createSegment(data
, nextUrl());
330 kDebug(5001) << "Segment created at offset: "<< data
.offset
<<" with "<< data
.bytes
<< " bytes.";
336 Segment
*SegmentFactory::createSegment( SegData data
, const KUrl
&src
)
339 Segment
*seg
= new Segment(this);
340 connect( seg
, SIGNAL(statusChanged( Segment
*)),
341 SLOT(slotStatusChanged( Segment
*)));
343 seg
->createTransfer( src
);
344 m_Segments
.append(seg
);
345 emit
createdSegment(seg
);
349 void SegmentFactory::deleteSegment(Segment
*seg
)
351 m_Segments
.removeAll(seg
);
352 kDebug(5001) << m_Segments
.size() << " segments left.";
355 void SegmentFactory::slotStatusChanged( Segment
*seg
)
357 kDebug(5001) << seg
->status();
358 switch (seg
->status())
360 case Segment::Killed
:
361 //this site does not allow resuming. so its useless for multiseg
362 if ( !DeleteUrl( seg
->job()->url() ) )
364 //TODO: notify that we cant resume or manage this transfer
367 case Segment::Timeout
:
368 kDebug(5001) << "Restarting Segment in 5 seg... ";
369 m_TimeOutSegments
<< seg
;
370 QTimer::singleShot(5000, this, SLOT(slotSegmentTimeOut()));
372 case Segment::Finished
:
374 if( !m_Segments
.isEmpty() )
376 Segment
* longSeg
= takeLongest();
379 QList
<Segment
*> segl
= splitSegment( longSeg
, 2);
380 if( !segl
.isEmpty() )
381 segl
.takeFirst()->startTransfer();
389 void SegmentFactory::slotSegmentTimeOut()
391 kDebug(5001) << m_TimeOutSegments
.size();
392 if(m_TimeOutSegments
.isEmpty())
394 m_TimeOutSegments
.takeFirst()->restartTransfer( nextUrl() );
397 Segment
*SegmentFactory::takeLongest()
401 Segment
*longest
= 0;
402 KIO::filesize_t bytes
= MultiSegKioSettings::splitSize()*1024;
404 QList
<Segment
*>::const_iterator it
= m_Segments
.begin();
405 QList
<Segment
*>::const_iterator itEnd
= m_Segments
.end();
406 for ( ; it
!=itEnd
; ++it
)
408 if((*it
)->data().bytes
> bytes
)
411 bytes
= (*it
)->data().bytes
;
416 kDebug(5001) << "the longest segment has: " << longest
->data().bytes
;
421 const KUrl
SegmentFactory::nextUrl()
424 if ( it_Urls
== m_Urls
.end() )
426 it_Urls
= m_Urls
.begin();
433 bool SegmentFactory::DeleteUrl(const KUrl
&url
)
435 if ( m_Urls
.count() == 1 )
439 if ( m_Urls
.contains( url
) )
441 m_Urls
.removeAll( url
);
447 #include "segmentfactory.moc"