|
| 1 | +<!DOCTYPE html> |
| 2 | +<html lang="en"> |
| 3 | +<head> |
| 4 | + <meta charset="utf-8" /> |
| 5 | + <link rel="icon" href=favicon.ico" /> |
| 6 | + <meta name="viewport" content="width=device-width, initial-scale=1" /> |
| 7 | + <meta name="theme-color" content="#000000" /> |
| 8 | + <meta name="google" content="notranslate" /> |
| 9 | + <meta |
| 10 | + name="description" |
| 11 | + content="OS2Display client online check" |
| 12 | + /> |
| 13 | + <title>OS2Display online check</title> |
| 14 | + |
| 15 | + <style> |
| 16 | + html { |
| 17 | + cursor: none; |
| 18 | + } |
| 19 | + |
| 20 | + body { |
| 21 | + background-color: #333333; |
| 22 | + margin-top: 10%; |
| 23 | + text-align: center; |
| 24 | + font-family: Arial,Helvetica,sans-serif; |
| 25 | + color: #fff; |
| 26 | + font-size: 20px; |
| 27 | + } |
| 28 | + |
| 29 | + #logo { |
| 30 | + position: absolute; |
| 31 | + bottom: 10px; |
| 32 | + right: 10px; |
| 33 | + } |
| 34 | + |
| 35 | + #status { |
| 36 | + margin-top: 0; |
| 37 | + font-size: 3em; |
| 38 | + font-weight: bold; |
| 39 | + } |
| 40 | + </style> |
| 41 | + |
| 42 | + <script> |
| 43 | + /* |
| 44 | + * *************** Online / Offline Detection *************** |
| 45 | + * |
| 46 | + * This page can be used as a startup page for screen clients. |
| 47 | + * |
| 48 | + * It aims to solve the problem with screens not starting properly |
| 49 | + * if the browser loads the "client" application from cache before |
| 50 | + * the network is ready. |
| 51 | + * |
| 52 | + * On load it will attempt to load 1 pixel image form the server. If this |
| 53 | + * fails it will wait and try again at a given interval. The first |
| 54 | + * interval is set at random, the following are set at 30 seconds. |
| 55 | + * This is done to spread the load from the clients. |
| 56 | + * |
| 57 | + * A countdown clock is shown as a minimalist UI to aid in debugging |
| 58 | + * client behavior. |
| 59 | + * |
| 60 | + * When the call succeeds the client is deemed to be online and is |
| 61 | + * redirected to proper client application. |
| 62 | + * |
| 63 | + * By design all scripts, styles and assets are inlined in the html |
| 64 | + * to ensure the script works even if loaded from cache with no network |
| 65 | + * access. |
| 66 | + * |
| 67 | + * Note: |
| 68 | + * "navigator.onLine" is not used because it can give false positives |
| 69 | + * @see https://developer.mozilla.org/en-US/docs/Web/API/Navigator/onLine |
| 70 | + */ |
| 71 | + |
| 72 | + const checkOnlineStatus = async () => { |
| 73 | + try { |
| 74 | + const online = await fetch("1pixel.png?no_cache=" + Date.now()); |
| 75 | + return online.status >= 200 && online.status < 300; // either true or false |
| 76 | + } catch (err) { |
| 77 | + return false; // definitely offline |
| 78 | + } |
| 79 | + }; |
| 80 | + |
| 81 | + function getRandomInt(max) { |
| 82 | + return Math.floor(Math.random() * max); |
| 83 | + } |
| 84 | + |
| 85 | + function redirectToClient() { |
| 86 | + const helpDisplay = document.getElementById("help"); |
| 87 | + helpDisplay.textContent = "Redirecting to client..."; |
| 88 | + |
| 89 | + setTimeout(async () => { |
| 90 | + window.location.assign("../"); |
| 91 | + }, 3000 |
| 92 | + ) |
| 93 | + } |
| 94 | + |
| 95 | + const interval = 30; |
| 96 | + |
| 97 | + let clock = getRandomInt(interval); |
| 98 | + (function pollOnlineStatus() { |
| 99 | + setTimeout(async () => { |
| 100 | + clock--; |
| 101 | + |
| 102 | + if (0 === clock) { |
| 103 | + clock = interval; |
| 104 | + const result = await checkOnlineStatus(); |
| 105 | + const statusDisplay = document.getElementById("status"); |
| 106 | + statusDisplay.textContent = result ? "Online" : "Offline"; |
| 107 | + |
| 108 | + if (result) { |
| 109 | + redirectToClient(); |
| 110 | + } |
| 111 | + } |
| 112 | + |
| 113 | + const statusDisplay = document.getElementById("clock"); |
| 114 | + statusDisplay.textContent = clock.toString(); |
| 115 | + |
| 116 | + pollOnlineStatus(); |
| 117 | + }, 1000); |
| 118 | + })() |
| 119 | + |
| 120 | + window.addEventListener("load", async (event) => { |
| 121 | + const result = await checkOnlineStatus(); |
| 122 | + if (result) { |
| 123 | + redirectToClient(); |
| 124 | + } |
| 125 | + |
| 126 | + const statusDisplay = document.getElementById("status"); |
| 127 | + statusDisplay.textContent = result ? "Online" : "Offline"; |
| 128 | + |
| 129 | + const statusClock = document.getElementById("clock"); |
| 130 | + statusClock.textContent = clock.toString(); |
| 131 | + }); |
| 132 | + </script> |
| 133 | +</head> |
| 134 | +<body> |
| 135 | +<noscript>You need to enable JavaScript to run this app.</noscript> |
| 136 | + |
| 137 | +<svg id="logo" version="1.0" xmlns="http://www.w3.org/2000/svg" |
| 138 | + width="108pt" height="30.4pt" viewBox="0 0 1200 334"> |
| 139 | + <g transform="translate(0,334) scale(0.1,-0.1)" |
| 140 | + fill="#fff" stroke="none"> |
| 141 | + <path d="M5829 3317 c-25 -7 -65 -25 -90 -39 -49 -29 -140 -117 -170 -165 |
| 142 | +l-19 -30 94 -57 c52 -31 98 -56 103 -56 4 1 23 21 40 45 93 125 260 129 292 7 |
| 143 | +25 -94 -16 -156 -296 -442 l-213 -218 0 -96 0 -96 400 0 400 0 0 115 0 115 |
| 144 | +-219 2 -219 3 152 162 c211 223 247 284 249 418 2 140 -65 246 -198 310 -52 |
| 145 | +26 -72 30 -160 32 -59 2 -119 -3 -146 -10z"/> |
| 146 | + <path d="M1240 2745 l0 -575 210 0 210 0 0 575 0 575 -210 0 -210 0 0 -575z"/> |
| 147 | + <path d="M3970 3130 c-452 -36 -761 -248 -846 -580 -23 -86 -22 -262 0 -354 |
| 148 | +56 -235 221 -394 527 -511 52 -20 198 -67 324 -105 127 -38 264 -83 305 -101 |
| 149 | +202 -86 291 -189 292 -337 1 -161 -109 -275 -309 -317 -90 -19 -290 -19 -392 |
| 150 | +0 -214 41 -471 164 -646 309 -27 23 -57 47 -67 54 -14 12 -26 -8 -113 -185 |
| 151 | +l-96 -198 48 -43 c123 -111 354 -239 541 -301 377 -125 827 -109 1125 40 214 |
| 152 | +107 354 276 408 490 18 70 21 103 17 209 -8 189 -55 311 -166 432 -135 146 |
| 153 | +-279 217 -712 352 -368 116 -494 186 -555 311 -35 71 -38 171 -7 230 93 180 |
| 154 | +403 228 775 120 104 -30 277 -102 357 -149 35 -20 66 -38 71 -39 5 -1 52 88 |
| 155 | +105 198 l95 199 -23 17 c-39 30 -169 96 -263 134 -101 40 -221 75 -340 99 -75 |
| 156 | +15 -296 37 -340 34 -11 0 -63 -4 -115 -8z"/> |
| 157 | + <path d="M731 2954 c-371 -207 -603 -514 -693 -915 -30 -138 -33 -417 -5 -549 |
| 158 | +58 -277 179 -503 372 -695 207 -207 455 -336 760 -397 159 -32 434 -32 590 0 |
| 159 | +301 60 540 186 746 391 199 200 314 414 376 702 28 131 25 410 -6 549 -24 109 |
| 160 | +-69 237 -116 331 -118 233 -354 468 -597 594 -37 19 -60 26 -66 20 -12 -13 |
| 161 | +-172 -359 -172 -372 0 -5 34 -31 76 -58 195 -123 348 -338 406 -571 32 -128 |
| 162 | +31 -344 -1 -464 -65 -243 -206 -443 -405 -575 -396 -262 -916 -204 -1243 139 |
| 163 | +-124 129 -197 254 -245 422 -20 69 -23 100 -22 249 0 156 2 178 28 260 71 235 |
| 164 | +217 428 417 551 32 20 59 42 59 48 -1 26 -169 371 -181 374 -8 1 -43 -14 -78 |
| 165 | +-34z"/> |
| 166 | + <path d="M6903 1765 c-40 -17 -73 -69 -73 -113 0 -99 95 -161 180 -117 43 22 |
| 167 | +60 53 60 111 0 60 -24 99 -76 120 -41 17 -50 17 -91 -1z"/> |
| 168 | + <path d="M6310 1469 l0 -281 -46 51 c-154 171 -466 170 -638 -2 -96 -96 -140 |
| 169 | +-213 -140 -372 0 -301 190 -506 469 -505 132 1 222 35 303 117 l52 54 0 -81 0 |
| 170 | +-80 105 0 105 0 0 690 0 690 -105 0 -105 0 0 -281z m-177 -311 c60 -26 120 |
| 171 | +-93 148 -167 30 -80 24 -214 -13 -286 -55 -106 -144 -159 -268 -159 -124 0 |
| 172 | +-213 53 -268 159 -33 65 -42 186 -18 267 51 177 241 262 419 186z"/> |
| 173 | + <path d="M9530 1060 l0 -690 105 0 105 0 0 690 0 690 -105 0 -105 0 0 -690z"/> |
| 174 | + <path d="M7605 1364 c-107 -17 -190 -57 -240 -116 -46 -54 -57 -93 -53 -184 3 |
| 175 | +-72 7 -87 33 -126 45 -64 109 -101 266 -153 191 -64 239 -108 205 -188 -22 |
| 176 | +-54 -70 -71 -180 -64 -102 5 -178 30 -254 81 l-49 32 -38 -74 -39 -75 30 -24 |
| 177 | +c45 -37 142 -79 221 -97 186 -41 373 -1 462 101 70 79 84 204 34 303 -40 78 |
| 178 | +-111 123 -280 178 -143 47 -193 74 -207 113 -43 124 160 161 367 66 l54 -24 |
| 179 | +36 73 c21 41 37 78 37 83 0 13 -98 60 -161 77 -58 15 -195 25 -244 18z"/> |
| 180 | + <path d="M8720 1356 c-81 -17 -144 -53 -200 -112 l-50 -53 0 85 0 84 -105 0 |
| 181 | +-105 0 0 -675 0 -675 105 0 105 0 0 260 c0 143 2 260 5 260 2 0 25 -22 51 -50 |
| 182 | +87 -93 223 -134 371 -112 254 39 405 243 390 527 -13 248 -145 414 -366 461 |
| 183 | +-79 16 -127 16 -201 0z m163 -186 c110 -41 177 -141 185 -276 8 -152 -45 -256 |
| 184 | +-159 -313 -138 -69 -301 -27 -380 98 -38 60 -51 109 -51 196 1 227 200 372 |
| 185 | +405 295z"/> |
| 186 | + <path d="M10295 1356 c-73 -17 -153 -48 -212 -82 l-43 -26 32 -57 c17 -31 36 |
| 187 | +-63 41 -72 8 -13 19 -11 83 22 229 115 454 49 454 -132 l0 -39 -172 0 c-256 0 |
| 188 | +-346 -25 -431 -119 -97 -107 -82 -302 30 -401 137 -120 420 -114 551 13 l32 |
| 189 | +31 0 -62 0 -63 103 3 102 3 0 360 c0 426 -1 433 -94 526 -80 79 -140 101 -296 |
| 190 | +105 -78 2 -141 -1 -180 -10z m355 -606 c0 -67 -14 -101 -57 -142 -64 -61 -200 |
| 191 | +-93 -290 -69 -150 41 -164 227 -20 260 23 5 115 9 205 10 l162 1 0 -60z"/> |
| 192 | + <path d="M6850 865 l0 -495 105 0 105 0 0 495 0 495 -105 0 -105 0 0 -495z"/> |
| 193 | + <path d="M10994 1343 c4 -10 95 -229 204 -488 l199 -470 -24 -55 c-53 -121 |
| 194 | +-135 -158 -242 -110 -24 11 -45 20 -46 20 -6 0 -85 -147 -85 -158 0 -6 30 -26 |
| 195 | +67 -44 61 -30 77 -33 153 -33 126 0 207 41 273 137 24 34 115 253 263 623 124 |
| 196 | +314 228 576 231 583 4 10 -18 12 -102 10 l-108 -3 -92 -250 c-50 -137 -111 |
| 197 | +-303 -135 -368 -23 -65 -46 -115 -50 -110 -6 6 -204 503 -285 716 -6 15 -22 |
| 198 | +17 -117 17 -100 0 -109 -2 -104 -17z"/> |
| 199 | + </g> |
| 200 | +</svg> |
| 201 | + |
| 202 | +<p>Network connection:</p> |
| 203 | +<p id="status">Initialising...</p> |
| 204 | +<p id="help">Retrying in <span id="clock"></span> seconds...</p> |
| 205 | + |
| 206 | +</body> |
| 207 | +</html> |
0 commit comments