aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorToni Uhlig <Toni.Uhlig@tq-group.com>2017-12-04 11:11:19 +0100
committerToni Uhlig <Toni.Uhlig@tq-group.com>2017-12-04 11:11:19 +0100
commita7cd547ae39ee6f647f5d79a6a1edcbc20097ada (patch)
treed49f2a48715f6666c0bc20c6d5d527f47b74ec42
parentc0313c0bf7f27c668ff68c9cf9b2fe2630396602 (diff)
* CSV exception handling
* port string-to-int convert exception handling * code documentation * gather and print more information about backend jobs
-rw-r--r--src/UpdateFactory.cpp42
-rw-r--r--src/UpdateFactory.hpp6
-rw-r--r--src/UpdateGUI.cpp48
-rw-r--r--src/UpdateGUI.hpp5
-rw-r--r--src/UpdateTool.cpp7
5 files changed, 80 insertions, 28 deletions
diff --git a/src/UpdateFactory.cpp b/src/UpdateFactory.cpp
index ba11376..d5dac40 100644
--- a/src/UpdateFactory.cpp
+++ b/src/UpdateFactory.cpp
@@ -88,7 +88,8 @@ static const std::map<const int, const std::string> error_map = {
{ UPDATE_AUTH_ERROR, "Authentication failed" },
{ UPDATE_VERSION, "Invalid EnergyManager version" },
{ UPDATE_UPDATED, "EnergyManager already updated to an equal or higher firmware version" },
- { UPDATE_FILE, "Could not open update file" }
+ { UPDATE_FILE, "Could not open update file" },
+ { UPDATE_CSV, "Invalid CSV file format" }
};
void mapEmcError(int error, std::string& out)
@@ -384,24 +385,49 @@ bool UpdateFactory::parseJsonResult(httplib::Response& res, json11::Json& result
return !result.is_null();
}
-int loadUpdateFactoriesFromCSV(const char *csv_file, const char *update_file, std::vector<UpdateFactory*>& update_list)
+int loadUpdateFactoriesFromCSV(const char *csv_file, const char *update_file, std::vector<UpdateFactory*>& update_list, std::vector<std::string>& error_list)
{
std::vector<int> err_line;
io::CSVReader<3> in(csv_file);
- in.read_header(io::ignore_extra_column, "hostname", "port", "password");
std::string hostname, port, passwd;
try {
- while (in.read_row(hostname, port, passwd)) {
- UpdateFactory *uf = new UpdateFactory();
+ in.read_header(io::ignore_extra_column, "hostname", "port", "password");
+ } catch (io::error::base& err) {
+ error_list.push_back(err.what());
+ return UPDATE_CSV;
+ } catch (...) {
+ error_list.push_back("Unknown error during CSV read header");
+ return UPDATE_CSV;
+ }
+
+ while (true) {
+ try {
+ if (!in.read_row(hostname, port, passwd))
+ break;
+ } catch (io::error::base& err) {
+ error_list.push_back(err.what());
+ continue;
+ } catch (...) {
+ error_list.push_back("Unknown error during CSV read row");
+ return UPDATE_CSV;
+ }
+
+ UpdateFactory *uf = new UpdateFactory();
+ /* try-catch invalid port numbers */
+ try {
+ if (port.length() == 0)
+ port = "80";
uf->setDest(hostname, port);
uf->setPass(passwd);
uf->setUpdateFile(update_file);
update_list.push_back(uf);
+ } catch (std::invalid_argument& err) {
+ error_list.push_back(std::string("Invalid value in line ")
+ + std::to_string(in.get_file_line()) + std::string(" in file ")
+ + std::string(csv_file));
+ delete uf;
}
- } catch (io::error::with_file_line& err) {
- err_line.push_back(err.file_line); /* not used atm */
- } catch (io::error::with_file_name& err) {
}
return UPDATE_OK;
diff --git a/src/UpdateFactory.hpp b/src/UpdateFactory.hpp
index 190ddf1..57aa3a5 100644
--- a/src/UpdateFactory.hpp
+++ b/src/UpdateFactory.hpp
@@ -16,6 +16,7 @@
#define UPDATE_VERSION 6
#define UPDATE_UPDATED 7
#define UPDATE_FILE 8
+#define UPDATE_CSV 9
enum EMCVersion {
@@ -51,8 +52,11 @@ public:
enum EMCVersion getEmcVersion() const { return this->mapped_emc_version; }
enum EMCVersion getFwVersion() const { return this->mapped_firmware_version; }
int getPort() const { return this->port; }
+ /** authenticate against a hostname */
int doAuth();
+ /** load an update file into memory */
int loadUpdateFile();
+ /** upload an update file */
int doUpdate();
friend void dump_class(UpdateFactory *uf);
protected:
@@ -78,7 +82,7 @@ private:
int port;
};
-int loadUpdateFactoriesFromCSV(const char *csv_file, const char *update_file, std::vector<UpdateFactory*>& update_list);
+int loadUpdateFactoriesFromCSV(const char *csv_file, const char *update_file, std::vector<UpdateFactory*>& update_list, std::vector<std::string>& error_list);
void loadUpdateFactoriesFromStr(std::string& hostPorts, const char *update_file, const char *password, std::vector<UpdateFactory*>& update_list);
diff --git a/src/UpdateGUI.cpp b/src/UpdateGUI.cpp
index ff6697e..0eabffe 100644
--- a/src/UpdateGUI.cpp
+++ b/src/UpdateGUI.cpp
@@ -43,6 +43,8 @@ bool UpdateGUI::OnInit()
UpdateGUIFrame::UpdateGUIFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
: wxFrame(NULL, wxID_ANY, title, pos, size)
{
+ SetBackgroundColour(wxColour(220, 230, 250));
+
wxMenu *menuFile = new wxMenu;
menuFile->Append(wxID_UPDATEFILE,
"&Select Image ...\tCtrl-F",
@@ -85,6 +87,7 @@ UpdateGUIFrame::UpdateGUIFrame(const wxString& title, const wxPoint& pos, const
subBox->AddStretchSpacer();
ipEntry = new wxTextCtrl(this, wxID_IP, wxEmptyString, wxDefaultPosition,
wxDefaultSize, 0);
+ ipEntry->SetHint(wxT("energymanager.tld,energymanager.tld:8080,192.168.0.1,192.168.0.1:8080"));
ipBox->Add(ipEntry, 1, wxEXPAND|wxALL, 5);
pwEntry = new wxTextCtrl(this, wxID_PW, wxEmptyString, wxDefaultPosition,
wxDefaultSize, wxTE_PASSWORD);
@@ -148,19 +151,19 @@ void UpdateGUIFrame::tLog(enum LogType type, std::string& text, const char *iden
void UpdateGUIFrame::OnClose(wxCloseEvent& event)
{
- if (!threads.empty() && jobs->Stacksize() > 0) {
+ if (!threads.empty() && (jobs->Stacksize() > 0 || jobs->getBusyWorker() > 0)) {
std::ostringstream log;
- log << "You have " << jobs->Stacksize() << " pending job(s). Quit?";
+ log << "You have " << jobs->Stacksize() << " pending and "
+ << jobs->getBusyWorker() << " running job(s). Quit?";
wxMessageDialog dlg(this, log.str(), wxMessageBoxCaptionStr,
wxYES_NO | wxCENTRE | wxICON_QUESTION);
dlg.SetYesNoLabels("&Quit", "&Don't quit");
switch (dlg.ShowModal()) {
- case wxID_YES: Destroy(); return;
+ case wxID_YES: Destroy(); _exit(0);
case wxID_NO:
- default: dlg.Destroy(); return;
+ default: return;
}
- dlg.Destroy();
}
for (unsigned i = 0; i < threads.size(); ++i) {
@@ -216,7 +219,6 @@ void UpdateGUIFrame::OnUpdateFile(wxCommandEvent& event)
"image files (*.image)|*.image", wxFD_OPEN|wxFD_FILE_MUST_EXIST);
if (openFileDialog.ShowModal() == wxID_CANCEL) {
- openFileDialog.Destroy();
return;
}
@@ -224,16 +226,14 @@ void UpdateGUIFrame::OnUpdateFile(wxCommandEvent& event)
imgEntry->AppendText(openFileDialog.GetPath());
log = wxString::Format(wxT("Update File: \"%s\""), openFileDialog.GetPath());
tLog(RTL_DEFAULT, log);
-
- openFileDialog.Destroy();
}
void UpdateGUIFrame::OnImportCSV(wxCommandEvent& event)
{
- int rv;
+ int jobid;
std::vector<UpdateFactory*> uf;
- std::string err;
wxString log;
+ std::vector<std::string> error_list;
wxFileDialog openFileDialog(this, _("Select Update CSV"), "", "",
"image files (*.csv)|*.csv", wxFD_OPEN|wxFD_FILE_MUST_EXIST);
@@ -243,25 +243,23 @@ void UpdateGUIFrame::OnImportCSV(wxCommandEvent& event)
}
if (openFileDialog.ShowModal() == wxID_CANCEL) {
- openFileDialog.Destroy();
return;
}
log = wxString::Format(wxT("CSV File: \"%s\""), openFileDialog.GetPath());
tLog(RTL_DEFAULT, log);
- rv = loadUpdateFactoriesFromCSV(openFileDialog.GetPath(), imgEntry->GetValue(), uf);
- if (rv != UPDATE_OK) {
- mapEmcError(rv, err);
- tLog(RTL_RED, wxString::Format(wxT("CSV parse failed: \"%s\""), err));
+ loadUpdateFactoriesFromCSV(openFileDialog.GetPath(), imgEntry->GetValue(), uf, error_list);
+ for (auto& errstr : error_list) {
+ tLog(RTL_RED, wxString::Format(wxT("CSV read error: \"%s\""), errstr));
}
- int jobid = rand();
+
+ jobid = rand();
for (auto *u : uf) {
jobs->AddJob(Job(Job::eID_THREAD_JOB, JobArgs(jobid, *u)));
jobid++;
delete u;
}
SetStatusText(wxString::Format(wxT("CSV Import %s"), openFileDialog.GetPath()));
- openFileDialog.Destroy();
}
void UpdateGUIFrame::OnUpdate(wxCommandEvent& event)
@@ -279,6 +277,7 @@ void UpdateGUIFrame::OnUpdate(wxCommandEvent& event)
}
str = ipEntry->GetValue();
+ /* parse multiple hostname:port combinations */
loadUpdateFactoriesFromStr(str, imgEntry->GetValue(), pwEntry->GetValue(), uf);
int jobid = rand();
for (auto *u : uf) {
@@ -307,7 +306,15 @@ void UpdateGUIFrame::OnThread(wxCommandEvent& event)
{
wxString wxs;
LogType tp = RTL_DEFAULT;
+ static size_t counter = 0;
+ /* some periodic informational output */
+ if ((++counter % 30) == 0) {
+ wxs = wxString::Format(wxT("%u jobs done, %u jobs pending, %u jobs running"), jobs->getTotalJobsDone(), jobs->Stacksize(), jobs->getBusyWorker());
+ tLog(RTL_DEFAULT, wxs);
+ }
+
+ /* process the wx event itself */
switch (event.GetId()) {
case Job::eID_THREAD_JOB:
case Job::eID_THREAD_MSG:
@@ -332,4 +339,11 @@ void UpdateGUIFrame::OnThread(wxCommandEvent& event)
break;
default: event.Skip();
}
+
+ /* give the user feedback if all jobs finished */
+ if (jobs->getTotalJobsDone() > 1 && jobs->Stacksize() == 0 && jobs->getBusyWorker() == 0) {
+ tLog(RTL_GREEN, "All jobs finished.");
+ jobs->resetTotalJobsDone();
+ counter = 0;
+ }
}
diff --git a/src/UpdateGUI.hpp b/src/UpdateGUI.hpp
index e953ac6..6f34bbf 100644
--- a/src/UpdateGUI.hpp
+++ b/src/UpdateGUI.hpp
@@ -35,9 +35,11 @@ public:
protected:
UpdateFactory uf;
private:
+ /* log to GUI */
void tLog(enum LogType type, const char *text, const char *ident=nullptr);
void tLog(enum LogType type, std::string& text, const char *ident=nullptr);
+ /* wxWidgets GUI/Thread events */
void OnClose(wxCloseEvent& event);
void OnExit(wxCommandEvent& event);
void OnAbout(wxCommandEvent& event);
@@ -50,12 +52,15 @@ private:
wxDECLARE_EVENT_TABLE();
+ /* GUI elements */
wxBoxSizer *mainVSizer;
wxStaticBoxSizer *ipBox, *pwBox, *imgBox, *subBox, *logBox;
wxButton *imgButton, *subButton, *csvButton;
wxTextCtrl *ipEntry, *pwEntry, *imgEntry, *logText;
+ /** JobQueue */
Queue *jobs;
+ /** Thread list IDs */
std::list<int> threads;
};
diff --git a/src/UpdateTool.cpp b/src/UpdateTool.cpp
index 5f2ab1a..1f4d2af 100644
--- a/src/UpdateTool.cpp
+++ b/src/UpdateTool.cpp
@@ -35,12 +35,15 @@ int main(int argc, char *argv[])
if (argc == 0)
return 1;
if (argc == 3) {
- uf.clear();
- rv = loadUpdateFactoriesFromCSV(argv[1], argv[2], uf);
+ std::vector<std::string> error_list;
+ rv = loadUpdateFactoriesFromCSV(argv[1], argv[2], uf, error_list);
if (rv != UPDATE_OK) {
std::cerr << "CSV file read \"" << argv[1] << "\" failed with: " << rv << std::endl;
return 1;
}
+ for (auto& errstr : error_list) {
+ std::cerr << "CSV read error: " << errstr << std::endl;
+ }
} else
if (argc == 4) {
hostPorts = std::string(argv[1]);