import express from "express"; import dotenv from "dotenv"; import axios from "axios"; import { Buffer } from "buffer"; dotenv.config(); const app = express(); const PORT = process.env.PORT || 7860; app.use(express.json({ limit: "10mb" })); app.use(express.urlencoded({ extended: true })); // GitHub Configuration const GITHUB_TOKEN = process.env.GITHUB_TOKEN || "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"; const GITHUB_OWNER = process.env.GITHUB_OWNER || "Atlastech45"; const GITHUB_REPO = process.env.GITHUB_REPO || "Session_3"; const GITHUB_BRANCH = process.env.GITHUB_BRANCH || "main"; // GitHub API base URL const GITHUB_API = "https://api.github.com"; const BASE_PATH = "sessions"; // Folder where sessions will be stored // Create axios instance with auth headers const githubApi = axios.create({ baseURL: GITHUB_API, headers: { Authorization: `token ${GITHUB_TOKEN}`, Accept: "application/vnd.github.v3+json", "User-Agent": "Session_3" } }); // Helper: Check if file exists in GitHub async function fileExists(sessionId, filename) { try { const path = `${BASE_PATH}/session_${sessionId}/${filename}`; const response = await githubApi.get(`/repos/${GITHUB_OWNER}/${GITHUB_REPO}/contents/${path}`, { params: { ref: GITHUB_BRANCH } }); return { exists: true, sha: response.data.sha }; } catch (error) { if (error.response?.status === 404) { return { exists: false, sha: null }; } throw error; } } // Helper: Upload file to GitHub async function uploadToGitHub(sessionId, filename, content, sha = null) { try { const path = `${BASE_PATH}/session_${sessionId}/${filename}`; const message = sha ? `Update ${filename} for session ${sessionId}` : `Create ${filename} for session ${sessionId}`; const payload = { message, content: Buffer.from(JSON.stringify(content, null, 2)).toString("base64"), branch: GITHUB_BRANCH }; if (sha) { payload.sha = sha; } const response = await githubApi.put( `/repos/${GITHUB_OWNER}/${GITHUB_REPO}/contents/${path}`, payload ); return response.data; } catch (error) { console.error(`GitHub upload error for ${filename}:`, error.response?.data || error.message); throw error; } } // Helper: Download file from GitHub async function downloadFromGitHub(sessionId, filename) { try { const path = `${BASE_PATH}/session_${sessionId}/${filename}`; const response = await githubApi.get(`/repos/${GITHUB_OWNER}/${GITHUB_REPO}/contents/${path}`, { params: { ref: GITHUB_BRANCH } }); const content = Buffer.from(response.data.content, "base64").toString("utf-8"); return JSON.parse(content); } catch (error) { if (error.response?.status === 404) { return null; } throw error; } } // Helper: Delete file from GitHub async function deleteFromGitHub(sessionId, filename) { try { const fileInfo = await fileExists(sessionId, filename); if (!fileInfo.exists) { return false; } const path = `${BASE_PATH}/session_${sessionId}/${filename}`; await githubApi.delete(`/repos/${GITHUB_OWNER}/${GITHUB_REPO}/contents/${path}`, { data: { message: `Delete ${filename} for session ${sessionId}`, sha: fileInfo.sha, branch: GITHUB_BRANCH } }); return true; } catch (error) { console.error(`GitHub delete error for ${filename}:`, error.response?.data || error.message); throw error; } } // Helper: List all sessions async function listSessions() { try { // First, check if sessions folder exists try { const response = await githubApi.get(`/repos/${GITHUB_OWNER}/${GITHUB_REPO}/contents/${BASE_PATH}`, { params: { ref: GITHUB_BRANCH } }); const sessions = response.data .filter(item => item.type === "dir" && item.name.startsWith("session_")) .map(item => item.name.replace("session_", "")); return sessions; } catch (error) { if (error.response?.status === 404) { // Sessions folder doesn't exist yet return []; } throw error; } } catch (error) { console.error("List sessions error:", error); throw error; } } // -------------------- ROUTES -------------------- // // Health check app.get("/ping", (req, res) => res.json({ status: "ok", storage: "GitHub", repo: `${GITHUB_OWNER}/${GITHUB_REPO}` })); // Upload/Update session with both creds and settings app.post("/upload", async (req, res) => { try { const { sessionId, creds, settings } = req.body; if (!sessionId || !creds) { return res.status(400).json({ error: "sessionId and creds are required" }); } // Check if creds.json exists const credsInfo = await fileExists(sessionId, "creds.json"); // Upload/Update creds.json await uploadToGitHub(sessionId, "creds.json", creds, credsInfo.sha); // Upload/Update settings.json const settingsToSave = settings || getDefaultSettings(); const settingsInfo = await fileExists(sessionId, "settings.json"); await uploadToGitHub(sessionId, "settings.json", settingsToSave, settingsInfo.sha); console.log(`✅ ${credsInfo.exists ? 'Updated' : 'Created'} session ${sessionId} in GitHub`); res.json({ success: true, message: `Session ${sessionId} ${credsInfo.exists ? 'updated' : 'created'}.`, timestamp: new Date().toISOString(), storage: "github", repo: `${GITHUB_OWNER}/${GITHUB_REPO}` }); } catch (err) { console.error("Upload error:", err); res.status(500).json({ error: "Failed to upload session", details: err.message }); } }); // Update session (explicit overwrite) app.put("/session/:id", async (req, res) => { try { const sessionId = req.params.id; const { creds, settings } = req.body; if (!creds) { return res.status(400).json({ error: "creds are required" }); } // Check if session exists const credsInfo = await fileExists(sessionId, "creds.json"); if (!credsInfo.exists) { return res.status(404).json({ error: "Session not found" }); } // Force update creds.json await uploadToGitHub(sessionId, "creds.json", creds, credsInfo.sha); // Force update settings.json const settingsToSave = settings || getDefaultSettings(); const settingsInfo = await fileExists(sessionId, "settings.json"); await uploadToGitHub(sessionId, "settings.json", settingsToSave, settingsInfo.exists ? settingsInfo.sha : null); console.log(`🔄 Force-updated session ${sessionId} in GitHub`); res.json({ success: true, message: `Session ${sessionId} force-updated.`, timestamp: new Date().toISOString() }); } catch (err) { console.error("Update error:", err); res.status(500).json({ error: "Failed to update session", details: err.message }); } }); // Download session with both creds and settings app.get("/session/:id", async (req, res) => { try { const sessionId = req.params.id; const files = {}; // Download creds.json const creds = await downloadFromGitHub(sessionId, "creds.json"); if (!creds) { return res.status(404).json({ error: "Session creds not found" }); } files["creds.json"] = creds; // Download settings.json if exists const settings = await downloadFromGitHub(sessionId, "settings.json"); files["settings.json"] = settings || getDefaultSettings(); res.json({ sessionId, files, storage: "github", repo: `${GITHUB_OWNER}/${GITHUB_REPO}` }); } catch (err) { console.error("Download error:", err); res.status(404).json({ error: "Session not found", details: err.message }); } }); // Delete session (both creds and settings) app.delete("/session/:id", async (req, res) => { try { const sessionId = req.params.id; // Delete both files const credsDeleted = await deleteFromGitHub(sessionId, "creds.json"); const settingsDeleted = await deleteFromGitHub(sessionId, "settings.json"); if (!credsDeleted && !settingsDeleted) { return res.status(404).json({ error: "Session not found" }); } console.log(`🗑 Deleted session ${sessionId} from GitHub`); res.json({ success: true, message: `Session ${sessionId} deleted.`, credsDeleted, settingsDeleted }); } catch (err) { console.error("Delete error:", err); res.status(500).json({ error: "Failed to delete session", details: err.message }); } }); // List all sessions app.get("/sessions", async (req, res) => { try { const sessions = await listSessions(); res.json({ sessions, count: sessions.length, storage: "github", repo: `${GITHUB_OWNER}/${GITHUB_REPO}` }); } catch (err) { console.error("List sessions error:", err); res.status(500).json({ error: "Failed to list sessions", details: err.message }); } }); // Get session info app.get("/session/:id/info", async (req, res) => { try { const sessionId = req.params.id; // Check if session exists const credsInfo = await fileExists(sessionId, "creds.json"); if (!credsInfo.exists) { return res.status(404).json({ error: "Session not found" }); } // Get commit history for the session folder try { const response = await githubApi.get(`/repos/${GITHUB_OWNER}/${GITHUB_REPO}/commits`, { params: { path: `${BASE_PATH}/session_${sessionId}`, per_page: 1 } }); if (response.data.length > 0) { const lastCommit = response.data[0]; res.json({ sessionId, lastModified: lastCommit.commit.committer.date, author: lastCommit.commit.author.name, message: lastCommit.commit.message, storage: "github" }); } else { res.json({ sessionId, message: "No commit history found", storage: "github" }); } } catch (commitError) { res.json({ sessionId, message: "Session exists but no commit info available", storage: "github" }); } } catch (err) { console.error("Session info error:", err); res.status(500).json({ error: "Failed to get session info", details: err.message }); } }); // Test GitHub connection app.get("/github-test", async (req, res) => { try { // Test repository access const repoResponse = await githubApi.get(`/repos/${GITHUB_OWNER}/${GITHUB_REPO}`); // Test creating a test file const testPath = "test-connection.txt"; const testContent = `Connection test at ${new Date().toISOString()}`; await githubApi.put( `/repos/${GITHUB_OWNER}/${GITHUB_REPO}/contents/${testPath}`, { message: "Test connection from session server", content: Buffer.from(testContent).toString("base64"), branch: GITHUB_BRANCH } ); // Delete the test file const fileInfo = await githubApi.get(`/repos/${GITHUB_OWNER}/${GITHUB_REPO}/contents/${testPath}`); await githubApi.delete(`/repos/${GITHUB_OWNER}/${GITHUB_REPO}/contents/${testPath}`, { data: { message: "Clean up test file", sha: fileInfo.data.sha, branch: GITHUB_BRANCH } }); res.json({ success: true, message: "GitHub connection test successful", repo: repoResponse.data.full_name, owner: repoResponse.data.owner.login, default_branch: repoResponse.data.default_branch, permissions: repoResponse.data.permissions }); } catch (error) { console.error("GitHub test error:", error.response?.data || error.message); res.status(500).json({ success: false, error: "GitHub connection failed", details: error.response?.data || error.message }); } }); // Helper function for default settings function getDefaultSettings() { return { autoreact: false, autostatusview: false, autostatusreact: false, autotype: false, autodelete: false, antilink: false, badwords: false, prefix: ".", language: "en", botmode: "public", autorecording: false }; } // -------------------- GLOBAL HANDLERS -------------------- // process.on("uncaughtException", (err) => console.error("Uncaught Exception:", err)); process.on("unhandledRejection", (err) => console.error("Unhandled Rejection:", err)); app.listen(PORT, '0.0.0.0', () => { console.log(`✅ Session server running on port ${PORT}`); console.log(`📁 Storage: GitHub (${GITHUB_OWNER}/${GITHUB_REPO})`); console.log(`🔑 Using token: ${GITHUB_TOKEN.substring(0, 10)}...`); });