<commit_before>import { app } from 'electron';
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';

import { ChildProcess, ExecException, execFile } from 'child_process';
import * as util from 'util';
import { IScreenSnippet } from '../common/api-interface';
import { isDevEnv, isMac } from '../common/env';
import { i18n } from '../common/i18n';
import { logger } from '../common/logger';
import { updateAlwaysOnTop } from './window-actions';
import { windowHandler } from './window-handler';

const readFile = util.promisify(fs.readFile);

class ScreenSnippet {
    private readonly tempDir: string;
    private readonly captureUtil: string;
    private outputFileName: string | undefined;
    private isAlwaysOnTop: boolean;
    private captureUtilArgs: ReadonlyArray<string> | undefined;
    private child: ChildProcess | undefined;

    constructor() {
        this.tempDir = os.tmpdir();
        this.isAlwaysOnTop = false;
        this.captureUtil = isMac ? '/usr/sbin/screencapture' : isDevEnv
            ? path.join(__dirname,
                '../../node_modules/screen-snippet/bin/Release/ScreenSnippet.exe')
            : path.join(path.dirname(app.getPath('exe')), 'ScreenSnippet.exe');
    }

    /**
     * Captures a user selected portion of the monitor and returns jpeg image
     * encoded in base64 format.
     *
     * @param webContents {Electron.webContents}
     */
    public async capture(webContents: Electron.webContents) {
        logger.info(`screen-snippet-handler: Starting screen capture!`);
        this.outputFileName = path.join(this.tempDir, 'symphonyImage-' + Date.now() + '.jpg');
        this.captureUtilArgs = isMac
            ? [ '-i', '-s', '-t', 'jpg', this.outputFileName ]
            : [ this.outputFileName, i18n.getLocale() ];

        logger.info(`screen-snippet-handler: Capturing snippet with file ${this.outputFileName} and args ${this.captureUtilArgs}!`);

        const mainWindow = windowHandler.getMainWindow();
        if (mainWindow) {
            this.isAlwaysOnTop = mainWindow.isAlwaysOnTop();
            logger.info(`screen-snippet-handler: Is main window always on top? ${this.isAlwaysOnTop}!`);
            updateAlwaysOnTop(false, false);
        }
        // only allow one screen capture at a time.
        if (this.child) {
            logger.info(`screen-snippet-handler: Child screen capture exists, killing it and keeping only 1 instance!`);
            this.child.kill();
        }
        try {
            await this.execCmd(this.captureUtil, this.captureUtilArgs);
            const { message, data, type }: IScreenSnippet = await this.convertFileToData();
            logger.info(`screen-snippet-handler: Snippet captured! Sending data to SFE`);
            webContents.send('screen-snippet-data', { message, data, type });
        } catch (error) {
            logger.error(`screen-snippet-handler: screen capture failed with error: ${error}!`);
        }
    }

    /**
     * Kills the child process when the application is reloaded
     */
    public killChildProcess(): void {
        if (this.child && typeof this.child.kill === 'function') {
            this.child.kill();
        }
    }

