not playing audio from buffer stored in the database - blob

I've spent 2 days with this thing and couldn't find a solution but seems like im getting closer. The goal is to record audio in the browser and store in the the database and get it whenever i need it.
I encoded the audio to base64 and sent it to the server stored as binary in the mongodb, created a get route in which i find the audio by id and send the buffer via res.send() along with the content type set to audio/webm (default mime type)
but the thing is I'm getting this blank video, seems like it's not knowing how to decode it or something. There might be something wrong with the content type.
navigator.mediaDevices.getUserMedia({ audio: true, video: false })
.then((mediaRecorderObj) => {
let mediaRecorder = new MediaRecorder(mediaRecorderObj, { mimType: 'audio/webm;base64' })
const m = mediaRecorder;
let chunk = []
startBtn.addEventListener('click', () => {
mediaRecorder.start()
console.log('started recording..');
})
endBtn.addEventListener('click', () => {
mediaRecorder.stop()
console.log('just stopped recording');
})
//-----When Data Is Available
mediaRecorder.ondataavailable = (e) => {
chunk.push(e.data);
}
//--------When finished adding it to chunk
mediaRecorder.onstop = () => {
const blob = new Blob(chunk, { 'type': 'audio/webm' })
chunk = []
const reader = new FileReader()
reader.readAsDataURL(blob)
reader.onloadend = async () => {
const buffer = reader.result
const bodyObj = {
voice: buffer
}
await fetch('http://localhost:3000/upload-spoken-bio', {
method: 'post',
body: JSON.stringify(bodyObj),
headers: { 'Content-Type': 'application/json' }
})
}
}
})
and this is the server side
//----------Upload
spokenBio.post('/upload-spoken-bio', async (req, res) => {
const buffer = req.body
try {
const newBuffer = new SpokenCon(buffer)
await newBuffer.save()
}
catch (err) {
console.log(err.message);
}
})
//----------Retrieve
spokenBio.get('/get-spoken-bio/:id', async (req, res) => {
const id = req.params.id
try {
const field = await SpokenCon.findById(id)
const binary = field.voice
res.set({ 'Content-Type': 'audio/webm' })
res.send(binary)
}
catch (err) {
console.log(err.message);
}
})

Related

Struggling to correctly make use of returned values from functions that are being called Asynchronously by Axios

I have an Express server which serves as an API Request forwarding tool (i.e my client calls the express server, and the express server forwards that call to another API).
The way this server is supposed to work is that there is a single entry point which makes a request, and then based on the response makes further API requests and returns a result based on the combo of API request responses.
To be clearer, the main logic is as follows:
Single entry point, which makes an async axios call to get an ID value
Within this function, we call an async function, getPartnerDetails (passing that ID as the parameter)
getPartnerDetailscalls a 3rd async function, '''getRawJson''' which is supposed to return the final required result, passing it back to '''getPartnerDetails''' which then passes it to the main entry point.
Whats going wrong is that the results are being recieved but are not being pass back correctly. The console logs within the '''.then(()=>{})''' of my async functions are coming back as '''undefined'''.
Code below:
app.post('/checkuser', async (req, res, next) => {
const { man, bfn, bln, bsn, bc, bs, bz, bco } = req.body;
const bodyContent = {
man: man,
bfn: bfn,
bln: bln,
bsn: bsn,
bc: bc,
bs: bs,
bz: bz,
bco: bco,
profile: 'DEFAULT',
};
try {
await axios
.post('https://host.com/im/account/consumer', bodyContent, { headers })
.then((response) => {
const addressValidResult = response.data.score.etr.filter(
(result) => result.test === '19:2'
)[0];
// console.log(res.json(result.details));
const requestId = response.data.mtid;
const currentValidAddress = getPartnerDetails(requestId).then(
(result) => {
console.log('this is currentvalidaddress ' + result);
res.json({
validationMessage: addressValidResult,
currentValidAddress: result,
});
}
);
})
.catch((err) => next(err));
} catch {}
});
async function getPartnerDetails(appId) {
let config = {
headers: {
'Content-Type': 'application/json',
Authorization: 'Basic M2QzMsdfsslkfglkdjfglkdjflkgd',
},
params: {
partner: 19,
},
};
const res = await axios
.get(
`https://host.com/im/account/consumer/${appId}/partner/requests`,
config
)
.then((response) => {
const requestId = response.data.requests[0].request_id;
console.log('this is request id ' + JSON.stringify(requestId));
const raw = getRawJson(appId, requestId).then((result) => {
console.log('this is getRawJson result ' + JSON.stringify(result));
return JSON.stringify(result);
});
// https://host.com/im/account/consumer/:appId/partner/request/:requestId
})
.catch((err) => console.log('err2' + err));
}
async function getRawJson(appId, requestId) {
const res = await axios
.get(`host.com/im/account/consumer/${appId}/partner/request/${requestId}`, {
headers,
})
.then((response) => {
console.log('this is response ' + JSON.stringify(response.data));
return JSON.stringify(response.data);
})
.catch((err) => console.log('err1 ' + err));
}
It might have something to do with how I'm using async and await, I'm new to it so I'm hoping that I'll learn a thing or 2 more about it by solving this project.
I'm also aware that maybe I should split the entry point out into 3 different entry points, and have the client manage the chaining of the requests and responses instead.
Thanks!!
Probably an error due to incorrect async await usage.
Try to change your code like this:
app.post('/checkuser', async (req, res, next) => {
const { man, bfn, bln, bsn, bc, bs, bz, bco } = req.body;
const bodyContent = {
man: man,
bfn: bfn,
bln: bln,
bsn: bsn,
bc: bc,
bs: bs,
bz: bz,
bco: bco,
profile: 'DEFAULT',
};
try {
const { data } = await axios.post(
'https://host.com/im/account/consumer',
bodyContent,
{ headers }
);
const addressValidResult = data.score.etr.filter(
(result) => result.test === '19:2'
)[0];
const requestId = data.mtid;
const currentValidAddress = await getPartnerDetails(requestId);
console.log('this is currentvalidaddress ' + currentValidAddress);
res.json({
validationMessage: addressValidResult,
currentValidAddress: currentValidAddress,
});
} catch (err) {
next(err);
}
});
async function getPartnerDetails(appId) {
let config = {
headers: {
'Content-Type': 'application/json',
Authorization: 'Basic M2QzMsdfsslkfglkdjfglkdjflkgd',
},
params: {
partner: 19,
},
};
const { data } = await axios.get(
`https://host.com/im/account/consumer/${appId}/partner/requests`,
config
);
const requestId = data.requests[0].request_id;
console.log('this is request id ' + JSON.stringify(requestId));
return getRawJson(appId, requestId);
}
function getRawJson(appId, requestId) {
return axios
.get(`host.com/im/account/consumer/${appId}/partner/request/${requestId}`, {
headers,
})
}

Problem to generate pdf from a blob in an expo app using FileSystem

I get a blob and I treat it like this:
const file = response.data;
var blob = new Blob([file], {
type: 'application/pdf',
});
const fileReaderInstance = new FileReader();
fileReaderInstance.readAsDataURL(blob);
fileReaderInstance.onload = async () => {
const fileUri = `${FileSystem.documentDirectory}file.pdf`;
await FileSystem.writeAsStringAsync(
fileUri,
fileReaderInstance.result.split(',')[1],
{
encoding: FileSystem.EncodingType.Base64,
}
);
console.log(fileUri);
Sharing.shareAsync(fileUri);
};
however when I generate and share the file, I can't access it and if I get its URI and search on the web it returns:
i solved my problem in this way:
This is a func who get other data to request, do the request (generate PDF()) and treat the data and generate by received blob the buffer on (fileReaderInstance.result) who is shared in Sharing.shareAsync()
const generatePDF = async () => {
setAnimating(true);
const companyReponse = await CompanyService.getCompany();
const peopleResponse = await PeopleService.getPerson(sale.customerId);
const company = companyReponse.response.company;
const people = peopleResponse.response;
const quote = false;
const json = await SaleService.generatePDF({
sale,
company,
people,
quote,
});
if (json && json.success) {
try {
const fileReaderInstance = new FileReader();
fileReaderInstance.readAsDataURL(json.data);
fileReaderInstance.onload = async () => {
const base64data = fileReaderInstance.result.split(',');
const pdfBuffer = base64data[1];
const path = `${FileSystem.documentDirectory}/${sale._id}.pdf`;
await FileSystem.writeAsStringAsync(`${path}`, pdfBuffer, {
encoding: FileSystem.EncodingType.Base64,
});
await Sharing.shareAsync(path, { mimeType: 'application/pdf' });
};
} catch (error) {
Alert.alert('Erro ao gerar o PDF', error.message);
}
}
setAnimating(false);
}
This is the func in SaleServicegeneratePDF who do the request to api and pass the parameters that return a blob of pdf using axios:
generatePDF: async ({ sale, company, people, quote }) => {
const token = await AsyncStorage.getItem('token');
const body = { sale, company, people, quote };
try {
const response = await axios(`${BASE_API}/generate-sale-pdf`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: token,
},
responseType: 'blob',
data: body,
});
return {
success: true,
data: response.data,
};
} catch (err) {
return err.error;
}
},
I have solved this problem by passing the blob string to WriteAsStringAsync method of FileSystem library from expo.
const blobDat = data.data[0].data; //blob data coming from an API call
const fileUri = FileSystem.documentDirectory + `testt.pdf`; //Directory Link of the file to be saved
await FileSystem.writeAsStringAsync(fileUri, blobDat, {
encoding: FileSystem.EncodingType.UTF8,
}) //This step writes the blob string to the pdf fileURI
await IntentLauncher.startActivityAsync("android.intent.action.VIEW", {
data: fileUri,
flags: 1,
type: "application/pdf",
});
//prompts user with available application to open the above created pdf.

