Initial commit: itinova-podcasts v1
Stack: Node.js/Express + React/Vite + tRPC + MySQL (Drizzle ORM) Features: Gestion de podcasts, établissements, mots-clés, upload audio S3 Migrations: 0000-0002 (users, etablissements, mots_cles, podcasts, podcast_mots_cles)
This commit is contained in:
102
server/_core/index.ts
Normal file
102
server/_core/index.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import "dotenv/config";
|
||||
import express from "express";
|
||||
import { createServer } from "http";
|
||||
import net from "net";
|
||||
import { createExpressMiddleware } from "@trpc/server/adapters/express";
|
||||
import { registerOAuthRoutes } from "./oauth";
|
||||
import { appRouter } from "../routers";
|
||||
import { createContext } from "./context";
|
||||
import { serveStatic, setupVite } from "./vite";
|
||||
import { storagePut } from "../storage";
|
||||
import { nanoid } from "nanoid";
|
||||
import { sdk } from "./sdk";
|
||||
|
||||
function isPortAvailable(port: number): Promise<boolean> {
|
||||
return new Promise(resolve => {
|
||||
const server = net.createServer();
|
||||
server.listen(port, () => {
|
||||
server.close(() => resolve(true));
|
||||
});
|
||||
server.on("error", () => resolve(false));
|
||||
});
|
||||
}
|
||||
|
||||
async function findAvailablePort(startPort: number = 3000): Promise<number> {
|
||||
for (let port = startPort; port < startPort + 20; port++) {
|
||||
if (await isPortAvailable(port)) {
|
||||
return port;
|
||||
}
|
||||
}
|
||||
throw new Error(`No available port found starting from ${startPort}`);
|
||||
}
|
||||
|
||||
async function startServer() {
|
||||
const app = express();
|
||||
const server = createServer(app);
|
||||
app.use(express.json({ limit: "60mb" }));
|
||||
app.use(express.urlencoded({ limit: "60mb", extended: true }));
|
||||
|
||||
// OAuth callback under /api/oauth/callback
|
||||
registerOAuthRoutes(app);
|
||||
|
||||
// Route d'upload audio (base64 → S3)
|
||||
app.post("/api/upload-audio", async (req, res) => {
|
||||
try {
|
||||
let user;
|
||||
try { user = await sdk.authenticateRequest(req); } catch { user = null; }
|
||||
if (!user) {
|
||||
res.status(401).json({ error: "Non authentifié" });
|
||||
return;
|
||||
}
|
||||
|
||||
const { data, contentType, filename } = req.body as {
|
||||
data: string;
|
||||
contentType: string;
|
||||
filename: string;
|
||||
};
|
||||
|
||||
if (!data || !contentType) {
|
||||
res.status(400).json({ error: "Données manquantes" });
|
||||
return;
|
||||
}
|
||||
|
||||
const ext = filename?.split(".").pop() ?? "mp3";
|
||||
const key = `podcasts/audio/${nanoid()}.${ext}`;
|
||||
const buffer = Buffer.from(data, "base64");
|
||||
|
||||
const { url } = await storagePut(key, buffer, contentType);
|
||||
res.json({ key, url });
|
||||
} catch (err: any) {
|
||||
console.error("[upload-audio]", err);
|
||||
res.status(500).json({ error: err.message ?? "Erreur serveur" });
|
||||
}
|
||||
});
|
||||
|
||||
// tRPC API
|
||||
app.use(
|
||||
"/api/trpc",
|
||||
createExpressMiddleware({
|
||||
router: appRouter,
|
||||
createContext,
|
||||
})
|
||||
);
|
||||
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
await setupVite(app, server);
|
||||
} else {
|
||||
serveStatic(app);
|
||||
}
|
||||
|
||||
const preferredPort = parseInt(process.env.PORT || "3000");
|
||||
const port = await findAvailablePort(preferredPort);
|
||||
|
||||
if (port !== preferredPort) {
|
||||
console.log(`Port ${preferredPort} is busy, using port ${port} instead`);
|
||||
}
|
||||
|
||||
server.listen(port, () => {
|
||||
console.log(`Server running on http://localhost:${port}/`);
|
||||
});
|
||||
}
|
||||
|
||||
startServer().catch(console.error);
|
||||
Reference in New Issue
Block a user