Merged electron into main code. One unified codebase for both web and native version of client.

master
Håvar Aambø Fosstveit 2019-11-10 23:57:28 +01:00
parent aea08b4cbe
commit 99dd6433a6
12 changed files with 230 additions and 45 deletions

2
app/Procfile 100644
View File

@ -0,0 +1,2 @@
react: npm start
electron: node src/electron-wait-react

View File

@ -5,6 +5,8 @@
"description": "multiparty meeting service",
"author": "Håvar Aambø Fosstveit <h@fosstveit.net>",
"license": "MIT",
"homepage": "./",
"main": "src/electron-starter.js",
"dependencies": {
"@material-ui/core": "^4.5.1",
"@material-ui/icons": "^4.5.1",
@ -13,6 +15,7 @@
"domready": "^1.0.8",
"file-saver": "^2.0.2",
"hark": "^1.2.3",
"is-electron": "^2.2.0",
"marked": "^0.7.0",
"mediasoup-client": "^3.2.7",
"notistack": "^0.9.5",
@ -41,7 +44,9 @@
"start": "HTTPS=true PORT=4443 react-scripts start",
"build": "react-scripts build && mkdir -p ../server/public && rm -rf ../server/public/* && cp -r build/* ../server/public/",
"test": "react-scripts test",
"eject": "react-scripts eject"
"eject": "react-scripts eject",
"electron": "electron .",
"dev": "nf start -p 3000"
},
"browserslist": [
">0.2%",
@ -50,8 +55,10 @@
"not op_mini all"
],
"devDependencies": {
"electron": "^7.1.1",
"eslint": "^6.5.1",
"eslint-plugin-import": "^2.18.2",
"eslint-plugin-react": "^7.16.0"
"eslint-plugin-react": "^7.16.0",
"foreman": "^3.0.1"
}
}

View File

