Running a node.js file from website - javascript

I have recently started using the Twilio platform to send SMS to my users. I am perfectly able to run the node.js file from the node terminal with the command:
node twilio.js
Now, my goal is to be able to send those SMS, but from my website. For instance, when the user provides his phone number and presses the "Send sms" button. How can I achieve this? I have been looking this up for a while and I came across Express platform, ajax post requests, http server, etc. But, I can't figure out how to use them. I currently make many ajax requests (POST and GET) on my site, but I'm not able to make a request to a node file.
Thanks in advance,
Here is the twilio.js file:
// Twilio Credentials
var accountSid = 'ACCOUNT SID';
var authToken = 'ACCOUNT TOKEN';
//require the Twilio module and create a REST client
var client = require('twilio')(accountSid, authToken);
client.messages.create({
to: 'TO',
from: 'FROM',
body: 'Message sent from Twilio!',
}, function (err, message) {
console.log(message.sid);
});

Being able to run any arbitrary script on your server from a webpage would be a huge security risk - don't do that. I'm not sure where you're hosting your site, or what technology stack you're running your site on, but since you mentioned Express and Node -- if you're using Express I'd recommend that you setup a route that handles an ajax request. When someone presses 'Send SMS' you send an ajax request to that route, and in the handler that gets invoked you place the Twilio logic.

Here is a very simple way to setup an Express request that calls you node module:
twilio.js:
// Twilio Credentials
var accountSid = 'ACCOUNT SID';
var authToken = 'ACCOUNT TOKEN';
//require the Twilio module and create a REST client
var client = require('twilio')(accountSid, authToken);
function sendSms(callback) {
client.messages.create({
to: 'TO',
from: 'FROM',
body: 'Message sent from Twilio!',
}, callback);
}
// Export this function as a node module so that you can require it elsewhere
module.exports = sendSms;
Here is a good start for Express.
server.js:
var express = require('express');
var app = express();
// Requiring that function that you exported
var twilio = require('/path/to/twilio.js');
// Creating a controller for the get request: localhost:8081/send/sms
app.get('/send/sms', function (req, res) {
twilio(function(err, message) {
if (err) res.send(err);
res.send('Message sent: ' + message);
});
});
// Creating an HTTP server that listens on port 8081 (localhost:8081)
var server = app.listen(8081, function () {
var host = server.address().address;
var port = server.address().port;
console.log("Example app listening at http://%s:%s", host, port);
});
Then you can run node server.js, go to your browser and go to the url: localhost:8081/send/sms and your message will be sent :)

I'd make it so the client sends a HTTP POST request to the server, and then the server will send the message on behalf of the client.
Easiest way is to use express. I'm a bit unsure of how you're serving your website from a Node.js app without using express. Do you have a custom solution or only a non-connected from end, or something like heroku or something? In any case, you can create a route that processes posts with the following:
app.post("send_twilio_message_route", function(req,res){
// this receives the post request -- process here
});
^ Note that doesn't actually create the express app. See my link below and they give examples of some of the nitty gritty and syntax.
So the above would be on the server, in your Node.js app. From the front-end client code that runs in the browser, you need to create a post. The easiest way and most likely way to do it is through $.post in Jquery. if you are using Angular there's a slightly different syntax but it's the same idea. You call post, point it to a url, and put in the body data.
Make the body of the post request contain data such the message, phone numbers,
authentication token maybe.
See this to be able to get the body from a post request and some more implementation details of how to set it up:
How to retrieve POST query parameters?
Depending on the nature of what you're doing you might consider having the sms processing stuff run separate from the actual web service. I would create the sms unique stuff as its own module and have a function retrieve the router so that you can mount is onto the app and move it about later. This might be overkill if you're doing something small, but I'm basically encouraging you to at the start put thought into isolating your services of your website, else you will create a mess. That being said, if it's just a small thing and just for you it might not matter. Depends on your needs.
Important: I highly encourage you to think about the malicious user aka me. If you don't add any authentication in the post body (or you could include it in the url but I wouldn't do that although it's equivalent), a malicious client could totally be a jerk and expend all of your twilio resources. So once you get it basic up in running, before deploying it to anything that people will see it, I recommend you add authentication and rate limiting.

Related

