From 811eee602fcd483d7b563eeb7b5a96c6d641ccb7 Mon Sep 17 00:00:00 2001 From: Jan Grewe <jan@faked.org> Date: Sun, 4 Jun 2023 20:38:45 +0200 Subject: [PATCH] gzip data --- .gitignore | 1 + data/jquery.simple.websocket.min.js | 1 - {data => data_src}/favicon.ico | Bin {data => data_src}/index.html | 43 +++++++++++++-------- {data => data_src}/main.js | 5 ++- {data => data_src}/styles.css | 0 gzip_data.py | 58 ++++++++++++++++++++++++++++ platformio.ini | 2 + 8 files changed, 91 insertions(+), 19 deletions(-) delete mode 100644 data/jquery.simple.websocket.min.js rename {data => data_src}/favicon.ico (100%) rename {data => data_src}/index.html (66%) rename {data => data_src}/main.js (97%) rename {data => data_src}/styles.css (100%) create mode 100644 gzip_data.py diff --git a/.gitignore b/.gitignore index 20ea4e0..dba6614 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ .vscode/launch.json .vscode/ipch /src/config.h +/data diff --git a/data/jquery.simple.websocket.min.js b/data/jquery.simple.websocket.min.js deleted file mode 100644 index 7dd5539..0000000 --- a/data/jquery.simple.websocket.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(a){"object"==typeof module&&"string"===module.exports?module.exports=a(jQuery):a(jQuery)}(function(a){var b=function(b){if(this._isEmpty(b,"url"))throw new Error('Missing argument, example usage: $.simpleWebSocket({ url: "ws://127.0.0.1:3000" }); ');this._opt=b,this._ws=null,this._reConnectTries=60,this._reConnectDeferred=null,this._closeDeferred=null,this._dataType=this._prop(this._opt,"dataType","json"),this._listeners=[],this._onOpen=this._prop(this._opt,"onOpen",null),this._onClose=this._prop(this._opt,"onClose",null),this._onError=this._prop(this._opt,"onError",null);var c=this;return this._api=function(){return{connect:function(){return a.extend(c._api,c._reConnect.apply(c,[]))},isConnected:function(a){return a?(a.apply(this,[c._isConnected.apply(c,[])]),c._api):c._isConnected.apply(c,[])},send:function(b){return a.extend(c._api,c._send.apply(c,[b]))},listen:function(b){return a.extend(c._api,c._listenReconnect.apply(c,[b]))},remove:function(a){return c._remove.apply(c,[a]),c._api},removeAll:function(){return c._removeAll.apply(c,[]),c._api},close:function(){return c._reset.apply(c,[]),a.extend(c._api,c._close.apply(c,[]))},getWsAdapter:function(){return this._ws}}}(),this._api};return b.prototype={_createWebSocket:function(a){var b=null;if(a.protocols)if(void 0===window.MozWebSocket){if(!window.WebSocket)throw new Error("Error, websocket could not be initialized.");b=new WebSocket(a.url,a.protocols)}else b=new MozWebSocket(a.url,a.protocols);else if(void 0===window.MozWebSocket){if(!window.WebSocket)throw new Error("Error, websocket could not be initialized.");b=new WebSocket(a.url)}else b=new MozWebSocket(a.url);return b},_bindSocketEvents:function(b,c){var d=this;a(b).bind("open",c.open).bind("close",c.close).bind("message",function(a){try{if("function"==typeof c.message)if(d._dataType&&"json"===d._dataType.toLowerCase()){var b=JSON.parse(a.originalEvent.data);c.message.call(this,b)}else if(d._dataType&&"xml"===d._dataType.toLowerCase()){var e=new DOMParser,f=e.parseFromString(a.originalEvent.data,"text/xml");c.message.call(this,f)}else c.message.call(this,a.originalEvent.data)}catch(a){"function"==typeof c.error&&c.error.call(this,a)}}).bind("error",function(a){"function"==typeof c.error&&c.error.call(this,a)})},_webSocket:function(a){var b=this._createWebSocket(a);return this._bindSocketEvents(b,a),b},_getSocketEventHandler:function(a){var b=this;return{open:function(c){b._onOpen&&b._onOpen.apply(b,[c]);var d=this;a&&a.resolve(d)},close:function(c){b._closeDeferred&&b._closeDeferred.resolve(),b._onClose&&b._onClose.apply(b,[c]),a&&a.rejectWith(c)},message:function(a){for(var c=0,d=b._listeners.length;c<d;c++)try{b._listeners[c].deferred.notify.apply(b,[a])}catch(a){}},error:function(c){b._ws=null,b._onError&&b._onError.apply(b,[c]);for(var d=0,e=b._listeners.length;d<e;d++)b._listeners[d].deferred.reject.apply(b,[c]);a&&a.rejectWith.apply(b,[c])}}},_connect:function(){var b=a.Deferred();if(this._ws)if(2===this._ws.readyState)this._ws.close();else if(3===this._ws.readyState)this._ws.close();else{if(0===this._ws.readyState)return b.promise();if(1===this._ws.readyState)return b.resolve(this._ws),b.promise()}return this._ws=this._webSocket(a.extend(this._opt,this._getSocketEventHandler(b))),b.promise()},_reset:function(){this._reConnectTries=this._prop(this._opt,"attempts",60),this._reConnectDeferred=a.Deferred()},_close:function(){return this._closeDeferred=a.Deferred(),this._ws&&(this._ws.close(),this._ws=null),this._closeDeferred.promise()},_isConnected:function(){return null!==this._ws&&1===this._ws.readyState},_reConnectTry:function(){var a=this;this._connect().done(function(){a._reConnectDeferred.resolve.apply(a,[a._ws])}).fail(function(b){a._reConnectTries--,a._reConnectTries>0?window.setTimeout(function(){a._reConnect.apply(a,[])},a._prop.apply(a,[a._opt,"timeout",1e4])):a._reConnectDeferred.rejectWith.apply(a,[b])})},_reConnect:function(){var a=this;return null===this._reConnectDeferred?this._reset():"resolved"===this._reConnectDeferred.state()?this._reset():"rejected"===this._reConnectDeferred.state()&&this._reset(),this._ws&&1===this._ws.readyState?this._reConnectDeferred.resolve(this._ws):this._reConnectTry(),a._reConnectDeferred.promise.apply(a,[])},_preparePayload:function(a){return this._opt.dataType&&"text"===this._opt.dataType.toLowerCase()?a:this._opt.dataType&&"xml"===this._opt.dataType.toLowerCase()?a:(this._opt.dataType&&this._opt.dataType.toLowerCase(),JSON.stringify(a))},_send:function(b){var c=this,d=a.Deferred();return function(a){c._reConnect.apply(c,[]).done(function(b){b.send(a),d.resolve.apply(c,[c._api])}).fail(function(a){d.rejectWith.apply(c,[a])})}(this._preparePayload(b)),d.promise()},_indexOfListener:function(a){for(var b=0,c=this._listeners.length;b<c;b++)if(this._listeners[b].listener===a)return b;return-1},_isEmpty:function(a,b){return"string"===a||(null===a||(void 0===b||(null===b||(""===b||(void 0===a[b]||null===a[b])))))},_prop:function(a,b,c){return this._isEmpty(a,b)?c:a[b]},_listen:function(b){var c=this,d=a.Deferred();return c._reConnect.apply(c,[]).done(function(){d.progress(function(){b.apply(this,arguments)}),c._remove.apply(c,[b]),c._listeners.push({deferred:d,listener:b})}).fail(function(a){d.reject(a)}),d.promise()},_listenReconnect:function(b){var c=a.Deferred(),d=this;return this._listen(b).fail(function(){c.notify(arguments),d._listenReconnect.apply(d,[b])}).done(function(){c.resolve()}),c.promise()},_remove:function(a){var b=this._indexOfListener(a);0<=b&&(this._listeners[b].deferred.resolve(),this._listeners.splice(b,1))},_removeAll:function(){for(var a=0,b=this._listeners.length;a<b;a++)this._listeners[a].deferred.resolve();this._listeners=[]}},a.extend({simpleWebSocket:function(a){return new b(a)}}),a.simpleWebSocket}); \ No newline at end of file diff --git a/data/favicon.ico b/data_src/favicon.ico similarity index 100% rename from data/favicon.ico rename to data_src/favicon.ico diff --git a/data/index.html b/data_src/index.html similarity index 66% rename from data/index.html rename to data_src/index.html index 1f75d39..9ce4494 100644 --- a/data/index.html +++ b/data_src/index.html @@ -5,7 +5,8 @@ <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Matrix of Life</title> - <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous"> + <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" + integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous"> <link href="styles.css" rel="stylesheet"> </head> @@ -22,14 +23,16 @@ </div> </h5> <div class="card-body text-center"> - + <div class="row mb-3 px-3"> <label for="rangeBrightness" class="col-form-label">Brightness</label> - <input type="range" class="form-range rangeConfig" id="rangeBrightness" data-name="brightness" min="1" max="100" steps="1"> + <input type="range" class="form-range rangeConfig" id="rangeBrightness" data-name="brightness" min="1" + max="100" steps="1" disabled> </div> <div class="row mb-3 px-3"> <label for="rangeSpeed" class="col-form-label">Speed</label> - <input type="range" class="form-range rangeConfig" id="rangeSpeed" data-name="interval" min="1" max="100" steps="10"> + <input type="range" class="form-range rangeConfig" id="rangeSpeed" data-name="interval" min="1" max="100" + steps="10" disabled> </div> </div> @@ -37,19 +40,21 @@ <div class="card-footer text-body-secondary py-3"> <div class="row"> <div class="col-6"> - <button type="button" class="btn btn-sm btn-primary btnAction" data-action="addGlider">Add Glider</button> + <button type="button" class="btn btn-sm btn-primary btnAction" data-action="addGlider" disabled>Add + Glider</button> </div> <div class="col-6 text-end"> - <button type="button" class="btn btn-sm btn-outline-secondary me-1" data-bs-toggle="collapse" data-bs-target="#debug">Debug</button> - <button type="button" class="btn btn-sm btn-danger btnAction " data-action="reboot">Reboot</button> + <button type="button" class="btn btn-sm btn-outline-secondary me-1" data-bs-toggle="collapse" + data-bs-target="#debug">Debug</button> + <button type="button" class="btn btn-sm btn-danger btnAction " data-action="reboot" + disabled>Reboot</button> </div> </div> - </div> - + </div> </div> - </div> + </div> <!-- main --> <div class="col-lg-4 offset-lg-4 mt-3 collapse" id="debug"> @@ -65,20 +70,26 @@ <span class="input-group-text">➡️</span> <input type="text" id="prompt" class="form-control form-control-sm fs-6 font-monospace"> </div> - + </div> - + </div> </div> - </div> + </div> <!-- debug --> </div> - <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" crossorigin="anonymous"></script> - <script src="https://code.jquery.com/jquery-3.7.0.min.js" integrity="sha256-2Pmvv0kuTBOenSvLm6bvfBSSHrUJ+3A7x6P5Ebd07/g=" crossorigin="anonymous"></script> - <script src="jquery.simple.websocket.min.js"></script> + <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" + integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" + crossorigin="anonymous"></script> + <script src="https://code.jquery.com/jquery-3.7.0.min.js" + integrity="sha256-2Pmvv0kuTBOenSvLm6bvfBSSHrUJ+3A7x6P5Ebd07/g=" crossorigin="anonymous"></script> + <script + src="https://cdn.jsdelivr.net/gh/jbloemendal/jquery-simple-websocket@master/dist/jquery.simple.websocket.min.js" + crossorigin="anonymous"></script> <script src="main.js"></script> + </body> </html> diff --git a/data/main.js b/data_src/main.js similarity index 97% rename from data/main.js rename to data_src/main.js index 6be0cf0..368dbc0 100644 --- a/data/main.js +++ b/data_src/main.js @@ -1,6 +1,5 @@ var wsUrl = 'ws://' + document.location.host + '/ws' -var ws = null; var config = { brightness: 0, interval: 0, @@ -75,6 +74,7 @@ function wsSend(msg) { }); } +var ws; function startSocket() { ws = $.simpleWebSocket({ url: wsUrl, @@ -93,6 +93,7 @@ function startSocket() { addMessage("❗️ error"); }, }); + ws.listen(function (data) { var json = JSON.stringify(data); var msg = "⬅️ " + json; @@ -111,6 +112,6 @@ function loadConfig(data) { $('#rangeSpeed').val(mapRange(data.interval, 1000, 10, 1, 100)); } -function mapRange (number, inMin, inMax, outMin, outMax) { +function mapRange(number, inMin, inMax, outMin, outMax) { return Math.round((number - inMin) * (outMax - outMin) / (inMax - inMin) + outMin); } diff --git a/data/styles.css b/data_src/styles.css similarity index 100% rename from data/styles.css rename to data_src/styles.css diff --git a/gzip_data.py b/gzip_data.py new file mode 100644 index 0000000..97ff223 --- /dev/null +++ b/gzip_data.py @@ -0,0 +1,58 @@ +Import('env', 'projenv') + +import os +import gzip +import shutil +import glob + +def prepare_www_files(source, target, env): + #WARNING - this script will DELETE your 'data' dir and recreate an empty one to copy/gzip files from 'data_src' + # so make sure to edit your files in 'data_src' folder as changes madt to files in 'data' woll be LOST + # + # If 'data_src' dir doesn't exist, and 'data' dir is found, the script will autimatically + # rename 'data' to 'data_src + + + #add filetypes (extensions only) to be gzipped before uploading. Everything else will be copied directly + filetypes_to_gzip = ['html', 'js', 'css', 'ico'] + + print('[COPY/GZIP DATA FILES]') + + data_dir = env.get('PROJECT_DATA_DIR') + data_src_dir = os.path.join(env.get('PROJECT_DIR'), 'data_src') + + if(os.path.exists(data_dir) and not os.path.exists(data_src_dir) ): + print(' "data" dir exists, "data_src" not found.') + print(' renaming "' + data_dir + '" to "' + data_src_dir + '"') + os.rename(data_dir, data_src_dir) + + if(os.path.exists(data_dir)): + print(' Deleting data dir ' + data_dir) + shutil.rmtree(data_dir) + + print(' Re-creating empty data dir ' + data_dir) + os.mkdir(data_dir) + + files_to_gzip = [] + for extension in filetypes_to_gzip: + files_to_gzip.extend(glob.glob(os.path.join(data_src_dir, '*.' + extension))) + + print(' files to gzip: ' + str(files_to_gzip)) + + all_files = glob.glob(os.path.join(data_src_dir, '*.*')) + files_to_copy = list(set(all_files) - set(files_to_gzip)) + + print(' files to copy: ' + str(files_to_copy)) + + for file in files_to_copy: + print(' Copying file: ' + file + ' to data dir') + shutil.copy(file, data_dir) + + for file in files_to_gzip: + print(' GZipping file: ' + file + ' to data dir') + with open(file, 'rb') as src, gzip.open(os.path.join(data_dir, os.path.basename(file) + '.gz'), 'wb') as dst: + dst.writelines(src) + + print('[/COPY/GZIP DATA FILES]') + +env.AddPreAction('$BUILD_DIR/littlefs.bin', prepare_www_files) diff --git a/platformio.ini b/platformio.ini index e97b462..628b5ea 100644 --- a/platformio.ini +++ b/platformio.ini @@ -17,6 +17,8 @@ monitor_port = COM8 monitor_speed = 115200 monitor_filters = esp32_exception_decoder board_build.filesystem = littlefs +extra_scripts = + post:gzip_data.py platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#2.0.9 board_build.arduino.upstream_packages = no lib_deps = -- GitLab