As a chatbot developer, it is often necessary to run your chatbot locally and map localhost to the internet using ngrok. However, every time ngrok is started, the URL it generates changes, which can be a hassle when you need to update the endpoint for your chatbot in Azure. To solve this problem, we can implement an automated process that retrieves the ngrok endpoint and updates the Azure bot endpoint for us.
Here is a code snippet that does just that:
import axios from 'axios';
import { exec } from 'child_process';
const TestMode = process.argv.indexOf('test') > -1;
if (TestMode) {
console.log(`In Test Mode.`);
let ngrokEndpoint: string | null = null;
const TestInit = async () => {
try {
ngrokEndpoint = await tryFetchNgrokEndpoint();
console.log(`Successfully get ngrok endpoint: ${ngrokEndpoint}`);
exec(
`az bot update -n <YOUR_BOT_NAME> -g <YOUR_RESOURCE_GROUP_NAME> --endpoint "${ngrokEndpoint}/api/messages"`,
(err, stdout, stderr) => {
if (err) {
console.log(
`Failed to change test bot's endpoint: ${err}`
);
}
if (!err && !stderr && stdout) {
console.log(`Bot's endpoint is updated successfully!`);
}
if (stderr) {
console.log(
`Failed to change test bot's endpoint:: ${stderr}`
);
}
}
);
} catch (e) {}
};
const tryFetchNgrokEndpoint = async (): Promise<string> => {
return new Promise((resolve, reject) => {
let ngrokTunnelsAPI = 'http://127.0.0.1:4040/api/tunnels';
console.log(`Fetching ngrok endpoint from ${ngrokTunnelsAPI}...`);
axios
.get(ngrokTunnelsAPI)
.then((response) => {
resolve(response.data.tunnels[0].public_url);
})
.catch((err) => {
console.log(
`Failed to get the ngrok endpoint, will try again after 5s.`
);
setTimeout(async () => {
await TestInit();
}, 5000);
});
});
};
TestInit();
}
The code first checks if it is in the test environment by checking if the 'test' argument is passed to the script. However, you can also use other methods to determine if you are in the test environment, such as reading the process.env
or other methods. If it is in the test environment, it initializes the TestInit
function which attempts to retrieve the ngrok endpoint and update the bot endpoint in Azure. If the ngrok endpoint cannot be retrieved, the function will retry every 5 seconds until it succeeds. Upon success, a message will be logged to the console indicating that the bot endpoint has been updated successfully. If an error occurs, a message will be logged to the console with the error details.
To use this automated process, you will need to have the Azure CLI installed.
You will also need to replace the placeholder names <YOUR_BOT_NAME>
and <YOUR_RESOURCE_GROUP_NAME>
in the code snippet with the actual names of your chatbot and resource group.
This code can be inserted at the beginning of your main program file (such as app.ts
or server.ts
) so that it will be executed as soon as the program is run.
To ensure that ngrok
is running alone with your program, you can run the bot-dev script in your package.json
file. This script is written as powershell.exe -File .\\StartNgrok.ps1 && nodemon
, where the StartNgrok.ps1
script is defined as follows
Start-Process "ngrok.exe" -ArgumentList "http", "--host-header=rewrite", "3978"
It is important to use a PowerShell script to start ngrok.exe
in this manner rather than ngrok.exe http --host-header=rewrite 3978 && nodemon
because ngrok.exe
is a continuous running console and unless you manually end it, the subsequent nodemon will not have a chance to execute.
With this automated process in place, you can now simply run npm run bot-dev
during chatbot development to automatically start ngrok
(if it is not already running) and retrieve the ngrok endpoint. The Azure bot endpoint will then be updated with the retrieved ngrok endpoint, saving you the hassle of manually updating the endpoint every time you start ngrok
. Note that if ngrok
is already running, the additional instance started by npm run bot-dev
will automatically close.
I hope this helps make your chatbot development process a little bit easier!