I am creating an audio recording function in my ionic app. I am using media plugin:
$ ionic cordova plugin add cordova-plugin-media
$ npm install --save #ionic-native/media
I can record the audio and play it successfully like this:
constructor(private media: Media,private base64: Base64) {
this.file = this.media.create('file.mp3');
}
record_audio(){
this.file.startRecord();
}
to uplaod to firebase I cannot directly upload the file.mp3, looks like I need to convert it to Blob or base64 first so I tried doing this but it says "MediaObject cannot be assigned to string":
let filePath: string = 'this.file.mp3';
this.base64.encodeFile(filePath).then((base64File: string) => {
console.log(base64File);
}, (err) => {
console.log(err);
});
The objective is to upload the recorded audio file to firebase. to do that I need to convert this file.mp3 to base64.
startRecording() {
console.log("Started Recording");
this.recording = true;
this.file.createFile(this.file.tempDirectory, 'my_file.m4a', true).then(() => {
const audio: MediaObject = this.media.create(this.file.tempDirectory.replace(/^file:\/\//, '') + 'my_file.m4a');
console.log("Audio assigned to constant audio media object");
console.log(audio);
this.audio = audio;
console.log("Audio assigned to this.audio media object");
console.log(this.audio);
this.audio.startRecord();
this.listenToAudioEvents();
window.setTimeout(() => {
if (this.recording) this.stopRecording();
}, 10000);
});
}
listenToAudioEvents() {
this.audio.onStatusUpdate.subscribe(status => {
console.log("Status of this.audio updated");
console.log(status);
if (status == 4 && this.playingAudio) {
console.log("Time to stop playback")
this.stopPlayback();
}
});
}
stopRecording() {
this.audio.stopRecord();
console.log("Stopped Recording");
console.log(this.audio);
this.recording = false;
this.audioReady = true;
this.audio.getDuration();
console.log("Audio Duration: " + this.duration);
console.log("Audio Duration Property: " + this.audio.duration);
}
playAudio() {
console.log("Playing Audio");
this.playingAudio = true;
this.audio.play();
}
stopPlayback() {
console.log("Stopping Playback");
this.playingAudio = false;
this.audio.stop();
}
uploadAudio() {
console.log("Uploading record");
this.storeRecord().subscribe((downloadURL) => {
console.log("Finished storing record");
console.log("Download URL is " + downloadURL);
this.audioURL = downloadURL;
this.audioURLReady = true;
});
}
storeRecord() {
return Observable.create((observer) => {
console.log('Saving record');
const filePath = `${this.file.tempDirectory}my_file.m4a`;
console.log("Path to record is " + filePath);
const readFile: any = window['resolveLocalFileSystemURL'];
return readFile(filePath, (fileEntry) => {
return fileEntry.file((file) => {
const fileReader = new FileReader();
fileReader.onloadend = (result: any) => {
let arrayBuffer = result.target.result;
let blob = new Blob([new Uint8Array(arrayBuffer)], { type: 'audio/m4a' });
console.log("Blob is ");
console.log(blob);
var storageRef = firebase.storage().ref('content/' + this.firebase.user.uid + '/my-file.m4a');
console.log("Storage reference is " + storageRef);
var uploadTask = storageRef.put(blob);
console.log('Upload started:');
uploadTask.on('state_changed', (snapshot) => {
console.log("state changed");
let percent = uploadTask.snapshot.bytesTransferred / uploadTask.snapshot.totalBytes * 100;
console.log(percent + "% done");
}, (e) => {
console.error(e);
observer.error(e);
}, () => {
var downloadURL = uploadTask.snapshot.downloadURL;
console.log('Storage Download URL:' + downloadURL);
observer.next(downloadURL);
});
};
fileReader.onerror = (e: any) => {
console.error(e);
observer.error(e);
};
fileReader.readAsArrayBuffer(file);
}, (e) => {
console.error(e);
observer.error(e);
});
}, (e) => {
console.error(e);
observer.error(e);
});
});
}
downloadAudio() {
console.log("Downloading Audio")
const fileTransfer: FileTransferObject = this.fileTransfer.create();
var destPath = (cordova.file.externalDataDirectory || cordova.file.dataDirectory) + "my_file.m4a"
fileTransfer.download(this.audioURL, destPath, ).then((entry) => {
let rawAudioURI = entry.toURL();
this.audioURI = rawAudioURI.replace(/^file:\/\//, '/private');
this.audioURIReady = true;
console.log("Audio URI: " + this.audioURI);
}, (error) => {
console.error(error);
});
}
playAudioURI() {
console.log("Playing AudioURI");
let downloadedAudio: MediaObject = this.media.create(this.audioURI);
console.log("Downloaded audio: " + downloadedAudio);
downloadedAudio.play();
}
}
Related
I'm getting memory leak warning in the console for my Electron app, i don't know what to do to increase limit. It's causing it everytime i run the app.
Does the error is linked to uiohook? Or did i miss something here?
How can i use emitter.setMaxListeners() in my case? I have no clue of how to fix it, and hwo to increase the memory leak.
[3452:1014/104426.056:ERROR:service_worker_storage.cc(1904)] Failed to delete the database: Database IO error
(node:21792) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 terminate-timer listeners added to [EventEmitter]. Use emitter.setMaxListeners() to increase limit
(Use `electron --trace-warnings ...` to show where the warning was created)
(node:21792) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 set-activity listeners added to [EventEmitter]. Use emitter.setMaxListeners() to increase limit
Electron
const electron = require('electron');
const BrowserWindow = electron.BrowserWindow;
const dialog = electron.dialog;
const desktopCapturer = electron.desktopCapturer;
const idle = electron.powerMonitor;
const remote = electron.remote;
const notification = electron.Notification;
const globalShortcut = electron.globalShortcut;
const screen = electron.screen;
const ipcMain = electron.ipcMain;
const app = electron.app;
const isDev = require('electron-is-dev');
const path = require('path');
const activeWindows = require('electron-active-window');
const activeWindowPage = require('active-win');
const BMParser = require('bookmark-parser');
const axios = require('axios');
const uiohook = require('uiohook-napi');
const { autoUpdater } = require("electron-updater");
const debug = require('debug')('Franz:ipcApi:autoUpdate');
const dns = require("dns");
const activity = { is_mouse: 0, is_keyboard: 0 };
const headers = {
'Content-Type': 'application/json;charset=UTF-8',
"Access-Control-Allow-Headers": "*",
"Access-Control-Allow-Origin": "*",
"Accept": "application/json"
}
const sessionUser = null;
let updateInterval = null;
app.disableHardwareAcceleration();
electron.powerSaveBlocker.start('prevent-app-suspension');
//electron.commandLine.appendSwitch ("disable-http-cache");
// Change App Name on Windows
if (process.platform === 'win32')
{
app.setAppUserModelId('Rubii');
}
let apiEndpoint = "http://creaz:81/xorix/api"; // Brian
let frameUrl = 'http://localhost:3000'; // Brian
//if (isDev) { // or if(process.env.NODE_ENV)
// apiEndpoint = "http://creaz:81/xorix/api";
// frameUrl = 'http://localhost:3000';
//}
var internetAvailable = require("internet-available");
let isConnected = false;
let counterInternet = 0;
let allowSendInternetNotification = 1;
async function liveInternetCheck() {
var userSessionCheck = await getSessionUser();
// Most easy way
internetAvailable({
domainName: "rubii.com",
// Provide maximum execution time for the verification
timeout: 10000,
// If it tries 10 times and it fails, then it will throw no internet
retries: 10
}).then(() => {
// Available Internet
isConnected = true;
counterInternet++;
if(counterInternet > 3 && allowSendInternetNotification == 0) {
allowSendInternetNotification = 1;
}
}).catch(() => {
// Not available internet
isConnected = false;
if(isConnected == false && userSessionCheck && allowSendInternetNotification == 1) {
var message = 'Your internet has been disconnected! Please login again';
new notification({ title: 'Ooops', body: message }).show();
// Logout the user in the other end
win.webContents.send("terminate-timer", "hello");
allowSendInternetNotification = 0;
counterInternet = 0;
}
});
}
autoUpdater.on("update-available", (_event, releaseNotes, releaseName) => {
const dialogOpts = {
type: 'info',
buttons: ['Ok'],
title: 'Update Available',
message: process.platform === 'win32' ? releaseNotes : releaseName,
detail: 'A new version download started. The app will be restarted to install the update.'
};
dialog.showMessageBox(dialogOpts);
updateInterval = null;
});
autoUpdater.on("update-downloaded", (_event, releaseNotes, releaseName) => {
const dialogOpts = {
type: 'info',
buttons: ['Restart'],
title: 'Application Update',
message: process.platform === 'win32' ? releaseNotes : releaseName,
detail: 'A new version has been downloaded. Restart the application to apply the updates.'
};
dialog.showMessageBox(dialogOpts).then((returnValue) => {
if (returnValue.response === 0) autoUpdater.quitAndInstall()
});
});
function checkUpdate() {
updateInterval = setInterval(() => autoUpdater.checkForUpdates(), 600000);
}
let win;
ipcMain.on('close-me', (evt, arg) => {
new notification({ title: 'Ooops', body: 'We hope to see you again!' }).show();
app.quit()
});
function determineScreenShotSize() {
var screenSize = screen.getPrimaryDisplay().workAreaSize
return {
width: screenSize.width,
height: screenSize.height
}
}
async function takeScreenshot() {
var user = await getSessionUser();
var timer = await getSessionTimer();
if (user && timer) {
if (timer.timer == 1) {
//console.log('Gathering screens...');
//console.log(app.getPath('pictures'));
const thumbSize = determineScreenShotSize();
const workaroundTimestamp = Date.now();
const options = {
types: ['screen'],
thumbnailSize: { ...thumbSize, workaroundTimestamp }
};
desktopCapturer.getSources(options).then((sources) => {
console.log('Sources received:' + sources.length);
sources.forEach(function (source) {
const sourceName = source.name.toLowerCase();
//console.log(sourceName);
if (['entire screen', 'screen 1'].includes(sourceName)) {
var the_screenshot = source.thumbnail.toPNG();
var data = {
user_id: user.id,
company_id: timer.company_id,
image: the_screenshot.toString('base64')
}
axios.post(apiEndpoint + "/desktop/save_screenshots", data, {
headers: headers
})
.then((response) => {
// console.log(response);
})
.catch((error) => {
//console.log(error);
})
}
})
}).catch(console.error);
}
}
}
function saveSoftware() {
(async () => {
var options = [];
var software = await activeWindowPage();
var user = await getSessionUser();
var timer = await getSessionTimer();
if (user && timer) {
if (timer.timer == 1) {
software.user = user;
software.timer = timer;
axios.post(apiEndpoint + "/desktop/save_app", software, {
headers: headers
})
.then((response) => {
//console.log(response);
})
.catch((error) => {
//console.log(error);
})
}
}
})();
}
function getSessionUser() {
return win.webContents.executeJavaScript('sessionStorage.getItem("user");', true)
.then(result => {
if (result) {
return JSON.parse(result);
}
});
}
function getSessionTimer() {
return win.webContents.executeJavaScript('sessionStorage.getItem("timer");', true)
.then(result => {
if (result) {
return JSON.parse(result);
}
});
}
async function generateActivity() {
win.webContents.send("set-activity", activity);
// We reset after we send it
activity.is_mouse = activity.is_keyboard = 0;
}
function secondsToHms(d) {
d = Number(d);
var h = Math.floor(d / 3600);
var m = Math.floor(d % 3600 / 60);
var s = Math.floor(d % 3600 % 60);
var hDisplay = h > 0 ? h + (h == 1 ? " hour, " : " hours, ") : "";
var mDisplay = m > 0 ? m + (m == 1 ? " minute, " : " minutes, ") : "";
var sDisplay = s > 0 ? s + (s == 1 ? " second" : " seconds") : "";
return hDisplay + mDisplay + sDisplay;
}
function createWindow() {
win = new BrowserWindow({
width: 1200,
height: 900,
frame: true,
webPreferences: {
webSecurity: false,
nodeIntegration: true,
enableRemoteModule: true,
contextIsolation: false,
backgroundThrottling: false
}
});
//win.loadURL('https://desktop.rubii.com');
win.loadURL(frameUrl, { "extraHeaders": "pragma: no-cache\n" });
// http://localhost:3000
//win.webContents.openDevTools();
//win.removeMenu(); // Brian
// or set the Menu to null
//win.setMenu(null); // Brian
// Reload cache
win.webContents.reloadIgnoringCache();
// Keyboard activity
uiohook.uIOhook.on('keydown', (e) => {
//console.log('Keyboard!')
activity.is_keyboard = 1;
})
// Mouse activity
uiohook.uIOhook.on('mousemove', (e) => {
//console.log('mouse');
activity.is_mouse = 1;
})
// Start listener for keyboard and mouse
uiohook.uIOhook.start();
win.on('close', function () {
win = null;
})
}
app.whenReady().then(createWindow).then(checkUpdate);
app.on('window-all-closed', function () {
app.quit();
});
app.on('activate', function () {
if (win == null) {
createWindow();
}
})
setInterval(takeScreenshot, 10 * 60 * 1000); // 10 minutes
setInterval(saveSoftware, 5 * 1000); // 5 seconds
setInterval(generateActivity, 1 * 1000);
setInterval(function() { liveInternetCheck(); }, 10 * 1000); // 10 seconds
Render
ipcRenderer.on("terminate-timer", function (event, data) {
// Logout if there is no internet connection
handleLogout();
});
// Set activity if there were any keyboard, mouse
ipcRenderer.on("set-activity", function (event, data) {
// If the timer is on
if(timer) {
setActivity(data);
}
});
I need to get localMediaStream in one effect, while it is set in another effect. Please tell me why in this context it is always null (if you do not set it in the same effect), but in this case I have a duplicate userMedia. Consequences - the camera does not go out when I call track.stop(). Based on this package
const peerConnections = useRef({});
const localMediaStream = useRef(null);
const peerMediaElements = useRef({
[LOCAL_VIDEO]: null,
});
useEffect(() => {
async function handleNewPeer({peerID, createOffer}) {
if (peerID in peerConnections.current) {
return console.warn(`Already connected to peer ${peerID}`);
}
peerConnections.current[peerID] = new RTCPeerConnection({
iceServers: freeice(),
});
peerConnections.current[peerID].onicecandidate = event => {
if (event.candidate) {
socket.emit(ACTIONS.RELAY_ICE, {
peerID,
iceCandidate: event.candidate,
});
}
}
let tracksNumber = 0;
peerConnections.current[peerID].ontrack = ({streams: [remoteStream]}) => {
tracksNumber++
if (tracksNumber === 2) { // video & audio tracks received
tracksNumber = 0;
addNewClient(peerID, () => {
if (peerMediaElements.current[peerID]) {
peerMediaElements.current[peerID].srcObject = remoteStream;
} else {
// FIX LONG RENDER IN CASE OF MANY CLIENTS
let settled = false;
const interval = setInterval(() => {
if (peerMediaElements.current[peerID]) {
peerMediaElements.current[peerID].srcObject = remoteStream;
settled = true;
}
if (settled) {
clearInterval(interval);
}
}, 1000);
}
});
}
}
/*localMediaStream.current = await navigator.mediaDevices.getUserMedia({
audio: audio,
video: video
})*/
localMediaStream.current.getTracks().forEach(track => { // localMediaStream null
peerConnections.current[peerID].addTrack(track, localMediaStream.current);
});
if (createOffer) {
const offer = await peerConnections.current[peerID].createOffer();
await peerConnections.current[peerID].setLocalDescription(offer);
socket.emit(ACTIONS.RELAY_SDP, {
peerID,
sessionDescription: offer,
});
}
}
socket.on(ACTIONS.ADD_PEER, handleNewPeer);
return () => {
socket.off(ACTIONS.ADD_PEER);
}
}, []);
// The installation, everything is as in the source, it did not work until I added the crutch above, but when it came to stopping the video stream, a bug appeared with the camera always on
useEffect(() => {
async function startCapture() {
console.log('start capture');
localMediaStream.current = await navigator.mediaDevices.getUserMedia({
audio: audio,
video: video
}).catch(console.log);
addNewClient(LOCAL_VIDEO, () => {
const localVideoElement = peerMediaElements.current[LOCAL_VIDEO];
if (localVideoElement) {
localVideoElement.volume = 0;
localVideoElement.srcObject = localMediaStream.current;
}
});
}
startCapture().then((data) => socket.emit(ACTIONS.JOIN, {room: roomID})).catch((e) => console.error(e)).finally(() => console.log('finally'));
console.log(roomID);
return () => {
localMediaStream.current.getTracks().forEach(track => track.stop());
socket.emit(ACTIONS.LEAVE);
};
}, [roomID]);
Thanks you very much.
Currently I am using below code to read xlsx file in react when my system having office (excel) installed. But the same is throwing error on other machine where office(excel) is not installed.
Error is at this point console.log(this.state.file.type)
Here is console.log :
lastModified: 1595606065652
lastModifiedDate: Fri Jul 24 2020 15:54:25 GMT+0000 (Greenwich Mean Time) {}
name: "ExamAnswer.xlsx"
size: 14266
type: "" // here type is null
webkitRelativePath: ""
__proto__: File
So, could you please tell how to read file type
handleExamInputFile() {
const reader = new FileReader();
const rABS = !!reader.readAsBinaryString;
console.log("file", this.state.file);
console.log(this.state.file.type);
let fileType =
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
if (this.state.file.size > 0) {
console.log(this.state.file.size);
if (this.state.file.type === fileType) {
if (rABS) {
reader.readAsBinaryString(this.state.file);
} else {
reader.readAsArrayBuffer(this.state.file);
}
reader.onload = (e) => {
const bstr = e.target.result;
const wb = XLSX.read(bstr, {
type: rABS ? "binary" : "array",
bookVBA: true,
});
const wsname = wb.SheetNames[0];
const ws = wb.Sheets[wsname];
const data = XLSX.utils.sheet_to_json(ws, {
raw: true,
});
const header = [];
const columnCount = XLSX.utils.decode_range(ws["!ref"]).e.c + 1;
for (let i = 0; i < columnCount; ++i) {
if (ws[`${XLSX.utils.encode_col(i)}1`] != undefined) {
header[i] = ws[`${XLSX.utils.encode_col(i)}1`].v;
}
}
console.log(header);
let headerMustHave = ["Exam Name", "EId", "Name"];
// let ifFound = header.every(function (val) {
// console.log(val);
// return headerMustHave.indexOf(val) !== -1;
// });
let checker = (arr, target) => target.every((v) => arr.includes(v));
let ifFound = checker(header, headerMustHave);
console.log(ifFound);
if (ifFound === true) {
for (var i = 0; i < data.length; i++) {
let excel_date = this.ExcelDateToJSDate(data[i]["Report Date"]);
data[i]["Report Date"] = excel_date;
}
this.setState({
data: data,
result: JSON.stringify(data),
cols: make_cols(ws["!ref"]),
});
const exceldata = JSON.parse(this.state.result);
const excelList = exceldata.map((data) => data);
const excel = { data: excelList };
const url = "http://localhost:8000/upload";
const config = {
headers: {
Accept: "*",
"Content-Type": "application/json",
"Allow-Control-Allow-Origin": "*",
// Accept: "application/json",
},
};
return post(url, excel, config).then((response) => {
toast.success(response.data, {
position: toast.POSITION.TOP_CENTER,
});
document.getElementById("file1").value = "";
this.setState({ file: "" });
});
} else {
toast.error("Some columns are not presented in uploaded file.", {
position: toast.POSITION.TOP_CENTER,
autoClose: 3000,
});
this.setState({ file: "" });
}
};
} else {
toast.error(
"This file format is not supported. Please select an .xlsx file.",
{
position: toast.POSITION.TOP_CENTER,
autoClose: 3000,
}
);
this.setState({ file: "" });
}
} else {
toast.error("Please select .xlsx file to upload.", {
position: toast.POSITION.TOP_CENTER,
autoClose: 3000,
});
this.setState({ file: "" });
}
}
Alternatively, is it possible to read the same xlsx file through python on above type machine?
TIA
Since this is React.js code, it's running client-side, in a browser.
Your problem with type being empty is that not all machines and browsers know how to map the file type .xlsx to the MIME type 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'; those with Excel, or maybe LibreOffice installed, certainly might, but even that's not a given. Whether or not Excel is actually installed has no bearing on whether the XLSX.js library you're using can actually parse the file (since the browser doesn't know about Excel).
As I mentioned in the comments, you can simply optionally look at the extension of the file uploaded – and even that's not necessary; you could just attempt to pass the file to XLSX; it would fail to parse files that are not XLSX documents anyway.
Here's a refactoring of your code to move to promise-based asynchronicity, moving the actual processing code out of the React component, so it's more easily testable.
In addition, you seemed to be doing some strange to-JSON-from-JSON coercion before posting the data; I got rid of that (and all of the Toast error handling for a more minimal example)...
function ExcelDateToJSDate(x) {
return x; // TODO: implement
}
function processWorkbook(wb) {
const wsname = wb.SheetNames[0];
const ws = wb.Sheets[wsname];
const data = XLSX.utils.sheet_to_json(ws, {
raw: true,
});
const header = [];
const columnCount = XLSX.utils.decode_range(ws["!ref"]).e.c + 1;
for (let i = 0; i < columnCount; ++i) {
const col = `${XLSX.utils.encode_col(i)}1`;
if (ws[col] != undefined) {
header[i] = ws[col].v;
}
}
console.log(header);
const headerMustHave = ["Exam Name", "EId", "Name"];
const checker = (arr, target) => target.every((v) => arr.includes(v));
let ifFound = checker(header, headerMustHave);
if (ifFound === true) {
for (var i = 0; i < data.length; i++) {
let excel_date = ExcelDateToJSDate(data[i]["Report Date"]);
data[i]["Report Date"] = excel_date;
}
}
return { ws, data };
}
/**
* Read a DOM File into a binary string or array buffer; returns a Promise.
*/
function readFile(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
let type;
if (reader.readAsBinaryString) {
reader.readAsBinaryString(file);
type = "binaryString";
} else {
reader.readAsArrayBuffer(file);
type = "arrayBuffer";
}
reader.onload = (event) => {
resolve({ type, data: event.target.result });
};
reader.onerror = (event) => reject(event);
});
}
async function processExamInputFile(file) {
if (!file) {
throw new Error("No file selected.");
}
if (
!(
file.type === "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ||
file.name.endsWith(".xlsx")
)
) {
throw new Error("Invalid file type or extension.");
}
const { data, type } = await readFile(file);
const wb = XLSX.read(data, {
type: type === "binaryString" ? "binary" : "array",
bookVBA: true,
});
return processWorkbook(wb);
}
class X {
async handleExamInputFile() {
try {
const { ws, data } = await processExamInputFile(this.state.file);
this.setState({
data: data,
result: JSON.stringify(data),
cols: make_cols(ws["!ref"]),
});
await post(
"http://localhost:8000/upload",
{ data },
{
headers: {
Accept: "*",
"Content-Type": "application/json",
"Allow-Control-Allow-Origin": "*",
},
},
);
} catch (err) {
console.log(err); // TODO: improve
}
}
}
I got a little problem with synchronous/asynchronous system in the function "Array.foreach".
I don't know how to force my code to wait its end.
I tried to use await/async system but my code did not wait the code in "async responseDB =>".
This is my class:
...
let responsesDTO = [];
await Array.prototype.forEach.call(await searchResponsesByQuestionAndUserId(questions[cpt].idquestion, idUser), async responseDB => {
if(responseDB !== undefined){
const responseDTO = {
response_id:0,
response_text:"",
response_type:""
}
const responseEntity = await searchResponseByResponseId(responseDB.response_id);
responseDTO.response_id = responseDB.response_id;
responseDTO.response_text= responseEntity.text;
responseDTO.response_type= responseDB.type;
responsesDTO.push(responseDTO);
}
});
questionResponse.responses=responsesDTO;
questionResponses[cpt]=questionResponse;
}
Could you help me please? Thanks in advance.
I had to mock your async functions. However, the relevant part is to use for..of instead of forEach
async function searchResponsesByQuestionAndUserId() {
let responsesDB = [];
for (let i = 0; i < 10; i++) {
responsesDB.push({
response_id: parseInt(1000 * Math.random(), 10),
type: 'whatever ' + i
});
}
return new Promise((res) => {
window.setTimeout(() => {
res(responsesDB);
}, 1500);
});
}
async function searchResponseByResponseId(response_id) {
return new Promise((res) => {
window.setTimeout(() => {
res({
text: 'text for response ' + response_id
});
}, 300);
});
}
async function getResponsesDTO() {
let responsesDTO = [],
responsesDB = await searchResponsesByQuestionAndUserId();
for (let responseDB of responsesDB) {
if (responseDB === undefined) {
continue;
}
let responseDTO = {
response_id: 0,
response_text: "",
response_type: ""
},
responseEntity = await searchResponseByResponseId(responseDB.response_id);
responseDTO.response_id = responseDB.response_id;
responseDTO.response_text = responseEntity.text;
responseDTO.response_type = responseDB.type;
responsesDTO.push(responseDTO);
console.log({responseDTO});
}
return responsesDTO;
}
getResponsesDTO().then(responsesDTO => {
console.log(responsesDTO);
});
I'm developing pdf down load function with react/typescript.
(using pdfmake)
My bundle.js file size is too large.(8MB over)
So, I want to reduce this.
The main cause is the bundle.js contains vfs_fonts.js.
this file size is over 17MB.
I've tried fetching font file dynamically instead of bundling the file, referring to this page.
https://github.com/bpampuch/pdfmake/issues/1374
But it didn't work.
this is a part of my code
import * as pdfMake from 'pdfmake/build/pdfmake';
function fetchFont (fontURL: string) {
return new Promise((resolve, reject) => {
const request = new XMLHttpRequest();
request.open('GET', fontURL, true);
request.responseType = 'arraybuffer';
request.onload = function (e: any) {
resolve(request.response);
};
request.onerror = reject;
request.send();
});
}
interface Dictionary {
[index: string]: string;
}
class PdfFontLoader {
fontDefs: Dictionary[];
vfs: {};
loaded: boolean;
constructor () {
this.fontDefs = [];
this.vfs = {};
}
addFont (fontDef: Dictionary) {
this.fontDefs.push(fontDef);
}
load() {
return new Promise((resolve, reject) => {
if (this.loaded) {
resolve();
} else {
const fetches = this.fontDefs.map(fontDef => {
return fetchFont(fontDef.URL).then((data) => {
console.log('fetched ' + JSON.stringify(data));
this.vfs[fontDef.name] = data;
}).catch(e => {
console.log('error ' + e);
});
});
Promise.all(fetches).then(() => {
this.loaded = true;
resolve();
}).catch(reject);
}
});
}
}
const pdf = pdfMake;
pdf.vfs = fontLoader.vfs;
fontLoader.addFont({URL: 'GenShinGothic-Normal.ttf', name: 'GenShinGothic-Normal.ttf'});
fontLoader.addFont({URL: 'GenShinGothic-Bold.ttf', name: 'GenShinGothic-Bold.ttf'});
fontLoader.load().then(res => {
console.log('load finished');
pdf.fonts = {
GenShinGothic: {
normal: 'GenShinGothic-Normal.ttf',
bold: 'GenShinGothic-Bold.ttf'
}
};
console.log("vfs is " + JSON.stringify(pdf.vfs));
console.log
load finished
fetched {}
vfs is {"GenShinGothic-Normal.ttf":{},"GenShinGothic-Bold.ttf":{}}
if pdf generating...
Error: unknown font format
Can you help me?
====additional info=====
the font file(ttf) are deployed in same directory with bundle.js...