Skip to content

Commit 877b7d0

Browse files
authored
Merge branch 'develop' into hotfix/ip-logging
2 parents f8db346 + cf31fe7 commit 877b7d0

File tree

17 files changed

+181
-83
lines changed

17 files changed

+181
-83
lines changed

.docker/vhost.conf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,7 @@ server {
77
proxy_set_header X-Forwarded-For $remote_addr;
88
proxy_set_header Host $http_host;
99
proxy_pass http://node:3000;
10+
add_header Cache-Control "public, max-age=604800";
11+
expires 7d;
1012
}
1113
}

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
- [#123](https://github.com/os2display/display-client/pull/123)
6+
- Changed to apply max-age 7d to all files and added cache busting to config.json and release.json.
7+
- Added "loginCheckTimeout", "configFetchInterval", "refreshTokenTimeout", "releaseTimestampIntervalTimeout" to config.json.
8+
- Simplified config.json.
9+
- [#122](https://github.com/os2display/display-client/pull/122)
10+
- Added max-age and expires 1 hour to config.json and release.json.
11+
- [#121](https://github.com/os2display/display-client/pull/120)
12+
- Add releaseVersion, releaseTimestamp and screenId searchParams when starting app.
13+
514
## [2.0.1] - 2024-04-10
615

716
- [#120](https://github.com/os2display/display-client/pull/120)

README.md

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,30 @@ See [https://github.com/os2display/display-docs/blob/main/client.md](https://git
55

66
## Config
77
The client can be configured by creating `public/config.json` with relevant values.
8-
See `public/example_config.json` for values.
9-
10-
```json
11-
{
12-
"apiEndpoint": "",
13-
"authenticationEndpoint": "/v2/authentication/screen",
14-
"authenticationRefreshTokenEndpoint": "/v2/authentication/token/refresh",
15-
"dataStrategy": {
16-
"type": "pull",
17-
"config": {
18-
"interval": 30000,
19-
"endpoint": ""
20-
}
21-
},
22-
"colorScheme": {
23-
"type": "library",
24-
"lat": 56.0,
25-
"lng": 10.0
26-
},
27-
"schedulingInterval": 60000,
28-
"debug": false
29-
}
30-
```
31-
All endpoint should be configured with out a trailing slash. The endpoints `apiEndpoint` and `dataStrategy.config.endpoint` can be
8+
See `public/example_config.json` for example values.
9+
10+
Values explained:
11+
12+
* apiEndpoint - The endpoint where the API is located.
13+
* loginCheckTimeout - How often (milliseconds) should the screen check for
14+
status when it is not logged in, and waiting for being activated in the
15+
administration.
16+
* configFetchInterval - How often (milliseconds) should a fresh
17+
config.json be fetched.
18+
* refreshTokenTimeout - How often (milliseconds) should it be checked
19+
whether the token needs to be refreshed?
20+
* releaseTimestampIntervalTimeout - How often (milliseconds) should the
21+
code check if a new release has been deployed, and reload if true?
22+
* dataStrategy.config.interval - How often (milliseconds) should data be fetched
23+
for the logged in screen?
24+
* colorScheme.lat - Where is the screen located? Used for darkmode.
25+
* colorScheme.lng - Where is the screen located? Used for darkmode.
26+
* schedulingInterval - How often (milliseconds) should scheduling for the
27+
screen be checked.
28+
* debug - Should the screen be in debug mode? If true, the cursor will be
29+
invisible.
30+
31+
All endpoint should be configured without a trailing slash. The endpoints `apiEndpoint` can be
3232
left empty if the api is hosted from the root of the same domain as the client. E.g. if the api is at https://example.org and the client is at
3333
https://example.org/client
3434

infrastructure/itkdev/etc/confd/templates/config.tmpl

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
{
22
"apiEndpoint": "{{ getenv "APP_API_ENDPOINT" "" }}",
3-
"authenticationEndpoint": "{{ getenv "APP_API_AUTHENTICATION_ENDPOINT" "/v2/authentication/token" }}",
4-
"authenticationRefreshTokenEndpoint": "{{ getenv "APP_API_AUTHENTICATION_REFRESH_ENDPOINT" "/v2/authentication/token/refresh" }}",
3+
"loginCheckTimeout": {{ getenv "APP_LOGIN_CHECK_TIMEOUT" "20000" }},
4+
"configFetchInterval": {{ getenv "APP_CONFIG_FETCH_INTERVAL" "600000" }},
5+
"refreshTokenTimeout": {{ getenv "APP_REFRESH_TOKEN_TIMEOUT" "60000" }},
6+
"releaseTimestampIntervalTimeout": {{ getenv "APP_RELEASE_TIMESTAMP_INTERVAL_TIMEOUT" "600000" }},
57
"dataStrategy": {
68
"type": "pull",
79
"config": {
8-
"interval": {{ getenv "APP_DATA_PULL_INTERVAL" "30000" }},
9-
"endpoint": "{{ getenv "APP_API_PATH" "" }}"
10+
"interval": {{ getenv "APP_DATA_PULL_INTERVAL" "30000" }}
1011
}
1112
},
1213
"colorScheme": {

infrastructure/itkdev/etc/confd/templates/default.conf.tmpl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ server {
77
rewrite ^{{ getenv "APP_SCREEN_CLIENT_PATH" "/" }}(.*) /$1 break;
88
index index.html;
99
autoindex off;
10+
add_header Cache-Control "public, max-age=604800";
11+
expires 7d;
1012
try_files $uri $uri/ =404;
1113
}
1214

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,26 @@
11
# OS2display image build
22

33
This folder contains the infrastructure files for building the `os2display/display-client` image.
4+
5+
## Environment variables that can be set
6+
7+
### config.json
8+
9+
* APP_API_ENDPOINT - The endpoint where the API can be called.
10+
* APP_LOGIN_CHECK_TIMEOUT - How often (milliseconds) should the screen check for
11+
status when it is not logged in, and waiting for being activated in the
12+
administration.
13+
* APP_CONFIG_FETCH_INTERVAL - How often (milliseconds) should a fresh
14+
config.json be fetched.
15+
* APP_REFRESH_TOKEN_TIMEOUT - How often (milliseconds) should it be checked
16+
whether the token needs to be refreshed?
17+
* APP_RELEASE_TIMESTAMP_INTERVAL_TIMEOUT - How often (milliseconds) should the
18+
code check if a new release has been deployed, and reload if true?
19+
* APP_DATA_PULL_INTERVAL - How often (milliseconds) should data be fetched for
20+
the logged in screen?
21+
* APP_CLIENT_LATITUDE - Where is the screen located? Used for darkmode.
22+
* APP_CLIENT_LONGITUDE - Where is the screen located? Used for darkmode.
23+
* APP_SCHEDULING_INTERVAL - How often (milliseconds) should scheduling for the
24+
screen be checked.
25+
* APP_DEBUG - Should the screen be in debug mode? If true, the cursor will be
26+
invisible.

infrastructure/os2display/etc/confd/templates/config.tmpl

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
{
22
"apiEndpoint": "{{ getenv "APP_API_ENDPOINT" "/" }}",
3-
"authenticationEndpoint": "{{ getenv "APP_API_AUTHENTICATION_ENDPOINT" "/v2/authentication/token" }}",
4-
"authenticationRefreshTokenEndpoint": "{{ getenv "APP_API_AUTHENTICATION_REFRESH_ENDPOINT" "/v2/authentication/token/refresh" }}",
3+
"loginCheckTimeout": {{ getenv "APP_LOGIN_CHECK_TIMEOUT" "20000" }},
4+
"configFetchInterval": {{ getenv "APP_CONFIG_FETCH_INTERVAL" "600000" }},
5+
"refreshTokenTimeout": {{ getenv "APP_REFRESH_TOKEN_TIMEOUT" "60000" }},
6+
"releaseTimestampIntervalTimeout": {{ getenv "APP_RELEASE_TIMESTAMP_INTERVAL_TIMEOUT" "600000" }},
57
"dataStrategy": {
68
"type": "pull",
79
"config": {
8-
"interval": {{ getenv "APP_DATA_PULL_INTERVAL" "30000" }},
9-
"endpoint": "{{ getenv "APP_API_PATH" "/" }}"
10+
"interval": {{ getenv "APP_DATA_PULL_INTERVAL" "30000" }}
1011
}
1112
},
1213
"colorScheme": {

infrastructure/os2display/etc/confd/templates/default.conf.tmpl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ server {
77
rewrite ^{{ getenv "APP_SCREEN_CLIENT_PATH" "/" }}(.*) /$1 break;
88
index index.html;
99
autoindex off;
10+
add_header Cache-Control "public, max-age=604800";
11+
expires 7d;
1012
try_files $uri $uri/ =404;
1113
}
1214

public/example_config.json

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
{
2-
"apiEndpoint": "",
3-
"authenticationEndpoint": "/v2/authentication/screen",
4-
"authenticationRefreshTokenEndpoint": "/v2/authentication/token/refresh",
2+
"apiEndpoint": "https://os2display.example.org",
3+
"loginCheckTimeout": 20000,
4+
"configFetchInterval": 90000,
5+
"refreshTokenTimeout": 900000,
6+
"releaseTimestampIntervalTimeout": 600000,
57
"dataStrategy": {
68
"type": "pull",
79
"config": {
8-
"interval": 30000,
9-
"endpoint": ""
10+
"interval": 30000
1011
}
1112
},
1213
"colorScheme": {
@@ -15,5 +16,11 @@
1516
"lng": 10.0
1617
},
1718
"schedulingInterval": 60000,
18-
"debug": false
19+
"debug": false,
20+
"logging": [
21+
{
22+
"transport": "console",
23+
"level": "info"
24+
}
25+
]
1926
}

src/app.js

Lines changed: 55 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import Logger from './logger/logger';
88
import './app.scss';
99
import localStorageKeys from './local-storage-keys';
1010
import fallback from './assets/fallback.png';
11+
import idFromPath from './id-from-path';
1112

1213
/**
1314
* App component.
@@ -20,9 +21,9 @@ function App() {
2021
localStorageKeys.FALLBACK_IMAGE
2122
);
2223

23-
const loginCheckTimeout = 15 * 1000;
24-
const refreshTimeout = 60 * 1000;
25-
const releaseTimestampIntervalTimeout = 1000 * 60 * 5;
24+
const loginCheckTimeoutDefault = 20 * 1000;
25+
const refreshTokenTimeoutDefault = 60 * 1000 * 15;
26+
const releaseTimestampIntervalTimeoutDefault = 1000 * 60 * 10;
2627

2728
const [running, setRunning] = useState(false);
2829
const [screen, setScreen] = useState('');
@@ -96,7 +97,7 @@ function App() {
9697
Logger.log('info', 'Refreshing token.');
9798

9899
ConfigLoader.loadConfig().then((config) => {
99-
fetch(config.authenticationRefreshTokenEndpoint, {
100+
fetch(`${config.apiEndpoint}/v2/authentication/token/refresh`, {
100101
method: 'POST',
101102
headers: {
102103
'Content-Type': 'application/json',
@@ -167,8 +168,13 @@ function App() {
167168
})
168169
);
169170

170-
// Start refresh token interval.
171-
refreshTokenIntervalRef.current = setInterval(checkToken, refreshTimeout);
171+
ConfigLoader.loadConfig().then((config) => {
172+
// Start refresh token interval.
173+
refreshTokenIntervalRef.current = setInterval(
174+
checkToken,
175+
config.refreshTokenTimeout ?? refreshTokenTimeoutDefault
176+
);
177+
});
172178
};
173179

174180
const checkLogin = () => {
@@ -181,7 +187,7 @@ function App() {
181187
startContent(localScreenId);
182188
} else {
183189
ConfigLoader.loadConfig().then((config) => {
184-
fetch(config.authenticationEndpoint, {
190+
fetch(`${config.apiEndpoint}/v2/authentication/screen`, {
185191
method: 'POST',
186192
mode: 'cors',
187193
credentials: 'include',
@@ -224,15 +230,21 @@ function App() {
224230
clearTimeout(timeoutRef.current);
225231
}
226232

227-
timeoutRef.current = setTimeout(checkLogin, loginCheckTimeout);
233+
timeoutRef.current = setTimeout(
234+
checkLogin,
235+
config.loginCheckTimeout ?? loginCheckTimeoutDefault
236+
);
228237
}
229238
})
230239
.catch(() => {
231240
if (timeoutRef.current !== null) {
232241
clearTimeout(timeoutRef.current);
233242
}
234243

235-
timeoutRef.current = setTimeout(checkLogin, loginCheckTimeout);
244+
timeoutRef.current = setTimeout(
245+
checkLogin,
246+
config.loginCheckTimeout ?? loginCheckTimeoutDefault
247+
);
236248
});
237249
});
238250
}
@@ -302,6 +314,24 @@ function App() {
302314
};
303315

304316
useEffect(() => {
317+
const currentUrl = new URL(window.location.href);
318+
319+
// Make sure have releaseVersion and releaseTimestamp set in url parameters.
320+
if (
321+
!currentUrl.searchParams.has('releaseVersion') ||
322+
!currentUrl.searchParams.has('releaseTimestamp')
323+
) {
324+
ReleaseLoader.loadConfig().then((release) => {
325+
currentUrl.searchParams.set(
326+
'releaseTimestamp',
327+
release.releaseTimestamp
328+
);
329+
currentUrl.searchParams.set('releaseVersion', release.releaseVersion);
330+
331+
window.history.replaceState(null, '', currentUrl);
332+
});
333+
}
334+
305335
document.addEventListener('screen', screenHandler);
306336
document.addEventListener('reauthenticate', reauthenticateHandler);
307337
document.addEventListener('contentEmpty', contentEmpty);
@@ -312,10 +342,13 @@ function App() {
312342

313343
checkForUpdates();
314344

315-
releaseTimestampIntervalRef.current = setInterval(
316-
checkForUpdates,
317-
releaseTimestampIntervalTimeout
318-
);
345+
ConfigLoader.loadConfig().then((config) => {
346+
releaseTimestampIntervalRef.current = setInterval(
347+
checkForUpdates,
348+
config.releaseTimestampIntervalTimeout ??
349+
releaseTimestampIntervalTimeoutDefault
350+
);
351+
});
319352

320353
return function cleanup() {
321354
Logger.log('info', 'Unmounting App.');
@@ -341,6 +374,15 @@ function App() {
341374
}, []);
342375

343376
useEffect(() => {
377+
// Append screenId to current url for easier debugging. If errors are logged in the API's standard http log this
378+
// makes it easy to see what screen client has made the http call by putting the screen id in the referer http
379+
// header.
380+
if (screen && screen['@id']) {
381+
const url = new URL(window.location.href);
382+
url.searchParams.set('screenId', idFromPath(screen['@id']));
383+
window.history.replaceState(null, '', url);
384+
}
385+
344386
ConfigLoader.loadConfig().then((config) => {
345387
const token = localStorage.getItem(localStorageKeys.API_TOKEN);
346388
const tenantKey = localStorage.getItem(localStorageKeys.TENANT_KEY);

0 commit comments

Comments
 (0)