Spaces:
Sleeping
Sleeping
File size: 4,999 Bytes
4befee3 28268ed 4befee3 28268ed 4befee3 28268ed 6042f7c 4befee3 28268ed 4befee3 28268ed 6042f7c 28268ed 4befee3 28268ed 7dd4a60 4befee3 28268ed 4befee3 28268ed 4befee3 28268ed 4befee3 28268ed 4befee3 28268ed 4befee3 28268ed 4befee3 28268ed 4befee3 28268ed 4befee3 1a8b559 28268ed 4befee3 28268ed 4befee3 28268ed 4befee3 28268ed 4befee3 28268ed 4befee3 28268ed 4befee3 28268ed 4befee3 28268ed 4befee3 28268ed 4befee3 28268ed 4befee3 28268ed 4befee3 28268ed 7dd4a60 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | 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(`
<div style="font-family: sans-serif; text-align: center; margin-top: 50px;">
<h1>🚀 Distributed Storage API is Online</h1>
<p>Status: <b>Connected to ${STORAGE_POOLS.length} Storage Pools</b></p>
<p>Use <code>/posts</code> (GET) to fetch data and <code>/posts</code> (POST) to upload.</p>
</div>
`);
});
// 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}`);
}); |