const express = require('express'); const axios = require('axios'); const { google } = require('googleapis'); const multer = require('multer'); const upload = multer(); //include dotenv package require('dotenv').config(); const app = express(); app.use(express.json()); const PORT = process.env.PORT || 3000; const FLY_API_BASE_URL = process.env.FLY_API_BASE_URL const FLY_API_TOKEN = process.env.FLY_API_TOKEN //not from env at the moment const GOOGLE_API_CREDENTIALS = 'the_google_api_credentials.json'; let machinePool = []; // To store machine objects class Machine { constructor(id, ip) { this.id = id; this.ip = ip; } } // Helper function to initialize Google APIs async function initializeGoogleApis() { const auth = new google.auth.GoogleAuth({ keyFile: GOOGLE_API_CREDENTIALS, scopes: ['https://www.googleapis.com/auth/drive', 'https://www.googleapis.com/auth/spreadsheets'], }); return auth.getClient(); } // Helper function to create a machine async function createMachine() { const response = await axios.post( `${FLY_API_BASE_URL}/v1/machines`, { /* Add machine configuration here */ }, { headers: { Authorization: `Bearer ${FLY_API_TOKEN}` } } ); //look at all question marks, we are ensuring safety const machine = new Machine(response.data.id, response.data.config?.network?.ip_addresses); // Suspend the machine for now, we'll unsuspend when needed await axios.post( `${FLY_API_BASE_URL}/v1/machines/${machine.id}/suspend`, {}, { headers: { Authorization: `Bearer ${FLY_API_TOKEN}` } } ); return machine; } // Endpoint to create Fly machines asynchronously app.post('/machines/create', async (req, res) => { const { count = 1 } = req.body; res.sendStatus(200); // Respond immediately // Asynchronously create machines try { const promises = Array.from({ length: count }, createMachine); const results = await Promise.all(promises); machinePool.push(...results); } catch (error) { console.error('Error creating machines:', error); } }); // Endpoint to get a machine (or multiple machines) app.post('/machines/get', async (req, res) => { const { count = 1 } = req.body; const allocatedMachines = []; try { // Use existing machines first while (allocatedMachines.length < count && machinePool.length > 0) { allocatedMachines.push(machinePool.pop()); } // Create new machines if needed const needed = count - allocatedMachines.length; if (needed > 0) { const promises = Array.from({ length: needed }, createMachine); const results = await Promise.all(promises); allocatedMachines.push(...results); } res.json({ machines: allocatedMachines }); } catch (error) { console.error('Error retrieving machines:', error); res.status(500).json({ error: 'Failed to retrieve machines' }); } }); // Endpoint to upload files to Google Drive app.post('/drive/upload', upload.fields([{ name: 'pythonFile' }, { name: 'jsonFile', maxCount: 1 }]), async (req, res) => { const { folderLink } = req.body; const { pythonFile, jsonFile } = req.files; if (!folderLink || !pythonFile) { return res.status(400).json({ error: 'Folder link and Python file are required' }); } try { const driveClient = google.drive({ version: 'v3', auth: await initializeGoogleApis() }); const folderId = folderLink.split('/').pop(); // Extract folder ID from link const uploadFile = async (file, mimeType) => { const response = await driveClient.files.create({ requestBody: { name: file.originalname, parents: [folderId], }, media: { mimeType, body: Buffer.from(file.buffer), }, }); return response.data; }; const pythonResponse = await uploadFile(pythonFile[0], 'text/x-python'); let jsonResponse; if (jsonFile) { jsonResponse = await uploadFile(jsonFile[0], 'application/json'); } res.json({ pythonFileId: pythonResponse.id, jsonFileId: jsonResponse?.id, }); } catch (error) { console.error(error); res.status(500).json({ error: 'Failed to upload files' }); } }); // Endpoint to insert data into Google Sheets app.post('/sheets/insert', async (req, res) => { const { spreadsheetId, range, data } = req.body; if (!spreadsheetId || !range || !data) { return res.status(400).json({ error: 'Spreadsheet ID, range, and data are required' }); } try { const sheetsClient = google.sheets({ version: 'v4', auth: await initializeGoogleApis() }); await sheetsClient.spreadsheets.values.append({ spreadsheetId, range, valueInputOption: 'RAW', requestBody: { values: Array.isArray(data) ? data : [data], }, }); res.json({ success: true }); } catch (error) { console.error(error); res.status(500).json({ error: 'Failed to insert data into the sheet' }); } }); app.listen(PORT, () => { console.log(`Server is running on http://localhost:${PORT}`); });