Skip to content

Commit 06aa6ba

Browse files
authored
Merge pull request #230 from thewtex/contrib-updates
2 parents c3a1647 + fb4d392 commit 06aa6ba

File tree

5 files changed

+59
-101
lines changed

5 files changed

+59
-101
lines changed
2.09 MB
Binary file not shown.

src/assets/use-this-template.png

137 KB
Loading

src/content.config.ts

Lines changed: 54 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -118,14 +118,7 @@ async function generateArticleArchive(
118118
` Downloading thumbnail from ${pageData.frontmatter.thumbnail}`
119119
);
120120

121-
const controller = new AbortController();
122-
const timeoutId = setTimeout(() => controller.abort(), 30000);
123-
124-
const response = await fetch(pageData.frontmatter.thumbnail, {
125-
signal: controller.signal,
126-
});
127-
128-
clearTimeout(timeoutId);
121+
const response = await fetchWithRetry(pageData.frontmatter.thumbnail);
129122

130123
if (response.ok) {
131124
const buffer = await response.arrayBuffer();
@@ -158,14 +151,7 @@ async function generateArticleArchive(
158151
` Downloading ${download.filename} from ${download.url}`
159152
);
160153

161-
const controller = new AbortController();
162-
const timeoutId = setTimeout(() => controller.abort(), 30000);
163-
164-
const response = await fetch(download.url, {
165-
signal: controller.signal,
166-
});
167-
168-
clearTimeout(timeoutId);
154+
const response = await fetchWithRetry(download.url);
169155

170156
if (response.ok) {
171157
const buffer = await response.arrayBuffer();
@@ -261,6 +247,50 @@ function getArticlesFromConfig(
261247
}
262248
}
263249

250+
/**
251+
* Fetch with retry logic
252+
*/
253+
async function fetchWithRetry(
254+
url: string,
255+
options: RequestInit = {},
256+
maxRetries: number = 3,
257+
timeout: number = 60000
258+
): Promise<Response> {
259+
let lastError: Error | null = null;
260+
261+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
262+
try {
263+
const controller = new AbortController();
264+
const timeoutId = setTimeout(() => controller.abort(), timeout);
265+
266+
const response = await fetch(url, {
267+
...options,
268+
signal: controller.signal,
269+
});
270+
271+
clearTimeout(timeoutId);
272+
return response;
273+
} catch (error) {
274+
lastError = error as Error;
275+
console.warn(
276+
`Fetch attempt ${attempt}/${maxRetries} failed for ${url}:`,
277+
error
278+
);
279+
280+
if (attempt < maxRetries) {
281+
const delay = Math.min(1000 * Math.pow(2, attempt - 1), 5000);
282+
console.log(`Retrying in ${delay}ms...`);
283+
await new Promise((resolve) => setTimeout(resolve, delay));
284+
}
285+
}
286+
}
287+
288+
throw (
289+
lastError ||
290+
new Error(`Failed to fetch ${url} after ${maxRetries} attempts`)
291+
);
292+
}
293+
264294
/**
265295
* Fetch all article IDs from myst.xref.json
266296
*/
@@ -269,14 +299,7 @@ async function getAllArticles(baseUrl: string): Promise<number[]> {
269299
const xrefUrl = `${baseUrl}/myst.xref.json`;
270300
console.log(`Fetching all articles from ${xrefUrl}`);
271301

272-
const controller = new AbortController();
273-
const timeoutId = setTimeout(() => controller.abort(), 10000);
274-
275-
const response = await fetch(xrefUrl, {
276-
signal: controller.signal,
277-
});
278-
279-
clearTimeout(timeoutId);
302+
const response = await fetchWithRetry(xrefUrl);
280303

281304
if (!response.ok) {
282305
console.warn(`Failed to fetch myst.xref.json: ${response.status}`);
@@ -346,18 +369,10 @@ const createFilteredPagesLoader = (
346369
`Fetching article ${articleId} from https://dev-beta.dpid.org/${articleId}?format=myst`
347370
);
348371

349-
const controller = new AbortController();
350-
const timeoutId = setTimeout(() => controller.abort(), 10000);
351-
352-
const response = await fetch(
353-
`https://dev-beta.dpid.org/${articleId}?format=myst`,
354-
{
355-
signal: controller.signal,
356-
}
372+
const response = await fetchWithRetry(
373+
`https://dev-beta.dpid.org/${articleId}?format=myst`
357374
);
358375

359-
clearTimeout(timeoutId);
360-
361376
if (!response.ok) {
362377
console.warn(
363378
`Failed to fetch article ${articleId}: ${response.status}`
@@ -447,17 +462,7 @@ const createFilteredPagesLoader = (
447462
`Downloading article.pdf for ${insightJournalId} from ${articlePdfDownload.url}`
448463
);
449464

450-
const pdfController = new AbortController();
451-
const pdfTimeoutId = setTimeout(
452-
() => pdfController.abort(),
453-
30000
454-
);
455-
456-
const pdfResponse = await fetch(articlePdfDownload.url, {
457-
signal: pdfController.signal,
458-
});
459-
460-
clearTimeout(pdfTimeoutId);
465+
const pdfResponse = await fetchWithRetry(articlePdfDownload.url);
461466

462467
if (pdfResponse.ok) {
463468
const pdfBuffer = await pdfResponse.arrayBuffer();
@@ -497,56 +502,16 @@ const createFilteredPagesLoader = (
497502
`Fetching insight-journal-metadata.json for ${insightJournalId} from ${metadataDownload.url}`
498503
);
499504

500-
const metadataController = new AbortController();
501-
const metadataTimeoutId = setTimeout(
502-
() => metadataController.abort(),
503-
10000
505+
const metadataResponse = await fetchWithRetry(
506+
metadataDownload.url
504507
);
505508

506-
const metadataResponse = await fetch(metadataDownload.url, {
507-
signal: metadataController.signal,
508-
});
509-
510-
clearTimeout(metadataTimeoutId);
511-
512509
if (metadataResponse.ok) {
513510
const metadataJson = await metadataResponse.json();
514511
console.log(
515512
`✓ Fetched insight-journal-metadata.json for ${insightJournalId}`
516513
);
517514

518-
// Merge tags into keywords
519-
if (metadataJson.tags && Array.isArray(metadataJson.tags)) {
520-
// Initialize keywords array if it doesn't exist
521-
if (!pageData.frontmatter) {
522-
pageData.frontmatter = {};
523-
}
524-
if (!Array.isArray(pageData.frontmatter.keywords)) {
525-
pageData.frontmatter.keywords = [];
526-
}
527-
528-
// Add tags to keywords if not already present
529-
const existingKeywords = new Set(
530-
pageData.frontmatter.keywords.map((k: string) =>
531-
k.toLowerCase()
532-
)
533-
);
534-
535-
for (const tag of metadataJson.tags) {
536-
if (
537-
typeof tag === "string" &&
538-
!existingKeywords.has(tag.toLowerCase())
539-
) {
540-
pageData.frontmatter.keywords.push(tag);
541-
existingKeywords.add(tag.toLowerCase());
542-
}
543-
}
544-
545-
console.log(
546-
`✓ Added ${metadataJson.tags.length} tags to keywords (now ${pageData.frontmatter.keywords.length} total)`
547-
);
548-
}
549-
550515
// Set github property from source_code_git_repo if it contains "github.com"
551516
if (
552517
metadataJson.source_code_git_repo &&
@@ -582,21 +547,10 @@ const createFilteredPagesLoader = (
582547
`Downloading thumbnail for ${insightJournalId} from ${pageData.frontmatter.thumbnail}`
583548
);
584549

585-
const thumbnailController = new AbortController();
586-
const thumbnailTimeoutId = setTimeout(
587-
() => thumbnailController.abort(),
588-
30000
550+
const thumbnailResponse = await fetchWithRetry(
551+
pageData.frontmatter.thumbnail
589552
);
590553

591-
const thumbnailResponse = await fetch(
592-
pageData.frontmatter.thumbnail,
593-
{
594-
signal: thumbnailController.signal,
595-
}
596-
);
597-
598-
clearTimeout(thumbnailTimeoutId);
599-
600554
if (thumbnailResponse.ok) {
601555
const thumbnailBuffer = await thumbnailResponse.arrayBuffer();
602556
const thumbnailsDir = join(publicDir, "thumbnails");

src/pages/about.astro

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { Image } from 'astro:assets';
1313
import { Code } from 'astro:components';
1414
import galileoPortrait from '../assets/GalileoPortraitBySustermans.jpg';
1515
import merkleTrees from '../assets/Merkle.png';
16+
import useThisTemplate from '../assets/use-this-template.png';
1617
1718
const title = "About - The Insight Journal";
1819
const description = "Learn about the Insight Journal's mission, technology, and how to contribute to open, reproducible medical image analysis research.";
@@ -456,6 +457,9 @@ image = itk.imread('data/img1.png')
456457
<li>Guidelines for including code, data, and visualizations</li>
457458
<li>Cross-platform continuous integration testing with GitHub Actions</li>
458459
</ul>
460+
<a href="https://github.com/InsightSoftwareConsortium/InsightJournalTemplate" target="_blank" rel="noopener noreferrer">
461+
<Image src={useThisTemplate} alt="Use this template screenshot" />
462+
</a>
459463
<p>
460464
To create a new article repository, click the <i>"Use this template"</i> button on the GitHub page.
461465
This will create a new repository in your GitHub account that you can clone and edit locally.

src/pages/index.astro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ const featuredArticle = {
221221
};
222222
const nv1 = new Niivue(defaults);
223223
await nv1.attachToCanvas(gl1);
224-
await nv1.loadVolumes([{ url: "/assets/visiblehuman.nii.gz" }]);
224+
await nv1.loadVolumes([{ url: "/assets/visiblehuman-small.nii.gz" }]);
225225

226226
// Set only rendering mode (no slices)
227227
nv1.setSliceType(nv1.sliceTypeRender);

0 commit comments

Comments
 (0)