Skip to content

Commit c081413

Browse files
committed
Updates
1 parent ae354b5 commit c081413

File tree

5 files changed

+186
-159
lines changed

5 files changed

+186
-159
lines changed

src/Commands/Listen.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
use Amp\Socket\InternetAddress;
1111
use Amp\Websocket\Server\Rfc6455Acceptor;
1212
use Amp\Websocket\Server\Websocket;
13-
use Flat3\RevPi\JsonRpc\JsonRpcPeer;
13+
use Flat3\RevPi\JsonRpc\JsonRpcDevice;
1414
use Illuminate\Console\Command;
1515
use Psr\Log\LoggerInterface;
1616
use Revolt\EventLoop;
@@ -40,7 +40,7 @@ public function handle(LoggerInterface $logger): void
4040
httpServer: $server,
4141
logger: $logger,
4242
acceptor: app(Rfc6455Acceptor::class),
43-
clientHandler: app(JsonRpcPeer::class),
43+
clientHandler: app(JsonRpcDevice::class),
4444
)
4545
);
4646

src/Hardware/Remote/RemoteCharacterDevice.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use Flat3\RevPi\Constants;
88
use Flat3\RevPi\Interfaces\Hardware\Stream;
99
use Flat3\RevPi\JsonRpc\Event;
10-
use Flat3\RevPi\JsonRpc\JsonRpcPeer;
10+
use Flat3\RevPi\JsonRpc\JsonRpcDevice;
1111
use Revolt\EventLoop;
1212

1313
abstract class RemoteCharacterDevice extends RemoteDevice implements Stream
@@ -18,7 +18,7 @@ abstract class RemoteCharacterDevice extends RemoteDevice implements Stream
1818
/** @var resource */
1919
protected mixed $remote;
2020

