mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
Add local cache and fallback for default subplebbits
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"title": "5chan directories",
|
||||
"description": "Each 5chan directory is assigned to a board (subplebbit) handpicked by the team, until DAO curation is implemented.\n\nhttps://github.com/plebbit/temporary-default-subplebbits",
|
||||
"createdAt": 1762179811,
|
||||
"updatedAt": 1762179811,
|
||||
"subplebbits": [
|
||||
{
|
||||
"title": "/pol/ - Politically Incorrect",
|
||||
"address": "politically-incorrect.eth",
|
||||
"nsfw": true
|
||||
},
|
||||
{
|
||||
"title": "/biz/ - Business & Finance",
|
||||
"address": "business-and-finance.eth",
|
||||
"nsfw": false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import defaultSubplebbitsData from '../data/default-subplebbits.json';
|
||||
|
||||
export interface MultisubMetadata {
|
||||
title: string;
|
||||
@@ -13,15 +14,70 @@ export interface MultisubSubplebbit {
|
||||
nsfw?: boolean;
|
||||
}
|
||||
|
||||
export interface MultisubData {
|
||||
title: string;
|
||||
description: string;
|
||||
createdAt: number;
|
||||
updatedAt: number;
|
||||
subplebbits: MultisubSubplebbit[];
|
||||
}
|
||||
|
||||
export interface DefaultSubplebbitsState {
|
||||
subplebbits: MultisubSubplebbit[];
|
||||
loading: boolean;
|
||||
error: Error | null;
|
||||
}
|
||||
|
||||
const GITHUB_URL = 'https://raw.githubusercontent.com/plebbit/lists/master/5chan-multisub.json';
|
||||
const LOCALSTORAGE_KEY = '5chan-subplebbits-cache';
|
||||
const LOCALSTORAGE_TIMESTAMP_KEY = '5chan-subplebbits-cache-timestamp';
|
||||
const CACHE_MAX_AGE_MS = 60 * 60 * 1000; // 1 hour
|
||||
|
||||
let cacheSubplebbits: MultisubSubplebbit[] | null = null;
|
||||
let cacheMetadata: MultisubMetadata | null = null;
|
||||
|
||||
const getFromLocalStorage = (): MultisubData | null => {
|
||||
try {
|
||||
const cached = localStorage.getItem(LOCALSTORAGE_KEY);
|
||||
const timestamp = localStorage.getItem(LOCALSTORAGE_TIMESTAMP_KEY);
|
||||
if (cached && timestamp) {
|
||||
const age = Date.now() - parseInt(timestamp, 10);
|
||||
if (age < CACHE_MAX_AGE_MS) {
|
||||
return JSON.parse(cached);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Failed to read from localStorage:', e);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const saveToLocalStorage = (data: MultisubData) => {
|
||||
try {
|
||||
localStorage.setItem(LOCALSTORAGE_KEY, JSON.stringify(data));
|
||||
localStorage.setItem(LOCALSTORAGE_TIMESTAMP_KEY, Date.now().toString());
|
||||
} catch (e) {
|
||||
console.warn('Failed to save to localStorage:', e);
|
||||
}
|
||||
};
|
||||
|
||||
const fetchMultisubData = async (): Promise<MultisubData> => {
|
||||
try {
|
||||
const response = await fetch(GITHUB_URL);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
const data = await response.json();
|
||||
// Save successful fetch to localStorage
|
||||
saveToLocalStorage(data);
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.warn('Failed to fetch subplebbits from GitHub, using vendored fallback:', e);
|
||||
// Fall back to vendored file
|
||||
return defaultSubplebbitsData as MultisubData;
|
||||
}
|
||||
};
|
||||
|
||||
export const useDefaultSubplebbits = () => {
|
||||
const [state, setState] = useState<DefaultSubplebbitsState>({
|
||||
subplebbits: [],
|
||||
@@ -41,13 +97,29 @@ export const useDefaultSubplebbits = () => {
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
const multisub = await fetch('https://raw.githubusercontent.com/plebbit/lists/master/5chan-multisub.json').then((res) => {
|
||||
if (!res.ok) {
|
||||
throw new Error(`HTTP error! status: ${res.status}`);
|
||||
}
|
||||
return res.json();
|
||||
});
|
||||
// Check localStorage first
|
||||
const cachedData = getFromLocalStorage();
|
||||
if (cachedData) {
|
||||
cacheSubplebbits = cachedData.subplebbits;
|
||||
setState({
|
||||
subplebbits: cachedData.subplebbits,
|
||||
loading: false,
|
||||
error: null,
|
||||
});
|
||||
// Still try to fetch fresh data in background (don't await)
|
||||
fetchMultisubData().then((data) => {
|
||||
cacheSubplebbits = data.subplebbits;
|
||||
setState({
|
||||
subplebbits: data.subplebbits,
|
||||
loading: false,
|
||||
error: null,
|
||||
});
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// No cache, fetch fresh data
|
||||
const multisub = await fetchMultisubData();
|
||||
cacheSubplebbits = multisub.subplebbits;
|
||||
|
||||
setState({
|
||||
@@ -56,12 +128,15 @@ export const useDefaultSubplebbits = () => {
|
||||
error: null,
|
||||
});
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
console.warn('Failed to load subplebbits:', e);
|
||||
// Fallback to vendored data
|
||||
const fallbackData = defaultSubplebbitsData as MultisubData;
|
||||
cacheSubplebbits = fallbackData.subplebbits;
|
||||
setState({
|
||||
subplebbits: fallbackData.subplebbits,
|
||||
loading: false,
|
||||
error: e instanceof Error ? e : new Error('Failed to fetch subplebbits'),
|
||||
}));
|
||||
error: null,
|
||||
});
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
@@ -89,13 +164,29 @@ export const useDefaultSubplebbitsState = () => {
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
const multisub = await fetch('https://raw.githubusercontent.com/plebbit/lists/master/5chan-multisub.json').then((res) => {
|
||||
if (!res.ok) {
|
||||
throw new Error(`HTTP error! status: ${res.status}`);
|
||||
}
|
||||
return res.json();
|
||||
});
|
||||
// Check localStorage first
|
||||
const cachedData = getFromLocalStorage();
|
||||
if (cachedData) {
|
||||
cacheSubplebbits = cachedData.subplebbits;
|
||||
setState({
|
||||
subplebbits: cachedData.subplebbits,
|
||||
loading: false,
|
||||
error: null,
|
||||
});
|
||||
// Still try to fetch fresh data in background (don't await)
|
||||
fetchMultisubData().then((data) => {
|
||||
cacheSubplebbits = data.subplebbits;
|
||||
setState({
|
||||
subplebbits: data.subplebbits,
|
||||
loading: false,
|
||||
error: null,
|
||||
});
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// No cache, fetch fresh data
|
||||
const multisub = await fetchMultisubData();
|
||||
cacheSubplebbits = multisub.subplebbits;
|
||||
|
||||
setState({
|
||||
@@ -104,12 +195,15 @@ export const useDefaultSubplebbitsState = () => {
|
||||
error: null,
|
||||
});
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
console.warn('Failed to load subplebbits:', e);
|
||||
// Fallback to vendored data
|
||||
const fallbackData = defaultSubplebbitsData as MultisubData;
|
||||
cacheSubplebbits = fallbackData.subplebbits;
|
||||
setState({
|
||||
subplebbits: fallbackData.subplebbits,
|
||||
loading: false,
|
||||
error: e instanceof Error ? e : new Error('Failed to fetch subplebbits'),
|
||||
}));
|
||||
error: null,
|
||||
});
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
@@ -131,16 +225,53 @@ export const useMultisubMetadata = () => {
|
||||
}
|
||||
(async () => {
|
||||
try {
|
||||
const multisub = await fetch(
|
||||
'https://raw.githubusercontent.com/plebbit/lists/master/5chan-multisub.json',
|
||||
// { cache: 'no-cache' }
|
||||
).then((res) => res.json());
|
||||
const { title, description, createdAt, updatedAt } = multisub;
|
||||
const metadata: MultisubMetadata = { title, description, createdAt, updatedAt };
|
||||
// Check localStorage first
|
||||
const cachedData = getFromLocalStorage();
|
||||
if (cachedData) {
|
||||
const metadata: MultisubMetadata = {
|
||||
title: cachedData.title,
|
||||
description: cachedData.description,
|
||||
createdAt: cachedData.createdAt,
|
||||
updatedAt: cachedData.updatedAt,
|
||||
};
|
||||
cacheMetadata = metadata;
|
||||
setMetadata(metadata);
|
||||
// Still try to fetch fresh data in background (don't await)
|
||||
fetchMultisubData().then((data) => {
|
||||
const freshMetadata: MultisubMetadata = {
|
||||
title: data.title,
|
||||
description: data.description,
|
||||
createdAt: data.createdAt,
|
||||
updatedAt: data.updatedAt,
|
||||
};
|
||||
cacheMetadata = freshMetadata;
|
||||
setMetadata(freshMetadata);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// No cache, fetch fresh data
|
||||
const multisub = await fetchMultisubData();
|
||||
const metadata: MultisubMetadata = {
|
||||
title: multisub.title,
|
||||
description: multisub.description,
|
||||
createdAt: multisub.createdAt,
|
||||
updatedAt: multisub.updatedAt,
|
||||
};
|
||||
cacheMetadata = metadata;
|
||||
setMetadata(metadata);
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
console.warn('Failed to load metadata, using vendored fallback:', e);
|
||||
// Fallback to vendored data
|
||||
const fallbackData = defaultSubplebbitsData as MultisubData;
|
||||
const metadata: MultisubMetadata = {
|
||||
title: fallbackData.title,
|
||||
description: fallbackData.description,
|
||||
createdAt: fallbackData.createdAt,
|
||||
updatedAt: fallbackData.updatedAt,
|
||||
};
|
||||
cacheMetadata = metadata;
|
||||
setMetadata(metadata);
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
|
||||
Reference in New Issue
Block a user