source: src-qt4/life-preserver/LPTray.cpp @ 845aaf6

9.2-releasereleng/10.0releng/10.0.1
Last change on this file since 845aaf6 was 845aaf6, checked in by Ken Moore <ken@…>, 8 months ago

Setup the new snapshot process as an external process and update the message appropriately. Also make sure that we parse every single line in the log, just to make sure that we don't miss an important message (keep it quiet during the initial startup phase though).

  • Property mode set to 100644
File size: 8.8 KB
Line 
1#include "LPTray.h"
2
3//PUBLIC
4LPTray::LPTray() : QSystemTrayIcon(){
5  initPhase = true; //flag that we are in the startup process
6  //Start up the log file watcher
7  QString logfile = "/var/log/lpreserver/lpreserver.log";
8  watcher = new QFileSystemWatcher();
9        if(!QFile::exists(logfile)){ 
10          if(!QFile::exists("/var/log/lpreserver")){ system( "mkdir /var/log/lpreserver"); }
11          system( QString("touch "+logfile).toUtf8() ); 
12        }
13        watcher->addPath(logfile);
14  logFile = new QFile(logfile);
15        logFile->open(QIODevice::ReadOnly | QIODevice::Text); //open it now, for faster reading
16  LFStream = new QTextStream(logFile);
17        connect(watcher, SIGNAL(fileChanged(QString)),this,SLOT(slotNewLogMessage(QString)) ); //now connect the signal/slot
18  //Setup the context menu
19  menu = new QMenu;
20        menu->addAction(new QAction(QIcon(":/images/application-exit.png"),tr("Close Life Preserver Tray"),this) );
21        connect(menu, SIGNAL(triggered(QAction*)), this, SLOT(slotClose()) );
22  this->setContextMenu(menu);
23  //Setup the animated icon timer
24  timer = new QTimer();
25        timer->setInterval(100);
26        connect(timer, SIGNAL(timeout()), this, SLOT(displayWorkingIcon()) );
27  //Setup initial icon for the tray
28  this->setIcon( QIcon(":/images/tray-icon-idle.png") );
29  //Create the configuration GUI
30  GUI = new mainUI();
31  //connect other signals/slots
32  connect(this, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(slotTrayClicked(QSystemTrayIcon::ActivationReason)) );
33  //Make sure we check the latest line in the logfile
34  QTimer::singleShot(1000, this,SLOT(firstCheck()));
35}
36
37LPTray::~LPTray(){
38  if(statFile != 0){ statFile->close(); }
39  logFile->close();
40  delete statFile;
41  delete logFile;
42  delete watcher;
43  delete menu;
44  delete timer;
45}
46
47// ===============
48//  PRIVATE FUNCTIONS
49// ===============
50void LPTray::parseLogMessage(QString log, bool quiet){
51  //Divide up the log into it's sections
52  QString timestamp = log.section(":",0,2).simplified();
53  QString time = timestamp.section(" ",3,3).simplified();
54  QString message = log.section(":",3,3).toLower().simplified();
55  QString dev = log.section(":",4,4).simplified(); //dataset/snapshot/nothing
56  //Now decide what to do/show because of the log message
57  qDebug() << "New Log Message:" << log;
58  if(message.contains("creating snapshot")){
59    dev = message.section(" ",-1).simplified();
60    if(!quiet){ this->showMessage( time, QString(tr("Creating snapshot for %1")).arg(dev), QSystemTrayIcon::Information, 5000); }
61    //Just set the standard idle icon
62    this->setIcon( QIcon(":/images/tray-icon-idle.png") );   
63    setIdleToolTip();
64  }else if(message.contains("starting replication")){
65    startWorkingIcon();
66    //Setup the file watcher for this new log file
67    sFile = dev;
68    if(!sFile.isEmpty()){
69      if(!QFile::exists(sFile)){ system( QString("touch "+sFile).toUtf8() ); }
70      statFile = new QFile(sFile);
71        statFile->open(QIODevice::ReadOnly | QIODevice::Text);
72        SFStream = new QTextStream(statFile);
73      watcher->addPath(sFile); //will update/set tooltips
74    }
75  }else if(message.contains("finished replication")){
76    stopWorkingIcon();
77    //Stop the file wather from watching the status file and clean up
78    if(!sFile.isEmpty()){
79      watcher->removePath(sFile);
80          statFile->close();
81          sFile.clear();
82    }
83    //Clean up and show messages
84    repTotK.clear();
85    setIdleToolTip();
86    dev = message.section(" ",-1).simplified();
87    if(!quiet){ this->showMessage( time, QString(tr("Finished replication for %1")).arg(dev), QSystemTrayIcon::Information, 5000); }
88  }else if( message.contains("FAILED replication") ){
89    stopWorkingIcon();
90    //Stop the file wather from watching the status file and clean up
91    if(!sFile.isEmpty()){
92      watcher->removePath(sFile);
93          statFile->close();
94          sFile.clear();
95    }
96    //Clean up and show messages
97    repTotK.clear();
98    dev = message.section(" ",-1).simplified();
99    QString file = log.section("LOGFILE:",1,1).simplified();
100    QString tt = QString(tr("%1: Replication Failed on %2")).arg(time,dev) +"\n"+ QString(tr("Logfile available at: %1")).arg(file);
101    this->setToolTip(tt);   
102    if(!quiet){ this->showMessage( time, QString(tr("Replication Error for %1")).arg(dev), QSystemTrayIcon::Information, 5000); }
103    this->setIcon(QIcon(":/images/tray-icon-failed.png"));
104  }else{
105    //Just set the standard idle icon
106    //this->setIcon( QIcon(":/images/tray-icon-idle.png") );   
107  }
108  if(GUI->isVisible()){
109    GUI->setupUI();
110  }
111}
112
113void LPTray::parseStatusMessage(QString stat){
114  qDebug() << "New Status Message:" << stat;
115  //Divide up the status message into sections
116  stat.replace("\t"," ");
117  QString dataset = stat.section(" ",2,2,QString::SectionSkipEmpty).section("/",0,0).simplified();
118  QString cSize = stat.section(" ",1,1,QString::SectionSkipEmpty);
119  //Now Setup the tooltip
120  if(cSize != lastSize){ //don't update the tooltip if the same size info
121    QString percent;
122    if(!repTotK.isEmpty()){
123      //calculate the percentage
124      double tot = displayToDoubleK(repTotK);
125      double c = displayToDoubleK(cSize);
126      if( tot!=-1 & c!=-1){
127        double p = (c*100)/tot;
128        p = int(p*10)/10.0; //round to 1 decimel places
129        percent = QString::number(p) + "%";
130      }
131    }
132    if(repTotK.isEmpty()){ repTotK = "??"; }
133    //Format the tooltip String
134    QString status = cSize+"/"+repTotK;
135    if(!percent.isEmpty()){ status.append(" ("+percent+")"); }
136    QString txt = QString(tr("Replicating %1: %2")).arg(dataset, status);
137    this->setToolTip(txt);
138    lastSize = cSize; //save the current size for later
139  }
140}
141
142void LPTray::setIdleToolTip(){
143  //Get the last snapshot created
144  QStringList dsList = LPBackend::listDatasets();
145  if(dsList.isEmpty()){
146    this->setToolTip(tr("Automatic Backups Disabled"));
147  }else{
148    //Grab the newest snapshot from each dataset
149    QString tt; //tooltip
150    for(int i=0; i<dsList.length(); i++){
151      QStringList snaps = LPBackend::listLPSnapshots(dsList[0]);
152      if(!tt.isEmpty()){ tt.append("\n"); } //put each dataset on a new line
153      if(snaps.isEmpty()){
154        tt.append( QString(tr("%1: No snapshots available")).arg(dsList[0]) );
155      }else{
156        tt.append( QString(tr("%1: %2 available")).arg(dsList[0],snaps[0]) );
157      }
158    }
159    this->setToolTip(tt);
160  }
161       
162}
163
164void LPTray::startWorkingIcon(){
165  this->setIcon( QIcon(":/images/tray-icon-active7.png"));
166  //wNum = 1; //start on the first image
167  //timer->start();
168}
169
170void LPTray::stopWorkingIcon(){
171  //timer->stop();
172  this->setIcon( QIcon(":/images/tray-icon-idle.png") );     
173}
174
175double LPTray::displayToDoubleK(QString displayNumber){
176  QStringList labels; 
177    labels << "K" << "M" << "G" << "T" << "P" << "E";
178  QString clab = displayNumber.right(1); //last character is the size label
179        displayNumber.chop(1); //remove the label from the number
180  double num = displayNumber.toDouble();
181  //Now format the number properly
182  bool ok = false;
183  for(int i=0; i<labels.length(); i++){
184    if(labels[i] == clab){ ok = true; break; }
185    else{ num = num*1024; } //get ready for the next size
186  }
187  if(!ok){ num = -1; } //could not determine the size
188  return num;
189}
190
191// ===============
192//     PRIVATE SLOTS
193// ===============
194void LPTray::firstCheck(){
195  slotNewLogMessage("/var/log/lpreserver/lpreserver.log");
196  initPhase = false; //done with initializations
197}
198
199void LPTray::slotNewLogMessage(QString file){
200  //qDebug() << "New Log Message in file:" << file;
201  if(file == "/var/log/lpreserver/lpreserver.log"){
202    //Backend Status Update
203    //get the last line from the log file
204    //Now parse the log lines and do stuff with it
205    while( !LFStream->atEnd() ){ parseLogMessage(LFStream->readLine(), initPhase); }
206  }else{
207    //Replication status update
208      //get the last line from the file
209      QString stat;
210      while( !SFStream->atEnd() ){ 
211        QString line = SFStream->readLine(); 
212        if(line.contains("total estimated size")){ repTotK = line.section(" ",-1).simplified(); } //save the total size to replicate
213        else if(line.startsWith("send from ")){}
214        else if(line.startsWith("TIME ")){}
215        else{ stat = line; } //only save the relevant status line
216      }
217      //parse the status line
218      if(!stat.isEmpty()){ parseStatusMessage(stat); }
219  }
220}
221
222void LPTray::slotTrayClicked(QSystemTrayIcon::ActivationReason reason){
223  if(reason == QSystemTrayIcon::Trigger){ 
224    if(GUI->isVisible()){ GUI->hide(); }
225    else{ startGUI(); }
226  }else if( reason == QSystemTrayIcon::Context){
227    this->contextMenu()->popup(QCursor::pos());
228  }
229}
230
231void LPTray::slotClose(){
232  exit(0);
233}
234
235void LPTray::slotSingleInstance(){
236  this->show();
237}
238
239void LPTray::startGUI(){
240  //Start up the GUI
241    GUI->setupUI();
242    GUI->raise();
243    GUI->show();
244}
245
246void LPTray::displayWorkingIcon(){
247  QString ico = ":/images/tray-icon-active"+QString::number(wNum)+".png";
248  this->setIcon(QIcon(ico));
249  if(wNum == 16){ wNum = 1; } //go back to the beginning of the loop
250  else{ wNum++; }
251}
Note: See TracBrowser for help on using the repository browser.