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 "multisegkio.h"
12 #include "multisegkiosettings.h"
14 #include "core/kget.h"
24 static const unsigned int max_nums
= 8;
25 class MultiSegmentCopyJob::MultiSegmentCopyJobPrivate
28 MultiSegmentCopyJobPrivate() {
29 start_time
.tv_sec
= 0;
30 start_time
.tv_usec
= 0;
35 struct timeval start_time
;
38 KIO::filesize_t sizes
[max_nums
];
40 KIO::filesize_t bytes
;
47 * class MultiSegmentCopyJob
49 MultiSegmentCopyJob::MultiSegmentCopyJob( const QList
<KUrl
> Urls
, const KUrl
& dest
, int permissions
, uint segments
)
50 :KJob(0), d(new MultiSegmentCopyJobPrivate
),
52 m_permissions(permissions
),
53 m_writeBlocked(false),
58 SegFactory
= new SegmentFactory( segments
, Urls
);
59 connect(SegFactory
, SIGNAL(createdSegment(Segment
*)), SLOT(slotConnectSegment( Segment
*)));
62 connect(&d
->speed_timer
, SIGNAL(timeout()), SLOT(calcSpeed()));
63 QTimer::singleShot(0, this, SLOT(slotStart()));
66 MultiSegmentCopyJob::MultiSegmentCopyJob(
67 const QList
<KUrl
> Urls
,
70 qulonglong ProcessedSize
,
71 KIO::filesize_t totalSize
,
72 QList
<SegData
> SegmentsData
,
75 :KJob(0), d(new MultiSegmentCopyJobPrivate
),
77 m_permissions(permissions
),
78 m_writeBlocked(false),
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() );
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()
105 SegFactory
->deleteLater();
109 QList
<SegData
> MultiSegmentCopyJob::SegmentsData()
111 return SegFactory
->SegmentsData();
114 void MultiSegmentCopyJob::stop()
117 setError(KIO::ERR_USER_CANCELED
);
119 SegFactory
->stopTransfer();
124 void MultiSegmentCopyJob::slotUrls(QList
<KUrl
>& Urls
)
126 SegFactory
->setUrls(Urls
);
130 void MultiSegmentCopyJob::slotStart()
133 if( !checkLocalFile() )
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
)
153 if( SegFactory
->startTransfer() )
156 gettimeofday(&d
->start_time
, 0);
158 d
->sizes
[0] = processedAmount(Bytes
) - d
->bytes
;
161 d
->speed_timer
.start(1000);
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
) )
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()
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) {
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
];
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]);
232 d
->sizes
[0] = processedAmount(Bytes
) - d
->bytes
;
234 emit
speed(this, lspeed
);
238 void MultiSegmentCopyJob::slotConnectSegment( Segment
*seg
)
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()
253 if(!m_firstSeg
->data().bytes
)
255 QTimer::singleShot(10000, this, SLOT(slotSplitSegment()));
258 QList
<Segment
*> segments
= SegFactory
->splitSegment( m_firstSeg
,SegFactory
->nunOfSegments() );
259 if(segments
.isEmpty())
261 QList
<Segment
*>::iterator it
= segments
.begin();
262 QList
<Segment
*>::iterator itEnd
= segments
.end();
263 for ( ; it
!=itEnd
; ++it
)
265 (*it
)->startTransfer();
270 void MultiSegmentCopyJob::slotDataReq( Segment
*seg
, const QByteArray
&data
, bool &result
)
272 // kDebug(5001) << "MultiSegmentCopyJob::slotDataReq() ";
273 if ( m_writeBlocked
)
278 m_writeBlocked
= true;
279 m_putJob
->seek(seg
->offset());
280 m_putJob
->write(data
);
283 m_chunkSize
+= data
.size();
284 if( m_chunkSize
> (uint
)MultiSegKioSettings::saveSegSize() * 1024)
286 emit
updateSegmentsData();
291 void MultiSegmentCopyJob::slotResult( KJob
*job
)
297 setError( job
->error() );
298 setErrorText( job
->errorText() );
301 if (job
== m_putJob
)
303 kDebug(5001) << "m_putJob finished";
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);
317 d
->sizes
[0] = processedAmount(Bytes
) - d
->bytes
;
320 d
->speed_timer
.start(1000);
322 if(!MultiSegKioSettings::useSearchEngines() || (SegFactory
->Urls().size() > 1))
324 kDebug(5001) << "slotSplitSegment() now";
329 void MultiSegmentCopyJob::slotPercent( KJob
*job
, unsigned long pct
)
335 void MultiSegmentCopyJob::slotSpeed( KJob
* job
, unsigned long bytes_per_second
)
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);
352 QByteArray _dest
= QFile::encodeName(dest_part
);
355 if (m_permissions
!= -1)
356 initialMode
= m_permissions
| S_IWUSR
| S_IRUSR
;
360 fd
= KDE_open(_dest
.data(), O_CREAT
| O_TRUNC
| O_WRONLY
, initialMode
);
363 kDebug(5001) << " error";
364 /* if ( errno == EACCES )
365 error( ERR_WRITE_ACCESS_DENIED, dest_part );
367 error( ERR_CANNOT_OPEN_FOR_WRITING, dest_part );*/
375 m_dest_part
= m_dest
;
376 m_dest_part
.setPath(dest_part
);
377 kDebug(5001) << "success";
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
,
390 qulonglong ProcessedSize
,
391 KIO::filesize_t totalSize
,
392 QList
<SegData
> SegmentsData
,
395 return new MultiSegmentCopyJob( Urls
, dest
, permissions
, ProcessedSize
, totalSize
,SegmentsData
, segments
);
398 #include "multisegkio.moc"