import {talkEvent} from "http://talk.kospo.co.kr:3000/static/js/module/talkEvent.js"; import {global} from "http://talk.kospo.co.kr:3000/static/js/module/variable.js"; import Common from "http://talk.kospo.co.kr:3000/static/js/utils.js"; // 첨부파일 업로드 기능 function readFileAsDataURL(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = (e) => resolve(e.target.result); reader.onerror = reject; reader.readAsDataURL(file); }); } function loadImage(src) { return new Promise((resolve, reject) => { const img = new Image(); img.onload = () => resolve(img); img.onerror = reject; img.src = src; }); } const attachUpload = async (files) => { checkAllowExt() const chunkSize = 256 * 1024; const key = talkEvent.generateUUID() const workId = localStorage.getItem('workId'); const workNm = localStorage.getItem('workNm'); const talkId = localStorage.getItem(global.tabId); if(talkId === null || workId === null) { global.notifier.alert('통신 오류가 발생 했어요.
새로고침 해주세요.') return } const $files = []; const insDate = Common.dateWithNanos(new Date()); let allFileSize = 0; let isImage = true; // mimtype 조회 이미지가 아닌 다른 파일이 있는지 확인 Array.from(files).forEach((fi) => { if (!(fi.type.includes('image'))) { isImage = false; } }) for (const file of Array.from(files)) { const idx = Array.from(files).indexOf(file); allFileSize += file.size; const att = { onm: file.name, type: file.type, sort: idx, size: file.size, } // 파일 전체가 이미지 일 경우 해당 바이너리 정보 주입 if (isImage) { // 1. 파일을 읽어서 DataURL로 변환 (FileReader 비동기 처리) const dataURL = await readFileAsDataURL(file); // 2. 변환된 DataURL을 이용해 이미지 로드 (Image 비동기 처리) const img = await loadImage(dataURL); // 3. 썸네일 용 dataURL 생성 const blob = await Common.cropImage(img, 105); att.data = blob; } $files.push(att); } /* 첨부파일 업로드 설정 소켓 통신으로 해당 파일의 정보를 보내준다. 정보를 받는 대상자는 첨부파일 업로드 화면을 렌더링 한다. 이미지 같은 경우는 위 바이너리 정보로 썸네일 구성 이미지외 파일 혼합된 경우 파일 다운로드 화면 구성 (서버에서는 해당 내용으로 메시지를 저장한다.) */ talkEvent.attach(global.talkParams({ type: 'INIT', talkId: talkId, workId: workId, workNm: workNm, message: isImage ? "[사진]" : '[파일]', insDate: insDate, talkAttachDtos: $files, attach: { key: key, totalSize: allFileSize } })) setTimeout(attachStart, 300) function checkAllowExt() { const allow = ["jpg", "jpeg", "gif", "png", "bmp", "xls", "xlsx", "csv", "pdf", "hwp", "doc", "docx", "ppt", "pptx", "txt", "zip", "egg", "mp4"] files = Array.from(files).filter((file) => { const fileExt = file.name.toLowerCase().substr(file.name.toLowerCase().lastIndexOf('.') + 1) return allow.join(',').includes(fileExt) }) } function attachStart() { if (files.length !== 0) { Array.from(files).forEach((file, idx) => { const vnm = Common.getAttachVnm(new Date(), global.tabId) console.log(idx, vnm) let offset = 0; /* 각파일 정보를 전송 (서버에서는 메시지 첨부파일을 저장한다.) */ talkEvent.attach(global.talkParams({ type: 'START', talkId: talkId, workId: workId, workNm: workNm, insDate: insDate, attach: { key: key, onm: file.name, vnm: vnm, size: file.size, type: file.type, sort: idx, totalSize: allFileSize } })) readAndSEndChunk(file, idx, offset, vnm) }) } } let progressSize = 0; function readAndSEndChunk(file, idx, offset, vnm) { const reader = new FileReader(); reader.onload = (e) => { const chunk = reader.result; /* 파일의 바이너리 정보를 chunkSize 256kb 로 잘라서 전송한다. 받는 대상자는 해당 첨부파일의 진행률을 돌려받는다. */ talkEvent.attach(global.talkParams({ type: 'PROGRESS', talkId: talkId, workId: workId, workNm: workNm, insDate: insDate, attach: { key: key, onm: file.name, sort: idx, vnm: vnm, totalSize: allFileSize, size: progressSize, data: Array.from(new Uint8Array(chunk)) }, })) progressSize += chunk.byteLength; offset += chunk.byteLength; if (offset < file.size) { Common.sleep(100).then(() => { readAndSEndChunk(file, idx, offset, vnm) }) } else { /* 파일 전송 완료 메시지 */ talkEvent.attach(global.talkParams({ type: 'END', talkId: talkId, workId: workId, workNm: workNm, insDate: insDate, attach: { onm: file.name, vnm: vnm, key: key, }, })) } } const slice = file.slice(offset, offset + chunkSize); reader.readAsArrayBuffer(slice) } } export {attachUpload}