diff --git a/.travis.yml b/.travis.yml index 194711c..925e64f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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 $! diff --git a/README.md b/README.md index f2018be..9b8fa90 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,37 @@ 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 @@ -34,7 +65,7 @@ Usage: hyper-run Example: - hyper-run -S localhost:8080 -s localhost:8081 + hyper-run -S localhost:8000 -s localhost:44300 [Required] -S ":" of an HTTP server. Multiple arguments can be accepted. @@ -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. diff --git a/hyper-run b/hyper-run index 8e0f0b5..a3e775b 100755 --- a/hyper-run +++ b/hyper-run @@ -30,7 +30,7 @@ Usage: $_SERVER[SCRIPT_NAME] Example: - $_SERVER[SCRIPT_NAME] -S localhost:8080 -s localhost:8081 + $_SERVER[SCRIPT_NAME] -S localhost:8000 -s localhost:44300 [Required] -S \":\" of an HTTP server. Multiple arguments can be accepted. @@ -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) { @@ -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)) { @@ -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]; } } @@ -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) { diff --git a/tests/unit/RemoteSimpleTest.php b/tests/unit/RemoteSimpleTest.php index cfb70d5..71d7beb 100644 --- a/tests/unit/RemoteSimpleTest.php +++ b/tests/unit/RemoteSimpleTest.php @@ -53,55 +53,55 @@ 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); @@ -109,7 +109,7 @@ public function testDelayedGroupDoubleAtOnce() 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);