114 lines
2.9 KiB
JavaScript
114 lines
2.9 KiB
JavaScript
const NodeCache = require('node-cache');
|
|
const config = require('../config');
|
|
const { IPFS_GATEWAY, CACHE_ENABLED, CACHE_TTL_SECONDS } = config;
|
|
|
|
// Setup cache
|
|
const cache = new NodeCache({
|
|
stdTTL: CACHE_TTL_SECONDS,
|
|
checkperiod: CACHE_TTL_SECONDS * 0.2,
|
|
});
|
|
|
|
// MIME type mapping helper
|
|
const mimeTypes = {
|
|
'.html': 'text/html',
|
|
'.css': 'text/css',
|
|
'.js': 'application/javascript',
|
|
'.json': 'application/json',
|
|
'.png': 'image/png',
|
|
'.jpg': 'image/jpeg',
|
|
'.jpeg': 'image/jpeg',
|
|
'.gif': 'image/gif',
|
|
'.svg': 'image/svg+xml',
|
|
'.pdf': 'application/pdf',
|
|
'.txt': 'text/plain'
|
|
};
|
|
|
|
/**
|
|
* Fetch content from IPFS by CID and path
|
|
* @param {string} cid - IPFS Content Identifier
|
|
* @param {string} path - Optional path within the CID
|
|
* @returns {Promise<{data: Buffer, mimeType: string}|null>} - Content and MIME type or null
|
|
*/
|
|
async function fetchFromIpfs(cid, path = '') {
|
|
const contentPath = path ? `${cid}/${path}` : cid;
|
|
|
|
// Check cache first
|
|
if (CACHE_ENABLED) {
|
|
const cachedContent = cache.get(`ipfs:${contentPath}`);
|
|
if (cachedContent) {
|
|
console.log(`Cache hit for IPFS content: ${contentPath}`);
|
|
return cachedContent;
|
|
}
|
|
}
|
|
|
|
try {
|
|
// Use the HTTP gateway directly instead of the IPFS client
|
|
const result = await fetchViaGateway(cid, path);
|
|
|
|
if (!result) {
|
|
return null;
|
|
}
|
|
|
|
// Determine MIME type if not set
|
|
if (!result.mimeType) {
|
|
result.mimeType = getMimeType(path);
|
|
}
|
|
|
|
// Cache the result
|
|
if (CACHE_ENABLED) {
|
|
cache.set(`ipfs:${contentPath}`, result);
|
|
}
|
|
|
|
return result;
|
|
} catch (error) {
|
|
console.error(`Error fetching ${contentPath} from IPFS:`, error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fetch content via IPFS HTTP gateway
|
|
* @param {string} cid - IPFS Content Identifier
|
|
* @param {string} path - Path within the CID
|
|
* @returns {Promise<{data: Buffer, mimeType: string}|null>} - Content and MIME type or null
|
|
*/
|
|
async function fetchViaGateway(cid, path) {
|
|
try {
|
|
const url = new URL(`${IPFS_GATEWAY}/ipfs/${cid}${path ? '/' + path : ''}`);
|
|
console.log(`Fetching from IPFS gateway: ${url}`);
|
|
|
|
const response = await fetch(url);
|
|
|
|
if (!response.ok) {
|
|
console.error(`Gateway returned ${response.status} for ${url}`);
|
|
return null;
|
|
}
|
|
|
|
const data = Buffer.from(await response.arrayBuffer());
|
|
const mimeType = response.headers.get('content-type');
|
|
|
|
return { data, mimeType };
|
|
} catch (error) {
|
|
console.error('Gateway fetch error:', error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Determine MIME type from file path
|
|
* @param {string} path - File path
|
|
* @returns {string} - MIME type or default
|
|
*/
|
|
function getMimeType(path) {
|
|
if (!path) return 'application/octet-stream';
|
|
|
|
const extension = path.split('.').pop();
|
|
if (!extension) return 'application/octet-stream';
|
|
|
|
return mimeTypes['.' + extension] || 'application/octet-stream';
|
|
}
|
|
|
|
module.exports = {
|
|
fetchFromIpfs
|
|
};
|