КЛИЕНТ:
- Получить файл из input[type=file]:
const { files } = e.target; file = files[0];
2. Затем нам нужно разрезать файл на части (я буду разрезать их на части по 100кБ):
const slice = file.slice(0, 100000);
3. Теперь мы можем начать отправлять эти слайсы, но перед этим мы должны прочитать файл как Array Buffer:
const fileReader = new FileReader(); fileReader.onload = () => { const int8Array = new Int8Array(fileReader.result); const data = []; each(int8Array, (item) => { data.push(item); }); // function right below is for emit websocket message to server it takes 2 parameters: 1 - type of message, 2 - data to send executeWebsocketRequest(SLICE_UPLOAD, { name: file.name, type: file.type, size: file.size, data, }); }; fileReader.readAsArrayBuffer(slice);
СЕРВЕР:
4. Здесь мы обработаем получение фрагментов изображения от клиента и проверим, получили ли мы все фрагменты, после чего загрузка файла закончилась:
const files = {}, struct = { name: null, type: null, size: 0, data: [], slice: 0, }; export const uploadFile = (ws, data) => { const sliceData = data.data; if (!files[sliceData.name]) { files[sliceData.name] = Object.assign({}, struct, sliceData); files[sliceData.name].data = []; } //convert the Object to Int8Array and then to Buffer sliceData.data = new Buffer(new Int8Array(sliceData.data)); //save the data files[sliceData.name].data.push(sliceData.data); files[sliceData.name].slice++; if (files[sliceData.name].slice * 100000 >= files[sliceData.name].size) { // file upload ended and we can send it to AWS S3 bucket sendToOpenedSocket(ws, { type: IMAGE_UPLOAD_ENDED }); // Concat all the image slices to one Buffer const fileBuffer = Buffer.concat(files[sliceData.name].data); const type = sliceData.type.split('/'); if (type[0] !== IMAGE) { // TODO write checking functionality for no image files and send error to client return; } uploadFileToAWS(fileBuffer, sliceData.name, type) .then((data) => { // add aws file link to db document field image const { collectionName, _id } = sliceData; documentUpdate(ws, { data: { collectionName: collectionName, _id, fields: { image: data.Location }}}); delete files[data.name]; }) .catch((err) => { console.log('aws error', err) }) } else { sendToOpenedSocket(ws, { type: NEXT_IMAGE_SLICE_UPLOAD, currentSlice: files[sliceData.name].slice }) } };
5. Как видите, мы также написали функционал для загрузки изображений в корзину AWS S3. (https://medium.com/quant-five/node-js-with-amazon-sdk-for-s3-uploads-d20dd5c9ca4b)
// configure the keys for accessing AWS AWS.config.update({ accessKeyId: AWS_ACCESS_KEY_ID, secretAccessKey: AWS_SECRET_ACCESS_KEY }); // configure AWS to work with promises AWS.config.setPromisesDependency(bluebird); // create S3 instance const s3 = new AWS.S3(); export const uploadFileToAWS = (buffer, name, type) => { const params = { ACL: 'public-read', Body: buffer, Bucket: S3_BUCKET, ContentType: type[0], Key: name }; return s3.upload(params).promise(); };