Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .docker/templates/default.conf.template
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ server {
try_files $uri /index.php$is_args$args;
}

# Screen client online check should just serve static files
location /client/online-check {
index index.html index.htm;
}

# Protect files and directories from prying eyes.
location ~* \.(engine|inc|install|make|module|profile|po|sh|.*sql|.tar|.gz|.bz2|theme|twig|tpl(\.php)?|xtmpl|yml)(~|\.sw[op]|\.bak|\.orig|\.save)?$|^(\.(?!well-known).*|Entries.*|Repository|Root|Tag|Template|composer\.(json|lock)|web\.config)$|^#.*#$|\.php(~|\.sw[op]|\.bak|\.orig|\.save)$ {
deny all;
Expand Down
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ All notable changes to this project will be documented in this file.
* Removed propTypes.
* Upgraded redux-toolkit and how api slices are generated.
* Fixed redux-toolkit cache handling.
* Added Taskfile
* Add Taskfile
* Added (Client) online-check to public.
* Updated developer documentation.

### NB! Prior to 3.x the project was split into separate repositories
Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,15 @@ classDiagram
Feed "0..n" -- "1" FeedSource
```

## Online check for Client

If the client does not have internet when starting, it cannot load the assets needed for the Client.
The `public/client/online-check` has been added to handle this.
The folder contains an `index.html`, that checks connectivity before redirecting to `/client`.
If this index.html is cached in the browser the online check page can load without internet.

To use this, set the starting path of the Client to `/client/online-check`.

## Error codes in the Client

The Client at `/client` can display the following error codes:
Expand Down
3 changes: 3 additions & 0 deletions config/routes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ authentication-unbind-screen:
controller: App\Controller\Api\AuthScreenUnbindController

admin:
# Sub routes are included to pass route control to the React App.
path: /admin{subroutes}
requirements:
# https://symfony.com/doc/current/routing.html#slash-characters-in-route-parameters
Expand All @@ -29,6 +30,7 @@ admin:
controller: App\Controller\Admin\AdminController

client:
# Sub routes are included to pass route control to the React App.
path: /client{subroutes}
requirements:
# https://symfony.com/doc/current/routing.html#slash-characters-in-route-parameters
Expand All @@ -48,6 +50,7 @@ client_config:

when@dev:
templates:
# Sub routes are included to pass route control to the React App.
path: /template{subroutes}
methods: ['GET']
requirements:
Expand Down
Binary file added public/client/online-check/1pixel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
207 changes: 207 additions & 0 deletions public/client/online-check/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href=favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="google" content="notranslate" />
<meta
name="description"
content="OS2Display client online check"
/>
<title>OS2Display online check</title>

<style>
html {
cursor: none;
}

body {
background-color: #000000;
margin-top: 10%;
text-align: center;
font-family: Arial, Helvetica, sans-serif;
color: #fff;
font-size: 20px;
}

#logo {
position: absolute;
bottom: 10px;
right: 10px;
}

#status {
margin-top: 0;
font-size: 3em;
font-weight: bold;
}
</style>

<script>
/*
* *************** Online / Offline Detection ***************
*
* This page can be used as a startup page for screen clients.
*
* It aims to solve the problem with screens not starting properly
* if the browser loads the "client" application from cache before
* the network is ready.
*
* On load it will attempt to load 1 pixel image form the server. If this
* fails it will wait and try again at a given interval. The first
* interval is set at random, the following are set at 30 seconds.
* This is done to spread the load from the clients.
*
* A countdown clock is shown as a minimalist UI to aid in debugging
* client behavior.
*
* When the call succeeds the client is deemed to be online and is
* redirected to proper client application.
*
* By design all scripts, styles and assets are inlined in the html
* to ensure the script works even if loaded from cache with no network
* access.
*
* Note:
* "navigator.onLine" is not used because it can give false positives
* @see https://developer.mozilla.org/en-US/docs/Web/API/Navigator/onLine
*/

const checkOnlineStatus = async () => {
try {
const online = await fetch("1pixel.png?ts=" + Date.now());
return online.status >= 200 && online.status < 300; // either true or false
} catch (err) {
return false; // definitely offline
}
};

function getRandomInt(max) {
return Math.floor(Math.random() * max);
}

function redirectToClient() {
const helpDisplay = document.getElementById("help");
helpDisplay.textContent = "Redirecting to client...";

setTimeout(async () => {
window.location.assign("/client/?ts=" + Date.now());
}, 3000
);
}

const interval = 30;

let clock = getRandomInt(interval);
(function pollOnlineStatus() {
setTimeout(async () => {
clock--;

if (0 === clock) {
clock = interval;
const result = await checkOnlineStatus();
const statusDisplay = document.getElementById("status");
statusDisplay.textContent = result ? "Online" : "Offline";

if (result) {
redirectToClient();
}
}

const statusDisplay = document.getElementById("clock");
statusDisplay.textContent = clock.toString();

pollOnlineStatus();
}, 1000);
})();

window.addEventListener("load", async (event) => {
const result = await checkOnlineStatus();
if (result) {
redirectToClient();
}

const statusDisplay = document.getElementById("status");
statusDisplay.textContent = result ? "Online" : "Offline";

const statusClock = document.getElementById("clock");
statusClock.textContent = clock.toString();
});
</script>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>

<svg id="logo" version="1.0" xmlns="http://www.w3.org/2000/svg"
width="108pt" height="30.4pt" viewBox="0 0 1200 334">
<g transform="translate(0,334) scale(0.1,-0.1)"
fill="#fff" stroke="none">
<path d="M5829 3317 c-25 -7 -65 -25 -90 -39 -49 -29 -140 -117 -170 -165
l-19 -30 94 -57 c52 -31 98 -56 103 -56 4 1 23 21 40 45 93 125 260 129 292 7
25 -94 -16 -156 -296 -442 l-213 -218 0 -96 0 -96 400 0 400 0 0 115 0 115
-219 2 -219 3 152 162 c211 223 247 284 249 418 2 140 -65 246 -198 310 -52
26 -72 30 -160 32 -59 2 -119 -3 -146 -10z" />
<path d="M1240 2745 l0 -575 210 0 210 0 0 575 0 575 -210 0 -210 0 0 -575z" />
<path d="M3970 3130 c-452 -36 -761 -248 -846 -580 -23 -86 -22 -262 0 -354
56 -235 221 -394 527 -511 52 -20 198 -67 324 -105 127 -38 264 -83 305 -101
202 -86 291 -189 292 -337 1 -161 -109 -275 -309 -317 -90 -19 -290 -19 -392
0 -214 41 -471 164 -646 309 -27 23 -57 47 -67 54 -14 12 -26 -8 -113 -185
l-96 -198 48 -43 c123 -111 354 -239 541 -301 377 -125 827 -109 1125 40 214
107 354 276 408 490 18 70 21 103 17 209 -8 189 -55 311 -166 432 -135 146
-279 217 -712 352 -368 116 -494 186 -555 311 -35 71 -38 171 -7 230 93 180
403 228 775 120 104 -30 277 -102 357 -149 35 -20 66 -38 71 -39 5 -1 52 88
105 198 l95 199 -23 17 c-39 30 -169 96 -263 134 -101 40 -221 75 -340 99 -75
15 -296 37 -340 34 -11 0 -63 -4 -115 -8z" />
<path d="M731 2954 c-371 -207 -603 -514 -693 -915 -30 -138 -33 -417 -5 -549
58 -277 179 -503 372 -695 207 -207 455 -336 760 -397 159 -32 434 -32 590 0
301 60 540 186 746 391 199 200 314 414 376 702 28 131 25 410 -6 549 -24 109
-69 237 -116 331 -118 233 -354 468 -597 594 -37 19 -60 26 -66 20 -12 -13
-172 -359 -172 -372 0 -5 34 -31 76 -58 195 -123 348 -338 406 -571 32 -128
31 -344 -1 -464 -65 -243 -206 -443 -405 -575 -396 -262 -916 -204 -1243 139
-124 129 -197 254 -245 422 -20 69 -23 100 -22 249 0 156 2 178 28 260 71 235
217 428 417 551 32 20 59 42 59 48 -1 26 -169 371 -181 374 -8 1 -43 -14 -78
-34z" />
<path d="M6903 1765 c-40 -17 -73 -69 -73 -113 0 -99 95 -161 180 -117 43 22
60 53 60 111 0 60 -24 99 -76 120 -41 17 -50 17 -91 -1z" />
<path d="M6310 1469 l0 -281 -46 51 c-154 171 -466 170 -638 -2 -96 -96 -140
-213 -140 -372 0 -301 190 -506 469 -505 132 1 222 35 303 117 l52 54 0 -81 0
-80 105 0 105 0 0 690 0 690 -105 0 -105 0 0 -281z m-177 -311 c60 -26 120
-93 148 -167 30 -80 24 -214 -13 -286 -55 -106 -144 -159 -268 -159 -124 0
-213 53 -268 159 -33 65 -42 186 -18 267 51 177 241 262 419 186z" />
<path d="M9530 1060 l0 -690 105 0 105 0 0 690 0 690 -105 0 -105 0 0 -690z" />
<path d="M7605 1364 c-107 -17 -190 -57 -240 -116 -46 -54 -57 -93 -53 -184 3
-72 7 -87 33 -126 45 -64 109 -101 266 -153 191 -64 239 -108 205 -188 -22
-54 -70 -71 -180 -64 -102 5 -178 30 -254 81 l-49 32 -38 -74 -39 -75 30 -24
c45 -37 142 -79 221 -97 186 -41 373 -1 462 101 70 79 84 204 34 303 -40 78
-111 123 -280 178 -143 47 -193 74 -207 113 -43 124 160 161 367 66 l54 -24
36 73 c21 41 37 78 37 83 0 13 -98 60 -161 77 -58 15 -195 25 -244 18z" />
<path d="M8720 1356 c-81 -17 -144 -53 -200 -112 l-50 -53 0 85 0 84 -105 0
-105 0 0 -675 0 -675 105 0 105 0 0 260 c0 143 2 260 5 260 2 0 25 -22 51 -50
87 -93 223 -134 371 -112 254 39 405 243 390 527 -13 248 -145 414 -366 461
-79 16 -127 16 -201 0z m163 -186 c110 -41 177 -141 185 -276 8 -152 -45 -256
-159 -313 -138 -69 -301 -27 -380 98 -38 60 -51 109 -51 196 1 227 200 372
405 295z" />
<path d="M10295 1356 c-73 -17 -153 -48 -212 -82 l-43 -26 32 -57 c17 -31 36
-63 41 -72 8 -13 19 -11 83 22 229 115 454 49 454 -132 l0 -39 -172 0 c-256 0
-346 -25 -431 -119 -97 -107 -82 -302 30 -401 137 -120 420 -114 551 13 l32
31 0 -62 0 -63 103 3 102 3 0 360 c0 426 -1 433 -94 526 -80 79 -140 101 -296
105 -78 2 -141 -1 -180 -10z m355 -606 c0 -67 -14 -101 -57 -142 -64 -61 -200
-93 -290 -69 -150 41 -164 227 -20 260 23 5 115 9 205 10 l162 1 0 -60z" />
<path d="M6850 865 l0 -495 105 0 105 0 0 495 0 495 -105 0 -105 0 0 -495z" />
<path d="M10994 1343 c4 -10 95 -229 204 -488 l199 -470 -24 -55 c-53 -121
-135 -158 -242 -110 -24 11 -45 20 -46 20 -6 0 -85 -147 -85 -158 0 -6 30 -26
67 -44 61 -30 77 -33 153 -33 126 0 207 41 273 137 24 34 115 253 263 623 124
314 228 576 231 583 4 10 -18 12 -102 10 l-108 -3 -92 -250 c-50 -137 -111
-303 -135 -368 -23 -65 -46 -115 -50 -110 -6 6 -204 503 -285 716 -6 15 -22
17 -117 17 -100 0 -109 -2 -104 -17z" />
</g>
</svg>

<p>Network connection:</p>
<p id="status">Initialising...</p>
<p id="help">Retrying in <span id="clock"></span> seconds...</p>

</body>
</html>