1
0
mirror of https://github.com/bpatrik/pigallery2.git synced 2024-12-25 02:04:15 +02:00

improving logging and fixing file reader error handling bug

This commit is contained in:
Braun Patrik 2017-06-03 22:35:47 +02:00
parent e430f0bdf6
commit 4333e41155
8 changed files with 132 additions and 72 deletions

3
.gitignore vendored
View File

@ -1,8 +1,7 @@
.idea/
release
PiGallery2.iml
node_modules/
typings/
pigallery2.zip
frontend/app/**/*.js
frontend/app/**/*.js.map
frontend/main.js

View File

@ -1,4 +1,5 @@
# PiGallery2
[![npm version](https://badge.fury.io/js/pigallery2.svg)](https://badge.fury.io/js/pigallery2)
[![Build Status](https://travis-ci.org/bpatrik/PiGallery2.svg?branch=master)](https://travis-ci.org/bpatrik/PiGallery2)
[![Coverage Status](https://coveralls.io/repos/github/bpatrik/PiGallery2/badge.svg?branch=master)](https://coveralls.io/github/bpatrik/PiGallery2?branch=master)
[![Heroku](https://heroku-badge.herokuapp.com/?app=pigallery2&style=flat)](https://pigallery2.herokuapp.com)

32
backend/Logger.ts Normal file
View File

@ -0,0 +1,32 @@
import * as winston from "winston";
declare module 'winston' {
interface LoggerInstance {
logFileName: string;
logFilePath: string;
}
}
export const Logger = new winston.Logger({
transports: [
new winston.transports.Console({
level: 'silly',
handleExceptions: true,
json: false,
colorize: true,
timestamp: function () {
return (new Date()).toLocaleString();
},
label: "innerLabel",
formatter: (options) => {
// Return string will be passed to logger.
return options.timestamp() + '[' + winston['config']['colorize'](options.level, options.level.toUpperCase()) + '] ' +
(undefined !== options.message ? options.message : '') +
(options.meta && Object.keys(options.meta).length ? '\n\t' + JSON.stringify(options.meta) : '' );
},
debugStdout: true
})
],
exitOnError: false
});

View File

@ -10,7 +10,10 @@ import {SearchResultDTO} from "../../common/entities/SearchResult";
import {PhotoDTO} from "../../common/entities/PhotoDTO";
import {Config} from "../config/Config";
import {ProjectPath} from "../ProjectPath";
import {Logger} from "../Logger";
const LOG_TAG = "[GalleryMWs]";
export class GalleryMWs {
@ -24,6 +27,7 @@ export class GalleryMWs {
ObjectManagerRepository.getInstance().getGalleryManager().listDirectory(directoryName, (err, directory: DirectoryDTO) => {
if (err || !directory) {
Logger.warn(LOG_TAG, "Error during listing the directory", err);
console.error(err);
return next(new Error(ErrorCodes.GENERAL_ERROR, err));
}

View File

@ -10,9 +10,13 @@ import {
PositionMetaData
} from "../../common/entities/PhotoDTO";
import {ProjectPath} from "../ProjectPath";
import {Logger} from "../Logger";
const Pool = require('threads').Pool;
const pool = new Pool();
const LOG_TAG = "[DiskManager]";
pool.run(
(input: {
relativeDirectoryName: string,
@ -49,13 +53,15 @@ pool.run(
return new Promise<PhotoMetadata>((resolve: (metadata: PhotoMetadata) => void, reject) => {
fs.readFile(fullPath, function (err, data) {
if (err) {
return reject(err);
} else {
let exif = exif_parser.create(data).parse();
let iptcData = iptc(data);
return reject({file: fullPath, error: err});
}
try {
let imageSize: ImageSize = {width: exif.imageSize.width, height: exif.imageSize.height};
let cameraData: CameraMetadata = {
const exif = exif_parser.create(data).parse();
const iptcData = iptc(data);
const imageSize: ImageSize = {width: exif.imageSize.width, height: exif.imageSize.height};
const cameraData: CameraMetadata = {
ISO: exif.tags.ISO,
model: exif.tags.Modeol,
maker: exif.tags.Make,
@ -64,14 +70,14 @@ pool.run(
focalLength: exif.tags.FocalLength,
lens: exif.tags.LensModel,
};
let GPS: GPSMetadata = {
const GPS: GPSMetadata = {
latitude: exif.tags.GPSLatitude,
longitude: exif.tags.GPSLongitude,
altitude: exif.tags.GPSAltitude
};
let positionData: PositionMetaData = {
const positionData: PositionMetaData = {
GPSData: GPS,
country: iptcData.country_or_primary_location_name,
state: iptcData.province_or_state,
@ -79,7 +85,7 @@ pool.run(
};
//Decode characters to UTF8
let decode = (s: any) => {
const decode = (s: any) => {
for (let a, b, i = -1, l = (s = s.split("")).length, o = String.fromCharCode, c = "charCodeAt"; ++i < l;
((a = s[i][c](0)) & 0x80) &&
(s[i] = (a & 0xfc) == 0xc0 && ((b = s[i + 1][c](0)) & 0xc0) == 0x80 ?
@ -88,11 +94,12 @@ pool.run(
return s.join("");
};
let keywords: [string] = iptcData.keywords.map((s: string) => decode(s));
let creationDate: number = iptcData.date_time.getTime();
const keywords: string[] = (iptcData.keywords || []).map((s: string) => decode(s));
const creationDate: number = iptcData.date_time ? iptcData.date_time.getTime() : 0;
let metadata: PhotoMetadata = <PhotoMetadata>{
const metadata: PhotoMetadata = <PhotoMetadata>{
keywords: keywords,
cameraData: cameraData,
positionData: positionData,
@ -100,6 +107,8 @@ pool.run(
creationDate: creationDate
};
return resolve(metadata);
} catch (err) {
return reject({file: fullPath, error: err});
}
});
});
@ -111,7 +120,6 @@ pool.run(
directoryParent: string,
absoluteDirectoryName: string
}, maxPhotos: number = null, photosOnly: boolean = false): Promise<DirectoryDTO> => {
return new Promise<DirectoryDTO>((resolve, reject) => {
let promises: Array<Promise<any>> = [];
let directory = <DirectoryDTO>{
@ -127,41 +135,49 @@ pool.run(
return reject(err);
}
for (let i = 0; i < list.length; i++) {
let file = list[i];
let fullFilePath = path.normalize(path.resolve(directoryInfo.absoluteDirectoryName, file));
if (photosOnly == false && fs.statSync(fullFilePath).isDirectory()) {
let promise = parseDir({
relativeDirectoryName: path.join(directoryInfo.relativeDirectoryName, path.sep),
directoryName: file,
directoryParent: path.join(directoryInfo.relativeDirectoryName, path.sep),
absoluteDirectoryName: fullFilePath
},
5, true
).then((dir) => {
directory.directories.push(dir);
});
promises.push(promise);
} else if (isImage(fullFilePath)) {
try {
for (let i = 0; i < list.length; i++) {
let file = list[i];
console.log(list[i]);
let fullFilePath = path.normalize(path.resolve(directoryInfo.absoluteDirectoryName, file));
if (photosOnly == false && fs.statSync(fullFilePath).isDirectory()) {
let promise = parseDir({
relativeDirectoryName: path.join(directoryInfo.relativeDirectoryName, path.sep),
directoryName: file,
directoryParent: path.join(directoryInfo.relativeDirectoryName, path.sep),
absoluteDirectoryName: fullFilePath
},
5, true
).then((dir) => {
directory.directories.push(dir);
});
promises.push(promise);
} else if (isImage(fullFilePath)) {
let promise = loadPhotoMetadata(fullFilePath).then((photoMetadata) => {
directory.photos.push(<PhotoDTO>{name: file, directory: null, metadata: photoMetadata});
});
let promise = loadPhotoMetadata(fullFilePath).then((photoMetadata) => {
directory.photos.push(<PhotoDTO>{
name: file,
directory: null,
metadata: photoMetadata
});
});
promises.push(promise);
if (maxPhotos != null && promises.length > maxPhotos) {
break;
promises.push(promise);
if (maxPhotos != null && promises.length > maxPhotos) {
break;
}
}
}
}
Promise.all(promises).then(() => {
return resolve(directory);
}).catch((err) => {
console.error(err);
});
Promise.all(promises).then(() => {
return resolve(directory);
}).catch((err) => {
return reject({directoryInfo: directoryInfo, error: err});
});
} catch (err) {
return reject({directoryInfo: directoryInfo, error: err});
}
});
@ -179,7 +195,7 @@ pool.run(
export class DiskManager {
public static scanDirectory(relativeDirectoryName: string, cb: (error: any, result: DirectoryDTO) => void) {
console.log("DiskManager: scanDirectory");
Logger.silly(LOG_TAG, "scanDirectory");
let directoryName = path.basename(relativeDirectoryName);
let directoryParent = path.join(path.dirname(relativeDirectoryName), path.sep);
let absoluteDirectoryName = path.join(ProjectPath.ImageFolder, relativeDirectoryName);
@ -189,7 +205,11 @@ export class DiskManager {
directoryName,
directoryParent,
absoluteDirectoryName
}) .on('done', (error: any, result: DirectoryDTO) => {
}).on('done', (error: any, result: DirectoryDTO) => {
if (error || !result) {
return cb(error, result);
}
let addDirs = (dir: DirectoryDTO) => {
dir.photos.forEach((ph) => {
ph.directory = dir;
@ -199,9 +219,8 @@ export class DiskManager {
});
};
addDirs(result);
return cb(error, result);
}).on('error', (job, error) => {
}).on('error', (error) => {
return cb(error, null);
});
}

View File

@ -12,8 +12,9 @@ import {SharingRouter} from "./routes/SharingRouter";
import {DatabaseType} from "../common/config/Config";
import {ObjectManagerRepository} from "./model/ObjectManagerRepository";
import {Config} from "./config/Config";
import {Logger} from "./Logger";
const LOG_TAG = "[server]";
export class Server {
private debug: any;
@ -21,8 +22,8 @@ export class Server {
private server: any;
constructor() {
console.log("using config");
console.log(Config);
Logger.info(LOG_TAG, "config:");
Logger.info(LOG_TAG, JSON.stringify(Config, null, '\t'));
this.debug = _debug("PiGallery2:server");
this.app = _express();
@ -55,19 +56,21 @@ export class Server {
// for parsing application/json
this.app.use(_bodyParser.json());
ObjectManagerRepository.InitMySQLManagers().catch((err) => {
console.error("Erro during initailizing mysql falling back to memory DB");
console.log(err);
Config.setDatabaseType(DatabaseType.memory);
if (Config.Server.database.type == DatabaseType.mysql) {
ObjectManagerRepository.InitMySQLManagers().catch((err) => {
Logger.warn(LOG_TAG, "Error during initailizing mysql falling back to memory DB", err);
Config.setDatabaseType(DatabaseType.memory);
ObjectManagerRepository.InitMemoryManagers();
});
} else {
ObjectManagerRepository.InitMemoryManagers();
});
}
if (Config.Server.thumbnail.hardwareAcceleration == true) {
try {
const sharp = require.resolve("sharp");
} catch (err) {
console.error("Thumbnail hardware acceleration is not possible." +
Logger.warn(LOG_TAG, "Thumbnail hardware acceleration is not possible." +
" 'Sharp' node module is not found." +
" Falling back to JS based thumbnail generation");
Config.Server.thumbnail.hardwareAcceleration = false;
@ -114,11 +117,11 @@ export class Server {
// handle specific listen error with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
Logger.error(LOG_TAG, bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
Logger.error(LOG_TAG, bind + ' is already in use');
process.exit(1);
break;
default:
@ -135,14 +138,14 @@ export class Server {
const bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
this.debug('Listening on ' + bind);
Logger.debug(LOG_TAG, 'Listening on ' + bind);
};
}
if (process.env.DEBUG) {
console.log("Running in DEBUG mode");
Logger.debug(LOG_TAG, "Running in DEBUG mode");
}
new Server();

View File

@ -1,22 +1,22 @@
export enum ErrorCodes{
NOT_AUTHENTICATED,
ALREADY_AUTHENTICATED,
NOT_AUTHORISED,
CREDENTIAL_NOT_FOUND,
NOT_AUTHENTICATED = 0,
ALREADY_AUTHENTICATED = 1,
NOT_AUTHORISED = 2,
CREDENTIAL_NOT_FOUND = 3,
USER_CREATION_ERROR,
USER_CREATION_ERROR = 4,
GENERAL_ERROR,
THUMBNAIL_GENERATION_ERROR,
SERVER_ERROR,
GENERAL_ERROR = 5,
THUMBNAIL_GENERATION_ERROR = 6,
SERVER_ERROR = 7,
USER_MANAGEMENT_DISABLED
USER_MANAGEMENT_DISABLED = 8
}
export class Error {
constructor(public code:ErrorCodes, public message?:String) {
constructor(public code: ErrorCodes, public message?: string) {
}
}

View File

@ -50,6 +50,7 @@
"systemjs": "0.20.12",
"threads": "^0.7.3",
"typeorm": "0.0.11",
"winston": "^2.3.1",
"zone.js": "^0.8.11"
},
"devDependencies": {
@ -59,6 +60,7 @@
"@types/node": "^7.0.22",
"@types/optimist": "0.0.29",
"@types/sharp": "^0.17.1",
"@types/winston": "^2.3.3",
"chai": "^4.0.0",
"gulp": "^3.9.1",
"gulp-typescript": "^3.1.7",