app.js (7483B)
1 /* 2 * Copyright (c) 2016, Natacha Porté 3 * 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 var cfg_endpoint = null; 18 var cfg_data_field = null; 19 var cfg_sign_algo = ""; 20 var cfg_sign_field = ""; 21 var cfg_sign_field_format = ""; 22 var cfg_sign_key = ""; 23 var cfg_sign_key_format = ""; 24 var cfg_extra_fields = []; 25 var cfg_wakeup_time = -1; 26 27 var to_send = []; 28 var senders = [new XMLHttpRequest(), new XMLHttpRequest()]; 29 var i_sender = 1; 30 var jsSHA = require("sha"); 31 32 function sendPayload(payload) { 33 var data = new FormData(); 34 data.append(cfg_data_field, payload); 35 36 if (cfg_sign_field) { 37 var sha = new jsSHA(cfg_sign_algo, "TEXT"); 38 sha.setHMACKey(cfg_sign_key, cfg_sign_key_format); 39 sha.update(payload); 40 data.append(cfg_sign_field, sha.getHMAC(cfg_sign_field_format)); 41 } 42 43 if (cfg_extra_fields.length > 0) { 44 for (var i = 0; i < cfg_extra_fields.length; i += 1) { 45 var decoded = decodeURIComponent(cfg_extra_fields[i]).split("="); 46 var name = decoded.shift(); 47 var value = decoded.join("="); 48 data.append(name, value); 49 } 50 } 51 52 i_sender = 1 - i_sender; 53 senders[i_sender].open("POST", cfg_endpoint, true); 54 senders[i_sender].send(data); 55 } 56 57 function sendHead() { 58 if (to_send.length < 1) return; 59 sendPayload(to_send[0].split(";")[1]); 60 } 61 62 function enqueue(key, line) { 63 to_send.push(key + ";" + line); 64 localStorage.setItem("toSend", to_send.join("|")); 65 localStorage.setItem("lastSent", key); 66 if (to_send.length === 1) { 67 sendHead(); 68 } 69 } 70 71 function uploadDone() { 72 var sent_key = to_send.shift().split(";")[0]; 73 localStorage.setItem("toSend", to_send.join("|")); 74 if (to_send.length === 0) { 75 Pebble.sendAppMessage({ "lastPosted": parseInt(sent_key, 10) }); 76 } 77 sendHead(); 78 } 79 80 function uploadError() { console.log(this.statusText); } 81 82 senders[0].addEventListener("load", uploadDone); 83 senders[0].addEventListener("error", uploadError); 84 senders[1].addEventListener("load", uploadDone); 85 senders[1].addEventListener("error", uploadError); 86 87 Pebble.addEventListener("ready", function(e) { 88 console.log("Battery- JS ready"); 89 90 var str_to_send = localStorage.getItem("toSend"); 91 to_send = str_to_send ? str_to_send.split("|") : []; 92 93 var str_extra_fields = localStorage.getItem("extraFields"); 94 cfg_extra_fields = str_extra_fields ? str_extra_fields.split(",") : []; 95 96 cfg_endpoint = localStorage.getItem("cfgEndpoint"); 97 cfg_data_field = localStorage.getItem("cfgDataField"); 98 cfg_sign_algo = localStorage.getItem("cfgSignAlgorithm"); 99 cfg_sign_field = localStorage.getItem("cfgSignFieldName"); 100 cfg_sign_field_format = localStorage.getItem("cfgSignFieldFormat"); 101 cfg_sign_key = localStorage.getItem("cfgSignKey"); 102 cfg_sign_key_format = localStorage.getItem("cfgSignKeyFormat"); 103 cfg_wakeup_time = parseInt(localStorage.getItem("cfgWakeupTime") || "-1", 10); 104 105 if (cfg_endpoint && cfg_data_field) { 106 Pebble.sendAppMessage({ "lastSent": 107 parseInt(localStorage.getItem("lastSent") || "0", 10) }); 108 } 109 110 if (to_send.length >= 1) { 111 sendHead(); 112 } 113 }); 114 115 Pebble.addEventListener("appmessage", function(e) { 116 if (e.payload.dataKey && e.payload.dataLine) { 117 enqueue(e.payload.dataKey, e.payload.dataLine); 118 } 119 }); 120 121 Pebble.addEventListener("showConfiguration", function() { 122 var settings = "?v=1.0"; 123 124 if (cfg_endpoint) { 125 settings += "&url=" + encodeURIComponent(cfg_endpoint); 126 } 127 128 if (cfg_data_field) { 129 settings += "&data_field=" + encodeURIComponent(cfg_data_field); 130 } 131 132 if (cfg_sign_field) { 133 settings += "&s_algo=" + encodeURIComponent(cfg_sign_algo) 134 + "&s_field=" + encodeURIComponent(cfg_sign_field) 135 + "&s_fieldf=" + encodeURIComponent(cfg_sign_field_format) 136 + "&s_key=" + encodeURIComponent(cfg_sign_key) 137 + "&s_keyf=" + encodeURIComponent(cfg_sign_key_format); 138 } 139 140 if (cfg_wakeup_time >= 0) { 141 settings += "&wakeup=" + cfg_wakeup_time.toString(10); 142 } 143 144 if (cfg_extra_fields.length > 0) { 145 settings += "&extra=" + cfg_extra_fields.join(","); 146 } 147 148 Pebble.openURL("https://cdn.rawgit.com/faelys/battery-minus/v1.0/config.html" + settings); 149 }); 150 151 Pebble.addEventListener("webviewclosed", function(e) { 152 var configData = JSON.parse(e.response); 153 var wasConfigured = (cfg_endpoint && cfg_data_field); 154 155 if (configData.url) { 156 cfg_endpoint = decodeURIComponent(configData.url); 157 localStorage.setItem("cfgEndpoint", cfg_endpoint); 158 } 159 160 if (configData.dataField) { 161 cfg_data_field = configData.dataField; 162 localStorage.setItem("cfgDataField", cfg_data_field); 163 } 164 165 if (configData.signAlgorithm) { 166 cfg_sign_algo = configData.signAlgorithm; 167 localStorage.setItem("cfgSignAlgorithm", cfg_sign_algo); 168 } 169 170 if (configData.signFieldName) { 171 cfg_sign_field = configData.signFieldName; 172 localStorage.setItem("cfgSignFieldName", cfg_sign_field); 173 } 174 175 if (configData.signFieldFormat) { 176 cfg_sign_field_format = configData.signFieldFormat; 177 localStorage.setItem("cfgSignFieldFormat", cfg_sign_field_format); 178 } 179 180 if (configData.signKey) { 181 cfg_sign_key = decodeURIComponent(configData.signKey); 182 localStorage.setItem("cfgSignKey", cfg_sign_key); 183 } 184 185 if (configData.signKeyFormat) { 186 cfg_sign_key_format = configData.signKeyFormat; 187 localStorage.setItem("cfgSignKeyFormat", cfg_sign_key_format); 188 } 189 190 if (configData.wakeupTime !== null) { 191 console.log("Received wakeupTime \"" + configData.wakeupTime + "\""); 192 var wakeupComponents = configData.wakeupTime.split(":"); 193 if (wakeupComponents.length === 2) { 194 var wakeupH = parseInt(wakeupComponents[0], 10); 195 var wakeupM = parseInt(wakeupComponents[1], 10); 196 if (wakeupH >= 0 && wakeupH < 24 && wakeupM >= 0 && wakeupM < 60) { 197 cfg_wakeup_time = wakeupH * 60 + wakeupM; 198 localStorage.setItem("cfgWakeupTime", cfg_wakeup_time); 199 Pebble.sendAppMessage({ "cfgWakeupTime": cfg_wakeup_time }); 200 } 201 else 202 console.log("Invalid wakeupTime \"" + configData.wakeupTime + "\""); 203 } 204 else 205 console.log("Invalid wakeupTime \"" + configData.wakeupTime + "\""); 206 } 207 208 if (configData.extraFields !== null) { 209 cfg_extra_fields = configData.extraFields 210 ? configData.extraFields.split(",") : []; 211 localStorage.setItem("extraFields", cfg_extra_fields.join(",")); 212 } 213 214 if (configData.resend) { 215 senders[0].abort(); 216 senders[1].abort(); 217 localStorage.setItem("toSend", ""); 218 localStorage.setItem("lastSent", "0"); 219 to_send = []; 220 wasConfigured = false; 221 } 222 223 if (!wasConfigured && cfg_endpoint && cfg_data_field) { 224 Pebble.sendAppMessage({ "lastSent": 0 }); 225 } 226 });