source: src-qt4/life-preserver/LPTray.cpp @ 2a5e337

9.2-releasereleng/10.0releng/10.0.1releng/10.0.2releng/10.0.3releng/10.1
Last change on this file since 2a5e337 was 2a5e337, checked in by Kris Moore <kris@…>, 16 months ago

Replace old life-preserver utility with our new one which uses ZFS snapshots / replication

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