diff options
author | Toni Uhlig <Toni.Uhlig@tq-group.com> | 2017-12-04 11:11:19 +0100 |
---|---|---|
committer | Toni Uhlig <Toni.Uhlig@tq-group.com> | 2017-12-04 11:11:19 +0100 |
commit | a7cd547ae39ee6f647f5d79a6a1edcbc20097ada (patch) | |
tree | d49f2a48715f6666c0bc20c6d5d527f47b74ec42 | |
parent | c0313c0bf7f27c668ff68c9cf9b2fe2630396602 (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.cpp | 42 | ||||
-rw-r--r-- | src/UpdateFactory.hpp | 6 | ||||
-rw-r--r-- | src/UpdateGUI.cpp | 48 | ||||
-rw-r--r-- | src/UpdateGUI.hpp | 5 | ||||
-rw-r--r-- | src/UpdateTool.cpp | 7 |
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]); |