@ -3,6 +3,8 @@ var config =
{
loginEnabled : false,
developmentPort : 3443,
productionPort : 443,
multipartyServer : 'letsmeet.no',
turnServers : [
{
urls : [

View File

@ -1,3 +1,70 @@
import isElectron from 'is-electron';
let electron = null;
if (isElectron())
electron = window.require('electron');
class ElectronScreenShare
{
constructor()
{
this._stream = null;
}
start()
{
return Promise.resolve()
.then(() =>
{
return electron.desktopCapturer.getSources({ types: [ 'window', 'screen' ] });
})
.then((sources) =>
{
for (const source of sources)
{
// Currently only getting whole screen
if (source.name === 'Entire Screen')
{
return navigator.mediaDevices.getUserMedia({
audio : false,
video :
{
mandatory :
{
chromeMediaSource : 'desktop',
chromeMediaSourceId : source.id
}
}
});
}
}
})
.then((stream) =>
{
this._stream = stream;
return stream;
});
}
stop()
{
if (this._stream instanceof MediaStream === false)
{
return;
}
this._stream.getTracks().forEach((track) => track.stop());
this._stream = null;
}
isScreenShareAvailable()
{
return true;
}
}
class DisplayMediaScreenShare
{
constructor()
@ -130,6 +197,10 @@ class DefaultScreenShare
export default class ScreenShare
{
static create(device)
{
if (isElectron())
return new ElectronScreenShare();
else
{
switch (device.flag)
{
@ -154,4 +225,5 @@ export default class ScreenShare
}
}
}
}
}

View File

@ -1,5 +1,5 @@
import React, { useEffect, Suspense } from 'react';
import { useParams} from 'react-router';
import { useParams } from 'react-router';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import JoinDialog from './JoinDialog';
@ -14,7 +14,7 @@ const App = (props) =>
room
} = props;
let { id } = useParams();
const { id } = useParams();
useEffect(() =>
{

View File

@ -3,6 +3,7 @@ import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import { withStyles } from '@material-ui/core/styles';
import { withRoomContext } from '../RoomContext';
import isElectron from 'is-electron';
import PropTypes from 'prop-types';
import { useIntl, FormattedMessage } from 'react-intl';
import randomString from 'random-string';
@ -239,12 +240,14 @@ const ChooseRoom = ({
</Button>
</DialogActions>
{ !isElectron() &&
<CookieConsent>
<FormattedMessage
id='room.cookieConsent'
defaultMessage='This website uses cookies to enhance the user experience'
/>
</CookieConsent>
}
</Dialog>
</div>
);

View File

@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react';
import { connect } from 'react-redux';
import { withStyles } from '@material-ui/core/styles';
import { withRoomContext } from '../RoomContext';
import isElectron from 'is-electron';
import * as settingsActions from '../actions/settingsActions';
import PropTypes from 'prop-types';
import { useIntl, FormattedMessage } from 'react-intl';
@ -334,12 +335,14 @@ const JoinDialog = ({
</DialogContent>
}
{ !isElectron() &&
<CookieConsent>
<FormattedMessage
id='room.cookieConsent'
defaultMessage='This website uses cookies to enhance the user experience'
/>
</CookieConsent>
}
</Dialog>
</div>
);

View File

@ -3,6 +3,7 @@ import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import * as appPropTypes from './appPropTypes';
import { withStyles } from '@material-ui/core/styles';
import isElectron from 'is-electron';
import * as roomActions from '../actions/roomActions';
import * as toolareaActions from '../actions/toolareaActions';
import { idle } from '../utils';
@ -152,12 +153,14 @@ class Room extends React.PureComponent
return (
<div className={classes.root}>
{ !isElectron() &&
<CookieConsent>
<FormattedMessage
id='room.cookieConsent'
defaultMessage='This website uses cookies to enhance the user experience'
/>
</CookieConsent>
}
<FullScreenView advancedMode={advancedMode} />

View File

@ -0,0 +1,50 @@
const electron = require('electron');
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;
const path = require('path');
const url = require('url');
let mainWindow;
function createWindow()
{
mainWindow = new BrowserWindow({
width : 1280,
height : 720,
webPreferences : { nodeIntegration: true }
});
const startUrl = process.env.ELECTRON_START_URL || url.format({
pathname : path.join(__dirname, '/../build/index.html'),
protocol : 'file:',
slashes : true
});
mainWindow.loadURL(startUrl);
mainWindow.on('closed', () =>
{
mainWindow = null;
});
}
app.on('ready', createWindow);
app.on('window-all-closed', () =>
{
if (process.platform !== 'darwin')
{
app.quit();
}
});
app.on('activate', () =>
{
if (mainWindow === null)
{
createWindow();
}
});

View File

@ -0,0 +1,39 @@
const net = require('net');
const port = process.env.PORT ? (process.env.PORT - 100) : 3000;
process.env.ELECTRON_START_URL = `http://localhost:${port}`;
const client = new net.Socket();
let startedElectron = false;
const tryConnection = () =>
client.connect({ port: port }, () =>
{
client.end();
if (!startedElectron)
{
// eslint-disable-next-line no-console
console.log('starting electron');
startedElectron = true;
const exec = require('child_process').exec;
const electron = exec('npm run electron');
electron.stdout.on('data', (data) =>
{
// eslint-disable-next-line no-console
console.log(`stdout: ${data.toString()}`);
});
}
});
tryConnection();
client.on('error', () =>
{
setTimeout(tryConnection, 1000);
});

View File

@ -3,7 +3,7 @@ import React, { Suspense } from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import { createIntl, createIntlCache, RawIntlProvider } from 'react-intl';
import { Route, BrowserRouter as Router } from 'react-router-dom'
import { Route, HashRouter as Router } from 'react-router-dom';
import randomString from 'random-string';
import Logger from './Logger';
import debug from 'debug';

View File

@ -1,8 +1,12 @@
export function getSignalingUrl(peerId, roomId)
{
const hostname = window.location.hostname;
const hostname = window.config.multipartyServer;
const port = process.env.NODE_ENV !== 'production' ? window.config.developmentPort : window.location.port;
const port =
process.env.NODE_ENV !== 'production' ?
window.config.developmentPort
:
window.config.productionPort;
const url = `wss://${hostname}:${port}/?peerId=${peerId}&roomId=${roomId}`;