1
0
Fork 0
mirror of synced 2024-09-29 08:51:28 +13:00

updated server

This commit is contained in:
Eldad Fux 2024-04-14 10:58:05 +02:00
parent 08b3182ef3
commit 9e234b7600
2 changed files with 506 additions and 494 deletions

View file

@ -1,7 +1,5 @@
<?php
require_once __DIR__ . '/../init.php';
use Appwrite\Event\Certificate;
use Appwrite\Event\Event;
use Appwrite\Event\Usage;
@ -24,349 +22,351 @@ use Utopia\Database\Document;
use Utopia\Database\Helpers\ID;
use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use Utopia\DI\Dependency;
use Utopia\Domains\Domain;
use Utopia\Http\Http;
use Utopia\Http\Route;
use Utopia\Http\Validator\Hostname;
use Utopia\Http\Validator\Text;
use Utopia\Locale\Locale;
use Utopia\Logger\Log;
use Utopia\Logger\Log\User;
use Utopia\Logger\Logger;
use Utopia\Registry\Registry;
use Utopia\System\System;
Config::setParam('domainVerification', false);
Config::setParam('cookieDomain', 'localhost');
Config::setParam('cookieSamesite', Response::COOKIE_SAMESITE_NONE);
function router(Http $utopia, Database $dbForConsole, callable $getProjectDB, SwooleRequest $swooleRequest, Request $request, Response $response, Event $queueForEvents, Usage $queueForUsage, Reader $geodb, Authorization $auth)
{
$utopia->getRoute()?->label('error', __DIR__ . '/../views/general/error.phtml');
// function router(Http $utopia, Database $dbForConsole, callable $getProjectDB, Request $request, Response $response, Route $route, Event $queueForEvents, Usage $queueForUsage, Reader $geodb, Authorization $auth)
// {
// $route?->label('error', __DIR__ . '/../views/general/error.phtml');
$host = $request->getHostname() ?? '';
// $host = $request->getHostname() ?? '';
$route = $auth->skip(
fn () => $dbForConsole->find('rules', [
Query::equal('domain', [$host]),
Query::limit(1)
])
)[0] ?? null;
// $route = $auth->skip(
// fn () => $dbForConsole->find('rules', [
// Query::equal('domain', [$host]),
// Query::limit(1)
// ])
// )[0] ?? null;
if ($route === null) {
if ($host === System::getEnv('_APP_DOMAIN_FUNCTIONS', '')) {
throw new AppwriteException(AppwriteException::GENERAL_ACCESS_FORBIDDEN, 'This domain cannot be used for security reasons. Please use any subdomain instead.');
}
// if ($route === null) {
// if ($host === System::getEnv('_APP_DOMAIN_FUNCTIONS', '')) {
// throw new AppwriteException(AppwriteException::GENERAL_ACCESS_FORBIDDEN, 'This domain cannot be used for security reasons. Please use any subdomain instead.');
// }
if (\str_ends_with($host, System::getEnv('_APP_DOMAIN_FUNCTIONS', ''))) {
throw new AppwriteException(AppwriteException::GENERAL_ACCESS_FORBIDDEN, 'This domain is not connected to any Appwrite resource yet. Please configure custom domain or function domain to allow this request.');
}
// if (\str_ends_with($host, System::getEnv('_APP_DOMAIN_FUNCTIONS', ''))) {
// throw new AppwriteException(AppwriteException::GENERAL_ACCESS_FORBIDDEN, 'This domain is not connected to any Appwrite resource yet. Please configure custom domain or function domain to allow this request.');
// }
if (System::getEnv('_APP_OPTIONS_ROUTER_PROTECTION', 'disabled') === 'enabled') {
if ($host !== 'localhost' && $host !== APP_HOSTNAME_INTERNAL) { // localhost allowed for proxy, APP_HOSTNAME_INTERNAL allowed for migrations
throw new AppwriteException(AppwriteException::GENERAL_ACCESS_FORBIDDEN, 'Router protection does not allow accessing Appwrite over this domain. Please add it as custom domain to your project or disable _APP_OPTIONS_ROUTER_PROTECTION environment variable.');
}
}
// if (System::getEnv('_APP_OPTIONS_ROUTER_PROTECTION', 'disabled') === 'enabled') {
// if ($host !== 'localhost' && $host !== APP_HOSTNAME_INTERNAL) { // localhost allowed for proxy, APP_HOSTNAME_INTERNAL allowed for migrations
// throw new AppwriteException(AppwriteException::GENERAL_ACCESS_FORBIDDEN, 'Router protection does not allow accessing Appwrite over this domain. Please add it as custom domain to your project or disable _APP_OPTIONS_ROUTER_PROTECTION environment variable.');
// }
// }
// Act as API - no Proxy logic
$utopia->getRoute()?->label('error', '');
return false;
}
// // Act as API - no Proxy logic
// $utopia->getRoute()?->label('error', '');
// return false;
// }
$projectId = $route->getAttribute('projectId');
$project = $auth->skip(
fn () => $dbForConsole->getDocument('projects', $projectId)
);
if (array_key_exists('proxy', $project->getAttribute('services', []))) {
$status = $project->getAttribute('services', [])['proxy'];
if (!$status) {
throw new AppwriteException(AppwriteException::GENERAL_SERVICE_DISABLED);
}
}
// $projectId = $route->getAttribute('projectId');
// $project = $auth->skip(
// fn () => $dbForConsole->getDocument('projects', $projectId)
// );
// if (array_key_exists('proxy', $project->getAttribute('services', []))) {
// $status = $project->getAttribute('services', [])['proxy'];
// if (!$status) {
// throw new AppwriteException(AppwriteException::GENERAL_SERVICE_DISABLED);
// }
// }
// Skip Appwrite Router for ACME challenge. Nessessary for certificate generation
$path = ($swooleRequest->server['request_uri'] ?? '/');
if (\str_starts_with($path, '/.well-known/acme-challenge')) {
return false;
}
// // Skip Appwrite Router for ACME challenge. Nessessary for certificate generation
// $path = ($request->getURI() ?? '/');
// if (\str_starts_with($path, '/.well-known/acme-challenge')) {
// return false;
// }
$type = $route->getAttribute('resourceType');
// $type = $route->getAttribute('resourceType');
if ($type === 'function') {
if (System::getEnv('_APP_OPTIONS_FUNCTIONS_FORCE_HTTPS', 'disabled') === 'enabled') { // Force HTTPS
if ($request->getProtocol() !== 'https') {
if ($request->getMethod() !== Request::METHOD_GET) {
throw new AppwriteException(AppwriteException::GENERAL_PROTOCOL_UNSUPPORTED, 'Method unsupported over HTTP. Please use HTTPS instead.');
}
// if ($type === 'function') {
// if (System::getEnv('_APP_OPTIONS_FUNCTIONS_FORCE_HTTPS', 'disabled') === 'enabled') { // Force HTTPS
// if ($request->getProtocol() !== 'https') {
// if ($request->getMethod() !== Request::METHOD_GET) {
// throw new AppwriteException(AppwriteException::GENERAL_PROTOCOL_UNSUPPORTED, 'Method unsupported over HTTP. Please use HTTPS instead.');
// }
return $response->redirect('https://' . $request->getHostname() . $request->getURI());
}
}
// return $response->redirect('https://' . $request->getHostname() . $request->getURI());
// }
// }
$functionId = $route->getAttribute('resourceId');
$projectId = $route->getAttribute('projectId');
// $functionId = $route->getAttribute('resourceId');
// $projectId = $route->getAttribute('projectId');
$path = ($swooleRequest->server['request_uri'] ?? '/');
$query = ($swooleRequest->server['query_string'] ?? '');
if (!empty($query)) {
$path .= '?' . $query;
}
// $path = ($swooleRequest->server['request_uri'] ?? '/');
// $query = ($swooleRequest->server['query_string'] ?? '');
// if (!empty($query)) {
// $path .= '?' . $query;
// }
$body = $swooleRequest->getContent() ?? '';
$method = $swooleRequest->server['request_method'];
// $body = $swooleRequest->getContent() ?? '';
// $method = $swooleRequest->server['request_method'];
$requestHeaders = $request->getHeaders();
// $requestHeaders = $request->getHeaders();
$project = $auth->skip(fn () => $dbForConsole->getDocument('projects', $projectId));
// $project = $auth->skip(fn () => $dbForConsole->getDocument('projects', $projectId));
$dbForProject = $getProjectDB($project);
// $dbForProject = $getProjectDB($project);
$function = $auth->skip(fn () => $dbForProject->getDocument('functions', $functionId));
// $function = $auth->skip(fn () => $dbForProject->getDocument('functions', $functionId));
if ($function->isEmpty() || !$function->getAttribute('enabled')) {
throw new AppwriteException(AppwriteException::FUNCTION_NOT_FOUND);
}
// if ($function->isEmpty() || !$function->getAttribute('enabled')) {
// throw new AppwriteException(AppwriteException::FUNCTION_NOT_FOUND);
// }
$version = $function->getAttribute('version', 'v2');
$runtimes = Config::getParam($version === 'v2' ? 'runtimes-v2' : 'runtimes', []);
// $version = $function->getAttribute('version', 'v2');
// $runtimes = Config::getParam($version === 'v2' ? 'runtimes-v2' : 'runtimes', []);
$runtime = (isset($runtimes[$function->getAttribute('runtime', '')])) ? $runtimes[$function->getAttribute('runtime', '')] : null;
// $runtime = (isset($runtimes[$function->getAttribute('runtime', '')])) ? $runtimes[$function->getAttribute('runtime', '')] : null;
if (\is_null($runtime)) {
throw new AppwriteException(AppwriteException::FUNCTION_RUNTIME_UNSUPPORTED, 'Runtime "' . $function->getAttribute('runtime', '') . '" is not supported');
}
// if (\is_null($runtime)) {
// throw new AppwriteException(AppwriteException::FUNCTION_RUNTIME_UNSUPPORTED, 'Runtime "' . $function->getAttribute('runtime', '') . '" is not supported');
// }
$deployment = $auth->skip(fn () => $dbForProject->getDocument('deployments', $function->getAttribute('deployment', '')));
// $deployment = $auth->skip(fn () => $dbForProject->getDocument('deployments', $function->getAttribute('deployment', '')));
if ($deployment->getAttribute('resourceId') !== $function->getId()) {
throw new AppwriteException(AppwriteException::DEPLOYMENT_NOT_FOUND, 'Deployment not found. Create a deployment before trying to execute a function');
}
// if ($deployment->getAttribute('resourceId') !== $function->getId()) {
// throw new AppwriteException(AppwriteException::DEPLOYMENT_NOT_FOUND, 'Deployment not found. Create a deployment before trying to execute a function');
// }
if ($deployment->isEmpty()) {
throw new AppwriteException(AppwriteException::DEPLOYMENT_NOT_FOUND, 'Deployment not found. Create a deployment before trying to execute a function');
}
// if ($deployment->isEmpty()) {
// throw new AppwriteException(AppwriteException::DEPLOYMENT_NOT_FOUND, 'Deployment not found. Create a deployment before trying to execute a function');
// }
/** Check if build has completed */
$build = $auth->skip(fn () => $dbForProject->getDocument('builds', $deployment->getAttribute('buildId', '')));
if ($build->isEmpty()) {
throw new AppwriteException(AppwriteException::BUILD_NOT_FOUND);
}
// /** Check if build has completed */
// $build = $auth->skip(fn () => $dbForProject->getDocument('builds', $deployment->getAttribute('buildId', '')));
// if ($build->isEmpty()) {
// throw new AppwriteException(AppwriteException::BUILD_NOT_FOUND);
// }
if ($build->getAttribute('status') !== 'ready') {
throw new AppwriteException(AppwriteException::BUILD_NOT_READY);
}
// if ($build->getAttribute('status') !== 'ready') {
// throw new AppwriteException(AppwriteException::BUILD_NOT_READY);
// }
$permissions = $function->getAttribute('execute');
// $permissions = $function->getAttribute('execute');
if (!(\in_array('any', $permissions)) && (\in_array('guests', $permissions))) {
throw new AppwriteException(AppwriteException::USER_UNAUTHORIZED, 'To execute function using domain, execute permissions must include "any" or "guests"');
}
// if (!(\in_array('any', $permissions)) && (\in_array('guests', $permissions))) {
// throw new AppwriteException(AppwriteException::USER_UNAUTHORIZED, 'To execute function using domain, execute permissions must include "any" or "guests"');
// }
$headers = \array_merge([], $requestHeaders);
$headers['x-appwrite-trigger'] = 'http';
$headers['x-appwrite-user-id'] = '';
$headers['x-appwrite-user-jwt'] = '';
$headers['x-appwrite-country-code'] = '';
$headers['x-appwrite-continent-code'] = '';
$headers['x-appwrite-continent-eu'] = 'false';
// $headers = \array_merge([], $requestHeaders);
// $headers['x-appwrite-trigger'] = 'http';
// $headers['x-appwrite-user-id'] = '';
// $headers['x-appwrite-user-jwt'] = '';
// $headers['x-appwrite-country-code'] = '';
// $headers['x-appwrite-continent-code'] = '';
// $headers['x-appwrite-continent-eu'] = 'false';
$ip = $headers['x-real-ip'] ?? '';
if (!empty($ip)) {
$record = $geodb->get($ip);
// $ip = $headers['x-real-ip'] ?? '';
// if (!empty($ip)) {
// $record = $geodb->get($ip);
if ($record) {
$eu = Config::getParam('locale-eu');
// if ($record) {
// $eu = Config::getParam('locale-eu');
$headers['x-appwrite-country-code'] = $record['country']['iso_code'] ?? '';
$headers['x-appwrite-continent-code'] = $record['continent']['code'] ?? '';
$headers['x-appwrite-continent-eu'] = (\in_array($record['country']['iso_code'], $eu)) ? 'true' : 'false';
}
}
// $headers['x-appwrite-country-code'] = $record['country']['iso_code'] ?? '';
// $headers['x-appwrite-continent-code'] = $record['continent']['code'] ?? '';
// $headers['x-appwrite-continent-eu'] = (\in_array($record['country']['iso_code'], $eu)) ? 'true' : 'false';
// }
// }
$headersFiltered = [];
foreach ($headers as $key => $value) {
if (\in_array(\strtolower($key), FUNCTION_ALLOWLIST_HEADERS_REQUEST)) {
$headersFiltered[] = ['name' => $key, 'value' => $value];
}
}
// $headersFiltered = [];
// foreach ($headers as $key => $value) {
// if (\in_array(\strtolower($key), FUNCTION_ALLOWLIST_HEADERS_REQUEST)) {
// $headersFiltered[] = ['name' => $key, 'value' => $value];
// }
// }
$executionId = ID::unique();
// $executionId = ID::unique();
$execution = new Document([
'$id' => $executionId,
'$permissions' => [],
'functionInternalId' => $function->getInternalId(),
'functionId' => $function->getId(),
'deploymentInternalId' => $deployment->getInternalId(),
'deploymentId' => $deployment->getId(),
'trigger' => 'http', // http / schedule / event
'status' => 'processing', // waiting / processing / completed / failed
'responseStatusCode' => 0,
'responseHeaders' => [],
'requestPath' => $path,
'requestMethod' => $method,
'requestHeaders' => $headersFiltered,
'errors' => '',
'logs' => '',
'duration' => 0.0,
'search' => implode(' ', [$functionId, $executionId]),
]);
// $execution = new Document([
// '$id' => $executionId,
// '$permissions' => [],
// 'functionInternalId' => $function->getInternalId(),
// 'functionId' => $function->getId(),
// 'deploymentInternalId' => $deployment->getInternalId(),
// 'deploymentId' => $deployment->getId(),
// 'trigger' => 'http', // http / schedule / event
// 'status' => 'processing', // waiting / processing / completed / failed
// 'responseStatusCode' => 0,
// 'responseHeaders' => [],
// 'requestPath' => $path,
// 'requestMethod' => $method,
// 'requestHeaders' => $headersFiltered,
// 'errors' => '',
// 'logs' => '',
// 'duration' => 0.0,
// 'search' => implode(' ', [$functionId, $executionId]),
// ]);
$queueForEvents
->setParam('functionId', $function->getId())
->setParam('executionId', $execution->getId())
->setContext('function', $function);
// $queueForEvents
// ->setParam('functionId', $function->getId())
// ->setParam('executionId', $execution->getId())
// ->setContext('function', $function);
$durationStart = \microtime(true);
// $durationStart = \microtime(true);
$vars = [];
// $vars = [];
// V2 vars
if ($version === 'v2') {
$vars = \array_merge($vars, [
'APPWRITE_FUNCTION_TRIGGER' => $headers['x-appwrite-trigger'] ?? '',
'APPWRITE_FUNCTION_DATA' => $body ?? '',
'APPWRITE_FUNCTION_USER_ID' => $headers['x-appwrite-user-id'] ?? '',
'APPWRITE_FUNCTION_JWT' => $headers['x-appwrite-user-jwt'] ?? ''
]);
}
// // V2 vars
// if ($version === 'v2') {
// $vars = \array_merge($vars, [
// 'APPWRITE_FUNCTION_TRIGGER' => $headers['x-appwrite-trigger'] ?? '',
// 'APPWRITE_FUNCTION_DATA' => $body ?? '',
// 'APPWRITE_FUNCTION_USER_ID' => $headers['x-appwrite-user-id'] ?? '',
// 'APPWRITE_FUNCTION_JWT' => $headers['x-appwrite-user-jwt'] ?? ''
// ]);
// }
// Shared vars
foreach ($function->getAttribute('varsProject', []) as $var) {
$vars[$var->getAttribute('key')] = $var->getAttribute('value', '');
}
// // Shared vars
// foreach ($function->getAttribute('varsProject', []) as $var) {
// $vars[$var->getAttribute('key')] = $var->getAttribute('value', '');
// }
// Function vars
foreach ($function->getAttribute('vars', []) as $var) {
$vars[$var->getAttribute('key')] = $var->getAttribute('value', '');
}
// // Function vars
// foreach ($function->getAttribute('vars', []) as $var) {
// $vars[$var->getAttribute('key')] = $var->getAttribute('value', '');
// }
// Appwrite vars
$vars = \array_merge($vars, [
'APPWRITE_FUNCTION_ID' => $functionId,
'APPWRITE_FUNCTION_NAME' => $function->getAttribute('name'),
'APPWRITE_FUNCTION_DEPLOYMENT' => $deployment->getId(),
'APPWRITE_FUNCTION_PROJECT_ID' => $project->getId(),
'APPWRITE_FUNCTION_RUNTIME_NAME' => $runtime['name'] ?? '',
'APPWRITE_FUNCTION_RUNTIME_VERSION' => $runtime['version'] ?? '',
]);
// // Appwrite vars
// $vars = \array_merge($vars, [
// 'APPWRITE_FUNCTION_ID' => $functionId,
// 'APPWRITE_FUNCTION_NAME' => $function->getAttribute('name'),
// 'APPWRITE_FUNCTION_DEPLOYMENT' => $deployment->getId(),
// 'APPWRITE_FUNCTION_PROJECT_ID' => $project->getId(),
// 'APPWRITE_FUNCTION_RUNTIME_NAME' => $runtime['name'] ?? '',
// 'APPWRITE_FUNCTION_RUNTIME_VERSION' => $runtime['version'] ?? '',
// ]);
/** Execute function */
$executor = new Executor(System::getEnv('_APP_EXECUTOR_HOST'));
try {
$version = $function->getAttribute('version', 'v2');
$command = $runtime['startCommand'];
$command = $version === 'v2' ? '' : 'cp /tmp/code.tar.gz /mnt/code/code.tar.gz && nohup helpers/start.sh "' . $command . '"';
$executionResponse = $executor->createExecution(
projectId: $project->getId(),
deploymentId: $deployment->getId(),
body: \strlen($body) > 0 ? $body : null,
variables: $vars,
timeout: $function->getAttribute('timeout', 0),
image: $runtime['image'],
source: $build->getAttribute('path', ''),
entrypoint: $deployment->getAttribute('entrypoint', ''),
version: $version,
path: $path,
method: $method,
headers: $headers,
runtimeEntrypoint: $command,
requestTimeout: 30
);
// /** Execute function */
// $executor = new Executor(System::getEnv('_APP_EXECUTOR_HOST'));
// try {
// $version = $function->getAttribute('version', 'v2');
// $command = $runtime['startCommand'];
// $command = $version === 'v2' ? '' : 'cp /tmp/code.tar.gz /mnt/code/code.tar.gz && nohup helpers/start.sh "' . $command . '"';
// $executionResponse = $executor->createExecution(
// projectId: $project->getId(),
// deploymentId: $deployment->getId(),
// body: \strlen($body) > 0 ? $body : null,
// variables: $vars,
// timeout: $function->getAttribute('timeout', 0),
// image: $runtime['image'],
// source: $build->getAttribute('path', ''),
// entrypoint: $deployment->getAttribute('entrypoint', ''),
// version: $version,
// path: $path,
// method: $method,
// headers: $headers,
// runtimeEntrypoint: $command,
// requestTimeout: 30
// );
$headersFiltered = [];
foreach ($executionResponse['headers'] as $key => $value) {
if (\in_array(\strtolower($key), FUNCTION_ALLOWLIST_HEADERS_RESPONSE)) {
$headersFiltered[] = ['name' => $key, 'value' => $value];
}
}
// $headersFiltered = [];
// foreach ($executionResponse['headers'] as $key => $value) {
// if (\in_array(\strtolower($key), FUNCTION_ALLOWLIST_HEADERS_RESPONSE)) {
// $headersFiltered[] = ['name' => $key, 'value' => $value];
// }
// }
/** Update execution status */
$status = $executionResponse['statusCode'] >= 400 ? 'failed' : 'completed';
$execution->setAttribute('status', $status);
$execution->setAttribute('responseStatusCode', $executionResponse['statusCode']);
$execution->setAttribute('responseHeaders', $headersFiltered);
$execution->setAttribute('logs', $executionResponse['logs']);
$execution->setAttribute('errors', $executionResponse['errors']);
$execution->setAttribute('duration', $executionResponse['duration']);
} catch (\Throwable $th) {
$durationEnd = \microtime(true);
// /** Update execution status */
// $status = $executionResponse['statusCode'] >= 400 ? 'failed' : 'completed';
// $execution->setAttribute('status', $status);
// $execution->setAttribute('responseStatusCode', $executionResponse['statusCode']);
// $execution->setAttribute('responseHeaders', $headersFiltered);
// $execution->setAttribute('logs', $executionResponse['logs']);
// $execution->setAttribute('errors', $executionResponse['errors']);
// $execution->setAttribute('duration', $executionResponse['duration']);
// } catch (\Throwable $th) {
// $durationEnd = \microtime(true);
$execution
->setAttribute('duration', $durationEnd - $durationStart)
->setAttribute('status', 'failed')
->setAttribute('responseStatusCode', 500)
->setAttribute('errors', $th->getMessage() . '\nError Code: ' . $th->getCode());
Console::error($th->getMessage());
} finally {
$queueForUsage
->addMetric(METRIC_EXECUTIONS, 1)
->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS), 1)
->addMetric(METRIC_EXECUTIONS_COMPUTE, (int)($execution->getAttribute('duration') * 1000)) // per project
->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE), (int)($execution->getAttribute('duration') * 1000)) // per function
;
}
// $execution
// ->setAttribute('duration', $durationEnd - $durationStart)
// ->setAttribute('status', 'failed')
// ->setAttribute('responseStatusCode', 500)
// ->setAttribute('errors', $th->getMessage() . '\nError Code: ' . $th->getCode());
// Console::error($th->getMessage());
// } finally {
// $queueForUsage
// ->addMetric(METRIC_EXECUTIONS, 1)
// ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS), 1)
// ->addMetric(METRIC_EXECUTIONS_COMPUTE, (int)($execution->getAttribute('duration') * 1000)) // per project
// ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE), (int)($execution->getAttribute('duration') * 1000)) // per function
// ;
// }
if ($function->getAttribute('logging')) {
/** @var Document $execution */
$execution = $auth->skip(fn () => $dbForProject->createDocument('executions', $execution));
}
// if ($function->getAttribute('logging')) {
// /** @var Document $execution */
// $execution = $auth->skip(fn () => $dbForProject->createDocument('executions', $execution));
// }
$execution->setAttribute('logs', '');
$execution->setAttribute('errors', '');
// $execution->setAttribute('logs', '');
// $execution->setAttribute('errors', '');
$headers = [];
foreach (($executionResponse['headers'] ?? []) as $key => $value) {
$headers[] = ['name' => $key, 'value' => $value];
}
// $headers = [];
// foreach (($executionResponse['headers'] ?? []) as $key => $value) {
// $headers[] = ['name' => $key, 'value' => $value];
// }
$execution->setAttribute('responseBody', $executionResponse['body'] ?? '');
$execution->setAttribute('responseHeaders', $headers);
// $execution->setAttribute('responseBody', $executionResponse['body'] ?? '');
// $execution->setAttribute('responseHeaders', $headers);
$body = $execution['responseBody'] ?? '';
// $body = $execution['responseBody'] ?? '';
$encodingKey = \array_search('x-open-runtimes-encoding', \array_column($execution['responseHeaders'], 'name'));
if ($encodingKey !== false) {
if (($execution['responseHeaders'][$encodingKey]['value'] ?? '') === 'base64') {
$body = \base64_decode($body);
}
}
// $encodingKey = \array_search('x-open-runtimes-encoding', \array_column($execution['responseHeaders'], 'name'));
// if ($encodingKey !== false) {
// if (($execution['responseHeaders'][$encodingKey]['value'] ?? '') === 'base64') {
// $body = \base64_decode($body);
// }
// }
$contentType = 'text/plain';
foreach ($execution['responseHeaders'] as $header) {
if (\strtolower($header['name']) === 'content-type') {
$contentType = $header['value'];
}
// $contentType = 'text/plain';
// foreach ($execution['responseHeaders'] as $header) {
// if (\strtolower($header['name']) === 'content-type') {
// $contentType = $header['value'];
// }
$response->setHeader($header['name'], $header['value']);
}
// $response->setHeader($header['name'], $header['value']);
// }
$response
->setContentType($contentType)
->setStatusCode($execution['responseStatusCode'] ?? 200)
->send($body);
// $response
// ->setContentType($contentType)
// ->setStatusCode($execution['responseStatusCode'] ?? 200)
// ->send($body);
return true;
} elseif ($type === 'api') {
$utopia->getRoute()?->label('error', '');
return false;
} else {
throw new AppwriteException(AppwriteException::GENERAL_SERVER_ERROR, 'Unknown resource type ' . $type);
}
// return true;
// } elseif ($type === 'api') {
// $utopia->getRoute()?->label('error', '');
// return false;
// } else {
// throw new AppwriteException(AppwriteException::GENERAL_SERVER_ERROR, 'Unknown resource type ' . $type);
// }
$utopia->getRoute()?->label('error', '');
return false;
}
// $utopia->getRoute()?->label('error', '');
// return false;
// }
Http::init()
->groups(['api', 'web'])
->inject('utopia')
->inject('swooleRequest')
->inject('request')
->inject('response')
->inject('route')
->inject('console')
->inject('project')
->inject('dbForConsole')
->inject('getProjectDB')
// ->inject('getProjectDB')
->inject('locale')
->inject('localeCodes')
->inject('clients')
@ -374,25 +374,25 @@ Http::init()
->inject('queueForUsage')
->inject('queueForEvents')
->inject('queueForCertificates')
->inject('auth')
->action(function (Http $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Document $console, Document $project, Database $dbForConsole, callable $getProjectDB, Locale $locale, array $localeCodes, array $clients, Reader $geodb, Usage $queueForUsage, Event $queueForEvents, Certificate $queueForCertificates, Authorization $auth) {
->inject('authorization')
->action(function (Request $request, Response $response, Route $route, Document $console, Document $project, Database $dbForConsole, Locale $locale, array $localeCodes, array $clients, Reader $geodb, Usage $queueForUsage, Event $queueForEvents, Certificate $queueForCertificates, Authorization $authorization) {
/*
* Appwrite Router
*/
$host = $request->getHostname() ?? '';
$mainDomain = System::getEnv('_APP_DOMAIN', '');
// Only run Router when external domain
if ($host !== $mainDomain) {
if (router($utopia, $dbForConsole, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForUsage, $geodb, $auth)) {
return;
}
}
// if ($host !== $mainDomain) {
// if (router($utopia, $dbForConsole, $getProjectDB, $request, $response, $queueForEvents, $queueForUsage, $geodb, $auth)) {
// return;
// }
// }
/*
* Request format
*/
$route = $utopia->getRoute();
Request::setRoute($route);
//$route = $utopia->getRoute();
//Request::setRoute($route);
if ($route === null) {
return $response->setStatusCode(404)->send('Not Found');
@ -419,7 +419,7 @@ Http::init()
} elseif (str_starts_with($request->getURI(), '/.well-known/acme-challenge')) {
Console::warning('Skipping SSL certificates generation on ACME challenge.');
} else {
$auth->disable();
$authorization->disable();
$envDomain = System::getEnv('_APP_DOMAIN', '');
$mainDomain = null;
@ -458,7 +458,7 @@ Http::init()
}
$domains[$domain->get()] = true;
$auth->reset(); // ensure authorization is re-enabled
$authorization->reset(); // ensure authorization is re-enabled
}
Config::setParam('domains', $domains);
}
@ -531,7 +531,9 @@ Http::init()
* @see https://www.owasp.org/index.php/List_of_useful_HTTP_headers
*/
if (System::getEnv('_APP_OPTIONS_FORCE_HTTPS', 'disabled') === 'enabled') { // Force HTTPS
if ($request->getProtocol() !== 'https' && ($swooleRequest->header['host'] ?? '') !== 'localhost' && ($swooleRequest->header['host'] ?? '') !== APP_HOSTNAME_INTERNAL) { // localhost allowed for proxy, APP_HOSTNAME_INTERNAL allowed for migrations
if ($request->getProtocol() !== 'https' // localhost allowed for proxy, APP_HOSTNAME_INTERNAL allowed for migrations
&& ($request->getHeader('host') ?? '') !== 'localhost'
&& ($request->getHeader('host') ?? '') !== APP_HOSTNAME_INTERNAL) {
if ($request->getMethod() !== Request::METHOD_GET) {
throw new AppwriteException(AppwriteException::GENERAL_PROTOCOL_UNSUPPORTED, 'Method unsupported over HTTP. Please use HTTPS instead.');
}
@ -571,54 +573,58 @@ Http::init()
}
});
Http::options()
->inject('utopia')
->inject('swooleRequest')
->inject('request')
->inject('response')
->inject('dbForConsole')
->inject('getProjectDB')
->inject('queueForEvents')
->inject('queueForUsage')
->inject('geodb')
->inject('auth')
->action(function (Http $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForConsole, callable $getProjectDB, Event $queueForEvents, Usage $queueForUsage, Reader $geodb, Authorization $auth) {
/*
* Appwrite Router
*/
$host = $request->getHostname() ?? '';
$mainDomain = System::getEnv('_APP_DOMAIN', '');
// Only run Router when external domain
if ($host !== $mainDomain) {
if (router($utopia, $dbForConsole, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForUsage, $geodb, $auth)) {
return;
}
}
// Http::options()
// ->inject('utopia')
// ->inject('swooleRequest')
// ->inject('request')
// ->inject('response')
// ->inject('dbForConsole')
// ->inject('getProjectDB')
// ->inject('queueForEvents')
// ->inject('queueForUsage')
// ->inject('geodb')
// ->inject('auth')
// ->action(function (Http $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForConsole, callable $getProjectDB, Event $queueForEvents, Usage $queueForUsage, Reader $geodb, Authorization $auth) {
// /*
// * Appwrite Router
// */
// $host = $request->getHostname() ?? '';
// $mainDomain = System::getEnv('_APP_DOMAIN', '');
// // Only run Router when external domain
// if ($host !== $mainDomain) {
// if (router($utopia, $dbForConsole, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForUsage, $geodb, $auth)) {
// return;
// }
// }
$origin = $request->getOrigin();
// $origin = $request->getOrigin();
$response
->addHeader('Server', 'Appwrite')
->addHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE')
->addHeader('Access-Control-Allow-Headers', 'Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-Appwrite-Timeout, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, X-Appwrite-ID, X-Appwrite-Timestamp, Content-Range, Range, Cache-Control, Expires, Pragma, X-Appwrite-Session, X-Fallback-Cookies, X-Forwarded-For, X-Forwarded-User-Agent')
->addHeader('Access-Control-Expose-Headers', 'X-Appwrite-Session, X-Fallback-Cookies')
->addHeader('Access-Control-Allow-Origin', $origin)
->addHeader('Access-Control-Allow-Credentials', 'true')
->noContent();
});
// $response
// ->addHeader('Server', 'Appwrite')
// ->addHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE')
// ->addHeader('Access-Control-Allow-Headers', 'Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-Appwrite-Timeout, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, X-Appwrite-ID, X-Appwrite-Timestamp, Content-Range, Range, Cache-Control, Expires, Pragma, X-Appwrite-Session, X-Fallback-Cookies, X-Forwarded-For, X-Forwarded-User-Agent')
// ->addHeader('Access-Control-Expose-Headers', 'X-Appwrite-Session, X-Fallback-Cookies')
// ->addHeader('Access-Control-Allow-Origin', $origin)
// ->addHeader('Access-Control-Allow-Credentials', 'true')
// ->noContent();
// });
Http::error()
->inject('error')
->inject('utopia')
->inject('user')
->inject('route')
->inject('request')
->inject('response')
->inject('project')
->inject('logger')
->inject('log')
->inject('auth')
->action(function (Throwable $error, Http $utopia, Request $request, Response $response, Document $project, ?Logger $logger, Log $log, Authorization $auth) {
->inject('authorization')
->action(function (Throwable $error, Document $user, ?Route $route, Request $request, Response $response, Document $project, ?Logger $logger, Log $log, Authorization $authorization) {
$version = System::getEnv('_APP_VERSION', 'UNKNOWN');
$route = $utopia->getRoute();
if(is_null($route)) {
$route = new Route($request->getMethod(), $request->getURI());
}
if ($error instanceof AppwriteException) {
$publish = $error->isPublishable();
@ -627,13 +633,6 @@ Http::error()
}
if ($logger && ($publish || $error->getCode() === 0)) {
try {
/** @var Utopia\Database\Document $user */
$user = $utopia->getResource('user');
} catch (\Throwable $th) {
// All good, user is optional information for logger
}
if (isset($user) && !$user->isEmpty()) {
$log->setUser(new User($user->getId()));
}
@ -657,7 +656,7 @@ Http::error()
$log->addExtra('line', $error->getLine());
$log->addExtra('trace', $error->getTraceAsString());
$log->addExtra('detailedTrace', $error->getTrace());
$log->addExtra('roles', $auth->getRoles());
$log->addExtra('roles', $authorization->getRoles());
$action = $route->getLabel("sdk.namespace", "UNKNOWN_NAMESPACE") . '.' . $route->getLabel("sdk.method", "UNKNOWN_METHOD");
$log->setAction($action);
@ -781,7 +780,7 @@ Http::error()
$response->dynamic(
new Document($output),
$utopia->isDevelopment() ? Response::MODEL_ERROR_DEV : Response::MODEL_ERROR
Http::isDevelopment() ? Response::MODEL_ERROR_DEV : Response::MODEL_ERROR
);
});
@ -855,16 +854,18 @@ Http::get('/.well-known/acme-challenge/*')
$response->text($content);
});
include_once __DIR__ . '/shared/api.php';
include_once __DIR__ . '/shared/api/auth.php';
//include_once __DIR__ . '/shared/api.php';
//include_once __DIR__ . '/shared/api/auth.php';
Http::wildcard()
->groups(['api'])
->label('scope', 'global')
->action(function () {
throw new AppwriteException(AppwriteException::GENERAL_ROUTE_NOT_FOUND);
});
// Http::wildcard()
// ->groups(['api'])
// ->label('scope', 'global')
// ->action(function () {
// throw new AppwriteException(AppwriteException::GENERAL_ROUTE_NOT_FOUND);
// });
foreach (Config::getParam('services', []) as $service) {
include_once $service['controller'];
//include_once $service['controller'];
}
include_once 'api/locale.php';

View file

@ -1,11 +1,15 @@
<?php
ini_set('memory_limit', '512M');
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
ini_set('default_socket_timeout', -1);
error_reporting(E_ALL);
require_once __DIR__ . '/../vendor/autoload.php';
use Appwrite\Utopia\Queue\Connections;
use Appwrite\Utopia\Request;
use Appwrite\Utopia\Response;
use Swoole\Process;
use Swoole\Runtime;
use Utopia\Abuse\Adapters\TimeLimit;
use Utopia\Audit\Audit;
use Utopia\CLI\Console;
@ -16,39 +20,53 @@ use Utopia\Database\Helpers\ID;
use Utopia\Database\Helpers\Permission;
use Utopia\Database\Helpers\Role;
use Utopia\Database\Validator\Authorization;
use Utopia\DI\Container;
use Utopia\Http\Adapter\Swoole\Server;
use Utopia\Http\Http;
use Utopia\Pools\Group;
$payloadSize = 6 * (1024 * 1024); // 6MB
$workerNumber = swoole_cpu_num() * intval(Http::getEnv('_APP_WORKER_PER_CORE', 6));
use Utopia\System\System;
// Unlimited memory limit to handle as many coroutines/requests as possible
ini_set('memory_limit', '-1');
Runtime::enableCoroutine(true, SWOOLE_HOOK_ALL);
$container = new Container();
$workerNumber = swoole_cpu_num() * intval(System::getEnv('_APP_WORKER_PER_CORE', 6));
$payloadSize = 6 * (1024 * 1024); // 6MB
include __DIR__ . '/controllers/general.php';
$http = new Http(new Server('0.0.0.0', Http::getEnv('PORT', 80), [
$server = new Server('0.0.0.0', '80', [
'open_http2_protocol' => true,
'http_compression' => true,
'http_compression_level' => 6,
'package_max_length' => $payloadSize,
'buffer_output_size' => $payloadSize,
]), 'UTC');
// 'http_compression' => true,
// 'http_compression_level' => 6,
// Server
// 'log_level' => 0,
'dispatch_mode' => 2,
'worker_num' => $workerNumber,
'reactor_num' => swoole_cpu_num() * 2,
// 'task_worker_num' => $workerNumber,
'open_cpu_affinity' => true,
// Coroutine
'enable_coroutine' => true,
'max_coroutine' => 10000,
]);
$http = new Http($server, $container, 'UTC');
// $http->loadFiles(__DIR__ . '/../console');
$http->setRequestClass(Request::class);
$http->setResponseClass(Response::class);
$http->loadFiles(__DIR__ . '/../console');
require_once __DIR__ . '/init.php';
require_once __DIR__ . '/init2.php';
include __DIR__ . '/controllers/general.php';
go(function () use ($register, $http, $payloadSize) {
$pools = $register->get('pools');
/** @var Group $pools */
Http::setResource('pools', fn () => $pools);
$auth = new Authorization();
global $global;
http::onStart()
->inject('authorization')
->inject('dbForConsole')
->inject('connections')
->action(function (Authorization $authorization, Database $dbForConsole, Connections $connections) {
// wait for database to be ready
$attempts = 0;
$max = 10;
@ -57,9 +75,7 @@ go(function () use ($register, $http, $payloadSize) {
do {
try {
$attempts++;
$dbForConsole = $http->getResource('dbForConsole');
$dbForConsole->ping();
/** @var Utopia\Database\Database $dbForConsole */
break; // leave the do-while if successful
} catch (\Throwable $e) {
Console::warning("Database not ready. Retrying connection ({$attempts})...");
@ -77,16 +93,17 @@ go(function () use ($register, $http, $payloadSize) {
$dbForConsole->create();
} catch (\Throwable $e) {
Console::success('[Setup] - Skip: metadata table already exists');
return true;
}
if ($dbForConsole->getCollection(Audit::COLLECTION)->isEmpty()) {
$audit = new Audit($dbForConsole, $auth);
$audit = new Audit($dbForConsole, $authorization);
$audit->setup();
}
if ($dbForConsole->getCollection(TimeLimit::COLLECTION)->isEmpty()) {
$adapter = new TimeLimit("", 0, 1, $dbForConsole, $auth);
$adapter->setup();
$abuse = new TimeLimit("", 0, 1, $dbForConsole, $authorization);
$abuse->setup();
}
/** @var array $collections */
@ -138,7 +155,7 @@ go(function () use ($register, $http, $payloadSize) {
'$id' => ID::custom('default'),
'$collection' => ID::custom('buckets'),
'name' => 'Default',
'maximumFileSize' => (int) Http::getEnv('_APP_STORAGE_LIMIT', 0), // 10MB
'maximumFileSize' => (int) System::getEnv('_APP_STORAGE_LIMIT', 0), // 10MB
'allowedFileExtensions' => [],
'enabled' => true,
'compression' => 'gzip',
@ -157,6 +174,7 @@ go(function () use ($register, $http, $payloadSize) {
$bucket = $dbForConsole->getDocument('buckets', 'default');
Console::success('[Setup] - Creating files collection for default bucket...');
$files = $collections['buckets']['files'] ?? [];
if (empty($files)) {
throw new Exception('Files collection is not configured.');
@ -192,24 +210,17 @@ go(function () use ($register, $http, $payloadSize) {
$dbForConsole->createCollection('bucket_' . $bucket->getInternalId(), $attributes, $indexes);
}
$pools->reclaim();
$connections->reclaim();
Console::success('[Setup] - Server database init completed...');
Console::success('Server started successfully (max payload is ' . number_format($payloadSize) . ' bytes)');
// listen ctrl + c
Process::signal(2, function () use ($http) {
Console::log('Stop by Ctrl+C');
$http->shutdown();
Console::success('Server started successfully');
});
Http::init()
->inject('auth')
->action(function (Authorization $auth) {
$auth->cleanRoles();
$auth->addRole(Role::any()->toString());
Http::init()
->inject('authorization')
->action(function (Authorization $authorization) {
$authorization->cleanRoles();
$authorization->addRole(Role::any()->toString());
});
$http->start();
});
$http->start();