From 061810585798a79a669f1cb09c0f1a04b8bb5f30 Mon Sep 17 00:00:00 2001 From: Patrik Braun Date: Thu, 20 Jul 2017 23:37:10 +0200 Subject: [PATCH] adding sqlite support, removing mysql required dependency --- backend/middlewares/AdminMWs.ts | 10 ++--- backend/model/ConfigDiagnostics.ts | 14 +++---- backend/model/ObjectManagerRepository.ts | 18 ++++----- .../model/{mysql => sql}/GalleryManager.ts | 6 +-- .../SQLConnection.ts} | 40 +++++++++++-------- backend/model/{mysql => sql}/SearchManager.ts | 8 ++-- .../model/{mysql => sql}/SharingManager.ts | 28 ++++++------- backend/model/{mysql => sql}/UserManager.ts | 12 +++--- .../enitites/DirectoryEntity.ts | 0 .../{mysql => sql}/enitites/PhotoEntity.ts | 0 .../{mysql => sql}/enitites/SharingEntity.ts | 0 .../{mysql => sql}/enitites/UserEntity.ts | 0 backend/server.ts | 4 +- common/config/private/IPrivateConfig.ts | 17 ++++++-- common/config/private/PrivateConfigClass.ts | 5 ++- .../database/database.settings.component.html | 8 ++++ package.json | 2 +- 17 files changed, 101 insertions(+), 71 deletions(-) rename backend/model/{mysql => sql}/GalleryManager.ts (97%) rename backend/model/{mysql/MySQLConnection.ts => sql/SQLConnection.ts} (74%) rename backend/model/{mysql => sql}/SearchManager.ts (96%) rename backend/model/{mysql => sql}/SharingManager.ts (84%) rename backend/model/{mysql => sql}/UserManager.ts (84%) rename backend/model/{mysql => sql}/enitites/DirectoryEntity.ts (100%) rename backend/model/{mysql => sql}/enitites/PhotoEntity.ts (100%) rename backend/model/{mysql => sql}/enitites/SharingEntity.ts (100%) rename backend/model/{mysql => sql}/enitites/UserEntity.ts (100%) diff --git a/backend/middlewares/AdminMWs.ts b/backend/middlewares/AdminMWs.ts index d17a491a..941b29dc 100644 --- a/backend/middlewares/AdminMWs.ts +++ b/backend/middlewares/AdminMWs.ts @@ -2,7 +2,7 @@ import {NextFunction, Request, Response} from "express"; import {ErrorCodes, ErrorDTO} from "../../common/entities/Error"; import {ObjectManagerRepository} from "../model/ObjectManagerRepository"; import {Logger} from "../Logger"; -import {MySQLConnection} from "../model/mysql/MySQLConnection"; +import {SQLConnection} from "../model/sql/SQLConnection"; import {DataBaseConfig, DatabaseType, ThumbnailConfig} from "../../common/config/private/IPrivateConfig"; import {Config} from "../../common/config/private/Config"; import {ConfigDiagnostics} from "../model/ConfigDiagnostics"; @@ -25,8 +25,8 @@ export class AdminMWs { const databaseSettings = req.body.settings; try { - if (databaseSettings.type == DatabaseType.mysql) { - await MySQLConnection.tryConnection(databaseSettings); + if (databaseSettings.type != DatabaseType.memory) { + await SQLConnection.tryConnection(databaseSettings); } Config.Server.database = databaseSettings; //only updating explicitly set config (not saving config set by the diagnostics) @@ -42,8 +42,8 @@ export class AdminMWs { Logger.info(LOG_TAG, JSON.stringify(Config, null, '\t')); ObjectManagerRepository.reset(); - if (Config.Server.database.type == DatabaseType.mysql) { - await ObjectManagerRepository.InitMySQLManagers(); + if (Config.Server.database.type != DatabaseType.memory) { + await ObjectManagerRepository.InitSQLManagers(); } else { await ObjectManagerRepository.InitMemoryManagers(); } diff --git a/backend/model/ConfigDiagnostics.ts b/backend/model/ConfigDiagnostics.ts index 40d33d02..e2e5ed9c 100644 --- a/backend/model/ConfigDiagnostics.ts +++ b/backend/model/ConfigDiagnostics.ts @@ -9,7 +9,7 @@ import { import {Logger} from "../Logger"; import {NotificationManager} from "./NotifocationManager"; import {ProjectPath} from "../ProjectPath"; -import {MySQLConnection} from "./mysql/MySQLConnection"; +import {SQLConnection} from "./sql/SQLConnection"; import * as fs from "fs"; import {ClientConfig} from "../../common/config/public/ConfigClass"; @@ -17,8 +17,8 @@ const LOG_TAG = "[ConfigDiagnostics]"; export class ConfigDiagnostics { static async testDatabase(databaseConfig: DataBaseConfig) { - if (databaseConfig.type == DatabaseType.mysql) { - await MySQLConnection.tryConnection(databaseConfig); + if (databaseConfig.type != DatabaseType.memory) { + await SQLConnection.tryConnection(databaseConfig); } } @@ -112,13 +112,13 @@ export class ConfigDiagnostics { static async runDiagnostics() { - if (Config.Server.database.type == DatabaseType.mysql) { + if (Config.Server.database.type != DatabaseType.memory) { try { await ConfigDiagnostics.testDatabase(Config.Server.database); } catch (err) { - Logger.warn(LOG_TAG, "[MYSQL error]", err); - Logger.warn(LOG_TAG, "Error during initializing mysql falling back temporally to memory DB"); - NotificationManager.warning("Error during initializing mysql falling back temporally to memory DB", err); + Logger.warn(LOG_TAG, "[SQL error]", err); + Logger.warn(LOG_TAG, "Error during initializing SQL falling back temporally to memory DB"); + NotificationManager.warning("Error during initializing SQL falling back temporally to memory DB", err); Config.setDatabaseType(DatabaseType.memory); } } diff --git a/backend/model/ObjectManagerRepository.ts b/backend/model/ObjectManagerRepository.ts index 54836113..42aec966 100644 --- a/backend/model/ObjectManagerRepository.ts +++ b/backend/model/ObjectManagerRepository.ts @@ -1,7 +1,7 @@ import {IUserManager} from "./interfaces/IUserManager"; import {IGalleryManager} from "./interfaces/IGalleryManager"; import {ISearchManager} from "./interfaces/ISearchManager"; -import {MySQLConnection} from "./mysql/MySQLConnection"; +import {SQLConnection} from "./sql/SQLConnection"; import {ISharingManager} from "./interfaces/ISharingManager"; import {Logger} from "../Logger"; @@ -26,18 +26,18 @@ export class ObjectManagerRepository { ObjectManagerRepository.getInstance().SharingManager = new SharingManager(); } - public static async InitMySQLManagers() { + public static async InitSQLManagers() { await ObjectManagerRepository.reset(); - await MySQLConnection.init(); - const GalleryManager = require("./mysql/GalleryManager").GalleryManager; - const UserManager = require("./mysql/UserManager").UserManager; - const SearchManager = require("./mysql/SearchManager").SearchManager; - const SharingManager = require("./mysql/SharingManager").SharingManager; + await SQLConnection.init(); + const GalleryManager = require("./sql/GalleryManager").GalleryManager; + const UserManager = require("./sql/UserManager").UserManager; + const SearchManager = require("./sql/SearchManager").SearchManager; + const SharingManager = require("./sql/SharingManager").SharingManager; ObjectManagerRepository.getInstance().GalleryManager = new GalleryManager(); ObjectManagerRepository.getInstance().UserManager = new UserManager(); ObjectManagerRepository.getInstance().SearchManager = new SearchManager(); ObjectManagerRepository.getInstance().SharingManager = new SharingManager(); - Logger.debug("MySQL DB inited"); + Logger.debug("SQL DB inited"); } public static getInstance() { @@ -48,7 +48,7 @@ export class ObjectManagerRepository { } public static async reset() { - await MySQLConnection.close(); + await SQLConnection.close(); this._instance = null; } diff --git a/backend/model/mysql/GalleryManager.ts b/backend/model/sql/GalleryManager.ts similarity index 97% rename from backend/model/mysql/GalleryManager.ts rename to backend/model/sql/GalleryManager.ts index dec326d8..5dae6dae 100644 --- a/backend/model/mysql/GalleryManager.ts +++ b/backend/model/sql/GalleryManager.ts @@ -3,7 +3,7 @@ import {DirectoryDTO} from "../../../common/entities/DirectoryDTO"; import * as path from "path"; import * as fs from "fs"; import {DirectoryEntity} from "./enitites/DirectoryEntity"; -import {MySQLConnection} from "./MySQLConnection"; +import {SQLConnection} from "./SQLConnection"; import {DiskManager} from "../DiskManger"; import {PhotoEntity, PhotoMetadataEntity} from "./enitites/PhotoEntity"; import {Utils} from "../../../common/Utils"; @@ -19,7 +19,7 @@ export class GalleryManager implements IGalleryManager { relativeDirectoryName = path.normalize(path.join("." + path.sep, relativeDirectoryName)); const directoryName = path.basename(relativeDirectoryName); const directoryParent = path.join(path.dirname(relativeDirectoryName), path.sep); - const connection = await MySQLConnection.getConnection(); + const connection = await SQLConnection.getConnection(); const stat = fs.statSync(path.join(ProjectPath.ImageFolder, relativeDirectoryName)); const lastModified = Math.max(stat.ctime.getTime(), stat.mtime.getTime()); let dir = await connection @@ -95,7 +95,7 @@ export class GalleryManager implements IGalleryManager { return new Promise(async (resolve, reject) => { try { const scannedDirectory = await DiskManager.scanDirectory(relativeDirectoryName); - const connection = await MySQLConnection.getConnection(); + const connection = await SQLConnection.getConnection(); //returning with the result scannedDirectory.photos.forEach(p => p.readyThumbnails = []); diff --git a/backend/model/mysql/MySQLConnection.ts b/backend/model/sql/SQLConnection.ts similarity index 74% rename from backend/model/mysql/MySQLConnection.ts rename to backend/model/sql/SQLConnection.ts index ca0d522e..4f29ee1b 100644 --- a/backend/model/mysql/MySQLConnection.ts +++ b/backend/model/sql/SQLConnection.ts @@ -1,16 +1,17 @@ import "reflect-metadata"; -import {Connection, createConnection, getConnection} from "typeorm"; +import {Connection, createConnection, DriverOptions, getConnection} from "typeorm"; import {UserEntity} from "./enitites/UserEntity"; import {UserRoles} from "../../../common/entities/UserDTO"; import {PhotoEntity, PhotoMetadataEntity} from "./enitites/PhotoEntity"; import {DirectoryEntity} from "./enitites/DirectoryEntity"; import {Config} from "../../../common/config/private/Config"; import {SharingEntity} from "./enitites/SharingEntity"; -import {DataBaseConfig} from "../../../common/config/private/IPrivateConfig"; +import {DataBaseConfig, DatabaseType} from "../../../common/config/private/IPrivateConfig"; import {PasswordHelper} from "../PasswordHelper"; +import {ProjectPath} from "../../ProjectPath"; -export class MySQLConnection { +export class SQLConnection { constructor() { @@ -22,16 +23,10 @@ export class MySQLConnection { public static async getConnection(): Promise { if (this.connection == null) { + this.connection = await createConnection({ name: "main", - driver: { - type: "mysql", - host: Config.Server.database.mysql.host, - port: 3306, - username: Config.Server.database.mysql.username, - password: Config.Server.database.mysql.password, - database: Config.Server.database.mysql.database - }, + driver: this.getDriver(Config.Server.database), entities: [ UserEntity, DirectoryEntity, @@ -59,17 +54,30 @@ export class MySQLConnection { } const conn = await createConnection({ name: "test", - driver: { + driver: this.getDriver(config) + }); + await conn.close(); + return true; + } + + private static getDriver(config: DataBaseConfig): DriverOptions { + let driver: DriverOptions = null; + if (config.type == DatabaseType.mysql) { + driver = { type: "mysql", host: config.mysql.host, port: 3306, username: config.mysql.username, password: config.mysql.password, database: config.mysql.database - } - }); - await conn.close(); - return true; + }; + } else if (config.type == DatabaseType.sqlite) { + driver = { + type: "sqlite", + storage: ProjectPath.getAbsolutePath(config.sqlite.storage) + }; + } + return driver; } public static async init(): Promise { diff --git a/backend/model/mysql/SearchManager.ts b/backend/model/sql/SearchManager.ts similarity index 96% rename from backend/model/mysql/SearchManager.ts rename to backend/model/sql/SearchManager.ts index 410d17b9..c427e58d 100644 --- a/backend/model/mysql/SearchManager.ts +++ b/backend/model/sql/SearchManager.ts @@ -1,7 +1,7 @@ import {AutoCompleteItem, SearchTypes} from "../../../common/entities/AutoCompleteItem"; import {ISearchManager} from "../interfaces/ISearchManager"; import {SearchResultDTO} from "../../../common/entities/SearchResultDTO"; -import {MySQLConnection} from "./MySQLConnection"; +import {SQLConnection} from "./SQLConnection"; import {PhotoEntity} from "./enitites/PhotoEntity"; import {DirectoryEntity} from "./enitites/DirectoryEntity"; import {PositionMetaData} from "../../../common/entities/PhotoDTO"; @@ -10,7 +10,7 @@ export class SearchManager implements ISearchManager { async autocomplete(text: string) { - const connection = await MySQLConnection.getConnection(); + const connection = await SQLConnection.getConnection(); let result: Array = []; let photoRepository = connection.getRepository(PhotoEntity); @@ -64,7 +64,7 @@ export class SearchManager implements ISearchManager { } async search(text: string, searchType: SearchTypes) { - const connection = await MySQLConnection.getConnection(); + const connection = await SQLConnection.getConnection(); let result: SearchResultDTO = { searchText: text, @@ -119,7 +119,7 @@ export class SearchManager implements ISearchManager { } async instantSearch(text: string) { - const connection = await MySQLConnection.getConnection(); + const connection = await SQLConnection.getConnection(); let result: SearchResultDTO = { searchText: text, diff --git a/backend/model/mysql/SharingManager.ts b/backend/model/sql/SharingManager.ts similarity index 84% rename from backend/model/mysql/SharingManager.ts rename to backend/model/sql/SharingManager.ts index 26eb693e..dec7c000 100644 --- a/backend/model/mysql/SharingManager.ts +++ b/backend/model/sql/SharingManager.ts @@ -1,31 +1,21 @@ import {ISharingManager} from "../interfaces/ISharingManager"; import {SharingDTO} from "../../../common/entities/SharingDTO"; -import {MySQLConnection} from "./MySQLConnection"; +import {SQLConnection} from "./SQLConnection"; import {SharingEntity} from "./enitites/SharingEntity"; import {Config} from "../../../common/config/private/Config"; import {PasswordHelper} from "../PasswordHelper"; export class SharingManager implements ISharingManager { - private async removeExpiredLink() { - const connection = await MySQLConnection.getConnection(); - return connection - .getRepository(SharingEntity) - .createQueryBuilder("share") - .where("expires < :now", {now: Date.now()}) - .delete() - .execute(); - } - async findOne(filter: any): Promise { await this.removeExpiredLink(); - const connection = await MySQLConnection.getConnection(); + const connection = await SQLConnection.getConnection(); return await connection.getRepository(SharingEntity).findOne(filter); } async createSharing(sharing: SharingDTO): Promise { await this.removeExpiredLink(); - const connection = await MySQLConnection.getConnection(); + const connection = await SQLConnection.getConnection(); if (sharing.password) { sharing.password = PasswordHelper.cryptPassword(sharing.password); } @@ -35,7 +25,7 @@ export class SharingManager implements ISharingManager { } async updateSharing(inSharing: SharingDTO): Promise { - const connection = await MySQLConnection.getConnection(); + const connection = await SQLConnection.getConnection(); let sharing = await connection.getRepository(SharingEntity).findOne({ id: inSharing.id, @@ -54,5 +44,15 @@ export class SharingManager implements ISharingManager { return await connection.getRepository(SharingEntity).persist(sharing); } + private async removeExpiredLink() { + const connection = await SQLConnection.getConnection(); + return connection + .getRepository(SharingEntity) + .createQueryBuilder("share") + .where("expires < :now", {now: Date.now()}) + .delete() + .execute(); + } + } diff --git a/backend/model/mysql/UserManager.ts b/backend/model/sql/UserManager.ts similarity index 84% rename from backend/model/mysql/UserManager.ts rename to backend/model/sql/UserManager.ts index ac45c194..adada0d8 100644 --- a/backend/model/mysql/UserManager.ts +++ b/backend/model/sql/UserManager.ts @@ -1,7 +1,7 @@ import {UserDTO, UserRoles} from "../../../common/entities/UserDTO"; import {IUserManager} from "../interfaces/IUserManager"; import {UserEntity} from "./enitites/UserEntity"; -import {MySQLConnection} from "./MySQLConnection"; +import {SQLConnection} from "./SQLConnection"; import {PasswordHelper} from "../PasswordHelper"; @@ -12,7 +12,7 @@ export class UserManager implements IUserManager { public async findOne(filter: any) { - const connection = await MySQLConnection.getConnection(); + const connection = await SQLConnection.getConnection(); let pass = filter.password; delete filter.password; const user = (await connection.getRepository(UserEntity).findOne(filter)); @@ -29,7 +29,7 @@ export class UserManager implements IUserManager { }; public async find(filter: any) { - const connection = await MySQLConnection.getConnection(); + const connection = await SQLConnection.getConnection(); return (await connection.getRepository(UserEntity).find(filter)).map(user => { if (user.permissions && user.permissions != null) { user.permissions = JSON.parse(user.permissions); @@ -39,7 +39,7 @@ export class UserManager implements IUserManager { } public async createUser(user: UserDTO) { - const connection = await MySQLConnection.getConnection(); + const connection = await SQLConnection.getConnection(); if (user.permissions && user.permissions != null) { user.permissions = JSON.stringify(user.permissions); } @@ -48,14 +48,14 @@ export class UserManager implements IUserManager { } public async deleteUser(id: number) { - const connection = await MySQLConnection.getConnection(); + const connection = await SQLConnection.getConnection(); const user = await connection.getRepository(UserEntity).findOne({id: id}); return await connection.getRepository(UserEntity).remove(user); } public async changeRole(id: number, newRole: UserRoles) { - const connection = await MySQLConnection.getConnection(); + const connection = await SQLConnection.getConnection(); let userRepository = connection.getRepository(UserEntity); const user = await userRepository.findOne({id: id}); user.role = newRole; diff --git a/backend/model/mysql/enitites/DirectoryEntity.ts b/backend/model/sql/enitites/DirectoryEntity.ts similarity index 100% rename from backend/model/mysql/enitites/DirectoryEntity.ts rename to backend/model/sql/enitites/DirectoryEntity.ts diff --git a/backend/model/mysql/enitites/PhotoEntity.ts b/backend/model/sql/enitites/PhotoEntity.ts similarity index 100% rename from backend/model/mysql/enitites/PhotoEntity.ts rename to backend/model/sql/enitites/PhotoEntity.ts diff --git a/backend/model/mysql/enitites/SharingEntity.ts b/backend/model/sql/enitites/SharingEntity.ts similarity index 100% rename from backend/model/mysql/enitites/SharingEntity.ts rename to backend/model/sql/enitites/SharingEntity.ts diff --git a/backend/model/mysql/enitites/UserEntity.ts b/backend/model/sql/enitites/UserEntity.ts similarity index 100% rename from backend/model/mysql/enitites/UserEntity.ts rename to backend/model/sql/enitites/UserEntity.ts diff --git a/backend/server.ts b/backend/server.ts index 322923fc..0228277e 100644 --- a/backend/server.ts +++ b/backend/server.ts @@ -67,8 +67,8 @@ export class Server { DiskManager.init(); ThumbnailGeneratorMWs.init(); - if (Config.Server.database.type == DatabaseType.mysql) { - await ObjectManagerRepository.InitMySQLManagers(); + if (Config.Server.database.type != DatabaseType.memory) { + await ObjectManagerRepository.InitSQLManagers(); } else { await ObjectManagerRepository.InitMemoryManagers(); } diff --git a/common/config/private/IPrivateConfig.ts b/common/config/private/IPrivateConfig.ts index ff198ddf..738c3e01 100644 --- a/common/config/private/IPrivateConfig.ts +++ b/common/config/private/IPrivateConfig.ts @@ -1,13 +1,14 @@ import {ClientConfig} from "../public/ConfigClass"; -export enum DatabaseType{ - memory = 0, mysql = 1 +export enum DatabaseType { + memory = 0, mysql = 1, sqlite = 2 } + export enum LogLevel { error, warn, info, debug, verbose } -export enum ThumbnailProcessingLib{ +export enum ThumbnailProcessingLib { Jimp = 0, gm = 1, sharp = 2 @@ -19,18 +20,27 @@ export interface MySQLConfig { username: string; password: string; } + +export interface SQLiteConfig { + storage: string; +} + export interface DataBaseConfig { type: DatabaseType; mysql?: MySQLConfig; + sqlite?: SQLiteConfig; } + export interface ThumbnailConfig { folder: string; processingLibrary: ThumbnailProcessingLib; qualityPriority: boolean; } + export interface SharingConfig { updateTimeout: number; } + export interface ServerConfig { port: number; imagesFolder: string; @@ -42,6 +52,7 @@ export interface ServerConfig { folderPreviewSize: number; cachedFolderTimeout: number;//Do not rescans the folder if seems ok } + export interface IPrivateConfig { Server: ServerConfig; Client: ClientConfig.Config; diff --git a/common/config/private/PrivateConfigClass.ts b/common/config/private/PrivateConfigClass.ts index c0dd7d34..0371ddae 100644 --- a/common/config/private/PrivateConfigClass.ts +++ b/common/config/private/PrivateConfigClass.ts @@ -18,13 +18,16 @@ export class PrivateConfigClass extends PublicConfigClass implements IPrivateCon }, sessionTimeout: 1000 * 60 * 60 * 24 * 7, database: { - type: DatabaseType.mysql, + type: DatabaseType.sqlite, mysql: { host: "", username: "", password: "", database: "" + }, + sqlite: { + storage: "sqlite.db" } }, sharing: { diff --git a/frontend/app/settings/database/database.settings.component.html b/frontend/app/settings/database/database.settings.component.html index b269161d..85060f8d 100644 --- a/frontend/app/settings/database/database.settings.component.html +++ b/frontend/app/settings/database/database.settings.component.html @@ -10,6 +10,9 @@ + Install manually mysql node module to use mysql (npm install mysql) +

MySQL settings:

+ +

SQLie settings:

+ +