const mongoose = require('mongoose'); const logger = require('./logger'); const bcrypt = require('bcrypt'); const MONGODB_URI = process.env.MONGODB_URI || 'mongodb://localhost:27017/stremio-manager'; // Connection options const options = { useNewUrlParser: true, useUnifiedTopology: true, serverSelectionTimeoutMS: 5000, socketTimeoutMS: 45000, }; // Create connection let db; async function connectDB() { try { if (!db) { db = await mongoose.connect(MONGODB_URI, options); logger.info('MongoDB connected successfully'); } return db; } catch (error) { logger.error('MongoDB connection error:', error); throw error; } } // Initialize connection before starting server async function initializeDB() { await connectDB(); } mongoose.connection.on('error', err => { logger.error('MongoDB error:', err); }); mongoose.connection.on('disconnected', () => { logger.warn('MongoDB disconnected. Attempting to reconnect...'); connectDB(); }); // Define schemas const userSchema = new mongoose.Schema({ email: { type: String, required: true, unique: true }, password: { type: String, required: true }, lastSync: Date, managedBy: { type: String, required: true } }); // Hash the password before saving it userSchema.pre('save', async function(next) { if (this.isModified('password')) { this.password = await bcrypt.hash(this.password, 10); } next(); }); const addonSchema = new mongoose.Schema({ transportUrl: { type: String, required: true }, transportName: { type: String, default: 'http' }, manifest: { id: String, name: String, version: String, description: String, logo: String, icon: String }, flags: { type: Map, of: Boolean }, userEmail: { type: String, required: true } }); const catalogSchema = new mongoose.Schema({ userEmail: { type: String, required: true }, addons: [{ transportUrl: String, transportName: String, manifest: { id: String, name: String, version: String, description: String, logo: String, icon: String }, flags: { type: Map, of: Boolean } }] }); // Create models const User = mongoose.model('User', userSchema); const Addon = mongoose.model('Addon', addonSchema); const Catalog = mongoose.model('Catalog', catalogSchema); // Database helper functions async function ensureUserDatabases(email) { const catalog = await Catalog.findOne({ userEmail: email }); if (!catalog) { await Catalog.create({ userEmail: email, addons: [] }); } } async function readDatabase(email) { const addons = await Addon.find({ userEmail: email }); return addons; } async function writeDatabase(email, data) { await Addon.deleteMany({ userEmail: email }); if (data.length > 0) { const addonsWithUser = data.map(addon => ({ ...addon, userEmail: email })); await Addon.insertMany(addonsWithUser); } logger.debug('Database updated successfully'); } async function readUsersDatabase(email) { const users = await User.find({ managedBy: email }); return users.map(user => ({ email: user.email, password: user.password, lastSync: user.lastSync })); } async function writeUsersDatabase(email, data) { await User.deleteMany({ managedBy: email }); if (data.length > 0) { const usersWithManager = data.map(user => ({ ...user, managedBy: email })); await User.insertMany(usersWithManager); } logger.debug('Users database updated successfully'); } async function writeCatalog(email, catalogs) { await Catalog.findOneAndUpdate( { userEmail: email }, { addons: catalogs }, { upsert: true } ); } async function readCatalog(email) { const catalog = await Catalog.findOne({ userEmail: email }); return catalog ? catalog.addons : []; } module.exports = { connectDB, initializeDB, ensureUserDatabases, readDatabase, writeDatabase, readUsersDatabase, writeUsersDatabase, writeCatalog, readCatalog, models: { User, Addon, Catalog } };