diff --git a/.env b/.env
index 3406ba1004..581af6d978 100644
--- a/.env
+++ b/.env
@@ -32,8 +32,8 @@ _APP_STORAGE_LIMIT=10000000
_APP_FUNCTIONS_TIMEOUT=900
_APP_FUNCTIONS_CONTAINERS=10
_APP_FUNCTIONS_CPUS=1
-_APP_FUNCTIONS_MEMORY=128
-_APP_FUNCTIONS_MEMORY_SWAP=128
+_APP_FUNCTIONS_MEMORY=256
+_APP_FUNCTIONS_MEMORY_SWAP=256
_APP_MAINTENANCE_INTERVAL=86400
_APP_MAINTENANCE_RETENTION_EXECUTION=1209600
_APP_MAINTENANCE_RETENTION_ABUSE=86400
diff --git a/app/config/environments.php b/app/config/environments.php
index 3e483829b7..9f1c5638e1 100644
--- a/app/config/environments.php
+++ b/app/config/environments.php
@@ -1,8 +1,12 @@
[
'name' => 'Node.js',
'version' => '14.5',
@@ -10,6 +14,7 @@ return [
'image' => 'appwrite/env-node-14.5:1.0.0',
'build' => '/usr/src/code/docker/environments/node-14.5',
'logo' => 'node.png',
+ 'supports' => [System::X86, System::PPC, System::ARM],
],
'node-15.5' => [
'name' => 'Node.js',
@@ -18,6 +23,7 @@ return [
'image' => 'appwrite/env-node-15.5:1.0.0',
'build' => '/usr/src/code/docker/environments/node-15.5',
'logo' => 'node.png',
+ 'supports' => [System::X86, System::PPC, System::ARM],
],
'php-7.4' => [
'name' => 'PHP',
@@ -26,6 +32,7 @@ return [
'image' => 'appwrite/env-php-7.4:1.0.0',
'build' => '/usr/src/code/docker/environments/php-7.4',
'logo' => 'php.png',
+ 'supports' => [System::X86, System::PPC, System::ARM],
],
'php-8.0' => [
'name' => 'PHP',
@@ -34,6 +41,7 @@ return [
'image' => 'appwrite/env-php-8.0:1.0.0',
'build' => '/usr/src/code/docker/environments/php-8.0',
'logo' => 'php.png',
+ 'supports' => [System::X86, System::PPC, System::ARM],
],
'ruby-2.7' => [
'name' => 'Ruby',
@@ -42,6 +50,7 @@ return [
'image' => 'appwrite/env-ruby-2.7:1.0.2',
'build' => '/usr/src/code/docker/environments/ruby-2.7',
'logo' => 'ruby.png',
+ 'supports' => [System::X86, System::PPC, System::ARM],
],
'ruby-3.0' => [
'name' => 'Ruby',
@@ -50,6 +59,7 @@ return [
'image' => 'appwrite/env-ruby-3.0:1.0.0',
'build' => '/usr/src/code/docker/environments/ruby-3.0',
'logo' => 'ruby.png',
+ 'supports' => [System::X86, System::PPC, System::ARM],
],
'python-3.8' => [
'name' => 'Python',
@@ -58,6 +68,7 @@ return [
'image' => 'appwrite/env-python-3.8:1.0.0',
'build' => '/usr/src/code/docker/environments/python-3.8',
'logo' => 'python.png',
+ 'supports' => [System::X86, System::PPC, System::ARM],
],
'deno-1.2' => [
'name' => 'Deno',
@@ -66,6 +77,7 @@ return [
'image' => 'appwrite/env-deno-1.2:1.0.0',
'build' => '/usr/src/code/docker/environments/deno-1.2',
'logo' => 'deno.png',
+ 'supports' => [System::X86, System::PPC, System::ARM],
],
'deno-1.5' => [
'name' => 'Deno',
@@ -74,6 +86,7 @@ return [
'image' => 'appwrite/env-deno-1.5:1.0.0',
'build' => '/usr/src/code/docker/environments/deno-1.5',
'logo' => 'deno.png',
+ 'supports' => [System::X86, System::PPC, System::ARM],
],
'deno-1.6' => [
'name' => 'Deno',
@@ -82,13 +95,44 @@ return [
'image' => 'appwrite/env-deno-1.6:1.0.0',
'build' => '/usr/src/code/docker/environments/deno-1.6',
'logo' => 'deno.png',
+ 'supports' => [System::X86, System::PPC, System::ARM],
],
- // 'dart-2.8' => [
- // 'name' => 'Dart',
- // 'version' => '2.8',
- // 'base' => 'google/dart:2.8',
- // 'image' => 'appwrite/env-dart:2.8',
- // 'build' => '/usr/src/code/docker/environments/dart-2.8',
- // 'logo' => 'dart.png',
- // ],
-];
\ No newline at end of file
+ 'dart-2.10' => [
+ 'name' => 'Dart',
+ 'version' => '2.10',
+ 'base' => 'google/dart:2.10',
+ 'image' => 'appwrite/env-dart-2.10:1.0.0',
+ 'build' => '/usr/src/code/docker/environments/dart-2.10',
+ 'logo' => 'dart.png',
+ 'supports' => [System::X86],
+ ],
+ 'dotnet-3.1' => [
+ 'name' => '.NET',
+ 'version' => '3.1',
+ 'base' => 'mcr.microsoft.com/dotnet/runtime:3.1-alpine',
+ 'image' => 'appwrite/env-dotnet-3.1:1.0.0',
+ 'build' => '/usr/src/code/docker/environments/dotnet-3.1',
+ 'logo' => 'dotnet.png',
+ 'supports' => [System::X86, System::ARM],
+ ],
+ 'dotnet-5.0' => [
+ 'name' => '.NET',
+ 'version' => '5.0',
+ 'base' => 'mcr.microsoft.com/dotnet/runtime:5.0-alpine',
+ 'image' => 'appwrite/env-dotnet-5.0:1.0.0',
+ 'build' => '/usr/src/code/docker/environments/dotnet-5.0',
+ 'logo' => 'dotnet.png',
+ 'supports' => [System::X86, System::ARM],
+ ],
+];
+
+$allowList = empty(App::getEnv('_APP_FUNCTIONS_ENVS', null)) ? false : \explode(',', App::getEnv('_APP_FUNCTIONS_ENVS', null));
+
+$environments = array_filter($environments, function ($environment, $key) use ($allowList) {
+ $isAllowed = $allowList && in_array($key, $allowList);
+ $isSupported = in_array(System::getArchEnum(), $environment["supports"]);
+
+ return $allowList ? ($isAllowed && $isSupported) : $isSupported;
+}, ARRAY_FILTER_USE_BOTH);
+
+return $environments;
\ No newline at end of file
diff --git a/app/config/variables.php b/app/config/variables.php
index cd5d220f3f..011164db25 100644
--- a/app/config/variables.php
+++ b/app/config/variables.php
@@ -1,5 +1,7 @@
'General',
@@ -22,7 +24,7 @@ return [
'question' => '',
],
[
- 'name' => '_APP_OPTIONS_FORCE_HTTPS',
+ 'name' => '_APP_OPTIONS_FORCE_HTTPS',
'description' => 'Allows you to force HTTPS connection to your API. This feature redirects any HTTP call to HTTPS and adds the \'Strict-Transport-Security\' header to all HTTP responses. By default, set to \'disabled\'. To enable, set to \'enabled\'. This feature will work only when your ports are set to default 80 and 443.',
'introduction' => '',
'default' => 'enabled',
@@ -51,7 +53,7 @@ return [
'introduction' => '',
'default' => 'localhost',
'required' => true,
- 'question' => "Enter a DNS A record hostname to serve as a CNAME for your custom domains.\nYou can use the same value as used for the Appwrite hostname.",
+ 'question' => 'Enter a DNS A record hostname to serve as a CNAME for your custom domains.\nYou can use the same value as used for the Appwrite hostname.',
],
[
'name' => '_APP_CONSOLE_WHITELIST_EMAILS',
@@ -63,7 +65,7 @@ return [
],
[
'name' => '_APP_CONSOLE_WHITELIST_DOMAINS',
- 'description' => "This option allows you to limit creation of users to Appwrite console for users sharing the same email domains. This option is very useful for team working with company emails domain.\n\nTo enable this option, pass a list of allowed email domains separated by a comma.",
+ 'description' => 'This option allows you to limit creation of users to Appwrite console for users sharing the same email domains. This option is very useful for team working with company emails domain.\n\nTo enable this option, pass a list of allowed email domains separated by a comma.',
'introduction' => '',
'default' => '',
'required' => false,
@@ -71,7 +73,7 @@ return [
],
[
'name' => '_APP_CONSOLE_WHITELIST_IPS',
- 'description' => "This last option allows you to limit creation of users in Appwrite console for users sharing the same set of IP addresses. This option is very useful for team working with a VPN service or a company IP.\n\nTo enable/activate this option, pass a list of allowed IP addresses separated by a comma.",
+ 'description' => 'This last option allows you to limit creation of users in Appwrite console for users sharing the same set of IP addresses. This option is very useful for team working with a VPN service or a company IP.\n\nTo enable/activate this option, pass a list of allowed IP addresses separated by a comma.',
'introduction' => '',
'default' => '',
'required' => false,
@@ -225,7 +227,7 @@ return [
],
[
'category' => 'SMTP',
- 'description' => "Appwrite is using an SMTP server for emailing your projects users and server admins. The SMTP env vars are used to allow Appwrite server to connect to the SMTP container.\n\nIf running in production, it might be easier to use a 3rd party SMTP server as it might be a little more difficult to set up a production SMTP server that will not send all your emails into your user's SPAM folder.",
+ 'description' => 'Appwrite is using an SMTP server for emailing your projects users and server admins. The SMTP env vars are used to allow Appwrite server to connect to the SMTP container.\n\nIf running in production, it might be easier to use a 3rd party SMTP server as it might be a little more difficult to set up a production SMTP server that will not send all your emails into your user\'s SPAM folder.',
'variables' => [
[
'name' => '_APP_SMTP_HOST',
@@ -347,7 +349,15 @@ return [
'name' => '_APP_FUNCTIONS_MEMORY_SWAP',
'description' => 'The maximum amount of swap memory a single cloud function is allowed to use in megabytes. The default value is 128.',
'introduction' => '0.7.0',
- 'default' => '128',
+ 'default' => '256',
+ 'required' => false,
+ 'question' => '',
+ ],
+ [
+ 'name' => '_APP_FUNCTIONS_ENVS',
+ 'description' => 'This option allows you to limit the available environments for cloud functions. This option is very useful for low-cost servers to safe disk space.\n\nTo enable/activate this option, pass a list of allowed environments separated by a comma.\n\nCurrently, supported environments are: ' . \implode(', ', \array_keys(Config::getParam('providers'))),
+ 'introduction' => '0.7.0',
+ 'default' => 'node-14.5,deno-1.6,php-7.4,python-3.8,ruby-3.0,dotnet-5.0',
'required' => false,
'question' => '',
],
diff --git a/app/views/install/compose.phtml b/app/views/install/compose.phtml
index 231d2f857b..9a182cc628 100644
--- a/app/views/install/compose.phtml
+++ b/app/views/install/compose.phtml
@@ -85,6 +85,7 @@ services:
- _APP_FUNCTIONS_CPUS
- _APP_FUNCTIONS_MEMORY
- _APP_FUNCTIONS_MEMORY_SWAP
+ - _APP_FUNCTIONS_ENVS
appwrite-worker-usage:
image: appwrite/appwrite:
diff --git a/app/workers/functions.php b/app/workers/functions.php
index c3a40f0811..368d40b076 100644
--- a/app/workers/functions.php
+++ b/app/workers/functions.php
@@ -335,7 +335,7 @@ class FunctionsV1
\array_walk($vars, function (&$value, $key) {
$key = $this->filterEnvKey($key);
$value = \escapeshellarg((empty($value)) ? 'null' : $value);
- $value = "\t\t\t--env {$key}={$value} \\";
+ $value = "--env {$key}={$value}";
});
$tagPath = $tag->getAttribute('path', '');
@@ -387,20 +387,20 @@ class FunctionsV1
$executionStart = \microtime(true);
$executionTime = \time();
- $exitCode = Console::execute("docker run \
- -d \
- --entrypoint=\"\" \
- --cpus=".App::getEnv('_APP_FUNCTIONS_CPUS', '1')." \
- --memory=".App::getEnv('_APP_FUNCTIONS_MEMORY', '128')."m \
- --memory-swap=".App::getEnv('_APP_FUNCTIONS_MEMORY_SWAP', '128')."m \
- --name={$container} \
- --label appwrite-type=function \
- --label appwrite-created=".$executionTime." \
- --volume {$tagPathTargetDir}:/tmp:rw \
- --workdir /usr/local/src \
- ".\implode("\n", $vars)."
- {$environment['image']} \
- sh -c 'mv /tmp/code.tar.gz /usr/local/src/code.tar.gz && tar -zxf /usr/local/src/code.tar.gz --strip 1 && rm /usr/local/src/code.tar.gz && tail -f /dev/null'"
+ $exitCode = Console::execute("docker run ".
+ " -d".
+ " --entrypoint=\"\"".
+ " --cpus=".App::getEnv('_APP_FUNCTIONS_CPUS', '1').
+ " --memory=".App::getEnv('_APP_FUNCTIONS_MEMORY', '256')."m".
+ " --memory-swap=".App::getEnv('_APP_FUNCTIONS_MEMORY_SWAP', '256')."m".
+ " --name={$container}".
+ " --label appwrite-type=function".
+ " --label appwrite-created={$executionTime}".
+ " --volume {$tagPathTargetDir}:/tmp:rw".
+ " --workdir /usr/local/src".
+ " ".\implode(" ", $vars).
+ " {$environment['image']}".
+ " sh -c 'mv /tmp/code.tar.gz /usr/local/src/code.tar.gz && tar -zxf /usr/local/src/code.tar.gz --strip 1 && rm /usr/local/src/code.tar.gz && tail -f /dev/null'"
, '', $stdout, $stderr, 30);
$executionEnd = \microtime(true);
@@ -430,11 +430,8 @@ class FunctionsV1
$executionStart = \microtime(true);
- $exitCode = Console::execute("docker exec \
- ".\implode("\n", $vars)."
- {$container} \
- {$command}"
- , '', $stdout, $stderr, $function->getAttribute('timeout', (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900)));
+ $exitCode = Console::execute("docker exec ".\implode(" ", $vars)." {$container} {$command}"
+ , '', $stdout, $stderr, $function->getAttribute('timeout', (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900)));
$executionEnd = \microtime(true);
$executionTime = ($executionEnd - $executionStart);
diff --git a/composer.json b/composer.json
index 8f2390da43..96d183ce66 100644
--- a/composer.json
+++ b/composer.json
@@ -45,6 +45,7 @@
"utopia-php/preloader": "0.2.*",
"utopia-php/domains": "0.2.*",
"utopia-php/swoole": "0.2.*",
+ "utopia-php/system": "0.3.*",
"utopia-php/storage": "0.2.*",
"resque/php-resque": "1.3.6",
diff --git a/composer.lock b/composer.lock
index afdf541573..b1d0a01fd0 100644
--- a/composer.lock
+++ b/composer.lock
@@ -1802,6 +1802,61 @@
"source": "https://github.com/utopia-php/swoole/tree/0.2.0"
},
"time": "2020-10-29T12:42:38+00:00"
+ },
+ {
+ "name": "utopia-php/system",
+ "version": "0.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/utopia-php/system.git",
+ "reference": "63a4f2ea06a60ed82b8904e24b4754df0f77fef2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/utopia-php/system/zipball/63a4f2ea06a60ed82b8904e24b4754df0f77fef2",
+ "reference": "63a4f2ea06a60ed82b8904e24b4754df0f77fef2",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.4"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3",
+ "vimeo/psalm": "4.0.1"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Utopia\\System\\": "src/System"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Eldad Fux",
+ "email": "eldad@appwrite.io"
+ },
+ {
+ "name": "Torsten Dittmann",
+ "email": "torsten@appwrite.io"
+ }
+ ],
+ "description": "A simple library for obtaining information about the host's system.",
+ "keywords": [
+ "framework",
+ "php",
+ "system",
+ "upf",
+ "utopia"
+ ],
+ "support": {
+ "issues": "https://github.com/utopia-php/system/issues",
+ "source": "https://github.com/utopia-php/system/tree/0.3.0"
+ },
+ "time": "2021-01-24T11:28:55+00:00"
}
],
"packages-dev": [
diff --git a/docker-compose.yml b/docker-compose.yml
index e601ae7086..6366e2ad25 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -108,6 +108,7 @@ services:
- _APP_FUNCTIONS_CPUS
- _APP_FUNCTIONS_MEMORY
- _APP_FUNCTIONS_MEMORY_SWAP
+ - _APP_FUNCTIONS_ENVS
appwrite-worker-usage:
entrypoint: worker-usage
diff --git a/docker/environments/build.sh b/docker/environments/build.sh
index 2958614d27..1543c5814d 100644
--- a/docker/environments/build.sh
+++ b/docker/environments/build.sh
@@ -29,3 +29,12 @@ docker buildx build --platform linux/amd64,linux/arm64,linux/386,linux/ppc64le -
echo 'Ruby 3.0...'
docker buildx build --platform linux/amd64,linux/arm64,linux/386,linux/ppc64le -t appwrite/env-ruby-3.0:1.0.0 ./docker/environments/ruby-3.0/ --push
+
+echo 'Dart 2.10...'
+docker buildx build --platform linux/amd64 -t appwrite/env-dart-2.10:1.0.0 ./docker/environments/dart-2.10/ --push
+
+echo '.NET 3.1...'
+docker buildx build --platform linux/amd64,linux/arm64 -t appwrite/env-dotnet-3.1:1.0.0 ./docker/environments/dotnet-3.1/ --push
+
+echo '.NET 5.0...'
+docker buildx build --platform linux/amd64,linux/arm64 -t appwrite/env-dotnet-5.0:1.0.0 ./docker/environments/dotnet-5.0/ --push
diff --git a/docker/environments/dart-2.10/Dockerfile b/docker/environments/dart-2.10/Dockerfile
new file mode 100644
index 0000000000..9216a9b4ee
--- /dev/null
+++ b/docker/environments/dart-2.10/Dockerfile
@@ -0,0 +1,9 @@
+FROM google/dart:2.10
+
+LABEL maintainer="team@appwrite.io"
+
+RUN apt-get update -y && apt-get install -y tar
+
+WORKDIR /usr/local/src/
+
+ENV PUB_CACHE=/usr/local/src/.appwrite
\ No newline at end of file
diff --git a/docker/environments/dotnet-3.1/Dockerfile b/docker/environments/dotnet-3.1/Dockerfile
new file mode 100644
index 0000000000..007b47a50c
--- /dev/null
+++ b/docker/environments/dotnet-3.1/Dockerfile
@@ -0,0 +1,7 @@
+FROM mcr.microsoft.com/dotnet/runtime:3.1-alpine
+
+LABEL maintainer="team@appwrite.io"
+
+RUN apk add tar
+
+WORKDIR /usr/local/src/
diff --git a/docker/environments/dotnet-5.0/Dockerfile b/docker/environments/dotnet-5.0/Dockerfile
new file mode 100644
index 0000000000..e259ae1e45
--- /dev/null
+++ b/docker/environments/dotnet-5.0/Dockerfile
@@ -0,0 +1,7 @@
+FROM mcr.microsoft.com/dotnet/runtime:5.0-alpine
+
+LABEL maintainer="team@appwrite.io"
+
+RUN apk add tar
+
+WORKDIR /usr/local/src/
diff --git a/public/images/environments/dart.png b/public/images/environments/dart.png
new file mode 100644
index 0000000000..1e49a2bf51
Binary files /dev/null and b/public/images/environments/dart.png differ
diff --git a/public/images/environments/dotnet.png b/public/images/environments/dotnet.png
new file mode 100644
index 0000000000..824721f200
Binary files /dev/null and b/public/images/environments/dotnet.png differ
diff --git a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php
index 41a66b1537..5b15b61ceb 100644
--- a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php
+++ b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php
@@ -535,9 +535,34 @@ class FunctionsCustomServerTest extends Scope
'command' => 'deno run --allow-env index.ts',
'timeout' => 15,
],
+ [
+ 'language' => 'Dart',
+ 'version' => '2.10',
+ 'name' => 'dart-2.10',
+ 'code' => $functions.'/dart.tar.gz',
+ 'command' => 'dart main.dart',
+ 'timeout' => 15,
+ ],
+ [
+ 'language' => '.NET',
+ 'version' => '3.1',
+ 'name' => 'dotnet-3.1',
+ 'code' => $functions.'/dotnet-3.1.tar.gz',
+ 'command' => 'dotnet dotnet.dll',
+ 'timeout' => 15,
+ ],
+ [
+ 'language' => '.NET',
+ 'version' => '5.0',
+ 'name' => 'dotnet-5.0',
+ 'code' => $functions.'/dotnet-5.0.tar.gz',
+ 'command' => 'dotnet dotnet.dll',
+ 'timeout' => 15,
+ ],
];
sleep(count($envs) * 20);
+ fwrite(STDERR, ".");
/**
* Test for SUCCESS
@@ -617,7 +642,7 @@ class FunctionsCustomServerTest extends Scope
$executionId = $execution['body']['$id'] ?? '';
$this->assertEquals(201, $execution['headers']['status-code']);
-
+
sleep(30);
$executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', array_merge([
@@ -653,6 +678,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals($stdout[4], $language);
$this->assertEquals($stdout[5], $version);
// $this->assertEquals($stdout[6], $fileId);
+ fwrite(STDERR, ".");
}
return [
@@ -736,4 +762,4 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals($executions['body']['executions'][0]['stdout'], '');
$this->assertEquals($executions['body']['executions'][0]['stderr'], '');
}
-}
\ No newline at end of file
+}
diff --git a/tests/resources/functions/dart.tar.gz b/tests/resources/functions/dart.tar.gz
new file mode 100644
index 0000000000..d444518a92
Binary files /dev/null and b/tests/resources/functions/dart.tar.gz differ
diff --git a/tests/resources/functions/dart/main.dart b/tests/resources/functions/dart/main.dart
new file mode 100644
index 0000000000..8dbe1aa708
--- /dev/null
+++ b/tests/resources/functions/dart/main.dart
@@ -0,0 +1,26 @@
+import "dart:io";
+import "package:dart_appwrite/dart_appwrite.dart";
+
+void main() { // Init SDK
+ Client client = Client();
+
+ client
+ .setEndpoint(Platform.environment["APPWRITE_ENDPOINT"]) // Your API Endpoint
+ .setProject(Platform.environment["APPWRITE_PROJECT"]) // Your project ID
+ .setKey(Platform.environment["APPWRITE_SECRET"]) // Your secret API key
+ ;
+
+ Storage storage = Storage(client);
+
+ //Future result = storage.getFile(fileId: '[FILE_ID]');
+
+ print(Platform.environment["APPWRITE_FUNCTION_ID"]);
+ print(Platform.environment["APPWRITE_FUNCTION_NAME"]);
+ print(Platform.environment["APPWRITE_FUNCTION_TAG"]);
+ print(Platform.environment["APPWRITE_FUNCTION_TRIGGER"]);
+ print(Platform.environment["APPWRITE_FUNCTION_ENV_NAME"]);
+ print(Platform.environment["APPWRITE_FUNCTION_ENV_VERSION"]);
+ // print(result['$id']);
+ print(Platform.environment["APPWRITE_FUNCTION_EVENT"]);
+ print(Platform.environment["APPWRITE_FUNCTION_EVENT_PAYLOAD"]);
+}
\ No newline at end of file
diff --git a/tests/resources/functions/dart/pubspec.yaml b/tests/resources/functions/dart/pubspec.yaml
new file mode 100644
index 0000000000..6478d8c4e1
--- /dev/null
+++ b/tests/resources/functions/dart/pubspec.yaml
@@ -0,0 +1,7 @@
+name: appwrite_cloud_function_demo
+version: 0.1.0
+description: Demo cloud function script.
+environment:
+ sdk: '>=2.10.0 <3.0.0'
+dependencies:
+ dart_appwrite: ^0.1.0
diff --git a/tests/resources/functions/dotnet-3.1.tar.gz b/tests/resources/functions/dotnet-3.1.tar.gz
new file mode 100644
index 0000000000..16627e89ad
Binary files /dev/null and b/tests/resources/functions/dotnet-3.1.tar.gz differ
diff --git a/tests/resources/functions/dotnet-3.1/Program.cs b/tests/resources/functions/dotnet-3.1/Program.cs
new file mode 100644
index 0000000000..ee5894aa7f
--- /dev/null
+++ b/tests/resources/functions/dotnet-3.1/Program.cs
@@ -0,0 +1,28 @@
+using System;
+using Appwrite;
+
+namespace dotnet
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ Client client = new Client();
+
+ client.SetEndPoint(Environment.GetEnvironmentVariable("APPWRITE_ENDPOINT"));
+ client.SetProject(Environment.GetEnvironmentVariable("APPWRITE_PROJECT"));
+ client.SetKey(Environment.GetEnvironmentVariable("APPWRITE_SECRET"));
+
+ Storage storage = new Storage(client);
+
+ Console.WriteLine(Environment.GetEnvironmentVariable("APPWRITE_FUNCTION_ID"));
+ Console.WriteLine(Environment.GetEnvironmentVariable("APPWRITE_FUNCTION_NAME"));
+ Console.WriteLine(Environment.GetEnvironmentVariable("APPWRITE_FUNCTION_TAG"));
+ Console.WriteLine(Environment.GetEnvironmentVariable("APPWRITE_FUNCTION_TRIGGER"));
+ Console.WriteLine(Environment.GetEnvironmentVariable("APPWRITE_FUNCTION_ENV_NAME"));
+ Console.WriteLine(Environment.GetEnvironmentVariable("APPWRITE_FUNCTION_ENV_VERSION"));
+ Console.WriteLine(Environment.GetEnvironmentVariable("APPWRITE_FUNCTION_EVENT"));
+ Console.WriteLine(Environment.GetEnvironmentVariable("APPWRITE_FUNCTION_EVENT_PAYLOAD"));
+ }
+ }
+}
diff --git a/tests/resources/functions/dotnet-3.1/dotnet.csproj b/tests/resources/functions/dotnet-3.1/dotnet.csproj
new file mode 100644
index 0000000000..1b2d649f68
--- /dev/null
+++ b/tests/resources/functions/dotnet-3.1/dotnet.csproj
@@ -0,0 +1,9 @@
+
+
+ Exe
+ netcoreapp3.1
+
+
+
+
+
diff --git a/tests/resources/functions/dotnet-5.0.tar.gz b/tests/resources/functions/dotnet-5.0.tar.gz
new file mode 100644
index 0000000000..7117cf924f
Binary files /dev/null and b/tests/resources/functions/dotnet-5.0.tar.gz differ
diff --git a/tests/resources/functions/dotnet-5.0/Program.cs b/tests/resources/functions/dotnet-5.0/Program.cs
new file mode 100644
index 0000000000..ee5894aa7f
--- /dev/null
+++ b/tests/resources/functions/dotnet-5.0/Program.cs
@@ -0,0 +1,28 @@
+using System;
+using Appwrite;
+
+namespace dotnet
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ Client client = new Client();
+
+ client.SetEndPoint(Environment.GetEnvironmentVariable("APPWRITE_ENDPOINT"));
+ client.SetProject(Environment.GetEnvironmentVariable("APPWRITE_PROJECT"));
+ client.SetKey(Environment.GetEnvironmentVariable("APPWRITE_SECRET"));
+
+ Storage storage = new Storage(client);
+
+ Console.WriteLine(Environment.GetEnvironmentVariable("APPWRITE_FUNCTION_ID"));
+ Console.WriteLine(Environment.GetEnvironmentVariable("APPWRITE_FUNCTION_NAME"));
+ Console.WriteLine(Environment.GetEnvironmentVariable("APPWRITE_FUNCTION_TAG"));
+ Console.WriteLine(Environment.GetEnvironmentVariable("APPWRITE_FUNCTION_TRIGGER"));
+ Console.WriteLine(Environment.GetEnvironmentVariable("APPWRITE_FUNCTION_ENV_NAME"));
+ Console.WriteLine(Environment.GetEnvironmentVariable("APPWRITE_FUNCTION_ENV_VERSION"));
+ Console.WriteLine(Environment.GetEnvironmentVariable("APPWRITE_FUNCTION_EVENT"));
+ Console.WriteLine(Environment.GetEnvironmentVariable("APPWRITE_FUNCTION_EVENT_PAYLOAD"));
+ }
+ }
+}
diff --git a/tests/resources/functions/dotnet-5.0/dotnet.csproj b/tests/resources/functions/dotnet-5.0/dotnet.csproj
new file mode 100644
index 0000000000..84fee71f31
--- /dev/null
+++ b/tests/resources/functions/dotnet-5.0/dotnet.csproj
@@ -0,0 +1,9 @@
+
+
+ Exe
+ net5.0
+
+
+
+
+
diff --git a/tests/resources/functions/package-dart.sh b/tests/resources/functions/package-dart.sh
new file mode 100644
index 0000000000..74cb73ca21
--- /dev/null
+++ b/tests/resources/functions/package-dart.sh
@@ -0,0 +1,13 @@
+
+echo 'Dart Packaging...'
+
+cp -r $(pwd)/tests/resources/functions/dart $(pwd)/tests/resources/functions/packages/dart
+
+docker run --rm -v $(pwd)/tests/resources/functions/packages/dart:/app -w /app appwrite/env-dart-2.10:1.0.0 ls
+docker run --rm -v $(pwd)/tests/resources/functions/packages/dart:/app -w /app --env PUB_CACHE=./.appwrite appwrite/env-dart-2.10:1.0.0 pub get
+
+docker run --rm -v $(pwd)/tests/resources/functions/packages/dart:/app -w /app appwrite/env-dart-2.10:1.0.0 tar -zcvf code.tar.gz .
+
+mv $(pwd)/tests/resources/functions/packages/dart/code.tar.gz $(pwd)/tests/resources/functions/dart.tar.gz
+
+rm -r $(pwd)/tests/resources/functions/packages/dart
diff --git a/tests/resources/functions/package-dotnet-3.1.sh b/tests/resources/functions/package-dotnet-3.1.sh
new file mode 100644
index 0000000000..f3cb92adfc
--- /dev/null
+++ b/tests/resources/functions/package-dotnet-3.1.sh
@@ -0,0 +1,12 @@
+
+echo '.NET 3.1 Packaging...'
+
+cp -r $(pwd)/tests/resources/functions/dotnet-3.1 $(pwd)/tests/resources/functions/packages/dotnet-3.1
+
+docker run --rm -v $(pwd)/tests/resources/functions/packages/dotnet-3.1:/app -w /app mcr.microsoft.com/dotnet/sdk:3.1-alpine dotnet restore
+docker run --rm -v $(pwd)/tests/resources/functions/packages/dotnet-3.1:/app -w /app mcr.microsoft.com/dotnet/sdk:3.1-alpine dotnet publish -o ./release
+docker run --rm -v $(pwd)/tests/resources/functions/packages/dotnet-3.1:/app -w /app/release appwrite/env-dotnet-3.1:1.0.0 tar -zcvf ../code.tar.gz .
+
+mv $(pwd)/tests/resources/functions/packages/dotnet-3.1/code.tar.gz $(pwd)/tests/resources/functions/dotnet-3.1.tar.gz
+
+rm -r $(pwd)/tests/resources/functions/packages/dotnet-3.1
diff --git a/tests/resources/functions/package-dotnet-5.0.sh b/tests/resources/functions/package-dotnet-5.0.sh
new file mode 100644
index 0000000000..d126812488
--- /dev/null
+++ b/tests/resources/functions/package-dotnet-5.0.sh
@@ -0,0 +1,12 @@
+
+echo '.NET 5.0 Packaging...'
+
+cp -r $(pwd)/tests/resources/functions/dotnet-5.0 $(pwd)/tests/resources/functions/packages/dotnet-5.0
+
+docker run --rm -v $(pwd)/tests/resources/functions/packages/dotnet-5.0:/app -w /app mcr.microsoft.com/dotnet/sdk:5.0-alpine dotnet restore
+docker run --rm -v $(pwd)/tests/resources/functions/packages/dotnet-5.0:/app -w /app mcr.microsoft.com/dotnet/sdk:5.0-alpine dotnet publish -o ./release
+docker run --rm -v $(pwd)/tests/resources/functions/packages/dotnet-5.0:/app -w /app/release appwrite/env-dotnet-5.0:1.0.0 tar -zcvf ../code.tar.gz .
+
+mv $(pwd)/tests/resources/functions/packages/dotnet-5.0/code.tar.gz $(pwd)/tests/resources/functions/dotnet-5.0.tar.gz
+
+rm -r $(pwd)/tests/resources/functions/packages/dotnet-5.0