How can I get the port that Mojolicious::Lite chooses?
Asked Answered
P

2

8

Joel Berger posted this little program to start a web server to serve local files, and it works great:

use Mojolicious::Lite;

@ARGV = qw(daemon);

use Cwd;
app->static->paths->[0] = getcwd;

any '/' => sub {
    shift->render_static('index.html');
    };

app->start;

I prepopulated the command line in @ARGV because I forget to do that. When it starts, it gives a message telling you which port it chose, using 3000 if it can:

$ perl ~/bin/mojo_cwd
[Fri Mar 29 19:14:09 2013] [info] Listening at "http://*:3000".
Server available at http://127.0.0.1:3000.

I'd like to get that port programmatically so a test suite can know where to look for it, and I'd prefer not to do it by scrapping output. None of my experiments for this were useful and I think I was always going in the wrong direction. It appears that it doesn't choose the port until it starts, and once I call start, that's the end of it.

I don't want to specify the port myself, either.

This isn't an urgent matter. I have a current solution to this with another simple HTTP framework, but I've been looking at replacing most of that stuff with Mojo if I can. Since the old stuff still works, this is really just something nice to have rather than something in my way.

Perissodactyl answered 30/3, 2013 at 0:19 Comment(4)
It would be helpful if you'd post the code from which you are trying to get the port number - so that we can see what you are expecting mojolicious to expose and how.Mcbryde
All the code is right there. I want to run that script and know the port number. sri's answer is that it's always 3000 or nothing.Perissodactyl
that would've been easy to test: trying to start 2 app instances in parallel gives the error Can't create listen socket: Address already in use at ... - this shows that the default is the only port triedMcbryde
Lots of things are easy in hindsight.Perissodactyl
L
10

You can't, but the daemon command only binds to port 3000 and will not try anything else unless you tell it to. If you're using Test::Mojo you don't need to know the port in advance anyway, for anything else you can always wrap your application in a little Mojo::Server::Daemon script.

use Mojolicious::Lite;
use Mojo::IOLoop;
use Mojo::Server::Daemon;

get '/' => {text => 'Hello World!'};

my $port   = Mojo::IOLoop->generate_port;
my $daemon = Mojo::Server::Daemon->new(
  app    => app,
  listen => ["http://*:$port"]
);
$daemon->run;
Laurasia answered 1/4, 2013 at 11:47 Comment(1)
Okay, good to know. I'm not really creating a Mojo app. I'm using a very light server to test fetching some static files for web client code.Perissodactyl
M
7

With the --listen param you specify to your app where to listen:

use Mojolicious::Lite;

@ARGV = qw(daemon --listen http://*:5000);

use Cwd;
app->static->paths->[0] = getcwd;

any '/' => sub {
    shift->render_static('index.html');
    };

app->start;

You can access the port number within the app with $self->tx->local_port:

#!/usr/bin/env perl
use Mojolicious::Lite;

@ARGV = qw(daemon --listen http://*:5000);

use Cwd;
app->static->paths->[0] = getcwd;

any '/' => sub {
    my $self = shift;

    $self->render_text('port: '. $self->tx->local_port);
    };

app->start if $ENV{MOJO_MODE} ne 'test';

1;

I like to test Mojolicious apps with Test::Mojo because you get access to the running app, for example, in a file t/test_mojo.t:

use strict;
use warnings;

use feature 'say';

use Test::More;
use Test::Mojo;

$ENV{MOJO_MODE} = 'test';

require "$FindBin::Bin/../test_mojo.pl";

my $t = Test::Mojo->new;
$t->get_ok('/')->status_is(200)->content_is('port: '.$t->tx->remote_port);

say 'local port: '. $t->tx->local_port; #as seen from the user-agent's perspective
say 'remote port:'. $t->tx->remote_port;
done_testing();

I'm not sure I correctly understood what you are trying to accomplish, but I hope this helps you.

Mcbryde answered 31/3, 2013 at 6:47 Comment(2)
I specifically said that I didn't want to choose the port. I don't want to do the work to find an open port. Also, accessing the web server to get the port means I don't need to find out what the port is.Perissodactyl
Hmm... the OP's point about not wanting to manually choose the port... maybe use a random number generator, and test the target port, and if it's not in use, assign that one?Oenone

© 2022 - 2024 — McMap. All rights reserved.