• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdenetwork API Reference
  • KDE Home
  • Contact Us
 

kget

  • sources
  • kde-4.12
  • kdenetwork
  • kget
  • transfer-plugins
  • multisegmentkio
segment.cpp
Go to the documentation of this file.
1 /* This file is part of the KDE project
2 
3  Copyright (C) 2006 Manolo Valdes <nolis71cu@gmail.com>
4  Copyright (C) 2009 Matthias Fuchs <mat69@gmx.net>
5 
6  This program is free software; you can redistribute it and/or
7  modify it under the terms of the GNU General Public
8  License as published by the Free Software Foundation; either
9  version 2 of the License, or (at your option) any later version.
10 */
11 
12 #include "segment.h"
13 #include "multisegkiosettings.h"
14 
15 #include <cmath>
16 
17 #include <KDebug>
18 #include <KLocale>
19 
20 #include <QtCore/QTimer>
21 
22 Segment::Segment(const KUrl &src, const QPair<KIO::fileoffset_t, KIO::fileoffset_t> &segmentSize, const QPair<int, int> &segmentRange, QObject *parent)
23  : QObject(parent),
24  m_findFilesize((segmentRange.first == -1) && (segmentRange.second == -1)),
25  m_canResume(true),
26  m_status(Stopped),
27  m_currentSegment(segmentRange.first),
28  m_endSegment(segmentRange.second),
29  m_errorCount(0),
30  m_offset(segmentSize.first * segmentRange.first),
31  m_currentSegSize(segmentSize.first),
32  m_bytesWritten(0),
33  m_getJob(0),
34  m_url(src),
35  m_segSize(segmentSize)
36 {
37  //last segment
38  if (m_endSegment - m_currentSegment == 0) {
39  m_currentSegSize = m_segSize.second;
40  }
41 
42  if (m_findFilesize) {
43  m_offset = 0;
44  m_currentSegSize = 0;
45  m_currentSegment = 0;
46  m_endSegment = 0;
47  m_totalBytesLeft = 0;
48  } else {
49  m_totalBytesLeft = m_segSize.first * (m_endSegment - m_currentSegment) + m_segSize.second;
50  }
51 }
52 
53 Segment::~Segment()
54 {
55  if (m_getJob)
56  {
57  kDebug(5001) << "Closing transfer ...";
58  m_getJob->kill(KJob::Quietly);
59  }
60 }
61 
62 bool Segment::findingFileSize() const
63 {
64  return m_findFilesize;
65 }
66 
67 bool Segment::createTransfer()
68 {
69  kDebug(5001) << " -- " << m_url;
70  if ( m_getJob )
71  return false;
72 
73  m_getJob = KIO::get(m_url, KIO::Reload, KIO::HideProgressInfo);
74  m_getJob->suspend();
75  m_getJob->addMetaData( "errorPage", "false" );
76  m_getJob->addMetaData( "AllowCompressedPage", "false" );
77  if (m_offset)
78  {
79  m_canResume = false;//FIXME set m_canResume to false by default!!
80  m_getJob->addMetaData( "resume", KIO::number(m_offset) );
81  connect(m_getJob, SIGNAL(canResume(KIO::Job*,KIO::filesize_t)),
82  SLOT(slotCanResume(KIO::Job*,KIO::filesize_t)));
83  }
84  #if 0 //TODO: we disable that code till it's implemented in kdelibs, also we need to think, which settings we should use
85  if (Settings::speedLimit())
86  {
87  m_getJob->addMetaData( "speed-limit", KIO::number(Settings::transferSpeedLimit() * 1024) );
88  }
89  #endif
90  connect(m_getJob, SIGNAL(totalSize(KJob*,qulonglong)), this, SLOT(slotTotalSize(KJob*,qulonglong)));
91  connect(m_getJob, SIGNAL(data(KIO::Job*,QByteArray)),
92  SLOT(slotData(KIO::Job*,QByteArray)));
93  connect(m_getJob, SIGNAL(result(KJob*)), SLOT(slotResult(KJob*)));
94  connect(m_getJob, SIGNAL(redirection(KIO::Job *,const KUrl &)), SLOT(slotRedirection(KIO::Job *, const KUrl &)));
95  return true;
96 }
97 
98 void Segment::slotRedirection(KIO::Job* , const KUrl &url)
99 {
100  m_url = url;
101  emit urlChanged(url);
102 }
103 
104 void Segment::slotCanResume( KIO::Job* job, KIO::filesize_t offset )
105 {
106  Q_UNUSED(job)
107  Q_UNUSED(offset)
108  kDebug(5001);
109  m_canResume = true;
110  emit canResume();
111 }
112 
113 void Segment::slotTotalSize(KJob *job, qulonglong size)
114 {
115  Q_UNUSED(job)
116  kDebug(5001) << "Size found for" << m_url;
117 
118  if (m_findFilesize) {
119  int numSegments = size / m_segSize.first;
120  KIO::fileoffset_t rest = size % m_segSize.first;
121  if (rest) {
122  ++numSegments;
123  m_segSize.second = rest;
124  }
125 
126  m_endSegment = numSegments - 1;
127 
128  m_currentSegment = 0;
129  m_currentSegSize = (numSegments == 1 ? m_segSize.second : m_segSize.first);
130  m_totalBytesLeft = size;
131 
132  emit totalSize(size, qMakePair(m_currentSegment, m_endSegment));
133  m_findFilesize = false;
134  } else {
135  emit totalSize(size, qMakePair(-1, -1));
136  }
137 }
138 
139 bool Segment::startTransfer ()
140 {
141  kDebug(5001) << m_url;
142  if (!m_getJob) {
143  createTransfer();
144  }
145  if (m_getJob && (m_status != Running)) {
146  setStatus(Running, false);
147  m_getJob->resume();
148  return true;
149  }
150  return false;
151 }
152 
153 bool Segment::stopTransfer()
154 {
155  kDebug(5001);
156 
157  setStatus(Stopped, false);
158  if (m_getJob) {
159  if (m_getJob) {
160  m_getJob->kill(KJob::EmitResult);
161  }
162  return true;
163  }
164  return false;
165 }
166 
167 void Segment::slotResult( KJob *job )
168 {
169  kDebug(5001) << "Job:" << job << m_url << "error:" << job->error();
170 
171  m_getJob = 0;
172 
173  //clear the buffer as the download might be moved around
174  if (m_status == Stopped)
175  {
176  m_buffer.clear();
177  }
178  if ( !m_buffer.isEmpty() )
179  {
180  if (m_findFilesize && !job->error()) {
181  kDebug(5001) << "Looping until write the buffer ..." << m_url;
182  slotWriteRest();
183  return;
184  }
185  }
186  if (!m_totalBytesLeft && !m_findFilesize)
187  {
188  setStatus(Finished);
189  return;
190  }
191  if( m_status == Killed )
192  {
193  return;
194  }
195  if (job->error() && (m_status == Running)) {
196  emit error(this, job->errorString(), Transfer::Log_Error);
197  }
198 }
199 
200 void Segment::slotData(KIO::Job *, const QByteArray& _data)
201 {
202  // Check if the transfer allows resuming...
203  if (m_offset && !m_canResume)
204  {
205  kDebug(5001) << m_url << "does not allow resuming.";
206  stopTransfer();
207  setStatus(Killed, false );
208  const QString errorText = KIO::buildErrorString(KIO::ERR_CANNOT_RESUME, m_url.prettyUrl());
209  emit error(this, errorText, Transfer::Log_Warning);
210  return;
211  }
212 
213  m_buffer.append(_data);
214  if (!m_findFilesize && m_totalBytesLeft && static_cast<uint>(m_buffer.size()) >= m_totalBytesLeft)
215  {
216  kDebug(5001) << "Segment::slotData() buffer full. stoping transfer...";//TODO really stop it? is this even needed?
217  if (m_getJob) {
218  m_getJob->kill(KJob::Quietly);
219  m_getJob = 0;
220  }
221  m_buffer.truncate(m_totalBytesLeft);
222  slotWriteRest();
223  }
224  else
225  {
226  /*
227  write to the local file only if the buffer has more than 100kbytes
228  this hack try to avoid too much cpu usage. it seems to be due KIO::Filejob
229  so remove it when it works property
230  */
231  if (m_buffer.size() > MultiSegKioSettings::saveSegSize() * 1024)
232  writeBuffer();
233  }
234 }
235 
236 bool Segment::writeBuffer()
237 {
238  kDebug(5001) << "Segment::writeBuffer() sending:" << m_buffer.size() << "from job:" << m_getJob;
239  if (m_buffer.isEmpty()) {
240  return false;
241  }
242 
243  bool worked = false;
244  emit data(m_offset, m_buffer, worked);
245 
246  if (worked) {
247  m_currentSegSize -= m_buffer.size();
248  if (!m_findFilesize) {
249  m_totalBytesLeft -= m_buffer.size();
250  }
251  m_offset += m_buffer.size();
252  m_bytesWritten += m_buffer.size();
253  m_buffer.clear();
254  kDebug(5001) << "Segment::writeBuffer() updating segment record of job:" << m_getJob << "--" << m_totalBytesLeft << "bytes left";
255  }
256 
257  //finding filesize, so no segments defined yet
258  if (m_findFilesize) {
259  return worked;
260  }
261 
262  //check which segments have been finished
263  bool finished = false;
264  //m_currentSegSize being smaller than 1 means that at least one segment has been finished
265  while (m_currentSegSize <= 0 && !finished) {
266  finished = (m_currentSegment == m_endSegment);
267  emit finishedSegment(this, m_currentSegment, finished);
268 
269  if (!finished) {
270  ++m_currentSegment;
271  m_currentSegSize += (m_currentSegment == m_endSegment ? m_segSize.second : m_segSize.first);
272  }
273  }
274 
275  return worked;
276 }
277 
278 void Segment::slotWriteRest()
279 {
280  if (m_buffer.isEmpty()) {
281  return;
282  }
283  kDebug() << this;
284 
285  if (writeBuffer()) {
286  m_errorCount = 0;
287  if (m_findFilesize) {
288  emit finishedDownload(m_bytesWritten);
289  }
290  return;
291  }
292 
293  if (++m_errorCount >= 100) {
294  kWarning() << "Failed to write to the file:" << m_url << this;
295  emit error(this, i18n("Failed to write to the file."), Transfer::Log_Error);
296  } else {
297  kDebug() << "Wait 50 msec:" << this;
298  QTimer::singleShot(50, this, SLOT(slotWriteRest()));
299  }
300 }
301 
302 void Segment::setStatus(Status stat, bool doEmit)
303 {
304  m_status = stat;
305  if (doEmit)
306  emit statusChanged(this);
307 }
308 
309 QPair<int, int> Segment::assignedSegments() const
310 {
311  return QPair<int, int>(m_currentSegment, m_endSegment);
312 }
313 
314 QPair<KIO::fileoffset_t, KIO::fileoffset_t> Segment::segmentSize() const
315 {
316  return m_segSize;
317 }
318 
319 int Segment::countUnfinishedSegments() const
320 {
321  return m_endSegment - m_currentSegment;
322 }
323 
324 QPair<int, int> Segment::split()
325 {
326  if (m_getJob)
327  {
328  m_getJob->suspend();
329  }
330 
331  QPair<int, int> freed = QPair<int, int>(-1, -1);
332  const int free = std::ceil((countUnfinishedSegments() + 1) / static_cast<double>(2));
333 
334  if (!free)
335  {
336  kDebug(5001) << "None freed, start:" << m_currentSegment << "end:" << m_endSegment;
337 
338  if (m_getJob)
339  {
340  m_getJob->resume();
341  }
342  return freed;
343  }
344 
345  const int newEnd = m_endSegment - free;
346  freed = QPair<int, int>(newEnd + 1, m_endSegment);
347  kDebug(5001) << "Start:" << m_currentSegment << "old end:" << m_endSegment << "new end:" << newEnd << "freed:" << freed;
348  m_endSegment = newEnd;
349  m_totalBytesLeft -= m_segSize.first * (free - 1) + m_segSize.second;
350 
351  //end changed, so in any case the lastSegSize should be the normal segSize
352  if (free)
353  {
354  m_segSize.second = m_segSize.first;
355  }
356 
357  if (m_getJob)
358  {
359  m_getJob->resume();
360  }
361  return freed;
362 }
363 
364 bool Segment::merge(const QPair<KIO::fileoffset_t, KIO::fileoffset_t> &segmentSize, const QPair<int, int> &segmentRange)
365 {
366  if (m_endSegment + 1 == segmentRange.first) {
367  m_endSegment = segmentRange.second;
368  m_segSize.second = segmentSize.second;
369  m_totalBytesLeft += segmentSize.first * (m_endSegment - segmentRange.first) + m_segSize.second;
370  return true;
371  }
372 
373  return false;
374 }
375 
376 #include "segment.moc"
Segment::countUnfinishedSegments
int countUnfinishedSegments() const
Definition: segment.cpp:319
MultiSegKioSettings::saveSegSize
static int saveSegSize()
Get SaveSegSize.
Definition: multisegkiosettings.h:49
Segment::canResume
void canResume()
Transfer::Log_Warning
Definition: transfer.h:84
Segment::split
QPair< int, int > split()
Definition: segment.cpp:324
Segment::Stopped
Definition: segment.h:43
Settings::speedLimit
static bool speedLimit()
Get SpeedLimit.
Definition: settings.h:620
Settings::transferSpeedLimit
static int transferSpeedLimit()
Get TransferSpeedLimit.
Definition: settings.h:639
multisegkiosettings.h
QObject
Segment::segmentSize
QPair< KIO::fileoffset_t, KIO::fileoffset_t > segmentSize() const
Definition: segment.cpp:314
Segment::stopTransfer
bool stopTransfer()
stop the segment transfer
Definition: segment.cpp:153
Segment::slotResult
void slotResult(KJob *job)
Called whenever a subjob finishes.
Definition: segment.cpp:167
Segment::Finished
Definition: segment.h:46
Segment::Running
Definition: segment.h:42
Segment::data
void data(KIO::fileoffset_t offset, const QByteArray &data, bool &worked)
segment.h
Segment::totalSize
void totalSize(KIO::filesize_t size, QPair< int, int > segmentRange)
Segment::merge
bool merge(const QPair< KIO::fileoffset_t, KIO::fileoffset_t > &segmentSize, const QPair< int, int > &segmentRange)
Definition: segment.cpp:364
Segment
class Segment
Definition: segment.h:26
Segment::startTransfer
bool startTransfer()
start the segment transfer
Definition: segment.cpp:139
Segment::Segment
Segment(const KUrl &src, const QPair< KIO::fileoffset_t, KIO::fileoffset_t > &segmentSize, const QPair< int, int > &segmentRange, QObject *parent)
Definition: segment.cpp:22
Segment::~Segment
~Segment()
Definition: segment.cpp:53
Segment::createTransfer
bool createTransfer()
Create the segment transfer.
Definition: segment.cpp:67
Segment::size
KIO::filesize_t size() const
Returns the size the current segment has.
Definition: segment.h:72
Segment::finishedSegment
void finishedSegment(Segment *segment, int segmentNum, bool connectionFinished=true)
Segment::error
void error(Segment *segment, const QString &errorText, Transfer::LogLevel logLevel)
Emitted whenever the transfer is closed with an error.
Segment::Status
Status
The status property describes the current segment status.
Definition: segment.h:40
Segment::findingFileSize
bool findingFileSize() const
Definition: segment.cpp:62
Segment::finishedDownload
void finishedDownload(KIO::filesize_t size)
Transfer::Log_Error
Definition: transfer.h:85
Segment::Killed
Definition: segment.h:44
Segment::statusChanged
void statusChanged(Segment *)
KJob
Segment::urlChanged
void urlChanged(const KUrl &newUrl)
Segment::assignedSegments
QPair< int, int > assignedSegments() const
Definition: segment.cpp:309
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:53:17 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kget

Skip menu "kget"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdenetwork API Reference

Skip menu "kdenetwork API Reference"
  • kget
  • kopete
  •   kopete
  •   libkopete
  • krdc
  • krfb

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal