Improvement the progress monitor for Sketch-binary update

pull/123/head
Hieromon Ikasamo 6 years ago
parent 836ec3376b
commit 84a2b97e55
  1. 17
      src/AutoConnectDefs.h
  2. 33
      src/AutoConnectUpdate.cpp
  3. 1
      src/AutoConnectUpdate.h
  4. 8
      src/AutoConnectUpdatePage.h
  5. 4
      src/AutoConnectUploadImpl.h

@ -205,13 +205,16 @@
// The purpose of this macro is to avoid the use of invalid member // The purpose of this macro is to avoid the use of invalid member
// functions due to differences in the version of the library which // functions due to differences in the version of the library which
// AutoConnect depends on. // AutoConnect depends on.
#define AC_HAS_FUNC(func) \ #define AC_HAS_FUNC(func) \
template<typename T> \ template<typename T> \
struct has_func_##func { \ struct has_func_##func { \
static auto check(...) -> decltype(std::false_type()); \ private: \
template<typename U> \ typedef char one; \
static auto check(U&) -> decltype(static_cast<decltype(U::func)*>(&U::func), std::true_type()); \ typedef long two; \
enum : bool { value = decltype(check(std::declval<T&>()))::value }; \ template<typename U> static one test(typeof(&U::func)); \
template<typename U> static two test(...); \
public: \
enum { value = sizeof(test<T>(0)) == sizeof(char) }; \
} }
#endif // _AUTOCONNECTDEFS_H_ #endif // _AUTOCONNECTDEFS_H_

