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
// functions due to differences in the version of the library which
// AutoConnect depends on.
#define AC_HAS_FUNC(func) \
template<typename T> \
struct has_func_##func { \
static auto check(...) -> decltype(std::false_type()); \
template<typename U> \
static auto check(U&) -> decltype(static_cast<decltype(U::func)*>(&U::func), std::true_type()); \
enum : bool { value = decltype(check(std::declval<T&>()))::value }; \
#define AC_HAS_FUNC(func) \
template<typename T> \
struct has_func_##func { \
private: \
typedef char one; \
typedef long two; \
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_

@ -85,17 +85,16 @@ namespace AutoConnectUtil {
AC_HAS_FUNC(onProgress);
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);
AC_DBG("Callback enabled\n");
AC_DBG("An updater keeps callback\n");
return AutoConnectUpdate::UPDATEDIALOG_METER;
}
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)(fn);
AC_DBG("Callback disabled\n");
return AutoConnectUpdate::UPDATEDIALOG_LOADER;
}
}
@ -143,11 +142,6 @@ void AutoConnectUpdate::attach(AutoConnect& portal) {
_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
// of the UpdateClass.
AutoConnectElement* loader = _progress->getElement(String(F("loader")));
@ -172,6 +166,9 @@ void AutoConnectUpdate::attach(AutoConnect& portal) {
AC_DBG("AutoConnectUpdate attached\n");
if (WiFi.status() == WL_CONNECTED)
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
// requests update processing.
if (_status == UPDATE_START) {
_ws->loop(); // Crawl the connection request.
unsigned long tm = millis();
while (_ws->connectedClients() <= 0) {
if (millis() - tm > AUTOCONNECT_UPDATE_TIMEOUT) {
while (!_wsConnected) {
if (millis() - tm > 30 * 1000) {
AC_DBG("WebSocket client connection timeout, update ignored\n");
break;
}
_ws->loop(); // Crawl the connection request.
}
// Launch the update
if (_ws->connectedClients())
if (_wsConnected)
update();
else
_status = UPDATE_IDLE;
@ -276,7 +272,7 @@ AC_UPDATESTATUS_t AutoConnectUpdate::update(void) {
}
_WiFiClient.reset(nullptr);
// Request the client to close the WebSocket.
_ws->sendTXT(_wsClient, "#e", 2);
_ws->sendTXT(_wsClient, "#e");
}
else {
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")));
wsurl->value = "ws://" + WiFi.localIP().toString() + ':' + AUTOCONNECT_WEBSOCKETPORT;
AC_DBG("Cast WS %s\n", wsurl->value.c_str());
_wsConnected = false;
_status = UPDATE_START;
return String("");
}
@ -473,6 +470,8 @@ String AutoConnectUpdate::_onResult(AutoConnectAux& result, PageArgument& args)
if (_ws) {
_ws->close();
while (_wsConnected)
_ws->loop();
_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) {
AC_DBG("WS client:%d event(%d)\n", client, event);
if (event == WStype_CONNECTED)
if (event == WStype_CONNECTED) {
_wsConnected = true;
_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 */
uint8_t _wsClient; /**< WebSocket client id */
bool _wsConnected; /**< WebSocket connection status */
size_t _amount; /**< Received amound bytes */
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
// update process.
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, "binname", nullptr, 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, "c4", "</span></div></div>", 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, "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, "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, "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(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, "c7", "</script>", nullptr },
};

@ -43,12 +43,12 @@ namespace AutoConnectUtil {
AC_HAS_FUNC(end);
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();
}
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);
}
}

Loading…
Cancel
Save