While I am in a process of integrating Spotify API into Google Assistant app, implementing Account Linking,
getaddrinfo EAI_AGAIN api.spotify.com:443
This above error has been kept coming out in the console, although it seems to be working like nothing is wrong around API implementation. The access token is properly created and received and client and secret ids were filled without any typo. Also, I tested API calls on Spotify Console (https://developer.spotify.com/console/get-artist-albums/). No error was found. It fetched expected data from the Spotify server, so it should not be related to Account Linking and Spotify Server. The created code myself is below: I assume there is something wrong around spotify-web-api-node, node, npm, or firebase-functions?? I recently have done node versioning so I might did something wrong.
Node version: v7.9.0
spotify-web-api-node: ^4.0.0
firebase-functions: ^2.0.3
npm version: 6.4.1
Added engines: { "node": "8" } // this is in package.json to use asyn and await
app.intent(SomeIntent, async (conv, params) => {
console.log('user info', JSON.stringify(conv.user));
conv.ask('lets play'); //okay
const access_token = conv.user.access.token || ''; // okay
console.log('Your TOKEN information here: ' + access_token); // okay
spotifyApi.setAccessToken(access_token); // should be set correctly
let data = await findMusic(); // error in the findMusic func
conv.ask('found this song。', data.name); // so no data.name
});
function findMusic() {
return spotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE').then((data) => {
console.log('artist song', data.body);
return data.body; //this does not return because error is produced
}).catch(err => {
console.log('Something went wrong!', err);
return err; // this error is WebapiError: getaddrinfo EAI_AGAIN api.spotify.com:443
});
}
UPDATE
#Nick-Felker mentioned in the comment below that external calls are allowed only through paid plans. So this might be the solution (not proved to be working right now because I am not using a paid plan. The detailed explanation below is quoted from An answer comment from another StackOverflow post
The Spark plan allows outbound network requests only to Google-owned services. Inbound invocation requests are allowed within the quota. On the Blaze plan, Cloud Functions provides a perpetual free tier. The first 2,000,000 invocations, 400,000 GB-sec, 200,000 CPU-sec, and 5 GB of Internet egress traffic is provided for free each month. You are only charged on usage past this free allotment. Pricing is based on total number of invocations, and compute time. Compute time is variable based on the amount of memory and CPU provisioned for a function. Usage limits are also enforced through daily and 100s quotas. For more information, see Cloud Functions Pricing.
UPDATE
In my case, the above solution worked. Hope this article helps others!
I got this error due to network problem. And solved when connected
Related
I have a Google Cloud function which first creates a Google Room Resource using resources.calendars.insert method from the Google admin sdk,
and right after I try to insert an ACL using Acl: insert method from the google calendar api.
Similar to the following code:
const AdminService = google.admin({version: 'directory_v1'});
try {
const response = await AdminService.resources.calendars.insert(options); // options omitted
} catch (error) {
console.log(`Google Room Resource FAIL`);
console.error(error.message);
}
await new Promise((r) => setTimeout(r, 10000));
const CalendarService = google.calendar({version: 'v3'});
try {
const res = await CalendarService.acl.insert(option); // options omitted
console.log(res);
} catch (error) {
console.log(error);
throw new Error(error.message);
}
As for the authentication, I am using a service account with the correct scopes which impersionates an admin user with the correct permissions. This is how I generate the required JWT token:
const generateJWT = async (scope:string[])=>{
const jwtClient = new google.auth.JWT(
client_email, // service account
undefined,
private_key,
scope,
subject // admin user
);
return jwtClient;
}
In the options parameter for each api call I directly acquire the token for the auth attribute like this:
const option = {
'calendarId': acl.calendarId,
'auth': await generateJWT('https://www.googleapis.com/auth/calendar'),
'resource': {
'role': acl.role,
'scope': {
'type': acl.scopeType,
'value': acl.scopeValue,
},
},
};
Since I await all api calls, I thought that I will only get the response back when everything is already propagated in Google Workspace but when I do not use the setTimeout in between I always get an Error: Not Found back.
First I had the timeout set to 5 seconds which worked until it didn't so I moved it up to 10 seconds. This worked quite long but now I get again sometimes the Not Found error back...
I don't like the setTimeout hack...and even less if it does not work reliable, so how should I deal with this asynchronous behavior without spinning up any other infrastructure like queues or similar?
Working with Google Workspace Calendar Resource
As a Super Admin on my organization when creating a Calendar Resource, from the API or the Web interface, it could take up to 24 hours to correctly propagate the information of the Calendar for the organizations, which generally affect the time it would take for any application to gather the ID of the newly created calendar, which could explain why you are increasing the time out.
You have already implemented the await option which is one of the best things you can do. You can also review the option to apply exponential back off to your application or similar to Google App Script a Utitlies.sleep().
There are multiple articles and references on how to utilize it for the retry process needed when the Resource itself has not fully propagated correctly.
You can also review the official Calendar API documentation that suggests that the error "Not Found" is a 404 error:
https://developers.google.com/calendar/api/guides/errors#404_not_found
With a suggested action of reviewing the option to set up exponential backoff to the application.
References:
GASRetry - Exponential backoff JavaScript implementation for Google Apps Script
Exponential backoff
Can't receive any notifications sent from the Server peripheral.
I am using ESP32 as Server with the "BLE_notify" code that you can find in the Arduino app (File> Examples ESP32 BLE Arduino > BLE_notify).
With this code the ESP32 starts notifying new messages every second once a Client connects.
The client used is a Raspberry Pi with Noble node library installed on it (https://github.com/abandonware/noble). this is the code I am using.
noble.on('discover', async (peripheral) => {
console.log('found peripheral:', peripheral.advertisement);
await noble.stopScanningAsync();
await peripheral.connectAsync();
console.log("Connected")
try {
const services = await peripheral.discoverServicesAsync([SERVICE_UUID]);
const characteristics = await services[0].discoverCharacteristicsAsync([CHARACTERISTIC_UUID])
const ch = characteristics[0]
ch.on('read', function(data, isNotification) {
console.log(isNotification)
console.log('Temperature Value: ', data.readUInt8(0));
})
ch.on('data', function(data, isNotification) {
console.log(isNotification)
console.log('Temperature Value: ', data.readUInt8(0));
})
ch.notify(true, function(error) {
console.log(error)
console.log('temperature notification on');
})
} catch (e) {
// handle error
console.log("ERROR: ",e)
}
});
SERVICE_UUID and CHARACTERISTIC_UUID are obviously the UUIDs coded in the ESP32.
This code sort of works, it can find Services and Characteristics and it can successfully connect to the peripheral, but it cannot receive messages notifications.
I also tried an Android app that works as client, from that app I can get all the messages notified by the peripheral once connected to it. So there is something missing in the noBLE client side.
I think there is something wrong in the on.read/on.data/notify(true) callback methods. Maybe these are not the methods to receive notifications from Server?
I also tried the subscribe methods but still not working.
The official documentation is not clear. Anyone could get it up and running? Please help.
on.read/on.data/ are event listeners. There is nothing wrong with them. They are invoked when there is a certain event.
For example adding characteristic.read([callback(error, data)]); would have invoked the on.read.
From the source:
Emitted when:
Characteristic read has completed, result of characteristic.read(...)
Characteristic value has been updated by peripheral via notification or indication, after having been enabled with
characteristic.notify(true[, callback(error)])
I resolve using the following two envs NOBLE_MULTI_ROLE=1 and NOBLE_REPORT_ALL_HCI_EVENTS=1 (see the documentation https://github.com/abandonware/noble)
I have written a progressive web app, following all available guides and examples, but for some reason when I click the Add to homescreen button, I keep getting this mysterious error:
Site cannot be installed: does not work offline
The major difference between my PWA and the examples, is that mine is running purely in a non-root path of the domain, so I have had to add extra paths to the configs in various places so the app is restricted to the non-root folder.
The Google Lighthouse site doesn't help much either, giving a very similar message.
Can anyone suggest what this error might be caused by?
Update:
Looks like Google also picked up on the quick hack and the warning has returned.
So since of Chrome93 (AUG-2021) the quick hack, will not work anymore :
self.addEventListener('fetch', function(event) {})
Solution working "for now" (since we never know what requirements Google will add later on)
I've found a nice article which provides with a few solutions, the first one the author provides is Network-Falling-Back-To-Cache strategy:
your service worker will first try to retrieve the resource from your
server. Then when it can’t do that — because for example, you’re
offline — retrieve it from the cache (if it exists there).
self.addEventListener('fetch', function(event) {
event.respondWith(async function() {
try{
var res = await fetch(event.request);
var cache = await caches.open('cache');
cache.put(event.request.url, res.clone());
return res;
}
catch(error){
return caches.match(event.request);
}
}());
});
You can find all the information and alternative solutions in the article:
https://javascript.plainenglish.io/your-pwa-is-going-to-break-in-august-2021-34982f329f40
I hope this will help futur visitors.
Original answer:
Also you need to define fetch listener in a service worker file:
this.addEventListener('fetch', function (event) {
// it can be empty if you just want to get rid of that error
});
So it took me a couple of hours, but I eventually figured out that there is a required scope parameter that you need to specify in the client JavaScript when connecting to the serviceworker, if it's not running on the root (/) path.
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('sw.js?v2', {
scope: '.' // <--- THIS BIT IS REQUIRED
}).then(function(registration) {
// Registration was successful
console.log('ServiceWorker registration successful with scope: ', registration.scope);
}, function(err) {
// registration failed :(
console.log('ServiceWorker registration failed: ', err);
});
}
You can see the working product here:
App: https://stampy.me/pwgen/
Manifest file: https://stampy.me/pwgen/manifest.json
ServiceWorker file: https://stampy.me/pwgen/sw.js
App script: https://stampy.me/pwgen/script.js (scroll to bottom for PWA code)
I hope my pain can save someone else some time.
Google web sign in has driven me positively crazy...
I'm building a simple web application, and I'm trying to integrate Google's sign in feature into the website (https://developers.google.com/identity/sign-in/web/).
The JavaScript seemed to go fairly well, and the next step was to verify the id_token I was receiving with my backend server (again, against Google's recommendation: https://developers.google.com/identity/sign-in/web/backend-auth).
It's a PHP-based web application, and I've successfully installed the Google Client API library using composer: composer require google/apiclient, but when posting my id_token value to my PHP backend system I'm consistently receiving the following error:
Firebase\JWT\SignatureInvalidException
File: .\vendor\firebase\php-jwt\src\JWT.php:112
Message: Signature verification failed
Stack trace:
#0 .\vendor\google\apiclient\src\Google\AccessToken\Verify.php(103): Firebase\JWT\JWT::decode('eyJhbGciOiJSUzI...', '-----BEGIN PUBL...', Array)
#1 .\vendor\google\apiclient\src\Google\Client.php(712): Google_AccessToken_Verify->verifyIdToken('eyJhbGciOiJSUzI...', '10...')
I've also used the id_token value on Google's "tokeninfo" endpoint (https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=ABC123), and the id_token validates perfectly, so I'm sure it's not the id_token value that's wrong. It's also passing it perfectly via the POST variable to the PHP script, so I'm at a bit of a loss.
Here's my code:
Javascript:
<script src="https://apis.google.com/js/platform.js?onload=googleAppStart" async defer></script>
<script>
var googleAppStart = function(){gapi.load('auth2', initGoogleSignIn);};
var auth = false;
function initGoogleSignIn(){
auth = gapi.auth2.init({
client_id : 'client-id-is-here',
scope : 'profile'
});
auth.attachClickHandler(document.getElementById('my-button'));
auth.isSignedIn.listen(googleSignInChanged);
auth.currentUser.listen(googleCurrentUserChanged);
if (auth.isSignedIn.get() == true)
auth.signIn();
}
function googleSignInChanged(signed_in){}
function googleCurrentUserChanged(user){
var auth_response = user.getAuthResponse();
var id_token = auth_response.id_token;
if (id_token != undefined){
var url = '/verify-google-signin';
var params = {id_token: id_token};
jQuery.post(url, params, function(data){}, 'json');
}
}
</script>
...and my PHP catching the POST:
<?php
require_once '/vendor/autoload.php';
$credentials = array("client_id" => "client-id-is-here");
$client = new \Google_Client($credentials);
$data = $_POST;
if (isset($data['id_token'])) {
$id_token = trim($data['id_token']);
// Exception generated here...
$payload = $client->verifyIdToken($id_token);
}
?>
Thank you so much for taking the time to read this, and for any assistance! It's greatly appreciated!
I had the same issue today.
Easier if you just execute:
composer require firebase/php-jwt:4.0
Fortunately you can verify id_token without google library as described here https://developers.google.com/identity/sign-in/web/backend-auth#calling-the-tokeninfo-endpoint
if (isset($data['id_token'])) {
$id_token = trim($data['id_token']);
try {
$res = (new \GuzzleHttp\Client())->request('GET',
'https://www.googleapis.com/oauth2/v3/tokeninfo', [
'query' => ['id_token' => $id_token],
]);
$payload = json_decode($res->getBody()->getContents(), true);
//you still need to check that the aud claim contains one of your app's client IDs
if ($payload['aud'] != "client-id-is-here") {
throw new \Exception("App Isn't valid", 422);
}
} catch (RequestException $e) {
//IF token isn't valid you will be here
if ($e->hasResponse()) {
/** #var \GuzzleHttp\Psr7\Response $resp */
$resp = $e->getResponse();
$error = json_decode($resp->getBody()->getContents(), true)['error_description'];
throw new \Exception($error, $resp->getStatusCode());
}
}
}
If you have no exceptions then your token is valid
It is a problem with php-jwt. Latest version is not working with Google Api Client.
Try to use php-jwt version 4.
I put "firebase/php-jwt": "<5.0" in my composer.json file.
Worked as a charm!
This has been fixed in v2.2.1 of google/apiclient so make sure you are running this version or later if anyone else encounters this issue.
Related discussions here and here.
I've got problems with Google Sign-In backend authentication yesterday, using both google/apiclient 2.2.0 and 2.1.3.
tl;dr it was most likely malfunctions on the Google side or some obscure limits I'm unaware of (nothing in the Developer Console about that).
First, the "idToken" Google was giving me client-side was not a valid JWT: openssl_verify() was rejecting it in Firebase\JWT\JWT, throwing a Firebase\JWT\SignatureInvalidException. I followed your advice, installed google/apiclient 2.1.3 and this exception was not being throwed anymore but the resulting payload was null (so the idToken was still invalid).
A few hours later, I had experienced intermittent results with the apiclient 2.3.0: sometimes the token was invalidated by signature verification (and throwing the signature exception) and sometimes the token was cryptographically valid but the returned payload was null. Once in a while, the token was valid (!).
In the end, the backend authenticaton process was succeeding every time.
As I began experiencing these problems, I tried to fix it generating new OAuth2 keys, revert to a previous verions of my codebase (both server-side and client-side) that I knew was working, removed all browser data and tried to get the token on Cordova with the Sign In for Android. Nothing worked. Also no message in the Developer Console, no visible limits, no security e-mail.
If it's not a bug but a feature, the error handling is quite harsh :)
If you are not using Firebase (taken from https://github.com/googleapis/google-api-php-client)
rm -r vendor/google/apiclient-services
Add this to composer.json
"scripts": {
"post-update-cmd": "Google\\Task\\Composer::cleanup"
},
"extra": {
"google/apiclient-services": [
"Drive" ,
"... any other services here ...",
]
}
Finally
composer install
This will resolve the error message with the added benefit of drastically reducing installed packages. As noted, there are at least 200 API services for GAPI
I have created a story on wit.ai using the quickstart guide.
Now I want to make a conversation with my chat bot using node-wit in node.js.
I guess I should use https://github.com/wit-ai/node-wit#runactions to run the messages, but I'm not sure how to start a conversation that never ends. I need to send a message and then get the response from the chat bot until I break the conversation.
I have looked through the wit.ai examples, but I cannot find any example of how to start a simple conversation in node.js.
I use socket.io to transmit the messages between client and server, and I have tried to solve my problem with
let sessions = {};
const sessionId = new Date().toISOString();
sessions[sessionId] = { context: {} };
io.on('connection', function (socket) {
socket.on('new message', function (message) {
client.runActions(
sessionId,
message,
sessions[sessionId].context
).then((context) => {
console.log(context);
sessions[sessionId].context = context;
}).catch((err) => {
console.error('Error: ', err.stack || err);
});
});
});
and it seems to almost work. I can chat with my bot, but it messes up the stories by sometimes answering multiple times from different stories. I guess I should probably end the stories somehow?
You should try with this link
https://github.com/wit-ai/node-wit/blob/master/examples/quickstart.js
Just clone/download the whole node-wit module from git or npm-install.
Then just run the command node quickstart.js "wit-token".
wit-token == wit-app-token
it will work .
Have you checked this Facebook Messenger integration example. The quickstart.js includes an interactive mode this is why it may be confusing.
Look at the messenger.js example on how to use runActions and send messages back to Messenger.
I was successful in doing this, although I'm still working on stories.