Merged electron into main code. One unified codebase for both web and native version of client.
parent
aea08b4cbe
commit
99dd6433a6
|
|
@ -0,0 +1,2 @@
|
||||||
|
react: npm start
|
||||||
|
electron: node src/electron-wait-react
|
||||||
|
|
@ -5,6 +5,8 @@
|
||||||
"description": "multiparty meeting service",
|
"description": "multiparty meeting service",
|
||||||
"author": "Håvar Aambø Fosstveit <h@fosstveit.net>",
|
"author": "Håvar Aambø Fosstveit <h@fosstveit.net>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"homepage": "./",
|
||||||
|
"main": "src/electron-starter.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@material-ui/core": "^4.5.1",
|
"@material-ui/core": "^4.5.1",
|
||||||
"@material-ui/icons": "^4.5.1",
|
"@material-ui/icons": "^4.5.1",
|
||||||
|
|
@ -13,6 +15,7 @@
|
||||||
"domready": "^1.0.8",
|
"domready": "^1.0.8",
|
||||||
"file-saver": "^2.0.2",
|
"file-saver": "^2.0.2",
|
||||||
"hark": "^1.2.3",
|
"hark": "^1.2.3",
|
||||||
|
"is-electron": "^2.2.0",
|
||||||
"marked": "^0.7.0",
|
"marked": "^0.7.0",
|
||||||
"mediasoup-client": "^3.2.7",
|
"mediasoup-client": "^3.2.7",
|
||||||
"notistack": "^0.9.5",
|
"notistack": "^0.9.5",
|
||||||
|
|
@ -41,7 +44,9 @@
|
||||||
"start": "HTTPS=true PORT=4443 react-scripts start",
|
"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/",
|
"build": "react-scripts build && mkdir -p ../server/public && rm -rf ../server/public/* && cp -r build/* ../server/public/",
|
||||||
"test": "react-scripts test",
|
"test": "react-scripts test",
|
||||||
"eject": "react-scripts eject"
|
"eject": "react-scripts eject",
|
||||||
|
"electron": "electron .",
|
||||||
|
"dev": "nf start -p 3000"
|
||||||
},
|
},
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
">0.2%",
|
">0.2%",
|
||||||
|
|
@ -50,8 +55,10 @@
|
||||||
"not op_mini all"
|
"not op_mini all"
|
||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"electron": "^7.1.1",
|
||||||
"eslint": "^6.5.1",
|
"eslint": "^6.5.1",
|
||||||
"eslint-plugin-import": "^2.18.2",
|
"eslint-plugin-import": "^2.18.2",
|
||||||
"eslint-plugin-react": "^7.16.0"
|
"eslint-plugin-react": "^7.16.0",
|
||||||
|
"foreman": "^3.0.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ var config =
|
||||||
{
|
{
|
||||||
loginEnabled : false,
|
loginEnabled : false,
|
||||||
developmentPort : 3443,
|
developmentPort : 3443,
|
||||||
|
productionPort : 443,
|
||||||
|
multipartyServer : 'letsmeet.no',
|
||||||
turnServers : [
|
turnServers : [
|
||||||
{
|
{
|
||||||
urls : [
|
urls : [
|
||||||
|
|
|
||||||
|
|
@ -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
|
class DisplayMediaScreenShare
|
||||||
{
|
{
|
||||||
constructor()
|
constructor()
|
||||||
|
|
@ -130,6 +197,10 @@ class DefaultScreenShare
|
||||||
export default class ScreenShare
|
export default class ScreenShare
|
||||||
{
|
{
|
||||||
static create(device)
|
static create(device)
|
||||||
|
{
|
||||||
|
if (isElectron())
|
||||||
|
return new ElectronScreenShare();
|
||||||
|
else
|
||||||
{
|
{
|
||||||
switch (device.flag)
|
switch (device.flag)
|
||||||
{
|
{
|
||||||
|
|
@ -154,4 +225,5 @@ export default class ScreenShare
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { useEffect, Suspense } from 'react';
|
import React, { useEffect, Suspense } from 'react';
|
||||||
import { useParams} from 'react-router';
|
import { useParams } from 'react-router';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import JoinDialog from './JoinDialog';
|
import JoinDialog from './JoinDialog';
|
||||||
|
|
@ -14,7 +14,7 @@ const App = (props) =>
|
||||||
room
|
room
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
let { id } = useParams();
|
const { id } = useParams();
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { Link } from 'react-router-dom';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { withStyles } from '@material-ui/core/styles';
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
import { withRoomContext } from '../RoomContext';
|
import { withRoomContext } from '../RoomContext';
|
||||||
|
import isElectron from 'is-electron';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { useIntl, FormattedMessage } from 'react-intl';
|
import { useIntl, FormattedMessage } from 'react-intl';
|
||||||
import randomString from 'random-string';
|
import randomString from 'random-string';
|
||||||
|
|
@ -239,12 +240,14 @@ const ChooseRoom = ({
|
||||||
</Button>
|
</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
|
|
||||||
|
{ !isElectron() &&
|
||||||
<CookieConsent>
|
<CookieConsent>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='room.cookieConsent'
|
id='room.cookieConsent'
|
||||||
defaultMessage='This website uses cookies to enhance the user experience'
|
defaultMessage='This website uses cookies to enhance the user experience'
|
||||||
/>
|
/>
|
||||||
</CookieConsent>
|
</CookieConsent>
|
||||||
|
}
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { withStyles } from '@material-ui/core/styles';
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
import { withRoomContext } from '../RoomContext';
|
import { withRoomContext } from '../RoomContext';
|
||||||
|
import isElectron from 'is-electron';
|
||||||
import * as settingsActions from '../actions/settingsActions';
|
import * as settingsActions from '../actions/settingsActions';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { useIntl, FormattedMessage } from 'react-intl';
|
import { useIntl, FormattedMessage } from 'react-intl';
|
||||||
|
|
@ -334,12 +335,14 @@ const JoinDialog = ({
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{ !isElectron() &&
|
||||||
<CookieConsent>
|
<CookieConsent>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='room.cookieConsent'
|
id='room.cookieConsent'
|
||||||
defaultMessage='This website uses cookies to enhance the user experience'
|
defaultMessage='This website uses cookies to enhance the user experience'
|
||||||
/>
|
/>
|
||||||
</CookieConsent>
|
</CookieConsent>
|
||||||
|
}
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { connect } from 'react-redux';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import * as appPropTypes from './appPropTypes';
|
import * as appPropTypes from './appPropTypes';
|
||||||
import { withStyles } from '@material-ui/core/styles';
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
|
import isElectron from 'is-electron';
|
||||||
import * as roomActions from '../actions/roomActions';
|
import * as roomActions from '../actions/roomActions';
|
||||||
import * as toolareaActions from '../actions/toolareaActions';
|
import * as toolareaActions from '../actions/toolareaActions';
|
||||||
import { idle } from '../utils';
|
import { idle } from '../utils';
|
||||||
|
|
@ -152,12 +153,14 @@ class Room extends React.PureComponent
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.root}>
|
<div className={classes.root}>
|
||||||
|
{ !isElectron() &&
|
||||||
<CookieConsent>
|
<CookieConsent>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='room.cookieConsent'
|
id='room.cookieConsent'
|
||||||
defaultMessage='This website uses cookies to enhance the user experience'
|
defaultMessage='This website uses cookies to enhance the user experience'
|
||||||
/>
|
/>
|
||||||
</CookieConsent>
|
</CookieConsent>
|
||||||
|
}
|
||||||
|
|
||||||
<FullScreenView advancedMode={advancedMode} />
|
<FullScreenView advancedMode={advancedMode} />
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
@ -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);
|
||||||
|
});
|
||||||
|
|
@ -3,7 +3,7 @@ import React, { Suspense } from 'react';
|
||||||
import { render } from 'react-dom';
|
import { render } from 'react-dom';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import { createIntl, createIntlCache, RawIntlProvider } from 'react-intl';
|
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 randomString from 'random-string';
|
||||||
import Logger from './Logger';
|
import Logger from './Logger';
|
||||||
import debug from 'debug';
|
import debug from 'debug';
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,12 @@
|
||||||
export function getSignalingUrl(peerId, roomId)
|
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}`;
|
const url = `wss://${hostname}:${port}/?peerId=${peerId}&roomId=${roomId}`;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue