Add ability to send file via base64-encoded msg
This commit is contained in:
parent
3352c68f5c
commit
644fcbe06d
@ -1,3 +1,4 @@
|
|||||||
|
import * as ChatActions from '../actions/ChatActions.js'
|
||||||
import * as NotifyActions from '../actions/NotifyActions.js'
|
import * as NotifyActions from '../actions/NotifyActions.js'
|
||||||
import * as StreamActions from '../actions/StreamActions.js'
|
import * as StreamActions from '../actions/StreamActions.js'
|
||||||
import * as constants from '../constants.js'
|
import * as constants from '../constants.js'
|
||||||
@ -46,10 +47,25 @@ class PeerHandler {
|
|||||||
}
|
}
|
||||||
handleData = object => {
|
handleData = object => {
|
||||||
const { dispatch, user } = this
|
const { dispatch, user } = this
|
||||||
object = JSON.parse(new window.TextDecoder('utf-8').decode(object))
|
const message = JSON.parse(new window.TextDecoder('utf-8').decode(object))
|
||||||
debug('peer: %s, message: %o', user.id, object)
|
debug('peer: %s, message: %o', user.id, object)
|
||||||
const message = user.id + ': ' + object.message
|
switch (object.type) {
|
||||||
dispatch(NotifyActions.info(message))
|
case 'file':
|
||||||
|
dispatch(ChatActions.addMessage({
|
||||||
|
userId: user.id,
|
||||||
|
message: 'Sent a file: "' + message.payload.name,
|
||||||
|
timestamp: new Date().toLocaleString(),
|
||||||
|
image: message.payload.data
|
||||||
|
}))
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
dispatch(ChatActions.addMessage({
|
||||||
|
userId: user.id,
|
||||||
|
message: message.payload,
|
||||||
|
timestamp: new Date().toLocaleString(),
|
||||||
|
image: null
|
||||||
|
}))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
handleClose = () => {
|
handleClose = () => {
|
||||||
const { dispatch, user } = this
|
const { dispatch, user } = this
|
||||||
@ -126,7 +142,42 @@ export const destroyPeers = () => ({
|
|||||||
})
|
})
|
||||||
|
|
||||||
export const sendMessage = message => (dispatch, getState) => {
|
export const sendMessage = message => (dispatch, getState) => {
|
||||||
message = JSON.stringify({ message })
|
|
||||||
const { peers } = getState()
|
const { peers } = getState()
|
||||||
_.each(peers, peer => peer.send(message))
|
dispatch(NotifyActions.info('Sending message type: {0} to {1} peers.',
|
||||||
|
message.type, Object.keys(peers).length))
|
||||||
|
_.each(peers, peer => {
|
||||||
|
switch (message.type) {
|
||||||
|
case 'file':
|
||||||
|
dispatch(ChatActions.addMessage({
|
||||||
|
userId: 'You',
|
||||||
|
message: 'Send file: "' +
|
||||||
|
message.payload.name + '" to peer: ' + peer._id,
|
||||||
|
timestamp: new Date().toLocaleString(),
|
||||||
|
image: message.payload.data
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
peer.send(JSON.stringify(message))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const sendFile = file => async (dispatch, getState) => {
|
||||||
|
const { name, size, type } = file
|
||||||
|
if (!window.FileReader) {
|
||||||
|
dispatch(NotifyActions.error('File API is not supported by your browser'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const reader = new window.FileReader()
|
||||||
|
const base64File = await new Promise(resolve => {
|
||||||
|
reader.addEventListener('load', () => {
|
||||||
|
resolve({
|
||||||
|
name,
|
||||||
|
size,
|
||||||
|
type,
|
||||||
|
data: reader.result
|
||||||
|
})
|
||||||
|
})
|
||||||
|
reader.readAsDataURL(file)
|
||||||
|
})
|
||||||
|
|
||||||
|
sendMessage({ payload: base64File, type: 'file' })(dispatch, getState)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,6 +20,7 @@ export default class App extends React.PureComponent {
|
|||||||
peers: PropTypes.object.isRequired,
|
peers: PropTypes.object.isRequired,
|
||||||
sendMessage: PropTypes.func.isRequired,
|
sendMessage: PropTypes.func.isRequired,
|
||||||
streams: PropTypes.objectOf(StreamPropType).isRequired,
|
streams: PropTypes.objectOf(StreamPropType).isRequired,
|
||||||
|
onSendFile: PropTypes.func.isRequired,
|
||||||
toggleActive: PropTypes.func.isRequired
|
toggleActive: PropTypes.func.isRequired
|
||||||
}
|
}
|
||||||
constructor () {
|
constructor () {
|
||||||
@ -56,6 +57,7 @@ export default class App extends React.PureComponent {
|
|||||||
notifications,
|
notifications,
|
||||||
notify,
|
notify,
|
||||||
messages,
|
messages,
|
||||||
|
onSendFile,
|
||||||
peers,
|
peers,
|
||||||
sendMessage,
|
sendMessage,
|
||||||
toggleActive,
|
toggleActive,
|
||||||
@ -70,6 +72,7 @@ export default class App extends React.PureComponent {
|
|||||||
chatVisible={this.state.chatVisible}
|
chatVisible={this.state.chatVisible}
|
||||||
messages={messages}
|
messages={messages}
|
||||||
onToggleChat={this.handleToggleChat}
|
onToggleChat={this.handleToggleChat}
|
||||||
|
onSendFile={onSendFile}
|
||||||
stream={streams[constants.ME]}
|
stream={streams[constants.ME]}
|
||||||
/>
|
/>
|
||||||
<Alerts alerts={alerts} dismiss={dismissAlert} />
|
<Alerts alerts={alerts} dismiss={dismissAlert} />
|
||||||
|
|||||||
@ -82,7 +82,12 @@ export default class Chat extends React.PureComponent {
|
|||||||
</span>
|
</span>
|
||||||
<span className="icon icon-schedule" />
|
<span className="icon icon-schedule" />
|
||||||
<time className="message-time">{message.timestamp}</time>
|
<time className="message-time">{message.timestamp}</time>
|
||||||
<p className="message-text">{message.message}</p>
|
<p className="message-text">
|
||||||
|
{message.image && (
|
||||||
|
<img src={message.image} width="100%" />
|
||||||
|
)}
|
||||||
|
{message.message}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -5,13 +5,22 @@ import screenfull from 'screenfull'
|
|||||||
import { MessagePropTypes } from './Chat.js'
|
import { MessagePropTypes } from './Chat.js'
|
||||||
import { StreamPropType } from './Video.js'
|
import { StreamPropType } from './Video.js'
|
||||||
|
|
||||||
|
const hidden = {
|
||||||
|
display: 'none'
|
||||||
|
}
|
||||||
|
|
||||||
export default class Toolbar extends React.PureComponent {
|
export default class Toolbar extends React.PureComponent {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
messages: PropTypes.arrayOf(MessagePropTypes).isRequired,
|
messages: PropTypes.arrayOf(MessagePropTypes).isRequired,
|
||||||
stream: StreamPropType,
|
stream: StreamPropType,
|
||||||
onToggleChat: PropTypes.func.isRequired,
|
onToggleChat: PropTypes.func.isRequired,
|
||||||
|
onSendFile: PropTypes.func.isRequired,
|
||||||
chatVisible: PropTypes.bool.isRequired
|
chatVisible: PropTypes.bool.isRequired
|
||||||
}
|
}
|
||||||
|
constructor (props) {
|
||||||
|
super(props)
|
||||||
|
this.file = React.createRef()
|
||||||
|
}
|
||||||
handleMicClick = () => {
|
handleMicClick = () => {
|
||||||
const { stream } = this.props
|
const { stream } = this.props
|
||||||
stream.mediaStream.getAudioTracks().forEach(track => {
|
stream.mediaStream.getAudioTracks().forEach(track => {
|
||||||
@ -35,6 +44,14 @@ export default class Toolbar extends React.PureComponent {
|
|||||||
handleHangoutClick = () => {
|
handleHangoutClick = () => {
|
||||||
window.location.href = '/'
|
window.location.href = '/'
|
||||||
}
|
}
|
||||||
|
handleSendFile = () => {
|
||||||
|
this.file.current.click()
|
||||||
|
}
|
||||||
|
handleSelectFiles = () => {
|
||||||
|
Array
|
||||||
|
.from(this.file.current.files)
|
||||||
|
.forEach(file => this.props.onSendFile(file))
|
||||||
|
}
|
||||||
render () {
|
render () {
|
||||||
const { messages, stream } = this.props
|
const { messages, stream } = this.props
|
||||||
|
|
||||||
@ -49,6 +66,20 @@ export default class Toolbar extends React.PureComponent {
|
|||||||
>
|
>
|
||||||
<span className="icon icon-question_answer" />
|
<span className="icon icon-question_answer" />
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
className="button send-file"
|
||||||
|
onClick={this.handleSendFile}
|
||||||
|
title="Send file"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
style={hidden}
|
||||||
|
type="file"
|
||||||
|
multiple
|
||||||
|
ref={this.file}
|
||||||
|
onChange={this.handleSelectFiles}
|
||||||
|
/>
|
||||||
|
<span className="icon icon-file-text2" />
|
||||||
|
</div>
|
||||||
|
|
||||||
{stream && (
|
{stream && (
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@ -23,7 +23,8 @@ function mapDispatchToProps (dispatch) {
|
|||||||
sendMessage: bindActionCreators(PeerActions.sendMessage, dispatch),
|
sendMessage: bindActionCreators(PeerActions.sendMessage, dispatch),
|
||||||
dismissAlert: bindActionCreators(NotifyActions.dismissAlert, dispatch),
|
dismissAlert: bindActionCreators(NotifyActions.dismissAlert, dispatch),
|
||||||
init: bindActionCreators(CallActions.init, dispatch),
|
init: bindActionCreators(CallActions.init, dispatch),
|
||||||
notify: bindActionCreators(NotifyActions.info, dispatch)
|
notify: bindActionCreators(NotifyActions.info, dispatch),
|
||||||
|
onSendFile: bindActionCreators(PeerActions.sendFile, dispatch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user