IBM Watson JavaScript SDK for Speech-To-Text WebSocket Issue - javascript

I'm writing a Vue.js web app and trying to access the Watson Speech-To-Text API. I found a very simple implementation using the JavaScript SDK (watson-speech) in documentation. This is the code I'm using:
execute () {
var stream;
fetch('/api/speech-to-text/token').then(function(response) {
return response.text();
}).then(function (token) {
stream = WatsonSpeech.SpeechToText.recognizeFile({
token: token,
file: document.querySelector('#audiofile').files[0],
play: true, // play the audio out loud
outputElement: '#output', // CSS selector or DOM Element (optional)
}
});
stream.on('error', function(err) {
console.log(err);
});
}).catch(function(error) {
console.log(error);
});
}
There's a button that when clicked (after a file upload) runs this execute() function.
When I run this at the link where I found it (https://watson-speech.mybluemix.net/file-upload.html), it works just fine. I've configured the environment variables to use my API username and password (and confirmed they work by downloading an example React project from another Watson repository). When I try to do it in my own project however, it doesn't work. I get the following error:
Error during WebSocket handshake: Unexpected response code: 403
I'm not sure if this is a CORS issue, or if this can't be done all client-side or what. Does WebSocket need to be installed? I had thought it was all handled by the Watson functions, so I'm at a loss. Any help would be greatly appreciated!

Found out that you CANNOT retrieve an authorization token client side. You have to have some sort of server side code to retrieve the token, and then the client can use that. Watson also has a Node.js SDK that can be used for this with easy handling of authentication.

Related

Querying internal metadata server from React app hosted on Google Cloud Run

I'm implementing Google Cloud's service-to-service authentication documentation between two apps hosted on Cloud Run. A client-side React app - created using create-react-app - will be making calls to a server-side Node.js app, where the latter doesn't have unauthenticated invocation allowed.
However, I'm not able to query the internal metadata server form my React app to get an authorization token. When running the request in the sample code on that page, I get the error in the attached screenshot. Does anyone have a solution to this?
Code to make call:
const buttonClickHandler = async (event) => {
const metadataServerTokenURL = 'http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience=';
const tokenRequestOptions = {
uri: metadataServerTokenURL + process.env.REACT_APP_API_BASE_URL,
headers: {
'Metadata-Flavor': 'Google'
}
};
// Fetch the token, then provide the token in the request to the receiving service
request(tokenRequestOptions)
.then((token) => {
return request(process.env.REACT_APP_API_BASE_URL).auth(null, null, true, token)
})
.then((response) => {
console.log(response)
})
.catch((error) => {
console.error(error)
});
}
Error:
TypeError: Failed to fetch
Browser console error
This service-to-service procedure you linked in your question is, as mentioned in the name, for service to service communication.
The documentation you shared mentions this:
Note that this method does not work outside of Google Cloud, including from your local machine.
The metadata server is not intended to be called from outside Google Cloud. This is why it is not working in your browser.
If you are calling a backend container, you could:
make this backend container callable by unauthenticated users (IAM role: "roles/run.invoker", member: "allUsers")
Implement token retrieval with firebase/auth and the Identity Platform.

RabbitMQ: Handshake Terminated by server (ACCESS-REFUSED)

I'm trying to send RabbitMQ messages from my host machine to a Minikube instance with a RabbitMQ cluster deployed.
When running my send script, I get hit with this error:
Handshake terminated by server: 403 (ACCESS-REFUSED) with message "ACCESS_REFUSED - Login was refused
using authentication mechanism PLAIN. For details see the broker logfile.
In the broker logfiles I can see this line:
Error on AMQP connection <0.13226.0> (172.17.0.1:40157 -> 172.17.0.8:5672, state: starting):
PLAIN login refused: user 'rabbitmq-cluster-default-user' - invalid credentials
I'm sure I have the correct credentials since I got them directly from the RabbitMQ pod, following the official documentation (link).
My send script is below:
const amqp = require('amqplib/callback_api');
const cluster = "amqp://rabbitmq-cluster-default-user:dJhLl2aVF78Gn07g2yGoRuwjXSc6tT11#192.168.49.2:30861";
amqp.connect(cluster, function(error0, connection)
{
if (error0)
{
throw error0;
}
connection.createChannel(function(error1, channel)
{
if (error1)
{
throw error1;
}
const queue = "files";
var msg = {
name: "Hello World"
};
var msgJson = JSON.stringify(msg);
channel.assertQueue(queue, {
durable: false
});
channel.sendToQueue(queue, Buffer.from(msgJson));
});
});
I know the code works as I ran the exact same script for my localhost setup and it worked. The only thing I've changed is the URL (for the Minikube RabbitMQ service).
I've seen a few other posts that contain a similar issue but most solutions are about including the correct credentials in the URI, which I have done.
Any other ideas?
You can use port forwarding the rabbitMQ service to your local machine and use UI login and check the password with the UI given by the RabbitMQ itself.
kubectl port-forward svc/rabbitmq UI-PORT:UI-PORT (must be 15672)
then from a browser
localhost:15762
must be enough
For clearance you can check if you can login from the container itself. If the login from the container fails you can also check the yaml file or the helm chart you are using for login methods and credentials. Plain login may be disabled.
Another situation may be with the distrubution. When deploying RabbitMQ I try to use bitnami charts. I can suggest them.
If all these fails there is another way you can use. You can try to create another user with admin privileges to connect to RabbitMQ and then keep using it.
For more information, you can post container/pod logs for us to see.
Good day.

Try to connect to a server with Google Assistance App

I need to send data out from my google assistance app to a database. In order to do this, I've created a server that takes the data, packages it, and then sends it out. I have the hostname and port and it works in a normal javascript/node.js program but when I use it in my google assistant app nothing happens. I tried figuring out the problem and it looks like the code just isn't connecting. The code I'm using to send data to the server is as follows:
function sendData(app){
var net = require('net');
var message = {"test": 200};
var thisMessage = JSON.stringify(message);
var client = new net.Socket();
client.connect(<port>, '<hostname>', function() {
app.tell(JSON.stringify(client.address()));
console.log('Connected');
client.write(thisMessage);
});
client.on('data', function(data) {
console.log('Received: ' + data);
client.destroy();
});
client.on('close', function() {
console.log('Connection closed');
});
return 0;
}
(NOTE: Port and hostname left out for privacy purposes)
This completely skips over the app.tell, leading me to believe the connection is never made. I know it works asynchronously with the server, however, I don't understand why it isn't connecting whatsoever.
I have tried it both in simulation and on my smartphone with sandbox on and off. Is there a better way to connect? Note that the server I'm connecting to is python-based.
The problem is likely that you're running it on Cloud Functions for Firebase which has a limit on outbound connections under their free "Spark" plan. With this plan, you can only connect to other Google services. This is usually a good way to start understanding how to handle Action requests, but has limitations. To access endpoints outside of Google, you need to upgrade to either their "Flame" fixed price plan or "Blaze" pay-as-you-go plan.
You do not, however, need to run on Google's servers or need to use node.js. All you need is a public HTTPS server with a valid SSL cert. If you are familiar with JSON, you can use any programming language to handle the request and response. If you are familiar with node.js, you just need a node.js server that can create Express request and response objects.

How to make Android Java code call Node.js code?

I have some code that I have and I want to invoke some Node.js code and I'm not sure how to go about this. I want to implement these Firebase notifications as described in this blog post:
https://firebase.googleblog.com/2016/08/sending-notifications-between-android.html
But there is some Node.js code that will listen on my Firebase Database and will detect if there is something being inserted into my database. Is there any way I can "deploy" this code somewhere on my Android application and have it so that this code will be invoked? Below is the Node.js code I woudl want to get invoked from my Android application:
var firebase = require('firebase');
var request = require('request');
var API_KEY = "..."; // Your Firebase Cloud Server API key
firebase.initializeApp({
serviceAccount: ".json",
databaseURL: "https://.firebaseio.com/"
});
ref = firebase.database().ref();
function listenForNotificationRequests() {
var requests = ref.child('notificationRequests');
ref.on('child_added', function(requestSnapshot) {
var request = requestSnapshot.val();
sendNotificationToUser(
request.username,
request.message,
function() {
request.ref().remove();
}
);
}, function(error) {
console.error(error);
});
};
function sendNotificationToUser(username, message, onSuccess) {
request({
url: 'https://fcm.googleapis.com/fcm/send',
method: 'POST',
headers: {
'Content-Type' :' application/json',
'Authorization': 'key='+API_KEY
},
body: JSON.stringify({
notification: {
title: message
},
to : '/topics/user_'+username
})
}, function(error, response, body) {
if (error) { console.error(error); }
else if (response.statusCode >= 400) {
console.error('HTTP Error: '+response.statusCode+' - '+response.statusMessage);
}
else {
onSuccess();
}
});
}
// start listening
listenForNotificationRequests();
I would imagine I would need to host the code somewhere, but I feel like if all I need is to host one file somewhere it wouldn't be necessarily to deploy something like Google App Engine or Heroku unless I am mistaken. I guess I am just confused on how I can communicate between this file and the Java Android code I've written so far. If anyone could point me in the right direction, that'd be great. Thanks!
You can install something like Termux on the android and install node.js on it, and host your code locally on the device, but I must say that it seems like a strange way to use a node.js server (but it sure does sound fun!)
Take a look at this guide for installing Termux and node.js on your Android:
https://medium.freecodecamp.com/building-a-node-js-application-on-android-part-1-termux-vim-and-node-js-dfa90c28958f#.z9zjw5o8w
I am not sure how well the network traffic will flow from your node.js server to the database and back considering it is being hosted from inside a sort of emulator on the Android, but it's worth a shot.
Is there any way I can "deploy" this code somewhere on my Android application and have it so that this code will be invoked?
No. You don't run node.js code inside you Android application. That would defeat the purpose of separating the code.
The Node.js code runs on a so-called app server. Such an app server is a trusted place where you can run code. Since you control such a server (after all, nobody else has access to it), you can trust that the code that runs on the server is the code that you put there.
On your users' Android device, you can run code. But you can never trust that the code running on the device is the code that you sent there. After all the user can make changes to the app.
You should never mix application code with code that runs on a trusted server. The Node.js script from my article requires the Firebase Cloud Messaging server key to be able to send messages to devices. Since having access to this key allows you to send messages on your project's behalf, it should only be present on trusted serves - such as your app server.

Always using the same OAUTH code with Dropbox-js

I'm using the official Dropbox JS library in a Node.js server. It only ever needs to authenticate as a single user, and it can't go through the whole OAUTH browser setup every time the server starts. I am attempting to write an auth driver that pretends to be like the NodeServer driver, but runs the callback straight away with a code that always stays the same.
Here's what I've got (it's coffeescript, but you get the idea):
myAuthDriver = {
authType: -> return "code"
url: -> return "http://localhost:8912/oauth_callback" # What the url would be if I were using NodeServer
doAuthorize: (authUrl_s, stateParam, client, callback) ->
authUrl = url.parse(authUrl_s, true)
callback({
code: "[a code I just got using the NodeServer driver]"
state: authUrl.query.state
})
}
Running authenticate with this driver set causes this error:
Dropbox OAuth error invalid_grant :: given "code" is not valid
The docs say that this should only occur with a broken auth driver (but it doesn't give any ideas for fixing it).
Does anyone with more knowledge of OAUTH or Dropbox know what's wrong here?
Note: I've found in several places online that Dropbox OAUTH codes never expire
Once you have an OAuth 2 access token, you can just do var client = new Dropbox.Client({token: '<your token>'});. No need for an auth driver at all.
(If you want an easy way to get an access token, consider using https://dbxoauth2.site44.com.)

Categories

Resources