mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-11 05:42:22 +00:00
fix(news): the browser keeps Local news an hour at most; docs say what the fixes do
Local kept World News API's rows listed after the server had deleted them. README names News among the routes refused behind a proxy; a timed-out request is said to count; the cockpit cached state is near the same place. Co-Authored-By: Claude Fable 5.2 <[email protected]>
This commit is contained in:
1 parent
671a256a6a
commit
caa6f6f812
5 files changed
+49
-8
No files matched your search
@@ -212,7 +212,7 @@ Keep the `env`: bash treats `UID` as read-only, so a plain `UID=1026` in front o
|
||||
|
||||
On SELinux hosts (Fedora, RHEL), compose mounts the checkout with `:z` so the container may read it; Docker may relabel the checkout for container access, which can take a moment on a large checkout. Without that, the start fails with `Cannot find module '/app/scripts/docker-start.mjs'`.
|
||||
|
||||
Behind a reverse proxy, put your keys in `.env` or pass them as environment variables - Provider Settings refuses proxied requests on purpose - and add the hostname you serve it on, for example `GEV_ALLOWED_HOSTS=globe.example.lan` (see [Sharing an instance](#-sharing-an-instance)). The map routes compare the browser's `Origin` with the `Host` the server sees, so the proxy must pass the original `Host` and, when it terminates TLS, `X-Forwarded-Proto`. Caddy does both by default; for nginx add `proxy_set_header Host $http_host;`, `proxy_set_header X-Forwarded-Proto $scheme;` and `proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;`. On an install outside Docker, that forwarding header also rate-limits the proxy's users apart from your own browser. Under the default Docker bridge network every client on the host, your browser included, reaches the container from its gateway address and shares one Overpass bucket.
|
||||
Behind a reverse proxy, put your keys in `.env` or pass them as environment variables - Provider Settings and the News layer refuse proxied requests on purpose - and add the hostname you serve it on, for example `GEV_ALLOWED_HOSTS=globe.example.lan` (see [Sharing an instance](#-sharing-an-instance)). The map routes compare the browser's `Origin` with the `Host` the server sees, so the proxy must pass the original `Host` and, when it terminates TLS, `X-Forwarded-Proto`. Caddy does both by default; for nginx add `proxy_set_header Host $http_host;`, `proxy_set_header X-Forwarded-Proto $scheme;` and `proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;`. On an install outside Docker, that forwarding header also rate-limits the proxy's users apart from your own browser. Under the default Docker bridge network every client on the host, your browser included, reaches the container from its gateway address and shares one Overpass bucket.
|
||||
|
||||
</details>
|
||||
|
||||
@@ -236,8 +236,8 @@ the container.
|
||||
|
||||
### Path 4 — GitHub Codespaces (cloud, no local install)
|
||||
|
||||
Codespaces requires a GitHub account. Overpass queries and OpenAI voice token
|
||||
requests return HTTP 403 through its forwarded HTTPS URL, even with API keys
|
||||
Codespaces requires a GitHub account. Overpass queries, the News layer and OpenAI
|
||||
voice token requests return HTTP 403 through its forwarded HTTPS URL, even with API keys
|
||||
in `.env` and `GEV_ALLOWED_HOSTS` configured. Use a local setup for these features.
|
||||
|
||||
The codespace runs the dev server in a cloud workspace, so Node and the dependencies
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
- Cockpit Regional News holds its list to the last 24 hours, newest first, on
|
||||
the server and in the client, and labels its four states apart: fresh
|
||||
results with no banner and a `LAST 24 H` footer, earlier results kept after
|
||||
a failed refresh as `CACHED · REFRESH FAILED`, `NO NEWS IN THE LAST 24 H`,
|
||||
a failed refresh near the same place as `CACHED · REFRESH FAILED`, `NO NEWS IN THE LAST 24 H`,
|
||||
and `REGIONAL NEWS UNAVAILABLE`. The banner is now really hidden over a
|
||||
populated list, and the footer no longer reverts to a static `RECENT` on a
|
||||
page change (Denis Groshev, @ZloyS, #1593).
|
||||
@@ -170,8 +170,9 @@ Status: Open (limits)
|
||||
and is tried again with the first ask a minute or more later.
|
||||
- Local needs a World News API key. Its free plan allows 50 points a day; Core
|
||||
stops at `WORLDNEWSAPI_DAILY_READS` reads (default 30) and Local then says the
|
||||
daily limit is reached. A request that never reached World News API (offline,
|
||||
timed out) is not counted; any answer from it is, a failing one too.
|
||||
daily limit is reached. A request that never reached World News API (offline)
|
||||
is not counted; any answer from it is, a failing one too, and so is a
|
||||
request that timed out.
|
||||
- A country's news is kept for at most 1 hour (World News API's terms, which
|
||||
also ask the operator for its written permission to cache at all). While
|
||||
World News API cannot be read, Local in that country therefore reads
|
||||
|
||||
@@ -1083,6 +1083,7 @@ export function createNewsLayer({
|
||||
minor: page.reports.filter((r) =>
|
||||
withinNewsWindow(r, now(), maxWindowMs),
|
||||
),
|
||||
readAt: now(),
|
||||
loading: false,
|
||||
error: null,
|
||||
};
|
||||
@@ -1094,7 +1095,8 @@ export function createNewsLayer({
|
||||
...inView,
|
||||
// A missing key is read again with the next refresh, not each pan.
|
||||
readKey: need ? readKey : inView.readKey,
|
||||
minor: need ? [] : inView.minor,
|
||||
// World News API's news is kept an hour at most, as the server does.
|
||||
minor: need || now() - inView.readAt >= 3_600_000 ? [] : inView.minor,
|
||||
loading: false,
|
||||
error: need ? null : cause?.message || FEED_UNAVAILABLE,
|
||||
};
|
||||
|
||||
@@ -45,6 +45,7 @@ function fixture(
|
||||
reduced = false,
|
||||
centre = () => ({ lat: 49, lon: 36 }),
|
||||
credits = [],
|
||||
now = () => NOW,
|
||||
} = {},
|
||||
) {
|
||||
const calls = { feed: [], hotspots: 0, outline: 0 };
|
||||
@@ -110,7 +111,7 @@ function fixture(
|
||||
const layer = createNewsLayer({
|
||||
source,
|
||||
overlayHost,
|
||||
now: () => NOW,
|
||||
now,
|
||||
matchMedia: () => ({ matches: reduced }),
|
||||
getViewCentre: () => centre(),
|
||||
registerCredit: (_viewer, credit) => {
|
||||
@@ -840,6 +841,43 @@ test('a failed Conflicts read leaves Local reading with each refresh', async (t)
|
||||
assert.equal(view.error, 'News feed unavailable');
|
||||
});
|
||||
|
||||
test('Local reports are listed an hour at most while they cannot be read again', async (t) => {
|
||||
t.mock.timers.enable({ apis: ['setTimeout'] });
|
||||
let at = NOW;
|
||||
let failing = false;
|
||||
const { layer } = fixture(t, {
|
||||
height: 1_000_000,
|
||||
now: () => at,
|
||||
source: {
|
||||
getFeed: async (query) => {
|
||||
if (query.at && failing) throw new Error('News feed unavailable');
|
||||
return {
|
||||
reports: [report('inside', { relevance: 'minor' })],
|
||||
nextBefore: null,
|
||||
};
|
||||
},
|
||||
getAreaOutline: async () => ukraine,
|
||||
},
|
||||
});
|
||||
const listed = () =>
|
||||
layer.getRowControls().feed.inView.items.map((item) => item.id);
|
||||
layer.enable();
|
||||
await layer.update();
|
||||
layer.setParams({ filters: { section: 'local' } });
|
||||
await flush();
|
||||
assert.deepEqual(listed(), ['inside']);
|
||||
// World News API's terms: its news is kept an hour at most, here too.
|
||||
failing = true;
|
||||
at += 59 * 60_000;
|
||||
await layer.update();
|
||||
await flush();
|
||||
assert.deepEqual(listed(), ['inside']);
|
||||
at += 2 * 60_000;
|
||||
await layer.update();
|
||||
await flush();
|
||||
assert.deepEqual(listed(), []);
|
||||
});
|
||||
|
||||
test('a failed read keeps the layer on with an error; disable clears the overlay', async (t) => {
|
||||
const { layer, entries } = fixture(t, {
|
||||
source: { getFeed: async () => Promise.reject(new Error('boom')) },
|
||||
|
||||
Reference in new issue
Block a user