21-
public function __construct(JsonRpcPeer $peer)
21+
public function __construct(JsonRpcDevice $peer)
2222
{
2323
parent::__construct($peer);
2424

src/Hardware/Remote/RemoteDevice.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
use Amp\Websocket\WebsocketClient;
88
use Flat3\RevPi\Interfaces\Hardware\Device;
99
use Flat3\RevPi\Interfaces\Hardware\Ioctl;
10-
use Flat3\RevPi\JsonRpc\JsonRpcPeer;
10+
use Flat3\RevPi\JsonRpc\JsonRpcDevice;
1111

1212
abstract class RemoteDevice implements Device, Ioctl
1313
{
14-
public function __construct(protected JsonRpcPeer $peer) {}
14+
public function __construct(protected JsonRpcDevice $peer) {}
1515

1616
public function socket(WebsocketClient $websocket): void
1717
{

src/JsonRpc/JsonRpcDevice.php

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
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\WebsocketClient;
10+
use Flat3\RevPi\Constants;
11+
use Flat3\RevPi\Exceptions\NotImplementedException;
12+
use Flat3\RevPi\Interfaces\Hardware\Device;
13+
use Flat3\RevPi\Interfaces\Hardware\Ioctl;
14+
use Flat3\RevPi\Interfaces\Hardware\PiControl;
15+
use Flat3\RevPi\Interfaces\Hardware\Seek;
16+
use Flat3\RevPi\Interfaces\Hardware\Stream;
17+
use Flat3\RevPi\Interfaces\Hardware\Terminal;
18+
use Revolt\EventLoop;
19+
20+
/**
21+
* @phpstan-import-type JsonRpcDeviceMethodT from JsonRpcPeer
22+
* @phpstan-import-type JsonRpcResponseResultT from JsonRpcPeer
23+
*/
24+
class JsonRpcDevice extends JsonRpcPeer
25+
{
26+
protected Device $device;
27+
28+
/**
29+
* @param JsonRpcDeviceMethodT $method
30+
* @param array<string, int|string|null> $params
31+
* @return JsonRpcResponseResultT
32+
*/
33+
protected function invoke(string $method, array $params): mixed
34+
{
35+
switch ($method) {
36+
case 'open':
37+
/** @var array{pathname: string, flags: int} $params */
38+
return $this->device->open($params['pathname'], $params['flags']);
39+
40+
case 'lseek':
41+
assert($this->device instanceof Seek);
42+
43+
/** @var array{offset: int, whence: int} $params */
44+
return $this->device->lseek($params['offset'], $params['whence']);
45+
46+
case 'ioctl':
47+
assert($this->device instanceof Ioctl);
48+
/** @var array{request:int, argp: string} $params */
49+
$argp = $params['argp'];
50+
$ret = $this->device->ioctl($params['request'], $argp);
51+
52+
return [
53+
'argp' => $argp,
54+
'return' => $ret,
55+
];
56+
57+
case 'read':
58+
/** @var array{buffer: string, count: int} $params */
59+
$buffer = $params['buffer'];
60+
$ret = $this->device->read($buffer, $params['count']);
61+
62+
return [
63+
'buffer' => $buffer,
64+
'return' => $ret,
65+
];
66+
67+
case 'write':
68+
/** @var array{buffer: string, count: int} $params */
69+
return $this->device->write($params['buffer'], $params['count']);
70+
71+
case 'close':
72+
return $this->device->close();
73+
74+
case 'cfgetispeed':
75+
assert($this->device instanceof Terminal);
76+
/** @var array{buffer: string} $params */
77+
$buffer = $params['buffer'];
78+
$ret = $this->device->cfgetispeed($buffer);
79+
80+
return [
81+
'buffer' => $buffer,
82+
'return' => $ret,
83+
];
84+
85+
case 'cfgetospeed':
86+
assert($this->device instanceof Terminal);
87+
/** @var array{buffer: string} $params */
88+
$buffer = $params['buffer'];
89+
$ret = $this->device->cfgetospeed($buffer);
90+
91+
return [
92+
'buffer' => $buffer,
93+
'return' => $ret,
94+
];
95+
96+
case 'cfsetispeed':
97+
assert($this->device instanceof Terminal);
98+
/** @var array{buffer: string, speed: int} $params */
99+
$buffer = $params['buffer'];
100+
$ret = $this->device->cfsetispeed($buffer, $params['speed']);
101+
102+
return [
103+
'buffer' => $buffer,
104+
'return' => $ret,
105+
];
106+
107+
case 'cfsetospeed':
108+
assert($this->device instanceof Terminal);
109+
/** @var array{buffer: string, speed: int} $params */
110+
$buffer = $params['buffer'];
111+
$ret = $this->device->cfsetospeed($buffer, $params['speed']);
112+
113+
return [
114+
'buffer' => $buffer,
115+
'return' => $ret,
116+
];
117+
118+
case 'tcflush':
119+
assert($this->device instanceof Terminal);
120+
121+
/** @var array{queue_selector: int} $params */
122+
return $this->device->tcflush($params['queue_selector']);
123+
124+
case 'tcdrain':
125+
assert($this->device instanceof Terminal);
126+
127+
return $this->device->tcdrain();
128+
129+
case 'tcsendbreak':
130+
assert($this->device instanceof Terminal);
131+
132+
/** @var array{duration: int} $params */
133+
return $this->device->tcsendbreak($params['duration']);
134+
135+
case 'fdopen':
136+
assert($this->device instanceof Stream);
137+
$stream = $this->device->fdopen();
138+
139+
EventLoop::onReadable($stream, function ($callbackId, $stream) {
140+
$data = @fread($stream, Constants::BlockSize);
141+
142+
if (is_string($data) && $data !== '') {
143+
$request = new Event;
144+
$request->type = 'readable';
145+
$request->payload = $data;
146+
147+
$this->socket->sendBinary(serialize($request));
148+
} elseif (! is_resource($stream) || @feof($stream)) {
149+
EventLoop::cancel($callbackId);
150+
}
151+
});
152+
153+
return 0;
154+
}
155+
156+
throw new NotImplementedException; // @phpstan-ignore deadCode.unreachable
157+
}
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+
}
169+
}

0 commit comments

Comments
 (0)