diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b722a0b19..c1604ce57 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -153,6 +153,12 @@ bash ./build.sh 1.0.0 Before running the command, make sure you have proper write permissions to the Appwrite docker hub team. +**Build for multicore** + +```bash +docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t appwrite/multicore:0.0.0 --push +``` + ## Tests To run tests manually, run phpunit from your command line: @@ -161,6 +167,27 @@ To run tests manually, run phpunit from your command line: docker exec appwrite test ``` +## Benchmarking + +You can use WRK Docker image to benchmark the server performance. Benchmarking is extremely useful when you want to compare how the server behaves before and after a change has been applied. Replace [APPWRITE_HOSTNAME_OR_IP] with your Appwrite server hostname or IP. Note that localhost is not accessible from inside the WRK container. + +``` + Options: + -c, --connections Connections to keep open + -d, --duration Duration of test + -t, --threads Number of threads to use + + -s, --script Load Lua script file + -H, --header Add header to request + --latency Print latency statistics + --timeout Socket/request timeout + -v, --version Print version details +``` + +```bash +docker run --rm skandyla/wrk -t5 -c10 -d30 https://[APPWRITE_HOSTNAME_OR_IP] +``` + ## Code Maintenance We use some automation tools to help us keep a healthy code base. diff --git a/Dockerfile b/Dockerfile index 6ac4169e4..58eba36a4 100755 --- a/Dockerfile +++ b/Dockerfile @@ -130,4 +130,4 @@ RUN echo extension=redis.so >> /usr/local/etc/php/conf.d/redis.ini EXPOSE 80 -CMD [ "php" , "app/server.php" ] \ No newline at end of file +CMD [ "php" , "app/server.php" ] diff --git a/app/config/platforms.php b/app/config/platforms.php index a0b4955a8..c7e6d8b5a 100644 --- a/app/config/platforms.php +++ b/app/config/platforms.php @@ -8,7 +8,7 @@ return [ APP_PLATFORM_CLIENT => [ 'key' => APP_PLATFORM_CLIENT, 'name' => 'Client', - 'description' => 'Client libraries for integrating with '.APP_NAME.' to build client-based applications and websites. Read the [getting started for web](/docs/getting-started-for-web) or [getting started for Flutter](/docs/getting-started-for-flutter) tutorials to start building your first application.', + 'description' => 'Client libraries for integrating with Appwrite to build client-based applications and websites. Read the [getting started for web](/docs/getting-started-for-web) or [getting started for Flutter](/docs/getting-started-for-flutter) tutorials to start building your first application.', 'enabled' => true, 'beta' => false, 'languages' => [ // TODO change key to 'sdks' @@ -121,7 +121,7 @@ return [ APP_PLATFORM_SERVER => [ 'key' => APP_PLATFORM_SERVER, 'name' => 'Server', - 'description' => 'Libraries for integrating with '.APP_NAME.' to build server side integrations. Read the [getting started for server](/docs/getting-started-for-server) tutorial to start building your first server integration.', + 'description' => 'Libraries for integrating with Appwrite to build server side integrations. Read the [getting started for server](/docs/getting-started-for-server) tutorial to start building your first server integration.', 'enabled' => true, 'beta' => false, 'languages' => [ // TODO change key to 'sdks' diff --git a/app/controllers/api/locale.php b/app/controllers/api/locale.php index 3e0d0fa37..8431e00f6 100644 --- a/app/controllers/api/locale.php +++ b/app/controllers/api/locale.php @@ -156,7 +156,6 @@ App::get('/v1/locale/continents') $response->json($list); }, ['response', 'locale']); - App::get('/v1/locale/currencies') ->desc('List Currencies') ->groups(['api', 'locale']) diff --git a/app/controllers/shared/web.php b/app/controllers/shared/web.php index d23828fd2..78402a4f9 100644 --- a/app/controllers/shared/web.php +++ b/app/controllers/shared/web.php @@ -12,7 +12,7 @@ App::init(function ($utopia, $request, $response, $layout) { if (!empty($request->getQuery('version', ''))) { $layout->setPath(__DIR__.'/../../views/layouts/empty.phtml'); } - + $layout ->setParam('title', APP_NAME) ->setParam('protocol', $request->getProtocol()) diff --git a/app/preload.php b/app/preload.php new file mode 100644 index 000000000..9c876d019 --- /dev/null +++ b/app/preload.php @@ -0,0 +1,34 @@ +paths(realpath(__DIR__ . '/../app/config')) + ->paths(realpath(__DIR__ . '/../app/controllers')) + ->paths(realpath(__DIR__ . '/../src')) + ->ignore(realpath(__DIR__ . '/../vendor/twig/twig')) + ->ignore(realpath(__DIR__ . '/../vendor/guzzlehttp/guzzle')) + ->ignore(realpath(__DIR__ . '/../vendor/geoip2')) + ->ignore(realpath(__DIR__ . '/../vendor/maxmind')) + ->ignore(realpath(__DIR__ . '/../vendor/maxmind-db')) + ->ignore(realpath(__DIR__ . '/../vendor/piwik')) + ->load(); \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index b9a8424dc..b4bc24980 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,7 +2,7 @@ version: '3' services: traefik: - image: traefik:v2.1.4 + image: traefik:2.2 container_name: appwrite_traefik command: - --log.level=DEBUG diff --git a/src/Appwrite/Preloader/Preloader.php b/src/Appwrite/Preloader/Preloader.php new file mode 100644 index 000000000..9e6364560 --- /dev/null +++ b/src/Appwrite/Preloader/Preloader.php @@ -0,0 +1,139 @@ +paths = $paths; + + // We'll use composer's classmap + // to easily find which classes to autoload, + // based on their filename + $classMap = require __DIR__ . '/../../../vendor/composer/autoload_classmap.php'; + + $this->paths = array_merge( + $this->paths, + array_values($classMap) + ); + } + + public function paths(string ...$paths): Preloader + { + $this->paths = array_merge( + $this->paths, + $paths + ); + + return $this; + } + + public function ignore(string ...$names): Preloader + { + $this->ignores = array_merge( + $this->ignores, + $names + ); + + return $this; + } + + public function load(): void + { + // We'll loop over all registered paths + // and load them one by one + foreach ($this->paths as $path) { + $this->loadPath(rtrim($path, '/')); + } + + $count = self::$count; + + echo "[Preloader] Preloaded {$count} classes" . PHP_EOL; + } + + private function loadPath(string $path): void + { + // If the current path is a directory, + // we'll load all files in it + if (is_dir($path)) { + $this->loadDir($path); + + return; + } + + // Otherwise we'll just load this one file + $this->loadFile($path); + } + + private function loadDir(string $path): void + { + $handle = opendir($path); + + // We'll loop over all files and directories + // in the current path, + // and load them one by one + while ($file = readdir($handle)) { + if (in_array($file, ['.', '..'])) { + continue; + } + + $this->loadPath("{$path}/{$file}"); + } + + closedir($handle); + } + + private function loadFile(string $path): void + { + // And use it to make sure the class shouldn't be ignored + if ($this->shouldIgnore($path)) { + return; + } + echo "[Preloader] Preloaded `{$path}`" . PHP_EOL; + // Finally we require the path, + // causing all its dependencies to be loaded as well + try { + ob_start(); //Start of build + + require_once $path; + + $output = mb_strlen(ob_get_contents()); + + ob_end_clean(); //End of build + } catch (\Throwable $th) { + echo "[Preloader] Failed to load `{$path}`" . PHP_EOL; + return; + } + + self::$count++; + } + + private function shouldIgnore(?string $path): bool + { + if($path === null) { + return true; + } + + if(!in_array(pathinfo($path, PATHINFO_EXTENSION), ['php'])) { + return true; + } + + foreach ($this->ignores as $ignore) { + if (strpos($path, $ignore) === 0) { + return true; + } + } + + return false; + } +} \ No newline at end of file diff --git a/src/Appwrite/Storage/Device/S3.php b/src/Appwrite/Storage/Device/S3.php index 5270c14d9..2b46c8d44 100644 --- a/src/Appwrite/Storage/Device/S3.php +++ b/src/Appwrite/Storage/Device/S3.php @@ -9,7 +9,7 @@ class S3 extends Device /** * @return string */ - public function getName() + public function getName():string { return 'S3 Storage'; } @@ -17,7 +17,7 @@ class S3 extends Device /** * @return string */ - public function getDescription() + public function getDescription():string { return 'S3 Bucket Storage drive for AWS or on premise solution'; } @@ -25,7 +25,7 @@ class S3 extends Device /** * @return string */ - public function getRoot() + public function getRoot():string { return ''; } @@ -35,14 +35,162 @@ class S3 extends Device * * @return string */ - public function getPath($filename) + public function getPath($filename):string { - $path = ''; - - for ($i = 0; $i < 4; ++$i) { - $path = ($i < \strlen($filename)) ? $path.DIRECTORY_SEPARATOR.$filename[$i] : $path.DIRECTORY_SEPARATOR.'x'; - } - - return $this->getRoot().$path.DIRECTORY_SEPARATOR.$filename; + return ''; } -} + + + /** + * Upload. + * + * Upload a file to desired destination in the selected disk. + * + * @param string $target + * @param string $filename + * + * @throws \Exception + * + * @return string|bool saved destination on success or false on failures + */ + public function upload($source, $path):bool + { + return false; + } + + /** + * Read file by given path. + * + * @param string $path + * + * @return string + */ + public function read(string $path):string + { + return ''; + } + + /** + * Write file by given path. + * + * @param string $path + * @param string $data + * + * @return bool + */ + public function write(string $path, string $data):bool + { + return false; + } + + /** + * Move file from given source to given path, Return true on success and false on failure. + * + * @see http://php.net/manual/en/function.filesize.php + * + * @param string $source + * @param string $target + * + * @return bool + */ + public function move(string $source, string $target):bool + { + return false; + } + + /** + * Delete file in given path, Return true on success and false on failure. + * + * @see http://php.net/manual/en/function.filesize.php + * + * @param string $path + * + * @return bool + */ + public function delete(string $path, bool $recursive = false):bool + { + return false; + } + + /** + * Returns given file path its size. + * + * @see http://php.net/manual/en/function.filesize.php + * + * @param $path + * + * @return int + */ + public function getFileSize(string $path):int + { + return 0; + } + + /** + * Returns given file path its mime type. + * + * @see http://php.net/manual/en/function.mime-content-type.php + * + * @param $path + * + * @return string + */ + public function getFileMimeType(string $path):string + { + return ''; + } + + /** + * Returns given file path its MD5 hash value. + * + * @see http://php.net/manual/en/function.md5-file.php + * + * @param $path + * + * @return string + */ + public function getFileHash(string $path):string + { + return ''; + } + + /** + * Get directory size in bytes. + * + * Return -1 on error + * + * Based on http://www.jonasjohn.de/snippets/php/dir-size.htm + * + * @param $path + * + * @return int + */ + public function getDirectorySize(string $path):int + { + return 0; + } + + /** + * Get Partition Free Space. + * + * disk_free_space — Returns available space on filesystem or disk partition + * + * @return float + */ + public function getPartitionFreeSpace():float + { + return 0.0; + } + + /** + * Get Partition Total Space. + * + * disk_total_space — Returns the total size of a filesystem or disk partition + * + * @return float + */ + public function getPartitionTotalSpace():float + { + return 0.0; + } +} \ No newline at end of file