source: src-qt4/libpcbsd/utils/pcbsd-DLProcess.cpp @ 2e26400

releng/10.0.1releng/10.0.2releng/10.0.3releng/10.1
Last change on this file since 2e26400 was 2e26400, checked in by Ken Moore <ken@…>, 10 months ago

Add a new DLProcess class to the libpcbsd utilities. Compiles fine, but untestedyet.

  • Property mode set to 100644
File size: 7.5 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){
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      spd = -1; //unknown
109    }
110    other = kbToString(spd)+"/s";
111  //Check for a filename instead
112  }else if(!filename.isEmpty() ){
113    other = filename;
114  }
115  //Now emit the stats
116  emit UpdatePercent(QString::number(percent), kbToString(tot), other);
117}
118
119void DLProcess::parsePBILine(QString line){
120  //Quick checks for line formatting
121  if( line.startsWith("FETCH:") ){ emit UpdateMessage(tr("Download Starting...")); return; }
122  else if( line == "FETCHDONE"){ emit UpdateMessage(tr("Download Finished")); return; }
123  else if(!line.startsWith("SIZE:")){ emit UpdateMessage(line); return; }
124  //Now parse the PBI download line
125  //qDebug() << "parse Download Line:" << line;
126  //Line format: SIZE:  <KB> DOWNLOADED:  <KB> SPEED:  <KB/s> KB/s
127  line = line.simplified();
128  line.replace("SIZE: ","");
129  line.replace("DOWNLOADED: ", "");
130  line.replace("SPEED: ","");
131  line.replace("KB/s","");
132  //Now run the calculations and emit the signal
133  calculateStats(line.section(" ",1,1), line.section(" ",0,0), line.section(" ",2,2), "");
134}
135
136void DLProcess::parsePKGLine(QString line){
137     // KPM!!
138     // TODO 12-12-2013
139     // No JSON in Qt4, once we move to Qt5, replace this hack
140     // with the new JSON parser
141     // Moved 2/18/14 to this class from pc-pkgmanager by Ken Moore
142
143     // Look for any "msg" lines
144     if ( line.indexOf("\"msg") != -1 ) {
145          line.remove(0, line.indexOf("\"msg") + 8);
146          line.truncate(line.lastIndexOf("\""));
147          emit UpdateMessage(line);
148          return;
149     }
150
151     // Look for a download status update
152     if ( line.indexOf("\"INFO_FETCH") != -1 && line.indexOf("\"url\"") != -1 ) {
153       QString file, dl, tot;
154          line.remove(0, line.indexOf("\"url") + 8);
155          line.truncate(line.lastIndexOf("}"));
156
157          // Get the file basename
158          file = line;
159          file.truncate(line.indexOf("\""));
160          file = file.section("/",-1).section(".",0,0); //replace the QFileInfo method below (Ken)
161          //QFileInfo tFile;
162          //tFile.setFile(file);
163          //file = tFile.baseName();
164
165          // Get the download / total
166          dl = line.section(":", 2, 2).section(",", 0, 0);
167          tot = line.section(":", 3, 3).section("}", 0, 0);
168          dl = dl.simplified();
169          tot = tot.simplified();
170             
171          //These are in bytes, need to convert to kilobytes before sending it on...
172          dl = QString::number( dl.toLongLong()/1024 );
173          tot = QString::number( tot.toLongLong()/1024 );
174             
175        //Now calculate the stats and emit the signal
176        calculateStats(dl, tot, "", file);
177     } 
178}
179
180QString DLProcess::kbToString(double kb){
181  double num = kb;
182   QStringList lab; lab << "KB" << "MB" << "GB" << "TB" << "PB";
183   int i=0;
184   while( (i<lab.length()) && (num > 1024) ){
185     num=num/1024; i++;   
186   }
187   //Round to 2 decimel places
188   num = int(num*100)/100.0;
189   QString output = QString::number(num)+" "+lab[i];
190   //qDebug() << "Size calculation:" << sizeK << output;
191   return output;
192}
193
194// ================
195//      PRIVATE SLOTS
196// ================
197void DLProcess::ProcFinished(){
198  if(DLTYPE == 1){
199    //PKG format - also kill the watcher process
200    watcher->kill();
201    QFile::remove(pipeFile); //remove the pipe file too
202  }
203}
204
205void DLProcess::newMessage(){
206  if(DLTYPE == 1){
207    //PKG type pulls info from a different QProcess
208    while(watcher->canReadLine()){
209       QString line = watcher->readLine().simplified();
210        if(line.isEmpty()){ continue; }
211        parsePKGLine(line);
212    }
213   
214  }else{         
215    //All other DL types pull from the main process
216         
217    while(this->canReadLine()){
218      QString line = this->readLine().simplified();
219      if(line.isEmpty()){ continue; }
220      if(DLTYPE == 0){ 
221        // PBI Download format
222        parsePBILine(line);
223      }else if(DLTYPE == 2){
224        // CDN Download format
225        parsePBILine(line); //same parser as PBI's at the moment
226      }else{
227        //Don't have parsing rules for this type: just spit it out
228        emit UpdateMessage(line);
229      }
230    }//End of loop over main process lines
231   
232  } //end check of PKG type
233}
Note: See TracBrowser for help on using the repository browser.