ngrok / ngrok-javascript

Embed ngrok secure ingress into your Node.js apps with a single line of code.
https://ngrok.com
Apache License 2.0
86 stars 17 forks source link

Create listener, if there is not already one there #97

Closed alexbjorlig closed 8 months ago

alexbjorlig commented 8 months ago

I have this code

const ngrokSdk = await import('@ngrok/ngrok');

const listener = await ngrokSdk.connect({
    addr: "http://localhost:3000",
    authtoken: '<my-token>',
});

It creates a listener as expected. But how would I protect against creating another listener on the same address (if there is already one there?)

bobzilladev commented 8 months ago

Hello, thanks for the question! If two listeners were created they would co-exist, both forwarding from their internet url to the localhost:3000 upstream. To check if one exists already, a call to listeners() will retrieve the list of currently active listeners. The optional fields forwards_to or metadata could be used to indicate what the listener is forwarding to, and then that information could be used to not create a duplicate. For example:

// create with forwards_to and/or metadata
const listener = await ngrokSdk.connect({
    addr: "http://localhost:3000",
    authtoken_from_env: true,
    forwards_to: 'http://localhost:3000',
    metadata: 'http://localhost:3000',
});
console.log(`Ingress established at: ${listener.url()}`);

// elsewhere
for (ls of await ngrokSdk.listeners()) {
    console.log(`listener forwardsTo: '${ls.forwardsTo()}' metadata: '${ls.metadata()}'`);
}

Hopefully that is helpful, let us know if you have more questions!

alexbjorlig commented 8 months ago

Hello, thanks for the question! If two listeners were created they would co-exist, both forwarding from their internet url to the localhost:3000 upstream. To check if one exists already, a call to listeners() will retrieve the list of currently active listeners. The optional fields forwards_to or metadata could be used to indicate what the listener is forwarding to, and then that information could be used to not create a duplicate. For example:

// create with forwards_to and/or metadata
const listener = await ngrokSdk.connect({
    addr: "http://localhost:3000",
    authtoken_from_env: true,
    forwards_to: 'http://localhost:3000',
    metadata: 'http://localhost:3000',
});
console.log(`Ingress established at: ${listener.url()}`);

// elsewhere
for (ls of await ngrokSdk.listeners()) {
    console.log(`listener forwardsTo: '${ls.forwardsTo()}' metadata: '${ls.metadata()}'`);
}

Hopefully that is helpful, let us know if you have more questions!

Ok, that was more or less what I thought. I did try something similar, but to my surprise ls.forwardsTo() gave something like app://Alexs-MacBook-Air.local//Users/alexbjorlig/.nvm/versions/node/v18.17.1/bin/node?pid=95176 - nothing indicating the port.

But I guess that's why you included forwards_to and metadata in the connect() call.

Another question regarding the pricing/limits. If I use this approach:

  1. How many listeners can I add from a machine running tests in parallel (isolated processes)
  2. What if developers are on separate machines, how many can use the same authorization token?
bobzilladev commented 8 months ago

Aye, by default the forwards_to is filled in with what process is being forwarded to from ngrok, so one level higher up in the chain.

On pricing/limits:

  1. As coded here, each listener will set up an internet endpoint with an ephemeral domain. The Free and Personal plans allow for one agent and endpoint, the Pro and Enterprise plans allow one per seat.
  2. Different machines can use the same auth token, or multiple auth tokens can be generated for the same account using Team Members or Bot Users.

Full details are on this pricing page: https://ngrok.com/pricing

alexbjorlig commented 8 months ago

Ok great.

This is where ngrok pricing for me is a bit hard to understand.

I'm only interested in scenario 2, different machines using the same auth token that belongs to a bot user.

  1. But what are the limits for that bot user then - is it this part of the pricing page?
  2. What exactly is an "agent" and what is a "tunnel"?
  3. If 3 machines in CI uses the same bot user token, is that 3 agents or 3 tunnels?

CleanShot 2023-10-25 at 19 51 28@2x

bobzilladev commented 8 months ago

Sure thing, answering each of these in line:

But what are the limits for that bot user then - is it this part of the pricing page?

The limits are for the account overall, not for any certain auth token or user on that account.

What exactly is an "agent" and what is a "tunnel"?

If 3 machines in CI uses the same bot user token, is that 3 agents or 3 tunnels?

That would be 3 agents and 3 tunnels.

alexbjorlig commented 8 months ago

That would be 3 agents and 3 tunnels.

Ok, then I don't think I can do what I was trying to accomplish 😢

My vision is this:

Certain routes in our web application only work with Ngrok (or a similar service), when running locally (because it's the only way external services can get access to the project served locally). I would like to make it easy for our developers to work with our project, and I don't want them to sign up for Ngrok, or for that matter understand any of that complexity. I would simply like to manage all of that, by using the ngrok-nodejs sdk when needed, and create the tunnels that are applicable. And I would very much like this to also be the case when running integration tests in CI.

What Ngrok license method should I go for? - thanks 🙏

samcrichard commented 8 months ago

Hey alex! I manage pricing at ngrok. I can help you if you'd like to email me at sam at ngrok.com

bobzilladev commented 8 months ago

I think the technical questions have been answered, and @samcrichard is handling the others, so I'll close out this issue. Thank you for your feedback, this is always helpful! Feel free to open new issues if other things come up.