mirror of
https://github.com/finos/SymphonyElectron.git
synced 2026-10-25 06:17:38 -05:00
SDA-4415: Finalizing the approach on working with files
This commit is contained in:
1 parent
4e4223915f
commit
0e75904399
6 files changed
+240
-7
No files matched your search
@@ -0,0 +1,15 @@
|
||||
import { IFile, IFileOptions } from '../../interfaces/file-helper.interface';
|
||||
import { Files } from './files';
|
||||
|
||||
export type GetLatestModifiedFiles = (
|
||||
folderPath: string,
|
||||
options?: IFileOptions,
|
||||
) => Map<string, IFile>;
|
||||
|
||||
export abstract class FileHelperBase {
|
||||
public abstract getLatestModifiedFiles: GetLatestModifiedFiles;
|
||||
|
||||
public createFiles = () => {
|
||||
return new Files();
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
import * as fs from 'fs';
|
||||
import path = require('path');
|
||||
import { isWindowsOS } from '../../../common/env';
|
||||
import { logger } from '../../../common/logger';
|
||||
import { IFile, IFiles } from '../../interfaces/file-helper.interface';
|
||||
import {
|
||||
LogCategory,
|
||||
LogUtilities,
|
||||
Platform,
|
||||
} from '../../interfaces/reports-handlers.interface';
|
||||
import { Files } from './files';
|
||||
import { FileHelperBase, GetLatestModifiedFiles } from './files-base-helper';
|
||||
|
||||
export class FileHelper extends FileHelperBase {
|
||||
private files: IFiles;
|
||||
constructor() {
|
||||
super();
|
||||
this.files = this.createFiles();
|
||||
}
|
||||
|
||||
public get = () => {
|
||||
return this.files;
|
||||
};
|
||||
|
||||
public set = (files: Files) => {
|
||||
return (this.files = files);
|
||||
};
|
||||
|
||||
public validateFilename = (filename: string): string => {
|
||||
return filename?.replace(/[^a-zA-Z0-9/_\.-]/g, '_');
|
||||
};
|
||||
|
||||
public validateFilePath = (path: string) => {
|
||||
const unixPathRegex = /^\/([^\/]+\/)*([^\/]+)$/;
|
||||
const windowsPathRegex = /^[a-zA-Z]:\\([^\\]+\\)*([^\\]+)$/;
|
||||
|
||||
if (isWindowsOS) {
|
||||
return windowsPathRegex.test(path);
|
||||
}
|
||||
|
||||
return unixPathRegex.test(path);
|
||||
};
|
||||
|
||||
public unsetFiles = () => {
|
||||
this.files = this.createFiles();
|
||||
};
|
||||
|
||||
public getLatestModifiedFiles: GetLatestModifiedFiles = (
|
||||
folderPath: string,
|
||||
options = {
|
||||
includeOnly: [''],
|
||||
type: '',
|
||||
},
|
||||
) => {
|
||||
const logFiles = fs.readdirSync(folderPath);
|
||||
const now = new Date();
|
||||
let latestModifiedLogTimestamp = 0;
|
||||
|
||||
logFiles?.forEach((file, index) => {
|
||||
const sanitizedLogname = this.validateFilename(file);
|
||||
const sanitizedFolderPath = path.normalize(folderPath);
|
||||
|
||||
if (!sanitizedLogname || !this.validateFilePath(sanitizedFolderPath)) {
|
||||
logger.log(
|
||||
'error',
|
||||
'file-helper: Log file has a malicious format to be exported',
|
||||
);
|
||||
return;
|
||||
}
|
||||
const logFilePath = path.join(sanitizedFolderPath, sanitizedLogname);
|
||||
const logFileStats = fs.statSync(logFilePath);
|
||||
const currentLogModifiedTimestamp = logFileStats.mtime.getTime();
|
||||
|
||||
if (
|
||||
logFileStats.isFile() &&
|
||||
options.includeOnly?.some((option) =>
|
||||
file.toLowerCase().includes(option),
|
||||
)
|
||||
) {
|
||||
const logLastModifiedTimestamp = new Date(logFileStats.mtime);
|
||||
const timestampDiffInMinutes =
|
||||
(now.getTime() - logLastModifiedTimestamp.getTime()) /
|
||||
LogUtilities.ONE_MINUTE;
|
||||
const modifiedFile: IFile = {
|
||||
fileName: file,
|
||||
platform: options.type ?? Platform.IV,
|
||||
modifiedTimestamp: currentLogModifiedTimestamp,
|
||||
};
|
||||
|
||||
if (
|
||||
timestampDiffInMinutes <= LogUtilities.LOG_TIMESTAMP_THRESH_HOLD &&
|
||||
logFileStats.mtime.getTime() > latestModifiedLogTimestamp
|
||||
) {
|
||||
this.files.get().set(`${LogCategory.LATEST}_${index}`, modifiedFile);
|
||||
latestModifiedLogTimestamp = logFileStats.mtime.getTime();
|
||||
} else if (currentLogModifiedTimestamp > latestModifiedLogTimestamp) {
|
||||
this.files.get().set(LogCategory.RECENT, modifiedFile);
|
||||
latestModifiedLogTimestamp = currentLogModifiedTimestamp;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (this.files.get().has(`${LogCategory.LATEST}_1`)) {
|
||||
this.files.get().delete(LogCategory.RECENT);
|
||||
}
|
||||
|
||||
return this.files.get();
|
||||
};
|
||||
}
|
||||
|
||||
export const fileHelper = new FileHelper();
|
||||
@@ -0,0 +1,17 @@
|
||||
import { IFile, IFiles } from '../../interfaces/file-helper.interface';
|
||||
|
||||
export class Files implements IFiles {
|
||||
private files = new Map<string, IFile>();
|
||||
|
||||
constructor(private _files?: Map<string, IFile>) {
|
||||
this.set(this._files ?? this.files);
|
||||
}
|
||||
|
||||
public get = () => {
|
||||
return this.files;
|
||||
};
|
||||
|
||||
public set = (files: Map<string, IFile>) => {
|
||||
this.files = files;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
export interface IFile {
|
||||
fileName: string;
|
||||
platform: string;
|
||||
modifiedTimestamp: number;
|
||||
}
|
||||
|
||||
export interface IFileOptions {
|
||||
includeOnly?: string[];
|
||||
type?: string;
|
||||
}
|
||||
|
||||
export interface IFiles {
|
||||
get: () => Map<string, IFile>;
|
||||
set: (files: Map<string, IFile>) => void;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
export enum Platform {
|
||||
IV = 'IV',
|
||||
}
|
||||
|
||||
export enum LogCategory {
|
||||
LATEST = 'LATEST',
|
||||
RECENT = 'RECENT',
|
||||
C9_TRADER = 'c9trader',
|
||||
C9_ZUES = 'c9zeus',
|
||||
}
|
||||
|
||||
export enum LogUtilities {
|
||||
ONE_MINUTE = 60000,
|
||||
LOG_TIMESTAMP_THRESH_HOLD = 31,
|
||||
}
|
||||
|
||||
export type RetrieveIVLogs = (logsPath: string) => void;
|
||||
export type RemoveIVLogs = (logsPath: string) => void;
|
||||
@@ -1,12 +1,19 @@
|
||||
import * as zip from 'adm-zip';
|
||||
import { app, BrowserWindow, dialog, shell, WebContents } from 'electron';
|
||||
import * as fs from 'fs';
|
||||
import { homedir as getHomedir } from 'os';
|
||||
import * as path from 'path';
|
||||
|
||||
import { ILogs } from '../common/api-interface';
|
||||
import { isLinux, isMac, isWindowsOS } from '../common/env';
|
||||
import { i18n } from '../common/i18n';
|
||||
import { logger } from '../common/logger';
|
||||
import { fileHelper } from './helpers/file/files-helper';
|
||||
import {
|
||||
LogCategory,
|
||||
RemoveIVLogs,
|
||||
RetrieveIVLogs,
|
||||
} from './interfaces/reports-handlers.interface';
|
||||
|
||||
/**
|
||||
* Archives files in the source directory
|
||||
@@ -65,14 +72,10 @@ let logWebContents: WebContents;
|
||||
const logTypes: string[] = [];
|
||||
const receivedLogs: ILogs[] = [];
|
||||
|
||||
const validateFilename = (filename: string): string => {
|
||||
return filename?.replace(/[^a-zA-Z0-9/_\.-]/g, '_');
|
||||
};
|
||||
|
||||
const writeClientLogs = async (retrievedLogs: ILogs[]) => {
|
||||
const writeLogs = async (retrievedLogs: ILogs[]) => {
|
||||
for await (const logs of retrievedLogs) {
|
||||
for (const logFile of logs.logFiles) {
|
||||
const sanitizedFilename = validateFilename(logFile.filename);
|
||||
const sanitizedFilename = fileHelper.validateFilename(logFile.filename);
|
||||
if (!sanitizedFilename) {
|
||||
continue;
|
||||
}
|
||||
@@ -123,7 +126,9 @@ export const packageLogs = async (retrievedLogs: ILogs[]): Promise<void> => {
|
||||
const timestamp = new Date().getTime();
|
||||
const destination = app.getPath('downloads') + destPath + timestamp + '.zip';
|
||||
|
||||
await writeClientLogs(retrievedLogs);
|
||||
removeLastIVLogs(logsPath);
|
||||
extractIVLogs(logsPath);
|
||||
await writeLogs(retrievedLogs);
|
||||
generateArchiveForDirectory(
|
||||
logsPath,
|
||||
destination,
|
||||
@@ -278,3 +283,55 @@ const writeDataToFile = async (filePath: string, data: string) => {
|
||||
|
||||
writeStream.end();
|
||||
};
|
||||
|
||||
const removeLastIVLogs: RemoveIVLogs = (logsPath: string) => {
|
||||
const ivLogsList = fileHelper.getLatestModifiedFiles(logsPath, {
|
||||
includeOnly: [LogCategory.C9_TRADER, LogCategory.C9_ZUES],
|
||||
});
|
||||
|
||||
ivLogsList.forEach((log) => {
|
||||
const logPath = `${logsPath}/${log.fileName}`;
|
||||
|
||||
try {
|
||||
fs.unlinkSync(logPath);
|
||||
logger.info(`reports-handler: removed ${log.fileName}`);
|
||||
} catch (e) {
|
||||
logger.error(`reports-handler: Error in removing file - ${e}`);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const extractIVLogs: RetrieveIVLogs = (logsPath: string) => {
|
||||
const ivFolderPath = path.join(
|
||||
getHomedir(),
|
||||
'AppData',
|
||||
'Local',
|
||||
'Cloud9_Technologies',
|
||||
'C9Trader',
|
||||
'log',
|
||||
);
|
||||
|
||||
fileHelper.set(fileHelper.createFiles());
|
||||
const ivLogsList = fileHelper.getLatestModifiedFiles(ivFolderPath);
|
||||
|
||||
if (ivLogsList.size < 1) {
|
||||
logger.error(`reports-handler: Cannot copy log, logs arent exist`);
|
||||
} else {
|
||||
try {
|
||||
ivLogsList.forEach((log) => {
|
||||
logger.info(`reports-handler: Start reading logs, ${log.fileName}`);
|
||||
const ivLog = fs.readFileSync(`${ivFolderPath}/${log.fileName}`);
|
||||
|
||||
if (ivLog) {
|
||||
logger.info(`reports-handler: Log found start copying content`);
|
||||
fs.writeFileSync(`${logsPath}/${log.fileName}`, ivLog);
|
||||
} else {
|
||||
logger.error(`reports-handler: ${log} cannot be found.`);
|
||||
}
|
||||
});
|
||||
fileHelper.unsetFiles();
|
||||
} catch (e) {
|
||||
logger.error(`reports-handler: ${e}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
Reference in new issue
Block a user