source: src-qt4/libpcbsd/utils/pcbsd-DLProcess.cpp @ 23e7b34

releng/10.0.1releng/10.0.2
Last change on this file since 23e7b34 was 23e7b34, checked in by Ken Moore <ken@…>, 6 months ago

Adjust the default output of the DlProcess? class to "??" instead of -1. This provides a much more "human-readable" output for errors or invalid information (easier to check programattically too).

  • Property mode set to 100644
File size: 7.6 KB
Line 
1#include "pcbsd-DLProcess.h"
2
3DLProcess::DLProcess(QObject* parent) : QProcess(parent){
4  //Setup the process environment for downloads
5  this->setProcessChannelMode(QProcess::MergedChannels);
6  //Setup the internal signals/slots
7  connect(this, SIGNAL(readyRead()), this, SLOT(newMessage()) );
8  connect(this, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(ProcFinished()) );
9  //Flag as no output parsing at the moment
10  DLTYPE = -1;
11  pipeFile.clear();
12}
13
14DLProcess::~DLProcess(){
15       
16}
17
18void DLProcess::setWardenDir(QString wardendir){
19  pipeFile = wardendir+"/tmp/pkg-fifo";
20  if(QFile::exists(pipeFile)){
21    //That pipe already exists: use a different one to prevent conflicts
22    int num =2;
23    while(QFile::exists(pipeFile+"-"+QString::number(num)) ){ num ++; }
24    pipeFile.append("-"+QString::number(num));
25  }
26}
27
28void DLProcess::setDLType(QString type){
29  type = type.toLower();
30  if(type=="pbi"){ 
31    DLTYPE = 0;
32    QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
33      env.insert("PBI_FETCH_PARSING","YES"); //For readable download notifications
34    this->setProcessEnvironment(env);
35         
36  }else if(type=="pkg"){ 
37    DLTYPE = 1; 
38    //For this type, need to run an additional process to watch an event-pipe
39    if(pipeFile.isEmpty()){ setWardenDir(""); } //generate the pipe file on base system
40    //Setup the pipe file on the system
41    system("mkfifo "+pipeFile.toUtf8()+" ; sleep 1");
42    watcher = new QProcess(this);
43          watcher->start("cat", QStringList() << "-u" << pipeFile );
44          connect(watcher, SIGNAL(readyRead()), this, SLOT(newMessage()) );
45    QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
46      env.insert("PCFETCHGUI","YES"); //For readable download notifications
47      env.insert("EVENT_PIPE", pipeFile);
48    this->setProcessEnvironment(env);
49    //Disconnect the main process from the parser
50    disconnect(SIGNAL(readyRead()), this, SLOT(newMessage()) );
51   
52  }else if(type=="cdn"){
53    DLTYPE = 2;
54    QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
55      env.insert("GUI_FETCH_PARSING","YES"); //For readable download notifications
56    this->setProcessEnvironment(env);
57         
58  }else{
59    DLTYPE = -1;
60    this->setProcessEnvironment( QProcessEnvironment::systemEnvironment() );
61  }
62}
63
64bool DLProcess::isRunning(){
65  return (this->state() != QProcess::NotRunning);
66}
67
68// ===============
69//  PRIVATE FUNCTIONS
70// ===============
71void DLProcess::calculateStats(QString current, QString total, QString speed, QString filename){
72  //Assumes all values are in KB or KB/s
73  bool totok, curok, spdok;
74  double tot, cur, spd, percent;
75  tot = total.toDouble(&totok);
76  cur = current.toDouble(&curok);
77
78  //qDebug() << " - DownloadStats:" << tot << cur << spd;
79  if(totok && tot==0){totok=false;}
80  if(curok && cur==0){curok=false;}
81  //Now format the output string
82  //Get percentage complete
83  if(totok && curok){
84    bool totErr = (tot==cur); //catch for a display error where the cur is always identical to the tot
85    if(!totErr){         
86      //Calculate the percentage
87      percent = (cur/tot)*100;
88      percent = int(percent*10)/10.0;
89    }else{
90      //(Total = Current) bug: unknown percentage since process is still running
91      percent = -1;
92    }       
93  }else{
94    percent = -1;
95  }     
96  //Check if total is known 
97  if(!totok && curok){
98    //Only Current is known
99    tot = cur; //output current instead of total since no percent either
100  }
101  //OTHER input (speed, filename)
102  QString other = "??";
103  //Check the speed
104  if(!speed.isEmpty()){
105    spd = speed.toDouble(&spdok);
106    if(spdok && spd<=0){ spdok=false; }
107    if(spdok){
108      other = kbToString(spd)+"/s";
109    }
110  //Check for a filename instead
111  }else if(!filename.isEmpty() ){
112    other = filename;
113  }
114  //Now emit the stats
115  QString perc = "??";
116  if(percent >= 0){ perc = QString::number(percent); }
117  QString tota = "??";
118  if(tot >= 0){ tota = kbToString(tot); }
119 
120  emit UpdatePercent(perc, tota, other);
121}
122
123void DLProcess::parsePBILine(QString line){
124  //Quick checks for line formatting
125  if( line.startsWith("FETCH:") ){ emit UpdateMessage(tr("Download Starting...")); return; }
126  else if( line == "FETCHDONE"){ emit UpdateMessage(tr("Download Finished")); return; }
127  else if(!line.startsWith("SIZE:")){ emit UpdateMessage(line); return; }
128  //Now parse the PBI download line
129  //qDebug() << "parse Download Line:" << line;
130  //Line format: SIZE:  <KB> DOWNLOADED:  <KB> SPEED:  <KB/s> KB/s
131  line = line.simplified();
132  line.replace("SIZE: ","");
133  line.replace("DOWNLOADED: ", "");
134  line.replace("SPEED: ","");
135  line.replace("KB/s","");
136  //Now run the calculations and emit the signal
137  calculateStats(line.section(" ",1,1), line.section(" ",0,0), line.section(" ",2,2), "");
138}
139
140void DLProcess::parsePKGLine(QString line){
141     // KPM!!
142     // TODO 12-12-2013
143     // No JSON in Qt4, once we move to Qt5, replace this hack
144     // with the new JSON parser
145     // Moved 2/18/14 to this class from pc-pkgmanager by Ken Moore
146
147     // Look for any "msg" lines
148     if ( line.indexOf("\"msg") != -1 ) {
149          line.remove(0, line.indexOf("\"msg") + 8);
150          line.truncate(line.lastIndexOf("\""));
151          emit UpdateMessage(line);
152          return;
153     }
154
155     // Look for a download status update
156     if ( line.indexOf("\"INFO_FETCH") != -1 && line.indexOf("\"url\"") != -1 ) {
157       QString file, dl, tot;
158          line.remove(0, line.indexOf("\"url") + 8);
159          line.truncate(line.lastIndexOf("}"));
160
161          // Get the file basename
162          file = line;
163          file.truncate(line.indexOf("\""));
164          file = file.section("/",-1).section(".",0,0); //replace the QFileInfo method below (Ken)
165          //QFileInfo tFile;
166          //tFile.setFile(file);
167          //file = tFile.baseName();
168
169          // Get the download / total
170          dl = line.section(":", 2, 2).section(",", 0, 0);
171          tot = line.section(":", 3, 3).section("}", 0, 0);
172          dl = dl.simplified();
173          tot = tot.simplified();
174             
175          //These are in bytes, need to convert to kilobytes before sending it on...
176          dl = QString::number( dl.toLongLong()/1024 );
177          tot = QString::number( tot.toLongLong()/1024 );
178             
179        //Now calculate the stats and emit the signal
180        calculateStats(dl, tot, "", file);
181     } 
182}
183
184QString DLProcess::kbToString(double kb){
185  double num = kb;
186   QStringList lab; lab << "KB" << "MB" << "GB" << "TB" << "PB";
187   int i=0;
188   while( (i<lab.length()) && (num > 1024) ){
189     num=num/1024; i++;   
190   }
191   //Round to 2 decimel places
192   num = int(num*100)/100.0;
193   QString output = QString::number(num)+" "+lab[i];
194   //qDebug() << "Size calculation:" << sizeK << output;
195   return output;
196}
197
198// ================
199//      PRIVATE SLOTS
200// ================
201void DLProcess::ProcFinished(){
202  if(DLTYPE == 1){
203    //PKG format - also kill the watcher process
204    watcher->kill();
205    QFile::remove(pipeFile); //remove the pipe file too
206  }
207}
208
209void DLProcess::newMessage(){
210  if(DLTYPE == 1){
211    //PKG type pulls info from a different QProcess
212    while(watcher->canReadLine()){
213       QString line = watcher->readLine().simplified();
214        if(line.isEmpty()){ continue; }
215        parsePKGLine(line);
216    }
217   
218  }else{         
219    //All other DL types pull from the main process
220         
221    while(this->canReadLine()){
222      QString line = this->readLine().simplified();
223      if(line.isEmpty()){ continue; }
224      if(DLTYPE == 0){ 
225        // PBI Download format
226        parsePBILine(line);
227      }else if(DLTYPE == 2){
228        // CDN Download format
229        parsePBILine(line); //same parser as PBI's at the moment
230      }else{
231        //Don't have parsing rules for this type: just spit it out
232        emit UpdateMessage(line);
233      }
234    }//End of loop over main process lines
235   
236  } //end check of PKG type
237}
Note: See TracBrowser for help on using the repository browser.