| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8" /> |
| <title>WPE</title> |
| <style> |
| |
| @keyframes fade { |
| 0% { opacity: 0; } |
| 30% { opacity: 0; } |
| 90% { opacity: 1; } |
| 100% { opacity: 0; } |
| } |
| |
| html, body { |
| background-color: #111; |
| color: #fff; |
| font-family: "Bitstream Vera Sans Mono"; |
| margin: 0; |
| } |
| |
| div#logo { |
| position: relative; |
| margin: 15% 41.5%; |
| width: 12%; |
| } |
| |
| div#logo:after { |
| content: ""; |
| display: block; |
| padding-bottom: 100%; |
| } |
| |
| div#logo div { |
| width: 45%; |
| height: 45%; |
| } |
| div#logo.animate div { |
| opacity: 0; |
| animation: fade 3s linear infinite; |
| } |
| div#logo div:nth-of-type(1) { |
| position: absolute; |
| top: 2.5%; |
| left: 2.5%; |
| background-color: #3399ff; |
| } |
| div#logo div:nth-of-type(2) { |
| position: absolute; |
| top: 2.5%; |
| right: 2.5%; |
| animation-delay: -0.15s; |
| background-color: #336699; |
| |
| } |
| div#logo div:nth-of-type(3) { |
| position: absolute; |
| bottom: 2.5%; |
| right: -47.5%; |
| animation-delay: -0.5s; |
| background-color: #66cc33; |
| } |
| div#logo div:nth-of-type(4) { |
| position: absolute; |
| bottom: 2.5%; |
| left: 2.5%; |
| animation-delay: -0.65s; |
| background-color: #003366; |
| } |
| |
| div#logo div:nth-of-type(5) { |
| position: absolute; |
| bottom: -47.5%; |
| right: -47.5%; |
| animation-delay: -0.25s; |
| background-color: #006600; |
| } |
| |
| div#logo div:nth-of-type(6) { |
| position: absolute; |
| bottom: -47.5%; |
| right: 2.5%; |
| animation-delay: -0.35s; |
| background-color: #003300; |
| } |
| |
| div#status { |
| display: block; |
| position: absolute; |
| left: 0; |
| bottom: 23%; |
| right: 0; |
| margin: auto; |
| width: 100%; |
| font-size: 280%; |
| text-align: center; |
| } |
| |
| div#interfaces { |
| display: block; |
| position: absolute; |
| left: 0; |
| bottom: 10%; |
| right: 0; |
| margin: auto; |
| width: 100%; |
| font-size: 200%; |
| text-align: center; |
| } |
| </style> |
| </head> |
| <body> |
| <div id="logo" class="animate"><div></div><div></div><div></div><div></div><div></div><div></div></div> |
| <div id="status">Hello</div> |
| <div id="interfaces"></div> |
| <script type="text/javascript"> |
| (function (host, lan, wlan) { |
| var logoEl = document.getElementById('logo'), |
| statusEl = document.getElementById('status'), |
| interfacesEl = document.getElementById('interfaces'); |
| function delay(t, v) { |
| return new Promise((resolve) => { |
| setTimeout(resolve.bind(null, v), t) |
| }); |
| } |
| function log(interfaces) { |
| return new Promise((resolve, reject) => { |
| var ip = ''; |
| for (var i = 0; i < interfaces.length; i++) |
| ip += `${interfaces[i].name}: ${interfaces[i].ip}<br/>`; |
| if (ip !== '') interfacesEl.innerHTML = ip; |
| resolve(interfaces); |
| }); |
| } |
| function wpe(arr) { |
| return new Promise((resolve, reject) => { |
| var http = new XMLHttpRequest(); |
| http.onreadystatechange = (event) => { |
| var req = event.target; |
| if (req.readyState == 4) { |
| if (req.status == 200) { |
| try { |
| resolve(arr[0] === 'GET' ? JSON.parse(req.responseText) : undefined); |
| } catch(err) { |
| reject(err); |
| } |
| } else { |
| reject('XHR failed'); |
| } |
| |
| } |
| }; |
| http.open(arr[0] || 'GET', `http://${host}/Service${arr[1]}`, true); |
| http.send(arr[2]); |
| }); |
| } |
| function interfaces() { |
| return new Promise((resolve, reject) => { |
| wpe(['GET', '/DeviceInfo']) |
| .then((deviceInfo) => { |
| var result = []; |
| if (!deviceInfo.addresses) return resolve(result); |
| for (var i = 0; i < deviceInfo.addresses.length; i++) { |
| if (Array.isArray(deviceInfo.addresses[i].ip) && deviceInfo.addresses[i].ip[0] !== '127.0.0.1') |
| result.push({name: deviceInfo.addresses[i].name, ip: deviceInfo.addresses[i].ip}); |
| } |
| resolve(result); |
| }); |
| }); |
| } |
| return new Promise((resolve, reject) => { |
| var joining = false; |
| var socket = new WebSocket(`ws://${host}/Service/Controller`, 'notification'); |
| socket.onmessage = (msg) => { |
| var data; |
| try { |
| data = msg && msg.data && JSON.parse(msg.data.replace(/\\x00/g, '')); |
| } catch(err) { |
| // Silently fail |
| console.error(msg.data, err); |
| return; |
| } |
| console.log(data); |
| if (data.callsign === 'WifiControl' && data.state === 'activated' && !joining) { |
| statusEl.innerHTML = 'Scanning WiFi'; |
| delay(1000).then(wpe.bind(null, ['PUT', '/WifiControl/Scan'])); |
| } |
| if (data.callsign === 'WifiControl' && data.data && data.data.networks && !joining) { |
| joining = true; |
| var networks = {}; |
| for (var i = 0; i < data.data.networks.length; i++) { |
| var network = data.data.networks[i]; |
| if (network.ssid && !networks[network.ssid]) |
| networks[network.ssid] = network; |
| } |
| console.log(networks); |
| } |
| if (data.callsign === 'NetworkControl' && data.data && data.data.interface) { |
| if (data.data.ip) { |
| if (data.data.interface === wlan) { |
| joining = false; |
| } |
| interfaces().then(log); |
| } else if (data.data.status === 11) { |
| // Ignore wlan DHCP failure when not in joining progress |
| if (data.data.interface === wlan && !joining) return; |
| delay(2000) |
| .then(wpe.bind(null, ['PUT', `/NetworkControl/${data.data.interface}/Request`])) |
| .catch(reject); |
| } |
| } |
| if (data.events && data.events.Decryption) { |
| logoEl.className = ''; |
| statusEl.innerHTML = 'We're ready!'; |
| } |
| }; |
| socket.onopen = () => { |
| interfaces().then(log); |
| }; |
| socket.onerror = (err) => { |
| reject(err); |
| }; |
| socket.onclose = () => { |
| reject('Connection lost'); |
| }; |
| }); |
| }('localhost', 'eth0', 'wlan0')).catch(console.error); |
| </script> |
| </body> |
| </html> |