Skip to content

Commit 7b0b8ef

Browse files
committed
Updates
1 parent 4e1455c commit 7b0b8ef

16 files changed

+154
-150
lines changed

composer.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@
2424
"nette/php-generator": "^4.1",
2525
"revolt/event-loop": "^1.0",
2626
"amphp/websocket-server": "^4.0",
27-
"amphp/websocket-client": "^2.0",
28-
"amphp/http-server-router": "^2.0"
27+
"amphp/websocket-client": "^2.0"
2928
},
3029
"require-dev": {
3130
"laravel/pint": "^1.22",

src/Commands/Listen.php

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@
55
namespace Flat3\RevPi\Commands;
66

77
use Amp\Http\Server\DefaultErrorHandler;
8-
use Amp\Http\Server\Router;
98
use Amp\Http\Server\SocketHttpServer;
109
use Amp\Socket\InternetAddress;
1110
use Amp\Websocket\Server\Rfc6455Acceptor;
1211
use Amp\Websocket\Server\Websocket;
13-
use Flat3\RevPi\JsonRpc\JsonRpcDevice;
12+
use Flat3\RevPi\JsonRpc\ClientHandler;
1413
use Illuminate\Console\Command;
1514
use Psr\Log\LoggerInterface;
1615
use Revolt\EventLoop;
@@ -23,31 +22,23 @@ class Listen extends Command
2322

2423
public function handle(LoggerInterface $logger): void
2524
{
26-
$server = SocketHttpServer::createForDirectAccess($logger);
2725
$address = $this->option('address');
2826
assert(is_string($address));
2927

3028
/** @var int<0, 65535> $port */
3129
$port = (int) $this->option('port');
30+
31+
$server = SocketHttpServer::createForDirectAccess($logger);
3232
$server->expose(new InternetAddress($address, $port));
3333

34-
$router = new Router($server, $logger, new DefaultErrorHandler);
35-
36-
$router->addRoute(
37-
method: 'GET',
38-
uri: '/',
39-
requestHandler: new Websocket(
40-
httpServer: $server,
41-
logger: $logger,
42-
acceptor: app(Rfc6455Acceptor::class),
43-
clientHandler: app(JsonRpcDevice::class),
44-
)
34+
$socket = new Websocket(
35+
httpServer: $server,
36+
logger: $logger,
37+
acceptor: app(Rfc6455Acceptor::class),
38+
clientHandler: app(ClientHandler::class),
4539
);
4640

47-
$server->start(
48-
$router,
49-
new DefaultErrorHandler
50-
);
41+
$server->start($socket, new DefaultErrorHandler);
5142

5243
EventLoop::run();
5344
}

src/Hardware/Local/LocalDevice.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ class LocalDevice implements Device
1313

1414
protected ?int $fd = null;
1515

16+
protected string $pathname;
17+
1618
public function __construct()
1719
{
1820
$this->ffi = FFI::cdef(<<<'EOF'
@@ -34,6 +36,7 @@ public function __construct()
3436

3537
public function open(string $pathname, int $flags): int
3638
{
39+
$this->pathname = $pathname;
3740
if ($this->fd !== null) {
3841
return 0;
3942
}

src/Hardware/Remote/RemoteBlockDevice.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ abstract class RemoteBlockDevice extends RemoteDevice implements Seek
1010
{
1111
public function lseek(int $offset, int $whence): int
1212
{
13-
return (int) $this->peer->request('lseek', ['offset' => $offset, 'whence' => $whence])->await();
13+
return (int) $this->device->request('lseek', ['offset' => $offset, 'whence' => $whence])->await();
1414
}
1515
}

src/Hardware/Remote/RemoteCharacterDevice.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ public function __construct(JsonRpcDevice $peer)
3030

3131
public function fdopen(): mixed
3232
{
33-
$this->peer->request('fdopen')->await();
33+
$this->device->request('fdopen')->await();
3434

35-
$this->peer->on('readable', function (string $payload) {
35+
$this->device->on('readable', function (string $payload) {
3636
fwrite($this->remote, $payload);
3737
});
3838

src/Hardware/Remote/RemoteDevice.php

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,43 +9,46 @@
99
use Flat3\RevPi\Interfaces\Hardware\Ioctl;
1010
use Flat3\RevPi\JsonRpc\JsonRpcDevice;
1111

12+
use function Amp\async;
13+
1214
abstract class RemoteDevice implements Device, Ioctl
1315
{
14-
public function __construct(protected JsonRpcDevice $peer) {}
16+
public function __construct(protected JsonRpcDevice $device) {}
1517

1618
public function socket(WebsocketClient $websocket): void
1719
{
18-
$this->peer->withSocket($websocket);
20+
$this->device->attachSocket($websocket);
21+
async(fn () => $this->device->loop());
1922
}
2023

2124
public function open(string $pathname, int $flags): int
2225
{
23-
return (int) $this->peer->request('open', ['pathname' => $pathname, 'flags' => $flags])->await();
26+
return (int) $this->device->request('open', ['pathname' => $pathname, 'flags' => $flags])->await();
2427
}
2528

2629
public function close(): int
2730
{
28-
return (int) $this->peer->request('close')->await();
31+
return (int) $this->device->request('close')->await();
2932
}
3033

3134
public function read(string &$buffer, int $count): int
3235
{
3336
/** @var array{buffer: string, return: int} $response */
34-
$response = $this->peer->request('read', ['buffer' => $buffer, 'count' => $count])->await();
37+
$response = $this->device->request('read', ['buffer' => $buffer, 'count' => $count])->await();
3538
$buffer = $response['buffer'];
3639

3740
return $response['return'];
3841
}
3942

4043
public function write(string $buffer, int $count): int
4144
{
42-
return (int) $this->peer->request('write', ['buffer' => $buffer, 'count' => $count])->await();
45+
return (int) $this->device->request('write', ['buffer' => $buffer, 'count' => $count])->await();
4346
}
4447

4548
public function ioctl(int $request, ?string &$argp = null): int
4649
{
4750
/** @var array{argp: ?string, return: int} $response */
48-
$response = $this->peer->request('ioctl', ['request' => $request, 'argp' => $argp])->await();
51+
$response = $this->device->request('ioctl', ['request' => $request, 'argp' => $argp])->await();
4952

5053
$argp = $response['argp'];
5154

src/Hardware/Remote/RemoteTerminalDevice.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ class RemoteTerminalDevice extends RemoteCharacterDevice implements Terminal
1111
public function cfgetispeed(string &$buffer): int
1212
{
1313
/** @var array{buffer: string, return: int} $response */
14-
$response = $this->peer->request('cfgetispeed', ['buffer' => $buffer])->await();
14+
$response = $this->device->request('cfgetispeed', ['buffer' => $buffer])->await();
1515
$buffer = $response['buffer'];
1616

1717
return $response['return'];
@@ -20,7 +20,7 @@ public function cfgetispeed(string &$buffer): int
2020
public function cfgetospeed(string &$buffer): int
2121
{
2222
/** @var array{buffer: string, return: int} $response */
23-
$response = $this->peer->request('cfgetospeed', ['buffer' => $buffer])->await();
23+
$response = $this->device->request('cfgetospeed', ['buffer' => $buffer])->await();
2424
$buffer = $response['buffer'];
2525

2626
return $response['return'];
@@ -29,7 +29,7 @@ public function cfgetospeed(string &$buffer): int
2929
public function cfsetispeed(string &$buffer, int $speed): int
3030
{
3131
/** @var array{buffer: string, return: int} $response */
32-
$response = $this->peer->request('cfsetispeed', ['buffer' => $buffer, 'speed' => $speed])->await();
32+
$response = $this->device->request('cfsetispeed', ['buffer' => $buffer, 'speed' => $speed])->await();
3333
$buffer = $response['buffer'];
3434

3535
return $response['return'];
@@ -38,24 +38,24 @@ public function cfsetispeed(string &$buffer, int $speed): int
3838
public function cfsetospeed(string &$buffer, int $speed): int
3939
{
4040
/** @var array{buffer: string, return: int} $response */
41-
$response = $this->peer->request('cfsetospeed', ['buffer' => $buffer, 'speed' => $speed])->await();
41+
$response = $this->device->request('cfsetospeed', ['buffer' => $buffer, 'speed' => $speed])->await();
4242
$buffer = $response['buffer'];
4343

4444
return $response['return'];
4545
}
4646

4747
public function tcflush(int $queue_selector): int
4848
{
49-
return (int) $this->peer->request('tcflush', ['queue_selector' => $queue_selector])->await();
49+
return (int) $this->device->request('tcflush', ['queue_selector' => $queue_selector])->await();
5050
}
5151

5252
public function tcdrain(): int
5353
{
54-
return (int) $this->peer->request('tcdrain')->await();
54+
return (int) $this->device->request('tcdrain')->await();
5555
}
5656

5757
public function tcsendbreak(int $duration = 0): int
5858
{
59-
return (int) $this->peer->request('tcsendbreak', ['duration' => $duration])->await();
59+
return (int) $this->device->request('tcsendbreak', ['duration' => $duration])->await();
6060
}
6161
}

src/JsonRpc/ClientHandler.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Flat3\RevPi\JsonRpc;
6+
7+
use Amp\Http\Server\Request;
8+
use Amp\Http\Server\Response;
9+
use Amp\Websocket\Server\WebsocketClientHandler;
10+
use Amp\Websocket\WebsocketClient;
11+
use Flat3\RevPi\Exceptions\NotImplementedException;
12+
use Flat3\RevPi\Interfaces\Hardware\PiControl;
13+
use Flat3\RevPi\Interfaces\Hardware\Terminal;
14+
15+
class ClientHandler implements WebsocketClientHandler
16+
{
17+
public function handleClient(WebsocketClient $client, Request $request, Response $response): void
18+
{
19+
$target = match ($request->getQueryParameter('device')) {
20+
'picontrol' => app(PiControl::class),
21+
'terminal' => app(Terminal::class),
22+
default => throw new NotImplementedException,
23+
};
24+
25+
$handler = app(JsonRpcDevice::class);
26+
$handler->setDevice($target);
27+
28+
$handler->attachSocket($client);
29+
$handler->loop();
30+
}
31+
}

src/JsonRpc/Event.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
namespace Flat3\RevPi\JsonRpc;
66

77
/**
8-
* @phpstan-import-type JsonRpcEventT from JsonRpcPeer
9-
* @phpstan-import-type JsonRpcEventTypeT from JsonRpcPeer
8+
* @phpstan-import-type JsonRpcEventT from JsonRpcHandler
9+
* @phpstan-import-type JsonRpcEventTypeT from JsonRpcHandler
1010
*/
1111
class Event
1212
{

src/JsonRpc/JsonRpcDevice.php

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,29 @@
44

55
namespace Flat3\RevPi\JsonRpc;
66

7-
use Amp\Http\Server\Request;
8-
use Amp\Http\Server\Response;
9-
use Amp\Websocket\WebsocketClient;
7+
use Amp\Websocket\WebsocketClosedException;
108
use Flat3\RevPi\Constants;
119
use Flat3\RevPi\Exceptions\NotImplementedException;
1210
use Flat3\RevPi\Interfaces\Hardware\Device;
1311
use Flat3\RevPi\Interfaces\Hardware\Ioctl;
14-
use Flat3\RevPi\Interfaces\Hardware\PiControl;
1512
use Flat3\RevPi\Interfaces\Hardware\Seek;
1613
use Flat3\RevPi\Interfaces\Hardware\Stream;
1714
use Flat3\RevPi\Interfaces\Hardware\Terminal;
1815
use Revolt\EventLoop;
1916

2017
/**
21-
* @phpstan-import-type JsonRpcDeviceMethodT from JsonRpcPeer
22-
* @phpstan-import-type JsonRpcResponseResultT from JsonRpcPeer
18+
* @phpstan-import-type JsonRpcDeviceMethodT from JsonRpcHandler
19+
* @phpstan-import-type JsonRpcResponseResultT from JsonRpcHandler
2320
*/
24-
class JsonRpcDevice extends JsonRpcPeer
21+
class JsonRpcDevice extends JsonRpcHandler
2522
{
2623
protected Device $device;
2724

25+
public function setDevice(Device $device): void
26+
{
27+
$this->device = $device;
28+
}
29+
2830
/**
2931
* @param JsonRpcDeviceMethodT $method
3032
* @param array<string, int|string|null> $params
@@ -140,11 +142,15 @@ protected function invoke(string $method, array $params): mixed
140142
$data = @fread($stream, Constants::BlockSize);
141143

142144
if (is_string($data) && $data !== '') {
143-
$request = new Event;
144-
$request->type = 'readable';
145-
$request->payload = $data;
146-
147-
$this->socket->sendBinary(serialize($request));
145+
$event = new Event;
146+
$event->type = 'readable';
147+
$event->payload = $data;
148+
149+
try {
150+
$this->socket->sendBinary(serialize($event));
151+
} catch (WebsocketClosedException) {
152+
EventLoop::cancel($callbackId);
153+
}
148154
} elseif (! is_resource($stream) || @feof($stream)) {
149155
EventLoop::cancel($callbackId);
150156
}
@@ -155,15 +161,4 @@ protected function invoke(string $method, array $params): mixed
155161

156162
throw new NotImplementedException; // @phpstan-ignore deadCode.unreachable
157163
}
158-
159-
public function handleClient(WebsocketClient $client, Request $request, Response $response): void
160-
{
161-
$this->device = match ($request->getQueryParameter('device')) {
162-
'picontrol' => app(PiControl::class),
163-
'terminal' => app(Terminal::class),
164-
default => throw new NotImplementedException,
165-
};
166-
167-
parent::handleClient($client, $request, $response);
168-
}
169164
}

0 commit comments

Comments
 (0)