In a previous Stack Overflow question, I shied away from using an external webhook on Actions on Google
so I needed to go back to the inline editor. I got that worked out, but now I'm feeling brave again.
I've outgrown the inline editor and want the ability to develop my code on my laptop, testing it in Firebase, and publishing to a site for my webhook, presumably where the inline code editor publishes to. In fact, I have already written the require functions and deployed them from Firebase. So the full functionality is ready to go, I just need to hook it up properly to Actions on Google.
What I have now in Actions on Google, inline editor, is more of a stub. I want to merge that stub into my more fullblown logic that I have in Firebase. Here is what is in the inline editor:
const { conversation } = require('#assistant/conversation');
const functions = require('firebase-functions');
const app = conversation();
app.handle('intent_a_handler', conv => {
// Implement your code here
conv.add("Here I am in intent A");
});
app.handle('intent_b_handler', conv => {
// Implement your code here
conv.add("Here I am in intent B");
});
exports.ActionsOnGoogleFulfillment = functions.https.onRequest(app);
When I search on the Internet, I see discussion from the point of view of Dialogflow, but like I say, I'm in "Actions on Google". I want to transition away from the inline editor, taking what I already have, as a basis.Can someone explain how I set that up? I'm happy to do this within the context of the Google ecosystem.
To test your own webhook locally on your own system I would recommend incorporating a web app framework such as express. With express you can host code on your local machine and make it respond to request from Actions on Google. In your case you would replace this will all the code related to the Firebase functions package. Here is an example of what a simple webhook for Actions on Google looks like:
const express = require('express');
const bodyParser = require('body-parser')
const { conversation } = require('#assistant/conversation');
const exprs = express();
exprs.use(bodyParser.json()) // allows Express to work with JSON requests
const app = conversation();
app.handle('example intent', () => {
// Do something
})
// More app.handle() setups
exprs.post('/', app);
exprs.listen(3000);
With this setup you should be able to run your own application locally. The only thing you need to do is install the required dependencies and add your own intent handlers for your action. At this point you have a webhook running on your own machine, but that isn't enough to use it as a webhook in Actions on Google because it runs locally and isn't publicly available via the internet.
For this reason we will be using a tool called ngrok. With ngrok you can create a public https address that runs all messages to your local machine. This way you can use ngrok address as your webhook URL. Now you can just make as many code changes as you want and Actions on Google will automatically use the latest changes when you develop. No need to upload and wait for Firebase to do this.
Just to be clear: Ngrok should only be used for development. When you are done with developing your action you should upload all your code to a cloud service or host it on your own server if you have any. A (free plan) ngrok URL usually expires every 6 hours. So its not a suitable solution for anything other than development.
Related
I've been examining this code base as an example of how to implement LinkedIn authorization to my project with a Firebase Backend. One thing I'm confused about is these lines:
var code = getURLParameter("code");
var state = getURLParameter("state");
var error = getURLParameter("error");
if (error) {
document.body.innerText = "Error back from the LinkedIn auth page: " + error;
} else if (!code) {
// Start the auth flow.
window.location.href = "/redirect";
}
at window.location.href = '/redirect', I believe it is meant to invoke the cloud function called "redirect". In my code base, it simply goes to an unknown route and triggers my fallback. Am I wrong about the purpose of this line of code? Does anyone know any possible reasons it's not triggering the cloud function (console says 0 invocations)? What other information should I look into to try to debug this?
To provide a bit fuller of an answer:
The example you provided relies on a Firebase.json file. This file provides configuration if (and only if) your application is hosted with Firebase hosting (see docs).
If you expect to host your app elsewhere, you'll need to make sure your /redirect path points to the Firebase function URL itself (probably something like https://us-central1-project-name.cloudfunctions.net/redirect). In the authorization flow, the LinkedIn module in the example repo then will redirect to either a default or a configured callback url.
I have site that deployed on firebase hosting site
on the site I wrote Version 3 but instead of that I want to show the deployment / release version like e925c5 that writen on the history version.
can I get history version with Rest API.? or can I define it before deployed.?
thank you
Update
I try with reading documentation and working with it, but still stuck with the authentication method,
Simple function is this, but always returned 403 response, already try with getGlobalDefaultAccount.login() and getGlobalDefaultAccount.getAccessToken() and getGlobalDefaultAccount() still not working,
const requireAuth = require('firebase-tools/lib/requireAuth')
const getGlobalDefaultAccount = require('firebase-tools/lib/auth')
const api = require('firebase-tools/lib/api')
const site = 'sarafe-testing'
requireAuth(getGlobalDefaultAccount.getAccessToken(), ['https://www.googleapis.com/auth/cloud-platform']).then(async () => {
try {
const response = await api.request('GET', `/v1beta1/sites/${site}/releases`, { auth: true, origin: api.hostingApiOrigin })
console.log(response)
} catch(e) {
console.log(e.message)
}
})
Full version
For now I just created table that hold version code (manuali update from firebase page) and make API to get the version, but this not a valid solution because is only show the latest version, some other people just open the webpage without refresh / clear cache so that one is still using the old version of webpage with latest version written,
Yes, there is a REST API that allows you to manage versions and releases for Firebase Hosting, and it has a method to get a list of versions for the site. I recommend checking out its documentation and reporting back if you get stuck while implementing the code.
Writing a mobile app with Firebase being my backend, also using ES to power my search. I'm completely new to ES.
Suppose each user can publish articles, each of which contains some number of tags, which denotes what this article is about, kind of like questions asked here. Users can search for articles, with tags, and articles containing that tag will be displayed. I manage to do that with Cloud Function, so, the Cloud Function basically looks like this:
exports.articleSearch = functions.https.onRequest((req, res) => {
const { tag } = req.query;
const ElasticSearchConfig = {
uri: '..<my elastic cloud url>/articles/article/_search...',
method: 'GET',
body: ...,
json: true,
auth: {
username: '...<my elastic cloud username>...',
password: '...<my elastic cloud password>...'
}
};
// If succeeds, send results back to user, if not, send error back
request(ElasticSearchConfig).then((results) => ...)
.catch((error) => ...);
});
This works, however, it's a bit slow, because I'm not running ElasticSearch on user's devices, instead, through a cloud function. But if I do run the above code on user's devices, you noticed auth property of ElasticSearchConfig object, I'm basically giving everybody permissions to access and manipulate my ES server. How can I run the above code on user's devices and at the same time, prevent them from reading or writing anything without proper permission?
There's no secure way to do what your asking. Even if it was possible, you don't want that kind of processing client side draining the battery, especially on mobile. Your slow response from cloud functions may be caused from the function entering a timeout state, meaning it hasn't been called in a while.
Trying to build an Electron app using ember-electron and am trying to use emberfire to communicate with Firebase. Everything runs fine when running as a web app with ember s but when launching as an Electron app I get nothing but errors like this:
XMLHttpRequest cannot load https://www.googleapis.com/identitytoolkit/v3/relyingparty/signupNewUser?key=AIzaSyBYyuJ-1E3ufujlzdKhj8gE9I6QH8TreJE. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'serve://dist' is therefore not allowed access. The response had HTTP status code 404.
Is this a known problem or does anyone know a way around this? Unfortunately cannot simply add serve://dist to the list of authorized domains as Google doesn't consider it a valid domain name.
Update: I would still love to know if anyone has a possible workaround but I found a tool called Nativefier (https://github.com/jiahaog/nativefier) which works for my purposes. Since I am simultaneously developing a web app and a desktop app, once the web app is being hosted, can use nativefier to build the desktop app
I didn't try with electron, but played with node-webkit. Many problems related to origin can be solved by running local web-server: in main script run a web-server using express which serves your app. This is piece of code that I use to start local server:
let express = require('express');
let http = require('http');
let app = express();
app.use('/', express.static('dist'));
let server = http.createServer(app);
let port = 9000;
let maxPort = 50000;
server.on('error', function (e) {
if (port < maxPort) {
server.listen(++port);
} else {
alert('Your system has no free ports to start a web-server, which is needed for this app to work');
window.nw.Window.get().close();
}
});
server.on('listening', function () {
location = 'http://localhost:' + port + '/index.html';
});
server.listen(port);
I think that something similar should work for electron, too
I am planning to use Meteor for a realtime logging application for various
My requirement is pretty simple, I will pass a log Message as request Parameter ( POST Or GET) from various application and Meteor need to simply update a collection.
I need to access Request Parameters in Meteor server code and update Mongo collection with the incoming logMessage. I cannot update Mongo Collection directly from existing applications, so please no replies suggesting the same.I want to know how can I do it from Meteor framework and not doing it by adding more packages.
EDIT: Updated to use Iron Router, the successor to Meteor Router.
Install Iron Router and define a server-side route:
Router.map(function () {
this.route('foo', {
where: 'server',
action: function () {
doSomethingWithParams(this.request.query);
}
});
});
So for a request like http://yoursite.com/foo?q=somequery&src=somesource, the variable this.request.query in the function above would be { q: 'somequery', src: 'somesource' } and therefore you can request individual parameters via this.request.query.q and this.request.query.src and the like. I've only tested GET requests, but POST and other request types should work identically; this works as of Meteor 0.7.0.1. Make sure you put this code inside a Meteor.isServer block or in a file in the /server folder in your project.
Original Post:
Use Meteorite to install Meteor Router and define a server-side route:
Meteor.Router.add('/foo', function() {
doSomethingWithParams(this.request.query);
});
So for a request like http://yoursite.com/foo?q=somequery&src=somesource, the variable this.request.query in the function above would be { q: 'somequery', src: 'somesource' } and therefore you can request individual parameters via this.request.query.q and this.request.query.src and the like. I've only tested GET requests, but POST and other request types should work identically; this works as of Meteor 0.6.2.1. Make sure you put this code inside a Meteor.isServer block or in a file in the /server folder in your project.
I know the questioner doesn't want to add packages, but I think that using Meteorite to install Meteor Router seems to me a more future-proof way to implement this as compared to accessing internal undocumented Meteor objects like __meteor_bootstrap__. When the Package API is finalized in a future version of Meteor, the process of installing Meteor Router will become easier (no need for Meteorite) but nothing else is likely to change and your code would probably continue to work without requiring modification.
I found a workaround to add a router to the Meteor application to handle custom requests.
It uses the connect router middleware which is shipped with meteor. No extra dependencies!
Put this before/outside Meteor.startup on the Server. (Coffeescript)
SomeCollection = new Collection("...")
fibers = __meteor_bootstrap__.require("fibers")
connect = __meteor_bootstrap__.require('connect')
app = __meteor_bootstrap__.app
router = connect.middleware.router (route) ->
route.get '/foo', (req, res) ->
Fiber () ->
SomeCollection.insert(...)
.run()
res.writeHead(200)
res.end()
app.use(router)
Use IronRouter, it's so easy:
var path = IronLocation.path();
As things stand, there isn't support for server side routing or specific actions on the server side when URLs are hit. So it's not easy to do what you want. Here are some suggestions.
You can probably achieve what you want by borrowing techniques that are used by the oauth2 package on the auth branch: https://github.com/meteor/meteor/blob/auth/packages/accounts-oauth2-helper/oauth2_server.js#L100-109
However this isn't really supported so I'm not certain it's a good idea.
Your other applications could actually update the collections using DDP. This is probably easier than it sounds.
You could use an intermediate application which accepts POST/GET requests and talks to your meteor server using DDP. This is probably the technically easiest thing to do.
Maybe this one will help you?
http://docs.meteor.com/#meteor_http_post