npm react-native-fetch-blob - "RNFetchBlob.fetch is not a function" - node.js

I am using the npm package react-native-fetch-blob.
I have followed all the steps from the git repository to use the package.
I then imported the package using the following line:
var RNFetchBlob = require('react-native-fetch-blob');
I am trying to request a BLOB containing an image from the a server.
This is my main method.
fetchAttachment: function(attachment_uri) {
var authToken = 'youWillNeverGetThis!'
var deviceId = '123';
var xAuthToken = deviceId+'#'+authToken
//Authorization : 'Bearer access-token...',
// send http request in a new thread (using native code)
RNFetchBlob.fetch('GET', config.apiRoot+'/app/'+attachment_uri, {
'Origin': 'http://10.0.1.23:8081',
'X-AuthToken': xAuthToken
})
// when response status code is 200
.then((res) => {
// the conversion is done in native code
let base64Str = res.base64()
// the following conversions are done in js, it's SYNC
let text = res.text()
let json = res.json()
})
// Status code is not 200
.catch((errorMessage, statusCode) => {
// error handling
});
}
I keep receiving the following error:
"Possible Unhandled Promise Refection(id: 0): TypeError: RNFetchBlob.fetch is not a function".
Any ideas?

The issue is you are using ES5 style require statements with a library written against ES6/ES2015. You have two options:
ES5:
var RNFetchBlob = require('react-native-fetch-blob').default
ES6:
import RNFetchBlob from 'react-native-fetch-blob'

My import looks like this : import RNFetchBlob from 'rn-fetch-blob';
but I'v got an error : TypeError: RNFetchBlob.scanFile is not a function
My code:
const downloadAudio = async () => {
const { config, fs } = RNFetchBlob;
const meditationFilesPath =
Platform.OS == 'android'
? `${fs.dirs.DownloadDir}/meditations/${id}`
: `${fs.dirs.DocumentDir}/meditations/${id}`;
let audio_URL = track;
let options = {
fileCache: true,
path: meditationFilesPath + `/${id}.mp3`,
addAndroidDownloads: {
// Related to the Android only
useDownloadManager: true,
notification: true,
path: meditationFilesPath + `/${id}.mp3`,
description: 'Audio',
},
};
try {
const resAudio = await config(options).fetch('GET', audio_URL.uri);
if (resAudio) {
const audio = await RNFetchBlob.fs.scanFile([
{ path: resAudio.path(), mime: 'audio/mpeg' },
]);
console.log('res -> ', audio);
Alert.alert('Audio Downloaded Successfully.');
}
} catch (error) {
console.error('error from downloadAudio', error);
}
};

Related

Error when trying to upload an image to ImgBB