Using Node.js to access data from a running executable program

I have a large program written in C# using Visual Studio that is running as a standalone executable complete with an extensive GUI interface. We want to add a web interface to the program in order to get most, if not all of the functionality available.
The first step I took was to add a web server to the C# executable and I linked in some web pages (html and css) and I was able to present some data as a test case and this worked.
We decided that it would be better to treat the standalone executable like a database where we would prefer to send requests to the get data and post data to store data.
I'm using Node.js framework and Express as my webserver. I have a number of web pages designed and I'm using javascript and some embedded javascript to render data on some of the web pages.
The issue I'm having is how do I process a selected route on one of my webpages to force the the .js file that is processing the route to go out and access the executable program that is running on the same computer at this moment to both get and set data in the executable program and then present it back on the web page.
HTML code (test_data_02.ejs)
<input class="LSNButton1" type="button" style="color:black; background:green;" value="Test Button B" onclick="window.location.href = '/get_test_02b'" />
Javascript (Express) (main.js)
const { json } = require("express");
const express = require("express"),
app = express(),
fs = require("fs"),
homeController = require("./controllers/homeController"),
errorController = require("./controllers/errorController"),
data_entry_03 = require("./public/js/data_entry_03"),
layouts = require("express-ejs-layouts");
app.set("view engine", "ejs");
app.use(layouts);
app.use(express.static("public")); //tell the application to use the corresponding public folder to serve static files
app.use(express.urlencoded({ //assists in reading body contents, parse incoming requests in url format
extended: false
}));
app.use(express.json()); //assists in reading body contents, parse incoming requests in json format
app.set("port", process.env.PORT || 3000);
console.log("MAIN MAIN MAIN"); //this only happens once on start up - this file is only executed on startup, everything is configured on startup
//MIDDLEWARE CODE
app.use((req, res, next) => { //this is a generic middleware function that will be called before any route is processed
homeController.middleWareFunction(req, res); //process this function before moving on to next route that was selected
//console.log(req.query); //from the browser: http://localhost:3000?cart3&jack=5, this results in a request to /?cart=3&jack=5, how do i make a post for this
console.log(`request made to: ${req.url}`);
console.log("");
next();
})
//app.use("/general_data", homeController.readDataFile); //run this function for every request made to the path beginning with this route - it does not imply it is a middleware that will run on this route before the get
//GET ROUTE CODE
app.get("/", homeController.showHome); //a specific route has been identified and the callback function assoicated with the particular route is specified
app.get("/specific_data", homeController.showSpecificData);
app.get("/general_data", homeController.showGeneralData);
app.get("/get_test_02b", homeController.getTest02B);
More Javascript (homeController.js)
I was hoping somewhere in 'getTest02B' or in 'getTestData02B' I would be able to send or request data from the executable program somehow. Maybe using a URL. I would obviously need to add code to my executable to process the requests to either send or receive data. I would like to be able to process the data as JSON, XML, or text data in both directions. I just can't see the mechanism to perform this operation.
exports.getTest02B = (req, res) => {
console.log("in exports.getTest02B");
displayInformation(req.url, "URL");
displayInformation(req.method, "METHOD");
displayEmptyLine();
getTestData02B(function (err, data) {
if (err)
return res.send(err);
res.send(data);
});
};
One comment on this issue was that I needed to make a http request to the C#
program. I understand that Node.js allows several connections per server to
make HTTP requests.
I'm using the code below and it is not working.
const req = http.request('http://192.168.1.222/ListAlarms.html', (res) => {
console.log('STATUS:${res.statusCode}');
});
req.end;
When I run this code there appears to be no response from the C# program.
From the editing environment where I wrote the code above, if I select the URL and press CONTROL and CLICK I end up launching another browser with the data being displayed because the C# program is currently running. This implies to me that at least the URL in the http.request statement is good. Just to confirm the URL was working I ran the C# program in the debugger and I was able to break on receiving the URL. The URL is good but I just can't seem to access the C# program from the Node.js environment using the same URL. Obviously I'm doing something wrong.
I assume that once I'm able to generate a http.request from the Node.js environment I would be able to control the flow of data to and from the C# program.
Any input would be appreciated.

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.

Understanding how to use Redis with Node.js and Server Sent Events