Login state management and cache for React Native with Apollo client

I'm learning graphQL with React native and using the apollo client. I'm experimenting with some code that has a simple login screen and I'm trying to check my understanding of the cache. My graphql client code is below. By turning on the debug for the persistCache I see the line when use CMD + R to reload an iOS simulator with expo. This suggests the cache is working.
[apollo-cache-persist] Restored cache of size 29
My question is what else is needed to complete the overall process of not needing to login again? I assume I need to maintain state on whether it's logged in and not show the login screen. I'm after some examples which show this.
const retryLink = new RetryLink({
delay: {
initial: 300,
max: 5000,
jitter: true
},
attempts: {
max: Infinity,
retryIf: (error = {}) => {
return error.statusCode > 299 || !error.statusCode
}
}
});
const formatObject = data => _.isObject(data) ? JSON.stringify(data) : data;
const formatGraphQLError = err =>
`Message: ${err.message}, Location: ${formatObject(
err.locations
)}`;
const errorLink = onError(({ networkError = "", graphQLErrors = [] } = {}) => {
if (networkError)
console.log(`[Network Error]: ${networkError}`);
if (graphQLErrors.length)
graphQLErrors.map(formatGraphQLError).forEach(err => console.log(`[GraphQL Error]: ${err}`))
});
const authLink = setContext(async (_, { headers }) => {
const token = await Auth.token();
if (token)
return {
headers: {
...headers,
authorization: `Bearer ${token}`
}
};
else return { headers };
});
const httpLink = new HttpLink({
uri: Config.apiUrl
});
const cache = new InMemoryCache();
// Set up cache persistence.
persistCache({
cache,
storage: AsyncStorage,
trigger: 'background',
debug: true
});
const logLink = new ApolloLink((operation, forward) => {
console.log("Running GraphQL query or mutation");
return forward(operation);
});
//--
//-- Combine the links in your required order.
//--
let _notifications = 42;
const client = new ApolloClient({
resolvers: {
Query: {
permission: async (_, { type }) => await Permissions.askAsync(type),
token: async () => await Auth.token(),
notifications: () => _notifications
},
Mutation: {
login: async (_, { email, password }) => {
return await Auth.login(email, password)
},
updateNotifications: async (_, { notifications }) => _notifications = notifications
}
},
link: ApolloLink.from([
logLink,
retryLink,
errorLink,
authLink,
httpLink
]),
cache
});
export default client;

Cannot upload image to s3 using serverless framework but it work in offline (buffer issue)

