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:
parent
e430f0bdf6
commit
4333e41155
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,8 +1,7 @@
|
||||
.idea/
|
||||
release
|
||||
PiGallery2.iml
|
||||
node_modules/
|
||||
typings/
|
||||
pigallery2.zip
|
||||
frontend/app/**/*.js
|
||||
frontend/app/**/*.js.map
|
||||
frontend/main.js
|
||||
|
@ -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
32
backend/Logger.ts
Normal 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
|
||||
});
|
@ -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));
|
||||
}
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
@ -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();
|
@ -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) {
|
||||
}
|
||||
}
|
@ -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",
|
||||
|
Loading…
Reference in New Issue
Block a user