Skip to content

Commit 3b37549

Browse files
committed
Featured sources: valid_until and id attribute
1 parent 3f108c0 commit 3b37549

File tree

1 file changed

+66
-16
lines changed

1 file changed

+66
-16
lines changed

frontend/components/welcome/Featured.js

Lines changed: 66 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,16 @@ const fallback_collections = [
9494

9595
/**
9696
* @typedef FeaturedSource
97-
* @type {{url: String, integrity?: String}}
97+
* @type {{
98+
* url: String,
99+
* id?: String,
100+
* integrity?: String,
101+
* valid_until?: String
102+
* }}
98103
*/
99104

105+
const get_id = (/** @type {FeaturedSource} */ source) => source?.id ?? source.url
106+
100107
/**
101108
* @param {{
102109
* sources: FeaturedSource[]?,
@@ -109,25 +116,51 @@ export const Featured = ({ sources, direct_html_links }) => {
109116

110117
useEffect(() => {
111118
if (sources != null) {
119+
set_waited_too_long(false)
120+
set_source_data({})
121+
112122
// Start downloading the sources
113-
const promises = sources.map(async ({ url, integrity }) => {
114-
const data = await (await fetch(new Request(url, { integrity: integrity ?? undefined }))).json()
115-
116-
if (data.format_version !== "1") {
117-
throw new Error(`Invalid format version: ${data.format_version}`)
118-
}
119-
120-
set_source_data((old) => ({
121-
...old,
122-
[url]: {
123-
...data,
124-
source_url: url,
125-
},
126-
}))
123+
124+
const ids = Array.from(new Set(sources.map(get_id)))
125+
126+
console.log(ids)
127+
console.log("123123123213123")
128+
129+
const promises = ids.map((id) => {
130+
const sources_for_id = sources.filter((source) => get_id(source) === id)
131+
132+
let result = promise_any_with_priority(
133+
sources_for_id.map(async (source) => {
134+
const { url, integrity, valid_until } = source
135+
136+
if (valid_until != null && new Date(valid_until) < new Date()) {
137+
throw new Error(`Source ${url} is expired with valid_until ${valid_until}`)
138+
}
139+
140+
const data = await (await fetch(new Request(url, { integrity: integrity ?? undefined }))).json()
141+
142+
if (data.format_version !== "1") {
143+
throw new Error(`Invalid format version: ${data.format_version}`)
144+
}
145+
146+
return [data, id, url]
147+
})
148+
)
149+
150+
return result.then(([data, id, url]) => {
151+
set_source_data((old) => ({
152+
...old,
153+
[id]: {
154+
...data,
155+
source_url: url,
156+
},
157+
}))
158+
})
127159
})
128160

129161
Promise.any(promises).catch((e) => {
130162
console.error("All featured sources failed to load: ", e)
163+
;(e?.errors ?? []).forEach((e) => console.error(e))
131164
set_waited_too_long(true)
132165
})
133166
}
@@ -148,10 +181,14 @@ export const Featured = ({ sources, direct_html_links }) => {
148181

149182
const no_data = Object.entries(source_data).length === 0
150183

184+
const ids = Array.from(new Set(sources?.map(get_id) ?? []))
185+
186+
const sorted_on_source_order = ids.map((id) => source_data[id]).filter((d) => d != null)
187+
151188
return no_data && waited_too_long
152189
? offline_html
153190
: html`
154-
${(no_data ? placeholder_data : Object.values(source_data)).map((/** @type {SourceManifest} */ data) => {
191+
${(no_data ? placeholder_data : sorted_on_source_order).map((/** @type {SourceManifest} */ data) => {
155192
let collections = data?.collections ?? fallback_collections
156193
157194
return html`
@@ -187,3 +224,16 @@ const collection = (/** @type {SourceManifestNotebookEntry[]} */ notebooks, /**
187224
let n = (s) => (isNaN(s) ? s : Number(s))
188225
return /** @type {SourceManifestNotebookEntry[]} */ (_.sortBy(nbs, [(nb) => n(nb?.frontmatter?.order), "id"]))
189226
}
227+
228+
/**
229+
* Given a list promises, return promise[0].catch(() => promise[1].catch(() => promise[2]... etc))
230+
* @param {Promise[]} promises
231+
* @returns {Promise}
232+
*/
233+
const promise_any_with_priority = (/** @type {Promise[]} */ promises, /** @type {Promise[]} */ already_rejected = []) => {
234+
if (promises.length <= 1) {
235+
return Promise.any([...promises, ...already_rejected])
236+
} else {
237+
return promises[0].catch(() => promise_any_with_priority(promises.slice(1), [...already_rejected, promises[0]]))
238+
}
239+
}

0 commit comments

Comments
 (0)