commit 5f5ced71ff63df899aea41d2aaa1cf1be45b0a59 Author: Daniil Gentili Date: Tue Dec 17 17:35:15 2019 +0100 First commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5a2d43a --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +vendor +composer.lock + diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..0c10767 --- /dev/null +++ b/composer.json @@ -0,0 +1,18 @@ +{ + "name": "danog/ton-proxy", + "description": "Websocket proxy for the TON blockchain ADNL protocol", + "minimum-stability": "dev", + "type": "project", + "require": { + "amphp/websocket-server": "dev-master as v2.0.0-rc1", + "amphp/http-server-static-content": "dev-master", + "amphp/http-server-router": "dev-master", + "amphp/log": "dev-master" + }, + "authors": [ + { + "name": "Daniil Gentili", + "email": "daniil@daniil.it" + } + ] +} diff --git a/main.php b/main.php new file mode 100644 index 0000000..f6cb92f --- /dev/null +++ b/main.php @@ -0,0 +1,197 @@ +setFormatter(new ConsoleFormatter); +$logger = new Logger('server'); +$logger->pushHandler($logHandler); + + +$websocket = new Websocket(new class($ip, $port, $logger) implements ClientHandler { + /** + * TON validator URI. + * + * @var string + */ + private $validatorUri; + /** + * Logger. + * + * @var Logger + */ + private $logger; + /** + * Constructor. + * + * @param string $ip Validator IP + * @param integer $port Validator port + * @param Logger $logger Logger + */ + public function __construct(string $ip, int $port, Logger $logger) + { + $this->validatorUri = "tcp://$ip:$port"; + $this->logger = $logger; + } + + /** + * Called when the HTTP server is started. + * + * @param Websocket $endpoint + * + * @return Promise + */ + public function onStart(Websocket $endpoint): Promise + { + $this->logger->notice("Started WS server!"); + return new Success(); + } + + /** + * Called when the HTTP server is stopped. + * + * @param Websocket $endpoint + * + * @return Promise + */ + public function onStop(Websocket $endpoint): Promise + { + $this->logger->notice("Stopped WS server!"); + return new Success(); + } + + /** + * Accept all incoming connections. + * + * @param \Amp\Http\Server\Request $request + * @param \Amp\Http\Server\Response $response + * + * @return \Amp\Promise + */ + public function handleHandshake(\Amp\Http\Server\Request $request, \Amp\Http\Server\Response $response): \Amp\Promise + { + return new Success($response); + } + /** + * Handle client. + * + * @param Client $client Websocket client + * @param Request $request HTTP request + * @param Response $response HTTP response + * + * @return Promise + */ + public function handleClient(Client $client, Request $request, Response $response): Promise + { + return call([$this, 'handleClientGenerator'], $client); + } + /** + * Handle client. + * + * @param Client $client Websocket client + * @param Request $request HTTP request + * @param Response $response HTTP response + * + * @return Promise + */ + public function handleClientGenerator(Client $client): \Generator + { + $socket = yield connect($this->validatorUri); + try { + yield [ + call([$this, 'readLoop'], $client, $socket), + call([$this, 'writeLoop'], $client, $socket), + ]; + } catch (\Throwable $e) { + $this->logger->alert("Got exception in loops: $e"); + } finally { + try { + $socket->close(); + } catch (\Throwable $e) { + } + try { + $client->close(); + } catch (\Throwable $e) { + } + } + } + public function readLoop(Client $client, SocketSocket $socket): \Generator + { + try { + $this->logger->warning("Entered read loop"); + while ($message = yield $client->receive()) { + if (!$message instanceof Message) { + throw new \Exception('Connection closed!'); + } + yield $socket->write(yield $message->buffer()); + } + } finally { + $this->logger->warning("Exited read loop"); + $client->close(); + $socket->close(); + } + } + public function writeLoop(Client $client, SocketSocket $socket): \Generator + { + try { + $this->logger->warning("Entered write loop"); + while (($message = yield $socket->read()) !== null) { + yield $client->sendBinary($message); + } + } finally { + $this->logger->warning("Exited write loop"); + $client->close(); + $socket->close(); + } + } +}); + +$sockets = [ + Socket\listen('127.0.0.1:80'), + Socket\listen('[::1]:80'), +]; + +$router = new Router; +$router->addRoute('GET', '/ton', $websocket); +$router->setFallback( + new CallableRequestHandler( + function () { + return new Response(Status::FOUND, ['location' => 'https://ton.madelineproto.xyz'], 'Redirecting you to https://ton.madelineproto.xyz...'); + } + ) +); + +$server = new HttpServer($sockets, $router, $logger); + +Loop::run( + function () use ($server) { + yield $server->start(); + } +);