Merge pull request #28 from torjusti/fix/server-refactor
[WIP] Use Express instead of custom server, passport for auth and refactor server files Remember: config.example.js changed!master
commit
7800474234
|
|
@ -129,8 +129,6 @@ export default class RoomClient
|
||||||
|
|
||||||
login()
|
login()
|
||||||
{
|
{
|
||||||
this._dispatch(stateActions.setLoginInProgress(true));
|
|
||||||
|
|
||||||
const url = `/login?roomId=${this._room.roomId}&peerName=${this._peerName}`;
|
const url = `/login?roomId=${this._room.roomId}&peerName=${this._peerName}`;
|
||||||
|
|
||||||
this._loginWindow = window.open(url, 'loginWindow');
|
this._loginWindow = window.open(url, 'loginWindow');
|
||||||
|
|
@ -1079,8 +1077,6 @@ export default class RoomClient
|
||||||
logger.debug('got auth event from server', request.data);
|
logger.debug('got auth event from server', request.data);
|
||||||
accept();
|
accept();
|
||||||
|
|
||||||
if (request.data.verified == true)
|
|
||||||
{
|
|
||||||
this.changeDisplayName(request.data.name);
|
this.changeDisplayName(request.data.name);
|
||||||
|
|
||||||
this.changeProfilePicture(request.data.picture);
|
this.changeProfilePicture(request.data.picture);
|
||||||
|
|
@ -1091,20 +1087,10 @@ export default class RoomClient
|
||||||
text : `Authenticated successfully: ${request.data}`
|
text : `Authenticated successfully: ${request.data}`
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this._dispatch(requestActions.notify(
|
|
||||||
{
|
|
||||||
text : `Authentication failed: ${request.data}`
|
|
||||||
}
|
|
||||||
));
|
|
||||||
}
|
|
||||||
this.closeLoginWindow();
|
this.closeLoginWindow();
|
||||||
|
|
||||||
this._dispatch(stateActions.setLoginInProgress(false));
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'raisehand-message':
|
case 'raisehand-message':
|
||||||
|
|
|
||||||
|
|
@ -129,9 +129,7 @@ class Sidebar extends Component
|
||||||
|
|
||||||
{me.loginEnabled ?
|
{me.loginEnabled ?
|
||||||
<div
|
<div
|
||||||
className={classnames('button', 'login', 'off', {
|
className='button login off'
|
||||||
disabled : me.loginInProgress
|
|
||||||
})}
|
|
||||||
data-tip='Login'
|
data-tip='Login'
|
||||||
data-type='dark'
|
data-type='dark'
|
||||||
onClick={() => onLogin()}
|
onClick={() => onLogin()}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ const initialState =
|
||||||
webcamInProgress : false,
|
webcamInProgress : false,
|
||||||
audioInProgress : false,
|
audioInProgress : false,
|
||||||
screenShareInProgress : false,
|
screenShareInProgress : false,
|
||||||
loginInProgress : false,
|
|
||||||
loginEnabled : false,
|
loginEnabled : false,
|
||||||
audioOnly : false,
|
audioOnly : false,
|
||||||
audioOnlyInProgress : false,
|
audioOnlyInProgress : false,
|
||||||
|
|
@ -124,13 +123,6 @@ const me = (state = initialState, action) =>
|
||||||
return { ...state, screenShareInProgress: flag };
|
return { ...state, screenShareInProgress: flag };
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'SET_LOGIN_IN_PROGRESS':
|
|
||||||
{
|
|
||||||
const { flag } = action.payload;
|
|
||||||
|
|
||||||
return { ...state, loginInProgress: flag };
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'SET_DISPLAY_NAME':
|
case 'SET_DISPLAY_NAME':
|
||||||
{
|
{
|
||||||
let { displayName } = action.payload;
|
let { displayName } = action.payload;
|
||||||
|
|
|
||||||
|
|
@ -147,14 +147,6 @@ export const setMyRaiseHandState = (flag) =>
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const setLoginInProgress = (flag) =>
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
type : 'SET_LOGIN_IN_PROGRESS',
|
|
||||||
payload : { flag }
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const toggleSettings = () =>
|
export const toggleSettings = () =>
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,9 @@ module.exports =
|
||||||
// oAuth2 conf
|
// oAuth2 conf
|
||||||
oauth2 :
|
oauth2 :
|
||||||
{
|
{
|
||||||
client_id : '',
|
clientID : '',
|
||||||
client_secret : '',
|
clientSecret : '',
|
||||||
providerID : '',
|
callbackURL : 'https://mYDomainName:port/auth-callback'
|
||||||
redirect_uri : 'https://mYDomainName:port/auth-callback',
|
|
||||||
authorization_endpoint : '',
|
|
||||||
userinfo_endpoint : '',
|
|
||||||
token_endpoint : '',
|
|
||||||
scopes : { request : [ 'openid', 'userid','profile'] },
|
|
||||||
response_type : 'code'
|
|
||||||
},
|
},
|
||||||
// Listening hostname for `gulp live|open`.
|
// Listening hostname for `gulp live|open`.
|
||||||
domain : 'localhost',
|
domain : 'localhost',
|
||||||
|
|
|
||||||
|
|
@ -15,20 +15,30 @@ const gulp = require('gulp');
|
||||||
const plumber = require('gulp-plumber');
|
const plumber = require('gulp-plumber');
|
||||||
const eslint = require('gulp-eslint');
|
const eslint = require('gulp-eslint');
|
||||||
|
|
||||||
gulp.task('lint', () =>
|
const LINTING_FILES =
|
||||||
{
|
[
|
||||||
const src =
|
|
||||||
[
|
|
||||||
'gulpfile.js',
|
'gulpfile.js',
|
||||||
'server.js',
|
'server.js',
|
||||||
'config.example.js',
|
'config.example.js',
|
||||||
'lib/**/*.js'
|
'lib/**/*.js'
|
||||||
];
|
];
|
||||||
|
|
||||||
return gulp.src(src)
|
gulp.task('lint', () =>
|
||||||
|
{
|
||||||
|
|
||||||
|
return gulp.src(LINTING_FILES)
|
||||||
.pipe(plumber())
|
.pipe(plumber())
|
||||||
.pipe(eslint())
|
.pipe(eslint())
|
||||||
.pipe(eslint.format());
|
.pipe(eslint.format());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
gulp.task('lint-fix', function()
|
||||||
|
{
|
||||||
|
return gulp.src(LINTING_FILES)
|
||||||
|
.pipe(plumber())
|
||||||
|
.pipe(eslint({ fix: true }))
|
||||||
|
.pipe(eslint.format())
|
||||||
|
.pipe(gulp.dest((file) => file.base));
|
||||||
|
});
|
||||||
|
|
||||||
gulp.task('default', gulp.series('lint'));
|
gulp.task('default', gulp.series('lint'));
|
||||||
|
|
|
||||||
|
|
@ -233,8 +233,8 @@ class Room extends EventEmitter
|
||||||
accept();
|
accept();
|
||||||
|
|
||||||
this._protooRoom.spread('profile-picture-changed', {
|
this._protooRoom.spread('profile-picture-changed', {
|
||||||
peerName: protooPeer.id,
|
peerName : protooPeer.id,
|
||||||
picture: request.data.picture
|
picture : request.data.picture
|
||||||
}, [ protooPeer ]);
|
}, [ protooPeer ]);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,321 @@
|
||||||
|
const mediasoup = require('mediasoup');
|
||||||
|
const readline = require('readline');
|
||||||
|
const colors = require('colors/safe');
|
||||||
|
const repl = require('repl');
|
||||||
|
const homer = require('./lib/homer');
|
||||||
|
const config = require('./config');
|
||||||
|
|
||||||
|
// mediasoup server.
|
||||||
|
const mediaServer = mediasoup.Server(
|
||||||
|
{
|
||||||
|
numWorkers : 1,
|
||||||
|
logLevel : config.mediasoup.logLevel,
|
||||||
|
logTags : config.mediasoup.logTags,
|
||||||
|
rtcIPv4 : config.mediasoup.rtcIPv4,
|
||||||
|
rtcIPv6 : config.mediasoup.rtcIPv6,
|
||||||
|
rtcAnnouncedIPv4 : config.mediasoup.rtcAnnouncedIPv4,
|
||||||
|
rtcAnnouncedIPv6 : config.mediasoup.rtcAnnouncedIPv6,
|
||||||
|
rtcMinPort : config.mediasoup.rtcMinPort,
|
||||||
|
rtcMaxPort : config.mediasoup.rtcMaxPort
|
||||||
|
});
|
||||||
|
|
||||||
|
// Do Homer stuff.
|
||||||
|
if (process.env.MEDIASOUP_HOMER_OUTPUT)
|
||||||
|
homer(mediaServer);
|
||||||
|
|
||||||
|
global.SERVER = mediaServer;
|
||||||
|
|
||||||
|
mediaServer.on('newroom', (room) =>
|
||||||
|
{
|
||||||
|
global.ROOM = room;
|
||||||
|
|
||||||
|
room.on('newpeer', (peer) =>
|
||||||
|
{
|
||||||
|
global.PEER = peer;
|
||||||
|
|
||||||
|
if (peer.consumers.length > 0)
|
||||||
|
global.CONSUMER = peer.consumers[peer.consumers.length - 1];
|
||||||
|
|
||||||
|
peer.on('newtransport', (transport) =>
|
||||||
|
{
|
||||||
|
global.TRANSPORT = transport;
|
||||||
|
});
|
||||||
|
|
||||||
|
peer.on('newproducer', (producer) =>
|
||||||
|
{
|
||||||
|
global.PRODUCER = producer;
|
||||||
|
});
|
||||||
|
|
||||||
|
peer.on('newconsumer', (consumer) =>
|
||||||
|
{
|
||||||
|
global.CONSUMER = consumer;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Listen for keyboard input.
|
||||||
|
|
||||||
|
let cmd;
|
||||||
|
let terminal;
|
||||||
|
|
||||||
|
openCommandConsole();
|
||||||
|
|
||||||
|
function openCommandConsole()
|
||||||
|
{
|
||||||
|
stdinLog('[opening Readline Command Console...]');
|
||||||
|
|
||||||
|
closeCommandConsole();
|
||||||
|
closeTerminal();
|
||||||
|
|
||||||
|
cmd = readline.createInterface(
|
||||||
|
{
|
||||||
|
input : process.stdin,
|
||||||
|
output : process.stdout
|
||||||
|
});
|
||||||
|
|
||||||
|
cmd.on('SIGINT', () =>
|
||||||
|
{
|
||||||
|
process.exit();
|
||||||
|
});
|
||||||
|
|
||||||
|
readStdin();
|
||||||
|
|
||||||
|
function readStdin()
|
||||||
|
{
|
||||||
|
cmd.question('cmd> ', (answer) =>
|
||||||
|
{
|
||||||
|
switch (answer)
|
||||||
|
{
|
||||||
|
case '':
|
||||||
|
{
|
||||||
|
readStdin();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'h':
|
||||||
|
case 'help':
|
||||||
|
{
|
||||||
|
stdinLog('');
|
||||||
|
stdinLog('available commands:');
|
||||||
|
stdinLog('- h, help : show this message');
|
||||||
|
stdinLog('- sd, serverdump : execute server.dump()');
|
||||||
|
stdinLog('- rd, roomdump : execute room.dump() for the latest created mediasoup Room');
|
||||||
|
stdinLog('- pd, peerdump : execute peer.dump() for the latest created mediasoup Peer');
|
||||||
|
stdinLog('- td, transportdump : execute transport.dump() for the latest created mediasoup Transport');
|
||||||
|
stdinLog('- prd, producerdump : execute producer.dump() for the latest created mediasoup Producer');
|
||||||
|
stdinLog('- cd, consumerdump : execute consumer.dump() for the latest created mediasoup Consumer');
|
||||||
|
stdinLog('- t, terminal : open REPL Terminal');
|
||||||
|
stdinLog('');
|
||||||
|
readStdin();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'sd':
|
||||||
|
case 'serverdump':
|
||||||
|
{
|
||||||
|
mediaServer.dump()
|
||||||
|
.then((data) =>
|
||||||
|
{
|
||||||
|
stdinLog(`server.dump() succeeded:\n${JSON.stringify(data, null, ' ')}`);
|
||||||
|
readStdin();
|
||||||
|
})
|
||||||
|
.catch((error) =>
|
||||||
|
{
|
||||||
|
stdinError(`mediaServer.dump() failed: ${error}`);
|
||||||
|
readStdin();
|
||||||
|
});
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'rd':
|
||||||
|
case 'roomdump':
|
||||||
|
{
|
||||||
|
if (!global.ROOM)
|
||||||
|
{
|
||||||
|
readStdin();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
global.ROOM.dump()
|
||||||
|
.then((data) =>
|
||||||
|
{
|
||||||
|
stdinLog(`room.dump() succeeded:\n${JSON.stringify(data, null, ' ')}`);
|
||||||
|
readStdin();
|
||||||
|
})
|
||||||
|
.catch((error) =>
|
||||||
|
{
|
||||||
|
stdinError(`room.dump() failed: ${error}`);
|
||||||
|
readStdin();
|
||||||
|
});
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'pd':
|
||||||
|
case 'peerdump':
|
||||||
|
{
|
||||||
|
if (!global.PEER)
|
||||||
|
{
|
||||||
|
readStdin();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
global.PEER.dump()
|
||||||
|
.then((data) =>
|
||||||
|
{
|
||||||
|
stdinLog(`peer.dump() succeeded:\n${JSON.stringify(data, null, ' ')}`);
|
||||||
|
readStdin();
|
||||||
|
})
|
||||||
|
.catch((error) =>
|
||||||
|
{
|
||||||
|
stdinError(`peer.dump() failed: ${error}`);
|
||||||
|
readStdin();
|
||||||
|
});
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'td':
|
||||||
|
case 'transportdump':
|
||||||
|
{
|
||||||
|
if (!global.TRANSPORT)
|
||||||
|
{
|
||||||
|
readStdin();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
global.TRANSPORT.dump()
|
||||||
|
.then((data) =>
|
||||||
|
{
|
||||||
|
stdinLog(`transport.dump() succeeded:\n${JSON.stringify(data, null, ' ')}`);
|
||||||
|
readStdin();
|
||||||
|
})
|
||||||
|
.catch((error) =>
|
||||||
|
{
|
||||||
|
stdinError(`transport.dump() failed: ${error}`);
|
||||||
|
readStdin();
|
||||||
|
});
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'prd':
|
||||||
|
case 'producerdump':
|
||||||
|
{
|
||||||
|
if (!global.PRODUCER)
|
||||||
|
{
|
||||||
|
readStdin();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
global.PRODUCER.dump()
|
||||||
|
.then((data) =>
|
||||||
|
{
|
||||||
|
stdinLog(`producer.dump() succeeded:\n${JSON.stringify(data, null, ' ')}`);
|
||||||
|
readStdin();
|
||||||
|
})
|
||||||
|
.catch((error) =>
|
||||||
|
{
|
||||||
|
stdinError(`producer.dump() failed: ${error}`);
|
||||||
|
readStdin();
|
||||||
|
});
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'cd':
|
||||||
|
case 'consumerdump':
|
||||||
|
{
|
||||||
|
if (!global.CONSUMER)
|
||||||
|
{
|
||||||
|
readStdin();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
global.CONSUMER.dump()
|
||||||
|
.then((data) =>
|
||||||
|
{
|
||||||
|
stdinLog(`consumer.dump() succeeded:\n${JSON.stringify(data, null, ' ')}`);
|
||||||
|
readStdin();
|
||||||
|
})
|
||||||
|
.catch((error) =>
|
||||||
|
{
|
||||||
|
stdinError(`consumer.dump() failed: ${error}`);
|
||||||
|
readStdin();
|
||||||
|
});
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 't':
|
||||||
|
case 'terminal':
|
||||||
|
{
|
||||||
|
openTerminal();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
stdinError(`unknown command: ${answer}`);
|
||||||
|
stdinLog('press \'h\' or \'help\' to get the list of available commands');
|
||||||
|
|
||||||
|
readStdin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function openTerminal()
|
||||||
|
{
|
||||||
|
stdinLog('[opening REPL Terminal...]');
|
||||||
|
|
||||||
|
closeCommandConsole();
|
||||||
|
closeTerminal();
|
||||||
|
|
||||||
|
terminal = repl.start(
|
||||||
|
{
|
||||||
|
prompt : 'terminal> ',
|
||||||
|
useColors : true,
|
||||||
|
useGlobal : true,
|
||||||
|
ignoreUndefined : false
|
||||||
|
});
|
||||||
|
|
||||||
|
terminal.on('exit', () => openCommandConsole());
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeCommandConsole()
|
||||||
|
{
|
||||||
|
if (cmd)
|
||||||
|
{
|
||||||
|
cmd.close();
|
||||||
|
cmd = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeTerminal()
|
||||||
|
{
|
||||||
|
if (terminal)
|
||||||
|
{
|
||||||
|
terminal.removeAllListeners('exit');
|
||||||
|
terminal.close();
|
||||||
|
terminal = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function stdinLog(msg)
|
||||||
|
{
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(colors.green(msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
function stdinError(msg)
|
||||||
|
{
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error(colors.red.bold('ERROR: ') + colors.red(msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = mediaServer;
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -7,10 +7,12 @@
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"base-64": "^0.1.0",
|
||||||
"colors": "^1.1.2",
|
"colors": "^1.1.2",
|
||||||
"debug": "^3.1.0",
|
"debug": "^3.1.0",
|
||||||
"express": "^4.16.2",
|
"express": "^4.16.3",
|
||||||
"mediasoup": "^2.1.0",
|
"mediasoup": "^2.1.0",
|
||||||
|
"passport-dataporten": "^1.3.0",
|
||||||
"protoo-server": "^2.0.7"
|
"protoo-server": "^2.0.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
||||||
196
server/router.js
196
server/router.js
|
|
@ -1,196 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const EventEmitter = require( 'events' );
|
|
||||||
const eventEmitter = new EventEmitter();
|
|
||||||
const path = require('path');
|
|
||||||
const url = require('url');
|
|
||||||
const httpHelpers = require('./http-helpers');
|
|
||||||
const fs = require('fs');
|
|
||||||
const config = require('./config');
|
|
||||||
const utils = require('./util');
|
|
||||||
const querystring = require('querystring');
|
|
||||||
const https = require('https')
|
|
||||||
const Logger = require('./lib/Logger');
|
|
||||||
|
|
||||||
const logger = new Logger();
|
|
||||||
|
|
||||||
let authRequests = {}; // ongoing auth requests :
|
|
||||||
/*
|
|
||||||
{
|
|
||||||
state:
|
|
||||||
{
|
|
||||||
peerName:'peerName'
|
|
||||||
code:'oauth2 code',
|
|
||||||
roomId: 'romid',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
const actions = {
|
|
||||||
'GET': function(req, res) {
|
|
||||||
var parsedUrl = url.parse(req.url,true);
|
|
||||||
if ( parsedUrl.pathname === '/auth-callback' )
|
|
||||||
{
|
|
||||||
if ( typeof(authRequests[parsedUrl.query.state]) != 'undefined' )
|
|
||||||
{
|
|
||||||
console.log('got authorization code for access token: ',parsedUrl.query,authRequests[parsedUrl.query.state]);
|
|
||||||
const auth = "Basic " + new Buffer(config.oauth2.client_id + ":" + config.oauth2.client_secret).toString("base64");
|
|
||||||
const postUrl = url.parse(config.oauth2.token_endpoint);
|
|
||||||
let postData = querystring.stringify({
|
|
||||||
"grant_type":"authorization_code",
|
|
||||||
"code":parsedUrl.query.code,
|
|
||||||
"redirect_uri":config.oauth2.redirect_uri
|
|
||||||
});
|
|
||||||
|
|
||||||
let request = https.request( {
|
|
||||||
host : postUrl.hostname,
|
|
||||||
path : postUrl.pathname,
|
|
||||||
port : postUrl.port,
|
|
||||||
method : 'POST',
|
|
||||||
headers :
|
|
||||||
{
|
|
||||||
'Content-Type' : 'application/x-www-form-urlencoded',
|
|
||||||
'Authorization' : auth,
|
|
||||||
'Content-Length': Buffer.byteLength(postData)
|
|
||||||
}
|
|
||||||
}, function(res)
|
|
||||||
{
|
|
||||||
res.setEncoding("utf8");
|
|
||||||
let body = "";
|
|
||||||
res.on("data", data => {
|
|
||||||
body += data;
|
|
||||||
});
|
|
||||||
res.on("end", () => {
|
|
||||||
if ( res.statusCode == 200 )
|
|
||||||
{
|
|
||||||
console.log('We\'ve got an access token!', body);
|
|
||||||
body = JSON.parse(body);
|
|
||||||
authRequests[parsedUrl.query.state].access_token =
|
|
||||||
body.access_token;
|
|
||||||
const auth = "Bearer " + body.access_token;
|
|
||||||
const getUrl = url.parse(config.oauth2.userinfo_endpoint);
|
|
||||||
let request = https.request( {
|
|
||||||
host : getUrl.hostname,
|
|
||||||
path : getUrl.pathname,
|
|
||||||
port : getUrl.port,
|
|
||||||
method : 'GET',
|
|
||||||
headers :
|
|
||||||
{
|
|
||||||
'Authorization' : auth,
|
|
||||||
}
|
|
||||||
}, function(res)
|
|
||||||
{
|
|
||||||
res.setEncoding("utf8");
|
|
||||||
let body = '';
|
|
||||||
res.on("data", data => {
|
|
||||||
body += data;
|
|
||||||
});
|
|
||||||
res.on("end", () => {
|
|
||||||
// we don't need this any longer:
|
|
||||||
delete authRequests[parsedUrl.query.state].access_token;
|
|
||||||
|
|
||||||
body = JSON.parse(body);
|
|
||||||
console.log(body);
|
|
||||||
if ( res.statusCode == 200 )
|
|
||||||
{
|
|
||||||
authRequests[parsedUrl.query.state].verified = true;
|
|
||||||
if ( typeof(body.sub) != 'undefined')
|
|
||||||
{
|
|
||||||
authRequests[parsedUrl.query.state].sub = body.sub;
|
|
||||||
}
|
|
||||||
if ( typeof(body.name) != 'undefined')
|
|
||||||
{
|
|
||||||
authRequests[parsedUrl.query.state].name = body.name;
|
|
||||||
}
|
|
||||||
if ( typeof(body.picture) != 'undefined')
|
|
||||||
{
|
|
||||||
authRequests[parsedUrl.query.state].picture = body.picture;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
{
|
|
||||||
authRequests[parsedUrl.query.state].verified = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
eventEmitter.emit('auth',
|
|
||||||
authRequests[parsedUrl.query.state]);
|
|
||||||
|
|
||||||
delete authRequests[parsedUrl.query.state];
|
|
||||||
});
|
|
||||||
});
|
|
||||||
request.write(' ');
|
|
||||||
request.end;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
console.log('access_token denied',body);
|
|
||||||
authRequests[parsedUrl.query.state].verified = false;
|
|
||||||
delete authRequests[parsedUrl.query.state].access_token;
|
|
||||||
eventEmitter.emit('auth',
|
|
||||||
authRequests[parsedUrl.query.state]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
request.write(postData);
|
|
||||||
request.end;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
logger.warn('Got authorization_code for unseen state:', parsedUrl)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (parsedUrl.pathname === '/login') {
|
|
||||||
const state = utils.random(10);
|
|
||||||
httpHelpers.redirector(res, config.oauth2.authorization_endpoint
|
|
||||||
+ '?client_id=' + config.oauth2.client_id
|
|
||||||
+ '&redirect_uri=' + config.oauth2.redirect_uri
|
|
||||||
+ '&state=' + state
|
|
||||||
+ '&scopes=' + config.oauth2.scopes.request.join('+')
|
|
||||||
+ '&response_type=' + config.oauth2.response_type);
|
|
||||||
authRequests[state] =
|
|
||||||
{
|
|
||||||
'roomId' : parsedUrl.query.roomId,
|
|
||||||
'peerName' : parsedUrl.query.peerName
|
|
||||||
};
|
|
||||||
console.log('Started authorization process: ', parsedUrl.query);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
console.log('requested url:', parsedUrl.pathname);
|
|
||||||
var resolvedBase = path.resolve('./public');
|
|
||||||
var safeSuffix = path.normalize(req.url).replace(/^(\.\.[\/\\])+/, '');
|
|
||||||
var fileLoc = path.join(resolvedBase, safeSuffix);
|
|
||||||
var headers = {};
|
|
||||||
|
|
||||||
var stream = fs.createReadStream(fileLoc);
|
|
||||||
|
|
||||||
// Handle non-existent file -> delivering index.html
|
|
||||||
stream.on('error', function(error) {
|
|
||||||
stream = fs.createReadStream(path.resolve('./public/index.html'));
|
|
||||||
res.statusCode = 200;
|
|
||||||
stream.pipe(res);
|
|
||||||
});
|
|
||||||
|
|
||||||
// File exists, stream it to user
|
|
||||||
if (parsedUrl.pathname.indexOf('svg') === parsedUrl.pathname.length -3) {headers = {'Content-Type': 'image/svg+xml'}};
|
|
||||||
res.writeHead(200, headers);
|
|
||||||
stream.pipe(res);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
'POST': function(req, res) {
|
|
||||||
httpHelpers.prepareResponse(req, function(data) {
|
|
||||||
// Do something with the data that was just collected by the helper
|
|
||||||
// e.g., validate and save to db
|
|
||||||
// either redirect or respond
|
|
||||||
// should be based on result of the operation performed in response to the POST request intent
|
|
||||||
// e.g., if user wants to save, and save fails, throw error
|
|
||||||
httpHelpers.redirector(res, /* redirect path , optional status code - defaults to 302 */);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = eventEmitter;
|
|
||||||
|
|
||||||
module.exports.handleRequest = function(req, res) {
|
|
||||||
var action = actions[req.method];
|
|
||||||
action ? action(req, res) : httpHelpers.send404(res);
|
|
||||||
};
|
|
||||||
414
server/server.js
414
server/server.js
|
|
@ -5,6 +5,16 @@
|
||||||
process.title = 'multiparty-meeting-server';
|
process.title = 'multiparty-meeting-server';
|
||||||
|
|
||||||
const config = require('./config');
|
const config = require('./config');
|
||||||
|
const fs = require('fs');
|
||||||
|
const https = require('https');
|
||||||
|
const express = require('express');
|
||||||
|
const url = require('url');
|
||||||
|
const protooServer = require('protoo-server');
|
||||||
|
const Logger = require('./lib/Logger');
|
||||||
|
const Room = require('./lib/Room');
|
||||||
|
const Dataporten = require('passport-dataporten');
|
||||||
|
const utils = require('./util');
|
||||||
|
const base64 = require('base-64');
|
||||||
|
|
||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
console.log('- process.env.DEBUG:', process.env.DEBUG);
|
console.log('- process.env.DEBUG:', process.env.DEBUG);
|
||||||
|
|
@ -12,100 +22,83 @@ console.log('- config.mediasoup.logLevel:', config.mediasoup.logLevel);
|
||||||
console.log('- config.mediasoup.logTags:', config.mediasoup.logTags);
|
console.log('- config.mediasoup.logTags:', config.mediasoup.logTags);
|
||||||
/* eslint-enable no-console */
|
/* eslint-enable no-console */
|
||||||
|
|
||||||
const fs = require('fs');
|
// Start the mediasoup server.
|
||||||
const https = require('https');
|
const mediaServer = require('./mediasoup');
|
||||||
const router = require('./router');
|
|
||||||
const url = require('url');
|
|
||||||
const path = require('path');
|
|
||||||
const protooServer = require('protoo-server');
|
|
||||||
const mediasoup = require('mediasoup');
|
|
||||||
const readline = require('readline');
|
|
||||||
const colors = require('colors/safe');
|
|
||||||
const repl = require('repl');
|
|
||||||
const Logger = require('./lib/Logger');
|
|
||||||
const Room = require('./lib/Room');
|
|
||||||
const homer = require('./lib/homer');
|
|
||||||
|
|
||||||
const logger = new Logger();
|
const logger = new Logger();
|
||||||
|
|
||||||
// Map of Room instances indexed by roomId.
|
// Map of Room instances indexed by roomId.
|
||||||
const rooms = new Map();
|
const rooms = new Map();
|
||||||
|
|
||||||
// mediasoup server.
|
// TLS server configuration.
|
||||||
const mediaServer = mediasoup.Server(
|
|
||||||
{
|
|
||||||
numWorkers : 1,
|
|
||||||
logLevel : config.mediasoup.logLevel,
|
|
||||||
logTags : config.mediasoup.logTags,
|
|
||||||
rtcIPv4 : config.mediasoup.rtcIPv4,
|
|
||||||
rtcIPv6 : config.mediasoup.rtcIPv6,
|
|
||||||
rtcAnnouncedIPv4 : config.mediasoup.rtcAnnouncedIPv4,
|
|
||||||
rtcAnnouncedIPv6 : config.mediasoup.rtcAnnouncedIPv6,
|
|
||||||
rtcMinPort : config.mediasoup.rtcMinPort,
|
|
||||||
rtcMaxPort : config.mediasoup.rtcMaxPort
|
|
||||||
});
|
|
||||||
|
|
||||||
// Do Homer stuff.
|
|
||||||
if (process.env.MEDIASOUP_HOMER_OUTPUT)
|
|
||||||
homer(mediaServer);
|
|
||||||
|
|
||||||
global.SERVER = mediaServer;
|
|
||||||
|
|
||||||
mediaServer.on('newroom', (room) =>
|
|
||||||
{
|
|
||||||
global.ROOM = room;
|
|
||||||
|
|
||||||
room.on('newpeer', (peer) =>
|
|
||||||
{
|
|
||||||
global.PEER = peer;
|
|
||||||
|
|
||||||
if (peer.consumers.length > 0)
|
|
||||||
global.CONSUMER = peer.consumers[peer.consumers.length - 1];
|
|
||||||
|
|
||||||
peer.on('newtransport', (transport) =>
|
|
||||||
{
|
|
||||||
global.TRANSPORT = transport;
|
|
||||||
});
|
|
||||||
|
|
||||||
peer.on('newproducer', (producer) =>
|
|
||||||
{
|
|
||||||
global.PRODUCER = producer;
|
|
||||||
});
|
|
||||||
|
|
||||||
peer.on('newconsumer', (consumer) =>
|
|
||||||
{
|
|
||||||
global.CONSUMER = consumer;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// HTTPS server
|
|
||||||
const tls =
|
const tls =
|
||||||
{
|
{
|
||||||
cert : fs.readFileSync(config.tls.cert),
|
cert : fs.readFileSync(config.tls.cert),
|
||||||
key : fs.readFileSync(config.tls.key)
|
key : fs.readFileSync(config.tls.key)
|
||||||
};
|
};
|
||||||
|
|
||||||
const httpsServer = https.createServer(tls, router.handleRequest);
|
const app = express();
|
||||||
httpsServer.listen(config.listeningPort, '0.0.0.0', () =>
|
|
||||||
|
const dataporten = new Dataporten.Setup(config.oauth2);
|
||||||
|
|
||||||
|
app.use(dataporten.passport.initialize());
|
||||||
|
app.use(dataporten.passport.session());
|
||||||
|
|
||||||
|
app.get('/login', (req, res, next) =>
|
||||||
{
|
{
|
||||||
logger.info('Server running, port: ',config.listeningPort);
|
dataporten.passport.authenticate('dataporten', {
|
||||||
|
state : base64.encode(JSON.stringify({
|
||||||
|
roomId : req.query.roomId,
|
||||||
|
peerName : req.query.peerName,
|
||||||
|
code : utils.random(10)
|
||||||
|
}))
|
||||||
|
|
||||||
|
})(req, res, next);
|
||||||
});
|
});
|
||||||
|
|
||||||
router.on('auth',function(event){
|
dataporten.setupLogout(app, '/logout');
|
||||||
console.log('router: Got an event: ',event)
|
|
||||||
if ( rooms.has(event.roomId) )
|
|
||||||
{
|
|
||||||
const room = rooms.get(event.roomId)._protooRoom;
|
|
||||||
if ( room.hasPeer(event.peerName) )
|
|
||||||
{
|
|
||||||
const peer = room.getPeer(event.peerName);
|
|
||||||
peer.send('auth', event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Protoo WebSocket server listens to same webserver so everythink is available
|
app.get(
|
||||||
|
'/auth-callback',
|
||||||
|
|
||||||
|
dataporten.passport.authenticate('dataporten', { failureRedirect: '/login' }),
|
||||||
|
|
||||||
|
(req, res) =>
|
||||||
|
{
|
||||||
|
const state = JSON.parse(base64.decode(req.query.state));
|
||||||
|
|
||||||
|
if (rooms.has(state.roomId))
|
||||||
|
{
|
||||||
|
const room = rooms.get(state.roomId)._protooRoom;
|
||||||
|
|
||||||
|
if (room.hasPeer(state.peerName))
|
||||||
|
{
|
||||||
|
const peer = room.getPeer(state.peerName);
|
||||||
|
|
||||||
|
peer.send('auth', {
|
||||||
|
name : req.user.data.displayName,
|
||||||
|
picture : req.user.data.photos[0]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res.send('');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Serve all files in the public folder as static files.
|
||||||
|
app.use(express.static('public'));
|
||||||
|
|
||||||
|
app.use((req, res) => res.sendFile(`${__dirname}/public/index.html`));
|
||||||
|
|
||||||
|
const httpsServer = https.createServer(tls, app);
|
||||||
|
|
||||||
|
httpsServer.listen(config.listeningPort, '0.0.0.0', () =>
|
||||||
|
{
|
||||||
|
logger.info('Server running on port: ', config.listeningPort);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Protoo WebSocket server listens to same webserver so everything is available
|
||||||
// via same port
|
// via same port
|
||||||
const webSocketServer = new protooServer.WebSocketServer(httpsServer,
|
const webSocketServer = new protooServer.WebSocketServer(httpsServer,
|
||||||
{
|
{
|
||||||
|
|
@ -179,268 +172,3 @@ webSocketServer.on('connectionrequest', (info, accept, reject) =>
|
||||||
|
|
||||||
room.handleConnection(peerName, transport);
|
room.handleConnection(peerName, transport);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Listen for keyboard input.
|
|
||||||
|
|
||||||
let cmd;
|
|
||||||
let terminal;
|
|
||||||
|
|
||||||
openCommandConsole();
|
|
||||||
|
|
||||||
function openCommandConsole()
|
|
||||||
{
|
|
||||||
stdinLog('[opening Readline Command Console...]');
|
|
||||||
|
|
||||||
closeCommandConsole();
|
|
||||||
closeTerminal();
|
|
||||||
|
|
||||||
cmd = readline.createInterface(
|
|
||||||
{
|
|
||||||
input : process.stdin,
|
|
||||||
output : process.stdout
|
|
||||||
});
|
|
||||||
|
|
||||||
cmd.on('SIGINT', () =>
|
|
||||||
{
|
|
||||||
process.exit();
|
|
||||||
});
|
|
||||||
|
|
||||||
readStdin();
|
|
||||||
|
|
||||||
function readStdin()
|
|
||||||
{
|
|
||||||
cmd.question('cmd> ', (answer) =>
|
|
||||||
{
|
|
||||||
switch (answer)
|
|
||||||
{
|
|
||||||
case '':
|
|
||||||
{
|
|
||||||
readStdin();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'h':
|
|
||||||
case 'help':
|
|
||||||
{
|
|
||||||
stdinLog('');
|
|
||||||
stdinLog('available commands:');
|
|
||||||
stdinLog('- h, help : show this message');
|
|
||||||
stdinLog('- sd, serverdump : execute server.dump()');
|
|
||||||
stdinLog('- rd, roomdump : execute room.dump() for the latest created mediasoup Room');
|
|
||||||
stdinLog('- pd, peerdump : execute peer.dump() for the latest created mediasoup Peer');
|
|
||||||
stdinLog('- td, transportdump : execute transport.dump() for the latest created mediasoup Transport');
|
|
||||||
stdinLog('- prd, producerdump : execute producer.dump() for the latest created mediasoup Producer');
|
|
||||||
stdinLog('- cd, consumerdump : execute consumer.dump() for the latest created mediasoup Consumer');
|
|
||||||
stdinLog('- t, terminal : open REPL Terminal');
|
|
||||||
stdinLog('');
|
|
||||||
readStdin();
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'sd':
|
|
||||||
case 'serverdump':
|
|
||||||
{
|
|
||||||
mediaServer.dump()
|
|
||||||
.then((data) =>
|
|
||||||
{
|
|
||||||
stdinLog(`server.dump() succeeded:\n${JSON.stringify(data, null, ' ')}`);
|
|
||||||
readStdin();
|
|
||||||
})
|
|
||||||
.catch((error) =>
|
|
||||||
{
|
|
||||||
stdinError(`mediaServer.dump() failed: ${error}`);
|
|
||||||
readStdin();
|
|
||||||
});
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'rd':
|
|
||||||
case 'roomdump':
|
|
||||||
{
|
|
||||||
if (!global.ROOM)
|
|
||||||
{
|
|
||||||
readStdin();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
global.ROOM.dump()
|
|
||||||
.then((data) =>
|
|
||||||
{
|
|
||||||
stdinLog(`room.dump() succeeded:\n${JSON.stringify(data, null, ' ')}`);
|
|
||||||
readStdin();
|
|
||||||
})
|
|
||||||
.catch((error) =>
|
|
||||||
{
|
|
||||||
stdinError(`room.dump() failed: ${error}`);
|
|
||||||
readStdin();
|
|
||||||
});
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'pd':
|
|
||||||
case 'peerdump':
|
|
||||||
{
|
|
||||||
if (!global.PEER)
|
|
||||||
{
|
|
||||||
readStdin();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
global.PEER.dump()
|
|
||||||
.then((data) =>
|
|
||||||
{
|
|
||||||
stdinLog(`peer.dump() succeeded:\n${JSON.stringify(data, null, ' ')}`);
|
|
||||||
readStdin();
|
|
||||||
})
|
|
||||||
.catch((error) =>
|
|
||||||
{
|
|
||||||
stdinError(`peer.dump() failed: ${error}`);
|
|
||||||
readStdin();
|
|
||||||
});
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'td':
|
|
||||||
case 'transportdump':
|
|
||||||
{
|
|
||||||
if (!global.TRANSPORT)
|
|
||||||
{
|
|
||||||
readStdin();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
global.TRANSPORT.dump()
|
|
||||||
.then((data) =>
|
|
||||||
{
|
|
||||||
stdinLog(`transport.dump() succeeded:\n${JSON.stringify(data, null, ' ')}`);
|
|
||||||
readStdin();
|
|
||||||
})
|
|
||||||
.catch((error) =>
|
|
||||||
{
|
|
||||||
stdinError(`transport.dump() failed: ${error}`);
|
|
||||||
readStdin();
|
|
||||||
});
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'prd':
|
|
||||||
case 'producerdump':
|
|
||||||
{
|
|
||||||
if (!global.PRODUCER)
|
|
||||||
{
|
|
||||||
readStdin();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
global.PRODUCER.dump()
|
|
||||||
.then((data) =>
|
|
||||||
{
|
|
||||||
stdinLog(`producer.dump() succeeded:\n${JSON.stringify(data, null, ' ')}`);
|
|
||||||
readStdin();
|
|
||||||
})
|
|
||||||
.catch((error) =>
|
|
||||||
{
|
|
||||||
stdinError(`producer.dump() failed: ${error}`);
|
|
||||||
readStdin();
|
|
||||||
});
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'cd':
|
|
||||||
case 'consumerdump':
|
|
||||||
{
|
|
||||||
if (!global.CONSUMER)
|
|
||||||
{
|
|
||||||
readStdin();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
global.CONSUMER.dump()
|
|
||||||
.then((data) =>
|
|
||||||
{
|
|
||||||
stdinLog(`consumer.dump() succeeded:\n${JSON.stringify(data, null, ' ')}`);
|
|
||||||
readStdin();
|
|
||||||
})
|
|
||||||
.catch((error) =>
|
|
||||||
{
|
|
||||||
stdinError(`consumer.dump() failed: ${error}`);
|
|
||||||
readStdin();
|
|
||||||
});
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 't':
|
|
||||||
case 'terminal':
|
|
||||||
{
|
|
||||||
openTerminal();
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
stdinError(`unknown command: ${answer}`);
|
|
||||||
stdinLog('press \'h\' or \'help\' to get the list of available commands');
|
|
||||||
|
|
||||||
readStdin();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function openTerminal()
|
|
||||||
{
|
|
||||||
stdinLog('[opening REPL Terminal...]');
|
|
||||||
|
|
||||||
closeCommandConsole();
|
|
||||||
closeTerminal();
|
|
||||||
|
|
||||||
terminal = repl.start(
|
|
||||||
{
|
|
||||||
prompt : 'terminal> ',
|
|
||||||
useColors : true,
|
|
||||||
useGlobal : true,
|
|
||||||
ignoreUndefined : false
|
|
||||||
});
|
|
||||||
|
|
||||||
terminal.on('exit', () => openCommandConsole());
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeCommandConsole()
|
|
||||||
{
|
|
||||||
if (cmd)
|
|
||||||
{
|
|
||||||
cmd.close();
|
|
||||||
cmd = undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeTerminal()
|
|
||||||
{
|
|
||||||
if (terminal)
|
|
||||||
{
|
|
||||||
terminal.removeAllListeners('exit');
|
|
||||||
terminal.close();
|
|
||||||
terminal = undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function stdinLog(msg)
|
|
||||||
{
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log(colors.green(msg));
|
|
||||||
}
|
|
||||||
|
|
||||||
function stdinError(msg)
|
|
||||||
{
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.error(colors.red.bold('ERROR: ') + colors.red(msg));
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue