updated server
This commit is contained in:
parent
08b3182ef3
commit
9e234b7600
2 changed files with 506 additions and 494 deletions
|
@ -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';
|
||||
|
|
337
app/http.php
337
app/http.php
|
@ -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,200 +20,207 @@ 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;
|
||||
|
||||
// wait for database to be ready
|
||||
$attempts = 0;
|
||||
$max = 10;
|
||||
$sleep = 1;
|
||||
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;
|
||||
$sleep = 1;
|
||||
|
||||
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})...");
|
||||
if ($attempts >= $max) {
|
||||
throw new \Exception('Failed to connect to database: ' . $e->getMessage());
|
||||
do {
|
||||
try {
|
||||
$attempts++;
|
||||
$dbForConsole->ping();
|
||||
break; // leave the do-while if successful
|
||||
} catch (\Throwable $e) {
|
||||
Console::warning("Database not ready. Retrying connection ({$attempts})...");
|
||||
if ($attempts >= $max) {
|
||||
throw new \Exception('Failed to connect to database: ' . $e->getMessage());
|
||||
}
|
||||
sleep($sleep);
|
||||
}
|
||||
sleep($sleep);
|
||||
}
|
||||
} while ($attempts < $max);
|
||||
} while ($attempts < $max);
|
||||
|
||||
Console::success('[Setup] - Server database init started...');
|
||||
Console::success('[Setup] - Server database init started...');
|
||||
|
||||
try {
|
||||
Console::success('[Setup] - Creating database: appwrite...');
|
||||
$dbForConsole->create();
|
||||
} catch (\Throwable $e) {
|
||||
Console::success('[Setup] - Skip: metadata table already exists');
|
||||
}
|
||||
|
||||
if ($dbForConsole->getCollection(Audit::COLLECTION)->isEmpty()) {
|
||||
$audit = new Audit($dbForConsole, $auth);
|
||||
$audit->setup();
|
||||
}
|
||||
|
||||
if ($dbForConsole->getCollection(TimeLimit::COLLECTION)->isEmpty()) {
|
||||
$adapter = new TimeLimit("", 0, 1, $dbForConsole, $auth);
|
||||
$adapter->setup();
|
||||
}
|
||||
|
||||
/** @var array $collections */
|
||||
$collections = Config::getParam('collections', []);
|
||||
$consoleCollections = $collections['console'];
|
||||
foreach ($consoleCollections as $key => $collection) {
|
||||
if (($collection['$collection'] ?? '') !== Database::METADATA) {
|
||||
continue;
|
||||
}
|
||||
if (!$dbForConsole->getCollection($key)->isEmpty()) {
|
||||
continue;
|
||||
try {
|
||||
Console::success('[Setup] - Creating database: appwrite...');
|
||||
$dbForConsole->create();
|
||||
} catch (\Throwable $e) {
|
||||
Console::success('[Setup] - Skip: metadata table already exists');
|
||||
return true;
|
||||
}
|
||||
|
||||
Console::success('[Setup] - Creating collection: ' . $collection['$id'] . '...');
|
||||
|
||||
$attributes = [];
|
||||
$indexes = [];
|
||||
|
||||
foreach ($collection['attributes'] as $attribute) {
|
||||
$attributes[] = new Document([
|
||||
'$id' => ID::custom($attribute['$id']),
|
||||
'type' => $attribute['type'],
|
||||
'size' => $attribute['size'],
|
||||
'required' => $attribute['required'],
|
||||
'signed' => $attribute['signed'],
|
||||
'array' => $attribute['array'],
|
||||
'filters' => $attribute['filters'],
|
||||
'default' => $attribute['default'] ?? null,
|
||||
'format' => $attribute['format'] ?? ''
|
||||
]);
|
||||
if ($dbForConsole->getCollection(Audit::COLLECTION)->isEmpty()) {
|
||||
$audit = new Audit($dbForConsole, $authorization);
|
||||
$audit->setup();
|
||||
}
|
||||
|
||||
foreach ($collection['indexes'] as $index) {
|
||||
$indexes[] = new Document([
|
||||
'$id' => ID::custom($index['$id']),
|
||||
'type' => $index['type'],
|
||||
'attributes' => $index['attributes'],
|
||||
'lengths' => $index['lengths'],
|
||||
'orders' => $index['orders'],
|
||||
]);
|
||||
if ($dbForConsole->getCollection(TimeLimit::COLLECTION)->isEmpty()) {
|
||||
$abuse = new TimeLimit("", 0, 1, $dbForConsole, $authorization);
|
||||
$abuse->setup();
|
||||
}
|
||||
|
||||
$dbForConsole->createCollection($key, $attributes, $indexes);
|
||||
}
|
||||
/** @var array $collections */
|
||||
$collections = Config::getParam('collections', []);
|
||||
$consoleCollections = $collections['console'];
|
||||
foreach ($consoleCollections as $key => $collection) {
|
||||
if (($collection['$collection'] ?? '') !== Database::METADATA) {
|
||||
continue;
|
||||
}
|
||||
if (!$dbForConsole->getCollection($key)->isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($dbForConsole->getDocument('buckets', 'default')->isEmpty() && !$dbForConsole->exists($dbForConsole->getDatabase(), 'bucket_1')) {
|
||||
Console::success('[Setup] - Creating default bucket...');
|
||||
$dbForConsole->createDocument('buckets', new Document([
|
||||
'$id' => ID::custom('default'),
|
||||
'$collection' => ID::custom('buckets'),
|
||||
'name' => 'Default',
|
||||
'maximumFileSize' => (int) Http::getEnv('_APP_STORAGE_LIMIT', 0), // 10MB
|
||||
'allowedFileExtensions' => [],
|
||||
'enabled' => true,
|
||||
'compression' => 'gzip',
|
||||
'encryption' => true,
|
||||
'antivirus' => true,
|
||||
'fileSecurity' => true,
|
||||
'$permissions' => [
|
||||
Permission::create(Role::any()),
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
'search' => 'buckets Default',
|
||||
]));
|
||||
Console::success('[Setup] - Creating collection: ' . $collection['$id'] . '...');
|
||||
|
||||
$bucket = $dbForConsole->getDocument('buckets', 'default');
|
||||
$attributes = [];
|
||||
$indexes = [];
|
||||
|
||||
Console::success('[Setup] - Creating files collection for default bucket...');
|
||||
$files = $collections['buckets']['files'] ?? [];
|
||||
if (empty($files)) {
|
||||
throw new Exception('Files collection is not configured.');
|
||||
foreach ($collection['attributes'] as $attribute) {
|
||||
$attributes[] = new Document([
|
||||
'$id' => ID::custom($attribute['$id']),
|
||||
'type' => $attribute['type'],
|
||||
'size' => $attribute['size'],
|
||||
'required' => $attribute['required'],
|
||||
'signed' => $attribute['signed'],
|
||||
'array' => $attribute['array'],
|
||||
'filters' => $attribute['filters'],
|
||||
'default' => $attribute['default'] ?? null,
|
||||
'format' => $attribute['format'] ?? ''
|
||||
]);
|
||||
}
|
||||
|
||||
foreach ($collection['indexes'] as $index) {
|
||||
$indexes[] = new Document([
|
||||
'$id' => ID::custom($index['$id']),
|
||||
'type' => $index['type'],
|
||||
'attributes' => $index['attributes'],
|
||||
'lengths' => $index['lengths'],
|
||||
'orders' => $index['orders'],
|
||||
]);
|
||||
}
|
||||
|
||||
$dbForConsole->createCollection($key, $attributes, $indexes);
|
||||
}
|
||||
|
||||
$attributes = [];
|
||||
$indexes = [];
|
||||
if ($dbForConsole->getDocument('buckets', 'default')->isEmpty() && !$dbForConsole->exists($dbForConsole->getDatabase(), 'bucket_1')) {
|
||||
Console::success('[Setup] - Creating default bucket...');
|
||||
$dbForConsole->createDocument('buckets', new Document([
|
||||
'$id' => ID::custom('default'),
|
||||
'$collection' => ID::custom('buckets'),
|
||||
'name' => 'Default',
|
||||
'maximumFileSize' => (int) System::getEnv('_APP_STORAGE_LIMIT', 0), // 10MB
|
||||
'allowedFileExtensions' => [],
|
||||
'enabled' => true,
|
||||
'compression' => 'gzip',
|
||||
'encryption' => true,
|
||||
'antivirus' => true,
|
||||
'fileSecurity' => true,
|
||||
'$permissions' => [
|
||||
Permission::create(Role::any()),
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
'search' => 'buckets Default',
|
||||
]));
|
||||
|
||||
foreach ($files['attributes'] as $attribute) {
|
||||
$attributes[] = new Document([
|
||||
'$id' => ID::custom($attribute['$id']),
|
||||
'type' => $attribute['type'],
|
||||
'size' => $attribute['size'],
|
||||
'required' => $attribute['required'],
|
||||
'signed' => $attribute['signed'],
|
||||
'array' => $attribute['array'],
|
||||
'filters' => $attribute['filters'],
|
||||
'default' => $attribute['default'] ?? null,
|
||||
'format' => $attribute['format'] ?? ''
|
||||
]);
|
||||
$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.');
|
||||
}
|
||||
|
||||
$attributes = [];
|
||||
$indexes = [];
|
||||
|
||||
foreach ($files['attributes'] as $attribute) {
|
||||
$attributes[] = new Document([
|
||||
'$id' => ID::custom($attribute['$id']),
|
||||
'type' => $attribute['type'],
|
||||
'size' => $attribute['size'],
|
||||
'required' => $attribute['required'],
|
||||
'signed' => $attribute['signed'],
|
||||
'array' => $attribute['array'],
|
||||
'filters' => $attribute['filters'],
|
||||
'default' => $attribute['default'] ?? null,
|
||||
'format' => $attribute['format'] ?? ''
|
||||
]);
|
||||
}
|
||||
|
||||
foreach ($files['indexes'] as $index) {
|
||||
$indexes[] = new Document([
|
||||
'$id' => ID::custom($index['$id']),
|
||||
'type' => $index['type'],
|
||||
'attributes' => $index['attributes'],
|
||||
'lengths' => $index['lengths'],
|
||||
'orders' => $index['orders'],
|
||||
]);
|
||||
}
|
||||
|
||||
$dbForConsole->createCollection('bucket_' . $bucket->getInternalId(), $attributes, $indexes);
|
||||
}
|
||||
|
||||
foreach ($files['indexes'] as $index) {
|
||||
$indexes[] = new Document([
|
||||
'$id' => ID::custom($index['$id']),
|
||||
'type' => $index['type'],
|
||||
'attributes' => $index['attributes'],
|
||||
'lengths' => $index['lengths'],
|
||||
'orders' => $index['orders'],
|
||||
]);
|
||||
}
|
||||
$connections->reclaim();
|
||||
|
||||
$dbForConsole->createCollection('bucket_' . $bucket->getInternalId(), $attributes, $indexes);
|
||||
}
|
||||
|
||||
$pools->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('[Setup] - Server database init completed...');
|
||||
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();
|
Loading…
Reference in a new issue