mirror of
https://github.com/yusufipk/OpenFrame.git
synced 2026-09-11 09:36:08 +00:00
feat: add video watch progress tracking with resume functionality
Implements a complete watch progress system that allows users to: - Save playback position automatically every 5 seconds while watching - Resume from last position when returning to a video - Save progress on page leave using sendBeacon for reliability Also includes: - Optimized slug generation in projects and workspaces APIs (single query vs loop) - Added isActive filter to version queries across all video endpoints - Added pagination support for video and comment queries - Enhanced database pool management with connection limits and graceful shutdown - New WatchProgress Prisma model with user-version relations
This commit is contained in:
@@ -1,11 +1,52 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import { PrismaPg } from '@prisma/adapter-pg';
|
||||
import { Pool } from 'pg';
|
||||
import { Pool, PoolConfig } from 'pg';
|
||||
|
||||
const globalForPrisma = globalThis as unknown as {
|
||||
prisma: PrismaClient | undefined;
|
||||
};
|
||||
|
||||
const globalForPool = globalThis as unknown as {
|
||||
pgPool: Pool | undefined;
|
||||
};
|
||||
|
||||
function createPool(connectionString: string): Pool {
|
||||
// Prevent multiple pools from being created during development (Next.js hot reload)
|
||||
if (globalForPool.pgPool) {
|
||||
return globalForPool.pgPool;
|
||||
}
|
||||
|
||||
const poolConfig: PoolConfig = {
|
||||
connectionString,
|
||||
max: 20, // Maximum number of connections
|
||||
idleTimeoutMillis: 30000, // Close idle connections after 30 seconds
|
||||
connectionTimeoutMillis: 5000, // Return error after 5 seconds if can't connect
|
||||
};
|
||||
|
||||
const pool = new Pool(poolConfig);
|
||||
|
||||
// Add error handling for pool errors
|
||||
pool.on('error', (err, client) => {
|
||||
console.error('Unexpected database pool error:', err.message);
|
||||
// Don't crash the app on unexpected pool errors
|
||||
});
|
||||
|
||||
pool.on('connect', () => {
|
||||
console.debug('New database connection established');
|
||||
});
|
||||
|
||||
pool.on('acquire', () => {
|
||||
console.debug('Connection acquired from pool');
|
||||
});
|
||||
|
||||
// Store pool globally to prevent multiple instances during development
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
globalForPool.pgPool = pool;
|
||||
}
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
function createPrismaClient() {
|
||||
// In development without a database, we'll create a mock-friendly client
|
||||
// For production or when DATABASE_URL is set, use the real adapter
|
||||
@@ -14,13 +55,14 @@ function createPrismaClient() {
|
||||
if (!connectionString) {
|
||||
console.warn('DATABASE_URL not set - database features will not work');
|
||||
// Return a client that will throw clear errors when used
|
||||
const pool = createPool('postgresql://localhost:5432/dummy');
|
||||
return new PrismaClient({
|
||||
// This will fail on actual DB operations but allows imports to work
|
||||
adapter: new PrismaPg(new Pool({ connectionString: 'postgresql://localhost:5432/dummy' })),
|
||||
adapter: new PrismaPg(pool),
|
||||
});
|
||||
}
|
||||
|
||||
const pool = new Pool({ connectionString });
|
||||
const pool = createPool(connectionString);
|
||||
const adapter = new PrismaPg(pool);
|
||||
|
||||
return new PrismaClient({
|
||||
@@ -35,4 +77,21 @@ if (process.env.NODE_ENV !== 'production') {
|
||||
globalForPrisma.prisma = db;
|
||||
}
|
||||
|
||||
// Graceful shutdown handler
|
||||
async function shutdown() {
|
||||
console.log('Shutting down database connections...');
|
||||
|
||||
if (globalForPool.pgPool) {
|
||||
await globalForPool.pgPool.end();
|
||||
console.log('Database pool closed');
|
||||
}
|
||||
|
||||
await db.$disconnect();
|
||||
console.log('Prisma client disconnected');
|
||||
}
|
||||
|
||||
// Register shutdown handlers
|
||||
process.on('SIGINT', shutdown);
|
||||
process.on('SIGTERM', shutdown);
|
||||
|
||||
export default db;
|
||||
|
||||
Reference in New Issue
Block a user