@ -85,17 +85,16 @@ namespace AutoConnectUtil {
AC_HAS_FUNC(onProgress); AC_HAS_FUNC(onProgress);
template<typename T> template<typename T>
typename std::enable_if<AutoConnectUtil::has_func_onProgress<T>::value, AutoConnectUpdate::AC_UPDATEDIALOG_t>::type onProgress(const T& updater, std::function<void(size_t, size_t)> fn) { typename std::enable_if<AutoConnectUtil::has_func_onProgress<T>::value, AutoConnectUpdate::AC_UPDATEDIALOG_t>::type onProgress(T& updater, std::function<void(size_t, size_t)> fn) {
updater.onProgress(fn); updater.onProgress(fn);
AC_DBG("Callback enabled\n"); AC_DBG("An updater keeps callback\n");
return AutoConnectUpdate::UPDATEDIALOG_METER; return AutoConnectUpdate::UPDATEDIALOG_METER;
} }
template<typename T> template<typename T>
typename std::enable_if<!AutoConnectUtil::has_func_onProgress<T>::value, AutoConnectUpdate::AC_UPDATEDIALOG_t>::type onProgress(const T& updater, std::function<void(size_t, size_t)> fn) { typename std::enable_if<!AutoConnectUtil::has_func_onProgress<T>::value, AutoConnectUpdate::AC_UPDATEDIALOG_t>::type onProgress(T& updater, std::function<void(size_t, size_t)> fn) {
(void)(updater); (void)(updater);
(void)(fn); (void)(fn);
AC_DBG("Callback disabled\n");
return AutoConnectUpdate::UPDATEDIALOG_LOADER; return AutoConnectUpdate::UPDATEDIALOG_LOADER;
} }
} }
@ -143,11 +142,6 @@ void AutoConnectUpdate::attach(AutoConnect& portal) {
_status = UPDATE_IDLE; _status = UPDATE_IDLE;
// Register the callback to inform the update progress
_dialog = AutoConnectUtil::onProgress<UpdateVariedClass>(Update, std::bind(&AutoConnectUpdate::_inProgress, this, std::placeholders::_1, std::placeholders::_2));
// Update.onProgress(std::bind(&AutoConnectUpdate::_inProgress, this, std::placeholders::_1, std::placeholders::_2));
// _dialog = UPDATEDIALOG_METER;
// Adjust the client dialog pattern according to the callback validity // Adjust the client dialog pattern according to the callback validity
// of the UpdateClass. // of the UpdateClass.
AutoConnectElement* loader = _progress->getElement(String(F("loader"))); AutoConnectElement* loader = _progress->getElement(String(F("loader")));
@ -172,6 +166,9 @@ void AutoConnectUpdate::attach(AutoConnect& portal) {
AC_DBG("AutoConnectUpdate attached\n"); AC_DBG("AutoConnectUpdate attached\n");
if (WiFi.status() == WL_CONNECTED) if (WiFi.status() == WL_CONNECTED)
enable(); enable();
// Register the callback to inform the update progress
_dialog = AutoConnectUtil::onProgress<UpdateVariedClass>(Update, std::bind(&AutoConnectUpdate::_inProgress, this, std::placeholders::_1, std::placeholders::_2));
} }
/** /**
@ -217,17 +214,16 @@ void AutoConnectUpdate::handleUpdate(void) {
// execute it accordingly. It is only this process point that // execute it accordingly. It is only this process point that
// requests update processing. // requests update processing.
if (_status == UPDATE_START) { if (_status == UPDATE_START) {
_ws->loop(); // Crawl the connection request.
unsigned long tm = millis(); unsigned long tm = millis();
while (_ws->connectedClients() <= 0) { while (!_wsConnected) {
if (millis() - tm > AUTOCONNECT_UPDATE_TIMEOUT) { if (millis() - tm > 30 * 1000) {
AC_DBG("WebSocket client connection timeout, update ignored\n"); AC_DBG("WebSocket client connection timeout, update ignored\n");
break; break;
} }
_ws->loop(); // Crawl the connection request. _ws->loop(); // Crawl the connection request.
} }
// Launch the update // Launch the update
if (_ws->connectedClients()) if (_wsConnected)
update(); update();
else else
_status = UPDATE_IDLE; _status = UPDATE_IDLE;
@ -276,7 +272,7 @@ AC_UPDATESTATUS_t AutoConnectUpdate::update(void) {
} }
_WiFiClient.reset(nullptr); _WiFiClient.reset(nullptr);
// Request the client to close the WebSocket. // Request the client to close the WebSocket.
_ws->sendTXT(_wsClient, "#e", 2); _ws->sendTXT(_wsClient, "#e");
} }
else { else {
AC_DBG("An update has not specified"); AC_DBG("An update has not specified");
@ -454,6 +450,7 @@ String AutoConnectUpdate::_onUpdate(AutoConnectAux& progress, PageArgument& args
AutoConnectElement* wsurl = progress.getElement(String(F("wsurl"))); AutoConnectElement* wsurl = progress.getElement(String(F("wsurl")));
wsurl->value = "ws://" + WiFi.localIP().toString() + ':' + AUTOCONNECT_WEBSOCKETPORT; wsurl->value = "ws://" + WiFi.localIP().toString() + ':' + AUTOCONNECT_WEBSOCKETPORT;
AC_DBG("Cast WS %s\n", wsurl->value.c_str()); AC_DBG("Cast WS %s\n", wsurl->value.c_str());
_wsConnected = false;
_status = UPDATE_START; _status = UPDATE_START;
return String(""); return String("");
} }
@ -473,6 +470,8 @@ String AutoConnectUpdate::_onResult(AutoConnectAux& result, PageArgument& args)
if (_ws) { if (_ws) {
_ws->close(); _ws->close();
while (_wsConnected)
_ws->loop();
_ws.reset(nullptr); _ws.reset(nullptr);
} }
@ -512,6 +511,10 @@ void AutoConnectUpdate::_inProgress(size_t amount, size_t size) {
void AutoConnectUpdate::_wsEvent(uint8_t client, WStype_t event, uint8_t* payload, size_t length) { void AutoConnectUpdate::_wsEvent(uint8_t client, WStype_t event, uint8_t* payload, size_t length) {
AC_DBG("WS client:%d event(%d)\n", client, event); AC_DBG("WS client:%d event(%d)\n", client, event);
if (event == WStype_CONNECTED) if (event == WStype_CONNECTED) {
_wsConnected = true;
_wsClient = client; _wsClient = client;
}
else if (event == WStype_DISCONNECTED)
_wsConnected = false;
} }

@ -131,6 +131,7 @@ class AutoConnectUpdate : public HTTPUpdateClass {
std::unique_ptr<WebSocketsServer> _ws; /**< Reports the update progress measure */ std::unique_ptr<WebSocketsServer> _ws; /**< Reports the update progress measure */
uint8_t _wsClient; /**< WebSocket client id */ uint8_t _wsClient; /**< WebSocket client id */
bool _wsConnected; /**< WebSocket connection status */
size_t _amount; /**< Received amound bytes */ size_t _amount; /**< Received amound bytes */
size_t _binSize; /**< Updater binary size */ size_t _binSize; /**< Updater binary size */