I'm trying to deploy a lambda function allowing me to upload a picture to S3.
The lambda works well in offline but when I'm deploy it to AWS, the function doesn't work.
The first error I encountered was this one :
ERROR (node:7) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
So, I followed the recommendation to use Buffer.from() method instead. But it doesn't work too. The lambda run until the timeout.
Can someone tell me where I was wrong or suggest me another solution ?
Below my lambda function :
const AWS = require("aws-sdk");
const Busboy = require("busboy");
const uuidv4 = require("uuid/v4");
require("dotenv").config();
AWS.config.update({
accessKeyId: process.env.ACCESS_KEY_ID,
secretAccessKey: process.env.SECRET_ACCESS_KEY,
subregion: process.env.SUB_REGION
});
const s3 = new AWS.S3();
const getContentType = event => {
// see the second block of codes
};
const parser = event => {
// see the third block of codes
};
module.exports.main = (event, context, callback) => {
context.callbackWaitsForEmptyEventLoop = false;
const uuid = uuidv4();
const uploadFile = async (image, uuid) =>
new Promise(() => {
// const bitmap = new Buffer(image, "base64"); // <====== deprecated
const bitmap = Buffer.from(image, "base64"); // <======== problem here
const params = {
Bucket: "my_bucket",
Key: `${uuid}.jpeg`,
ACL: "public-read",
Body: bitmap,
ContentType: "image/jpeg"
};
s3.putObject(params, function(err, data) {
if (err) {
return callback(null, "ERROR");
}
return callback(null, "SUCCESS");
});
});
parser(event).then(() => {
uploadFile(event.body.file, uuid);
});
};
getContentType() :
const getContentType = event => {
const contentType = event.headers["content-type"];
if (!contentType) {
return event.headers["Content-Type"];
}
return contentType;
};
parser()
const parser = event =>
new Promise((resolve, reject) => {
const busboy = new Busboy({
headers: {
"content-type": getContentType(event)
}
});
const result = {};
busboy.on("file", (fieldname, file, filename, encoding, mimetype) => {
file.on("data", data => {
result.file = data;
});
file.on("end", () => {
result.filename = filename;
result.contentType = mimetype;
});
});
busboy.on("field", (fieldname, value) => {
result[fieldname] = value;
});
busboy.on("error", error => reject(error));
busboy.on("finish", () => {
event.body = result;
resolve(event);
});
busboy.write(event.body, event.isBase64Encoded ? "base64" : "binary");
busboy.end();
});
new Buffer(number) // Old
Buffer.alloc(number) // New
new Buffer(string) // Old
Buffer.from(string) // New
new Buffer(string, encoding) // Old
Buffer.from(string, encoding) // New
new Buffer(...arguments) // Old
Buffer.from(...arguments) // New
You are using callbackWaitsForEmptyEventLoop which basically let lambda function thinks that the work is not over yet. Also, you are wrapping it in promise but not resolving it. You can simplify this logic using following inbuilt promise function on aws-sdk
module.exports.main = async event => {
const uuid = uuidv4();
await parser(event); // not sure if this needs to be async or not. check
const bitmap = Buffer.from(event.body.file, "base64"); // <======== problem here
const params = {
Bucket: "my_bucket",
Key: `${uuid}.jpeg`,
ACL: "public-read",
Body: bitmap,
ContentType: "image/jpeg"
};
const response = await s3.putObject(params).promise();
return response;
};

Sqlite3 returning empty array with GET request in Express

I am trying to make a get request to an sqlite3 table, using Express, based on input from a form. The fetch request works and so does the db.all, but I receive a response as an empty array from rows. I tried req.query and req.params already. Not sure where the error is.
//server.js
app.get('/names/state', (req, res, next) => {
const stateValue = req.query.state;
db.all(`SELECT name FROM states WHERE name=$stateVal`,
{
$stateVal: stateValue
},
(err, rows) => {
res.send({rows:rows});
})
});
//script.js
const fetchOneBtn = (e) => {
e.preventDefault();
const stateVal = stateInputValue.value;
fetch(`/names/state?state=${stateVal}`)
.then(response =>{
if(response.ok){
return response.json();
}
}).then(names => {
console.log(names);
})
};
You can change your code in your backend with this code below:
app.get('/names/state', (req, res, next) => {
const stateValue = req.query.state;
var query = "SELECT name FROM states WHERE name = " + stateValue;
db.all(query, (err, rows) => {
if(err) {
console.log(err);
res.status(500).send(err);
}else {
res.send({rows});
}
})
});
Now, for your frontend, you can change with the code below:
const fetchOneBtn = async (e) => {
e.preventDefault();
const stateVal = stateInputValue.value;
try {
const response = await fetch(`/names/state?state=${stateVal}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json'
},
});
console.log(await response.json());
return await response.json();
} catch(ex) {
console.log(ex);
}
};
I hope it can help you.