Reputation: 251
I am making a chat app as a project in school, and I am trying to add a onClick that runs a function, that uses socket-io-file-upload, to run a prompt function. From the socket-io-file-upload docs. When this method is called, the user will be prompted to choose a file to upload.
JavaScript:
document.getElementById("file_button").addEventListener("click", instance.prompt, false);
HTML:
<button id="file_button">Upload File</button>
Basically I am not sure how I would go about connected the back-end which is being ran separate on how I would be able to use socket-io, in the react front-end as far as using the file-upload..
Here are the files I have right now related to this component in some way - FYI - Using Styled Components
Front-End :
My Reducer (Maybe relevant) -
import React from "react";
import io from "socket.io-client";
export const CTX = React.createContext();
const initState = {
selectedChannel: "general",
socket: io(":3001"),
user: "RandomUser",
allChats: {
general: [''],
channel2: [{ from: "user1", msg: "hello" }],
},
};
const reducer = (state, action) => {
console.log(action);
switch (action.type) {
case "SET_CHANNEL_NAME":
const newChannelName = action.payload;
return {
...state,
allChats: {
...state.allChats,
[newChannelName]: [{from: "ChatBot", msg: "Welcome to a new chatroom!"}]
}
}
case "CREATE_CHANNEL":
return {
...state,
allChats: {
...state.allChats,
newChannel: [ {from: "chatbot", msg: "Welcome to a new chatroom! Type away!"}]
}
};
case "SET_USER_NAME":
return {
...state,
user: action.payload,
};
case "SET_SELECTED_CHANNEL":
return {
...state,
selectedChannel: action.payload,
};
case "RECEIVE_MESSAGE":
const { from, msg, channel } = action.payload;
return {
...state,
allChats: {
...state.allChats,
[channel]: [...state.allChats[state.selectedChannel], { from, msg }],
},
};
default:
return state;
}
};
// const sendChatAction = (value) => {
// socket.emit('chat message', value);
// }
export const Store = (props) => {
const [state, dispatch] = React.useReducer(reducer, initState);
const myDispatch = (type, payload) => {
if (typeof type === "object" && type !== null) {
dispatch(type);
}
dispatch({ type, payload });
};
return (
<CTX.Provider value={{ state, dispatch: myDispatch }}>
{props.children}
</CTX.Provider>
);
};
ChatBox.js -
import React from "react";
import styled from "styled-components";
import Sidebar from "../Sidebar";
import io from 'socket.io-client'
import UserMessage from "../UserMessage";
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faPlus } from '@fortawesome/free-solid-svg-icons'
import InputAddon from '../InputAddon'
import { CTX } from '../Store'
const ChatBox = () => {
const [textValue, changeTextValue] = React.useState('');
const { state, dispatch } = React.useContext(CTX);
console.log(state.user)
React.useEffect(() => {
console.log(state.user)
state.socket.on('message', function (msg) {
console.log("chat message recieved")
dispatch('RECEIVE_MESSAGE', msg);
})
}, [])
const onKeyPressHandler = (e) => {
if (e.key === 'Enter') {
e.preventDefault();
console.log("PRESSED")
state.socket.emit('sent message', { from: state.user, msg: textValue, channel: state.selectedChannel });
dispatch('RECEIVE_MESSAGE', { from: state.user, msg: textValue, channel: state.selectedChannel });
changeTextValue('')
}
}
const onChangeHandler = e => {
changeTextValue(e.target.value);
}
return (
<Layout>
<Sidebar />
<Wrapper>
<InnerBoxWrapper>
<InnerBox>
<UserMessage />
<InputWrapper>
<InputAddons id="InputAddon">
<FontAwesomeIcon icon={faPlus} onClick={InputAddon}></FontAwesomeIcon>
</InputAddons>
<input
label="Send a chat"
onChange={onChangeHandler}
value={textValue}
onKeyPress={onKeyPressHandler}
/>
</InputWrapper>
</InnerBox>
</InnerBoxWrapper>
</Wrapper>
</Layout>
)
}
InputAddon.js -
import React from 'react';
const InputAddon = () => {
console.log('clicked')
}
export default InputAddon;
BACKEND -
www.js -
/**
* Module dependencies.
*/
var app = require('../app');
var debug = require('debug')('cryptidbackend:server');
var http = require('http').createServer(app);
const io = require('socket.io')(http);
const siofu = require('socketio-file-upload')
const cors = require('cors');
app.use(cors());
// Socket.io
io.on('connection', function (socket) {
const uploader = new siofu(socket);
uploader.prompt(document.getElementById("InputAddon"))
uploader.listen(socket)
socket.on('sent message', function (msg) {
console.log('message' + ' : ' + JSON.stringify(msg))
socket.broadcast.emit('message', msg);
})
})
/**
* Get port from environment and store in Express.
*/
http.listen(3001, function () {
console.log('listening on 3001')
})
app.js -
const siofu = require('socketio-file-upload')
const app = express()
const cors = require("cors");
const bodyParser = require("body-parser");
const logger = require("morgan");
const session = require("express-session");
const FileStore = require("session-file-store")(session);
const upload = require("express-fileupload");
app.use(siofu.router)
app.use(upload());
console.log("Server Started!");
app.use(logger("dev"));
app.use(cors());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(
session({
resave: false,
secret: "hello",
saveUninitialized: true,
is_logged_in: false,
})
);
const indexRouter = require("./routes/index");
app.use("/", indexRouter);
const usersRouter = require('./routes/users');
app.use('/users', usersRouter);
module.exports = app;
If you have any questions, or can give me any tips please do I am only about 5 months into my coding career so I still have a lot to learn.
Upvotes: 3
Views: 7585
Reputation: 1
Uncaught TypeError: SocketIOFileUpload is not a constructor
import {SocketIOFileUpload} from "socketio-file-upload";
useEffect(() => {
const siofu = new SocketIOFileUpload(socket);
// call listen on input and pass the hidden input ref
}, [socket])
but :
Uncaught TypeError: SocketIOFileUpload is not a constructor
Upvotes: 0
Reputation: 1
identify the image file from your destination location then use
public static byte[] readBytesFromFile(File file) throws IOException
{
InputStream is = new FileInputStream(file);
// Get the size of the file
long length = file.length();
// You cannot create an array using a long type.
// It needs to be an int type.
// Before converting to an int type, check
// to ensure that file is not larger than Integer.MAX_VALUE.
if (length > Integer.MAX_VALUE)
{
is.close();
throw new IOException("Could not completely read file " + file.getName() + " as it is too long (" + length + " bytes, max supported " + Integer.MAX_VALUE + ")");
}
// Create the byte array to hold the data
byte[] bytes = new byte[(int)length];
// Read in the bytes
int offset = 0;
int numRead = 0;
while (offset < bytes.length && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0)
{
offset += numRead;
}
// Ensure all the bytes have been read in
if (offset < bytes.length)
{
is.close();
throw new IOException("Could not completely read file " +file.getName());
}
// Close the input stream and return bytes
is.close();
return bytes;
}
store image data into byte array.
Then, mention your destination location and apply
It will run.
Upvotes: -2
Reputation: 281834
In order to upload file from frontend, what you need to do is to create an instance of socket-file-upload on frontend in a useEffect inside ChatBox component.
Also you need to create a dummy hidden input on which you can simulate click when Upload button is clicked and also the input on which you can listen on
Small snippet code that you need to add
const fileRef = useRef(null);
useEffect(() => {
const siofu = new SocketIOFileUpload(state.socket);
// call listen on input and pass the hidden input ref
siofu.listenOnInput(fileRef.current);
}, [state.socket])
const InputAddon = () => {
// Trigger click on fileRef input
fileRef.current.click();
}
Full component code with input
import SocketIOFileUpload from 'socketio-file-upload';
const ChatBox = () => {
const [textValue, changeTextValue] = React.useState('');
const { state, dispatch } = React.useContext(CTX);
console.log(state.user)
React.useEffect(() => {
console.log(state.user)
state.socket.on('message', function (msg) {
console.log("chat message recieved")
dispatch('RECEIVE_MESSAGE', msg);
})
}, [])
const onKeyPressHandler = (e) => {
if (e.key === 'Enter') {
e.preventDefault();
console.log("PRESSED")
state.socket.emit('sent message', { from: state.user, msg: textValue, channel: state.selectedChannel });
dispatch('RECEIVE_MESSAGE', { from: state.user, msg: textValue, channel: state.selectedChannel });
changeTextValue('')
}
}
const onChangeHandler = e => {
changeTextValue(e.target.value);
}
const fileRef = useRef(null);
useEffect(() => {
const siofu = new SocketIOFileUpload(state.socket);
// call listen on input and pass the hidden input ref
siofu.listenOnInput(fileRef.current);
}, [state.socket])
const InputAddon = () => {
// Trigger click on fileRef input
fileRef.current.click();
}
return (
<Layout>
<Sidebar />
<Wrapper>
<InnerBoxWrapper>
<InnerBox>
<UserMessage />
<InputWrapper>
<InputAddons id="InputAddon">
<FontAwesomeIcon icon={faPlus} onClick={InputAddon}></FontAwesomeIcon>
</InputAddons>
<input
ref={fileRef}
label="file-picker"
type="file"
style={{display: 'none'}}
/>
<input
label="Send a chat"
onChange={onChangeHandler}
value={textValue}
onKeyPress={onKeyPressHandler}
/>
</InputWrapper>
</InnerBox>
</InnerBoxWrapper>
</Wrapper>
</Layout>
)
}
In the backend code you need to create a express server and add sockiofileUpload router to it
var app = require('../app');
var debug = require('debug')('cryptidbackend:server');
const socketio = require('socket.io');
/**
* Get port from environment and store in Express.
*/
app.listen(3001, function () {
console.log('listening on 3001')
})
var io = socketio.listen(app);
// Socket.io
io.sockets.on('connection', function (socket) {
const uploader = new siofu(socket);
uploader.listen(socket)
uploader.dir = "/srv/uploads";
uploader.listen(socket);
// Do something when a file is saved:
uploader.on("saved", function(event){
console.log(event.file);
});
// Error handler:
uploader.on("error", function(event){
console.log("Error from uploader", event);
});
})
app.js
const siofu = require('socketio-file-upload')
const app = express()
const cors = require("cors");
const bodyParser = require("body-parser");
const logger = require("morgan");
const session = require("express-session");
const FileStore = require("session-file-store")(session);
app.use(siofu.router)
console.log("Server Started!");
app.use(logger("dev"));
app.use(cors());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(
session({
resave: false,
secret: "hello",
saveUninitialized: true,
is_logged_in: false,
})
);
const indexRouter = require("./routes/index");
app.use("/", indexRouter);
const usersRouter = require('./routes/users');
app.use('/users', usersRouter);
Upvotes: 5
Reputation: 126
first of all this part of the code is in backend and in backend there is no document or window.which means document.getElementById wont work here.
io.on('connection', function (socket) {
const uploader = new siofu(socket);
uploader.prompt(document.getElementById("InputAddon"))
uploader.listen(socket)
socket.on('sent message', function (msg) {
console.log('message' + ' : ' + JSON.stringify(msg))
socket.broadcast.emit('message', msg);
})
})
then there is no upload file location/dir is define.
you can see the example
express-fileupload
app.use(fileUpload({
useTempFiles : true,
tempFileDir : '/tmp/'
}));
socketio-file-upload
io.on("connection", function(socket){
var uploader = new siofu();
uploader.dir = "/path/to/save/uploads"; ***//upload directory***
uploader.listen(socket);
});
so what i will suggest you is go throught the link mention below and update your code.
https://www.npmjs.com/package/express-fileupload
https://github.com/sffc/socketio-file-upload
Upvotes: 0