@ -25,7 +25,7 @@ const AutoConnectUpdate::ACPage_t AutoConnectUpdate::_auxCatalog PROGMEM = {
// Define the AUTOCONNECT_URI_UPDATE_ACT page to display during the // Define the AUTOCONNECT_URI_UPDATE_ACT page to display during the
// update process. // update process.
const AutoConnectUpdate::ACElementProp_t AutoConnectUpdate::_elmProgress[] PROGMEM = { const AutoConnectUpdate::ACElementProp_t AutoConnectUpdate::_elmProgress[] PROGMEM = {
{ AC_Element, "loader", "<style>.loader{border:2px solid #f3f3f3;border-radius:50%;border-top:2px solid #555;width: 12px;height:12px;-webkit-animation:spin 1s linear infinite;animation:spin 1s linear infinite}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg)}}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}</style>", nullptr }, { AC_Element, "loader", "<style>.loader{border:2px solid #f3f3f3;border-radius:50%;border-top:2px solid #555;width:12px;height:12px;-webkit-animation:spin 1s linear infinite;animation:spin 1s linear infinite}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0)}100%{-webkit-transform:rotate(360deg)}}@keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}</style>", nullptr },
{ AC_Element, "c1", "<div style=\"display:inline-block\">", nullptr }, { AC_Element, "c1", "<div style=\"display:inline-block\">", nullptr },
{ AC_Element, "binname", nullptr, nullptr }, { AC_Element, "binname", nullptr, nullptr },
{ AC_Element, "c2", "&ensp;from&ensp;", nullptr }, { AC_Element, "c2", "&ensp;from&ensp;", nullptr },
@ -35,10 +35,10 @@ const AutoConnectUpdate::ACElementProp_t AutoConnectUpdate::_elmProgress[] PROGM
{ AC_Element, "progress_loader", "<div class=\"loader\" />", nullptr }, { AC_Element, "progress_loader", "<div class=\"loader\" />", nullptr },
{ AC_Element, "c4", "</span></div></div>", nullptr }, { AC_Element, "c4", "</span></div></div>", nullptr },
{ AC_Text, "status", nullptr, nullptr }, { AC_Text, "status", nullptr, nullptr },
{ AC_Element, "c5", "<script type=\"text/javascript\">var ws;window.onload=function(){ws=new WebSocket('", nullptr }, { AC_Element, "c5", "<script type=\"text/javascript\">var ws;window.onload=function(){(ws=new WebSocket(\"", nullptr },
{ AC_Element, "wsurl", nullptr, nullptr }, { AC_Element, "wsurl", nullptr, nullptr },
{ AC_Element, "c6", "');ws.onopen=function(){ws.onmessage=function(e){var pl=e.data.split(',');if(pl[0]=='#e'){location.href='/_ac/update_result';}else if(pl[0]=='#p'){incr(pl[1]);}};};ws.onclose=function(e){console.log('WS close('+e.code+')'+e.reason);if(e.code!=1000){document.getElementById('status').textContent='WebSocket connection closed. ('+e.code+')';}};ws.onerror=function(e){if(ws.readyState==1){document.getElementById('status').textContent='WebSocket '+e.type;}};};window.onbeforeunload=function(){ws.close();};", nullptr }, { AC_Element, "c6", "\")).onopen=function(){ws.onmessage=function(e){var o=e.data.split(\",\");\"#e\"==o[0]?ws.close(1e3):\"#p\"==o[0]&&incr(o[1])}},ws.onclose=function(e){console.log(\"WS close(\"+e.code+\") \"+e.reason),1e3!=e.code&&(document.getElementById(\"status\").textContent=\"WebSocket connection closed. (\"+e.code+\")\"),location.href=\"" AUTOCONNECT_URI_UPDATE_RESULT "\"},ws.onerror=function(e){1==ws.readyState&&(document.getElementById(\"status\").textContent=\"WebSocket \"+e.type)}},window.onbeforeunload=function(){ws.close()};", nullptr },
{ AC_Element, "inprogress_meter", "function incr(pv){var iv=pv.split(':');var pb=document.getElementById('progress').getElementsByTagName('meter');pb[0].setAttribute('value',iv[0]);pb[0].setAttribute('max',iv[1]);}", nullptr }, { AC_Element, "inprogress_meter", "function incr(e){var t=e.split(\":\"),r=document.getElementById(\"progress\").getElementsByTagName(\"meter\");r[0].setAttribute(\"value\",t[0]),r[0].setAttribute(\"max\",t[1])}", nullptr },
{ AC_Element, "inprogress_loader", "function incr(pv){}", nullptr }, { AC_Element, "inprogress_loader", "function incr(pv){}", nullptr },
{ AC_Element, "c7", "</script>", nullptr }, { AC_Element, "c7", "</script>", nullptr },
}; };

@ -43,12 +43,12 @@ namespace AutoConnectUtil {
AC_HAS_FUNC(end); AC_HAS_FUNC(end);
template<typename T> template<typename T>
typename std::enable_if<AutoConnectUtil::has_func_end<T>::value, void>::type end(const T* media) { typename std::enable_if<AutoConnectUtil::has_func_end<T>::value, void>::type end(T* media) {
media->end(); media->end();
} }
template<typename T> template<typename T>
typename std::enable_if<!AutoConnectUtil::has_func_end<T>::value, void>::type end(const T* media) { typename std::enable_if<!AutoConnectUtil::has_func_end<T>::value, void>::type end(T* media) {
(void)(media); (void)(media);
} }
} }

Loading…
Cancel
Save