const express = require('express'); const cors = require('cors'); const fetch = require('node-fetch'); const bodyParser = require('body-parser'); const app = express(); const PORT = 7860; // Default port for Hugging Face Spaces // --- CONFIGURATION --- // These tokens must be set in your Space Settings -> Variables and secrets const STORAGE_POOLS = [ { repo: "abhy60098/MY-STORAGE", token: process.env.HF_TOKEN_1 }, { repo: "sushmasinharnc/MY-STORAGE", token: process.env.HF_TOKEN_2 }, { repo: "shuarya2011/MY-STORAGE", token: process.env.HF_TOKEN_3 } ]; const DB_FILE = "db.json"; // --- MIDDLEWARE --- app.use(cors()); // Allows any website to connect app.use(bodyParser.json({ limit: '50mb' })); // Allows large image uploads // --- ROUTES --- // 1. Health Check / Home Page app.get('/', (req, res) => { res.send(`

🚀 Distributed Storage API is Online

Status: Connected to ${STORAGE_POOLS.length} Storage Pools

Use /posts (GET) to fetch data and /posts (POST) to upload.

`); }); // 2. GET: Fetch data from all 3 datasets and merge them app.get('/posts', async (req, res) => { try { const allResults = await Promise.all(STORAGE_POOLS.map(async (pool) => { // We check if the token exists before calling if (!pool.token) return []; const url = `https://huggingface.co/api/datasets/${pool.repo}/raw/main/${DB_FILE}`; const response = await fetch(url, { headers: { Authorization: `Bearer ${pool.token}` } }); if (response.ok) { const data = await response.json(); return data.posts || []; } return []; // Return empty if file doesn't exist yet })); // Flatten the array of arrays and sort by ID (timestamp) descending const mergedPosts = allResults.flat().sort((a, b) => b.id - a.id); res.json(mergedPosts); } catch (err) { console.error("GET Error:", err); res.status(500).json({ error: "Failed to fetch posts from pools." }); } }); // 3. POST: Upload image and update database in a random pool app.post('/posts', async (req, res) => { try { const { username, caption, imageBase64, fileName } = req.body; if (!imageBase64 || !username) { return res.status(400).json({ error: "Missing required fields (username or image)." }); } // Pick a random pool to distribute storage usage const pool = STORAGE_POOLS[Math.floor(Math.random() * STORAGE_POOLS.length)]; if (!pool.token) { return res.status(500).json({ error: "Storage pool token not configured in Secrets." }); } const timestamp = Date.now(); const imagePath = `uploads/${timestamp}-${fileName}`; // A. Upload the Image file const uploadImageUrl = `https://huggingface.co/api/datasets/${pool.repo}/upload/main/${imagePath}`; const imageUploadRes = await fetch(uploadImageUrl, { method: 'POST', headers: { Authorization: `Bearer ${pool.token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ content: imageBase64, // Expecting raw base64 string message: `Upload image from ${username}` }) }); if (!imageUploadRes.ok) { const errorText = await imageUploadRes.text(); throw new Error(`Image Upload Failed: ${errorText}`); } const finalImageUrl = `https://huggingface.co/datasets/${pool.repo}/resolve/main/${imagePath}`; // B. Fetch existing db.json from the SAME pool const dbUrl = `https://huggingface.co/api/datasets/${pool.repo}/raw/main/${DB_FILE}`; const dbRes = await fetch(dbUrl, { headers: { Authorization: `Bearer ${pool.token}` } }); let db = { posts: [] }; if (dbRes.ok) { db = await dbRes.json(); } // C. Add new post to the beginning of the list db.posts.unshift({ id: timestamp, username, caption, imageUrl: finalImageUrl, pool: pool.repo }); // D. Upload the updated db.json back to Hugging Face const updateDbUrl = `https://huggingface.co/api/datasets/${pool.repo}/upload/main/${DB_FILE}`; const dbUploadRes = await fetch(updateDbUrl, { method: 'POST', headers: { Authorization: `Bearer ${pool.token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ content: Buffer.from(JSON.stringify(db, null, 2)).toString('base64'), message: "Update database JSON" }) }); if (!dbUploadRes.ok) throw new Error("Database update failed."); res.status(201).json({ success: true, imageUrl: finalImageUrl }); } catch (err) { console.error("POST Error:", err); res.status(500).json({ error: err.message }); } }); // Start the server app.listen(PORT, () => { console.log(`Server is running on http://localhost:${PORT}`); });