    /**
     * Executes the given command via a child process
     *
     * Windows: uses custom built windows screen capture tool
     * Mac OSX: uses built-in screencapture tool which has been
     * available since OSX ver 10.2.
     *
     * @param captureUtil {string}
     * @param captureUtilArgs {captureUtilArgs}
     * @example execCmd('-i -s', '/user/desktop/symphonyImage-1544025391698.jpg')
     */
    private execCmd(captureUtil: string, captureUtilArgs: ReadonlyArray<string>): Promise<ChildProcess> {
        return new Promise<ChildProcess>((resolve, reject) => {
            return this.child = execFile(captureUtil, captureUtilArgs, (error: ExecException | null) => {
                if (this.isAlwaysOnTop) {
                    updateAlwaysOnTop(true, false);<commit_msg>ELECTRON-1459 - Update screen snippet image type to png from jpg (#758)<commit_after>import { app } from 'electron';
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';

import { ChildProcess, ExecException, execFile } from 'child_process';
import * as util from 'util';
import { IScreenSnippet } from '../common/api-interface';
import { isDevEnv, isMac } from '../common/env';
import { i18n } from '../common/i18n';
import { logger } from '../common/logger';
import { updateAlwaysOnTop } from './window-actions';
import { windowHandler } from './window-handler';

const readFile = util.promisify(fs.readFile);

class ScreenSnippet {
    private readonly tempDir: string;
    private readonly captureUtil: string;
    private outputFileName: string | undefined;
    private isAlwaysOnTop: boolean;
    private captureUtilArgs: ReadonlyArray<string> | undefined;
    private child: ChildProcess | undefined;

    constructor() {
        this.tempDir = os.tmpdir();
        this.isAlwaysOnTop = false;
        this.captureUtil = isMac ? '/usr/sbin/screencapture' : isDevEnv
            ? path.join(__dirname,
                '../../node_modules/screen-snippet/bin/Release/ScreenSnippet.exe')
            : path.join(path.dirname(app.getPath('exe')), 'ScreenSnippet.exe');
    }

    /**
     * Captures a user selected portion of the monitor and returns jpeg image
     * encoded in base64 format.
     *
     * @param webContents {Electron.webContents}
     */
    public async capture(webContents: Electron.webContents) {
        logger.info(`screen-snippet-handler: Starting screen capture!`);
        this.outputFileName = path.join(this.tempDir, 'symphonyImage-' + Date.now() + '.png');
        this.captureUtilArgs = isMac
            ? [ '-i', '-s', '-t', 'png', this.outputFileName ]
            : [ this.outputFileName, i18n.getLocale() ];

        logger.info(`screen-snippet-handler: Capturing snippet with file ${this.outputFileName} and args ${this.captureUtilArgs}!`);

        const mainWindow = windowHandler.getMainWindow();
        if (mainWindow) {
            this.isAlwaysOnTop = mainWindow.isAlwaysOnTop();
            logger.info(`screen-snippet-handler: Is main window always on top? ${this.isAlwaysOnTop}!`);
            updateAlwaysOnTop(false, false);
        }
        // only allow one screen capture at a time.
        if (this.child) {
            logger.info(`screen-snippet-handler: Child screen capture exists, killing it and keeping only 1 instance!`);
            this.child.kill();
        }
        try {
            await this.execCmd(this.captureUtil, this.captureUtilArgs);
            const { message, data, type }: IScreenSnippet = await this.convertFileToData();
            logger.info(`screen-snippet-handler: Snippet captured! Sending data to SFE`);
            webContents.send('screen-snippet-data', { message, data, type });
        } catch (error) {
            logger.error(`screen-snippet-handler: screen capture failed with error: ${error}!`);
        }
    }

    /**
     * Kills the child process when the application is reloaded
     */
    public killChildProcess(): void {
        if (this.child && typeof this.child.kill === 'function') {
            this.child.kill();
        }
    }

    /**
     * Executes the given command via a child process
     *
     * Windows: uses custom built windows screen capture tool
     * Mac OSX: uses built-in screencapture tool which has been
     * available since OSX ver 10.2.
     *
     * @param captureUtil {string}
     * @param captureUtilArgs {captureUtilArgs}
     * @example execCmd('-i -s', '/user/desktop/symphonyImage-1544025391698.png')
     */
    private execCmd(captureUtil: string, captureUtilArgs: ReadonlyArray<string>): Promise<ChildProcess> {
        return new Promise<ChildProcess>((resolve, reject) => {
            return this.child = execFile(captureUtil, captureUtilArgs, (error: ExecException | null) => {
                if (this.isAlwaysOnTop) {
                    updateAlwaysOnTop(true, false);
{'fraction_non_alphanumeric': 0.1227656405163853, 'fraction_numerical': 0.007075471698113208, 'mean_word_length': 2.7404828226555247, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2866878', 'n_tokens_mistral': 2312, 'n_tokens_neox': 2228, 'n_words': 601}