diff --git a/docker/environments/base/Dockerfile b/docker/environments/base/Dockerfile index 2859c8512e..b91af634bf 100644 --- a/docker/environments/base/Dockerfile +++ b/docker/environments/base/Dockerfile @@ -2,7 +2,6 @@ FROM composer:2.0 as step0 WORKDIR /usr/local/src/ -COPY composer.lock /usr/local/src/ COPY composer.json /usr/local/src/ RUN composer update --ignore-platform-reqs --optimize-autoloader \ @@ -20,8 +19,7 @@ RUN \ gcc \ g++ \ git \ - zlib-dev \ - brotli-dev + zlib-dev RUN docker-php-ext-install sockets @@ -44,6 +42,9 @@ RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone RUN \ apk update \ && apk add --no-cache --virtual .deps \ + && apk add --no-cache \ + tar \ + libstdc++ \ && docker-php-ext-install sockets opcache \ && apk del .deps \ && rm -rf /var/cache/apk/* @@ -53,14 +54,20 @@ WORKDIR /usr/src/code COPY --from=step0 /usr/local/src/vendor /usr/src/code/vendor COPY --from=step1 /usr/local/lib/php/extensions/no-debug-non-zts-20190902/swoole.so /usr/local/lib/php/extensions/no-debug-non-zts-20190902/ +RUN ls -ll /usr/local/lib/php/extensions/no-debug-non-zts-20190902/ + # Add Source Code COPY ./app /usr/src/code/app +COPY ./start /usr/local/bin/start + +RUN chmod +x /usr/local/bin/start # Enable Extensions RUN echo extension=swoole.so >> /usr/local/etc/php/conf.d/swoole.ini +# PHP Settings RUN echo "opcache.enable_cli=1" >> /usr/local/etc/php/conf.d/appwrite.ini EXPOSE 80 -CMD [ "php", "app/http.php" ] +CMD [ "start" ] diff --git a/docker/environments/base/app/http.php b/docker/environments/base/app/http.php new file mode 100644 index 0000000000..71bd16d80c --- /dev/null +++ b/docker/environments/base/app/http.php @@ -0,0 +1,168 @@ +desc('Progressive app manifest file') + ->label('scope', 'public') + ->label('docs', false) + ->param('command', null, new Mock(), 'Command to execute', false) + ->param('timeout', 900, new Integer(), 'Timeout in seconds', false) + ->action(function ($command, $timeout, $response) { + /** @var Utopia\Swoole\Response $response */ + + Console::log('executing command: ' . $command); + + $stdout = ''; + $stderr = ''; + $exitCode = Console::execute($command, '', $stdout, $stderr, $timeout); + + $response->json([ + 'command' => $command, + 'timeout' => $timeout, + 'exitCode' => $exitCode, + 'stdout' => $stdout, + 'stderr' => $stderr, + ]); + }, ['response']); + +App::error(function ($error, $utopia, $request, $response) { + /** @var Exception $error */ + /** @var Utopia\App $utopia */ + /** @var Utopia\Swoole\Request $request */ + /** @var Appwrite\Utopia\Response $response */ + /** @var Utopia\View $layout */ + /** @var Appwrite\Database\Document $project */ + + $route = $utopia->match($request); + + if (php_sapi_name() === 'cli') { + Console::error('[Error] Method: '.$route->getMethod()); + Console::error('[Error] URL: '.$route->getURL()); + Console::error('[Error] Type: '.get_class($error)); + Console::error('[Error] Message: '.$error->getMessage()); + Console::error('[Error] File: '.$error->getFile()); + Console::error('[Error] Line: '.$error->getLine()); + } + + $version = App::getEnv('_APP_VERSION', 'UNKNOWN'); + + switch ($error->getCode()) { + case 400: // Error allowed publicly + case 401: // Error allowed publicly + case 402: // Error allowed publicly + case 403: // Error allowed publicly + case 404: // Error allowed publicly + case 409: // Error allowed publicly + case 412: // Error allowed publicly + case 429: // Error allowed publicly + $code = $error->getCode(); + $message = $error->getMessage(); + break; + default: + $code = 500; // All other errors get the generic 500 server error status code + $message = 'Server Error'; + } + + $output = ((App::isDevelopment())) ? [ + 'message' => $error->getMessage(), + 'code' => $error->getCode(), + 'file' => $error->getFile(), + 'line' => $error->getLine(), + 'trace' => $error->getTrace(), + 'version' => $version, + ] : [ + 'message' => $message, + 'code' => $code, + 'version' => $version, + ]; + + $response + ->addHeader('Cache-Control', 'no-cache, no-store, must-revalidate') + ->addHeader('Expires', '0') + ->addHeader('Pragma', 'no-cache') + ->setStatusCode($code) + ; + + $response->json($output); +}, ['error', 'utopia', 'request', 'response']); + + +$http = new Server("0.0.0.0", 80); + +$payloadSize = 4000000; /* 4mb */ + +$http + ->set([ + 'open_http2_protocol' => true, + // 'document_root' => __DIR__.'/../public', + // 'enable_static_handler' => true, + 'http_compression' => true, + 'http_compression_level' => 6, + 'package_max_length' => $payloadSize, + ]) +; + +$http->on('WorkerStart', function($serv, $workerId) { + Console::success('Worker '.++$workerId.' started succefully'); +}); + +$http->on('BeforeReload', function($serv, $workerId) { + Console::success('Starting reload...'); +}); + +$http->on('AfterReload', function($serv, $workerId) { + Console::success('Reload completed...'); +}); + +$http->on('start', function (Server $http) use ($payloadSize) { + Console::success('Server started succefully (max payload is '.number_format($payloadSize).' bytes)'); + + Console::info("Master pid {$http->master_pid}, manager pid {$http->manager_pid}"); + + // listen ctrl + c + Process::signal(2, function () use ($http) { + Console::log('Stop by Ctrl+C'); + $http->shutdown(); + }); +}); + +$http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swooleResponse) { + $request = new Request($swooleRequest); + $response = new Response($swooleResponse); + + $app = new App('America/New_York'); + + try { + $app->run($request, $response); + } catch (\Throwable $th) { + Console::error('[Error] Type: '.get_class($th)); + Console::error('[Error] Message: '.$th->getMessage()); + Console::error('[Error] File: '.$th->getFile()); + Console::error('[Error] Line: '.$th->getLine()); + + if(App::isDevelopment()) { + $swooleResponse->end('error: '.$th->getMessage()); + } + + $swooleResponse->end('500: Server Error'); + } +}); + +$http->start(); \ No newline at end of file diff --git a/docker/environments/base/composer.json b/docker/environments/base/composer.json new file mode 100644 index 0000000000..58a3728d1e --- /dev/null +++ b/docker/environments/base/composer.json @@ -0,0 +1,29 @@ +{ + "name": "appwrite/env-base", + "description": "Appwrite Function HTTP server.", + "type": "project", + "license": "BSD-3-Clause", + "authors": [ + { + "name": "Appwrite Team", + "email": "team@appwrite.io" + } + ], + "require": { + "php": ">=7.4.0", + "ext-swoole": "*", + + "utopia-php/framework": "0.9.7", + "utopia-php/swoole": "0.2.*", + "utopia-php/cli": "0.7.3" + }, + "require-dev": { + "swoole/ide-helper": "4.5.5" + }, + "minimum-stability": "dev", + "config": { + "platform": { + "php": "7.4" + } + } +} diff --git a/docker/environments/base/docker-compose.yml b/docker/environments/base/docker-compose.yml new file mode 100644 index 0000000000..e9bedc5732 --- /dev/null +++ b/docker/environments/base/docker-compose.yml @@ -0,0 +1,14 @@ +version: '3' + +services: + base: + container_name: base + build: + context: . + ports: + - 9503:80 + networks: + - gateway + +networks: + gateway: \ No newline at end of file diff --git a/docker/environments/base/start b/docker/environments/base/start new file mode 100644 index 0000000000..54531b33de --- /dev/null +++ b/docker/environments/base/start @@ -0,0 +1,9 @@ +#!/bin/sh + +mv /tmp/code.tar.gz /usr/local/src/code.tar.gz + +tar -zxf /usr/local/src/code.tar.gz --strip 1 + +rm /usr/local/src/code.tar.gz + +php /usr/src/code/app/http.php \ No newline at end of file