diff --git a/.eslintrc b/.eslintrc
index c93e21c..5058461 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -1,7 +1,9 @@
{
+ "parser": "babel-eslint",
"extends": ["standard", "standard-react"],
"rules": {
- "max-len": [2, 80, 4]
+ "max-len": [2, 80, 4],
+ "jsx-quotes": ["error", "prefer-double"]
},
"globals": {
"expect": true,
diff --git a/package.json b/package.json
index af79789..5dce48a 100644
--- a/package.json
+++ b/package.json
@@ -11,14 +11,21 @@
"lint": "eslint ./index.js ./src/js"
},
"babel": {
- "presets": ["es2016", "react", "transform-object-rest-spread"]
+ "presets": [
+ "es2016",
+ "react",
+ "transform-object-rest-spread",
+ "transform-class-properties"
+ ]
},
"author": "",
"license": "MIT",
"dependencies": {
"bluebird": "^3.3.4",
+ "classnames": "^2.2.5",
"config": "^1.26.1",
"express": "^4.13.3",
+ "prop-types": "^15.5.10",
"pug": "^2.0.0-rc.2",
"react": "^15.5.4",
"react-addons-transition-group": "^15.5.2",
@@ -26,6 +33,7 @@
"react-redux": "^5.0.5",
"redux": "^3.6.0",
"redux-thunk": "^2.2.0",
+ "seamless-immutable": "^7.1.2",
"simple-peer": "^8.1.0",
"socket.io": "1.6.0",
"socket.io-client": "1.6.0",
@@ -33,7 +41,9 @@
"uuid": "^2.0.1"
},
"devDependencies": {
+ "babel-eslint": "^7.2.3",
"babel-jest": "^20.0.3",
+ "babel-plugin-transform-class-properties": "^6.24.1",
"babel-plugin-transform-object-rest-spread": "^6.23.0",
"babel-preset-es2016": "^6.24.1",
"babel-preset-react": "^6.24.1",
diff --git a/src/client/action/__tests__/notify-test.js b/src/client/action/__tests__/notify-test.js
deleted file mode 100644
index 850b3cd..0000000
--- a/src/client/action/__tests__/notify-test.js
+++ /dev/null
@@ -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'
- }
- }]])
- })
- })
-})
diff --git a/src/client/action/notify.js b/src/client/action/notify.js
deleted file mode 100644
index 62e3c80..0000000
--- a/src/client/action/notify.js
+++ /dev/null
@@ -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 }
diff --git a/src/client/actions/CallActions.js b/src/client/actions/CallActions.js
new file mode 100644
index 0000000..2ee9c4f
--- /dev/null
+++ b/src/client/actions/CallActions.js
@@ -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
+ }
+})
diff --git a/src/client/actions/NotifyActions.js b/src/client/actions/NotifyActions.js
index b480ef3..7f6b895 100644
--- a/src/client/actions/NotifyActions.js
+++ b/src/client/actions/NotifyActions.js
@@ -7,34 +7,32 @@ function format (string, args) {
function _notify (type, args) {
let string = args[0] || ''
let message = format(string, Array.prototype.slice.call(args, 1))
- dispatcher.dispatch({
+ return {
type: 'notify',
- notification: { type, message }
- })
+ payload: { type, message }
+ }
}
-function info () {
- _notify('info', arguments)
+export function info () {
+ return _notify('info', arguments)
}
-function warn () {
- _notify('warning', arguments)
+export function warn () {
+ return _notify('warning', arguments)
}
-function error () {
- _notify('error', arguments)
+export function error () {
+ return _notify('error', arguments)
}
-function alert (message, dismissable) {
- dispatcher.dispatch({
+export function alert (message, dismissable) {
+ return {
type: 'alert',
- alert: {
+ payload: {
action: dismissable ? 'Dismiss' : '',
dismissable: !!dismissable,
message,
type: 'warning'
}
- })
+ }
}
-
-module.exports = { alert, info, warn, error }
diff --git a/src/client/browser/createObjectURL.js b/src/client/browser/createObjectURL.js
deleted file mode 100644
index e79b657..0000000
--- a/src/client/browser/createObjectURL.js
+++ /dev/null
@@ -1,2 +0,0 @@
-'use strict'
-module.exports = object => window.URL.createObjectURL(object)
diff --git a/src/client/browser/navigator.js b/src/client/browser/navigator.js
deleted file mode 100644
index e7206fe..0000000
--- a/src/client/browser/navigator.js
+++ /dev/null
@@ -1,2 +0,0 @@
-'use strict'
-module.exports = window.navigator
diff --git a/src/client/call.js b/src/client/call.js
deleted file mode 100644
index c8810e2..0000000
--- a/src/client/call.js
+++ /dev/null
@@ -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 }
diff --git a/src/client/callId.js b/src/client/callId.js
new file mode 100644
index 0000000..ffbb994
--- /dev/null
+++ b/src/client/callId.js
@@ -0,0 +1 @@
+export default window.document.getElementById('callId').value
diff --git a/src/client/components/Alert.js b/src/client/components/Alert.js
new file mode 100644
index 0000000..2550005
--- /dev/null
+++ b/src/client/components/Alert.js
@@ -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 (
+
+ {alert.message}
+ {alert.dismissable && (
+
+ )}
+
+ )
+ }
+}
+
+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 (
+
+ {alerts.map((alert, i) => (
+
+ ))}
+
+ )
+ }
+}
diff --git a/src/client/components/Input.js b/src/client/components/Input.js
new file mode 100644
index 0000000..31de1d7
--- /dev/null
+++ b/src/client/components/Input.js
@@ -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 (
+
+ )
+ }
+}
diff --git a/src/client/components/Notifications.js b/src/client/components/Notifications.js
new file mode 100644
index 0000000..e81b5be
--- /dev/null
+++ b/src/client/components/Notifications.js
@@ -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 (
+
+
+ {notifications.slice(max).map(notification => (
+
+ {notification.message}
+
+ ))}
+
+
+ )
+ }
+}
diff --git a/src/client/components/alert.js b/src/client/components/alert.js
deleted file mode 100644
index 77bc66b..0000000
--- a/src/client/components/alert.js
+++ /dev/null
@@ -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
- let button
-
- function dismiss () {
- dispatcher.dispatch({
- type: 'alert-dismiss',
- alert
- })
- }
-
- if (alert.dismissable) {
- button =
- }
-
- return (
-
- {alert.message}
- {button}
-
- )
-}
-
-module.exports = alert
diff --git a/src/client/components/input.js b/src/client/components/input.js
deleted file mode 100644
index 781a776..0000000
--- a/src/client/components/input.js
+++ /dev/null
@@ -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 (
-
- )
- }
-})
-
-module.exports = Input
diff --git a/src/client/components/notifications.js b/src/client/components/notifications.js
deleted file mode 100644
index 84112d9..0000000
--- a/src/client/components/notifications.js
+++ /dev/null
@@ -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 (
-
- {notif.message}
-
- )
- })
-
- return (
-
-
- {notificationElements}
-
-
- )
-}
-
-module.exports = notifications
diff --git a/src/client/constants.js b/src/client/constants.js
new file mode 100644
index 0000000..22d9f4a
--- /dev/null
+++ b/src/client/constants.js
@@ -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'
diff --git a/src/client/dispatcher/dispatcher.js b/src/client/dispatcher/dispatcher.js
deleted file mode 100644
index eddbb60..0000000
--- a/src/client/dispatcher/dispatcher.js
+++ /dev/null
@@ -1,5 +0,0 @@
-const Dispatcher = require('flux').Dispatcher
-
-const dispatcher = new Dispatcher()
-
-module.exports = dispatcher
diff --git a/src/client/iceServers.js b/src/client/iceServers.js
index 972198c..d780061 100644
--- a/src/client/iceServers.js
+++ b/src/client/iceServers.js
@@ -1,3 +1,3 @@
-module.exports = JSON.parse(
+export default JSON.parse(
window.document.getElementById('iceServers').value
)
diff --git a/src/client/reducers/alerts.js b/src/client/reducers/alerts.js
new file mode 100644
index 0000000..7c7ebb2
--- /dev/null
+++ b/src/client/reducers/alerts.js
@@ -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
+ }
+}
diff --git a/src/client/reducers/index.js b/src/client/reducers/index.js
new file mode 100644
index 0000000..c0cc0d5
--- /dev/null
+++ b/src/client/reducers/index.js
@@ -0,0 +1,9 @@
+import alerts from './alerts.js'
+import notifications from './notifications.js'
+import streams from './streams.js'
+
+export default {
+ alerts,
+ notifications,
+ streams
+}
diff --git a/src/client/reducers/notifications.js b/src/client/reducers/notifications.js
new file mode 100644
index 0000000..c74c6a3
--- /dev/null
+++ b/src/client/reducers/notifications.js
@@ -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
+ }
+}
diff --git a/src/client/reducers/stream.js b/src/client/reducers/stream.js
new file mode 100644
index 0000000..fadf08d
--- /dev/null
+++ b/src/client/reducers/stream.js
@@ -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
+ }
+}
diff --git a/src/client/socket.js b/src/client/socket.js
index 0dbb2b9..4821823 100644
--- a/src/client/socket.js
+++ b/src/client/socket.js
@@ -1,5 +1,2 @@
-let SocketIOClient = require('socket.io-client')
-
-let socket = new SocketIOClient()
-
-module.exports = socket
+import SocketIOClient from 'socket.io-client'
+export default new SocketIOClient()
diff --git a/src/client/store.js b/src/client/store.js
new file mode 100644
index 0000000..6b64bbb
--- /dev/null
+++ b/src/client/store.js
@@ -0,0 +1,8 @@
+import { applyMiddleware, createStore } from 'redux'
+import thunk from 'redux-thunk'
+import reducer from './reducers'
+
+export default createStore(
+ reducer,
+ applyMiddleware(thunk)
+)
diff --git a/src/client/store/__tests__/activeStore-test.js b/src/client/store/__tests__/activeStore-test.js
deleted file mode 100644
index 47c6b3e..0000000
--- a/src/client/store/__tests__/activeStore-test.js
+++ /dev/null
@@ -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)
- })
- })
-})
diff --git a/src/client/store/__tests__/alertStore-test.js b/src/client/store/__tests__/alertStore-test.js
deleted file mode 100644
index e3fc1e0..0000000
--- a/src/client/store/__tests__/alertStore-test.js
+++ /dev/null
@@ -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()
- })
- })
-})
diff --git a/src/client/store/__tests__/notificationsStore-test.js b/src/client/store/__tests__/notificationsStore-test.js
deleted file mode 100644
index c84354f..0000000
--- a/src/client/store/__tests__/notificationsStore-test.js
+++ /dev/null
@@ -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 ])
- })
- })
-})
diff --git a/src/client/store/__tests__/streamStore-test.js b/src/client/store/__tests__/streamStore-test.js
deleted file mode 100644
index df0739a..0000000
--- a/src/client/store/__tests__/streamStore-test.js
+++ /dev/null
@@ -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)
- })
- })
-})
diff --git a/src/client/store/activeStore.js b/src/client/store/activeStore.js
deleted file mode 100644
index 201eb71..0000000
--- a/src/client/store/activeStore.js
+++ /dev/null
@@ -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
-}
diff --git a/src/client/store/alertStore.js b/src/client/store/alertStore.js
deleted file mode 100644
index a85a317..0000000
--- a/src/client/store/alertStore.js
+++ /dev/null
@@ -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
-}
diff --git a/src/client/store/callIdStore.js b/src/client/store/callIdStore.js
deleted file mode 100644
index 921ed1b..0000000
--- a/src/client/store/callIdStore.js
+++ /dev/null
@@ -1,5 +0,0 @@
-function getCallId () {
- return window.document.getElementById('callId').value
-}
-
-module.exports = { getCallId }
diff --git a/src/client/store/notificationsStore.js b/src/client/store/notificationsStore.js
deleted file mode 100644
index 4a08bb5..0000000
--- a/src/client/store/notificationsStore.js
+++ /dev/null
@@ -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
-}
diff --git a/src/client/store/streamStore.js b/src/client/store/streamStore.js
deleted file mode 100644
index c2b0c5e..0000000
--- a/src/client/store/streamStore.js
+++ /dev/null
@@ -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
-}
diff --git a/src/client/window/createObjectURL.js b/src/client/window/createObjectURL.js
new file mode 100644
index 0000000..026adf9
--- /dev/null
+++ b/src/client/window/createObjectURL.js
@@ -0,0 +1 @@
+export default object => window.URL.createObjectURL(object)
diff --git a/src/client/browser/getUserMedia.js b/src/client/window/getUserMedia.js
similarity index 69%
rename from src/client/browser/getUserMedia.js
rename to src/client/window/getUserMedia.js
index 9e93c5e..2bd4f23 100644
--- a/src/client/browser/getUserMedia.js
+++ b/src/client/window/getUserMedia.js
@@ -1,8 +1,7 @@
-'use strict'
-const navigator = require('../browser/navigator.js')
-const Promise = require('bluebird')
+import Promise from 'bluebird'
+import navigator from './navigator.js'
-function getUserMedia (constraints) {
+export default function getUserMedia (constraints) {
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
return navigator.mediaDevices.getUserMedia(constraints)
}
@@ -13,5 +12,3 @@ function getUserMedia (constraints) {
getMedia.call(navigator, constraints, resolve, reject)
})
}
-
-module.exports = getUserMedia
diff --git a/src/client/window/navigator.js b/src/client/window/navigator.js
new file mode 100644
index 0000000..46f7f47
--- /dev/null
+++ b/src/client/window/navigator.js
@@ -0,0 +1 @@
+export default window.navigator
diff --git a/src/client/browser/video.js b/src/client/window/video.js
similarity index 87%
rename from src/client/browser/video.js
rename to src/client/window/video.js
index b5a8c76..2ff499c 100644
--- a/src/client/browser/video.js
+++ b/src/client/window/video.js
@@ -1,6 +1,6 @@
const debug = require('debug')('peer-calls:video')
-function play () {
+export function play () {
let videos = window.document.querySelectorAll('video')
Array.prototype.forEach.call(videos, (video, index) => {
debug('playing video: %s', index)
@@ -11,5 +11,3 @@ function play () {
}
})
}
-
-module.exports = { play }