176 lines
4.9 KiB
JavaScript
176 lines
4.9 KiB
JavaScript
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}`);
|
|
});
|