Skip to content

Commit

Permalink
Merge pull request #14 from cybercog/try-to-start-on-next-free-port
Browse files Browse the repository at this point in the history
Start server on the next unoccupied port
  • Loading branch information
antonkomarev authored Jun 2, 2020
2 parents b22fb76 + 63de67b commit 14a24b6
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 34 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ cache:
- $HOME/.composer/cache

script:
- ./hyper-run -S localhost:8080 -s localhost:8081 -n 5 -t examples &
- ./hyper-run -S localhost:8000 -s localhost:44300 -n 5 -t examples &
- vendor/bin/codecept run unit
- kill $!

Expand Down
46 changes: 32 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,45 @@ Use **`vendor/bin/hyper-run`** as the execution path.

## Usage

### Quick start

```shell script
hyper-run -S localhost -s localhost -t src/app/www
```

2 servers will start with the directory `src/app/www` as the document root:

- `http://localhost:8000`
- `https://localhost:44300`

Servers start with first unoccupied port within range depending on a scheme.

| Scheme | Default | Range |
| ------- | ------- | ----------- |
| `HTTP` | 8000 | 8000-8099 |
| `HTTPS` | 44300 | 44300-44399 |

### Customize ports

```shell script
hyper-run -S localhost:8080 -s localhost:4000 -t src/app/www
```

2 servers will start with the directory `src/app/www` as the document root:

- `http://localhost:8080`
- `https://localhost:4000`

### Command Reference

```ShellSession
mpyw@localhost:~$ hyper-run -h

Usage:
hyper-run <options>

Example:
hyper-run -S localhost:8080 -s localhost:8081
hyper-run -S localhost:8000 -s localhost:44300

[Required]
-S "<Host>:<Port>" of an HTTP server. Multiple arguments can be accepted.
Expand All @@ -54,19 +85,6 @@ Restrictions:
mpyw@localhost:~$
```

## Example

```shell script
hyper-run -S localhost:8080 -s localhost:8081 -t src/app/www
```

It listens on

- `http://localhost:8080`
- `https://localhost:8081`

using the directory `src/app/www` as the document root.

## Note for Windows users

Unfortunately, `cmd.exe` has no option to run via shebang `#!/usr/bin/env php`, so you need to create the following batch file in the proper directory.
Expand Down
50 changes: 41 additions & 9 deletions hyper-run
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Usage:
$_SERVER[SCRIPT_NAME] <options>
Example:
$_SERVER[SCRIPT_NAME] -S localhost:8080 -s localhost:8081
$_SERVER[SCRIPT_NAME] -S localhost:8000 -s localhost:44300
[Required]
-S \"<Host>:<Port>\" of an HTTP server. Multiple arguments can be accepted.
Expand Down Expand Up @@ -72,6 +72,35 @@ if (!$servers && !$secures) {
exit(1);
}

function startListener($master, $listener)
{
$host = sprintf(
'%s://%s:%s',
$listener[2] ? 'https' : 'http', $listener[0], $listener[1]
);
fwrite(STDOUT, "Development server started: <{$host}>\n");

try {
call_user_func_array([$master, 'addListener'], $listener);
} catch (React\Socket\ConnectionException $exception) {
$reason = 'Address already in use';

$isPortSpecified = $listener[4];

if ($isPortSpecified || strpos($exception->getMessage(), $reason) === false) {
throw $exception;
}

fwrite(STDERR, sprintf(
"Failed to listen on %s:%s (reason: %s)\n",
$listener[0], $listener[1], $reason
));

$listener[1] = (int) $listener[1] + 1;
startListener($master, $listener);
}
}

