Skip to content

Commit

Permalink
Merge 71fc949 into 6f11a13
Browse files Browse the repository at this point in the history
  • Loading branch information
kelunik committed Jun 14, 2017
2 parents 6f11a13 + 71fc949 commit f4fe067
Show file tree
Hide file tree
Showing 28 changed files with 1,533 additions and 657 deletions.
1 change: 0 additions & 1 deletion .coveralls.yml

This file was deleted.

45 changes: 17 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
![Unstable](https://img.shields.io/badge/api-unstable-orange.svg?style=flat-square)
![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)


`amphp/socket` is a socket lib for establishing and encrypting non-blocking sockets in the [`amp`](https://github.com/amphp/amp)
concurrency framework.
`amphp/socket` is a socket library for establishing and encrypting non-blocking sockets for [Amp](https://github.com/amphp/amp).

**Required PHP Version**

Expand All @@ -16,38 +14,29 @@ concurrency framework.
**Installation**

```bash
$ composer require amphp/socket: dev-master
composer require amphp/socket
```

**Example**

```php
<?php // basic server
<?php // basic server, see examples/simple-http-server.php

require __DIR__ . '/vendor/autoload.php';
require __DIR__ . '/../vendor/autoload.php';

use Amp as amp;
use Amp\Socket as socket;
use Amp\Loop;
use Amp\Socket\ServerSocket;

amp\execute(function () {
$socket = socket\listen("tcp://127.0.0.1:1337");
$server = new socket\Server($socket);
echo "listening for new connections ...\n";
while ($client = yield $server->accept()) {
new amp\Coroutine(onClient($client));
}
});
Loop::run(function () {
$server = Amp\Socket\listen("tcp://127.0.0.1:0", function (ServerSocket $socket) {
list($ip, $port) = explode(":", $socket->getRemoteAddress());

$body = "Hey, your IP is {$ip} and your local port used is {$port}.";
$bodyLength = \strlen($body);

// Generator coroutine is a lightweight "thread" for each client
function onClient(socket\Client $client) {
$clientId = $client->id();
echo "+ connected: {$clientId}\n";
while ($client->alive()) {
$data = yield $client->readLine();
echo "data read from {$clientId}: {$data}\n";
$bytes = yield $client->write("echo: {$data}\n");
echo "{$bytes} written to client {$clientId}\n";
}
echo "- disconnected {$clientId}\n";
}
yield $socket->end("HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: {$bodyLength}\r\n\r\n{$body}");
});

echo "Listening for new connections on " . $server->getAddress() . " ...\n";
});
```
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"amphp/byte-stream": "dev-master as 0.1"
},
"require-dev": {
"amphp/phpunit-util": "dev-master",
"phpunit/phpunit": "^6",
"friendsofphp/php-cs-fixer": "^2.3"
},
Expand Down
Binary file added core
Binary file not shown.
19 changes: 19 additions & 0 deletions examples/simple-http-server.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php // basic server

require __DIR__ . '/../vendor/autoload.php';

use Amp\Loop;
use Amp\Socket\ServerSocket;

Loop::run(function () {
$server = Amp\Socket\listen("tcp://127.0.0.1:0", function (ServerSocket $socket) {
list($ip, $port) = explode(":", $socket->getRemoteAddress());

$body = "Hey, your IP is {$ip} and your local port used is {$port}.";
$bodyLength = \strlen($body);

yield $socket->end("HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: {$bodyLength}\r\n\r\n{$body}");
});

echo "Listening for new connections on " . $server->getAddress() . " ...\n";
});
64 changes: 64 additions & 0 deletions lib/ClientConnectContext.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php

namespace Amp\Socket;

use function Amp\Socket\Internal\normalizeBindToOption;

final class ClientConnectContext {
private $bindTo = null;
private $connectTimeout = 10000;
private $maxAttempts = 2;

public function withBindTo(string $bindTo = null): self {
$bindTo = normalizeBindToOption($bindTo);

$clone = clone $this;
$clone->bindTo = $bindTo;

return $clone;
}

public function getBindTo() {
return $this->bindTo;
}

public function withConnectTimeout(int $timeout): self {
if ($timeout <= 0) {
throw new \Error("Invalid connect timeout ({$timeout}), must be greater than 0");
}

$clone = clone $this;
$clone->connectTimeout = $timeout;

return $clone;
}

public function getConnectTimeout(): int {
return $this->connectTimeout;
}

public function withMaxAttempts(int $maxAttempts): self {
if ($maxAttempts <= 0) {
throw new \Error("Invalid max attempts ({$maxAttempts}), must be greater than 0");
}

$clone = clone $this;
$clone->maxAttempts = $maxAttempts;

return $clone;
}

public function getMaxAttempts(): int {
return $this->maxAttempts;
}

public function toStreamContextArray(): array {
$options = [];

if ($this->bindTo !== null) {
$options["bindto"] = $this->bindTo;
}

return ["socket" => $options];
}
}
41 changes: 23 additions & 18 deletions lib/Socket.php → lib/ClientSocket.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@
use Amp\ByteStream\ResourceOutputStream;
use Amp\Failure;
use Amp\Promise;
use function Amp\Socket\Internal\cleanupSocketName;

class Socket implements InputStream, OutputStream {
class ClientSocket implements InputStream, OutputStream {
/** @var \Amp\ByteStream\ResourceInputStream */
private $reader;

Expand Down Expand Up @@ -38,50 +39,46 @@ public function getResource() {
}

/**
* @see \Amp\Socket\enableCrypto()
* Enables encryption on this socket.
*
* @param array $options
* @param ClientTlsContext $tlsContext
*
* @return \Amp\Promise
* @return Promise
*/
public function enableCrypto(array $options = []): Promise {
public function enableCrypto(ClientTlsContext $tlsContext = null): Promise {
if (($resource = $this->reader->getResource()) === null) {
return new Failure(new ClosedException("The socket has been closed"));
}

return enableCrypto($resource, $options);
$tlsContext = $tlsContext ?? new ClientTlsContext;

return Internal\enableCrypto($resource, $tlsContext->toStreamContextArray());
}

/**
* @see \Amp\Socket\disableCrypto()
* Disables encryption on this socket.
*
* @return \Amp\Promise
* @return Promise
*/
public function disableCrypto(): Promise {
if (($resource = $this->reader->getResource()) === null) {
return new Failure(new ClosedException("The socket has been closed"));
}

return disableCrypto($resource);
return Internal\disableCrypto($resource);
}

/**
* {@inheritdoc}
*/
/** @inheritdoc */
public function read(): Promise {
return $this->reader->read();
}

/**
* {@inheritdoc}
*/
/** @inheritdoc */
public function write(string $data): Promise {
return $this->writer->write($data);
}

/**
* {@inheritdoc}
*/
/** @inheritdoc */
public function end(string $data = ""): Promise {
$promise = $this->writer->end($data);
$promise->onResolve(function () {
Expand All @@ -98,4 +95,12 @@ public function close() {
$this->reader->close();
$this->writer->close();
}

public function getLocalAddress() {
return cleanupSocketName(@\stream_socket_get_name($this->getResource(), false));
}

public function getRemoteAddress() {
return cleanupSocketName(@\stream_socket_get_name($this->getResource(), true));
}
}
Loading

0 comments on commit f4fe067

Please sign in to comment.