initial commit

This commit is contained in:
Bhavnoor Singh Saroya 2025-01-07 04:45:03 -08:00
commit b25eb51ff0
280 changed files with 178550 additions and 0 deletions

2
uploader-service/.env Normal file
View file

@ -0,0 +1,2 @@
FLY_API_BASE_URL=https://api.fly.io
FLY_API_TOKEN=your-api-token

176
uploader-service/app.js Normal file
View file

@ -0,0 +1,176 @@
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}`);
});

View file

@ -0,0 +1,8 @@
# uploader microservice
- handle uploads and registration to:
1. fly vms with snakes and brains(json)
2. google drive folders
3. google sheet link population
4. battlesnake.com for snake registration with our links
- handle backend logic for multiple uploads, errors, reuploads, etc
- connect with appscript or sheets api for autopopulation