Add ability to send file via base64-encoded msg

This commit is contained in:
Jerko Steiner 2019-11-11 22:14:37 -03:00
parent 3352c68f5c
commit 644fcbe06d
5 changed files with 98 additions and 7 deletions

View File

@ -1,3 +1,4 @@
import * as ChatActions from '../actions/ChatActions.js'
import * as NotifyActions from '../actions/NotifyActions.js'
import * as StreamActions from '../actions/StreamActions.js'
import * as constants from '../constants.js'
@ -46,10 +47,25 @@ class PeerHandler {
}
handleData = object => {
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)
const message = user.id + ': ' + object.message
dispatch(NotifyActions.info(message))
switch (object.type) {
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 = () => {
const { dispatch, user } = this
@ -126,7 +142,42 @@ export const destroyPeers = () => ({
})
export const sendMessage = message => (dispatch, getState) => {
message = JSON.stringify({ message })
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)
}

View File

@ -20,6 +20,7 @@ export default class App extends React.PureComponent {
peers: PropTypes.object.isRequired,
sendMessage: PropTypes.func.isRequired,
streams: PropTypes.objectOf(StreamPropType).isRequired,
onSendFile: PropTypes.func.isRequired,
toggleActive: PropTypes.func.isRequired
}
constructor () {
@ -56,6 +57,7 @@ export default class App extends React.PureComponent {
notifications,
notify,
messages,
onSendFile,
peers,
sendMessage,
toggleActive,
@ -70,6 +72,7 @@ export default class App extends React.PureComponent {
chatVisible={this.state.chatVisible}
messages={messages}
onToggleChat={this.handleToggleChat}
onSendFile={onSendFile}
stream={streams[constants.ME]}
/>
<Alerts alerts={alerts} dismiss={dismissAlert} />

View File

@ -82,7 +82,12 @@ export default class Chat extends React.PureComponent {
</span>
<span className="icon icon-schedule" />
<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>
)}

View File

@ -5,13 +5,22 @@ import screenfull from 'screenfull'
import { MessagePropTypes } from './Chat.js'
import { StreamPropType } from './Video.js'
const hidden = {
display: 'none'
}
export default class Toolbar extends React.PureComponent {
static propTypes = {
messages: PropTypes.arrayOf(MessagePropTypes).isRequired,
stream: StreamPropType,
onToggleChat: PropTypes.func.isRequired,
onSendFile: PropTypes.func.isRequired,
chatVisible: PropTypes.bool.isRequired
}
constructor (props) {
super(props)
this.file = React.createRef()
}
handleMicClick = () => {
const { stream } = this.props
stream.mediaStream.getAudioTracks().forEach(track => {
@ -35,6 +44,14 @@ export default class Toolbar extends React.PureComponent {
handleHangoutClick = () => {
window.location.href = '/'
}
handleSendFile = () => {
this.file.current.click()
}
handleSelectFiles = () => {
Array
.from(this.file.current.files)
.forEach(file => this.props.onSendFile(file))
}
render () {
const { messages, stream } = this.props
@ -49,6 +66,20 @@ export default class Toolbar extends React.PureComponent {
>
<span className="icon icon-question_answer" />
</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 && (
<div>

View File

@ -23,7 +23,8 @@ function mapDispatchToProps (dispatch) {
sendMessage: bindActionCreators(PeerActions.sendMessage, dispatch),
dismissAlert: bindActionCreators(NotifyActions.dismissAlert, dispatch),
init: bindActionCreators(CallActions.init, dispatch),
notify: bindActionCreators(NotifyActions.info, dispatch)
notify: bindActionCreators(NotifyActions.info, dispatch),
onSendFile: bindActionCreators(PeerActions.sendFile, dispatch)
}
}