I'm trying to upload images to ImgBB using NodeJS and GraphQL.
I have a uploadImage mutation that takes an image in the form of a data url string, and goes as follows:
import parseDataUrl from "data-uri-to-buffer";
// ...
{
Mutation: {
async uploadImage(_, { dataUrl }) {
const buffer = parseDataUrl(dataUrl); // https://www.npmjs.com/package/data-uri-to-buffer
if (buffer.byteLength > 10 * 10 ** 6)
throw new Error("The image exceeds the maximum size of 10 MB");
const body = new FormData();
body.append("image", buffer);
const result = await fetch(
`https://api.imgbb.com/1/upload?key=${process.env.IMGBB_KEY}`,
{
method: "post",
headers: { ...body.getHeaders() },
body
}
).then<any>(result => result.json());
if (!result.success || !result.url) {
const msg = result.error?.message;
throw new Error(
`There was an error during upload${msg ? `: ${msg}` : ""}`
);
}
return result.url;
}
}
}
body.getHeaders() contains:
{
'content-type': 'multipart/form-data; boundary=--------------
------------656587403243047934588601'
}
(I'm using node-fetch)
But no matter the combinations of query params, headers and body I use, I always end up getting this error:
{
status_code: 400,
error: { message: 'Undefined array key "scheme"', code: 0 },
status_txt: 'Bad Request'
}
I can't find anything about it, do you have an idea?
There are multiple things you can do to resolve your issue.
Important thing with FormData, you need to explicitly provide a name for the image buffer if it's not already included, uploading without name API would throw the same error you have mentioned.
body.append("image", buffer, "addSomeImageName.png");
The api does not require any header explicitly so you can remove it.
{
method: "post",
headers: { ...body.getHeaders() }, // This can be removed.
body
}
The logic you are using to check for the result is faulty and would always throw error even if the result is successful.
if (!result.success || !result.url) { // Check for success flag only.
const msg = result.error?.message;
throw new Error(
`There was an error during upload${msg ? `: ${msg}` : ""}`
);
}
This is the block I tested and is working fine:
import parseDataUrl from "data-uri-to-buffer";
import fetch from 'node-fetch';
import FormData from "form-data";
async function uploadImage({
dataUrl
}) {
const buffer = parseDataUrl(dataUrl);
if (buffer.byteLength > 10 * 10 ** 6)
throw new Error("The image exceeds the maximum size of 10 MB");
const body = new FormData();
body.append("image", buffer, "someImageName.png");
const result = await fetch(
`https://api.imgbb.com/1/upload?key=<your-api-key>`, {
method: "post",
// headers: { ...body.getHeaders() },
body
}
).then(result => result.json())
// .then(data => {
// console.log(data); // Working fine here too.
// });
console.log("-------result--------\n", result); // Result is fine.
// Logic testing.
console.log(result.success);
console.log(result.url);
console.log(!result.success);
console.log(!result.url);
console.log(!result.success || !result.url);
if (!result.success || !result.url) {
const msg = result.error ? .message;
console.log(`There was an error during upload${msg ? `: ${msg}` : ""}`)
// throw new Error(
// `There was an error during upload${msg ? `: ${msg}` : ""}`
// );
}
return result.url;
}
console.log("--------------------- console result ------------------------")
console.log(uploadImage({
dataUrl: "data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7"
}));
One thing that seems odd to me:
const buffer = parseDataUrl(dataUrl); // https://www.npmjs.com/package/data-uri-to-buffer
The package in the comment only offers the function dataUriToBuffer, which you are not using. Are you using parseDataUrl from jsdom? Are you using node-fetch's own implementation of FormData as supposed to according to the documentation?
Please append your question with all relevant import statements and please also share the contents of body.getHeaders().

What argument is invalid for Google Document AI client library for Node js?

I'm trying to run Document OCR from Google with a Node js app.
So i used the client library for Node js #google-cloud/documentai
I did everything like in documentation sample
There is my code
const projectId = '*******';
const location = 'eu'; // Format is 'us' or 'eu'
const processor = '******'; // Create processor in Cloud Console
const keyFilename = './secret/******.json';
const { DocumentProcessorServiceClient } = require('#google-cloud/documentai').v1beta3;
const client = new DocumentProcessorServiceClient({projectId, keyFilename});
async function start(encodedImage) {
console.log("Google AI Started")
const name = `projects/${projectId}/locations/${location}/processors/${processor}`;
const request = {
name,
document: {
content: encodedImage,
mimeType: 'application/pdf',
},
}
try {
const [result] = await client.processDocument(request);
const { document } = result;
const { text } = document;
const getText = textAnchor => {
if (!textAnchor.textSegments || textAnchor.textSegments.length === 0) {
return '';
}
// First shard in document doesn't have startIndex property
const startIndex = textAnchor.textSegments[0].startIndex || 0;
const endIndex = textAnchor.textSegments[0].endIndex;
return text.substring(startIndex, endIndex);
};
const [page1] = document;
const { paragraphs } = page1;
for (const paragraph of paragraphs) {
const paragraphText = getText(paragraph.layout.textAnchor);
console.log(`Paragraph text:\n${paragraphText}`);
}
return paragraphs;
}
catch (error) {
console.error(error);
}
}
module.exports = {
start
}
Image encoding is here
const {start: google} = require('./document-ai/index')
if (mimeType === 'application/pdf') {
pdf = true;
encoded = Buffer.from(file).toString('base64');
}
await google(encoded);
In result i get this error
Google AI Started
Error: 3 INVALID_ARGUMENT: Request contains an invalid argument.
at Object.callErrorFromStatus (C:\Users\NIKIGAN\WebstormProjects\papper-project\server\node_modules\google-gax\node_modules\#grpc\grpc-js\build\src\call.js:31:26)
at Object.onReceiveStatus (C:\Users\NIKIGAN\WebstormProjects\papper-project\server\node_modules\google-gax\node_modules\#grpc\grpc-js\build\src\client.js:176:52)
at Object.onReceiveStatus (C:\Users\NIKIGAN\WebstormProjects\papper-project\server\node_modules\google-gax\node_modules\#grpc\grpc-js\build\src\client-interceptors.js:342:141)
at Object.onReceiveStatus (C:\Users\NIKIGAN\WebstormProjects\papper-project\server\node_modules\google-gax\node_modules\#grpc\grpc-js\build\src\client-interceptors.js:305:181)
at C:\Users\NIKIGAN\WebstormProjects\papper-project\server\node_modules\google-gax\node_modules\#grpc\grpc-js\build\src\call-stream.js:124:78
at processTicksAndRejections (internal/process/task_queues.js:79:11) {
code: 3,
details: 'Request contains an invalid argument.',
metadata: Metadata {
internalRepr: Map { 'grpc-server-stats-bin' => [Array] },
options: {}
},
note: 'Exception occurred in retry method that was not classified as transient'
}
What invalid arguments do I have in my request?
Environment details
OS: Windows 10
Node.js version: 12.18.3
npm version: 6.14.8
#google-cloud/documentai version: 2.2.1
I've strugglid with this as well and the solution is quite simple as it turns out: you have to set the parameter apiEndpoint when your location is not "us".
Here's an example for location "eu":
const client = new DocumentProcessorServiceClient({
keyFilename,
apiEndpoint: 'eu-documentai.googleapis.com'
});
More information here: GitHub: googleapis /
nodejs-document-ai

Intent handler failed with error: Buffer is not defined

I have built a Google Smart Home Action using the Local Fulfillment SDK as outlined in the following articles:
https://developers.google.com/assistant/smarthome/develop/local
https://github.com/actions-on-google/create-local-home-app
I am using UDP for device discovery and my Google Nest Hub can successfully scan and detect the virtual device running on my laptop as well as download the JS of the local app.
My Local Home SDK configuration is as follows - Local Home SDK Configuration.
When the Nest Hub executes the IDENTIFY intent of my app handler I am receiving the following error(s):
[smarthome.DeviceManager] Intent handler failed with error: Buffer is not defined
[smarthome.DeviceManager] Got a rejected promise Buffer is not defined
This appears to be a Node.JS error as opposed to something specific to the local SDK app itself. Below is the code of my local app.
/// <reference types="#google/local-home-sdk" />
import App = smarthome.App;
import Constants = smarthome.Constants;
import DataFlow = smarthome.DataFlow;
import Execute = smarthome.Execute;
import Intents = smarthome.Intents;
import IntentFlow = smarthome.IntentFlow;
const SERVER_PORT = 3388;
interface ILightParams {
on?: boolean,
brightness?: number
}
class LocalExecutionApp {
constructor(private readonly app: App) { }
identifyHandler(request: IntentFlow.IdentifyRequest):
Promise<IntentFlow.IdentifyResponse> {
console.log("IDENTIFY intent: " + JSON.stringify(request, null, 2));
const scanData = request.inputs[0].payload.device.udpScanData;
console.log("SCANDATA: " + JSON.stringify(scanData));
if (!scanData) {
const err = new IntentFlow.HandlerError(request.requestId, 'invalid_request', 'Invalid scan data');
return Promise.reject(err);
}
const localDeviceId = Buffer.from(scanData.data, 'hex');
console.log("ScanData Local Device: " + localDeviceId);
const response: IntentFlow.IdentifyResponse = {
intent: Intents.IDENTIFY,
requestId: request.requestId,
payload: {
device: {
// id: localDeviceId.toString(),
id: 'sample-device',
verificationId: localDeviceId.toString(),
}
}
};
console.log("IDENTIFY response: " + JSON.stringify(response, null, 2));
return Promise.resolve(response);
}
executeHandler(request: IntentFlow.ExecuteRequest):
Promise<IntentFlow.ExecuteResponse> {
console.log("EXECUTE intent: " + JSON.stringify(request, null, 2));
const command = request.inputs[0].payload.commands[0];
const execution = command.execution[0];
const response = new Execute.Response.Builder()
.setRequestId(request.requestId);
const promises: Promise<void>[] = command.devices.map((device) => {
console.log("Handling EXECUTE intent for device: " + JSON.stringify(device));
// Convert execution params to a string for the local device
const params = execution.params as ILightParams;
const payload = this.getDataForCommand(execution.command, params);
// Create a command to send over the local network
const radioCommand = new DataFlow.HttpRequestData();
radioCommand.requestId = request.requestId;
radioCommand.deviceId = device.id;
radioCommand.data = JSON.stringify(payload);
radioCommand.dataType = 'application/json';
radioCommand.port = SERVER_PORT;
radioCommand.method = Constants.HttpOperation.POST;
radioCommand.isSecure = false;
console.log("Sending HTTP request to the smart home device:", payload);
return this.app.getDeviceManager()
.send(radioCommand)
.then(() => {
const state = {online: true};
response.setSuccessState(device.id, Object.assign(state, params));
console.log(`Command successfully sent to ${device.id}`);
})
.catch((e: IntentFlow.HandlerError) => {
e.errorCode = e.errorCode || 'invalid_request';
response.setErrorState(device.id, e.errorCode);
console.error('An error occurred sending the command', e.errorCode);
});
});
return Promise.all(promises)
.then(() => {
return response.build();
})
.catch((e) => {
const err = new IntentFlow.HandlerError(request.requestId, 'invalid_request', e.message);
return Promise.reject(err);
});
}
/**
* Convert execution request into a local device command
*/
getDataForCommand(command: string, params: ILightParams): unknown {
switch (command) {
case 'action.devices.commands.OnOff':
return {
on: params.on ? true : false
};
default:
console.error('Unknown command', command);
return {};
}
}
}
const localHomeSdk = new App('1.0.0');
const localApp = new LocalExecutionApp(localHomeSdk);
localHomeSdk
.onIdentify(localApp.identifyHandler.bind(localApp))
.onExecute(localApp.executeHandler.bind(localApp))
.listen()
.then(() => console.log('Ready'))
.catch((e: Error) => console.error(e));
Any insight on why this error is occurring is greatly appreciated.
Cheers.
Reposting the answer in the comments:
Buffer is not a type that is directly supported in a browser environment. You can see this for yourself by trying to run something like x = new Buffer() in your web browser's dev console.
To support a class like Buffer, you can use a bundling tool like Webpack. In the official sample, you can see an example Webpack configuration. Other bundling tools can also be used, and examples can be found in the official Local Home scaffolding tool or can be called directly with an npm init command.
npm init #google/local-home-app app/ --bundler webpack
npm init #google/local-home-app app/ --bundler rollup
npm init #google/local-home-app app/ --bundler parcel

GoogleError: Error opening file: gs://mybucket/a.subpath/output.json

I am trying to do OCR on a PDF and am having difficulty getting it to work. I am getting this error:
GoogleError: Error opening file: gs://mybucket/a.subpath/output.json
at Operation._unpackResponse (/Users/my/project/node_modules/google-gax/build/src/longRunningCalls/longrunning.js:148:31)
at /Users/my/project/node_modules/google-gax/build/src/longRunningCalls/longrunning.js:134:18 {
code: 7
}
When running this Node.js script:
const fs = require('fs')
const vision = require('#google-cloud/vision').v1
const client = new vision.ImageAnnotatorClient()
parse('a.something')
function parse(name) {
var bucketName = `mybucket`
const features = [{type: 'DOCUMENT_TEXT_DETECTION'}]
let requests = []
let i = 0
while (i < 10) {
requests.push({
inputConfig: {
mimeType: 'application/pdf',
gcsSource: {
uri: `gs://${bucketName}/${name}.${i + 1}.pdf`
},
},
features: features,
outputConfig: {
gcsDestination: {
uri: `gs://${bucketName}/${name}.${i + 1}/`,
},
},
})
i++
}
const request = {
requests
}
client.asyncBatchAnnotateFiles(request).then(x => {
let [operation] = x
operation.promise().then(y => {
let [filesResponse] = y
const destinationUri =
filesResponse.responses[0].outputConfig.gcsDestination.uri
console.log('Json saved to: ' + destinationUri)
process.exit()
}).catch(e => {
console.log(e)
process.exit()
})
})
}
This is straight from the docs pretty much.
At first I just went into the console and uploaded the PDFs into Cloud Storage manually. I was logged in as foo#gmail.com. A few days before I created a JSON API key to export in the shell, for project bar (which I created when logged in as foo#gmail.com). I then got this error above. So what I tried doing is adding a new member to the project, who had my email foo#gmail.com. Then I gave them the roles I think equivalent to roles/storage.legacyObjectOwner, which were these:
Then, when I run the Node.js script, I get this error still. I don't know what's going on or how to fix it, any ideas?

Returning result of request to another module

I would like to return some of the body from a request made in request.js to the module that calls it in app.js
I have tried using module.exports to save information in the body. I know that the request is asynchronous so I have to wait for it to come back but I am not sure how to do this.
My app.js file:
const yargs = require('yargs');
const fs = require('fs');
const argv = yargs.
options({
capcity: {
description: 'capital city',
alias: 'c',
demand: true
}
})
.help()
.argv;
module.exports.capcity = argv.capcity;
const requestData = require('./requestData.js');
console.log(requestData.country);
My requestData.js file:
const request = require('request');
const app = require('./app.js');
var country;
request({
url: `https://restcountries.eu/rest/v2/capital/${app.capcity}`,
json: true
}
, (error, response, body) => {
console.log(app.capcity);
if (error) {
console.log('error:', error);
} else if (body.status == 404) {
console.log(JSON.stringify(body, undefined, 2));
console.log("invalid city entered");
} else {
country = {
name: body[0].name,
code: body[0].currencies[0].code,
symbol: body[0].currencies[0].symbol
}
country = JSON.stringify(country);
console.log(country);
}
});
module.exports.country = country;
It returns that country is undefined.
You've got some race conditions going on here, You many want to some research on callbacks, or better yet switch to using promises. Also you may want to export functions instead of variables, your code will be more reusable that way.
Heres an example using promises. note I'm using request-promise-native as suggested in the request documentation. you would need to install that dependency also to use this.
In your app.js
const yargs = require('yargs');
const fs = require('fs');
const argv = yargs.
options({
capcity: {
description: 'capital city',
alias: 'c',
demand: true
}
})
.help()
.argv;
const capcity = argv.capcity;
const requestDataFile = require('./requestData.js');
requestDataFile.requestData(capcity).then(country=>{
console.log(country)
})
In your requestData file
const request = require('request-promise-native');
const app = require('./app.js');
module.exports.requestData = (capcity)=>request({
url: `https://restcountries.eu/rest/v2/capital/${capcity}`,
json: true
}).then((body)=>{
return country = {
name: body[0].name,
code: body[0].currencies[0].code,
symbol: body[0].currencies[0].symbol
}
})

Resources