import { Injectable } from "@nestjs/common"; import { InjectRepository } from "@nestjs/typeorm"; import { DatabaseNode } from "../entities/database.node.entity"; import { Repository } from "typeorm"; import { DatabaseEncryptionService } from "../database.encryption.service"; import * as mysql from "mysql2/promise"; @Injectable() export class DatabaseNodeService extends DatabaseEncryptionService { constructor( @InjectRepository(DatabaseNode) private databaseNodeRepository: Repository ) { super(); } async findById(id: string): Promise { return this.databaseNodeRepository.findOne({ where: { id } }); } async findOptimalNode(): Promise { const nodes = await this.databaseNodeRepository.find({ relations: ["databases"], }); if (nodes.length === 0) { return null; } nodes.sort((a, b) => a.databases.length - b.databases.length); return nodes[0]; } async initDatabase( data: { database: string; c_username: string; q_username: string; password: string; }, databaseNodeId: string ): Promise { try { const dbConnection = await mysql.createConnection({ ...(await this.getConnectionOptions(databaseNodeId)), enableKeepAlive: true, }); await dbConnection.execute(`CREATE DATABASE \`${data.database}\`;`); await dbConnection.execute( `CREATE USER '${data.c_username}'@'%' IDENTIFIED BY '${data.password}';` ); await dbConnection.execute( `CREATE USER '${data.q_username}'@'%' IDENTIFIED BY '${data.password}';` ); await dbConnection.execute( `GRANT ALL PRIVILEGES ON \`${data.database}\`.* TO '${data.c_username}'@'%';` ); await dbConnection.execute( `GRANT SELECT, SHOW VIEW ON \`${data.database}\`.* TO '${data.q_username}'@'%';` ); await dbConnection.execute(`FLUSH PRIVILEGES;`); await dbConnection.end(); } catch (error) { console.error("Error initializing database:", error); throw error; } } async create( host: string, port: number, username: string, password: string ): Promise { const existingNode = await this.databaseNodeRepository.findOne({ where: { host, port }, }); if (existingNode) { existingNode.password = this.encryptPassword(password); existingNode.username = username; return this.databaseNodeRepository.save(existingNode); } const encryptedPassword = this.encryptPassword(password); const databaseNode = this.databaseNodeRepository.create({ host, port, username, password: encryptedPassword, }); return this.databaseNodeRepository.save(databaseNode); } async getConnectionOptions(id: string) { const node = await this.databaseNodeRepository.findOne({ where: { id } }); if (!node) { throw new Error("Database node not found"); } return { host: node.host, port: node.port, user: node.username, password: this.decryptPassword(node.password), }; } }