4f8bf7cc9a58da7999e600a53f05cd4fbf3badd2
[project/luci.git] / applications / luci-app-attendedsysupgrade / luasrc / view / attendedsysupgrade.htm
1 <%+header%>
2 <h2 name="content"><%:Attended Sysupgrade%></h2>
3 <div  class="container">
4         <div style="display: none" id="update_info" class="alert-message info">
5         </div>
6         <div style="display: none" id="update_error" class="alert-message danger">
7         </div>
8 </div>
9 <input class="cbi-button" value="search for updates" onclick="update_request()" type="button" id="update_button">
10
11 <script type="text/javascript">
12
13 latest_release = "";
14 data = {};
15 ubus_counter = 1
16 origin = document.location.href.replace(location.pathname, "")
17 ubus_url = origin + "/ubus/"
18
19 // requests to the update server
20 function server_request(request_dict, path, callback) {
21         url = data.update_server + "/" + path
22         request_dict.distro = data.release.distribution;
23         request_dict.target = data.release.target.split("\/")[0];
24         request_dict.subtarget = data.release.target.split("\/")[1];
25         request_dict.packages = data.packagelist;
26         var xmlhttp = new XMLHttpRequest();
27         xmlhttp.open("POST", url, true);
28         xmlhttp.setRequestHeader("Content-type", "application/json");
29         xmlhttp.send(JSON.stringify(request_dict));
30         xmlhttp.onerror = function(e) {
31                 update_error("update server down")
32         }
33         xmlhttp.addEventListener('load', function(event) {
34                 callback(xmlhttp)
35         });
36 }
37
38 // requests ubus via rpcd
39 function ubus_request(command, argument, params, callback) {
40         // perform login if ubus_rpc_session is empty
41         var request_data = '{ "jsonrpc": "2.0", "id": ' + ubus_counter + ', "method": "call", "params": [ "'+ data["ubus_rpc_session"] +'", "' + command + '", "' + argument + '", ' + params + ' ] }'
42         ubus_counter++
43         var xmlhttp = new XMLHttpRequest();
44         xmlhttp.open("POST", ubus_url, true);
45         xmlhttp.setRequestHeader("Content-type", "application/json");
46         xmlhttp.onerror = function(e) {
47                 setTimeout(back_online, 5000)
48         }
49         xmlhttp.addEventListener('load', function(event) {
50                 if(command === "uci") {
51                         ubus_request_callback_uci(xmlhttp, callback)
52                 } else {
53                         ubus_request_callback(xmlhttp, callback)
54                 }
55         });
56         xmlhttp.send(request_data);
57 }
58
59 // handle ubus_requests, set variables or perform functions
60 function ubus_request_callback(response_object, callback) {
61         if(response_object.status === 200) {
62                 console.log(callback)
63                 if(typeof callback === "string") {
64                         response_json = JSON.parse(response_object.responseText).result[1]
65                         data[callback] = response_json[callback]
66                 } else {
67                         callback(response_object)
68                 }
69         } else {
70                 console.log(respons_object.responseText)
71         }
72 }
73
74 function ubus_request_callback_uci(response_object, callback) {
75         if(response_object.status === 200) {
76                 console.log(callback)
77                 response_json = JSON.parse(response_object.responseText).result[1].value
78                 data[callback] = response_json
79         } else {
80                 console.log(respons_object.responseText)
81         }
82 }
83
84 // initial setup, get system information
85 function setup() {
86         data["ubus_rpc_session"] = "<%=luci.dispatcher.context.authsession%>"
87         ubus_request("packagelist", "list", '{  }', "packagelist")
88         ubus_request("system", "board", '{  }', "release")
89         ubus_request("system", "board", '{  }', "board_name")
90         ubus_request("uci", "get", '{"config": "attendedsysupgrade", "section": "@settings[0]", "option": "update_server"}', "update_server")
91 }
92
93 // shows notification if update is available
94 function update_info(info_output) {
95         document.getElementById("update_info").style.display = "block";
96         document.getElementById("update_info").innerHTML = info_output;
97 }
98
99 function update_error(error_output) {
100         document.getElementById("update_error").style.display = "block";
101         document.getElementById("update_error").innerHTML = error_output;
102         document.getElementById("update_info").style.display = "None";
103 }
104
105 // asks server for news updates, actually only based on relesae not packages
106 function update_request() {
107         console.log("update_request")
108         request_dict = {}
109         request_dict.version = data.release.version;
110         server_request(request_dict, "update-request", update_request_callback)
111 }
112
113 function update_request_callback(response_object) {
114         if (response_object.status === 500) {
115                 // python crashed
116                 update_error("internal server error, please try again later")
117                 console.log("update server issue")
118         } else if (response_object.status === 502) {
119                 // python part offline
120                 update_error("internal server error, please try again later")
121                 console.log("update server issue")
122         } else if (response_object.status === 503) {
123                 // handle overload
124                 update_error("server overloaded, retry in 5 minutes")
125                 console.log("server overloaded")
126                 setTimeout(update_request, 300000)
127         } else if (response_object.status === 201) {
128                 update_info("imagebuilder not ready, please wait")
129                 console.log("setting up imagebuilder")
130                 setTimeout(update_request, 5000)
131         } else if (response_object.status === 204) {
132                 // no updates
133                 update_info("no updates available")
134         } else if (response_object.status === 400) {
135                 // bad request
136                 console.log(response_object.responseText)
137                 response_object_content = JSON.parse(response_object.responseText)
138                 update_error(response_object_content)
139         } else if (response_object.status === 200) {
140                 // new release/updates
141                 response_object_content = JSON.parse(response_object.responseText)
142                 update_request_200(response_object_content)
143         }
144 }
145
146 function back_online() {
147         ubus_request("session", "login", '{  }', back_online_callback)
148 }
149
150 function back_online_callback(response_object) {
151         if (response_object.status != 200) {
152                 setTimeout(back_online, 5000)
153         } else {
154                 update_info("upgrade successfull!")
155                 document.getElementById("update_button").value = "reload page";
156                 document.getElementById("update_button").onclick = function() { location.reload(); }
157         }
158
159 }
160
161 function update_request_200(response_content) {
162         info_output = ""
163         if(response_content.version != undefined) {
164                 info_output += "new update available. from " + data.release.version + " to " + response_content.version
165                 latest_version = response_content.version;
166         }
167         if(response_content.packages != undefined) {
168                 info_output += "package updates available"
169         }
170         update_info(info_output)
171         document.getElementById("update_button").value = "request image";
172         document.getElementById("update_button").onclick = image_request;
173 }
174
175 // request the image, need merge with update_request
176 function image_request() {
177         console.log("image_request")
178         request_dict = {}
179         request_dict.version = latest_version;
180         request_dict.board = data.board_name
181         server_request(request_dict, "image-request", image_request_handler)
182 }
183
184 function image_request_handler(response) {
185         if (response.status === 400) {
186                 response_content = JSON.parse(response.responseText)
187                 update_error(response_content.error)
188         } else if (response.status === 500) {
189                 image_request_500()
190         } else if (response.status === 503) {
191                 update_error("please wait. server overloaded")
192                 // handle overload
193                 setTimeout(image_request, 30000)
194         } else if (response.status === 201) {
195                 response_content = JSON.parse(response.responseText)
196                 if(response_content.queue != undefined) {
197                         // in queue
198                         update_info("please wait. you are in queue position " + response_content.queue)
199                         console.log("queued")
200                 } else {
201                         update_info("imagebuilder not ready, please wait")
202                         console.log("setting up imagebuilder")
203                 }
204                 setTimeout(image_request, 5000)
205         } else if (response.status === 206) {
206                 // building
207                 console.log("building")
208                 update_info("building image")
209                 setTimeout(image_request, 5000)
210         } else if (response.status === 200) {
211                 // ready to download
212                 response_content = JSON.parse(response.responseText)
213                 update_info("image created")
214                 document.getElementById("update_button").value = "download and flash"
215                 document.getElementById("update_button").onclick = function() {download_image(response_content.url); }
216         }
217 }
218
219
220 // uploads received blob data to the server using cgi-io
221 function upload_image(blob) {
222         var upload_request = new XMLHttpRequest();
223         var form_data  = new FormData();
224
225         form_data.append("sessionid", data.ubus_rpc_session)
226         form_data.append("filename", "/tmp/sysupgrade.bin")
227         form_data.append("filemode", 755) // insecure?
228         form_data.append("filedata", blob)
229
230         upload_request.addEventListener('load', function(event) {
231                 // this checksum should be parsed
232                 document.getElementById("update_info").innerHTML = "flashing... please wait" // show fancy indicator http://www.ajaxload.info/
233                 ubus_request("attendedsysupgrade", "sysupgrade", '{  }', 'done');
234         });
235
236         upload_request.addEventListener('error', function(event) {
237                 document.getElementById("update_info").innerHTML = "uploading failed, please retry"
238         });
239
240         upload_request.open('POST', origin + '/cgi-bin/cgi-upload');
241         upload_request.send(form_data);
242 }
243
244 // download image from server once the url was received by image_request
245 function download_image(url) {
246         console.log("download_image")
247         document.getElementById("update_button").value = "flashing..."
248         document.getElementById("update_button").disabled = true;
249         var download_request = new XMLHttpRequest();
250         download_request.open("GET", url);
251         download_request.responseType = "arraybuffer";
252
253         download_request.onload = function () {
254                 if (this.status === 200) {
255                         var blob = new Blob([download_request.response], {type: "application/octet-stream"});
256                         upload_image(blob)
257                 }
258         };
259         document.getElementById("update_info").innerHTML = "downloading image"
260         download_request.send();
261 }
262
263 document.onload = setup()
264 </script>
265
266 <%+footer%>