try {

if (!ctype_digit($number) || $number < 1 || $number > 20) {
Expand All @@ -92,8 +121,17 @@ try {

$listeners = [];
foreach ([$servers, $secures] as $type => $group) {
$isSecure = $type === 1;
foreach ($group as $i => $server) {
list($host, $port) = explode(':', $server, 2) + [1 => ''];

if ($port === '') {
$port = $isSecure ? '44300' : '8000';
$isPortSpecified = false;
} else {
$isPortSpecified = true;
}

$ip = filter_var(gethostbyname($host), FILTER_VALIDATE_IP, FILTER_FLAG_IPV4);
$regex = '/\A(?:[0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])\z/';
if ($ip === false || !preg_match($regex, $port)) {
Expand All @@ -102,7 +140,7 @@ try {
if (isset($listeners[$server])) {
throw new \RuntimeException("Duplicated entry: $server");
}
$listeners[$server] = [$host, $port, $type === 1, $cert];
$listeners[$server] = [$host, $port, $isSecure, $cert, $isPortSpecified];
}
}

Expand All @@ -116,13 +154,7 @@ try {
$usedProcesses = $processes;
$master = new mpyw\HyperBuiltinServer\Master($loop, $processes);
foreach ($listeners as $listener) {
call_user_func_array([$master, 'addListener'], $listener);

$host = sprintf(
'%s://%s:%s',
$listener[2] ? 'https' : 'http', $listener[0], $listener[1]
);
fwrite(STDOUT, "Development server started: <{$host}>\n");
startListener($master, $listener);
}
})
->then(null, function ($e) use (&$usedProcesses) {
Expand Down
20 changes: 10 additions & 10 deletions tests/unit/RemoteSimpleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,63 +53,63 @@ private function curlsAssert200OK(array $curls)

public function testSimple()
{
Co::wait($ch = $this->curlInitWith('http://localhost:8080/upload_form.php'));
Co::wait($ch = $this->curlInitWith('http://localhost:8000/upload_form.php'));
$this->curlAssert200OK($ch);
}

public function testSimpleSecure()
{
Co::wait($ch = $this->curlInitWith('https://localhost:8081/upload_form.php'));
Co::wait($ch = $this->curlInitWith('https://localhost:44300/upload_form.php'));
$this->curlAssert200OK($ch);
}

public function testDelayed()
{
Co::wait($ch = $this->curlInitWith('http://localhost:8080/fast_hello.php'));
Co::wait($ch = $this->curlInitWith('http://localhost:8000/fast_hello.php'));
$this->curlAssert200OK($ch);
}

public function testDelayedSecure()
{
Co::wait($ch = $this->curlInitWith('https://localhost:8081/fast_hello.php'));
Co::wait($ch = $this->curlInitWith('https://localhost:44300/fast_hello.php'));
$this->curlAssert200OK($ch);
}

public function testDelayedGroupSingle()
{
Co::wait($chs = $this->curlsInitWith(5, 'http://localhost:8080/fast_hello.php'));
Co::wait($chs = $this->curlsInitWith(5, 'http://localhost:8000/fast_hello.php'));
$this->curlsAssert200OK($chs);
}

public function testDelayedGroupSingleSecure()
{
Co::wait($chs = $this->curlsInitWith(5, 'https://localhost:8081/fast_hello.php'));
Co::wait($chs = $this->curlsInitWith(5, 'https://localhost:44300/fast_hello.php'));
$this->curlsAssert200OK($chs);
}

public function testDelayedGroupDouble()
{
Co::wait($chs = $this->curlsInitWith(10, 'http://localhost:8080/fast_hello.php'));
Co::wait($chs = $this->curlsInitWith(10, 'http://localhost:8000/fast_hello.php'));
$this->curlsAssert200OK($chs);
}

public function testDelayedGroupDoubleSecure()
{
Co::wait($chs = $this->curlsInitWith(10, 'https://localhost:8081/fast_hello.php'));
Co::wait($chs = $this->curlsInitWith(10, 'https://localhost:44300/fast_hello.php'));
$this->curlsAssert200OK($chs);
}

public function testDelayedGroupDoubleAtOnce()
{
Co::wait($chs = $this->curlsInitWith(10, 'http://localhost:8080/fast_hello.php'), [
Co::wait($chs = $this->curlsInitWith(10, 'http://localhost:8000/fast_hello.php'), [
'concurrency' => 0,
]);
$this->curlsAssert200OK($chs);
}

public function testDelayedGroupDoubleAtOnceSecure()
{
Co::wait($chs = $this->curlsInitWith(10, 'https://localhost:8081/fast_hello.php'), [
Co::wait($chs = $this->curlsInitWith(10, 'https://localhost:44300/fast_hello.php'), [
'concurrency' => 0,
]);
$this->curlsAssert200OK($chs);
Expand Down

0 comments on commit 14a24b6

Please sign in to comment.