Middle of refactor
This commit is contained in:
parent
b50eb79463
commit
80c8be2f56
@ -1,7 +1,9 @@
|
|||||||
{
|
{
|
||||||
|
"parser": "babel-eslint",
|
||||||
"extends": ["standard", "standard-react"],
|
"extends": ["standard", "standard-react"],
|
||||||
"rules": {
|
"rules": {
|
||||||
"max-len": [2, 80, 4]
|
"max-len": [2, 80, 4],
|
||||||
|
"jsx-quotes": ["error", "prefer-double"]
|
||||||
},
|
},
|
||||||
"globals": {
|
"globals": {
|
||||||
"expect": true,
|
"expect": true,
|
||||||
|
|||||||
12
package.json
12
package.json
@ -11,14 +11,21 @@
|
|||||||
"lint": "eslint ./index.js ./src/js"
|
"lint": "eslint ./index.js ./src/js"
|
||||||
},
|
},
|
||||||
"babel": {
|
"babel": {
|
||||||
"presets": ["es2016", "react", "transform-object-rest-spread"]
|
"presets": [
|
||||||
|
"es2016",
|
||||||
|
"react",
|
||||||
|
"transform-object-rest-spread",
|
||||||
|
"transform-class-properties"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bluebird": "^3.3.4",
|
"bluebird": "^3.3.4",
|
||||||
|
"classnames": "^2.2.5",
|
||||||
"config": "^1.26.1",
|
"config": "^1.26.1",
|
||||||
"express": "^4.13.3",
|
"express": "^4.13.3",
|
||||||
|
"prop-types": "^15.5.10",
|
||||||
"pug": "^2.0.0-rc.2",
|
"pug": "^2.0.0-rc.2",
|
||||||
"react": "^15.5.4",
|
"react": "^15.5.4",
|
||||||
"react-addons-transition-group": "^15.5.2",
|
"react-addons-transition-group": "^15.5.2",
|
||||||
@ -26,6 +33,7 @@
|
|||||||
"react-redux": "^5.0.5",
|
"react-redux": "^5.0.5",
|
||||||
"redux": "^3.6.0",
|
"redux": "^3.6.0",
|
||||||
"redux-thunk": "^2.2.0",
|
"redux-thunk": "^2.2.0",
|
||||||
|
"seamless-immutable": "^7.1.2",
|
||||||
"simple-peer": "^8.1.0",
|
"simple-peer": "^8.1.0",
|
||||||
"socket.io": "1.6.0",
|
"socket.io": "1.6.0",
|
||||||
"socket.io-client": "1.6.0",
|
"socket.io-client": "1.6.0",
|
||||||
@ -33,7 +41,9 @@
|
|||||||
"uuid": "^2.0.1"
|
"uuid": "^2.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"babel-eslint": "^7.2.3",
|
||||||
"babel-jest": "^20.0.3",
|
"babel-jest": "^20.0.3",
|
||||||
|
"babel-plugin-transform-class-properties": "^6.24.1",
|
||||||
"babel-plugin-transform-object-rest-spread": "^6.23.0",
|
"babel-plugin-transform-object-rest-spread": "^6.23.0",
|
||||||
"babel-preset-es2016": "^6.24.1",
|
"babel-preset-es2016": "^6.24.1",
|
||||||
"babel-preset-react": "^6.24.1",
|
"babel-preset-react": "^6.24.1",
|
||||||
|
|||||||
@ -1,66 +0,0 @@
|
|||||||
jest.unmock('../notify.js')
|
|
||||||
|
|
||||||
const dispatcher = require('../../dispatcher/dispatcher.js')
|
|
||||||
const notify = require('../notify.js')
|
|
||||||
|
|
||||||
describe('notify', () => {
|
|
||||||
beforeEach(() => dispatcher.dispatch.mockClear())
|
|
||||||
|
|
||||||
describe('info', () => {
|
|
||||||
it('should dispatch info notification', () => {
|
|
||||||
notify.info('test: {0} {1}', 'arg1', 'arg2')
|
|
||||||
|
|
||||||
expect(dispatcher.dispatch.mock.calls).toEqual([[{
|
|
||||||
type: 'notify',
|
|
||||||
notification: {
|
|
||||||
message: 'test: arg1 arg2',
|
|
||||||
type: 'info'
|
|
||||||
}
|
|
||||||
}]])
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('warn', () => {
|
|
||||||
it('should dispatch warning notification', () => {
|
|
||||||
notify.warn('test: {0} {1}', 'arg1', 'arg2')
|
|
||||||
|
|
||||||
expect(dispatcher.dispatch.mock.calls).toEqual([[{
|
|
||||||
type: 'notify',
|
|
||||||
notification: {
|
|
||||||
message: 'test: arg1 arg2',
|
|
||||||
type: 'warning'
|
|
||||||
}
|
|
||||||
}]])
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('error', () => {
|
|
||||||
it('should dispatch error notification', () => {
|
|
||||||
notify.error('test: {0} {1}', 'arg1', 'arg2')
|
|
||||||
|
|
||||||
expect(dispatcher.dispatch.mock.calls).toEqual([[{
|
|
||||||
type: 'notify',
|
|
||||||
notification: {
|
|
||||||
message: 'test: arg1 arg2',
|
|
||||||
type: 'error'
|
|
||||||
}
|
|
||||||
}]])
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('alert', () => {
|
|
||||||
it('should dispatch an alert', () => {
|
|
||||||
notify.alert('alert!', true)
|
|
||||||
|
|
||||||
expect(dispatcher.dispatch.mock.calls).toEqual([[{
|
|
||||||
type: 'alert',
|
|
||||||
alert: {
|
|
||||||
action: 'Dismiss',
|
|
||||||
dismissable: true,
|
|
||||||
message: 'alert!',
|
|
||||||
type: 'warning'
|
|
||||||
}
|
|
||||||
}]])
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@ -1,42 +0,0 @@
|
|||||||
const dispatcher = require('../dispatcher/dispatcher.js')
|
|
||||||
|
|
||||||
function format (string, args) {
|
|
||||||
string = args
|
|
||||||
.reduce((string, arg, i) => string.replace('{' + i + '}', arg), string)
|
|
||||||
return string
|
|
||||||
}
|
|
||||||
|
|
||||||
function _notify (type, args) {
|
|
||||||
let string = args[0] || ''
|
|
||||||
let message = format(string, Array.prototype.slice.call(args, 1))
|
|
||||||
dispatcher.dispatch({
|
|
||||||
type: 'notify',
|
|
||||||
notification: { type, message }
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function info () {
|
|
||||||
_notify('info', arguments)
|
|
||||||
}
|
|
||||||
|
|
||||||
function warn () {
|
|
||||||
_notify('warning', arguments)
|
|
||||||
}
|
|
||||||
|
|
||||||
function error () {
|
|
||||||
_notify('error', arguments)
|
|
||||||
}
|
|
||||||
|
|
||||||
function alert (message, dismissable) {
|
|
||||||
dispatcher.dispatch({
|
|
||||||
type: 'alert',
|
|
||||||
alert: {
|
|
||||||
action: dismissable ? 'Dismiss' : '',
|
|
||||||
dismissable: !!dismissable,
|
|
||||||
message,
|
|
||||||
type: 'warning'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = { alert, info, warn, error }
|
|
||||||
49
src/client/actions/CallActions.js
Normal file
49
src/client/actions/CallActions.js
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import * as NotifyActions from './NotifyActions.js'
|
||||||
|
import * as constants from '../constants.js'
|
||||||
|
import Promise from 'bluebird'
|
||||||
|
import callId from '../callId.js'
|
||||||
|
import getUserMedia from './browser/getUserMedia.js'
|
||||||
|
import handshake from './peer/handshake.js'
|
||||||
|
import socket from './socket.js'
|
||||||
|
|
||||||
|
export const init = () => dispatch => {
|
||||||
|
return Promise.all([
|
||||||
|
connect()(dispatch),
|
||||||
|
getCameraStream()(dispatch)
|
||||||
|
])
|
||||||
|
.spread((socket, stream) => {
|
||||||
|
handshake.init({ socket, callId, stream })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const connect = () => dispatch => {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
socket.once('connect', () => {
|
||||||
|
dispatch(NotifyActions.warn('Connected to server socket'))
|
||||||
|
resolve(socket)
|
||||||
|
})
|
||||||
|
socket.on('disconnect', () => {
|
||||||
|
dispatch(NotifyActions.error('Server socket disconnected'))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getCameraStream = () => dispatch => {
|
||||||
|
return getUserMedia({ video: true, audio: true })
|
||||||
|
.then(stream => {
|
||||||
|
dispatch(addStream(stream))
|
||||||
|
return stream
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
dispatch(NotifyActions.alert('Could not get access to microphone & camera'))
|
||||||
|
return null
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const addStream = stream => ({
|
||||||
|
type: constants.STREAM_ADD,
|
||||||
|
payload: {
|
||||||
|
userId: '_me_',
|
||||||
|
stream
|
||||||
|
}
|
||||||
|
})
|
||||||
@ -7,34 +7,32 @@ function format (string, args) {
|
|||||||
function _notify (type, args) {
|
function _notify (type, args) {
|
||||||
let string = args[0] || ''
|
let string = args[0] || ''
|
||||||
let message = format(string, Array.prototype.slice.call(args, 1))
|
let message = format(string, Array.prototype.slice.call(args, 1))
|
||||||
dispatcher.dispatch({
|
return {
|
||||||
type: 'notify',
|
type: 'notify',
|
||||||
notification: { type, message }
|
payload: { type, message }
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function info () {
|
export function info () {
|
||||||
_notify('info', arguments)
|
return _notify('info', arguments)
|
||||||
}
|
}
|
||||||
|
|
||||||
function warn () {
|
export function warn () {
|
||||||
_notify('warning', arguments)
|
return _notify('warning', arguments)
|
||||||
}
|
}
|
||||||
|
|
||||||
function error () {
|
export function error () {
|
||||||
_notify('error', arguments)
|
return _notify('error', arguments)
|
||||||
}
|
}
|
||||||
|
|
||||||
function alert (message, dismissable) {
|
export function alert (message, dismissable) {
|
||||||
dispatcher.dispatch({
|
return {
|
||||||
type: 'alert',
|
type: 'alert',
|
||||||
alert: {
|
payload: {
|
||||||
action: dismissable ? 'Dismiss' : '',
|
action: dismissable ? 'Dismiss' : '',
|
||||||
dismissable: !!dismissable,
|
dismissable: !!dismissable,
|
||||||
message,
|
message,
|
||||||
type: 'warning'
|
type: 'warning'
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { alert, info, warn, error }
|
|
||||||
|
|||||||
@ -1,2 +0,0 @@
|
|||||||
'use strict'
|
|
||||||
module.exports = object => window.URL.createObjectURL(object)
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
'use strict'
|
|
||||||
module.exports = window.navigator
|
|
||||||
@ -1,53 +0,0 @@
|
|||||||
const Promise = require('bluebird')
|
|
||||||
const debug = require('debug')('peer-calls:call')
|
|
||||||
const dispatcher = require('./dispatcher/dispatcher.js')
|
|
||||||
const getUserMedia = require('./browser/getUserMedia.js')
|
|
||||||
const play = require('./browser/video.js').play
|
|
||||||
const notify = require('./action/notify.js')
|
|
||||||
const handshake = require('./peer/handshake.js')
|
|
||||||
const socket = require('./socket.js')
|
|
||||||
|
|
||||||
dispatcher.register(action => {
|
|
||||||
if (action.type === 'play') play()
|
|
||||||
})
|
|
||||||
|
|
||||||
function init () {
|
|
||||||
const callId = window.document.getElementById('callId').value
|
|
||||||
|
|
||||||
Promise.all([connect(), getCameraStream()])
|
|
||||||
.spread((_socket, stream) => {
|
|
||||||
debug('initializing peer connection')
|
|
||||||
handshake.init(_socket, callId, stream)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function connect () {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
socket.once('connect', () => {
|
|
||||||
notify.warn('Connected to server socket')
|
|
||||||
debug('socket connected')
|
|
||||||
resolve(socket)
|
|
||||||
})
|
|
||||||
socket.on('disconnect', () => {
|
|
||||||
notify.error('Server socket disconnected')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function getCameraStream () {
|
|
||||||
return getUserMedia({ video: true, audio: true })
|
|
||||||
.then(stream => {
|
|
||||||
debug('got our media stream:', stream)
|
|
||||||
dispatcher.dispatch({
|
|
||||||
type: 'add-stream',
|
|
||||||
userId: '_me_',
|
|
||||||
stream
|
|
||||||
})
|
|
||||||
return stream
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
notify.alert('Could not get access to microphone & camera')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = { init }
|
|
||||||
1
src/client/callId.js
Normal file
1
src/client/callId.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export default window.document.getElementById('callId').value
|
||||||
50
src/client/components/Alert.js
Normal file
50
src/client/components/Alert.js
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import classnames from 'classnames'
|
||||||
|
const React = require('react')
|
||||||
|
|
||||||
|
const AlertPropType = PropTypes.shape({
|
||||||
|
dismissable: PropTypes.bool,
|
||||||
|
action: PropTypes.string.isRequired,
|
||||||
|
message: PropTypes.string.isRequired
|
||||||
|
})
|
||||||
|
|
||||||
|
export class Alert extends React.PureComponent {
|
||||||
|
static propTypes = {
|
||||||
|
alert: AlertPropType,
|
||||||
|
dismiss: PropTypes.func.isRequired
|
||||||
|
}
|
||||||
|
dismiss = () => {
|
||||||
|
const { alert, dismiss } = this.props
|
||||||
|
dismiss(alert)
|
||||||
|
}
|
||||||
|
render () {
|
||||||
|
const { alert, dismiss } = this.props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classnames('alert', alert.type)}>
|
||||||
|
<span>{alert.message}</span>
|
||||||
|
{alert.dismissable && (
|
||||||
|
<button onClick={dismiss}>{alert.action}</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class Alerts extends React.PureComponent {
|
||||||
|
static propTypes = {
|
||||||
|
alerts: PropTypes.arrayOf(AlertPropType).isRequired,
|
||||||
|
dismiss: PropTypes.func.isRequired
|
||||||
|
}
|
||||||
|
render () {
|
||||||
|
const { alerts, dismiss } = this.props
|
||||||
|
return (
|
||||||
|
<div className="alerts">
|
||||||
|
{alerts.map((alert, i) => (
|
||||||
|
<Alert alert={alert} dismiss={dismiss} key={i} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
45
src/client/components/Input.js
Normal file
45
src/client/components/Input.js
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import notify from '../action/notify.js'
|
||||||
|
import peers from '../peer/peers.js'
|
||||||
|
|
||||||
|
export default class Input extends React.PureComponent {
|
||||||
|
constructor () {
|
||||||
|
super()
|
||||||
|
this.state = {
|
||||||
|
message: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
handleChange = e => {
|
||||||
|
this.setState({
|
||||||
|
message: e.target.value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
handleSubmit = e => {
|
||||||
|
e.preventDefault()
|
||||||
|
this.submit()
|
||||||
|
}
|
||||||
|
handleKeyPress = e => {
|
||||||
|
e.preventDefault()
|
||||||
|
e.key === 'Enter' && this.submit()
|
||||||
|
}
|
||||||
|
submit = () => {
|
||||||
|
const { message } = this.state
|
||||||
|
peers.message(message)
|
||||||
|
notify.info('You: ' + message)
|
||||||
|
this.setState({ message: '' })
|
||||||
|
}
|
||||||
|
render () {
|
||||||
|
const { message } = this.state
|
||||||
|
return (
|
||||||
|
<form className="input" onSubmit={this.handleSubmit}>
|
||||||
|
<input
|
||||||
|
onChange={this.handleChange}
|
||||||
|
onKeyPress={this.onKeyPress}
|
||||||
|
placeholder="Enter your message..."
|
||||||
|
type="text"
|
||||||
|
value={message}
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
39
src/client/components/Notifications.js
Normal file
39
src/client/components/Notifications.js
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import CSSTransitionGroup from 'react-transition-group'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import React from 'react'
|
||||||
|
import classnames from 'classnames'
|
||||||
|
|
||||||
|
export default class Notifications extends React.PureComponent {
|
||||||
|
static propTypes = {
|
||||||
|
notifications: PropTypes.arrayOf(PropTypes.shape({
|
||||||
|
id: PropTypes.string.isRequired,
|
||||||
|
type: PropTypes.string.isRequired,
|
||||||
|
message: PropTypes.string.isRequired
|
||||||
|
})),
|
||||||
|
max: PropTypes.number.isRequired
|
||||||
|
}
|
||||||
|
static defaultProps = {
|
||||||
|
max: 10
|
||||||
|
}
|
||||||
|
render () {
|
||||||
|
const { notifications, max } = this.props
|
||||||
|
return (
|
||||||
|
<div className="notifications">
|
||||||
|
<CSSTransitionGroup
|
||||||
|
transitionEnterTimeout={200}
|
||||||
|
transitionLeaveTimeout={100}
|
||||||
|
transitionName="fade"
|
||||||
|
>
|
||||||
|
{notifications.slice(max).map(notification => (
|
||||||
|
<div
|
||||||
|
className={classnames(notification.type, 'notification')}
|
||||||
|
key={notification.id}
|
||||||
|
>
|
||||||
|
{notification.message}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</CSSTransitionGroup>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,29 +0,0 @@
|
|||||||
const React = require('react')
|
|
||||||
const alertStore = require('../store/alertStore.js')
|
|
||||||
const dispatcher = require('../dispatcher/dispatcher.js')
|
|
||||||
|
|
||||||
function alert () {
|
|
||||||
let alert = alertStore.getAlert()
|
|
||||||
if (!alert) return <div className='alert hidden'><span> </span></div>
|
|
||||||
let button
|
|
||||||
|
|
||||||
function dismiss () {
|
|
||||||
dispatcher.dispatch({
|
|
||||||
type: 'alert-dismiss',
|
|
||||||
alert
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (alert.dismissable) {
|
|
||||||
button = <button onClick={dismiss}>{alert.action}</button>
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={alert.type + ' alert'}>
|
|
||||||
<span>{alert.message}</span>
|
|
||||||
{button}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = alert
|
|
||||||
@ -1,39 +0,0 @@
|
|||||||
const React = require('react')
|
|
||||||
const peers = require('../peer/peers.js')
|
|
||||||
const notify = require('../action/notify.js')
|
|
||||||
|
|
||||||
const Input = React.createClass({
|
|
||||||
getInitialState () {
|
|
||||||
return {
|
|
||||||
visible: false,
|
|
||||||
message: ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
handleChange (e) {
|
|
||||||
this.setState({
|
|
||||||
message: e.target.value
|
|
||||||
})
|
|
||||||
},
|
|
||||||
handleSubmit (e) {
|
|
||||||
e.preventDefault()
|
|
||||||
const { message } = this.state
|
|
||||||
peers.message(message)
|
|
||||||
notify.info('You: ' + message)
|
|
||||||
this.setState({ message: '' })
|
|
||||||
},
|
|
||||||
render () {
|
|
||||||
const { message } = this.state
|
|
||||||
return (
|
|
||||||
<form className='input' onSubmit={this.handleSubmit}>
|
|
||||||
<input
|
|
||||||
onChange={this.handleChange}
|
|
||||||
placeholder='Enter your message...'
|
|
||||||
type='text'
|
|
||||||
value={message}
|
|
||||||
/>
|
|
||||||
</form>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
module.exports = Input
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
const React = require('react')
|
|
||||||
const Transition = require('react-addons-css-transition-group')
|
|
||||||
const notificationsStore = require('../store/notificationsStore.js')
|
|
||||||
|
|
||||||
function notifications (props) {
|
|
||||||
let notifs = notificationsStore.getNotifications(props.max || 10)
|
|
||||||
|
|
||||||
let notificationElements = notifs.map(notif => {
|
|
||||||
return (
|
|
||||||
<div className={notif.type + ' notification'} key={notif._id}>
|
|
||||||
{notif.message}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='notifications'>
|
|
||||||
<Transition
|
|
||||||
transitionEnterTimeout={200}
|
|
||||||
transitionLeaveTimeout={100}
|
|
||||||
transitionName='fade'
|
|
||||||
>
|
|
||||||
{notificationElements}
|
|
||||||
</Transition>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = notifications
|
|
||||||
11
src/client/constants.js
Normal file
11
src/client/constants.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
export const ALERT = 'ALERT'
|
||||||
|
export const ALERT_DISMISS = 'ALERT_DISMISS'
|
||||||
|
export const ALERT_CLEAR = 'ALERT_CLEAR'
|
||||||
|
|
||||||
|
export const NOTIFY = 'NOTIFY'
|
||||||
|
export const NOTIFY_DISMISS = 'NOTIFY_DISMISS'
|
||||||
|
export const NOTIFY_CLEAR = 'NOTIFY_CLEAR'
|
||||||
|
|
||||||
|
export const STREAM_ADD = 'STREAM_ADD'
|
||||||
|
export const STREAM_ACTIVATE = 'STREAM_ACTIVATE'
|
||||||
|
export const STREAM_REMOVE = 'STREAM_REMOVE'
|
||||||
@ -1,5 +0,0 @@
|
|||||||
const Dispatcher = require('flux').Dispatcher
|
|
||||||
|
|
||||||
const dispatcher = new Dispatcher()
|
|
||||||
|
|
||||||
module.exports = dispatcher
|
|
||||||
@ -1,3 +1,3 @@
|
|||||||
module.exports = JSON.parse(
|
export default JSON.parse(
|
||||||
window.document.getElementById('iceServers').value
|
window.document.getElementById('iceServers').value
|
||||||
)
|
)
|
||||||
|
|||||||
17
src/client/reducers/alerts.js
Normal file
17
src/client/reducers/alerts.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import * as constants from '../constants.js'
|
||||||
|
import Immutable from 'seamless-immutable'
|
||||||
|
|
||||||
|
const defaultState = Immutable([])
|
||||||
|
|
||||||
|
export default function alert (state = defaultState, action) {
|
||||||
|
switch (action && action.type) {
|
||||||
|
case constants.ALERT:
|
||||||
|
return Immutable(state.asMutable().push(action.payload))
|
||||||
|
case constants.ALERT_DISMISS:
|
||||||
|
return state.filter(a => a !== action.payload)
|
||||||
|
case constants.ALERT_CLEAR:
|
||||||
|
return defaultState
|
||||||
|
default:
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/client/reducers/index.js
Normal file
9
src/client/reducers/index.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import alerts from './alerts.js'
|
||||||
|
import notifications from './notifications.js'
|
||||||
|
import streams from './streams.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
alerts,
|
||||||
|
notifications,
|
||||||
|
streams
|
||||||
|
}
|
||||||
25
src/client/reducers/notifications.js
Normal file
25
src/client/reducers/notifications.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import * as constants from '../constants.js'
|
||||||
|
import Immutable from 'seamless-immutable'
|
||||||
|
|
||||||
|
const defaultState = Immutable({
|
||||||
|
notifications: []
|
||||||
|
})
|
||||||
|
|
||||||
|
export default function notify (state = defaultState, action) {
|
||||||
|
switch (action && action.type) {
|
||||||
|
case constants.NOTIFY:
|
||||||
|
const notifications = state.notifications.asMutable()
|
||||||
|
notifications.push(action.payload)
|
||||||
|
return state.merge({
|
||||||
|
notifications
|
||||||
|
})
|
||||||
|
case constants.NOTIFY_DISMISS:
|
||||||
|
return state.merge({
|
||||||
|
notifications: state.notifications.filter(n => n !== action.payload)
|
||||||
|
})
|
||||||
|
case constants.NOTIFY_CLEAR:
|
||||||
|
return state.merge({ notifications: [] })
|
||||||
|
default:
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
}
|
||||||
36
src/client/reducers/stream.js
Normal file
36
src/client/reducers/stream.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import * as constants from '../constants.js'
|
||||||
|
import createObjectURL from '../browser/createObjectURL'
|
||||||
|
import Immutable from 'seamless-imutable'
|
||||||
|
|
||||||
|
const defaultState = Immutable({
|
||||||
|
active: null,
|
||||||
|
streams: {}
|
||||||
|
})
|
||||||
|
|
||||||
|
function addStream (state, action) {
|
||||||
|
const { userId, stream } = action.payload
|
||||||
|
const streams = state.streams.merge({
|
||||||
|
[userId]: {
|
||||||
|
userId,
|
||||||
|
stream,
|
||||||
|
url: createObjectURL(stream)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return { active: userId, streams }
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeStream (state, action) {
|
||||||
|
const streams = state.streams.without(action.payload.userId)
|
||||||
|
return state.merge({ streams })
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function stream (state = defaultState, action) {
|
||||||
|
switch (action && action.type) {
|
||||||
|
case constants.STREAM_ADD:
|
||||||
|
return addStream(state, action)
|
||||||
|
case constants.STREAM_REMOVE:
|
||||||
|
return removeStream(state, action)
|
||||||
|
default:
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,2 @@
|
|||||||
let SocketIOClient = require('socket.io-client')
|
import SocketIOClient from 'socket.io-client'
|
||||||
|
export default new SocketIOClient()
|
||||||
let socket = new SocketIOClient()
|
|
||||||
|
|
||||||
module.exports = socket
|
|
||||||
|
|||||||
8
src/client/store.js
Normal file
8
src/client/store.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { applyMiddleware, createStore } from 'redux'
|
||||||
|
import thunk from 'redux-thunk'
|
||||||
|
import reducer from './reducers'
|
||||||
|
|
||||||
|
export default createStore(
|
||||||
|
reducer,
|
||||||
|
applyMiddleware(thunk)
|
||||||
|
)
|
||||||
@ -1,30 +0,0 @@
|
|||||||
jest.unmock('../activeStore.js')
|
|
||||||
|
|
||||||
const dispatcher = require('../../dispatcher/dispatcher.js')
|
|
||||||
const activeStore = require('../activeStore.js')
|
|
||||||
|
|
||||||
describe('activeStore', () => {
|
|
||||||
let handleAction = dispatcher.register.mock.calls[0][0]
|
|
||||||
let onChange = jest.genMockFunction()
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
onChange.mockClear()
|
|
||||||
activeStore.addListener(onChange)
|
|
||||||
})
|
|
||||||
afterEach(() => activeStore.removeListener(onChange))
|
|
||||||
|
|
||||||
describe('mark-active', () => {
|
|
||||||
it('should mark id as active', () => {
|
|
||||||
expect(activeStore.getActive()).not.toBeDefined()
|
|
||||||
expect(activeStore.isActive('user1')).toBe(false)
|
|
||||||
expect(onChange.mock.calls.length).toBe(0)
|
|
||||||
|
|
||||||
handleAction({ type: 'mark-active', userId: 'user1' })
|
|
||||||
|
|
||||||
expect(activeStore.getActive()).toBe('user1')
|
|
||||||
expect(activeStore.isActive('user1')).toBe(true)
|
|
||||||
|
|
||||||
expect(onChange.mock.calls.length).toBe(1)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@ -1,62 +0,0 @@
|
|||||||
jest.unmock('../alertStore.js')
|
|
||||||
|
|
||||||
const dispatcher = require('../../dispatcher/dispatcher.js')
|
|
||||||
const alertStore = require('../alertStore.js')
|
|
||||||
|
|
||||||
describe('alertStore', () => {
|
|
||||||
let handleAction, onChange
|
|
||||||
beforeEach(() => {
|
|
||||||
handleAction = dispatcher.register.mock.calls[0][0]
|
|
||||||
handleAction({ type: 'alert-clear' })
|
|
||||||
|
|
||||||
onChange = jest.genMockFunction()
|
|
||||||
alertStore.addListener(onChange)
|
|
||||||
})
|
|
||||||
afterEach(() => {
|
|
||||||
alertStore.removeListener(onChange)
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('alert', () => {
|
|
||||||
it('should add alerts to end of queue and dispatch change', () => {
|
|
||||||
let alert1 = { message: 'example alert 1' }
|
|
||||||
let alert2 = { message: 'example alert 2' }
|
|
||||||
|
|
||||||
handleAction({ type: 'alert', alert: alert1 })
|
|
||||||
handleAction({ type: 'alert', alert: alert2 })
|
|
||||||
|
|
||||||
expect(onChange.mock.calls.length).toBe(2)
|
|
||||||
expect(alertStore.getAlerts()).toEqual([ alert1, alert2 ])
|
|
||||||
expect(alertStore.getAlert()).toBe(alert1)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('alert-dismiss', () => {
|
|
||||||
it('should remove alert and dispatch change', () => {
|
|
||||||
let alert1 = { message: 'example alert 1' }
|
|
||||||
let alert2 = { message: 'example alert 2' }
|
|
||||||
|
|
||||||
handleAction({ type: 'alert', alert: alert1 })
|
|
||||||
handleAction({ type: 'alert', alert: alert2 })
|
|
||||||
handleAction({ type: 'alert-dismiss', alert: alert1 })
|
|
||||||
|
|
||||||
expect(onChange.mock.calls.length).toBe(3)
|
|
||||||
expect(alertStore.getAlerts()).toEqual([ alert2 ])
|
|
||||||
expect(alertStore.getAlert()).toBe(alert2)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('alert-clear', () => {
|
|
||||||
it('should remove all alerts', () => {
|
|
||||||
let alert1 = { message: 'example alert 1' }
|
|
||||||
let alert2 = { message: 'example alert 2' }
|
|
||||||
|
|
||||||
handleAction({ type: 'alert', alert: alert1 })
|
|
||||||
handleAction({ type: 'alert', alert: alert2 })
|
|
||||||
handleAction({ type: 'alert-clear' })
|
|
||||||
|
|
||||||
expect(onChange.mock.calls.length).toBe(3)
|
|
||||||
expect(alertStore.getAlerts()).toEqual([])
|
|
||||||
expect(alertStore.getAlert()).not.toBeDefined()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@ -1,61 +0,0 @@
|
|||||||
jest.unmock('../notificationsStore.js')
|
|
||||||
|
|
||||||
const dispatcher = require('../../dispatcher/dispatcher.js')
|
|
||||||
const store = require('../notificationsStore.js')
|
|
||||||
|
|
||||||
describe('store', () => {
|
|
||||||
let handleAction, onChange
|
|
||||||
beforeEach(() => {
|
|
||||||
dispatcher.dispatch.mockClear()
|
|
||||||
handleAction = dispatcher.register.mock.calls[0][0]
|
|
||||||
|
|
||||||
handleAction({ type: 'notify-clear' })
|
|
||||||
|
|
||||||
onChange = jest.genMockFunction()
|
|
||||||
store.addListener(onChange)
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('notify', () => {
|
|
||||||
it('should add notification and dispatch change', () => {
|
|
||||||
let notif1 = { message: 'example notif 1' }
|
|
||||||
let notif2 = { message: 'example notif 2' }
|
|
||||||
|
|
||||||
handleAction({ type: 'notify', notification: notif1 })
|
|
||||||
handleAction({ type: 'notify', notification: notif2 })
|
|
||||||
|
|
||||||
expect(onChange.mock.calls.length).toBe(2)
|
|
||||||
expect(store.getNotifications()).toEqual([ notif1, notif2 ])
|
|
||||||
expect(store.getNotifications(1)).toEqual([ notif2 ])
|
|
||||||
expect(store.getNotifications(3)).toEqual([ notif1, notif2 ])
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should add timeout for autoremoval', () => {
|
|
||||||
let notif1 = { message: 'example notif 1' }
|
|
||||||
|
|
||||||
handleAction({ type: 'notify', notification: notif1 })
|
|
||||||
|
|
||||||
expect(onChange.mock.calls.length).toBe(1)
|
|
||||||
expect(store.getNotifications()).toEqual([ notif1 ])
|
|
||||||
|
|
||||||
jest.runAllTimers()
|
|
||||||
|
|
||||||
expect(onChange.mock.calls.length).toBe(2)
|
|
||||||
expect(store.getNotifications()).toEqual([])
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('notify-dismiss', () => {
|
|
||||||
it('should remove notif and dispatch change', () => {
|
|
||||||
let notif1 = { message: 'example notif 1' }
|
|
||||||
let notif2 = { message: 'example notif 2' }
|
|
||||||
|
|
||||||
handleAction({ type: 'notify', notification: notif1 })
|
|
||||||
handleAction({ type: 'notify', notification: notif2 })
|
|
||||||
handleAction({ type: 'notify-dismiss', notification: notif1 })
|
|
||||||
|
|
||||||
expect(onChange.mock.calls.length).toBe(3)
|
|
||||||
expect(store.getNotifications()).toEqual([ notif2 ])
|
|
||||||
expect(store.getNotifications(2)).toEqual([ notif2 ])
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@ -1,77 +0,0 @@
|
|||||||
jest.unmock('../streamStore.js')
|
|
||||||
|
|
||||||
const createObjectUrl = require('../../browser/createObjectURL.js')
|
|
||||||
const dispatcher = require('../../dispatcher/dispatcher.js')
|
|
||||||
const streamStore = require('../streamStore.js')
|
|
||||||
|
|
||||||
describe('streamStore', () => {
|
|
||||||
let handleAction = dispatcher.register.mock.calls[0][0]
|
|
||||||
let onChange = jest.genMockFunction()
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
onChange.mockClear()
|
|
||||||
streamStore.addListener(onChange)
|
|
||||||
})
|
|
||||||
afterEach(() => streamStore.removeListener(onChange))
|
|
||||||
|
|
||||||
describe('add-stream and remove-stream', () => {
|
|
||||||
it('should add a stream', () => {
|
|
||||||
let stream = {}
|
|
||||||
|
|
||||||
createObjectUrl.mockImplementation(str => {
|
|
||||||
if (str === stream) return 'url1'
|
|
||||||
})
|
|
||||||
|
|
||||||
handleAction({ type: 'add-stream', userId: 'user1', stream })
|
|
||||||
|
|
||||||
expect(streamStore.getStream('user1')).toEqual({
|
|
||||||
stream,
|
|
||||||
url: 'url1'
|
|
||||||
})
|
|
||||||
expect(onChange.mock.calls.length).toEqual(1)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should add a stream multiple times', () => {
|
|
||||||
let stream1 = {}
|
|
||||||
let stream2 = {}
|
|
||||||
|
|
||||||
createObjectUrl.mockImplementation(stream => {
|
|
||||||
if (stream === stream1) return 'url1'
|
|
||||||
if (stream === stream2) return 'url2'
|
|
||||||
})
|
|
||||||
|
|
||||||
handleAction({ type: 'add-stream', userId: 'user1', stream: stream1 })
|
|
||||||
handleAction({ type: 'add-stream', userId: 'user2', stream: stream2 })
|
|
||||||
|
|
||||||
expect(streamStore.getStream('user1')).toEqual({
|
|
||||||
stream: stream1,
|
|
||||||
url: 'url1'
|
|
||||||
})
|
|
||||||
expect(streamStore.getStream('user2')).toEqual({
|
|
||||||
stream: stream2,
|
|
||||||
url: 'url2'
|
|
||||||
})
|
|
||||||
expect(streamStore.getStreams()).toEqual({
|
|
||||||
user1: {
|
|
||||||
stream: stream1,
|
|
||||||
url: 'url1'
|
|
||||||
},
|
|
||||||
user2: {
|
|
||||||
stream: stream2,
|
|
||||||
url: 'url2'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
expect(onChange.mock.calls.length).toEqual(2)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should remove a stream', () => {
|
|
||||||
let stream = {}
|
|
||||||
|
|
||||||
handleAction({ type: 'add-stream', userId: 'user1', stream })
|
|
||||||
handleAction({ type: 'remove-stream', userId: 'user1' })
|
|
||||||
|
|
||||||
expect(streamStore.getStream('user1')).not.toBeDefined()
|
|
||||||
expect(onChange.mock.calls.length).toEqual(2)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@ -1,43 +0,0 @@
|
|||||||
'use strict'
|
|
||||||
const EventEmitter = require('events')
|
|
||||||
const debug = require('debug')('peer-calls:activeStore')
|
|
||||||
const dispatcher = require('../dispatcher/dispatcher.js')
|
|
||||||
|
|
||||||
const emitter = new EventEmitter()
|
|
||||||
const addListener = cb => emitter.on('change', cb)
|
|
||||||
const removeListener = cb => emitter.removeListener('change', cb)
|
|
||||||
|
|
||||||
let active
|
|
||||||
|
|
||||||
const handlers = {
|
|
||||||
'add-stream': ({ userId }) => {
|
|
||||||
active = userId
|
|
||||||
},
|
|
||||||
'mark-active': ({ userId }) => {
|
|
||||||
debug('mark-active, userId: %s', userId)
|
|
||||||
active = userId
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const dispatcherIndex = dispatcher.register(action => {
|
|
||||||
let handle = handlers[action.type]
|
|
||||||
if (!handle) return
|
|
||||||
handle(action)
|
|
||||||
emitter.emit('change')
|
|
||||||
})
|
|
||||||
|
|
||||||
function getActive () {
|
|
||||||
return active
|
|
||||||
}
|
|
||||||
|
|
||||||
function isActive (test) {
|
|
||||||
return active === test
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
dispatcherIndex,
|
|
||||||
addListener,
|
|
||||||
removeListener,
|
|
||||||
getActive,
|
|
||||||
isActive
|
|
||||||
}
|
|
||||||
@ -1,50 +0,0 @@
|
|||||||
const EventEmitter = require('events')
|
|
||||||
const debug = require('debug')('peer-calls:alertStore')
|
|
||||||
const dispatcher = require('../dispatcher/dispatcher.js')
|
|
||||||
|
|
||||||
const emitter = new EventEmitter()
|
|
||||||
const addListener = cb => emitter.on('change', cb)
|
|
||||||
const removeListener = cb => emitter.removeListener('change', cb)
|
|
||||||
|
|
||||||
let alerts = []
|
|
||||||
|
|
||||||
const handlers = {
|
|
||||||
alert: ({ alert }) => {
|
|
||||||
debug('alert: %s', alert.message)
|
|
||||||
alerts.push(alert)
|
|
||||||
},
|
|
||||||
'alert-dismiss': ({ alert }) => {
|
|
||||||
debug('alert-dismiss: %s', alert.message)
|
|
||||||
let index = alerts.indexOf(alert)
|
|
||||||
debug('index: %s', index)
|
|
||||||
if (index < 0) return
|
|
||||||
alerts.splice(index, 1)
|
|
||||||
},
|
|
||||||
'alert-clear': () => {
|
|
||||||
debug('alert-clear')
|
|
||||||
alerts = []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const dispatcherIndex = dispatcher.register(action => {
|
|
||||||
let handle = handlers[action.type]
|
|
||||||
if (!handle) return
|
|
||||||
handle(action)
|
|
||||||
emitter.emit('change')
|
|
||||||
})
|
|
||||||
|
|
||||||
function getAlert () {
|
|
||||||
return alerts[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
function getAlerts () {
|
|
||||||
return alerts
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
dispatcherIndex,
|
|
||||||
addListener,
|
|
||||||
removeListener,
|
|
||||||
getAlert,
|
|
||||||
getAlerts
|
|
||||||
}
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
function getCallId () {
|
|
||||||
return window.document.getElementById('callId').value
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = { getCallId }
|
|
||||||
@ -1,65 +0,0 @@
|
|||||||
const EventEmitter = require('events')
|
|
||||||
const debug = require('debug')('peer-calls:alertStore')
|
|
||||||
const dispatcher = require('../dispatcher/dispatcher.js')
|
|
||||||
|
|
||||||
const emitter = new EventEmitter()
|
|
||||||
const addListener = cb => emitter.on('change', cb)
|
|
||||||
const removeListener = cb => emitter.removeListener('change', cb)
|
|
||||||
|
|
||||||
let index = 0
|
|
||||||
let notifications = []
|
|
||||||
|
|
||||||
function dismiss (notification) {
|
|
||||||
let index = notifications.indexOf(notification)
|
|
||||||
if (index < 0) return
|
|
||||||
notifications.splice(index, 1)
|
|
||||||
clearTimeout(notification._timeout)
|
|
||||||
delete notification._timeout
|
|
||||||
}
|
|
||||||
|
|
||||||
function emitChange () {
|
|
||||||
emitter.emit('change')
|
|
||||||
}
|
|
||||||
|
|
||||||
const handlers = {
|
|
||||||
notify: ({ notification }) => {
|
|
||||||
index++
|
|
||||||
debug('notify', notification.message)
|
|
||||||
notification._id = index
|
|
||||||
notifications.push(notification)
|
|
||||||
notification._timeout = setTimeout(() => {
|
|
||||||
debug('notify-dismiss timeout: %s', notification.message)
|
|
||||||
dismiss(notification)
|
|
||||||
emitChange()
|
|
||||||
}, 10000)
|
|
||||||
},
|
|
||||||
'notify-dismiss': ({ notification }) => {
|
|
||||||
debug('notify-dismiss: %s', notification.message)
|
|
||||||
dismiss(notification)
|
|
||||||
},
|
|
||||||
'notify-clear': () => {
|
|
||||||
debug('notify-clear')
|
|
||||||
notifications = []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const dispatcherIndex = dispatcher.register(action => {
|
|
||||||
let handle = handlers[action.type]
|
|
||||||
if (!handle) return
|
|
||||||
handle(action)
|
|
||||||
emitChange()
|
|
||||||
})
|
|
||||||
|
|
||||||
function getNotifications (max) {
|
|
||||||
if (!max) max = notifications.length
|
|
||||||
let start = notifications.length - max
|
|
||||||
if (start < 0) start = 0
|
|
||||||
return notifications.slice(start, notifications.length)
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
dispatcherIndex,
|
|
||||||
addListener,
|
|
||||||
removeListener,
|
|
||||||
getNotifications
|
|
||||||
}
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
'use strict'
|
|
||||||
const EventEmitter = require('events')
|
|
||||||
const createObjectURL = require('../browser/createObjectURL')
|
|
||||||
const debug = require('debug')('peer-calls:streamStore')
|
|
||||||
const dispatcher = require('../dispatcher/dispatcher.js')
|
|
||||||
|
|
||||||
const emitter = new EventEmitter()
|
|
||||||
const addListener = cb => emitter.on('change', cb)
|
|
||||||
const removeListener = cb => emitter.removeListener('change', cb)
|
|
||||||
|
|
||||||
const streams = {}
|
|
||||||
|
|
||||||
const handlers = {
|
|
||||||
'add-stream': ({ userId, stream }) => {
|
|
||||||
debug('add-stream, user: %s', userId)
|
|
||||||
streams[userId] = {
|
|
||||||
stream,
|
|
||||||
url: createObjectURL(stream)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'remove-stream': ({ userId }) => {
|
|
||||||
debug('remove-stream, user: %s', userId)
|
|
||||||
delete streams[userId]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const dispatcherIndex = dispatcher.register(action => {
|
|
||||||
let handle = handlers[action.type]
|
|
||||||
if (!handle) return
|
|
||||||
handle(action)
|
|
||||||
emitter.emit('change')
|
|
||||||
})
|
|
||||||
|
|
||||||
function getStream (userId) {
|
|
||||||
return streams[userId]
|
|
||||||
}
|
|
||||||
|
|
||||||
function getStreams () {
|
|
||||||
return streams
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
dispatcherIndex,
|
|
||||||
addListener,
|
|
||||||
removeListener,
|
|
||||||
getStream,
|
|
||||||
getStreams
|
|
||||||
}
|
|
||||||
1
src/client/window/createObjectURL.js
Normal file
1
src/client/window/createObjectURL.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export default object => window.URL.createObjectURL(object)
|
||||||
@ -1,8 +1,7 @@
|
|||||||
'use strict'
|
import Promise from 'bluebird'
|
||||||
const navigator = require('../browser/navigator.js')
|
import navigator from './navigator.js'
|
||||||
const Promise = require('bluebird')
|
|
||||||
|
|
||||||
function getUserMedia (constraints) {
|
export default function getUserMedia (constraints) {
|
||||||
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
|
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
|
||||||
return navigator.mediaDevices.getUserMedia(constraints)
|
return navigator.mediaDevices.getUserMedia(constraints)
|
||||||
}
|
}
|
||||||
@ -13,5 +12,3 @@ function getUserMedia (constraints) {
|
|||||||
getMedia.call(navigator, constraints, resolve, reject)
|
getMedia.call(navigator, constraints, resolve, reject)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = getUserMedia
|
|
||||||
1
src/client/window/navigator.js
Normal file
1
src/client/window/navigator.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export default window.navigator
|
||||||
@ -1,6 +1,6 @@
|
|||||||
const debug = require('debug')('peer-calls:video')
|
const debug = require('debug')('peer-calls:video')
|
||||||
|
|
||||||
function play () {
|
export function play () {
|
||||||
let videos = window.document.querySelectorAll('video')
|
let videos = window.document.querySelectorAll('video')
|
||||||
Array.prototype.forEach.call(videos, (video, index) => {
|
Array.prototype.forEach.call(videos, (video, index) => {
|
||||||
debug('playing video: %s', index)
|
debug('playing video: %s', index)
|
||||||
@ -11,5 +11,3 @@ function play () {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { play }
|
|
||||||
Loading…
x
Reference in New Issue
Block a user