pasteboard/server.js
2025-04-11 00:51:29 +02:00

103 lines
3.2 KiB
JavaScript

// Import necessary modules
const express = require('express');
const path = require('path');
// --- Configuration ---
const PORT = process.env.PORT || 3000; // Use environment variable or default to 3000
const PASTE_TTL_HOURS = 2;
const PASTE_TTL_MS = PASTE_TTL_HOURS * 60 * 60 * 1000; // Time-to-live in milliseconds
// --- In-Memory Storage ---
// Using a Map for efficient key-based storage and deletion
const pastes = new Map(); // Stores { id: content }
// --- Express App Setup ---
const app = express();
// Middleware to parse plain text request bodies (like Hastebin)
// Limit set to 1MB, adjust as needed
app.use(express.text({ limit: '1mb', type: 'text/plain' }));
app.use(express.json()); // For JSON API responses
// Serve static files from the 'public' directory
app.use(express.static('public'));
// Function to generate a unique ID without crypto
function generateUniqueId() {
const timestamp = Date.now().toString(36);
const randomPart = Math.random().toString(36).substring(2, 10);
return `${timestamp}-${randomPart}`;
}
// --- API Routes ---
/**
* POST /api/pastes
* Creates a new paste.
* Expects the raw text content in the request body.
* Responds with the generated ID for the paste.
*/
app.post('/api/pastes', (req, res) => {
const content = req.body;
// Basic validation: Ensure content is present and is a string
if (!content || typeof content !== 'string' || content.trim() === '') {
return res.status(400).json({ error: 'Paste content cannot be empty.' });
}
// Generate a unique ID without using crypto
const id = generateUniqueId();
// Store the paste content in the map
pastes.set(id, content);
console.log(`[${new Date().toISOString()}] Paste created with ID: ${id}`);
// Schedule the paste for deletion after the TTL
setTimeout(() => {
if (pastes.has(id)) {
pastes.delete(id);
console.log(`[${new Date().toISOString()}] Paste expired and deleted: ${id}`);
}
}, PASTE_TTL_MS);
// Respond with the ID
res.status(201).json({ id: id });
});
/**
* GET /api/pastes/:id
* Retrieves the content of a specific paste by its ID.
* Responds with the raw text content or 404 if not found.
*/
app.get('/api/pastes/:id', (req, res) => {
const id = req.params.id;
if (pastes.has(id)) {
const content = pastes.get(id);
// Send raw text content
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
res.status(200).send(content);
} else {
res.status(404).json({ error: 'Paste not found or has expired.' });
}
});
// Serve the main HTML page for all other routes
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'public', 'index.html'));
});
// --- Start Server ---
app.listen(PORT, () => {
console.log(`Paste server listening on port ${PORT}`);
console.log(`Pastes will be stored for ${PASTE_TTL_HOURS} hours.`);
console.log(`Open http://localhost:${PORT} in your browser to use the application`);
});
// --- Graceful Shutdown (Optional but Recommended) ---
// Handles CTRL+C in the terminal
process.on('SIGINT', () => {
console.log('\nShutting down server...');
// Perform any cleanup here if needed (though in-memory storage is lost anyway)
process.exit(0);
});