My Project is built with Nodejs as proxy server to communicate with an external API.
The API send product updates via Redis (pub/sub); The Proxy server handle the message and send it to the client via SSE (Server Sent Events).
It is the first time for me using Redis and SSE and looking online for tutorials seems to be easy to implement and I did it.
On the Client side I just created an EventSource and as soon as I receive an update I do something with it:
// Client Side
var source = new EventSource('/redis'); // /redis is path to proxy server
source.addEventListener('items', handleItemsCallback, false);
source.addEventListener('users', handleUsersCallback, false);
source.addEventListener('customers', handleCustomersCallback, false);
// Function sample...
function handleItemsCallback (msg) {
// Do something with msg...
}
In the Proxy server I created a controller with routing to /redis to handle Redis messages:
exports.redisUpdates = function (req, res) {
// Redis Authentication
var redisURL = url.parse(process.env.REDISCLOUD_URL);
var client = redis.createClient(redisURL.port, redisURL.hostname, {ignore_subscribe_messages: false});
client.auth(redisURL.auth.split(":")[1]);
// let request last as long as possible
req.socket.setTimeout(0);
// Subscribe to channels
client.subscribe('items', 'users', 'customers');
// Handle messages
client.on('message', function (channel, message) {
res.write('retry: 5000\n');
res.write('event: ' + channel + '\n');
res.write('data: ' + message + '\n\n');
res.flush(); // If I do not add this it doesn't push updates to the client (?)
});
//send headers for event-stream connection
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
res.write('\n');
};
Using it locally in a development environment it works fine but using it in Production generate several different errors, the App is hosted on Heroku and the Heroku Metrics show several H18, H12, H27 Errors;
Sometimes the /redis call return status 503;
What I wish to understand is if I'm using those services correctly, why all tutorials do not mention res.flush() and I discovered it by myself to let it work the first time...
In all fairness, this question is not really answerable for a few reasons. I don't know which tutorials you are talking about since you didn't reference any in the question. I cannot speak on behalf of those who wrote the unreferenced tutorials. They could just be wrong, or maybe the architecture of what you are trying to accomplish differs in some small way. I also don't know what framework or optional middleware you are using in your project.
Now, with all of that said there are a few things I can share that may help you out.
Most tutorials you find out there are probably not going to open a connection and read from the stream indefinitely. When the process ends, the http response is closed with .end() or something similar. Since an HTTP response is a write stream, it follows the same rules as any other stream. You can find a lot of good info about streams here:
https://github.com/substack/stream-handbook
Something important to understand is that a stream can have a buffer and most http frameworks enable compression which causes buffers to be used. The code sample in the next link is a good example of what a framework would do for you behind the scenes (a minimal implementation of course)
https://nodejs.org/en/docs/guides/anatomy-of-an-http-transaction/#what-we-ve-got-so-far
Since you want the output to continue being updated, you either have to wait until the output buffer size is reached or you have to call .flush().
If you ARE using express, check out this next Stack Overflow post related to compression middleware. I believe you'll have to have it disabled for your /redis route.
Node Express Content-Length
I hope that helped a little. Like I said, its kind of hard to answer this question. ;)

Where to add Socket.io logic in Sailjs project

I am new to sailjs and socket.io. I have gone through the samples in socket.io home page. Now I am confused where(in which file) to write the logic of socket connected, emitting messages and chat room management in a sailjs project. Is there any clean documentation on using socket.io with sailjs.
I have seen this tutorial but he is not demonstrated it using sailsjs, even though the subject says Building a Sails Application: Ep18 - Understanding Web Sockets and Socket IO Including Room Creation and Management.
Thanks for all the help.
You'll find all the documentation here: http://sailsjs.org/#!documentation/sockets
Out of the box, Sails handles Socket.io requests the same way it handles HTTP requests-- through the Express interface. It does this by creating a fake Express request and automatically routing the socket requests to the proper controller and action. For instance, here is a simple controller:
// api/controllers/EchoController.js
module.exports = {
index: function (req,res) {
// Get the value of a parameter
var param = req.param('message');
// Send a JSON response
res.json({
success: true,
message: param
});
}
};
Note the file EchoController.js which in this example is where the sockets are handled.

Categories

Resources