Merge remote-tracking branch 'upstream/master' into new_screen_snippet_tool

This commit is contained in:
Mattias Gustavsson 2019-12-13 13:47:17 +01:00
commit f8d3a7e3d9
21 changed files with 372 additions and 43 deletions

View File

@ -8,8 +8,8 @@ addAssignees: true
reviewers:
- VishwasShashidhar
- KiranNiranjan
- keerthi16
- johankwarnmarksymphony
- mattias-symphony
# A list of keywords to be skipped the process that add reviewers if pull requests include it
skipKeywords:

1
.github/config.yml vendored
View File

@ -29,3 +29,4 @@ authorizedUsers:
- VishwasShashidhar
- KiranNiranjan
- johankwarnmarksymphony
- mattias-symphony

View File

@ -1,5 +1,7 @@
[![Symphony Software Foundation - Incubating](https://cdn.rawgit.com/symphonyoss/contrib-toolbox/master/images/ssf-badge-incubating.svg)](https://symphonyoss.atlassian.net/wiki/display/FM/Incubating)
[![Build Status](https://travis-ci.org/symphonyoss/SymphonyElectron.svg?branch=typescript-2)](https://travis-ci.org/symphonyoss/SymphonyElectron)
[![Known Vulnerabilities](https://snyk.io/test/github/symphonyoss/SymphonyElectron/badge.svg?targetFile=package.json)](https://snyk.io/test/github/symphonyoss/SymphonyElectron?targetFile=package.json)
# SymphonyElectron
## About:

View File

@ -125,6 +125,7 @@
<ROW Component="Jobber.exe" ComponentId="{AB38505C-2B94-49AA-BDD2-92CCC8F0DFCD}" Directory_="jobber_Dir" Attributes="0" KeyPath="Jobber.exe"/>
<ROW Component="PodUrl" ComponentId="{EA80D82D-BC65-4075-A9A8-F53E2B2513CE}" Directory_="APPDIR" Attributes="260" KeyPath="PodUrl"/>
<ROW Component="ProductInformation" ComponentId="{8B92B687-8AE0-4A5C-B6AB-5D1854009CEA}" Directory_="APPDIR" Attributes="4" KeyPath="Version"/>
<ROW Component="ScreenShareIndicatorFrame.exe" ComponentId="{85DC2888-EBE5-4084-A084-E076020086D5}" Directory_="APPDIR" Attributes="0" KeyPath="ScreenShareIndicatorFrame.exe"/>
<ROW Component="ScreenSnippet.exe" ComponentId="{B92951AB-9E69-4970-A3B5-B4E5C32F3477}" Directory_="APPDIR" Attributes="0" KeyPath="ScreenSnippet.exe"/>
<ROW Component="Symphony" ComponentId="{A6B4BA2F-2403-4B8E-9303-BF8400A9B1C4}" Directory_="Symphony_Dir" Attributes="0"/>
<ROW Component="Symphony.config" ComponentId="{644A231D-2C96-4D3D-ADB0-7820DA373499}" Directory_="config_Dir" Attributes="0" KeyPath="Symphony.config_1" Type="0"/>
@ -162,7 +163,7 @@
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiFeatsComponent">
<ROW Feature="D564007E3BBE4F85950A09B470A7CA65" Title="Visual C++ Redistributable for Visual Studio 2013 x86" Description="Visual C++ Redistributable for Visual Studio 2013 x86" Display="3" Level="1" Attributes="0"/>
<ROW Feature="MainFeature" Title="MainFeature" Description="Description" Display="1" Level="1" Directory_="APPDIR" Attributes="0" Components="AI_CustomARPName AI_DisableModify Jobber.exe PodUrl ProductInformation ScreenSnippet.exe Symphony Symphony.config Symphony.exe _ __1 am.pak appupdate.yml binding.node blink_image_resources_200_percent.pak build.cmd cld.node cld.node_1 d3dcompiler_47.dll dictionary diskusage.node_1 diskusage.node_2 enAU.bdic ffi_bindings.node ffinapi.node ffmpeg.dll index.js index.js_1 index.ts indexvalidatorx64.exe keyboardlayoutmanager.node libEGL.dll libGLESv2.dll libsymphonysearchx64.dll lz4winx64.exe refnapi.node spellchecker.node spellchecker.node_1 tarwin.exe"/>
<ROW Feature="MainFeature" Title="MainFeature" Description="Description" Display="1" Level="1" Directory_="APPDIR" Attributes="0" Components="AI_CustomARPName AI_DisableModify Jobber.exe PodUrl ProductInformation ScreenShareIndicatorFrame.exe ScreenSnippet.exe Symphony Symphony.config Symphony.exe _ __1 am.pak appupdate.yml binding.node blink_image_resources_200_percent.pak build.cmd cld.node cld.node_1 d3dcompiler_47.dll dictionary diskusage.node_1 diskusage.node_2 enAU.bdic ffi_bindings.node ffinapi.node ffmpeg.dll index.js index.js_1 index.ts indexvalidatorx64.exe keyboardlayoutmanager.node libEGL.dll libGLESv2.dll libsymphonysearchx64.dll lz4winx64.exe refnapi.node spellchecker.node spellchecker.node_1 tarwin.exe"/>
<ATTRIBUTE name="CurrentFeature" value="MainFeature"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiFilesComponent">
@ -172,6 +173,7 @@
<ROW File="LICENSE.electron.txt" Component_="blink_image_resources_200_percent.pak" FileName="LICENS~1.TXT|LICENSE.electron.txt" Attributes="0" SourcePath="..\..\dist\win-unpacked\LICENSE.electron.txt" SelfReg="false" NextFile="LICENSES.chromium.html"/>
<ROW File="LICENSES.chromium.html" Component_="blink_image_resources_200_percent.pak" FileName="LICENS~1.HTM|LICENSES.chromium.html" Attributes="0" SourcePath="..\..\dist\win-unpacked\LICENSES.chromium.html" SelfReg="false" NextFile="natives_blob.bin"/>
<ROW File="ScreenSnippet.exe" Component_="ScreenSnippet.exe" FileName="SCREEN~1.EXE|ScreenSnippet.exe" Attributes="0" SourcePath="..\..\node_modules\screen-snippet\ScreenSnippet.exe" SelfReg="false" NextFile="indexvalidatorx64.exe" DigSign="true"/>
<ROW File="ScreenShareIndicatorFrame.exe" Component_="ScreenShareIndicatorFrame.exe" FileName="SCREEN~2.EXE|ScreenShareIndicatorFrame.exe" Attributes="0" SourcePath="..\..\dist\win-unpacked\resources\app.asar.unpacked\node_modules\screen-share-indicator-frame\ScreenShareIndicatorFrame.exe" SelfReg="false" DigSign="true"/>
<ROW File="Symphony.config_1" Component_="Symphony.config" FileName="SYMPHO~1.CON|Symphony.config" Attributes="0" SourcePath="..\..\dist\win-unpacked\config\Symphony.config" SelfReg="false" NextFile="ScreenSnippet.exe"/>
<ROW File="Symphony.exe" Component_="Symphony.exe" FileName="Symphony.exe" Attributes="0" SourcePath="..\..\dist\win-unpacked\Symphony.exe" SelfReg="false" NextFile="am.pak" DigSign="true"/>
<ROW File="am.pak" Component_="am.pak" FileName="am.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\am.pak" SelfReg="false" NextFile="ar.pak"/>

View File

@ -124,6 +124,7 @@
<ROW Component="Jobber.exe" ComponentId="{AA93E17F-DDA4-4E55-A027-11FE49821386}" Directory_="jobber_Dir" Attributes="0" KeyPath="Jobber.exe"/>
<ROW Component="PodUrl" ComponentId="{EA80D82D-BC65-4075-A9A8-F53E2B2513CE}" Directory_="APPDIR" Attributes="260" KeyPath="PodUrl"/>
<ROW Component="ProductInformation" ComponentId="{8B92B687-8AE0-4A5C-B6AB-5D1854009CEA}" Directory_="APPDIR" Attributes="4" KeyPath="Version"/>
<ROW Component="ScreenShareIndicatorFrame.exe" ComponentId="{85DC2888-EBE5-4084-A084-E076020086D5}" Directory_="APPDIR" Attributes="0" KeyPath="ScreenShareIndicatorFrame.exe"/>
<ROW Component="ScreenSnippet.exe" ComponentId="{66D4F5CB-F7ED-48CD-B65B-D1C4DAEEB0B7}" Directory_="APPDIR" Attributes="0" KeyPath="ScreenSnippet.exe"/>
<ROW Component="Symphony" ComponentId="{A6B4BA2F-2403-4B8E-9303-BF8400A9B1C4}" Directory_="Symphony_Dir" Attributes="0"/>
<ROW Component="Symphony.config" ComponentId="{DBC82D0C-B96E-4939-A950-53020CEB1B7F}" Directory_="config_Dir" Attributes="0" KeyPath="Symphony.config" Type="0"/>
@ -161,7 +162,7 @@
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiFeatsComponent">
<ROW Feature="D564007E3BBE4F85950A09B470A7CA65" Title="Visual C++ Redistributable for Visual Studio 2013 x86" Description="Visual C++ Redistributable for Visual Studio 2013 x86" Display="3" Level="1" Attributes="0"/>
<ROW Feature="MainFeature" Title="MainFeature" Description="Description" Display="1" Level="1" Directory_="APPDIR" Attributes="0" Components="AI_CustomARPName AI_DisableModify Jobber.exe PodUrl ProductInformation ScreenSnippet.exe Symphony Symphony.config Symphony.exe _ __1 am.pak appupdate.yml binding.node blink_image_resources_200_percent.pak build.cmd cld.node cld.node_2 d3dcompiler_47.dll dictionary diskusage.node_1 diskusage.node_2 enAU.bdic ffi_bindings.node ffinapi.node ffmpeg.dll index.js index.js_1 index.ts indexvalidatorx86.exe keyboardlayoutmanager.node libEGL.dll libGLESv2.dll libsymphonysearchx86.dll lz4winx86.exe refnapi.node spellchecker.node spellchecker.node_1 tarwin.exe"/>
<ROW Feature="MainFeature" Title="MainFeature" Description="Description" Display="1" Level="1" Directory_="APPDIR" Attributes="0" Components="AI_CustomARPName AI_DisableModify Jobber.exe PodUrl ProductInformation ScreenShareIndicatorFrame.exe ScreenSnippet.exe Symphony Symphony.config Symphony.exe _ __1 am.pak appupdate.yml binding.node blink_image_resources_200_percent.pak build.cmd cld.node cld.node_2 d3dcompiler_47.dll dictionary diskusage.node_1 diskusage.node_2 enAU.bdic ffi_bindings.node ffinapi.node ffmpeg.dll index.js index.js_1 index.ts indexvalidatorx86.exe keyboardlayoutmanager.node libEGL.dll libGLESv2.dll libsymphonysearchx86.dll lz4winx86.exe refnapi.node spellchecker.node spellchecker.node_1 tarwin.exe"/>
<ATTRIBUTE name="CurrentFeature" value="MainFeature"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiFilesComponent">
@ -171,6 +172,7 @@
<ROW File="LICENSE.electron.txt" Component_="blink_image_resources_200_percent.pak" FileName="LICENS~1.TXT|LICENSE.electron.txt" Attributes="0" SourcePath="..\..\dist\win-ia32-unpacked\LICENSE.electron.txt" SelfReg="false" NextFile="LICENSES.chromium.html"/>
<ROW File="LICENSES.chromium.html" Component_="blink_image_resources_200_percent.pak" FileName="LICENS~1.HTM|LICENSES.chromium.html" Attributes="0" SourcePath="..\..\dist\win-ia32-unpacked\LICENSES.chromium.html" SelfReg="false" NextFile="natives_blob.bin"/>
<ROW File="ScreenSnippet.exe" Component_="ScreenSnippet.exe" FileName="SCREEN~1.EXE|ScreenSnippet.exe" Attributes="0" SourcePath="..\..\dist\win-ia32-unpacked\resources\app.asar.unpacked\node_modules\screen-snippet\ScreenSnippet.exe" SelfReg="false" NextFile="v8_context_snapshot.bin" DigSign="true"/>
<ROW File="ScreenShareIndicatorFrame.exe" Component_="ScreenShareIndicatorFrame.exe" FileName="SCREEN~2.EXE|ScreenShareIndicatorFrame.exe" Attributes="0" SourcePath="..\..\dist\win-ia32-unpacked\resources\app.asar.unpacked\node_modules\screen-share-indicator-frame\ScreenShareIndicatorFrame.exe" SelfReg="false" DigSign="true"/>
<ROW File="Symphony.config" Component_="Symphony.config" FileName="SYMPHO~1.CON|Symphony.config" Attributes="0" SourcePath="..\..\dist\win-ia32-unpacked\config\Symphony.config" SelfReg="false" NextFile="am.pak"/>
<ROW File="Symphony.exe" Component_="Symphony.exe" FileName="Symphony.exe" Attributes="0" SourcePath="..\..\dist\win-ia32-unpacked\Symphony.exe" SelfReg="false" NextFile="d3dcompiler_47.dll" DigSign="true"/>
<ROW File="am.pak" Component_="am.pak" FileName="am.pak" Attributes="0" SourcePath="..\..\dist\win-ia32-unpacked\locales\am.pak" SelfReg="false" NextFile="ar.pak"/>

5
package-lock.json generated
View File

@ -13059,6 +13059,11 @@
"object-assign": "^4.1.1"
}
},
"screen-share-indicator-frame": {
"version": "1.0.0",
"resolved": "git+https://github.com/symphonyoss/ScreenShareIndicatorFrame.git#52a5ce71de68202316e19faa22971b5590a9836f",
"optional": true
},
"screen-snippet": {
"version": "0.0.0",
"resolved": "git+https://github.com/mattias-symphony/ScreenSnippet2.git#34430ff991ad6704c59437bf9ed4e90440583a60",

View File

@ -133,6 +133,7 @@
},
"optionalDependencies": {
"screen-snippet": "git+https://github.com/mattias-symphony/ScreenSnippet2.git",
"screen-share-indicator-frame": "git+https://github.com/symphonyoss/ScreenShareIndicatorFrame.git#v1.0.0",
"swift-search": "2.0.1"
}
}

View File

@ -1,10 +1,28 @@
#!/bin/bash
NODE_REQUIRED_VERSION=v12.13.1
if ! [ -x "$(command -v git)" ]; then
echo 'GIT does not exist! Please set it up before running this script!' >&2
exit 1
fi
# Switch to the appropriate node version for the branch using NVM
if [ -x "$(command -v nvm)" ]; then
echo 'NVM does not not exist! Install it to switch to the appropriate node version!' >&2
exit 1
fi
# Source all the profile files to ensure nvm is in path
source $HOME/.nvm/nvm.sh
NODE_CURRENT_VERSION=$(nvm current)
if [ "$NODE_REQUIRED_VERSION" != "$NODE_CURRENT_VERSION" ]; then
echo 'Node version does not match required version! Installing the required version' >&2
nvm install $NODE_REQUIRED_VERSION
nvm use $NODE_REQUIRED_VERSION
fi
if ! [ -x "$(command -v node)" ]; then
echo 'NODE does not exist! Please set it up before running this script!' >&2
exit 1

View File

@ -1,10 +1,29 @@
#!/bin/bash
NODE_REQUIRED_VERSION=v12.13.1
# Check basic dependencies
if ! [ -x "$(command -v git)" ]; then
echo 'GIT does not exist! Please set it up before running this script!' >&2
exit 1
fi
# Switch to the appropriate node version for the branch using NVM
if [ -x "$(command -v nvm)" ]; then
echo 'NVM does not not exist! Install it to switch to the appropriate node version!' >&2
exit 1
fi
# Source all the profile files to ensure nvm is in path
source $HOME/.nvm/nvm.sh
NODE_CURRENT_VERSION=$(nvm current)
if [ "$NODE_REQUIRED_VERSION" != "$NODE_CURRENT_VERSION" ]; then
echo 'Node version does not match required version! Installing the required version' >&2
nvm install $NODE_REQUIRED_VERSION
nvm use $NODE_REQUIRED_VERSION
fi
if ! [ -x "$(command -v node)" ]; then
echo 'NODE does not exist! Please set it up before running this script!' >&2
exit 1
@ -15,24 +34,26 @@ if ! [ -x "$(command -v npm)" ]; then
exit 1
fi
if ! [ -x "$(command -v /usr/local/bin/packagesbuild)" ]; then
echo 'Packages build does not exist! Please set it up before running this script!' >&2
exit 1
fi
if ! [ -x "$(command -v gulp)" ]; then
echo 'Gulp does not exist! Install it for setting expiry!' >&2
exit 1
fi
if ! [ -x "$(command -v /usr/local/bin/packagesbuild)" ]; then
echo 'Packages build does not exist! Please set it up before running this script!' >&2
exit 1
fi
# If we don't get parent build number from parent job, set it to 0
if [ -z "$PARENT_BUILD_VERSION" ]; then
echo "PARENT_BUILD_VERSION is empty, setting default"
PARENT_BUILD_VERSION="0"
fi
NODE_VERSION=$(node --version)
echo "Node Version: ${NODE_VERSION}"
echo "Executing using Node Version: ${NODE_VERSION}"
# We need to include swift search libraries to build SDA
if [ ! -d "$HOME/tronlibraries/library" ]; then
echo 'Search libraries do not exist! Not building with swift search' >&2
else
@ -44,22 +65,26 @@ PKG_VERSION=$(node -e "console.log(require('./package.json').version);")
# Install app dependencies
npm install
# replace url in config
# Replace url in config
echo "Setting default pod url to https://corporate.symphony.com"
sed -i -e 's/\"url\"[[:space:]]*\:[[:space:]]*\".*\"/\"url\":\"https:\/\/corporate.symphony.com\"/g' config/Symphony.config
# setup the build version
# Setup the build version
echo "Setting build version to ${PARENT_BUILD_VERSION}"
sed -i -e "s/\"buildNumber\"[[:space:]]*\:[[:space:]]*\".*\"/\"buildNumber\":\" ${PARENT_BUILD_VERSION}\"/g" package.json
# replace version number in pre-install script
# Replace version number in pre-install script
echo "Setting package version in pre install script to ${PKG_VERSION}"
sed -i -e "s/CURRENT_VERSION=APP_VERSION/CURRENT_VERSION=${PKG_VERSION}/g" ./installer/mac/preinstall.sh
# Set expiry period for TTL builds
if [ -z "$EXPIRY_PERIOD" ]; then
echo 'Expiry period not set, so, not creating expiry for the build'
else
gulp setExpiry --period ${EXPIRY_PERIOD}
fi
# Build the app
echo "Running tests, code coverage, linting and building..."
npm run unpacked-mac

View File

@ -5,6 +5,7 @@ call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Tools\VsDevCmd
echo %PATH%
set DISABLE_REBUILD=true
set NODE_REQUIRED_VERSION=12.13.1
set PATH=%PATH%;C:\Program Files\nodejs\;C:\Program Files\Git\cmd
echo %PATH%
@ -18,6 +19,15 @@ if %ERRORLEVEL% NEQ 0 (
EXIT /B 1
)
WHERE nvm
if %ERRORLEVEL% NEQ 0 (
echo "NVM does not exist. Please set it up before running this script."
EXIT /B 1
)
nvm install %NODE_REQUIRED_VERSION%
nvm use %NODE_REQUIRED_VERSION%
WHERE node
if %ERRORLEVEL% NEQ 0 (
echo "NODE does not exist. Please set it up before running this script."
@ -30,11 +40,8 @@ if %ERRORLEVEL% NEQ 0 (
EXIT /B 1
)
WHERE gulp
if %ERRORLEVEL% NEQ 0 (
echo "GULP does not exist. Please set it up before running this script."
EXIT /B 1
)
echo "Node version is: "
call node --version
:: Below command replaces buildVersion with the appropriate build number from jenkins
sed -i -e "s/\"buildNumber\"[[:space:]]*\:[[:space:]]*\".*\"/\"buildNumber\":\"%PARENT_BUILD_VERSION%\"/g" package.json
@ -46,8 +53,6 @@ echo D | xcopy /y "C:\jenkins\workspace\tronlibraries\library" "library"
echo "Running npm install..."
call npm install
call npm i -g gulp-cli
:: Set expiry if required
IF "%EXPIRY_PERIOD%"=="" (
echo "Not setting expiry for the build!"

View File

@ -5,6 +5,7 @@ call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Tools\VsDevCmd
echo %PATH%
set DISABLE_REBUILD=true
set NODE_REQUIRED_VERSION=12.13.1
set PATH=%PATH%;C:\Program Files\nodejs\;C:\Program Files\Git\cmd
echo %PATH%
@ -18,6 +19,15 @@ if %ERRORLEVEL% NEQ 0 (
EXIT /B 1
)
WHERE nvm
if %ERRORLEVEL% NEQ 0 (
echo "NVM does not exist. Please set it up before running this script."
EXIT /B 1
)
nvm install %NODE_REQUIRED_VERSION%
nvm use %NODE_REQUIRED_VERSION%
WHERE node
if %ERRORLEVEL% NEQ 0 (
echo "NODE does not exist. Please set it up before running this script."
@ -30,11 +40,8 @@ if %ERRORLEVEL% NEQ 0 (
EXIT /B 1
)
WHERE gulp
if %ERRORLEVEL% NEQ 0 (
echo "GULP does not exist. Please set it up before running this script."
EXIT /B 1
)
echo "Node version is: "
call node --version
:: Below command replaces buildVersion with the appropriate build number from jenkins
sed -i -e "s/\"buildNumber\"[[:space:]]*\:[[:space:]]*\".*\"/\"buildNumber\":\"%PARENT_BUILD_VERSION%\"/g" package.json
@ -46,8 +53,6 @@ echo D | xcopy /y "C:\jenkins\workspace\tronlibraries\library" "library"
echo "Running npm install..."
call npm install
call npm i -g gulp-cli
:: Set expiry if required
IF "%EXPIRY_PERIOD%"=="" (
echo "Not setting expiry for the build!"

View File

@ -8,6 +8,7 @@ import { analytics } from './analytics-handler';
import { config } from './config-handler';
import { memoryMonitor } from './memory-monitor';
import { protocolHandler } from './protocol-handler';
import { finalizeLogExports, registerLogRetriever } from './reports-handler';
import { screenSnippet } from './screen-snippet-handler';
import { activate, handleKeyPress } from './window-actions';
import { ICustomBrowserWindow, windowHandler } from './window-handler';
@ -53,6 +54,12 @@ ipcMain.on(apiName.symphonyApi, (event: Electron.IpcMainEvent, arg: IApiArgs) =>
// we make use of it and update the pod version info on SDA
windowHandler.updateVersionInfo();
break;
case apiCmds.registerLogRetriever:
registerLogRetriever(event.sender, arg.logName);
break;
case apiCmds.sendLogs:
finalizeLogExports(arg.logs);
break;
case apiCmds.badgeDataUrl:
if (typeof arg.dataUrl === 'string' && typeof arg.count === 'number') {
setDataUrl(arg.dataUrl, arg.count);

View File

@ -4,6 +4,7 @@ import * as electron from 'electron';
import * as fs from 'fs';
import * as path from 'path';
import { ILogs } from '../common/api-interface';
import { isLinux, isMac } from '../common/env';
import { i18n } from '../common/i18n';
import { logger } from '../common/logger';
@ -17,19 +18,30 @@ import { logger } from '../common/logger';
* @param fileExtensions {Array} array of file ext
* @return {Promise<void>}
*/
const generateArchiveForDirectory = (source: string, destination: string, fileExtensions: string[]): Promise<void> => {
const generateArchiveForDirectory = (source: string, destination: string, fileExtensions: string[], retrievedLogs: ILogs[]): Promise<void> => {
return new Promise((resolve, reject) => {
logger.info(`reports-handler: generating archive for directory ${source}`);
const output = fs.createWriteStream(destination);
const archive = archiver('zip', { zlib: { level: 9 } });
const filesForCleanup: string[] = [];
output.on('close', () => {
for (const file of filesForCleanup) {
if (fs.existsSync(file)) {
fs.unlinkSync(file);
}
}
logger.info(`reports-handler: generated archive for directory ${source}`);
return resolve();
});
archive.on('error', (err: Error) => {
for (const file of filesForCleanup) {
if (fs.existsSync(file)) {
fs.unlinkSync(file);
}
}
logger.error(`reports-handler: error archiving directory for ${source} with error ${err}`);
return reject(err);
});
@ -53,17 +65,40 @@ const generateArchiveForDirectory = (source: string, destination: string, fileEx
}
});
for (const logs of retrievedLogs) {
for (const logFile of logs.logFiles) {
const file = path.join( source, logFile.filename );
fs.writeFileSync(file, logFile.contents );
archive.file(file, { name: 'logs/' + logFile.filename });
filesForCleanup.push(file);
}
}
archive.finalize();
});
};
let logWebContents: Electron.WebContents;
const logTypes: string[] = [];
const receivedLogs: ILogs[] = [];
export const registerLogRetriever = (sender: Electron.WebContents, logName: string): void => {
logWebContents = sender;
logTypes.push( logName );
};
export const collectLogs = (): void => {
receivedLogs.length = 0;
logWebContents.send('collect-logs' );
};
/**
* Compress and export logs stored under system log directory
*
* MacOS - /Library/Logs/Symphony/
* Windows - AppData\Roaming\Symphony\logs
*/
export const exportLogs = (): void => {
export const packageLogs = (retrievedLogs: ILogs[]): void => {
const FILE_EXTENSIONS = [ '.log' ];
const MAC_LOGS_PATH = '/Library/Logs/Symphony/';
const LINUX_LOGS_PATH = '/.config/Symphony/';
@ -86,7 +121,7 @@ export const exportLogs = (): void => {
const timestamp = new Date().getTime();
const destination = app.getPath('downloads') + destPath + timestamp + '.zip';
generateArchiveForDirectory(source, destination, FILE_EXTENSIONS)
generateArchiveForDirectory(source, destination, FILE_EXTENSIONS, retrievedLogs)
.then(() => {
shell.showItemInFolder(destination);
})
@ -102,6 +137,31 @@ export const exportLogs = (): void => {
});
};
export const finalizeLogExports = (logs: ILogs) => {
receivedLogs.push(logs);
let allReceived = true;
for (const logType of logTypes) {
const found = receivedLogs.some((log) => log.logName === logType);
if (!found) {
allReceived = false;
}
}
if (allReceived) {
packageLogs(receivedLogs);
receivedLogs.length = 0;
}
};
export const exportLogs = (): void => {
if (logTypes.length > 0) {
collectLogs();
} else {
packageLogs([]);
}
};
/**
* Compress and export crash dump stored under system crashes directory
*/
@ -125,7 +185,7 @@ export const exportCrashDumps = (): void => {
const destination = electron.app.getPath('downloads') + destPath + timestamp + '.zip';
generateArchiveForDirectory(source, destination, FILE_EXTENSIONS)
generateArchiveForDirectory(source, destination, FILE_EXTENSIONS, [])
.then(() => {
electron.shell.showItemInFolder(destination);
})

View File

@ -4,6 +4,7 @@ import * as fs from 'fs';
import * as path from 'path';
import { format, parse } from 'url';
import { ChildProcess, ExecException, execFile } from 'child_process';
import { apiName, WindowTypes } from '../common/api-interface';
import { isDevEnv, isMac, isWindowsOS } from '../common/env';
import { i18n, LocaleType } from '../common/i18n';
@ -87,6 +88,7 @@ export class WindowHandler {
private screenSharingFrameWindow: Electron.BrowserWindow | null = null;
private basicAuthWindow: Electron.BrowserWindow | null = null;
private notificationSettingsWindow: Electron.BrowserWindow | null = null;
private screenShareIndicatorFrameUtil: string;
constructor(opts?: Electron.BrowserViewConstructorOptions) {
// Use these variables only on initial setup
@ -113,6 +115,11 @@ export class WindowHandler {
this.isAutoReload = false;
this.isOnline = true;
this.screenShareIndicatorFrameUtil = !isWindowsOS ? '' : isDevEnv
? path.join(__dirname,
'../../../node_modules/screen-share-indicator-frame/ScreenShareIndicatorFrame.exe')
: path.join(path.dirname(app.getPath('exe')), 'ScreenShareIndicatorFrame.exe');
this.appMenu = null;
const locale: LocaleType = (this.config.locale || app.getLocale()) as LocaleType;
i18n.setLocale(locale);
@ -364,8 +371,12 @@ export class WindowHandler {
if (browserWindow && windowExists(browserWindow)) {
browserWindow.destroy();
if (this.screenSharingFrameWindow && windowExists(this.screenSharingFrameWindow)) {
this.screenSharingFrameWindow.close();
if (isWindowsOS) {
this.execCmd(this.screenShareIndicatorFrameUtil, []);
} else {
if (this.screenSharingFrameWindow && windowExists(this.screenSharingFrameWindow)) {
this.screenSharingFrameWindow.close();
}
}
}
}
@ -420,6 +431,43 @@ export class WindowHandler {
return browserWindow && window === browserWindow;
}
/**
* Move window to the same screen as main window
*/
public moveWindow(windowToMove: BrowserWindow) {
if (this.mainWindow && windowExists(this.mainWindow)) {
const display = electron.screen.getDisplayMatching(this.mainWindow.getBounds());
logger.info('window-handler: moveWindow, display: ' + JSON.stringify(display.workArea));
logger.info('window-handler: moveWindow, windowToMove: ' + JSON.stringify(windowToMove.getBounds()));
if (display.workArea.width < windowToMove.getBounds().width) {
windowToMove.setSize(display.workArea.width, windowToMove.getBounds().height);
}
if (display.workArea.height < windowToMove.getBounds().height) {
windowToMove.setSize(windowToMove.getBounds().width, display.workArea.height);
}
let positionX = Math.trunc(display.workArea.x + display.workArea.width / 2 - windowToMove.getBounds().width / 2);
if (positionX < display.workArea.x) {
positionX = display.workArea.x;
}
let positionY = Math.trunc(display.workArea.y + display.workArea.height / 2 - windowToMove.getBounds().height / 2);
if (positionY < display.workArea.y) {
positionY = display.workArea.y;
}
logger.info('window-handler: moveWindow, positionX: ' + positionX);
logger.info('window-handler: moveWindow, positionY: ' + positionY);
windowToMove.setPosition(positionX, positionY);
// Because of a bug for windows10 we need to call setPosition twice
windowToMove.setPosition(positionX, positionY);
}
}
/**
* Creates a about app window
*/
@ -436,16 +484,17 @@ export class WindowHandler {
}
const allWindows = BrowserWindow.getAllWindows();
const selectedParentWindow = allWindows.find((window) => {
return (window as ICustomBrowserWindow).winName === windowName;
});
const opts: BrowserWindowConstructorOptions = this.getWindowOpts({
width: 420,
width: 550,
height: isWindowsOS ? 745 : 705,
modal: false,
alwaysOnTop: isMac,
resizable: true,
resizable: false,
}, {
devTools: false,
});
@ -459,6 +508,7 @@ export class WindowHandler {
}
this.aboutAppWindow = createComponentWindow('about-app', opts);
this.moveWindow(this.aboutAppWindow);
this.aboutAppWindow.setVisibleOnAllWorkspaces(true);
this.aboutAppWindow.webContents.once('did-finish-load', async () => {
const ABOUT_SYMPHONY_NAMESPACE = 'AboutSymphony';
@ -506,7 +556,7 @@ export class WindowHandler {
}
this.screenPickerWindow = createComponentWindow('screen-picker', opts);
this.moveWindow(this.screenPickerWindow);
this.screenPickerWindow.webContents.once('did-finish-load', () => {
if (!this.screenPickerWindow || !windowExists(this.screenPickerWindow)) {
return;
@ -520,6 +570,17 @@ export class WindowHandler {
this.addWindow(opts.winKey, this.screenPickerWindow);
});
ipcMain.once('screen-source-selected', (_event, source) => {
if (source != null) {
if (isWindowsOS) {
logger.info(`window-handler: screen-source-selected`, source, id);
const type = source.id.split(':')[0];
if (type === 'window') {
const hwnd = source.id.split(':')[1];
this.execCmd(this.screenShareIndicatorFrameUtil, [ hwnd ]);
}
}
}
window.send('start-share' + id, source);
if (this.screenPickerWindow && windowExists(this.screenPickerWindow)) {
this.screenPickerWindow.close();
@ -556,6 +617,7 @@ export class WindowHandler {
});
opts.parent = window;
this.basicAuthWindow = createComponentWindow('basic-auth', opts);
this.moveWindow(this.basicAuthWindow);
this.basicAuthWindow.setVisibleOnAllWorkspaces(true);
this.basicAuthWindow.webContents.once('did-finish-load', () => {
if (!this.basicAuthWindow || !windowExists(this.basicAuthWindow)) {
@ -625,6 +687,7 @@ export class WindowHandler {
}
this.notificationSettingsWindow = createComponentWindow('notification-settings', opts);
this.moveWindow(this.notificationSettingsWindow);
this.notificationSettingsWindow.setVisibleOnAllWorkspaces(true);
this.notificationSettingsWindow.webContents.on('did-finish-load', () => {
if (this.notificationSettingsWindow && windowExists(this.notificationSettingsWindow)) {
@ -715,11 +778,18 @@ export class WindowHandler {
displays.forEach((element) => {
if (displayId === element.id.toString()) {
this.createScrenSharingFrameWindow('screen-sharing-frame',
element.workArea.width,
element.workArea.height,
element.workArea.x,
element.workArea.y);
if (isWindowsOS) {
logger.info(`window-handler: element:`, element);
const winX: string = element.bounds.x.toString();
const winY: string = element.bounds.y.toString();
this.execCmd(this.screenShareIndicatorFrameUtil, [ winX, winY ]);
} else {
this.createScrenSharingFrameWindow('screen-sharing-frame',
element.workArea.width,
element.workArea.height,
element.workArea.x,
element.workArea.y);
}
}
});
}
@ -950,6 +1020,26 @@ export class WindowHandler {
return {...defaultWindowOpts, ...windowOpts};
}
/**
* Executes the given command via a child process
*
* @param util {string}
* @param utilArgs {ReadonlyArray<string>}
*/
private execCmd(util: string, utilArgs: ReadonlyArray<string>): Promise<ChildProcess> {
logger.info(`window handler: execCmd: util: ${util} utilArgs: ${utilArgs}`);
return new Promise<ChildProcess>((resolve, reject) => {
return execFile(util, utilArgs, (error: ExecException | null) => {
if (error && error.killed) {
// processs was killed, just resolve with no data.
return reject(error);
}
resolve();
});
});
}
}
const windowHandler = new WindowHandler();

View File

@ -7,6 +7,8 @@ export enum apiCmds {
activate = 'activate',
registerBoundsChange = 'register-bounds-change',
registerProtocolHandler = 'register-protocol-handler',
registerLogRetriever = 'register-log-retriever',
sendLogs = 'send-logs',
registerAnalyticsHandler = 'register-analytics-handler',
registerActivityDetection = 'register-activity-detection',
showNotificationSettings = 'show-notification-settings',
@ -62,6 +64,8 @@ export interface IApiArgs {
displayId: string;
path: string;
type: string;
logName: string;
logs: ILogs;
}
export type WindowTypes = 'screen-picker' | 'screen-sharing-indicator' | 'notification-settings';
@ -145,3 +149,13 @@ export interface ILogMsg {
}
export type LogLevel = 'error' | 'warn' | 'info' | 'verbose' | 'debug' | 'silly';
export interface ILogFile {
filename: string;
contents: string;
}
export interface ILogs {
logName: string;
logFiles: ILogFile[];
}

View File

@ -126,6 +126,16 @@
<image id='snippet-img'/>
<button id='cancel-snippet'>cancel snippet</button>
<hr>
<p>Logs:</p>
Filename <input type='text' id='log-filename' value='test_log.log'/>
<p>Contents</p>
<textarea id="log-contents" rows="4">Test log contents</textarea>
<p/>
Filename <input type='text' id='log-filename2' value=''/>
<p>Contents</p>
<textarea id="log-contents2" rows="4"></textarea>
<hr>
<p>Window activate:</p>
<button id='open-win'>open window</button>
@ -176,6 +186,8 @@
activate: 'activate',
registerBoundsChange: 'register-bounds-change',
registerProtocolHandler: 'register-protocol-handler',
registerLogRetriever: 'register-log-retriever',
sendLogs: 'send-logs',
registerAnalyticHandler: 'register-analytic-handler',
registerActivityDetection: 'register-activity-detection',
showNotificationSettings: 'show-notification-settings',
@ -440,9 +452,33 @@
window.postMessage({ method, data }, '*');
};
const getTestLogs = () => {
if (document.getElementById('log-filename2').value == '') {
const filename = document.getElementById('log-filename').value;
const contents = document.getElementById('log-contents').value;
return [ { filename, contents }, ];
} else {
const filename1 = document.getElementById('log-filename').value;
const contents1 = document.getElementById('log-contents').value;
const filename2 = document.getElementById('log-filename2').value;
const contents2 = document.getElementById('log-contents2').value;
return [ { filename: filename1, contents: contents1 },
{ filename: filename2, contents: contents2 }, ];
}
}
const logTypeTestLogs = 'TestLogs';
window.addEventListener('message', (event) => {
const { data, method } = event.data;
switch (method) {
case 'collect-logs':
if (window.ssf) {
window.ssf.sendLogs(logTypeTestLogs, getTestLogs());
} else {
postMessage( apiCmds.sendLogs, { logName: logTypeTestLogs, logFiles: getTestLogs() } );
}
break;
case 'activity-callback':
activityCallback(data);
break;
@ -469,6 +505,15 @@
}
});
/**
* Log retriever
*/
if (window.ssf) {
window.ssf.registerLogRetriever(logTypeTestLogs);
} else {
postMessage(apiCmds.registerLogRetriever, logTypeTestLogs);
}
/**
* Analytic events
*/

View File

@ -49,6 +49,7 @@ export class AppBridge {
onRegisterLoggerCallback: (msg: ILogMsg, logLevel: LogLevel, showInConsole: boolean) =>
this.registerLoggerCallback(msg, logLevel, showInConsole),
onRegisterProtocolHandlerCallback: (uri: string) => this.protocolHandlerCallback(uri),
onCollectLogsCallback: () => this.collectLogsCallback(),
onScreenSharingIndicatorCallback: (arg: IScreenSharingIndicator) => this.screenSharingIndicatorCallback(arg),
onMediaSourceCallback: (
error: IScreenSourceError | null,
@ -126,6 +127,12 @@ export class AppBridge {
case apiCmds.registerProtocolHandler:
ssf.registerProtocolHandler(this.callbackHandlers.onRegisterProtocolHandlerCallback);
break;
case apiCmds.registerLogRetriever:
ssf.registerLogRetriever(this.callbackHandlers.onCollectLogsCallback, data);
break;
case apiCmds.sendLogs:
ssf.sendLogs(data.logName, data.logFiles);
break;
case apiCmds.openScreenSharingIndicator:
ssf.openScreenSharingIndicator(data as IScreenSharingIndicatorOptions, this.callbackHandlers.onScreenSharingIndicatorCallback);
break;
@ -194,6 +201,8 @@ export class AppBridge {
*/
private protocolHandlerCallback = (uri: string): void => this.broadcastMessage('protocol-callback', uri);
private collectLogsCallback = (): void => this.broadcastMessage('collect-logs', undefined);
/**
* Broadcast event that stops screen sharing
* @param arg {IScreenSharingIndicator}

View File

@ -1,4 +1,4 @@
import { clipboard, ipcRenderer, remote } from 'electron';
import { ipcRenderer, remote } from 'electron';
import * as React from 'react';
import { i18n } from '../../common/i18n-preload';
@ -149,7 +149,7 @@ export default class AboutApp extends React.Component<{}, IState> {
public copy(): void {
const data = this.state;
if (data) {
clipboard.write({ text: JSON.stringify(data) }, 'clipboard' );
remote.clipboard.write({ text: JSON.stringify(data) }, 'clipboard' );
}
}

View File

@ -419,6 +419,7 @@ class Notification extends NotificationHandler {
frame: false,
transparent: true,
acceptFirstMouse: true,
title: 'Notification - Symphony',
webPreferences: {
sandbox: true,
nodeIntegration: false,

View File

@ -38,6 +38,7 @@ export interface ILocalObject {
boundsChangeCallback?: (arg: IBoundsChange) => void;
screenSharingIndicatorCallback?: (arg: IScreenSharingIndicator) => void;
protocolActionCallback?: (arg: string) => void;
collectLogsCallback?: Array<( () => void )>;
analyticsEventHandler?: (arg: any) => void;
}
@ -263,6 +264,35 @@ export class SSFApi {
}
}
/**
* Allows JS to register a log retriever that can be used by the
* electron main process to retrieve current logs.
*/
public registerLogRetriever(collectLogs: () => void, logName: string): void {
if (typeof collectLogs === 'function') {
if (!local.collectLogsCallback) {
local.collectLogsCallback = new Array<( () => void )>();
}
local.collectLogsCallback.push(collectLogs);
local.ipcRenderer.send(apiName.symphonyApi, {
cmd: apiCmds.registerLogRetriever,
logName,
});
}
}
/**
* Send log files to main process when requested.
*/
public sendLogs(logName: string, logFiles): void {
local.ipcRenderer.send(apiName.symphonyApi, {
cmd: apiCmds.sendLogs,
logs: { logName, logFiles },
});
}
/**
* Allows JS to register analytics event handler
* to pass analytics event data
@ -501,6 +531,14 @@ local.ipcRenderer.on('screen-snippet-data', (_event: Event, arg: IScreenSnippet)
}
});
local.ipcRenderer.on('collect-logs', ( _event: Event ) => {
if (local.collectLogsCallback) {
for (const callback of local.collectLogsCallback) {
callback();
}
}
});
/**
* An event triggered by the main process
* for ever few minutes if the user is active

View File

@ -6,7 +6,6 @@
@text-padding: 10px;
body {
overflow: scroll;
background-color: white;
margin: 0;
height: 100%;