Merge pull request #675 from appwrite/swoole-and-functions
Cloud Functions
This commit is contained in:
commit
8ae624a389
3
.env
3
.env
|
@ -27,3 +27,6 @@ _APP_SMTP_PASSWORD=
|
|||
_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
|
||||
|
|
|
@ -37,6 +37,6 @@ install:
|
|||
script:
|
||||
- docker ps
|
||||
- docker-compose logs appwrite
|
||||
- docker exec appwrite doctor
|
||||
- docker exec appwrite vars
|
||||
- docker exec appwrite test
|
||||
- docker-compose exec appwrite doctor
|
||||
- docker-compose exec appwrite vars
|
||||
- docker-compose exec appwrite test
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
- Added pagination for projects list on the console home page.
|
||||
- Updated storage calculation to match IEC standards
|
||||
- Now using Alpine as base Docker image
|
||||
- Upgraded device detctor to version 3.12.6
|
||||
- Upgraded MariaDB to version 10.5.5
|
||||
- User & Team name max length is now 128 chars and not 100 for better API consistency
|
||||
- Collection name max length is now 128 chars and not 256 for better API consistency
|
||||
- Project name max length is now 128 chars and not 100 for better API consistency
|
||||
|
@ -37,6 +39,7 @@
|
|||
- API Key name max length is now 128 chars and not 256 for better API consistency
|
||||
- Task name max length is now 128 chars and not 256 for better API consistency
|
||||
- Platform name max length is now 128 chars and not 256 for better API consistency
|
||||
- Webhooks payloads are now exactly the same as any of the API response objects
|
||||
- Added new locale: Marathi -mr (@spielers)
|
||||
- New and consistent response format for all API object + new response examples in the docs
|
||||
- Removed user roles attribute from user object (can be fetched from /v1/teams/memberships) **
|
||||
|
|
|
@ -228,11 +228,18 @@ bash ./build.sh X.X.X
|
|||
|
||||
Before running the command, make sure you have proper write permissions to the Appwrite docker hub team.
|
||||
|
||||
**Build for multicore**
|
||||
**Build for Multicore**
|
||||
|
||||
```bash
|
||||
docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x -t appwrite/appwrite:dev --push .
|
||||
```
|
||||
**Build Functions Envs**
|
||||
|
||||
Build envs for all supported cloud functions (multicore builds)
|
||||
|
||||
```bash
|
||||
bash ./docker/environments/build.sh
|
||||
```
|
||||
|
||||
## Tests
|
||||
|
||||
|
|
|
@ -92,6 +92,9 @@ ENV _APP_SERVER=swoole \
|
|||
_APP_SMTP_PORT=25 \
|
||||
_APP_FUNCTIONS_TIMEOUT=900 \
|
||||
_APP_FUNCTIONS_CONTAINERS=10 \
|
||||
_APP_FUNCTIONS_CPUS=1 \
|
||||
_APP_FUNCTIONS_MEMORY=128 \
|
||||
_APP_FUNCTIONS_MEMORY_SWAP=128 \
|
||||
_APP_SETUP=self-hosted \
|
||||
_APP_VERSION=$VERSION
|
||||
#ENV _APP_SMTP_SECURE ''
|
||||
|
|
|
@ -5,35 +5,49 @@ return [
|
|||
'name' => 'Node.js',
|
||||
'version' => '14.5',
|
||||
'base' => 'node:14.5-alpine',
|
||||
'image' => 'appwrite/env-node:14.5',
|
||||
'image' => 'appwrite/env-node-14.5:1.0.0',
|
||||
'logo' => 'node.png',
|
||||
],
|
||||
'php-7.4' => [
|
||||
'name' => 'PHP',
|
||||
'version' => '7.4',
|
||||
'base' => 'php:7.4-cli-alpine',
|
||||
'image' => 'appwrite/env-php:7.4',
|
||||
'image' => 'appwrite/env-php-7.4:1.0.0',
|
||||
'logo' => 'php.png',
|
||||
],
|
||||
'php-8.0' => [
|
||||
'name' => 'PHP',
|
||||
'version' => '8.0',
|
||||
'base' => 'php:8.0-cli-alpine',
|
||||
'image' => 'appwrite/env-php-8.0:1.0.0',
|
||||
'logo' => 'php.png',
|
||||
],
|
||||
'ruby-2.7' => [
|
||||
'name' => 'Ruby',
|
||||
'version' => '2.7',
|
||||
'base' => 'ruby:2.7-alpine',
|
||||
'image' => 'appwrite/env-ruby:2.7',
|
||||
'image' => 'appwrite/env-ruby-2.7:1.0.2',
|
||||
'logo' => 'ruby.png',
|
||||
],
|
||||
'python-3.8' => [
|
||||
'name' => 'Python',
|
||||
'version' => '3.8',
|
||||
'base' => 'python:3.8-alpine',
|
||||
'image' => 'appwrite/env-python:3.8',
|
||||
'image' => 'appwrite/env-python-3.8:1.0.0',
|
||||
'logo' => 'python.png',
|
||||
],
|
||||
'deno-1.2' => [
|
||||
'name' => 'Deno',
|
||||
'version' => '1.2',
|
||||
'base' => 'hayd/deno:alpine-1.2.0',
|
||||
'image' => 'appwrite/env-deno:1.2',
|
||||
'image' => 'appwrite/env-deno-1.2:1.0.0',
|
||||
'logo' => 'deno.png',
|
||||
],
|
||||
'deno-1.5' => [
|
||||
'name' => 'Deno',
|
||||
'version' => '1.5',
|
||||
'base' => 'hayd/deno:alpine-1.5.0',
|
||||
'image' => 'appwrite/env-deno-1.5:1.0.0',
|
||||
'logo' => 'deno.png',
|
||||
],
|
||||
// 'dart-2.8' => [
|
||||
|
|
|
@ -151,4 +151,22 @@ return [
|
|||
'required' => false,
|
||||
'question' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_FUNCTIONS_CPUS',
|
||||
'default' => '1',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_FUNCTIONS_MEMORY',
|
||||
'default' => '128',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_FUNCTIONS_MEMORY_SWAP',
|
||||
'default' => '128',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
],
|
||||
];
|
|
@ -666,7 +666,6 @@ App::post('/v1/functions/:functionId/executions')
|
|||
throw new Exception('Failed saving execution to DB', 500);
|
||||
}
|
||||
|
||||
// Issue a TLS certificate when domain is verified
|
||||
Resque::enqueue('v1-functions', 'FunctionsV1', [
|
||||
'projectId' => $project->getId(),
|
||||
'functionId' => $function->getId(),
|
||||
|
|
|
@ -202,6 +202,7 @@ App::get('/v1/projects/:projectId/usage')
|
|||
|
||||
$requests = [];
|
||||
$network = [];
|
||||
$functions = [];
|
||||
|
||||
if ($client) {
|
||||
$start = $period[$range]['start']->format(DateTime::RFC3339);
|
||||
|
@ -229,6 +230,17 @@ App::get('/v1/projects/:projectId/usage')
|
|||
'date' => \strtotime($point['time']),
|
||||
];
|
||||
}
|
||||
|
||||
// Functions
|
||||
$result = $database->query('SELECT sum(value) AS "value" FROM "appwrite_usage_executions_all" WHERE time > \''.$start.'\' AND time < \''.$end.'\' AND "metric_type"=\'counter\' AND "project"=\''.$project->getId().'\' GROUP BY time('.$period[$range]['group'].') FILL(null)');
|
||||
$points = $result->getPoints();
|
||||
|
||||
foreach ($points as $point) {
|
||||
$functions[] = [
|
||||
'value' => (!empty($point['value'])) ? $point['value'] : 0,
|
||||
'date' => \strtotime($point['time']),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Users
|
||||
|
@ -286,6 +298,12 @@ App::get('/v1/projects/:projectId/usage')
|
|||
return $item['value'];
|
||||
}, $network)),
|
||||
],
|
||||
'functions' => [
|
||||
'data' => $functions,
|
||||
'total' => \array_sum(\array_map(function ($item) {
|
||||
return $item['value'];
|
||||
}, $functions)),
|
||||
],
|
||||
'collections' => [
|
||||
'data' => $collections,
|
||||
'total' => $collectionsTotal,
|
||||
|
|
|
@ -490,7 +490,6 @@ App::get('/v1/teams/:teamId/memberships')
|
|||
'teamId='.$teamId,
|
||||
],
|
||||
]);
|
||||
|
||||
$users = [];
|
||||
|
||||
foreach ($memberships as $membership) {
|
||||
|
|
|
@ -33,6 +33,8 @@ App::init(function ($utopia, $request, $response, $console, $project, $user, $lo
|
|||
/** @var Appwrite\Event\Event $audits */
|
||||
/** @var Appwrite\Event\Event $usage */
|
||||
/** @var Appwrite\Event\Event $deletes */
|
||||
/** @var Appwrite\Event\Event $functions */
|
||||
|
||||
/** @var bool $mode */
|
||||
/** @var array $clients */
|
||||
|
||||
|
@ -220,11 +222,15 @@ App::init(function ($utopia, $request, $response, $console, $project, $user, $lo
|
|||
/*
|
||||
* Background Jobs
|
||||
*/
|
||||
|
||||
$events
|
||||
->setParam('projectId', $project->getId())
|
||||
->setParam('userId', $user->getId())
|
||||
->setParam('event', $route->getLabel('event', ''))
|
||||
->setParam('payload', [])
|
||||
->setParam('functionId', null)
|
||||
->setParam('executionId', null)
|
||||
->setParam('trigger', 'event')
|
||||
;
|
||||
|
||||
$audits
|
||||
|
@ -250,6 +256,7 @@ App::init(function ($utopia, $request, $response, $console, $project, $user, $lo
|
|||
$deletes
|
||||
->setParam('projectId', $project->getId())
|
||||
;
|
||||
|
||||
}, ['utopia', 'request', 'response', 'console', 'project', 'user', 'locale', 'events', 'audits', 'usage', 'deletes', 'clients']);
|
||||
|
||||
App::shutdown(function ($utopia, $request, $response, $project, $events, $audits, $usage, $deletes, $mode) {
|
||||
|
@ -261,6 +268,7 @@ App::shutdown(function ($utopia, $request, $response, $project, $events, $audits
|
|||
/** @var Appwrite\Event\Event $audits */
|
||||
/** @var Appwrite\Event\Event $usage */
|
||||
/** @var Appwrite\Event\Event $deletes */
|
||||
/** @var Appwrite\Event\Event $functions */
|
||||
/** @var bool $mode */
|
||||
|
||||
if (!empty($events->getParam('event'))) {
|
||||
|
@ -268,12 +276,15 @@ App::shutdown(function ($utopia, $request, $response, $project, $events, $audits
|
|||
$events->setParam('payload', $response->getPayload());
|
||||
}
|
||||
|
||||
$events
|
||||
$webhooks = clone $events;
|
||||
$functions = clone $events;
|
||||
|
||||
$webhooks
|
||||
->setQueue('v1-webhooks')
|
||||
->setClass('WebhooksV1')
|
||||
->trigger();
|
||||
|
||||
$events
|
||||
$functions
|
||||
->setQueue('v1-functions')
|
||||
->setClass('FunctionsV1')
|
||||
->trigger();
|
||||
|
@ -299,6 +310,7 @@ App::shutdown(function ($utopia, $request, $response, $project, $events, $audits
|
|||
->trigger()
|
||||
;
|
||||
}
|
||||
|
||||
}, ['utopia', 'request', 'response', 'project', 'events', 'audits', 'usage', 'deletes', 'mode']);
|
||||
|
||||
App::options(function ($request, $response) {
|
||||
|
@ -377,7 +389,7 @@ App::error(function ($error, $utopia, $request, $response, $layout, $project) {
|
|||
->addHeader('Pragma', 'no-cache')
|
||||
->setStatusCode($code)
|
||||
;
|
||||
|
||||
|
||||
if ($template) {
|
||||
$comp = new View($template);
|
||||
|
||||
|
|
|
@ -43,4 +43,4 @@ $preloader
|
|||
->paths(realpath(__DIR__ . '/../app/config'))
|
||||
->paths(realpath(__DIR__ . '/../app/controllers'))
|
||||
->paths(realpath(__DIR__ . '/../src'))
|
||||
->load();
|
||||
->load();
|
||||
|
|
|
@ -85,11 +85,11 @@ $graph = $this->getParam('graph', false);
|
|||
<div class="value margin-bottom-small"><span class="sum" data-ls-bind="{{usage.network.total|humanFileSize}}" data-default="0">0</span></div>
|
||||
<div class="metric margin-bottom-small">Bandwidth</div>
|
||||
|
||||
<!-- <div class="margin-top-large value small">
|
||||
<div class="margin-top-large value small">
|
||||
<b class="text-size-small sum small" data-ls-bind="{{usage.functions.total|statsTotal}}" data-default="0"></b>
|
||||
<br />
|
||||
<b>Func. Executions</b>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -81,6 +81,9 @@ services:
|
|||
- _APP_STORAGE_LIMIT
|
||||
- _APP_FUNCTIONS_TIMEOUT
|
||||
- _APP_FUNCTIONS_CONTAINERS
|
||||
- _APP_FUNCTIONS_CPUS
|
||||
- _APP_FUNCTIONS_MEMORY
|
||||
- _APP_FUNCTIONS_MEMORY_SWAP
|
||||
|
||||
appwrite-worker-usage:
|
||||
image: appwrite/appwrite:<?php echo $version."\n"; ?>
|
||||
|
@ -220,8 +223,8 @@ services:
|
|||
- mariadb
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- /tmp:/tmp:rw
|
||||
- appwrite-functions:/storage/functions:rw
|
||||
- /tmp:/tmp:rw
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_REDIS_HOST
|
||||
|
@ -233,6 +236,9 @@ services:
|
|||
- _APP_DB_PASS
|
||||
- _APP_FUNCTIONS_TIMEOUT
|
||||
- _APP_FUNCTIONS_CONTAINERS
|
||||
- _APP_FUNCTIONS_CPUS
|
||||
- _APP_FUNCTIONS_MEMORY
|
||||
- _APP_FUNCTIONS_MEMORY_SWAP
|
||||
|
||||
appwrite-worker-mails:
|
||||
image: appwrite/appwrite:<?php echo $version."\n"; ?>
|
||||
|
|
|
@ -4,9 +4,12 @@ ini_set('display_startup_errors', 1);
|
|||
error_reporting(E_ALL);
|
||||
|
||||
use Appwrite\Database\Database;
|
||||
use Appwrite\Database\Document;
|
||||
use Appwrite\Database\Adapter\MySQL as MySQLAdapter;
|
||||
use Appwrite\Database\Adapter\Redis as RedisAdapter;
|
||||
use Appwrite\Database\Validator\Authorization;
|
||||
use Appwrite\Event\Event;
|
||||
use Swoole\Runtime;
|
||||
use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Config\Config;
|
||||
|
@ -15,19 +18,26 @@ require_once __DIR__.'/../init.php';
|
|||
|
||||
\cli_set_process_title('Functions V1 Worker');
|
||||
|
||||
Runtime::setHookFlags(SWOOLE_HOOK_ALL);
|
||||
|
||||
Console::success(APP_NAME.' functions worker v1 has started');
|
||||
|
||||
$environments = Config::getParam('environments');
|
||||
|
||||
/**
|
||||
* Warmup Docker Images
|
||||
*/
|
||||
$warmupStart = \microtime(true);
|
||||
|
||||
Co\run(function() use ($environments) {
|
||||
foreach($environments as $environment) { // Warmup: make sure images are ready to run fast 🚀
|
||||
Co\run(function() use ($environments) { // Warmup: make sure images are ready to run fast 🚀
|
||||
Swoole\Runtime::enableCoroutine(SWOOLE_HOOK_ALL);
|
||||
|
||||
foreach($environments as $environment) {
|
||||
go(function() use ($environment) {
|
||||
$stdout = '';
|
||||
$stderr = '';
|
||||
|
||||
Console::info('Warming up '.$environment['name'].' environment');
|
||||
Console::info('Warming up '.$environment['name'].' environment...');
|
||||
|
||||
Console::execute('docker pull '.$environment['image'], '', $stdout, $stderr);
|
||||
|
||||
|
@ -47,6 +57,62 @@ $warmupTime = $warmupEnd - $warmupStart;
|
|||
|
||||
Console::success('Finished warmup in '.$warmupTime.' seconds');
|
||||
|
||||
/**
|
||||
* List function servers
|
||||
*/
|
||||
$stdout = '';
|
||||
$stderr = '';
|
||||
|
||||
$exitCode = Console::execute('docker ps --all --format "name={{.Names}}&status={{.Status}}&labels={{.Labels}}" --filter label=appwrite-type=function'
|
||||
, '', $stdout, $stderr, 30);
|
||||
|
||||
$executionStart = \microtime(true);
|
||||
|
||||
$exitCode = Console::execute('docker ps --all --format "name={{.Names}}&status={{.Status}}&labels={{.Labels}}" --filter label=appwrite-type=function'
|
||||
, '', $stdout, $stderr, 30);
|
||||
|
||||
$executionEnd = \microtime(true);
|
||||
|
||||
$list = [];
|
||||
$stdout = \explode("\n", $stdout);
|
||||
|
||||
\array_map(function($value) use (&$list) {
|
||||
$container = [];
|
||||
|
||||
\parse_str($value, $container);
|
||||
|
||||
if(isset($container['name'])) {
|
||||
// $labels = [];
|
||||
// $temp = explode(',', $container['labels'] ?? []);
|
||||
|
||||
// foreach($temp as &$label) {
|
||||
// $label = explode('=', $label);
|
||||
// $labels[$label[0] || 0] = $label[1] || '';
|
||||
// }
|
||||
|
||||
$container = [
|
||||
'name' => $container['name'],
|
||||
'online' => (\substr($container['status'], 0, 2) === 'Up'),
|
||||
'status' => $container['status'],
|
||||
'labels' => $container['labels'],
|
||||
];
|
||||
|
||||
\array_map(function($value) use (&$container) {
|
||||
$value = \explode('=', $value);
|
||||
|
||||
if(isset($value[0]) && isset($value[1])) {
|
||||
$container[$value[0]] = $value[1];
|
||||
}
|
||||
}, \explode(',', $container['labels']));
|
||||
|
||||
$list[$container['name']] = $container;
|
||||
}
|
||||
}, $stdout);
|
||||
|
||||
var_dump(json_encode($list));
|
||||
|
||||
Console::info(count($list)." functions listed in " . ($executionEnd - $executionStart) . " seconds with exit code {$exitCode}");
|
||||
|
||||
/*
|
||||
* 1. Get Original Task
|
||||
* 2. Check for updates
|
||||
|
@ -69,8 +135,8 @@ Console::success('Finished warmup in '.$warmupTime.' seconds');
|
|||
* + pass one-time api key
|
||||
* 4. Update execution status - DONE
|
||||
* 5. Update execution stdout & stderr - DONE
|
||||
* 6. Trigger audit log
|
||||
* 7. Trigger usage log
|
||||
* 6. Trigger audit log - DONE
|
||||
* 7. Trigger usage log - DONE
|
||||
*/
|
||||
|
||||
//TODO aviod scheduled execution if delay is bigger than X offest
|
||||
|
@ -88,46 +154,141 @@ Console::success('Finished warmup in '.$warmupTime.' seconds');
|
|||
/**
|
||||
* Get Usage Stats
|
||||
* -> Network (docker stats --no-stream --format="{{.NetIO}}" appwrite)
|
||||
* -> CPU Time
|
||||
* -> Invoctions (+1)
|
||||
* Report to usage worker
|
||||
* -> CPU Time - DONE
|
||||
* -> Invoctions (+1) - DONE
|
||||
*/
|
||||
|
||||
// Double-check Cleanup
|
||||
|
||||
class FunctionsV1
|
||||
{
|
||||
public $args = [];
|
||||
|
||||
public $allowed = [];
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
}
|
||||
|
||||
public function perform()
|
||||
{
|
||||
global $environments, $register;
|
||||
global $register;
|
||||
|
||||
$projectId = $this->args['projectId'];
|
||||
$functionId = $this->args['functionId'];
|
||||
$functionTag = $this->args['functionTag'];
|
||||
$executionId = $this->args['executionId'];
|
||||
$functionTrigger = $this->args['functionTrigger'];
|
||||
$projectId = $this->args['projectId'] ?? '';
|
||||
$functionId = $this->args['functionId'] ?? '';
|
||||
$executionId = $this->args['executionId'] ?? '';
|
||||
$trigger = $this->args['trigger'] ?? '';
|
||||
$event = $this->args['event'] ?? '';
|
||||
$payload = (!empty($this->args['payload'])) ? json_encode($this->args['payload']) : '';
|
||||
|
||||
$projectDB = new Database();
|
||||
$projectDB->setAdapter(new RedisAdapter(new MySQLAdapter($register), $register));
|
||||
$projectDB->setNamespace('app_'.$projectId);
|
||||
$projectDB->setMocks(Config::getParam('collections', []));
|
||||
$database = new Database();
|
||||
$database->setAdapter(new RedisAdapter(new MySQLAdapter($register), $register));
|
||||
$database->setNamespace('app_'.$projectId);
|
||||
$database->setMocks(Config::getParam('collections', []));
|
||||
|
||||
Authorization::disable();
|
||||
$function = $projectDB->getDocument($functionId);
|
||||
Authorization::reset();
|
||||
switch ($trigger) {
|
||||
case 'event':
|
||||
$limit = 30;
|
||||
$sum = 30;
|
||||
$offset = 0;
|
||||
$functions = []; /** @var Document[] $functions */
|
||||
|
||||
if (empty($function->getId()) || Database::SYSTEM_COLLECTION_FUNCTIONS != $function->getCollection()) {
|
||||
throw new Exception('Function not found', 404);
|
||||
while ($sum >= $limit) {
|
||||
|
||||
Authorization::disable();
|
||||
|
||||
$functions = $database->getCollection([
|
||||
'limit' => $limit,
|
||||
'offset' => $offset,
|
||||
'orderField' => 'name',
|
||||
'orderType' => 'ASC',
|
||||
'orderCast' => 'string',
|
||||
'filters' => [
|
||||
'$collection='.Database::SYSTEM_COLLECTION_FUNCTIONS,
|
||||
],
|
||||
]);
|
||||
|
||||
Authorization::reset();
|
||||
|
||||
$sum = \count($functions);
|
||||
$offset = $offset + $limit;
|
||||
|
||||
Console::log('Fetched '.$sum.' functions...');
|
||||
|
||||
foreach($functions as $function) {
|
||||
$events = $function->getAttribute('events', []);
|
||||
$tag = $function->getAttribute('tag', []);
|
||||
|
||||
Console::success('Itterating function: '.$function->getAttribute('name'));
|
||||
|
||||
if(!\in_array($event, $events) || empty($tag)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Console::success('Triggered function: '.$event);
|
||||
|
||||
Swoole\Coroutine\run(function () use ($projectId, $database, $function, $event, $payload) {
|
||||
$this->execute('event', $projectId, '', $database, $function, $event, $payload);
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'schedule':
|
||||
/*
|
||||
* 1. Get Original Task
|
||||
* 2. Check for updates
|
||||
* If has updates skip task and don't reschedule
|
||||
* If status not equal to play skip task
|
||||
* 3. Check next run date, update task and add new job at the given date
|
||||
* 4. Execute task (set optional timeout)
|
||||
* 5. Update task response to log
|
||||
* On success reset error count
|
||||
* On failure add error count
|
||||
* If error count bigger than allowed change status to pause
|
||||
*/
|
||||
|
||||
break;
|
||||
|
||||
case 'http':
|
||||
Authorization::disable();
|
||||
$function = $database->getDocument($functionId);
|
||||
Authorization::reset();
|
||||
|
||||
if (empty($function->getId()) || Database::SYSTEM_COLLECTION_FUNCTIONS != $function->getCollection()) {
|
||||
throw new Exception('Function not found ('.$functionId.')');
|
||||
}
|
||||
|
||||
Swoole\Coroutine\run(function () use ($trigger, $projectId, $executionId, $database, $function) {
|
||||
$this->execute($trigger, $projectId, $executionId, $database, $function);
|
||||
});
|
||||
break;
|
||||
|
||||
default:
|
||||
# code...
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute function tag
|
||||
*
|
||||
* @param string $trigger
|
||||
* @param string $projectId
|
||||
* @param string $executionId
|
||||
* @param Database $database
|
||||
* @param Database $function
|
||||
* @param string $event
|
||||
* @param string $payload
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function execute(string $trigger, string $projectId, string $executionId, Database $database, Document $function, string $event = '', string $payload = ''): void
|
||||
{
|
||||
global $register, $list;
|
||||
|
||||
$environments = Config::getParam('environments');
|
||||
|
||||
Authorization::disable();
|
||||
$tag = $projectDB->getDocument($functionTag);
|
||||
$tag = $database->getDocument($function->getAttribute('tag', ''));
|
||||
Authorization::reset();
|
||||
|
||||
if($tag->getAttribute('functionId') !== $function->getId()) {
|
||||
|
@ -136,27 +297,24 @@ class FunctionsV1
|
|||
|
||||
Authorization::disable();
|
||||
|
||||
$execution = $projectDB->getDocument($executionId);
|
||||
$execution = (!empty($executionId)) ? $database->getDocument($executionId) : $database->createDocument([
|
||||
'$collection' => Database::SYSTEM_COLLECTION_EXECUTIONS,
|
||||
'$permissions' => [
|
||||
'read' => [],
|
||||
'write' => [],
|
||||
],
|
||||
'dateCreated' => time(),
|
||||
'functionId' => $function->getId(),
|
||||
'trigger' => $trigger, // http / schedule / event
|
||||
'status' => 'processing', // waiting / processing / completed / failed
|
||||
'exitCode' => 0,
|
||||
'stdout' => '',
|
||||
'stderr' => '',
|
||||
'time' => 0,
|
||||
]);
|
||||
|
||||
if (empty($execution->getId()) || Database::SYSTEM_COLLECTION_EXECUTIONS != $execution->getCollection()) {
|
||||
$execution = $projectDB->createDocument([
|
||||
'$collection' => Database::SYSTEM_COLLECTION_EXECUTIONS,
|
||||
'$permissions' => [
|
||||
'read' => [],
|
||||
'write' => [],
|
||||
],
|
||||
'dateCreated' => \time(),
|
||||
'functionId' => $function->getId(),
|
||||
'status' => 'processing', // waiting / processing / completed / failed
|
||||
'exitCode' => 0,
|
||||
'stdout' => '',
|
||||
'stderr' => '',
|
||||
'time' => 0,
|
||||
]);
|
||||
|
||||
if (false === $execution) {
|
||||
throw new Exception('Failed saving execution to DB', 500);
|
||||
}
|
||||
if(false === $execution) {
|
||||
throw new Exception('Failed to create execution');
|
||||
}
|
||||
|
||||
Authorization::reset();
|
||||
|
@ -170,27 +328,30 @@ class FunctionsV1
|
|||
}
|
||||
|
||||
$vars = \array_merge($function->getAttribute('vars', []), [
|
||||
'APPWRITE_FUNCTION_ID' => $functionId,
|
||||
'APPWRITE_FUNCTION_ID' => $function->getId(),
|
||||
'APPWRITE_FUNCTION_NAME' => $function->getAttribute('name', ''),
|
||||
'APPWRITE_FUNCTION_TAG' => $functionTag,
|
||||
'APPWRITE_FUNCTION_TRIGGER' => $functionTrigger,
|
||||
'APPWRITE_FUNCTION_TAG' => $tag->getId(),
|
||||
'APPWRITE_FUNCTION_TRIGGER' => $trigger,
|
||||
'APPWRITE_FUNCTION_ENV_NAME' => $environment['name'],
|
||||
'APPWRITE_FUNCTION_ENV_VERSION' => $environment['version'],
|
||||
'APPWRITE_FUNCTION_EVENT' => $event,
|
||||
'APPWRITE_FUNCTION_EVENT_PAYLOAD' => $payload,
|
||||
]);
|
||||
|
||||
\array_walk($vars, function (&$value, $key) {
|
||||
$value = (empty($value)) ? 'null' : $value;
|
||||
$key = $this->filterEnvKey($key);
|
||||
$value = \escapeshellarg((empty($value)) ? 'null' : $value);
|
||||
$value = "\t\t\t--env {$key}={$value} \\";
|
||||
});
|
||||
|
||||
$tagPath = $tag->getAttribute('codePath', '');
|
||||
$tagPath = $tag->getAttribute('path', '');
|
||||
$tagPathTarget = '/tmp/project-'.$projectId.'/'.$tag->getId().'/code.tar.gz';
|
||||
$tagPathTargetDir = \pathinfo($tagPathTarget, PATHINFO_DIRNAME);
|
||||
$container = 'appwrite-function-'.$tag->getId();
|
||||
$command = \escapeshellcmd($tag->getAttribute('command', ''));
|
||||
|
||||
if(!\is_readable($tagPath)) {
|
||||
throw new Exception('Code is not readable: '.$tag->getAttribute('codePath', ''));
|
||||
throw new Exception('Code is not readable: '.$tag->getAttribute('path', ''));
|
||||
}
|
||||
|
||||
if (!\file_exists($tagPathTargetDir)) {
|
||||
|
@ -205,47 +366,7 @@ class FunctionsV1
|
|||
}
|
||||
}
|
||||
|
||||
$stdout = '';
|
||||
$stderr = '';
|
||||
|
||||
$executionStart = \microtime(true);
|
||||
|
||||
$exitCode = Console::execute('docker ps --all --format "name={{.Names}}&status={{.Status}}&labels={{.Labels}}" --filter label=appwrite-type=function'
|
||||
, '', $stdout, $stderr, 30);
|
||||
|
||||
$executionEnd = \microtime(true);
|
||||
|
||||
$list = [];
|
||||
$stdout = \explode("\n", $stdout);
|
||||
|
||||
\array_map(function($value) use (&$list) {
|
||||
$container = [];
|
||||
|
||||
\parse_str($value, $container);
|
||||
|
||||
if(isset($container['name'])) {
|
||||
$container = [
|
||||
'name' => $container['name'],
|
||||
'online' => (\substr($container['status'], 0, 2) === 'Up'),
|
||||
'status' => $container['status'],
|
||||
'labels' => $container['labels'],
|
||||
];
|
||||
|
||||
\array_map(function($value) use (&$container) {
|
||||
$value = \explode('=', $value);
|
||||
|
||||
if(isset($value[0]) && isset($value[1])) {
|
||||
$container[$value[0]] = $value[1];
|
||||
}
|
||||
}, \explode(',', $container['labels']));
|
||||
|
||||
$list[$container['name']] = $container;
|
||||
}
|
||||
}, $stdout);
|
||||
|
||||
Console::info("Functions listed in " . ($executionEnd - $executionStart) . " seconds with exit code {$exitCode}");
|
||||
|
||||
if(isset($list[$container]) && !$list[$container]['online']) {
|
||||
if(isset($list[$container]) && !$list[$container]['online']) { // Remove conatiner if not online
|
||||
$stdout = '';
|
||||
$stderr = '';
|
||||
|
||||
|
@ -261,17 +382,17 @@ class FunctionsV1
|
|||
$stderr = '';
|
||||
|
||||
$executionStart = \microtime(true);
|
||||
|
||||
$executionTime = \time();
|
||||
|
||||
$exitCode = Console::execute("docker run \
|
||||
-d \
|
||||
--entrypoint=\"\" \
|
||||
--cpus=4 \
|
||||
--memory=128m \
|
||||
--memory-swap=128m \
|
||||
--rm \
|
||||
--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=".\time()." \
|
||||
--label appwrite-created=".$executionTime." \
|
||||
--volume {$tagPathTargetDir}:/tmp:rw \
|
||||
--workdir /usr/local/src \
|
||||
".\implode("\n", $vars)."
|
||||
|
@ -284,7 +405,17 @@ class FunctionsV1
|
|||
if($exitCode !== 0) {
|
||||
throw new Exception('Failed to create function environment: '.$stderr);
|
||||
}
|
||||
|
||||
|
||||
$list[$container] = [
|
||||
'name' => $container,
|
||||
'online' => true,
|
||||
'status' => 'Up',
|
||||
'labels' => [
|
||||
'appwrite-type' => 'function',
|
||||
'appwrite-created' => $executionTime,
|
||||
],
|
||||
];
|
||||
|
||||
Console::info("Function created in " . ($executionEnd - $executionStart) . " seconds with exit code {$exitCode}");
|
||||
}
|
||||
else {
|
||||
|
@ -296,22 +427,27 @@ class FunctionsV1
|
|||
|
||||
$executionStart = \microtime(true);
|
||||
|
||||
$exitCode = Console::execute("docker exec {$container} {$command}"
|
||||
$exitCode = Console::execute("docker exec \
|
||||
".\implode("\n", $vars)."
|
||||
{$container} \
|
||||
{$command}"
|
||||
, '', $stdout, $stderr, $function->getAttribute('timeout', (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900)));
|
||||
|
||||
$executionEnd = \microtime(true);
|
||||
$executionTime = ($executionEnd - $executionStart);
|
||||
$functionStatus = ($exitCode === 0) ? 'completed' : 'failed';
|
||||
|
||||
Console::info("Function executed in " . ($executionEnd - $executionStart) . " seconds with exit code {$exitCode}");
|
||||
|
||||
Authorization::disable();
|
||||
|
||||
$execution = $projectDB->updateDocument(array_merge($execution->getArrayCopy(), [
|
||||
$execution = $database->updateDocument(array_merge($execution->getArrayCopy(), [
|
||||
'tagId' => $tag->getId(),
|
||||
'status' => ($exitCode === 0) ? 'completed' : 'failed',
|
||||
'status' => $functionStatus,
|
||||
'exitCode' => $exitCode,
|
||||
'stdout' => mb_substr($stdout, -4000), // log last 4000 chars output
|
||||
'stderr' => mb_substr($stderr, -4000), // log last 4000 chars output
|
||||
'time' => ($executionEnd - $executionStart),
|
||||
'stdout' => \mb_substr($stdout, -4000), // log last 4000 chars output
|
||||
'stderr' => \mb_substr($stderr, -4000), // log last 4000 chars output
|
||||
'time' => $executionTime,
|
||||
]));
|
||||
|
||||
Authorization::reset();
|
||||
|
@ -320,6 +456,32 @@ class FunctionsV1
|
|||
throw new Exception('Failed saving execution to DB', 500);
|
||||
}
|
||||
|
||||
$usage = new Event('v1-usage', 'UsageV1');
|
||||
|
||||
$usage
|
||||
->setParam('projectId', $projectId)
|
||||
->setParam('functionId', $function->getId())
|
||||
->setParam('functionExecution', 1)
|
||||
->setParam('functionStatus', $functionStatus)
|
||||
->setParam('functionExecutionTime', $executionTime * 1000) // ms
|
||||
->setParam('networkRequestSize', 0)
|
||||
->setParam('networkResponseSize', 0)
|
||||
;
|
||||
|
||||
$usage->trigger();
|
||||
|
||||
$this->cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup any hanging containers above the allowed max containers.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function cleanup(): void
|
||||
{
|
||||
global $list;
|
||||
|
||||
Console::success(count($list).' running containers counted');
|
||||
|
||||
$max = (int) App::getEnv('_APP_FUNCTIONS_CONTAINERS');
|
||||
|
@ -332,7 +494,7 @@ class FunctionsV1
|
|||
foreach($list as $env) {
|
||||
$sorted[] = [
|
||||
'name' => $env['name'],
|
||||
'created' => (int)$env['appwrite-created']
|
||||
'created' => (int)($env['appwrite-created'] ?? 0)
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -354,6 +516,31 @@ class FunctionsV1
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter ENV vars
|
||||
*
|
||||
* @param string $string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function filterEnvKey(string $string): string
|
||||
{
|
||||
if(empty($this->allowed)) {
|
||||
$this->allowed = array_fill_keys(\str_split('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_'), true);
|
||||
}
|
||||
|
||||
$string = \str_split($string);
|
||||
$output = '';
|
||||
|
||||
foreach ($string as $char) {
|
||||
if(\array_key_exists($char, $this->allowed)) {
|
||||
$output .= $char;
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
public function tearDown(): void
|
||||
{
|
||||
}
|
||||
|
|
|
@ -27,17 +27,19 @@ class UsageV1
|
|||
$statsd = $register->get('statsd', true);
|
||||
|
||||
$projectId = $this->args['projectId'];
|
||||
$httpMethod = $this->args['httpMethod'];
|
||||
$httpRequest = $this->args['httpRequest'];
|
||||
|
||||
|
||||
$storage = $this->args['storage'];
|
||||
|
||||
$networkRequestSize = $this->args['networkRequestSize'];
|
||||
$networkResponseSize = $this->args['networkResponseSize'];
|
||||
|
||||
$storage = $this->args['storage'];
|
||||
$httpMethod = $this->args['httpMethod'];
|
||||
$httpRequest = $this->args['httpRequest'];
|
||||
|
||||
$functionId = $this->args['functionId'];
|
||||
$functionExecution = $this->args['functionExecution'];
|
||||
$functionExecutionTime = $this->args['functionExecutionTime'];
|
||||
$functionId = $this->args['functionId'];
|
||||
$functionStatus = $this->args['functionStatus'];
|
||||
|
||||
$tags = ",project={$projectId},version=".App::getEnv('_APP_VERSION', 'UNKNOWN').'';
|
||||
|
||||
|
@ -49,14 +51,18 @@ class UsageV1
|
|||
}
|
||||
|
||||
if($functionExecution >= 1) {
|
||||
$statsd->increment('executions.all'.$tags.',functionId='.$functionId);
|
||||
$statsd->increment('executions.all'.$tags.',functionId='.$functionId.',functionStatus='.$functionStatus);
|
||||
var_dump($tags.',functionId='.$functionId.',functionStatus='.$functionStatus);
|
||||
$statsd->count('executions.time'.$tags.',functionId='.$functionId, $functionExecutionTime);
|
||||
}
|
||||
|
||||
$statsd->count('network.all'.$tags, $networkRequestSize + $networkResponseSize);
|
||||
$statsd->count('network.inbound'.$tags, $networkRequestSize);
|
||||
$statsd->count('network.outbound'.$tags, $networkResponseSize);
|
||||
$statsd->count('storage.all'.$tags, $storage);
|
||||
$statsd->count('network.all'.$tags, $networkRequestSize + $networkResponseSize);
|
||||
|
||||
if($storage >= 1) {
|
||||
$statsd->count('storage.all'.$tags, $storage);
|
||||
}
|
||||
}
|
||||
|
||||
public function tearDown(): void
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
"utopia-php/abuse": "0.2.*",
|
||||
"utopia-php/audit": "0.3.*",
|
||||
"utopia-php/cache": "0.2.*",
|
||||
"utopia-php/cli": "0.7.2",
|
||||
"utopia-php/cli": "0.7.3",
|
||||
"utopia-php/config": "0.2.*",
|
||||
"utopia-php/locale": "0.3.*",
|
||||
"utopia-php/registry": "0.2.*",
|
||||
|
|
14
composer.lock
generated
14
composer.lock
generated
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "ec0368f495f4b9126f378e0057679100",
|
||||
"content-hash": "aa1bf812ee6a45af12cdfbbfb7229471",
|
||||
"packages": [
|
||||
{
|
||||
"name": "appwrite/php-clamav",
|
||||
|
@ -1268,16 +1268,16 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/cli",
|
||||
"version": "0.7.2",
|
||||
"version": "0.7.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/cli.git",
|
||||
"reference": "0b19cd33b86deb6aeb26bfdabc18bd2bdf5eba04"
|
||||
"reference": "0337918242278e0cf98f8dcab2e75b5a3153b856"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/cli/zipball/0b19cd33b86deb6aeb26bfdabc18bd2bdf5eba04",
|
||||
"reference": "0b19cd33b86deb6aeb26bfdabc18bd2bdf5eba04",
|
||||
"url": "https://api.github.com/repos/utopia-php/cli/zipball/0337918242278e0cf98f8dcab2e75b5a3153b856",
|
||||
"reference": "0337918242278e0cf98f8dcab2e75b5a3153b856",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1315,9 +1315,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/cli/issues",
|
||||
"source": "https://github.com/utopia-php/cli/tree/0.7.2"
|
||||
"source": "https://github.com/utopia-php/cli/tree/0.7.3"
|
||||
},
|
||||
"time": "2020-10-23T13:34:41+00:00"
|
||||
"time": "2020-11-02T07:50:18+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/config",
|
||||
|
|
|
@ -55,7 +55,6 @@ services:
|
|||
- traefik.http.routers.appwrite-secure.rule=PathPrefix(`/`)
|
||||
- traefik.http.routers.appwrite-secure.tls=true
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- appwrite-uploads:/storage/uploads:rw
|
||||
- appwrite-cache:/storage/cache:rw
|
||||
- appwrite-config:/storage/config:rw
|
||||
|
@ -102,6 +101,9 @@ services:
|
|||
- _APP_STORAGE_LIMIT
|
||||
- _APP_FUNCTIONS_TIMEOUT
|
||||
- _APP_FUNCTIONS_CONTAINERS
|
||||
- _APP_FUNCTIONS_CPUS
|
||||
- _APP_FUNCTIONS_MEMORY
|
||||
- _APP_FUNCTIONS_MEMORY_SWAP
|
||||
|
||||
appwrite-worker-usage:
|
||||
entrypoint: worker-usage
|
||||
|
@ -111,6 +113,9 @@ services:
|
|||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- redis
|
||||
- telegraf
|
||||
|
@ -129,6 +134,9 @@ services:
|
|||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
|
@ -150,6 +158,9 @@ services:
|
|||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
|
@ -173,6 +184,9 @@ services:
|
|||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
|
@ -195,12 +209,15 @@ services:
|
|||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
volumes:
|
||||
- appwrite-uploads:/storage/uploads:rw
|
||||
- appwrite-cache:/storage/cache:rw
|
||||
- appwrite-functions:/storage/functions:rw
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_REDIS_HOST
|
||||
|
@ -219,12 +236,14 @@ services:
|
|||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
volumes:
|
||||
- appwrite-config:/storage/config:rw
|
||||
- appwrite-certificates:/storage/certificates:rw
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_SYSTEM_SECURITY_EMAIL_ADDRESS
|
||||
|
@ -244,13 +263,15 @@ services:
|
|||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- appwrite-functions:/storage/functions:rw
|
||||
- /tmp:/tmp:rw
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- /tmp:/tmp:rw
|
||||
- appwrite-functions:/storage/functions:rw
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_REDIS_HOST
|
||||
|
@ -262,6 +283,9 @@ services:
|
|||
- _APP_DB_PASS
|
||||
- _APP_FUNCTIONS_TIMEOUT
|
||||
- _APP_FUNCTIONS_CONTAINERS
|
||||
- _APP_FUNCTIONS_CPUS
|
||||
- _APP_FUNCTIONS_MEMORY
|
||||
- _APP_FUNCTIONS_MEMORY_SWAP
|
||||
|
||||
appwrite-worker-mails:
|
||||
entrypoint: worker-mails
|
||||
|
@ -271,6 +295,9 @@ services:
|
|||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- redis
|
||||
- maildev
|
||||
|
@ -295,6 +322,9 @@ services:
|
|||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- redis
|
||||
environment:
|
||||
|
|
|
@ -2,4 +2,12 @@
|
|||
|
||||
Docker based enviornments for Appwrite Functions. You can use this Docker images to locally tests your functions by executing them on your local desktop or server.
|
||||
|
||||
All the supported enviornments are based on Docker Alpine images.
|
||||
All the supported enviornments are based on Docker Alpine images.
|
||||
|
||||
## Build
|
||||
|
||||
Build envs for all supported cloud functions (multicore builds)
|
||||
|
||||
```bash
|
||||
bash ./docker/environments/build.sh
|
||||
```
|
22
docker/environments/build.sh
Normal file
22
docker/environments/build.sh
Normal file
|
@ -0,0 +1,22 @@
|
|||
echo 'Starting build...'
|
||||
|
||||
echo 'Deno 1.2...'
|
||||
docker buildx build --platform linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/386,linux/ppc64le -t appwrite/env-deno-1.2:1.0.0 ./docker/environments/deno-1.2/ --push
|
||||
|
||||
echo 'Deno 1.5...'
|
||||
docker buildx build --platform linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/386,linux/ppc64le -t appwrite/env-deno-1.5:1.0.0 ./docker/environments/deno-1.5/ --push
|
||||
|
||||
echo 'Node 14.5...'
|
||||
docker buildx build --platform linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/ppc64le -t appwrite/env-node-14.5:1.0.0 ./docker/environments/node-14.5/ --push
|
||||
|
||||
echo 'PHP 7.4...'
|
||||
docker buildx build --platform linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/386,linux/ppc64le -t appwrite/env-php-7.4:1.0.0 ./docker/environments/php-7.4/ --push
|
||||
|
||||
echo 'PHP 8.0...'
|
||||
docker buildx build --platform linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/386,linux/ppc64le -t appwrite/env-php-8.0:1.0.0 ./docker/environments/php-8.0/ --push
|
||||
|
||||
echo 'Python 3.8...'
|
||||
docker buildx build --platform linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/386,linux/ppc64le -t appwrite/env-python-3.8:1.0.0 ./docker/environments/python-3.8/ --push
|
||||
|
||||
echo 'Ruby 2.7...'
|
||||
docker buildx build --platform linux/amd64,linux/arm64,linux/386,linux/ppc64le -t appwrite/env-ruby-2.7:1.0.2 ./docker/environments/ruby-2.7/ --push
|
|
@ -1,7 +0,0 @@
|
|||
echo 'Starting Deno 1.2 build...'
|
||||
|
||||
docker build --tag appwrite/env-deno:1.2 .
|
||||
|
||||
echo 'Pushing Deno 1.2 build to registry...'
|
||||
|
||||
docker push appwrite/env-deno:1.2
|
11
docker/environments/deno-1.5/Dockerfile
Normal file
11
docker/environments/deno-1.5/Dockerfile
Normal file
|
@ -0,0 +1,11 @@
|
|||
FROM hayd/deno:alpine-1.5.0
|
||||
|
||||
LABEL maintainer="team@appwrite.io"
|
||||
|
||||
RUN apk add tar
|
||||
|
||||
RUN mkdir /usr/local/src
|
||||
|
||||
WORKDIR /usr/local/src/
|
||||
|
||||
ENV DENO_DIR=/usr/local/src/.appwrite
|
|
@ -1,7 +0,0 @@
|
|||
echo 'Starting Node 14.5 build...'
|
||||
|
||||
docker build --tag appwrite/env-node:14.5 .
|
||||
|
||||
echo 'Pushing Node 14.5 build to registry...'
|
||||
|
||||
docker push appwrite/env-node:14.5
|
|
@ -1,7 +0,0 @@
|
|||
echo 'Starting PHP 7.4 build...'
|
||||
|
||||
docker build --tag appwrite/env-php:7.4 .
|
||||
|
||||
echo 'Pushing PHP 7.4 build to registry...'
|
||||
|
||||
docker push appwrite/env-php:7.4
|
9
docker/environments/php-8.0/Dockerfile
Normal file
9
docker/environments/php-8.0/Dockerfile
Normal file
|
@ -0,0 +1,9 @@
|
|||
FROM php:8.0-cli-alpine
|
||||
|
||||
LABEL maintainer="team@appwrite.io"
|
||||
|
||||
RUN apk add tar
|
||||
|
||||
RUN mkdir /usr/local/src
|
||||
|
||||
WORKDIR /usr/local/src/
|
|
@ -8,4 +8,4 @@ RUN mkdir /usr/local/src
|
|||
|
||||
WORKDIR /usr/local/src/
|
||||
|
||||
ENV PIP_TARGET=/usr/local/src/.appwrite
|
||||
ENV PYTHONPATH "${PYTHONPATH}:/usr/local/src/.appwrite"
|
|
@ -1,7 +0,0 @@
|
|||
echo 'Starting Python 3.8 build...'
|
||||
|
||||
docker build --tag appwrite/env-python:3.8 .
|
||||
|
||||
echo 'Pushing Python 3.8 build to registry...'
|
||||
|
||||
docker push appwrite/env-python:3.8
|
|
@ -8,5 +8,5 @@ RUN mkdir /usr/local/src
|
|||
|
||||
WORKDIR /usr/local/src/
|
||||
|
||||
ENV GEM_PATH=/usr/local/src/.appwrite/2.1.0
|
||||
ENV GEM_PATH=/usr/local/src/.appwrite
|
||||
ENV GEM_SPEC_CACHE=/usr/local/src/.appwrite/specs
|
|
@ -1,7 +0,0 @@
|
|||
echo 'Starting Ruby 2.7 build...'
|
||||
|
||||
docker build --tag appwrite/env-ruby:2.7 .
|
||||
|
||||
echo 'Pushing Ruby 2.7 build to registry...'
|
||||
|
||||
docker push appwrite/env-ruby:2.7
|
|
@ -0,0 +1,15 @@
|
|||
let sdk = new Appwrite();
|
||||
|
||||
sdk
|
||||
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
|
||||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
.setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key
|
||||
;
|
||||
|
||||
let promise = sdk.functions.getUsage('[FUNCTION_ID]');
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response); // Success
|
||||
}, function (error) {
|
||||
console.log(error); // Failure
|
||||
});
|
122
docs/lists/clients.json
Normal file
122
docs/lists/clients.json
Normal file
|
@ -0,0 +1,122 @@
|
|||
{
|
||||
"36": "360 Phone Browser",
|
||||
"3B": "360 Browser",
|
||||
"AA": "Avant Browser",
|
||||
"AB": "ABrowse",
|
||||
"AG": "ANTGalio",
|
||||
"AM": "Amaya",
|
||||
"AO": "Amigo",
|
||||
"AN": "Android Browser",
|
||||
"AR": "Arora",
|
||||
"AV": "Amiga Voyager",
|
||||
"AW": "Amiga Aweb",
|
||||
"BB": "BlackBerry Browser",
|
||||
"BD": "Baidu Browser",
|
||||
"BS": "Baidu Spark",
|
||||
"BE": "Beonex",
|
||||
"BJ": "Bunjalloo",
|
||||
"BX": "BrowseX",
|
||||
"CA": "Camino",
|
||||
"CC": "Coc Coc",
|
||||
"CD": "Comodo Dragon",
|
||||
"CX": "Charon",
|
||||
"CF": "Chrome Frame",
|
||||
"CH": "Chrome",
|
||||
"CI": "Chrome Mobile iOS",
|
||||
"CK": "Conkeror",
|
||||
"CM": "Chrome Mobile",
|
||||
"CN": "CoolNovo",
|
||||
"CO": "CometBird",
|
||||
"CP": "ChromePlus",
|
||||
"CR": "Chromium",
|
||||
"CS": "Cheshire",
|
||||
"DE": "Deepnet Explorer",
|
||||
"DF": "Dolphin",
|
||||
"DI": "Dillo",
|
||||
"EL": "Elinks",
|
||||
"EP": "Epiphany",
|
||||
"ES": "Espial TV Browser",
|
||||
"FB": "Firebird",
|
||||
"FD": "Fluid",
|
||||
"FE": "Fennec",
|
||||
"FF": "Firefox",
|
||||
"FL": "Flock",
|
||||
"FN": "Fireweb Navigator",
|
||||
"GA": "Galeon",
|
||||
"GE": "Google Earth",
|
||||
"HJ": "HotJava",
|
||||
"IA": "Iceape",
|
||||
"IB": "IBrowse",
|
||||
"IC": "iCab",
|
||||
"ID": "IceDragon",
|
||||
"IW": "Iceweasel",
|
||||
"IE": "Internet Explorer",
|
||||
"IM": "IE Mobile",
|
||||
"IR": "Iron",
|
||||
"JS": "Jasmine",
|
||||
"KI": "Kindle Browser",
|
||||
"KM": "K-meleon",
|
||||
"KO": "Konqueror",
|
||||
"KP": "Kapiko",
|
||||
"KY": "Kylo",
|
||||
"KZ": "Kazehakase",
|
||||
"LB": "Liebao",
|
||||
"LI": "Links",
|
||||
"LS": "Lunascape",
|
||||
"LX": "Lynx",
|
||||
"MB": "MicroB",
|
||||
"MC": "NCSA Mosaic",
|
||||
"ME": "Mercury",
|
||||
"MF": "Mobile Safari",
|
||||
"MI": "Midori",
|
||||
"MU": "MIUI Browser",
|
||||
"MS": "Mobile Silk",
|
||||
"MX": "Maxthon",
|
||||
"NB": "Nokia Browser",
|
||||
"NO": "Nokia OSS Browser",
|
||||
"NV": "Nokia Ovi Browser",
|
||||
"NF": "NetFront",
|
||||
"NL": "NetFront Life",
|
||||
"NP": "NetPositive",
|
||||
"NS": "Netscape",
|
||||
"OB": "Obigo",
|
||||
"OD": "Odyssey Web Browser",
|
||||
"OF": "Off By One",
|
||||
"OE": "ONE Browser",
|
||||
"OI": "Opera Mini",
|
||||
"OM": "Opera Mobile",
|
||||
"OP": "Opera",
|
||||
"ON": "Opera Next",
|
||||
"OR": "Oregano",
|
||||
"OV": "Openwave Mobile Browser",
|
||||
"OW": "OmniWeb",
|
||||
"PL": "Palm Blazer",
|
||||
"PM": "Pale Moon",
|
||||
"PR": "Palm Pre",
|
||||
"PU": "Puffin",
|
||||
"PW": "Palm WebPro",
|
||||
"PX": "Phoenix",
|
||||
"PO": "Polaris",
|
||||
"PS": "Microsoft Edge",
|
||||
"QQ": "QQ Browser",
|
||||
"RK": "Rekonq",
|
||||
"RM": "RockMelt",
|
||||
"SA": "Sailfish Browser",
|
||||
"SC": "SEMC-Browser",
|
||||
"SE": "Sogou Explorer",
|
||||
"SF": "Safari",
|
||||
"SH": "Shiira",
|
||||
"SL": "Sleipnir",
|
||||
"SM": "SeaMonkey",
|
||||
"SN": "Snowshoe",
|
||||
"SR": "Sunrise",
|
||||
"SX": "Swiftfox",
|
||||
"TZ": "Tizen Browser",
|
||||
"UC": "UC Browser",
|
||||
"VI": "Vivaldi",
|
||||
"WE": "WebPositive",
|
||||
"WO": "wOSBrowser",
|
||||
"WT": "WeTab Browser",
|
||||
"YA": "Yandex Browser",
|
||||
"XI": "Xiino"
|
||||
}
|
78
docs/lists/os.json
Normal file
78
docs/lists/os.json
Normal file
|
@ -0,0 +1,78 @@
|
|||
{
|
||||
"AIX": "AIX",
|
||||
"AND": "Android",
|
||||
"AMG": "AmigaOS",
|
||||
"ATV": "Apple TV",
|
||||
"ARL": "Arch Linux",
|
||||
"BTR": "BackTrack",
|
||||
"SBA": "Bada",
|
||||
"BEO": "BeOS",
|
||||
"BLB": "BlackBerry OS",
|
||||
"QNX": "BlackBerry Tablet OS",
|
||||
"BMP": "Brew",
|
||||
"CES": "CentOS",
|
||||
"COS": "Chrome OS",
|
||||
"CYN": "CyanogenMod",
|
||||
"DEB": "Debian",
|
||||
"DFB": "DragonFly",
|
||||
"FED": "Fedora",
|
||||
"FOS": "Firefox OS",
|
||||
"BSD": "FreeBSD",
|
||||
"GNT": "Gentoo",
|
||||
"GTV": "Google TV",
|
||||
"HPX": "HP-UX",
|
||||
"HAI": "Haiku OS",
|
||||
"IRI": "IRIX",
|
||||
"INF": "Inferno",
|
||||
"KNO": "Knoppix",
|
||||
"KBT": "Kubuntu",
|
||||
"LIN": "GNU\/Linux",
|
||||
"LBT": "Lubuntu",
|
||||
"VLN": "VectorLinux",
|
||||
"MAC": "Mac",
|
||||
"MAE": "Maemo",
|
||||
"MDR": "Mandriva",
|
||||
"SMG": "MeeGo",
|
||||
"MCD": "MocorDroid",
|
||||
"MIN": "Mint",
|
||||
"MLD": "MildWild",
|
||||
"MOR": "MorphOS",
|
||||
"NBS": "NetBSD",
|
||||
"MTK": "MTK \/ Nucleus",
|
||||
"WII": "Nintendo",
|
||||
"NDS": "Nintendo Mobile",
|
||||
"OS2": "OS\/2",
|
||||
"T64": "OSF1",
|
||||
"OBS": "OpenBSD",
|
||||
"PSP": "PlayStation Portable",
|
||||
"PS3": "PlayStation",
|
||||
"RHT": "Red Hat",
|
||||
"ROS": "RISC OS",
|
||||
"RZD": "RazoDroiD",
|
||||
"SAB": "Sabayon",
|
||||
"SSE": "SUSE",
|
||||
"SAF": "Sailfish OS",
|
||||
"SLW": "Slackware",
|
||||
"SOS": "Solaris",
|
||||
"SYL": "Syllable",
|
||||
"SYM": "Symbian",
|
||||
"SYS": "Symbian OS",
|
||||
"S40": "Symbian OS Series 40",
|
||||
"S60": "Symbian OS Series 60",
|
||||
"SY3": "Symbian^3",
|
||||
"TDX": "ThreadX",
|
||||
"TIZ": "Tizen",
|
||||
"UBT": "Ubuntu",
|
||||
"WTV": "WebTV",
|
||||
"WIN": "Windows",
|
||||
"WCE": "Windows CE",
|
||||
"WMO": "Windows Mobile",
|
||||
"WPH": "Windows Phone",
|
||||
"WRT": "Windows RT",
|
||||
"XBX": "Xbox",
|
||||
"XBT": "Xubuntu",
|
||||
"YNS": "YunOs",
|
||||
"IOS": "iOS",
|
||||
"POS": "palmOS",
|
||||
"WOS": "webOS"
|
||||
}
|
59
public/dist/scripts/app-all.js
vendored
59
public/dist/scripts/app-all.js
vendored
|
@ -205,7 +205,9 @@ return http.post(path,{'content-type':'multipart/form-data',},payload);},getTag:
|
|||
if(tagId===undefined){throw new Error('Missing required parameter: "tagId"');}
|
||||
let path='/functions/{functionId}/tags/{tagId}'.replace(new RegExp('{functionId}','g'),functionId).replace(new RegExp('{tagId}','g'),tagId);let payload={};return http.get(path,{'content-type':'application/json',},payload);},deleteTag:function(functionId,tagId){if(functionId===undefined){throw new Error('Missing required parameter: "functionId"');}
|
||||
if(tagId===undefined){throw new Error('Missing required parameter: "tagId"');}
|
||||
let path='/functions/{functionId}/tags/{tagId}'.replace(new RegExp('{functionId}','g'),functionId).replace(new RegExp('{tagId}','g'),tagId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);}};let health={get:function(){let path='/health';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getAntiVirus:function(){let path='/health/anti-virus';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCache:function(){let path='/health/cache';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getDB:function(){let path='/health/db';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueCertificates:function(){let path='/health/queue/certificates';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueFunctions:function(){let path='/health/queue/functions';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueLogs:function(){let path='/health/queue/logs';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueTasks:function(){let path='/health/queue/tasks';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueUsage:function(){let path='/health/queue/usage';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueWebhooks:function(){let path='/health/queue/webhooks';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getStorageLocal:function(){let path='/health/storage/local';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getTime:function(){let path='/health/time';let payload={};return http.get(path,{'content-type':'application/json',},payload);}};let locale={get:function(){let path='/locale';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getContinents:function(){let path='/locale/continents';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountries:function(){let path='/locale/countries';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountriesEU:function(){let path='/locale/countries/eu';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountriesPhones:function(){let path='/locale/countries/phones';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCurrencies:function(){let path='/locale/currencies';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getLanguages:function(){let path='/locale/languages';let payload={};return http.get(path,{'content-type':'application/json',},payload);}};let projects={list:function(search='',limit=25,offset=0,orderType='ASC'){let path='/projects';let payload={};if(search){payload['search']=search;}
|
||||
let path='/functions/{functionId}/tags/{tagId}'.replace(new RegExp('{functionId}','g'),functionId).replace(new RegExp('{tagId}','g'),tagId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);},getUsage:function(functionId,range='last30'){if(functionId===undefined){throw new Error('Missing required parameter: "functionId"');}
|
||||
let path='/functions/{functionId}/usage'.replace(new RegExp('{functionId}','g'),functionId);let payload={};if(range){payload['range']=range;}
|
||||
return http.get(path,{'content-type':'application/json',},payload);}};let health={get:function(){let path='/health';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getAntiVirus:function(){let path='/health/anti-virus';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCache:function(){let path='/health/cache';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getDB:function(){let path='/health/db';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueCertificates:function(){let path='/health/queue/certificates';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueFunctions:function(){let path='/health/queue/functions';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueLogs:function(){let path='/health/queue/logs';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueTasks:function(){let path='/health/queue/tasks';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueUsage:function(){let path='/health/queue/usage';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueWebhooks:function(){let path='/health/queue/webhooks';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getStorageLocal:function(){let path='/health/storage/local';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getTime:function(){let path='/health/time';let payload={};return http.get(path,{'content-type':'application/json',},payload);}};let locale={get:function(){let path='/locale';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getContinents:function(){let path='/locale/continents';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountries:function(){let path='/locale/countries';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountriesEU:function(){let path='/locale/countries/eu';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountriesPhones:function(){let path='/locale/countries/phones';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCurrencies:function(){let path='/locale/currencies';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getLanguages:function(){let path='/locale/languages';let payload={};return http.get(path,{'content-type':'application/json',},payload);}};let projects={list:function(search='',limit=25,offset=0,orderType='ASC'){let path='/projects';let payload={};if(search){payload['search']=search;}
|
||||
if(limit){payload['limit']=limit;}
|
||||
if(offset){payload['offset']=offset;}
|
||||
if(orderType){payload['orderType']=orderType;}
|
||||
|
@ -1959,7 +1961,8 @@ if(service.instance){return service.instance;}
|
|||
let instance=(typeof service.object==='function')?this.resolve(service.object):service.object;let skip=false;if(service.watch&&name!=='window'&&name!=='document'&&name!=='element'&&typeof instance==='object'&&instance!==null){let handler={name:service.name,watch:function(){},get:function(target,key){if(key==="__name"){return this.name;}
|
||||
if(key==="__watch"){return this.watch;}
|
||||
if(key==="__proxy"){return true;}
|
||||
if(typeof target[key]==='object'&&target[key]!==null&&!target[key].__proxy){let handler=Object.assign({},this);handler.name=handler.name+'.'+key;return new Proxy(target[key],handler)}else{return target[key];}},set:function(target,key,value,receiver){if(key==="__name"){return this.name=value;}
|
||||
if(typeof target[key]==='object'&&target[key]!==null&&!target[key].__proxy){let handler=Object.assign({},this);handler.name=handler.name+'.'+key;return new Proxy(target[key],handler)}
|
||||
else{return target[key];}},set:function(target,key,value,receiver){if(key==="__name"){return this.name=value;}
|
||||
if(key==="__watch"){return this.watch=value;}
|
||||
target[key]=value;let path=receiver.__name+'.'+key;document.dispatchEvent(new CustomEvent(path+'.changed'));if(skip){return true;}
|
||||
skip=true;container.set('$prop',key,true);container.set('$value',value,true);container.resolve(this.watch);container.set('$key',null,true);container.set('$value',null,true);skip=false;return true;},};instance=new Proxy(instance,handler);}
|
||||
|
@ -1976,7 +1979,8 @@ object[shift].unshift(value);break;case'splice':if(!Array.isArray(object[shift])
|
|||
object[shift].splice(value,1);break;default:object[shift]=value;}
|
||||
return true;}
|
||||
if(!object){return null;}
|
||||
if(!shift){result=object;}else{return object[shift];}
|
||||
if(!shift){result=object;}
|
||||
else{return object[shift];}
|
||||
return result;};let bind=function(element,path,callback){let event=container.scope(path)+'.changed';let service=event.split('.').slice(0,1).pop();let debug=element.getAttribute('data-debug')||false;listeners[service]=listeners[service]||{};listeners[service][event]=true;let printer=(function(x){return function(){if(!document.body.contains(element)){element=null;document.removeEventListener(event,printer,false);return false;}
|
||||
let oldNamespaces=namespaces;namespaces=x;callback();namespaces=oldNamespaces;}}(Object.assign({},namespaces)));document.addEventListener(event,printer);};let addNamespace=function(key,scope){namespaces[key]=scope;return this;}
|
||||
let removeNamespace=function(key){delete namespaces[key];return this;}
|
||||
|
@ -1987,9 +1991,10 @@ if(typeof url!=='string'){throw new Error('var url must be of type string');}
|
|||
if(typeof headers!=='object'){throw new Error('var headers must be of type object');}
|
||||
if(typeof url!=='string'){throw new Error('var url must be of type string');}
|
||||
for(i=0;i<globalParams.length;i++){url=addParam(url,globalParams[i].key,globalParams[i].value);}
|
||||
return new Promise(function(resolve,reject){let xmlhttp=new XMLHttpRequest();xmlhttp.open(method,url,true);xmlhttp.setRequestHeader('Ajax','1');for(i=0;i<globalHeaders.length;i++){xmlhttp.setRequestHeader(globalHeaders[i].key,globalHeaders[i].value);}
|
||||
return new Promise(function(resolve,reject){let xmlhttp=new XMLHttpRequest();xmlhttp.open(method,url,true);for(i=0;i<globalHeaders.length;i++){xmlhttp.setRequestHeader(globalHeaders[i].key,globalHeaders[i].value);}
|
||||
for(let key in headers){if(headers.hasOwnProperty(key)){xmlhttp.setRequestHeader(key,headers[key]);}}
|
||||
xmlhttp.onload=function(){if(4===xmlhttp.readyState&&200===xmlhttp.status){resolve(xmlhttp.response);}else{document.dispatchEvent(new CustomEvent('http-'+method.toLowerCase()+'-'+xmlhttp.status));reject(new Error(xmlhttp.statusText));}};if(progress){xmlhttp.addEventListener('progress',progress);xmlhttp.upload.addEventListener('progress',progress,false);}
|
||||
xmlhttp.onload=function(){if(4===xmlhttp.readyState&&200===xmlhttp.status){resolve(xmlhttp.response);}
|
||||
else{document.dispatchEvent(new CustomEvent('http-'+method.toLowerCase()+'-'+xmlhttp.status));reject(new Error(xmlhttp.statusText));}};if(progress){xmlhttp.addEventListener('progress',progress);xmlhttp.upload.addEventListener('progress',progress,false);}
|
||||
xmlhttp.onerror=function(){reject(new Error("Network Error"));};xmlhttp.send(payload);})};return{'get':function(url){return request('GET',url,{},'')},'post':function(url,headers,payload){return request('POST',url,headers,payload)},'put':function(url,headers,payload){return request('PUT',url,headers,payload)},'patch':function(url,headers,payload){return request('PATCH',url,headers,payload)},'delete':function(url){return request('DELETE',url,{},'')},'addGlobalParam':function(key,value){globalParams.push({key:key,value:value});},'addGlobalHeader':function(key,value){globalHeaders.push({key:key,value:value});}}},true,false);window.ls.container.set('cookie',function(document){function get(name){let value="; "+document.cookie,parts=value.split("; "+name+"=");if(parts.length===2){return parts.pop().split(";").shift();}
|
||||
return null;}
|
||||
function set(name,value,days){let date=new Date();date.setTime(date.getTime()+(days*24*60*60*1000));let expires=(0<days)?'expires='+date.toUTCString():'expires=0';document.cookie=name+"="+value+";"+expires+";path=/";return this;}
|
||||
|
@ -2012,22 +2017,30 @@ object[prop]=defaults[prop];}
|
|||
if(!object.selector){throw new Error('View component is missing a selector attribute');}
|
||||
stock[object.selector]=object;return this;},render:function(element,callback){parse(element,false,callback);element.dispatchEvent(new window.Event('rendered',{bubbles:false}));}}},true,false);window.ls.container.set('router',function(window){let getJsonFromUrl=function(URL){let query;if(URL){let pos=location.search.indexOf('?');if(pos===-1)return[];query=location.search.substr(pos+1);}else{query=location.search.substr(1);}
|
||||
let result={};query.split('&').forEach(function(part){if(!part){return;}
|
||||
part=part.split('+').join(' ');let eq=part.indexOf('=');let key=eq>-1?part.substr(0,eq):part;let val=eq>-1?decodeURIComponent(part.substr(eq+1)):'';let from=key.indexOf('[');if(from===-1){result[decodeURIComponent(key)]=val;}else{let to=key.indexOf(']');let index=decodeURIComponent(key.substring(from+1,to));key=decodeURIComponent(key.substring(0,from));if(!result[key]){result[key]=[];}
|
||||
if(!index){result[key].push(val);}else{result[key][index]=val;}}});return result;};let states=[];let params=getJsonFromUrl(window.location.search);let hash=window.location.hash;let current=null;let previous=null;let getPrevious=()=>previous;let getCurrent=()=>current;let setPrevious=(value)=>{previous=value;return this;};let setCurrent=(value)=>{current=value;return this;};let setParam=function(key,value){params[key]=value;return this;};let getParam=function(key,def){if(key in params){return params[key];}
|
||||
part=part.split('+').join(' ');let eq=part.indexOf('=');let key=eq>-1?part.substr(0,eq):part;let val=eq>-1?decodeURIComponent(part.substr(eq+1)):'';let from=key.indexOf('[');if(from===-1){result[decodeURIComponent(key)]=val;}
|
||||
else{let to=key.indexOf(']');let index=decodeURIComponent(key.substring(from+1,to));key=decodeURIComponent(key.substring(0,from));if(!result[key]){result[key]=[];}
|
||||
if(!index){result[key].push(val);}
|
||||
else{result[key][index]=val;}}});return result;};let states=[];let params=getJsonFromUrl(window.location.search);let hash=window.location.hash;let current=null;let previous=null;let getPrevious=()=>previous;let getCurrent=()=>current;let setPrevious=(value)=>{previous=value;return this;};let setCurrent=(value)=>{current=value;return this;};let setParam=function(key,value){params[key]=value;return this;};let getParam=function(key,def){if(key in params){return params[key];}
|
||||
return def;};let getParams=function(){return params;};let getURL=function(){return window.location.href;};let add=function(path,view){if(typeof path!=='string'){throw new Error('path must be of type string');}
|
||||
if(typeof view!=='object'){throw new Error('view must be of type object');}
|
||||
states[states.length++]={path:path,view:view};return this;};let match=function(location){let url=location.pathname;states.sort(function(a,b){return b.path.length-a.path.length;});states.sort(function(a,b){let n=b.path.split('/').length-a.path.split('/').length;if(n!==0){return n;}
|
||||
return b.path.length-a.path.length;});for(let i=0;i<states.length;i++){let value=states[i];value.path=(value.path.substring(0,1)!=='/')?location.pathname+value.path:value.path;let match=new RegExp("^"+value.path.replace(/:[^\s/]+/g,'([\\w-]+)')+"$");let found=url.match(match);if(found){previous=current;current=value;return value;}}
|
||||
return null};let change=function(URL,replace){if(!replace){window.history.pushState({},'',URL);}else{window.history.replaceState({},'',URL);}
|
||||
return null};let change=function(URL,replace){if(!replace){window.history.pushState({},'',URL);}
|
||||
else{window.history.replaceState({},'',URL);}
|
||||
window.dispatchEvent(new PopStateEvent('popstate',{}));return this;};let reload=function(){return change(window.location.href);};return{setParam:setParam,getParam:getParam,getParams:getParams,getURL:getURL,add:add,change:change,reload:reload,match:match,getCurrent:getCurrent,setCurrent:setCurrent,getPrevious:getPrevious,setPrevious:setPrevious,params:params,hash:hash,reset:function(){this.params=getJsonFromUrl(window.location.search);this.hash=window.location.hash;}};},true,true);window.ls.container.set('expression',function(container,filter){let paths=[];return{regex:/(\{{.*?\}})/gi,parse:function(string,def,cast=false){def=def||'';paths=[];return string.replace(this.regex,match=>{let reference=match.substring(2,match.length-2).replace('[\'','.').replace('\']','').trim();reference=reference.split('|');let path=container.scope((reference[0]||''));let result=container.path(path);path=container.scope(path);if(!paths.includes(path)){paths.push(path);}
|
||||
if(reference.length>=2){for(let i=1;i<reference.length;i++){result=filter.apply(reference[i],result);}}
|
||||
if(null===result||undefined===result){result=def;}else if(typeof result==='object'){result=JSON.stringify(result,null,4);}else if(((typeof result==='object')||(typeof result==='string'))&&cast){result='\''+result+'\'';}
|
||||
if(null===result||undefined===result){result=def;}
|
||||
else if(typeof result==='object'){result=JSON.stringify(result,null,4);}
|
||||
else if(((typeof result==='object')||(typeof result==='string'))&&cast){result='\''+result+'\'';}
|
||||
return result;}).replace(/\\{/g,"{").replace(/\\}/g,"}");},getPaths:()=>paths,}},true,false);window.ls.container.set('filter',function(container){let filters={};let add=function(name,callback){filters[name]=callback;return this;};let apply=function(name,value){container.set('$value',value,true,false);return container.resolve(filters[name]);};add('uppercase',($value)=>{if(typeof $value!=='string'){return $value;}
|
||||
return $value.toUpperCase();});add('lowercase',($value)=>{if(typeof $value!=='string'){return $value;}
|
||||
return $value.toLowerCase();});return{add:add,apply:apply}},true,false);window.ls.container.get('filter').add('escape',value=>{if(typeof value!=='string'){return value;}
|
||||
return value.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/\"/g,'"').replace(/\'/g,''').replace(/\//g,'/');});window.ls=window.ls||{};window.ls.container.set('window',window,true,false).set('document',window.document,true,false).set('element',window.document,true,false);window.ls.run=function(window){try{this.view.render(window.document);}catch(error){let handler=window.ls.container.resolve(this.error);handler(error);}};window.ls.error=()=>{return error=>{console.error('ls-error',error.message,error.stack,error.toString());}};window.ls.router=window.ls.container.get('router');window.ls.view=window.ls.container.get('view');window.ls.filter=window.ls.container.get('filter');window.ls.container.get('view').add({selector:'data-ls-router',repeat:false,controller:function(element,window,document,view,router){let firstFromServer=(element.getAttribute('data-first-from-server')==='true');let scope={selector:'data-ls-scope',template:false,repeat:true,controller:function(){},};let init=function(route){let count=parseInt(element.getAttribute('data-ls-scope-count')||0);element.setAttribute('data-ls-scope-count',count+1);window.scrollTo(0,0);if(window.document.body.scrollTo){window.document.body.scrollTo(0,0);}
|
||||
return value.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/\"/g,'"').replace(/\'/g,''').replace(/\//g,'/');});window.ls=window.ls||{};window.ls.container.set('window',window,true,false).set('document',window.document,true,false).set('element',window.document,true,false);window.ls.run=function(window){try{this.view.render(window.document);}
|
||||
catch(error){let handler=window.ls.container.resolve(this.error);handler(error);}};window.ls.error=()=>{return error=>{console.error('ls-error',error.message,error.stack,error.toString());}};window.ls.router=window.ls.container.get('router');window.ls.view=window.ls.container.get('view');window.ls.filter=window.ls.container.get('filter');window.ls.container.get('view').add({selector:'data-ls-router',controller:function(element,window,document,view,router){let firstFromServer=(element.getAttribute('data-first-from-server')==='true');let scope={selector:'data-ls-scope',template:false,repeat:true,controller:function(){},};let init=function(route){let count=parseInt(element.getAttribute('data-ls-scope-count')||0);element.setAttribute('data-ls-scope-count',count+1);window.scrollTo(0,0);if(window.document.body.scrollTo){window.document.body.scrollTo(0,0);}
|
||||
router.reset();if(null===route){return;}
|
||||
scope.template=(undefined!==route.view.template)?route.view.template:null;scope.controller=(undefined!==route.view.controller)?route.view.controller:function(){};document.dispatchEvent(new CustomEvent('state-change'));if(firstFromServer&&null===router.getPrevious()){scope.template='';document.dispatchEvent(new CustomEvent('state-changed'));}else if(count===1){view.render(element,function(){document.dispatchEvent(new CustomEvent('state-changed'));});}else if(null!==router.getPrevious()){view.render(element,function(){document.dispatchEvent(new CustomEvent('state-changed'));});}};let findParent=function(tagName,el){if((el.nodeName||el.tagName).toLowerCase()===tagName.toLowerCase()){return el;}
|
||||
scope.template=(undefined!==route.view.template)?route.view.template:null;scope.controller=(undefined!==route.view.controller)?route.view.controller:function(){};document.dispatchEvent(new CustomEvent('state-change'));if(firstFromServer&&null===router.getPrevious()){scope.template='';document.dispatchEvent(new CustomEvent('state-changed'));}
|
||||
else if(count===1){view.render(element,function(){document.dispatchEvent(new CustomEvent('state-changed'));});}
|
||||
else if(null!==router.getPrevious()){view.render(element,function(){document.dispatchEvent(new CustomEvent('state-changed'));});}};let findParent=function(tagName,el){if((el.nodeName||el.tagName).toLowerCase()===tagName.toLowerCase()){return el;}
|
||||
while(el=el.parentNode){if((el.nodeName||el.tagName).toLowerCase()===tagName.toLowerCase()){return el;}}
|
||||
return null;};element.removeAttribute('data-ls-router');element.setAttribute('data-ls-scope','');element.setAttribute('data-ls-scope-count',1);view.add(scope);document.addEventListener('click',function(event){let target=findParent('a',event.target);if(!target){return false;}
|
||||
if(!target.href){return false;}
|
||||
|
@ -2041,32 +2054,40 @@ window.history.pushState({},'Unknown',target.href);}
|
|||
init(route);return true;});window.addEventListener('popstate',function(){init(router.match(window.location));});window.addEventListener('hashchange',function(){init(router.match(window.location));});init(router.match(window.location));}});window.ls.container.get('view').add({selector:'data-ls-attrs',controller:function(element,expression,container){let attrs=element.getAttribute('data-ls-attrs').trim().split(',');let paths=[];let debug=element.getAttribute('data-debug')||false;let check=()=>{container.set('element',element,true,false);if(debug){console.info('debug-ls-attrs attributes:',attrs);}
|
||||
for(let i=0;i<attrs.length;i++){let attr=attrs[i];let key=expression.parse((attr.substring(0,attr.indexOf('='))||attr));paths=paths.concat(expression.getPaths());let value='';if(attr.indexOf('=')>-1){value=expression.parse(attr.substring(attr.indexOf('=')+1))||'';paths=paths.concat(expression.getPaths());}
|
||||
if(!key){return null;}
|
||||
element.setAttribute(key,value);}};check();for(let i=0;i<paths.length;i++){let path=paths[i].split('.');while(path.length){container.bind(element,path.join('.'),check);path.pop();}}}});window.ls.container.get('view').add({selector:'data-ls-bind',controller:function(element,expression,container){let debug=element.getAttribute('data-debug')||false;let echo=function(value,bind=true){if(element.tagName==='INPUT'||element.tagName==='SELECT'||element.tagName==='BUTTON'||element.tagName==='TEXTAREA'){let type=element.getAttribute('type');if('radio'===type){if(value.toString()===element.value){element.setAttribute('checked','checked');}else{element.removeAttribute('checked');}
|
||||
element.setAttribute(key,value);}};check();for(let i=0;i<paths.length;i++){let path=paths[i].split('.');while(path.length){container.bind(element,path.join('.'),check);path.pop();}}}});window.ls.container.get('view').add({selector:'data-ls-bind',controller:function(element,expression,container){let debug=element.getAttribute('data-debug')||false;let echo=function(value,bind=true){if(element.tagName==='INPUT'||element.tagName==='SELECT'||element.tagName==='BUTTON'||element.tagName==='TEXTAREA'){let type=element.getAttribute('type');if('radio'===type){if(value.toString()===element.value){element.setAttribute('checked','checked');}
|
||||
else{element.removeAttribute('checked');}
|
||||
if(bind){element.addEventListener('change',()=>{for(let i=0;i<paths.length;i++){if(element.checked){value=element.value;}
|
||||
container.path(paths[i],value);}});}
|
||||
return;}
|
||||
if('checkbox'===type){if(typeof value==='boolean'||value==='true'||value==='false'){if(value===true||value==='true'){element.setAttribute('checked','checked');element.checked=true;}else{element.removeAttribute('checked');element.checked=false;}}else{try{value=JSON.parse(value);element.checked=(Array.isArray(value)&&(value.indexOf(element.value)>-1));value=element.value;}catch{return null;}}
|
||||
if('checkbox'===type){if(typeof value==='boolean'||value==='true'||value==='false'){if(value===true||value==='true'){element.setAttribute('checked','checked');element.checked=true;}
|
||||
else{element.removeAttribute('checked');element.checked=false;}}
|
||||
else{try{value=JSON.parse(value);element.checked=(Array.isArray(value)&&(value.indexOf(element.value)>-1));value=element.value;}
|
||||
catch{return null;}}
|
||||
if(bind){element.addEventListener('change',()=>{for(let i=0;i<paths.length;i++){let value=container.path(paths[i]);let index=value.indexOf(element.value);if(element.checked&&index<0){value.push(element.value);}
|
||||
if(!element.checked&&index>-1){value.splice(index,1);}
|
||||
container.path(paths[i],value);}});}
|
||||
return;}
|
||||
if(element.value!==value){element.value=value;element.dispatchEvent(new Event('change'));}
|
||||
if(bind){element.addEventListener('input',sync);element.addEventListener('change',sync);}}else{if(element.textContent!=value){element.innerHTML=value;}}};let sync=(()=>{return()=>{if(debug){console.info('debug-ls-bind','sync-path',paths);console.info('debug-ls-bind','sync-syntax',syntax);console.info('debug-ls-bind','sync-syntax-parsed',parsedSyntax);console.info('debug-ls-bind','sync-value',element.value);}
|
||||
if(bind){element.addEventListener('input',sync);element.addEventListener('change',sync);}}
|
||||
else{if(element.innerHTML!=value){element.innerHTML=value;}}};let sync=(()=>{return()=>{if(debug){console.info('debug-ls-bind','sync-path',paths);console.info('debug-ls-bind','sync-syntax',syntax);console.info('debug-ls-bind','sync-syntax-parsed',parsedSyntax);console.info('debug-ls-bind','sync-value',element.value);}
|
||||
for(let i=0;i<paths.length;i++){if('{{'+paths[i]+'}}'!==parsedSyntax){if(debug){console.info('debug-ls-bind','sync-skipped-path',paths[i]);console.info('debug-ls-bind','sync-skipped-syntax',syntax);console.info('debug-ls-bind','sync-skipped-syntax-parsed',parsedSyntax);}
|
||||
continue;}
|
||||
if(debug){console.info('debug-ls-bind','sync-loop-path',paths[i]);console.info('debug-ls-bind','sync-loop-syntax',parsedSyntax);}
|
||||
container.path(paths[i],element.value);}}})();let syntax=element.getAttribute('data-ls-bind');let parsedSyntax=container.scope(syntax);let unsync=(!!element.getAttribute('data-unsync'))||false;let result=expression.parse(syntax);let paths=expression.getPaths();echo(result,!unsync);element.addEventListener('looped',function(){echo(expression.parse(parsedSyntax),false);});for(let i=0;i<paths.length;i++){let path=paths[i].split('.');if(debug){console.info('debug-ls-bind','bind-path',path);console.info('debug-ls-bind','bind-syntax',syntax);}
|
||||
while(path.length){container.bind(element,path.join('.'),()=>{echo(expression.parse(parsedSyntax),false);});path.pop();}}}});window.ls.container.get('view').add({selector:'data-ls-if',controller:function(element,expression,container,view){let result='';let syntax=element.getAttribute('data-ls-if')||'';let debug=element.getAttribute('data-debug')||false;let paths=[];let check=()=>{if(debug){console.info('debug-ls-if',expression.parse(syntax.replace(/(\r\n|\n|\r)/gm,' '),'undefined',true));}
|
||||
try{result=(eval(expression.parse(syntax.replace(/(\r\n|\n|\r)/gm,' '),'undefined',true)));}catch(error){throw new Error('Failed to evaluate expression "'+syntax+' (resulted with: "'+result+'")": '+error);}
|
||||
try{result=(eval(expression.parse(syntax.replace(/(\r\n|\n|\r)/gm,' '),'undefined',true)));}
|
||||
catch(error){throw new Error('Failed to evaluate expression "'+syntax+' (resulted with: "'+result+'")": '+error);}
|
||||
if(debug){console.info('debug-ls-if result:',result);}
|
||||
paths=expression.getPaths();let prv=element.$lsSkip;element.$lsSkip=!result;if(!result){element.style.visibility='hidden';element.style.display='none';}else{element.style.removeProperty('display');element.style.removeProperty('visibility');}
|
||||
if(prv===true&&element.$lsSkip===false){view.render(element)}};check();for(let i=0;i<paths.length;i++){let path=paths[i].split('.');while(path.length){container.bind(element,path.join('.'),check);path.pop();}}}});window.ls.container.get('view').add({selector:'data-ls-loop',template:false,repeat:false,nested:false,controller:function(element,view,container,window,expression){let expr=expression.parse(element.getAttribute('data-ls-loop'));let as=element.getAttribute('data-ls-as');let key=element.getAttribute('data-ls-key')||'$index';let limit=parseInt(expression.parse(element.getAttribute('data-limit')||'')||-1);let debug=element.getAttribute('data-debug')||false;let echo=function(){let array=container.path(expr);let counter=0;array=(!array)?[]:array;let watch=!!(array&&array.__proxy);while(element.hasChildNodes()){element.removeChild(element.lastChild);element.lastChild=null;}
|
||||
paths=expression.getPaths();let prv=element.$lsSkip;element.$lsSkip=!result;if(!result){element.style.visibility='hidden';element.style.display='none';}
|
||||
else{element.style.removeProperty('display');element.style.removeProperty('visibility');}
|
||||
if(prv===true&&element.$lsSkip===false){view.render(element)}};check();for(let i=0;i<paths.length;i++){let path=paths[i].split('.');while(path.length){container.bind(element,path.join('.'),check);path.pop();}}}});window.ls.container.get('view').add({selector:'data-ls-loop',template:false,nested:false,controller:function(element,view,container,window,expression){let expr=expression.parse(element.getAttribute('data-ls-loop'));let as=element.getAttribute('data-ls-as');let key=element.getAttribute('data-ls-key')||'$index';let limit=parseInt(expression.parse(element.getAttribute('data-limit')||'')||-1);let debug=element.getAttribute('data-debug')||false;let echo=function(){let array=container.path(expr);let counter=0;array=(!array)?[]:array;let watch=!!(array&&array.__proxy);while(element.hasChildNodes()){element.removeChild(element.lastChild);element.lastChild=null;}
|
||||
if(array instanceof Array&&typeof array!=='object'){throw new Error('Reference value must be array or object. '+(typeof array)+' given');}
|
||||
let children=[];element.$lsSkip=true;element.style.visibility=(0===array.length)?'hidden':'visible';for(let prop in array){if(counter==limit){break;}
|
||||
let children=[];element.$lsSkip=true;for(let prop in array){if(counter==limit){break;}
|
||||
counter++;if(!array.hasOwnProperty(prop)){continue;}
|
||||
children[prop]=template.cloneNode(true);element.appendChild(children[prop]);(index=>{let context=expr+'.'+index;container.addNamespace(as,context);if(debug){console.info('debug-ls-loop','index',index);console.info('debug-ls-loop','context',context);console.info('debug-ls-loop','context-path',container.path(context).name);console.info('debug-ls-loop','namespaces',container.namespaces);}
|
||||
container.set(as,container.path(context),true,watch);container.set(key,index,true,false);view.render(children[prop]);container.removeNamespace(as);})(prop);}
|
||||
element.dispatchEvent(new Event('looped'));};let template=(element.children.length===1)?element.children[0]:window.document.createElement('li');echo();container.bind(element,expr+'.length',echo);let path=(expr+'.length').split('.');while(path.length){container.bind(element,path.join('.'),echo);path.pop();}}});window.ls.container.get('view').add({selector:'data-ls-template',template:false,repeat:false,controller:function(element,view,http,expression,document,container){let template=element.getAttribute('data-ls-template')||'';let type=element.getAttribute('data-type')||'url';let debug=element.getAttribute('data-debug')||false;let paths=[];let check=function(init=false){let source=expression.parse(template);paths=expression.getPaths();element.innerHTML='';if('script'===type){let inlineTemplate=document.getElementById(source);if(inlineTemplate&&inlineTemplate.innerHTML){element.innerHTML=inlineTemplate.innerHTML;element.dispatchEvent(new CustomEvent('template-loaded',{bubbles:true,cancelable:false}));}else{if(debug){console.error('Missing template "'+source+'"');}}
|
||||
element.dispatchEvent(new Event('looped'));};let template=(element.children.length===1)?element.children[0]:window.document.createElement('li');echo();container.bind(element,expr+'.length',echo);let path=(expr+'.length').split('.');while(path.length){container.bind(element,path.join('.'),echo);path.pop();}}});window.ls.container.get('view').add({selector:'data-ls-template',template:false,controller:function(element,view,http,expression,document,container){let template=element.getAttribute('data-ls-template')||'';let type=element.getAttribute('data-type')||'url';let debug=element.getAttribute('data-debug')||false;let paths=[];let check=function(init=false){let source=expression.parse(template);paths=expression.getPaths();element.innerHTML='';if('script'===type){let inlineTemplate=document.getElementById(source);if(inlineTemplate&&inlineTemplate.innerHTML){element.innerHTML=inlineTemplate.innerHTML;element.dispatchEvent(new CustomEvent('template-loaded',{bubbles:true,cancelable:false}));}
|
||||
else{if(debug){console.error('Missing template "'+source+'"');}}
|
||||
if(!init){view.render(element);}
|
||||
return;}
|
||||
http.get(source).then(function(element){return function(data){element.innerHTML=data;view.render(element);element.dispatchEvent(new CustomEvent('template-loaded',{bubbles:true,cancelable:false}));}}(element),function(){throw new Error('Failed loading template');});};check(true);for(let i=0;i<paths.length;i++){let path=paths[i].split('.');while(path.length){container.bind(element,path.join('.'),check);path.pop();}}}});window.ls.error=function(){return function(error){window.console.error(error);if(window.location.pathname!=='/console'){window.location='/console';}};};window.addEventListener("error",function(event){console.error("ERROR-EVENT:",event.error.message,event.error.stack);});document.addEventListener("account.deleteSession",function(){window.location="/auth/signin";});document.addEventListener("account.create",function(){let container=window.ls.container;let form=container.get('serviceForm');let sdk=container.get('console');let promise=sdk.account.createSession(form.email,form.password);container.set("serviceForm",{},true,true);promise.then(function(){window.location='/console';},function(error){window.location='/auth/signup?failure=1';});});(function(window){"use strict";window.ls.container.set('alerts',function(window){return{list:[],ids:0,counter:0,max:5,add:function(message,time){var scope=this;message.id=scope.ids++;message.remove=function(){scope.remove(message.id);};scope.counter++;scope.list.unshift(message);if(scope.counter>scope.max){scope.list.pop();scope.counter--;}
|
||||
|
|
4
public/dist/scripts/app-dep.js
vendored
4
public/dist/scripts/app-dep.js
vendored
|
@ -205,7 +205,9 @@ return http.post(path,{'content-type':'multipart/form-data',},payload);},getTag:
|
|||
if(tagId===undefined){throw new Error('Missing required parameter: "tagId"');}
|
||||
let path='/functions/{functionId}/tags/{tagId}'.replace(new RegExp('{functionId}','g'),functionId).replace(new RegExp('{tagId}','g'),tagId);let payload={};return http.get(path,{'content-type':'application/json',},payload);},deleteTag:function(functionId,tagId){if(functionId===undefined){throw new Error('Missing required parameter: "functionId"');}
|
||||
if(tagId===undefined){throw new Error('Missing required parameter: "tagId"');}
|
||||
let path='/functions/{functionId}/tags/{tagId}'.replace(new RegExp('{functionId}','g'),functionId).replace(new RegExp('{tagId}','g'),tagId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);}};let health={get:function(){let path='/health';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getAntiVirus:function(){let path='/health/anti-virus';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCache:function(){let path='/health/cache';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getDB:function(){let path='/health/db';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueCertificates:function(){let path='/health/queue/certificates';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueFunctions:function(){let path='/health/queue/functions';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueLogs:function(){let path='/health/queue/logs';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueTasks:function(){let path='/health/queue/tasks';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueUsage:function(){let path='/health/queue/usage';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueWebhooks:function(){let path='/health/queue/webhooks';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getStorageLocal:function(){let path='/health/storage/local';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getTime:function(){let path='/health/time';let payload={};return http.get(path,{'content-type':'application/json',},payload);}};let locale={get:function(){let path='/locale';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getContinents:function(){let path='/locale/continents';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountries:function(){let path='/locale/countries';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountriesEU:function(){let path='/locale/countries/eu';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountriesPhones:function(){let path='/locale/countries/phones';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCurrencies:function(){let path='/locale/currencies';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getLanguages:function(){let path='/locale/languages';let payload={};return http.get(path,{'content-type':'application/json',},payload);}};let projects={list:function(search='',limit=25,offset=0,orderType='ASC'){let path='/projects';let payload={};if(search){payload['search']=search;}
|
||||
let path='/functions/{functionId}/tags/{tagId}'.replace(new RegExp('{functionId}','g'),functionId).replace(new RegExp('{tagId}','g'),tagId);let payload={};return http.delete(path,{'content-type':'application/json',},payload);},getUsage:function(functionId,range='last30'){if(functionId===undefined){throw new Error('Missing required parameter: "functionId"');}
|
||||
let path='/functions/{functionId}/usage'.replace(new RegExp('{functionId}','g'),functionId);let payload={};if(range){payload['range']=range;}
|
||||
return http.get(path,{'content-type':'application/json',},payload);}};let health={get:function(){let path='/health';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getAntiVirus:function(){let path='/health/anti-virus';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCache:function(){let path='/health/cache';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getDB:function(){let path='/health/db';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueCertificates:function(){let path='/health/queue/certificates';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueFunctions:function(){let path='/health/queue/functions';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueLogs:function(){let path='/health/queue/logs';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueTasks:function(){let path='/health/queue/tasks';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueUsage:function(){let path='/health/queue/usage';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getQueueWebhooks:function(){let path='/health/queue/webhooks';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getStorageLocal:function(){let path='/health/storage/local';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getTime:function(){let path='/health/time';let payload={};return http.get(path,{'content-type':'application/json',},payload);}};let locale={get:function(){let path='/locale';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getContinents:function(){let path='/locale/continents';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountries:function(){let path='/locale/countries';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountriesEU:function(){let path='/locale/countries/eu';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCountriesPhones:function(){let path='/locale/countries/phones';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getCurrencies:function(){let path='/locale/currencies';let payload={};return http.get(path,{'content-type':'application/json',},payload);},getLanguages:function(){let path='/locale/languages';let payload={};return http.get(path,{'content-type':'application/json',},payload);}};let projects={list:function(search='',limit=25,offset=0,orderType='ASC'){let path='/projects';let payload={};if(search){payload['search']=search;}
|
||||
if(limit){payload['limit']=limit;}
|
||||
if(offset){payload['offset']=offset;}
|
||||
if(orderType){payload['orderType']=orderType;}
|
||||
|
|
55
public/dist/scripts/app.js
vendored
55
public/dist/scripts/app.js
vendored
|
@ -8,7 +8,8 @@ if(service.instance){return service.instance;}
|
|||
let instance=(typeof service.object==='function')?this.resolve(service.object):service.object;let skip=false;if(service.watch&&name!=='window'&&name!=='document'&&name!=='element'&&typeof instance==='object'&&instance!==null){let handler={name:service.name,watch:function(){},get:function(target,key){if(key==="__name"){return this.name;}
|
||||
if(key==="__watch"){return this.watch;}
|
||||
if(key==="__proxy"){return true;}
|
||||
if(typeof target[key]==='object'&&target[key]!==null&&!target[key].__proxy){let handler=Object.assign({},this);handler.name=handler.name+'.'+key;return new Proxy(target[key],handler)}else{return target[key];}},set:function(target,key,value,receiver){if(key==="__name"){return this.name=value;}
|
||||
if(typeof target[key]==='object'&&target[key]!==null&&!target[key].__proxy){let handler=Object.assign({},this);handler.name=handler.name+'.'+key;return new Proxy(target[key],handler)}
|
||||
else{return target[key];}},set:function(target,key,value,receiver){if(key==="__name"){return this.name=value;}
|
||||
if(key==="__watch"){return this.watch=value;}
|
||||
target[key]=value;let path=receiver.__name+'.'+key;document.dispatchEvent(new CustomEvent(path+'.changed'));if(skip){return true;}
|
||||
skip=true;container.set('$prop',key,true);container.set('$value',value,true);container.resolve(this.watch);container.set('$key',null,true);container.set('$value',null,true);skip=false;return true;},};instance=new Proxy(instance,handler);}
|
||||
|
@ -25,7 +26,8 @@ object[shift].unshift(value);break;case'splice':if(!Array.isArray(object[shift])
|
|||
object[shift].splice(value,1);break;default:object[shift]=value;}
|
||||
return true;}
|
||||
if(!object){return null;}
|
||||
if(!shift){result=object;}else{return object[shift];}
|
||||
if(!shift){result=object;}
|
||||
else{return object[shift];}
|
||||
return result;};let bind=function(element,path,callback){let event=container.scope(path)+'.changed';let service=event.split('.').slice(0,1).pop();let debug=element.getAttribute('data-debug')||false;listeners[service]=listeners[service]||{};listeners[service][event]=true;let printer=(function(x){return function(){if(!document.body.contains(element)){element=null;document.removeEventListener(event,printer,false);return false;}
|
||||
let oldNamespaces=namespaces;namespaces=x;callback();namespaces=oldNamespaces;}}(Object.assign({},namespaces)));document.addEventListener(event,printer);};let addNamespace=function(key,scope){namespaces[key]=scope;return this;}
|
||||
let removeNamespace=function(key){delete namespaces[key];return this;}
|
||||
|
@ -36,9 +38,10 @@ if(typeof url!=='string'){throw new Error('var url must be of type string');}
|
|||
if(typeof headers!=='object'){throw new Error('var headers must be of type object');}
|
||||
if(typeof url!=='string'){throw new Error('var url must be of type string');}
|
||||
for(i=0;i<globalParams.length;i++){url=addParam(url,globalParams[i].key,globalParams[i].value);}
|
||||
return new Promise(function(resolve,reject){let xmlhttp=new XMLHttpRequest();xmlhttp.open(method,url,true);xmlhttp.setRequestHeader('Ajax','1');for(i=0;i<globalHeaders.length;i++){xmlhttp.setRequestHeader(globalHeaders[i].key,globalHeaders[i].value);}
|
||||
return new Promise(function(resolve,reject){let xmlhttp=new XMLHttpRequest();xmlhttp.open(method,url,true);for(i=0;i<globalHeaders.length;i++){xmlhttp.setRequestHeader(globalHeaders[i].key,globalHeaders[i].value);}
|
||||
for(let key in headers){if(headers.hasOwnProperty(key)){xmlhttp.setRequestHeader(key,headers[key]);}}
|
||||
xmlhttp.onload=function(){if(4===xmlhttp.readyState&&200===xmlhttp.status){resolve(xmlhttp.response);}else{document.dispatchEvent(new CustomEvent('http-'+method.toLowerCase()+'-'+xmlhttp.status));reject(new Error(xmlhttp.statusText));}};if(progress){xmlhttp.addEventListener('progress',progress);xmlhttp.upload.addEventListener('progress',progress,false);}
|
||||
xmlhttp.onload=function(){if(4===xmlhttp.readyState&&200===xmlhttp.status){resolve(xmlhttp.response);}
|
||||
else{document.dispatchEvent(new CustomEvent('http-'+method.toLowerCase()+'-'+xmlhttp.status));reject(new Error(xmlhttp.statusText));}};if(progress){xmlhttp.addEventListener('progress',progress);xmlhttp.upload.addEventListener('progress',progress,false);}
|
||||
xmlhttp.onerror=function(){reject(new Error("Network Error"));};xmlhttp.send(payload);})};return{'get':function(url){return request('GET',url,{},'')},'post':function(url,headers,payload){return request('POST',url,headers,payload)},'put':function(url,headers,payload){return request('PUT',url,headers,payload)},'patch':function(url,headers,payload){return request('PATCH',url,headers,payload)},'delete':function(url){return request('DELETE',url,{},'')},'addGlobalParam':function(key,value){globalParams.push({key:key,value:value});},'addGlobalHeader':function(key,value){globalHeaders.push({key:key,value:value});}}},true,false);window.ls.container.set('cookie',function(document){function get(name){let value="; "+document.cookie,parts=value.split("; "+name+"=");if(parts.length===2){return parts.pop().split(";").shift();}
|
||||
return null;}
|
||||
function set(name,value,days){let date=new Date();date.setTime(date.getTime()+(days*24*60*60*1000));let expires=(0<days)?'expires='+date.toUTCString():'expires=0';document.cookie=name+"="+value+";"+expires+";path=/";return this;}
|
||||
|
@ -61,22 +64,30 @@ object[prop]=defaults[prop];}
|
|||
if(!object.selector){throw new Error('View component is missing a selector attribute');}
|
||||
stock[object.selector]=object;return this;},render:function(element,callback){parse(element,false,callback);element.dispatchEvent(new window.Event('rendered',{bubbles:false}));}}},true,false);window.ls.container.set('router',function(window){let getJsonFromUrl=function(URL){let query;if(URL){let pos=location.search.indexOf('?');if(pos===-1)return[];query=location.search.substr(pos+1);}else{query=location.search.substr(1);}
|
||||
let result={};query.split('&').forEach(function(part){if(!part){return;}
|
||||
part=part.split('+').join(' ');let eq=part.indexOf('=');let key=eq>-1?part.substr(0,eq):part;let val=eq>-1?decodeURIComponent(part.substr(eq+1)):'';let from=key.indexOf('[');if(from===-1){result[decodeURIComponent(key)]=val;}else{let to=key.indexOf(']');let index=decodeURIComponent(key.substring(from+1,to));key=decodeURIComponent(key.substring(0,from));if(!result[key]){result[key]=[];}
|
||||
if(!index){result[key].push(val);}else{result[key][index]=val;}}});return result;};let states=[];let params=getJsonFromUrl(window.location.search);let hash=window.location.hash;let current=null;let previous=null;let getPrevious=()=>previous;let getCurrent=()=>current;let setPrevious=(value)=>{previous=value;return this;};let setCurrent=(value)=>{current=value;return this;};let setParam=function(key,value){params[key]=value;return this;};let getParam=function(key,def){if(key in params){return params[key];}
|
||||
part=part.split('+').join(' ');let eq=part.indexOf('=');let key=eq>-1?part.substr(0,eq):part;let val=eq>-1?decodeURIComponent(part.substr(eq+1)):'';let from=key.indexOf('[');if(from===-1){result[decodeURIComponent(key)]=val;}
|
||||
else{let to=key.indexOf(']');let index=decodeURIComponent(key.substring(from+1,to));key=decodeURIComponent(key.substring(0,from));if(!result[key]){result[key]=[];}
|
||||
if(!index){result[key].push(val);}
|
||||
else{result[key][index]=val;}}});return result;};let states=[];let params=getJsonFromUrl(window.location.search);let hash=window.location.hash;let current=null;let previous=null;let getPrevious=()=>previous;let getCurrent=()=>current;let setPrevious=(value)=>{previous=value;return this;};let setCurrent=(value)=>{current=value;return this;};let setParam=function(key,value){params[key]=value;return this;};let getParam=function(key,def){if(key in params){return params[key];}
|
||||
return def;};let getParams=function(){return params;};let getURL=function(){return window.location.href;};let add=function(path,view){if(typeof path!=='string'){throw new Error('path must be of type string');}
|
||||
if(typeof view!=='object'){throw new Error('view must be of type object');}
|
||||
states[states.length++]={path:path,view:view};return this;};let match=function(location){let url=location.pathname;states.sort(function(a,b){return b.path.length-a.path.length;});states.sort(function(a,b){let n=b.path.split('/').length-a.path.split('/').length;if(n!==0){return n;}
|
||||
return b.path.length-a.path.length;});for(let i=0;i<states.length;i++){let value=states[i];value.path=(value.path.substring(0,1)!=='/')?location.pathname+value.path:value.path;let match=new RegExp("^"+value.path.replace(/:[^\s/]+/g,'([\\w-]+)')+"$");let found=url.match(match);if(found){previous=current;current=value;return value;}}
|
||||
return null};let change=function(URL,replace){if(!replace){window.history.pushState({},'',URL);}else{window.history.replaceState({},'',URL);}
|
||||
return null};let change=function(URL,replace){if(!replace){window.history.pushState({},'',URL);}
|
||||
else{window.history.replaceState({},'',URL);}
|
||||
window.dispatchEvent(new PopStateEvent('popstate',{}));return this;};let reload=function(){return change(window.location.href);};return{setParam:setParam,getParam:getParam,getParams:getParams,getURL:getURL,add:add,change:change,reload:reload,match:match,getCurrent:getCurrent,setCurrent:setCurrent,getPrevious:getPrevious,setPrevious:setPrevious,params:params,hash:hash,reset:function(){this.params=getJsonFromUrl(window.location.search);this.hash=window.location.hash;}};},true,true);window.ls.container.set('expression',function(container,filter){let paths=[];return{regex:/(\{{.*?\}})/gi,parse:function(string,def,cast=false){def=def||'';paths=[];return string.replace(this.regex,match=>{let reference=match.substring(2,match.length-2).replace('[\'','.').replace('\']','').trim();reference=reference.split('|');let path=container.scope((reference[0]||''));let result=container.path(path);path=container.scope(path);if(!paths.includes(path)){paths.push(path);}
|
||||
if(reference.length>=2){for(let i=1;i<reference.length;i++){result=filter.apply(reference[i],result);}}
|
||||
if(null===result||undefined===result){result=def;}else if(typeof result==='object'){result=JSON.stringify(result,null,4);}else if(((typeof result==='object')||(typeof result==='string'))&&cast){result='\''+result+'\'';}
|
||||
if(null===result||undefined===result){result=def;}
|
||||
else if(typeof result==='object'){result=JSON.stringify(result,null,4);}
|
||||
else if(((typeof result==='object')||(typeof result==='string'))&&cast){result='\''+result+'\'';}
|
||||
return result;}).replace(/\\{/g,"{").replace(/\\}/g,"}");},getPaths:()=>paths,}},true,false);window.ls.container.set('filter',function(container){let filters={};let add=function(name,callback){filters[name]=callback;return this;};let apply=function(name,value){container.set('$value',value,true,false);return container.resolve(filters[name]);};add('uppercase',($value)=>{if(typeof $value!=='string'){return $value;}
|
||||
return $value.toUpperCase();});add('lowercase',($value)=>{if(typeof $value!=='string'){return $value;}
|
||||
return $value.toLowerCase();});return{add:add,apply:apply}},true,false);window.ls.container.get('filter').add('escape',value=>{if(typeof value!=='string'){return value;}
|
||||
return value.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/\"/g,'"').replace(/\'/g,''').replace(/\//g,'/');});window.ls=window.ls||{};window.ls.container.set('window',window,true,false).set('document',window.document,true,false).set('element',window.document,true,false);window.ls.run=function(window){try{this.view.render(window.document);}catch(error){let handler=window.ls.container.resolve(this.error);handler(error);}};window.ls.error=()=>{return error=>{console.error('ls-error',error.message,error.stack,error.toString());}};window.ls.router=window.ls.container.get('router');window.ls.view=window.ls.container.get('view');window.ls.filter=window.ls.container.get('filter');window.ls.container.get('view').add({selector:'data-ls-router',repeat:false,controller:function(element,window,document,view,router){let firstFromServer=(element.getAttribute('data-first-from-server')==='true');let scope={selector:'data-ls-scope',template:false,repeat:true,controller:function(){},};let init=function(route){let count=parseInt(element.getAttribute('data-ls-scope-count')||0);element.setAttribute('data-ls-scope-count',count+1);window.scrollTo(0,0);if(window.document.body.scrollTo){window.document.body.scrollTo(0,0);}
|
||||
return value.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/\"/g,'"').replace(/\'/g,''').replace(/\//g,'/');});window.ls=window.ls||{};window.ls.container.set('window',window,true,false).set('document',window.document,true,false).set('element',window.document,true,false);window.ls.run=function(window){try{this.view.render(window.document);}
|
||||
catch(error){let handler=window.ls.container.resolve(this.error);handler(error);}};window.ls.error=()=>{return error=>{console.error('ls-error',error.message,error.stack,error.toString());}};window.ls.router=window.ls.container.get('router');window.ls.view=window.ls.container.get('view');window.ls.filter=window.ls.container.get('filter');window.ls.container.get('view').add({selector:'data-ls-router',controller:function(element,window,document,view,router){let firstFromServer=(element.getAttribute('data-first-from-server')==='true');let scope={selector:'data-ls-scope',template:false,repeat:true,controller:function(){},};let init=function(route){let count=parseInt(element.getAttribute('data-ls-scope-count')||0);element.setAttribute('data-ls-scope-count',count+1);window.scrollTo(0,0);if(window.document.body.scrollTo){window.document.body.scrollTo(0,0);}
|
||||
router.reset();if(null===route){return;}
|
||||
scope.template=(undefined!==route.view.template)?route.view.template:null;scope.controller=(undefined!==route.view.controller)?route.view.controller:function(){};document.dispatchEvent(new CustomEvent('state-change'));if(firstFromServer&&null===router.getPrevious()){scope.template='';document.dispatchEvent(new CustomEvent('state-changed'));}else if(count===1){view.render(element,function(){document.dispatchEvent(new CustomEvent('state-changed'));});}else if(null!==router.getPrevious()){view.render(element,function(){document.dispatchEvent(new CustomEvent('state-changed'));});}};let findParent=function(tagName,el){if((el.nodeName||el.tagName).toLowerCase()===tagName.toLowerCase()){return el;}
|
||||
scope.template=(undefined!==route.view.template)?route.view.template:null;scope.controller=(undefined!==route.view.controller)?route.view.controller:function(){};document.dispatchEvent(new CustomEvent('state-change'));if(firstFromServer&&null===router.getPrevious()){scope.template='';document.dispatchEvent(new CustomEvent('state-changed'));}
|
||||
else if(count===1){view.render(element,function(){document.dispatchEvent(new CustomEvent('state-changed'));});}
|
||||
else if(null!==router.getPrevious()){view.render(element,function(){document.dispatchEvent(new CustomEvent('state-changed'));});}};let findParent=function(tagName,el){if((el.nodeName||el.tagName).toLowerCase()===tagName.toLowerCase()){return el;}
|
||||
while(el=el.parentNode){if((el.nodeName||el.tagName).toLowerCase()===tagName.toLowerCase()){return el;}}
|
||||
return null;};element.removeAttribute('data-ls-router');element.setAttribute('data-ls-scope','');element.setAttribute('data-ls-scope-count',1);view.add(scope);document.addEventListener('click',function(event){let target=findParent('a',event.target);if(!target){return false;}
|
||||
if(!target.href){return false;}
|
||||
|
@ -90,32 +101,40 @@ window.history.pushState({},'Unknown',target.href);}
|
|||
init(route);return true;});window.addEventListener('popstate',function(){init(router.match(window.location));});window.addEventListener('hashchange',function(){init(router.match(window.location));});init(router.match(window.location));}});window.ls.container.get('view').add({selector:'data-ls-attrs',controller:function(element,expression,container){let attrs=element.getAttribute('data-ls-attrs').trim().split(',');let paths=[];let debug=element.getAttribute('data-debug')||false;let check=()=>{container.set('element',element,true,false);if(debug){console.info('debug-ls-attrs attributes:',attrs);}
|
||||
for(let i=0;i<attrs.length;i++){let attr=attrs[i];let key=expression.parse((attr.substring(0,attr.indexOf('='))||attr));paths=paths.concat(expression.getPaths());let value='';if(attr.indexOf('=')>-1){value=expression.parse(attr.substring(attr.indexOf('=')+1))||'';paths=paths.concat(expression.getPaths());}
|
||||
if(!key){return null;}
|
||||
element.setAttribute(key,value);}};check();for(let i=0;i<paths.length;i++){let path=paths[i].split('.');while(path.length){container.bind(element,path.join('.'),check);path.pop();}}}});window.ls.container.get('view').add({selector:'data-ls-bind',controller:function(element,expression,container){let debug=element.getAttribute('data-debug')||false;let echo=function(value,bind=true){if(element.tagName==='INPUT'||element.tagName==='SELECT'||element.tagName==='BUTTON'||element.tagName==='TEXTAREA'){let type=element.getAttribute('type');if('radio'===type){if(value.toString()===element.value){element.setAttribute('checked','checked');}else{element.removeAttribute('checked');}
|
||||
element.setAttribute(key,value);}};check();for(let i=0;i<paths.length;i++){let path=paths[i].split('.');while(path.length){container.bind(element,path.join('.'),check);path.pop();}}}});window.ls.container.get('view').add({selector:'data-ls-bind',controller:function(element,expression,container){let debug=element.getAttribute('data-debug')||false;let echo=function(value,bind=true){if(element.tagName==='INPUT'||element.tagName==='SELECT'||element.tagName==='BUTTON'||element.tagName==='TEXTAREA'){let type=element.getAttribute('type');if('radio'===type){if(value.toString()===element.value){element.setAttribute('checked','checked');}
|
||||
else{element.removeAttribute('checked');}
|
||||
if(bind){element.addEventListener('change',()=>{for(let i=0;i<paths.length;i++){if(element.checked){value=element.value;}
|
||||
container.path(paths[i],value);}});}
|
||||
return;}
|
||||
if('checkbox'===type){if(typeof value==='boolean'||value==='true'||value==='false'){if(value===true||value==='true'){element.setAttribute('checked','checked');element.checked=true;}else{element.removeAttribute('checked');element.checked=false;}}else{try{value=JSON.parse(value);element.checked=(Array.isArray(value)&&(value.indexOf(element.value)>-1));value=element.value;}catch{return null;}}
|
||||
if('checkbox'===type){if(typeof value==='boolean'||value==='true'||value==='false'){if(value===true||value==='true'){element.setAttribute('checked','checked');element.checked=true;}
|
||||
else{element.removeAttribute('checked');element.checked=false;}}
|
||||
else{try{value=JSON.parse(value);element.checked=(Array.isArray(value)&&(value.indexOf(element.value)>-1));value=element.value;}
|
||||
catch{return null;}}
|
||||
if(bind){element.addEventListener('change',()=>{for(let i=0;i<paths.length;i++){let value=container.path(paths[i]);let index=value.indexOf(element.value);if(element.checked&&index<0){value.push(element.value);}
|
||||
if(!element.checked&&index>-1){value.splice(index,1);}
|
||||
container.path(paths[i],value);}});}
|
||||
return;}
|
||||
if(element.value!==value){element.value=value;element.dispatchEvent(new Event('change'));}
|
||||
if(bind){element.addEventListener('input',sync);element.addEventListener('change',sync);}}else{if(element.textContent!=value){element.innerHTML=value;}}};let sync=(()=>{return()=>{if(debug){console.info('debug-ls-bind','sync-path',paths);console.info('debug-ls-bind','sync-syntax',syntax);console.info('debug-ls-bind','sync-syntax-parsed',parsedSyntax);console.info('debug-ls-bind','sync-value',element.value);}
|
||||
if(bind){element.addEventListener('input',sync);element.addEventListener('change',sync);}}
|
||||
else{if(element.innerHTML!=value){element.innerHTML=value;}}};let sync=(()=>{return()=>{if(debug){console.info('debug-ls-bind','sync-path',paths);console.info('debug-ls-bind','sync-syntax',syntax);console.info('debug-ls-bind','sync-syntax-parsed',parsedSyntax);console.info('debug-ls-bind','sync-value',element.value);}
|
||||
for(let i=0;i<paths.length;i++){if('{{'+paths[i]+'}}'!==parsedSyntax){if(debug){console.info('debug-ls-bind','sync-skipped-path',paths[i]);console.info('debug-ls-bind','sync-skipped-syntax',syntax);console.info('debug-ls-bind','sync-skipped-syntax-parsed',parsedSyntax);}
|
||||
continue;}
|
||||
if(debug){console.info('debug-ls-bind','sync-loop-path',paths[i]);console.info('debug-ls-bind','sync-loop-syntax',parsedSyntax);}
|
||||
container.path(paths[i],element.value);}}})();let syntax=element.getAttribute('data-ls-bind');let parsedSyntax=container.scope(syntax);let unsync=(!!element.getAttribute('data-unsync'))||false;let result=expression.parse(syntax);let paths=expression.getPaths();echo(result,!unsync);element.addEventListener('looped',function(){echo(expression.parse(parsedSyntax),false);});for(let i=0;i<paths.length;i++){let path=paths[i].split('.');if(debug){console.info('debug-ls-bind','bind-path',path);console.info('debug-ls-bind','bind-syntax',syntax);}
|
||||
while(path.length){container.bind(element,path.join('.'),()=>{echo(expression.parse(parsedSyntax),false);});path.pop();}}}});window.ls.container.get('view').add({selector:'data-ls-if',controller:function(element,expression,container,view){let result='';let syntax=element.getAttribute('data-ls-if')||'';let debug=element.getAttribute('data-debug')||false;let paths=[];let check=()=>{if(debug){console.info('debug-ls-if',expression.parse(syntax.replace(/(\r\n|\n|\r)/gm,' '),'undefined',true));}
|
||||
try{result=(eval(expression.parse(syntax.replace(/(\r\n|\n|\r)/gm,' '),'undefined',true)));}catch(error){throw new Error('Failed to evaluate expression "'+syntax+' (resulted with: "'+result+'")": '+error);}
|
||||
try{result=(eval(expression.parse(syntax.replace(/(\r\n|\n|\r)/gm,' '),'undefined',true)));}
|
||||
catch(error){throw new Error('Failed to evaluate expression "'+syntax+' (resulted with: "'+result+'")": '+error);}
|
||||
if(debug){console.info('debug-ls-if result:',result);}
|
||||
paths=expression.getPaths();let prv=element.$lsSkip;element.$lsSkip=!result;if(!result){element.style.visibility='hidden';element.style.display='none';}else{element.style.removeProperty('display');element.style.removeProperty('visibility');}
|
||||
if(prv===true&&element.$lsSkip===false){view.render(element)}};check();for(let i=0;i<paths.length;i++){let path=paths[i].split('.');while(path.length){container.bind(element,path.join('.'),check);path.pop();}}}});window.ls.container.get('view').add({selector:'data-ls-loop',template:false,repeat:false,nested:false,controller:function(element,view,container,window,expression){let expr=expression.parse(element.getAttribute('data-ls-loop'));let as=element.getAttribute('data-ls-as');let key=element.getAttribute('data-ls-key')||'$index';let limit=parseInt(expression.parse(element.getAttribute('data-limit')||'')||-1);let debug=element.getAttribute('data-debug')||false;let echo=function(){let array=container.path(expr);let counter=0;array=(!array)?[]:array;let watch=!!(array&&array.__proxy);while(element.hasChildNodes()){element.removeChild(element.lastChild);element.lastChild=null;}
|
||||
paths=expression.getPaths();let prv=element.$lsSkip;element.$lsSkip=!result;if(!result){element.style.visibility='hidden';element.style.display='none';}
|
||||
else{element.style.removeProperty('display');element.style.removeProperty('visibility');}
|
||||
if(prv===true&&element.$lsSkip===false){view.render(element)}};check();for(let i=0;i<paths.length;i++){let path=paths[i].split('.');while(path.length){container.bind(element,path.join('.'),check);path.pop();}}}});window.ls.container.get('view').add({selector:'data-ls-loop',template:false,nested:false,controller:function(element,view,container,window,expression){let expr=expression.parse(element.getAttribute('data-ls-loop'));let as=element.getAttribute('data-ls-as');let key=element.getAttribute('data-ls-key')||'$index';let limit=parseInt(expression.parse(element.getAttribute('data-limit')||'')||-1);let debug=element.getAttribute('data-debug')||false;let echo=function(){let array=container.path(expr);let counter=0;array=(!array)?[]:array;let watch=!!(array&&array.__proxy);while(element.hasChildNodes()){element.removeChild(element.lastChild);element.lastChild=null;}
|
||||
if(array instanceof Array&&typeof array!=='object'){throw new Error('Reference value must be array or object. '+(typeof array)+' given');}
|
||||
let children=[];element.$lsSkip=true;element.style.visibility=(0===array.length)?'hidden':'visible';for(let prop in array){if(counter==limit){break;}
|
||||
let children=[];element.$lsSkip=true;for(let prop in array){if(counter==limit){break;}
|
||||
counter++;if(!array.hasOwnProperty(prop)){continue;}
|
||||
children[prop]=template.cloneNode(true);element.appendChild(children[prop]);(index=>{let context=expr+'.'+index;container.addNamespace(as,context);if(debug){console.info('debug-ls-loop','index',index);console.info('debug-ls-loop','context',context);console.info('debug-ls-loop','context-path',container.path(context).name);console.info('debug-ls-loop','namespaces',container.namespaces);}
|
||||
container.set(as,container.path(context),true,watch);container.set(key,index,true,false);view.render(children[prop]);container.removeNamespace(as);})(prop);}
|
||||
element.dispatchEvent(new Event('looped'));};let template=(element.children.length===1)?element.children[0]:window.document.createElement('li');echo();container.bind(element,expr+'.length',echo);let path=(expr+'.length').split('.');while(path.length){container.bind(element,path.join('.'),echo);path.pop();}}});window.ls.container.get('view').add({selector:'data-ls-template',template:false,repeat:false,controller:function(element,view,http,expression,document,container){let template=element.getAttribute('data-ls-template')||'';let type=element.getAttribute('data-type')||'url';let debug=element.getAttribute('data-debug')||false;let paths=[];let check=function(init=false){let source=expression.parse(template);paths=expression.getPaths();element.innerHTML='';if('script'===type){let inlineTemplate=document.getElementById(source);if(inlineTemplate&&inlineTemplate.innerHTML){element.innerHTML=inlineTemplate.innerHTML;element.dispatchEvent(new CustomEvent('template-loaded',{bubbles:true,cancelable:false}));}else{if(debug){console.error('Missing template "'+source+'"');}}
|
||||
element.dispatchEvent(new Event('looped'));};let template=(element.children.length===1)?element.children[0]:window.document.createElement('li');echo();container.bind(element,expr+'.length',echo);let path=(expr+'.length').split('.');while(path.length){container.bind(element,path.join('.'),echo);path.pop();}}});window.ls.container.get('view').add({selector:'data-ls-template',template:false,controller:function(element,view,http,expression,document,container){let template=element.getAttribute('data-ls-template')||'';let type=element.getAttribute('data-type')||'url';let debug=element.getAttribute('data-debug')||false;let paths=[];let check=function(init=false){let source=expression.parse(template);paths=expression.getPaths();element.innerHTML='';if('script'===type){let inlineTemplate=document.getElementById(source);if(inlineTemplate&&inlineTemplate.innerHTML){element.innerHTML=inlineTemplate.innerHTML;element.dispatchEvent(new CustomEvent('template-loaded',{bubbles:true,cancelable:false}));}
|
||||
else{if(debug){console.error('Missing template "'+source+'"');}}
|
||||
if(!init){view.render(element);}
|
||||
return;}
|
||||
http.get(source).then(function(element){return function(data){element.innerHTML=data;view.render(element);element.dispatchEvent(new CustomEvent('template-loaded',{bubbles:true,cancelable:false}));}}(element),function(){throw new Error('Failed loading template');});};check(true);for(let i=0;i<paths.length;i++){let path=paths[i].split('.');while(path.length){container.bind(element,path.join('.'),check);path.pop();}}}});window.ls.error=function(){return function(error){window.console.error(error);if(window.location.pathname!=='/console'){window.location='/console';}};};window.addEventListener("error",function(event){console.error("ERROR-EVENT:",event.error.message,event.error.stack);});document.addEventListener("account.deleteSession",function(){window.location="/auth/signin";});document.addEventListener("account.create",function(){let container=window.ls.container;let form=container.get('serviceForm');let sdk=container.get('console');let promise=sdk.account.createSession(form.email,form.password);container.set("serviceForm",{},true,true);promise.then(function(){window.location='/console';},function(error){window.location='/auth/signup?failure=1';});});(function(window){"use strict";window.ls.container.set('alerts',function(window){return{list:[],ids:0,counter:0,max:5,add:function(message,time){var scope=this;message.id=scope.ids++;message.remove=function(){scope.remove(message.id);};scope.counter++;scope.list.unshift(message);if(scope.counter>scope.max){scope.list.pop();scope.counter--;}
|
||||
|
|
|
@ -2238,6 +2238,34 @@
|
|||
.delete(path, {
|
||||
'content-type': 'application/json',
|
||||
}, payload);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get Function Usage
|
||||
*
|
||||
*
|
||||
* @param {string} functionId
|
||||
* @param {string} range
|
||||
* @throws {Error}
|
||||
* @return {Promise}
|
||||
*/
|
||||
getUsage: function(functionId, range = 'last30') {
|
||||
if(functionId === undefined) {
|
||||
throw new Error('Missing required parameter: "functionId"');
|
||||
}
|
||||
|
||||
let path = '/functions/{functionId}/usage'.replace(new RegExp('{functionId}', 'g'), functionId);
|
||||
|
||||
let payload = {};
|
||||
|
||||
if(range) {
|
||||
payload['range'] = range;
|
||||
}
|
||||
|
||||
return http
|
||||
.get(path, {
|
||||
'content-type': 'application/json',
|
||||
}, payload);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -48,4 +48,4 @@
|
|||
|
||||
}
|
||||
});
|
||||
})(window);
|
||||
})(window);
|
||||
|
|
|
@ -7,6 +7,7 @@ use Tests\E2E\Client;
|
|||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\SideServer;
|
||||
use Utopia\CLI\Console;
|
||||
|
||||
class FunctionsCustomServerTest extends Scope
|
||||
{
|
||||
|
@ -183,7 +184,7 @@ class FunctionsCustomServerTest extends Scope
|
|||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'command' => 'php function.php',
|
||||
'code' => new CURLFile(realpath(__DIR__ . '/../../../resources/functions/php-fx.tar.gz'), 'application/x-gzip', 'php-fx.tar.gz'),
|
||||
'code' => new CURLFile(realpath(__DIR__ . '/../../../resources/functions/php.tar.gz'), 'application/x-gzip', 'php-fx.tar.gz'),
|
||||
]);
|
||||
|
||||
$tagId = $tag['body']['$id'] ?? '';
|
||||
|
@ -192,7 +193,7 @@ class FunctionsCustomServerTest extends Scope
|
|||
$this->assertNotEmpty($tag['body']['$id']);
|
||||
$this->assertIsInt($tag['body']['dateCreated']);
|
||||
$this->assertEquals('php function.php', $tag['body']['command']);
|
||||
$this->assertEquals(751, $tag['body']['size']);
|
||||
$this->assertGreaterThan(10000, $tag['body']['size']);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
|
@ -264,7 +265,7 @@ class FunctionsCustomServerTest extends Scope
|
|||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $function['headers']['status-code']);
|
||||
$this->assertEquals(751, $function['body']['size']);
|
||||
$this->assertGreaterThan(10000, $function['body']['size']);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
|
@ -279,7 +280,6 @@ class FunctionsCustomServerTest extends Scope
|
|||
return $data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @depends testUpdateTag
|
||||
*/
|
||||
|
@ -337,10 +337,11 @@ class FunctionsCustomServerTest extends Scope
|
|||
* Test for FAILURE
|
||||
*/
|
||||
|
||||
sleep(10);
|
||||
|
||||
return array_merge($data, ['executionId' => $executionId]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @depends testCreateExecution
|
||||
*/
|
||||
|
@ -451,4 +452,254 @@ class FunctionsCustomServerTest extends Scope
|
|||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function testENVS():array
|
||||
{
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$file = $this->client->call(Client::METHOD_POST, '/storage/files', array_merge([
|
||||
'content-type' => 'multipart/form-data',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'),
|
||||
'read' => ['*'],
|
||||
'write' => ['*'],
|
||||
'folderId' => 'xyz',
|
||||
]);
|
||||
|
||||
$this->assertEquals($file['headers']['status-code'], 201);
|
||||
$this->assertNotEmpty($file['body']['$id']);
|
||||
|
||||
$fileId = $file['body']['$id'] ?? '';
|
||||
|
||||
$functions = realpath(__DIR__ . '/../../../resources/functions');
|
||||
|
||||
/**
|
||||
* Command for rebuilding code packages:
|
||||
* bash tests/resources/functions/package-*.sh
|
||||
*/
|
||||
$envs = [
|
||||
[
|
||||
'language' => 'PHP',
|
||||
'version' => '7.4',
|
||||
'name' => 'php-7.4',
|
||||
'code' => $functions.'/php.tar.gz',
|
||||
'command' => 'php index.php',
|
||||
'timeout' => 15,
|
||||
],
|
||||
[
|
||||
'language' => 'PHP',
|
||||
'version' => '8.0',
|
||||
'name' => 'php-8.0',
|
||||
'code' => $functions.'/php.tar.gz',
|
||||
'command' => 'php index.php',
|
||||
'timeout' => 15,
|
||||
],
|
||||
[
|
||||
'language' => 'Python',
|
||||
'version' => '3.8',
|
||||
'name' => 'python-3.8',
|
||||
'code' => $functions.'/python.tar.gz',
|
||||
'command' => 'python main.py',
|
||||
'timeout' => 15,
|
||||
],
|
||||
[
|
||||
'language' => 'Node.js',
|
||||
'version' => '14.5',
|
||||
'name' => 'node-14',
|
||||
'code' => $functions.'/node.tar.gz',
|
||||
'command' => 'node index.js',
|
||||
'timeout' => 15,
|
||||
],
|
||||
[
|
||||
'language' => 'Ruby',
|
||||
'version' => '2.7',
|
||||
'name' => 'ruby-2.7',
|
||||
'code' => $functions.'/ruby.tar.gz',
|
||||
'command' => 'ruby app.rb',
|
||||
'timeout' => 15,
|
||||
],
|
||||
[
|
||||
'language' => 'Deno',
|
||||
'version' => '1.5',
|
||||
'name' => 'deno-1.5',
|
||||
'code' => $functions.'/deno.tar.gz',
|
||||
'command' => 'deno run --allow-env index.ts',
|
||||
'timeout' => 15,
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($envs as $key => $env) {
|
||||
$language = $env['language'] ?? '';
|
||||
$version = $env['version'] ?? '';
|
||||
$name = $env['name'] ?? '';
|
||||
$code = $env['code'] ?? '';
|
||||
$command = $env['command'] ?? '';
|
||||
$timeout = $env['timeout'] ?? 15;
|
||||
|
||||
$function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'name' => 'Test '.$name,
|
||||
'env' => $name,
|
||||
'vars' => [
|
||||
'APPWRITE_ENDPOINT' => 'http://appwrite.test/v1',
|
||||
'APPWRITE_PROJECT' => $this->getProject()['$id'],
|
||||
'APPWRITE_SECRET' => $this->getProject()['apiKey'],
|
||||
'APPWRITE_FILEID' => $fileId,
|
||||
],
|
||||
'events' => [],
|
||||
'schedule' => '',
|
||||
'timeout' => $timeout,
|
||||
]);
|
||||
|
||||
// var_dump('http://'.gethostbyname(trim(`hostname`)).'/v1');
|
||||
|
||||
$functionId = $function['body']['$id'] ?? '';
|
||||
|
||||
$this->assertEquals(201, $function['headers']['status-code']);
|
||||
|
||||
$tag = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/tags', array_merge([
|
||||
'content-type' => 'multipart/form-data',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'command' => $command,
|
||||
'code' => new CURLFile($code, 'application/x-gzip', basename($code)),
|
||||
]);
|
||||
|
||||
$tagId = $tag['body']['$id'] ?? '';
|
||||
$this->assertEquals(201, $tag['headers']['status-code']);
|
||||
|
||||
$tag = $this->client->call(Client::METHOD_PATCH, '/functions/'.$functionId.'/tag', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'tag' => $tagId,
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $tag['headers']['status-code']);
|
||||
|
||||
$execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'async' => 1,
|
||||
]);
|
||||
|
||||
$executionId = $execution['body']['$id'] ?? '';
|
||||
$this->assertEquals(201, $execution['headers']['status-code']);
|
||||
|
||||
sleep(15);
|
||||
|
||||
$executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
if($executions['body']['executions'][0]['status'] === 'failed') {
|
||||
var_dump($executions['body']['executions'][0]);
|
||||
}
|
||||
|
||||
$this->assertEquals($executions['headers']['status-code'], 200);
|
||||
$this->assertEquals($executions['body']['sum'], 1);
|
||||
$this->assertIsArray($executions['body']['executions']);
|
||||
$this->assertCount(1, $executions['body']['executions']);
|
||||
$this->assertEquals($executions['body']['executions'][0]['$id'], $executionId);
|
||||
$this->assertEquals($executions['body']['executions'][0]['trigger'], 'http');
|
||||
$this->assertEquals($executions['body']['executions'][0]['status'], 'completed');
|
||||
$this->assertEquals($executions['body']['executions'][0]['exitCode'], 0);
|
||||
|
||||
$stdout = explode("\n", $executions['body']['executions'][0]['stdout']);
|
||||
|
||||
$this->assertEquals($stdout[0], $functionId);
|
||||
$this->assertEquals($stdout[1], 'Test '.$name);
|
||||
$this->assertEquals($stdout[2], $tagId);
|
||||
$this->assertEquals($stdout[3], 'http');
|
||||
$this->assertEquals($stdout[4], $language);
|
||||
$this->assertEquals($stdout[5], $version);
|
||||
// $this->assertEquals($stdout[6], $fileId);
|
||||
}
|
||||
|
||||
return [
|
||||
'functionId' => $functionId,
|
||||
];
|
||||
}
|
||||
/**
|
||||
* @depends testENVS
|
||||
*/
|
||||
public function testTimeout()
|
||||
{
|
||||
$name = 'php-8.0';
|
||||
$code = realpath(__DIR__ . '/../../../resources/functions').'/timeout.tar.gz';
|
||||
$command = 'php index.php';
|
||||
$timeout = 2;
|
||||
|
||||
$function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'name' => 'Test '.$name,
|
||||
'env' => $name,
|
||||
'vars' => [],
|
||||
'events' => [],
|
||||
'schedule' => '',
|
||||
'timeout' => $timeout,
|
||||
]);
|
||||
|
||||
$functionId = $function['body']['$id'] ?? '';
|
||||
|
||||
$this->assertEquals(201, $function['headers']['status-code']);
|
||||
|
||||
$tag = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/tags', array_merge([
|
||||
'content-type' => 'multipart/form-data',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'command' => $command,
|
||||
'code' => new CURLFile($code, 'application/x-gzip', basename($code)),
|
||||
]);
|
||||
|
||||
$tagId = $tag['body']['$id'] ?? '';
|
||||
$this->assertEquals(201, $tag['headers']['status-code']);
|
||||
|
||||
$tag = $this->client->call(Client::METHOD_PATCH, '/functions/'.$functionId.'/tag', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'tag' => $tagId,
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $tag['headers']['status-code']);
|
||||
|
||||
$execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'async' => 1,
|
||||
]);
|
||||
|
||||
$executionId = $execution['body']['$id'] ?? '';
|
||||
$this->assertEquals(201, $execution['headers']['status-code']);
|
||||
|
||||
sleep(15);
|
||||
|
||||
$executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals($executions['headers']['status-code'], 200);
|
||||
$this->assertEquals($executions['body']['sum'], 1);
|
||||
$this->assertIsArray($executions['body']['executions']);
|
||||
$this->assertCount(1, $executions['body']['executions']);
|
||||
$this->assertEquals($executions['body']['executions'][0]['$id'], $executionId);
|
||||
$this->assertEquals($executions['body']['executions'][0]['trigger'], 'http');
|
||||
$this->assertEquals($executions['body']['executions'][0]['status'], 'failed');
|
||||
$this->assertEquals($executions['body']['executions'][0]['exitCode'], 1);
|
||||
$this->assertGreaterThan(2, $executions['body']['executions'][0]['time']);
|
||||
$this->assertLessThan(3, $executions['body']['executions'][0]['time']);
|
||||
$this->assertEquals($executions['body']['executions'][0]['stdout'], '');
|
||||
$this->assertEquals($executions['body']['executions'][0]['stderr'], '');
|
||||
}
|
||||
}
|
|
@ -83,6 +83,9 @@ services:
|
|||
- _APP_STORAGE_LIMIT
|
||||
- _APP_FUNCTIONS_TIMEOUT
|
||||
- _APP_FUNCTIONS_CONTAINERS
|
||||
- _APP_FUNCTIONS_CPUS
|
||||
- _APP_FUNCTIONS_MEMORY
|
||||
- _APP_FUNCTIONS_MEMORY_SWAP
|
||||
|
||||
appwrite-worker-usage:
|
||||
entrypoint: worker-usage
|
||||
|
@ -239,6 +242,9 @@ services:
|
|||
- _APP_DB_PASS
|
||||
- _APP_FUNCTIONS_TIMEOUT
|
||||
- _APP_FUNCTIONS_CONTAINERS
|
||||
- _APP_FUNCTIONS_CPUS
|
||||
- _APP_FUNCTIONS_MEMORY
|
||||
- _APP_FUNCTIONS_MEMORY_SWAP
|
||||
|
||||
appwrite-worker-mails:
|
||||
entrypoint: worker-mails
|
||||
|
|
BIN
tests/resources/functions/deno-fx.tar.gz
Normal file
BIN
tests/resources/functions/deno-fx.tar.gz
Normal file
Binary file not shown.
BIN
tests/resources/functions/deno.tar.gz
Normal file
BIN
tests/resources/functions/deno.tar.gz
Normal file
Binary file not shown.
23
tests/resources/functions/deno/index.ts
Normal file
23
tests/resources/functions/deno/index.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
import * as sdk from "https://deno.land/x/appwrite/mod.ts";
|
||||
|
||||
let client = new sdk.Client();
|
||||
|
||||
client
|
||||
.setEndpoint(Deno.env.get("APPWRITE_ENDPOINT") || '') // Your API Endpoint
|
||||
.setProject(Deno.env.get("APPWRITE_PROJECT") || '') // Your project ID
|
||||
.setKey(Deno.env.get("APPWRITE_SECRET") || '') // Your secret API key
|
||||
;
|
||||
|
||||
let storage = new sdk.Storage(client);
|
||||
|
||||
// let result = storage.getFile(Deno.env.get("APPWRITE_FILEID"));
|
||||
|
||||
console.log(Deno.env.get("APPWRITE_FUNCTION_ID") || '');
|
||||
console.log(Deno.env.get("APPWRITE_FUNCTION_NAME") || '');
|
||||
console.log(Deno.env.get("APPWRITE_FUNCTION_TAG") || '');
|
||||
console.log(Deno.env.get("APPWRITE_FUNCTION_TRIGGER") || '');
|
||||
console.log(Deno.env.get("APPWRITE_FUNCTION_ENV_NAME") || '');
|
||||
console.log(Deno.env.get("APPWRITE_FUNCTION_ENV_VERSION") || '');
|
||||
// console.log(result['$id']"));
|
||||
console.log(Deno.env.get("APPWRITE_FUNCTION_EVENT") || '');
|
||||
console.log(Deno.env.get("APPWRITE_FUNCTION_EVENT_PAYLOAD") || '');
|
BIN
tests/resources/functions/node.tar.gz
Normal file
BIN
tests/resources/functions/node.tar.gz
Normal file
Binary file not shown.
23
tests/resources/functions/node/index.js
Normal file
23
tests/resources/functions/node/index.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
const sdk = require('node-appwrite');
|
||||
|
||||
let client = new sdk.Client();
|
||||
|
||||
client
|
||||
.setEndpoint(process.env.APPWRITE_ENDPOINT) // Your API Endpoint
|
||||
.setProject(process.env.APPWRITE_PROJECT) // Your project ID
|
||||
.setKey(process.env.APPWRITE_SECRET) // Your secret API key
|
||||
;
|
||||
|
||||
let storage = new sdk.Storage(client);
|
||||
|
||||
// let result = storage.getFile(process.env.APPWRITE_FILEID);
|
||||
|
||||
console.log(process.env.APPWRITE_FUNCTION_ID);
|
||||
console.log(process.env.APPWRITE_FUNCTION_NAME);
|
||||
console.log(process.env.APPWRITE_FUNCTION_TAG);
|
||||
console.log(process.env.APPWRITE_FUNCTION_TRIGGER);
|
||||
console.log(process.env.APPWRITE_FUNCTION_ENV_NAME);
|
||||
console.log(process.env.APPWRITE_FUNCTION_ENV_VERSION);
|
||||
// console.log(result['$id']);
|
||||
console.log(process.env.APPWRITE_FUNCTION_EVENT);
|
||||
console.log(process.env.APPWRITE_FUNCTION_EVENT_PAYLOAD);
|
376
tests/resources/functions/node/package-lock.json
generated
Normal file
376
tests/resources/functions/node/package-lock.json
generated
Normal file
|
@ -0,0 +1,376 @@
|
|||
{
|
||||
"name": "appwrite-cloud-function-demo",
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"ajv": {
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
"json-schema-traverse": "^0.4.1",
|
||||
"uri-js": "^4.2.2"
|
||||
}
|
||||
},
|
||||
"asn1": {
|
||||
"version": "0.2.4",
|
||||
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
|
||||
"integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
|
||||
"requires": {
|
||||
"safer-buffer": "~2.1.0"
|
||||
}
|
||||
},
|
||||
"assert-plus": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
|
||||
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
|
||||
},
|
||||
"asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
|
||||
},
|
||||
"aws-sign2": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
|
||||
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
|
||||
},
|
||||
"aws4": {
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz",
|
||||
"integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA=="
|
||||
},
|
||||
"bcrypt-pbkdf": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
|
||||
"integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
|
||||
"requires": {
|
||||
"tweetnacl": "^0.14.3"
|
||||
}
|
||||
},
|
||||
"caseless": {
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
|
||||
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
|
||||
},
|
||||
"combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"requires": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
}
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
|
||||
},
|
||||
"dashdash": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
|
||||
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
|
||||
"requires": {
|
||||
"assert-plus": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
|
||||
},
|
||||
"ecc-jsbn": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
|
||||
"integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
|
||||
"requires": {
|
||||
"jsbn": "~0.1.0",
|
||||
"safer-buffer": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"extend": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
|
||||
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
|
||||
},
|
||||
"extsprintf": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
|
||||
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
|
||||
},
|
||||
"fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
|
||||
},
|
||||
"fast-json-stable-stringify": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
|
||||
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
|
||||
},
|
||||
"forever-agent": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
|
||||
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
|
||||
},
|
||||
"form-data": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
|
||||
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.6",
|
||||
"mime-types": "^2.1.12"
|
||||
}
|
||||
},
|
||||
"getpass": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
|
||||
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
|
||||
"requires": {
|
||||
"assert-plus": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"har-schema": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
|
||||
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
|
||||
},
|
||||
"har-validator": {
|
||||
"version": "5.1.5",
|
||||
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
|
||||
"integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
|
||||
"requires": {
|
||||
"ajv": "^6.12.3",
|
||||
"har-schema": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"http-signature": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
|
||||
"integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
|
||||
"requires": {
|
||||
"assert-plus": "^1.0.0",
|
||||
"jsprim": "^1.2.2",
|
||||
"sshpk": "^1.7.0"
|
||||
}
|
||||
},
|
||||
"is-typedarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
|
||||
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
|
||||
},
|
||||
"isstream": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
|
||||
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
|
||||
},
|
||||
"jsbn": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
|
||||
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
|
||||
},
|
||||
"json-schema": {
|
||||
"version": "0.2.3",
|
||||
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
|
||||
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
|
||||
},
|
||||
"json-stringify-safe": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
|
||||
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
|
||||
},
|
||||
"jsprim": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
|
||||
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
|
||||
"requires": {
|
||||
"assert-plus": "1.0.0",
|
||||
"extsprintf": "1.3.0",
|
||||
"json-schema": "0.2.3",
|
||||
"verror": "1.10.0"
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.20",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
|
||||
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
|
||||
},
|
||||
"mime-db": {
|
||||
"version": "1.44.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
|
||||
"integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg=="
|
||||
},
|
||||
"mime-types": {
|
||||
"version": "2.1.27",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
|
||||
"integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
|
||||
"requires": {
|
||||
"mime-db": "1.44.0"
|
||||
}
|
||||
},
|
||||
"node-appwrite": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/node-appwrite/-/node-appwrite-1.1.0.tgz",
|
||||
"integrity": "sha512-ZLOsxmsGry4ZRT63QRbNgUxhYiUzJlQntQL2nKAy6PBL1S/hMCChKrdLIdJv3ytGxPrrIWiDWxXivMeUeCW5KA==",
|
||||
"requires": {
|
||||
"request": "^2.88.0",
|
||||
"request-promise-native": "^1.0.7"
|
||||
}
|
||||
},
|
||||
"oauth-sign": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
|
||||
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
|
||||
},
|
||||
"performance-now": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
|
||||
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
|
||||
},
|
||||
"psl": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
|
||||
"integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ=="
|
||||
},
|
||||
"punycode": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
||||
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
|
||||
},
|
||||
"qs": {
|
||||
"version": "6.5.2",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
|
||||
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
|
||||
},
|
||||
"request": {
|
||||
"version": "2.88.2",
|
||||
"resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
|
||||
"integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
|
||||
"requires": {
|
||||
"aws-sign2": "~0.7.0",
|
||||
"aws4": "^1.8.0",
|
||||
"caseless": "~0.12.0",
|
||||
"combined-stream": "~1.0.6",
|
||||
"extend": "~3.0.2",
|
||||
"forever-agent": "~0.6.1",
|
||||
"form-data": "~2.3.2",
|
||||
"har-validator": "~5.1.3",
|
||||
"http-signature": "~1.2.0",
|
||||
"is-typedarray": "~1.0.0",
|
||||
"isstream": "~0.1.2",
|
||||
"json-stringify-safe": "~5.0.1",
|
||||
"mime-types": "~2.1.19",
|
||||
"oauth-sign": "~0.9.0",
|
||||
"performance-now": "^2.1.0",
|
||||
"qs": "~6.5.2",
|
||||
"safe-buffer": "^5.1.2",
|
||||
"tough-cookie": "~2.5.0",
|
||||
"tunnel-agent": "^0.6.0",
|
||||
"uuid": "^3.3.2"
|
||||
}
|
||||
},
|
||||
"request-promise-core": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz",
|
||||
"integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==",
|
||||
"requires": {
|
||||
"lodash": "^4.17.19"
|
||||
}
|
||||
},
|
||||
"request-promise-native": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz",
|
||||
"integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==",
|
||||
"requires": {
|
||||
"request-promise-core": "1.1.4",
|
||||
"stealthy-require": "^1.1.1",
|
||||
"tough-cookie": "^2.3.3"
|
||||
}
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||
},
|
||||
"sshpk": {
|
||||
"version": "1.16.1",
|
||||
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
|
||||
"integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
|
||||
"requires": {
|
||||
"asn1": "~0.2.3",
|
||||
"assert-plus": "^1.0.0",
|
||||
"bcrypt-pbkdf": "^1.0.0",
|
||||
"dashdash": "^1.12.0",
|
||||
"ecc-jsbn": "~0.1.1",
|
||||
"getpass": "^0.1.1",
|
||||
"jsbn": "~0.1.0",
|
||||
"safer-buffer": "^2.0.2",
|
||||
"tweetnacl": "~0.14.0"
|
||||
}
|
||||
},
|
||||
"stealthy-require": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
|
||||
"integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks="
|
||||
},
|
||||
"tough-cookie": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
|
||||
"integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
|
||||
"requires": {
|
||||
"psl": "^1.1.28",
|
||||
"punycode": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"tunnel-agent": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
||||
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
|
||||
"requires": {
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"tweetnacl": {
|
||||
"version": "0.14.5",
|
||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
|
||||
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
|
||||
},
|
||||
"uri-js": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz",
|
||||
"integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==",
|
||||
"requires": {
|
||||
"punycode": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"uuid": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
|
||||
},
|
||||
"verror": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
|
||||
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
|
||||
"requires": {
|
||||
"assert-plus": "^1.0.0",
|
||||
"core-util-is": "1.0.2",
|
||||
"extsprintf": "^1.2.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
9
tests/resources/functions/node/package.json
Normal file
9
tests/resources/functions/node/package.json
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"name": "appwrite-cloud-function-demo",
|
||||
"version": "0.1.0",
|
||||
"license": "BSD-3-Clause",
|
||||
"repository": "public",
|
||||
"dependencies": {
|
||||
"node-appwrite": "1.1.0"
|
||||
}
|
||||
}
|
12
tests/resources/functions/package-deno.sh
Normal file
12
tests/resources/functions/package-deno.sh
Normal file
|
@ -0,0 +1,12 @@
|
|||
|
||||
echo 'Deno Packaging...'
|
||||
|
||||
cp -r $(pwd)/tests/resources/functions/deno $(pwd)/tests/resources/functions/packages/deno
|
||||
|
||||
docker run --rm -v $(pwd)/tests/resources/functions/packages/deno:/app -w /app appwrite/env-deno-1.5:1.0.0 ls
|
||||
docker run --rm --env DENO_DIR=./.appwrite -v $(pwd)/tests/resources/functions/packages/deno:/app -w /app appwrite/env-deno-1.5:1.0.0 deno cache index.ts
|
||||
docker run --rm -v $(pwd)/tests/resources/functions/packages/deno:/app -w /app appwrite/env-deno-1.5:1.0.0 tar -zcvf code.tar.gz .
|
||||
|
||||
mv $(pwd)/tests/resources/functions/packages/deno/code.tar.gz $(pwd)/tests/resources/functions/deno.tar.gz
|
||||
|
||||
rm -r $(pwd)/tests/resources/functions/packages/deno
|
12
tests/resources/functions/package-node.sh
Normal file
12
tests/resources/functions/package-node.sh
Normal file
|
@ -0,0 +1,12 @@
|
|||
|
||||
echo 'Node Packaging...'
|
||||
|
||||
cp -r $(pwd)/tests/resources/functions/node $(pwd)/tests/resources/functions/packages/node
|
||||
|
||||
docker run --rm -v $(pwd)/tests/resources/functions/packages/node:/app -w /app appwrite/env-node-14.5:1.0.0 npm install
|
||||
|
||||
docker run --rm -v $(pwd)/tests/resources/functions/packages/node:/app -w /app appwrite/env-node-14.5:1.0.0 tar -zcvf code.tar.gz .
|
||||
|
||||
mv $(pwd)/tests/resources/functions/packages/node/code.tar.gz $(pwd)/tests/resources/functions/node.tar.gz
|
||||
|
||||
rm -r $(pwd)/tests/resources/functions/packages/node
|
12
tests/resources/functions/package-php.sh
Normal file
12
tests/resources/functions/package-php.sh
Normal file
|
@ -0,0 +1,12 @@
|
|||
|
||||
echo 'PHP Packaging...'
|
||||
|
||||
cp -r $(pwd)/tests/resources/functions/php $(pwd)/tests/resources/functions/packages/php
|
||||
|
||||
docker run --rm -v $(pwd)/tests/resources/functions/packages/php:/app -w /app composer:2.0 composer install --ignore-platform-reqs
|
||||
|
||||
docker run --rm -v $(pwd)/tests/resources/functions/packages/php:/app -w /app appwrite/env-php-8.0:1.0.0 tar -zcvf code.tar.gz .
|
||||
|
||||
mv $(pwd)/tests/resources/functions/packages/php/code.tar.gz $(pwd)/tests/resources/functions/php.tar.gz
|
||||
|
||||
rm -r $(pwd)/tests/resources/functions/packages/php
|
12
tests/resources/functions/package-python.sh
Normal file
12
tests/resources/functions/package-python.sh
Normal file
|
@ -0,0 +1,12 @@
|
|||
|
||||
echo 'Python Packaging...'
|
||||
|
||||
cp -r $(pwd)/tests/resources/functions/python $(pwd)/tests/resources/functions/packages/python
|
||||
|
||||
docker run --rm -v $(pwd)/tests/resources/functions/packages/python:/app -w /app --env PIP_TARGET=./.appwrite appwrite/env-python-3.8:1.0.0 pip install -r ./requirements.txt --upgrade --ignore-installed
|
||||
|
||||
docker run --rm -v $(pwd)/tests/resources/functions/packages/python:/app -w /app appwrite/env-python-3.8:1.0.0 tar -zcvf code.tar.gz .
|
||||
|
||||
mv $(pwd)/tests/resources/functions/packages/python/code.tar.gz $(pwd)/tests/resources/functions/python.tar.gz
|
||||
|
||||
rm -r $(pwd)/tests/resources/functions/packages/python
|
12
tests/resources/functions/package-ruby.sh
Normal file
12
tests/resources/functions/package-ruby.sh
Normal file
|
@ -0,0 +1,12 @@
|
|||
|
||||
echo 'Ruby Packaging...'
|
||||
|
||||
cp -r $(pwd)/tests/resources/functions/ruby $(pwd)/tests/resources/functions/packages/ruby
|
||||
|
||||
docker run --rm -v $(pwd)/tests/resources/functions/packages/ruby:/app -w /app --env GEM_HOME=./.appwrite appwrite/env-ruby-2.7:1.0.2 bundle install
|
||||
|
||||
docker run --rm -v $(pwd)/tests/resources/functions/packages/ruby:/app -w /app appwrite/env-ruby-2.7:1.0.2 tar -zcvf code.tar.gz .
|
||||
|
||||
mv $(pwd)/tests/resources/functions/packages/ruby/code.tar.gz $(pwd)/tests/resources/functions/ruby.tar.gz
|
||||
|
||||
rm -r $(pwd)/tests/resources/functions/packages/ruby
|
10
tests/resources/functions/package-timeout.sh
Normal file
10
tests/resources/functions/package-timeout.sh
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
echo 'Timeout Packaging...'
|
||||
|
||||
cp -r $(pwd)/tests/resources/functions/timeout $(pwd)/tests/resources/functions/packages/timeout
|
||||
|
||||
docker run --rm -v $(pwd)/tests/resources/functions/packages/timeout:/app -w /app appwrite/env-php-8.0:1.0.0 tar -zcvf code.tar.gz .
|
||||
|
||||
mv $(pwd)/tests/resources/functions/packages/timeout/code.tar.gz $(pwd)/tests/resources/functions/timeout.tar.gz
|
||||
|
||||
rm -r $(pwd)/tests/resources/functions/packages/timeout
|
0
tests/resources/functions/packages/.gitkeep
Normal file
0
tests/resources/functions/packages/.gitkeep
Normal file
Binary file not shown.
BIN
tests/resources/functions/php.tar.gz
Normal file
BIN
tests/resources/functions/php.tar.gz
Normal file
Binary file not shown.
18
tests/resources/functions/php/composer.json
Normal file
18
tests/resources/functions/php/composer.json
Normal file
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "appwrite/cloud-function-demo",
|
||||
"description": "Demo cloud function script",
|
||||
"type": "library",
|
||||
"license": "BSD-3-Clause",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Team Appwrite",
|
||||
"email": "team@appwrite.io"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.4.0",
|
||||
"ext-curl": "*",
|
||||
"ext-json": "*",
|
||||
"appwrite/appwrite": "1.1.*"
|
||||
}
|
||||
}
|
64
tests/resources/functions/php/composer.lock
generated
Normal file
64
tests/resources/functions/php/composer.lock
generated
Normal file
|
@ -0,0 +1,64 @@
|
|||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "afdff6a172e6c44aee11f1562175f81a",
|
||||
"packages": [
|
||||
{
|
||||
"name": "appwrite/appwrite",
|
||||
"version": "1.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/appwrite/sdk-for-php.git",
|
||||
"reference": "98b327d3fd18a72f4582019916afd735a0e9e0e7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-for-php/zipball/98b327d3fd18a72f4582019916afd735a0e9e0e7",
|
||||
"reference": "98b327d3fd18a72f4582019916afd735a0e9e0e7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-curl": "*",
|
||||
"ext-json": "*",
|
||||
"php": ">=7.1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "3.7.35"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Appwrite\\": "src/Appwrite"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"description": "Appwrite is an open-source backend as a service server that abstract and simplify complex and repetitive development tasks",
|
||||
"support": {
|
||||
"email": "team@localhost.test",
|
||||
"issues": "https://github.com/appwrite/sdk-for-php/issues",
|
||||
"source": "https://github.com/appwrite/sdk-for-php/tree/1.1.2",
|
||||
"url": "https://appwrite.io/support"
|
||||
},
|
||||
"time": "2020-08-15T18:24:32+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"php": ">=7.4.0",
|
||||
"ext-curl": "*",
|
||||
"ext-json": "*"
|
||||
},
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "2.0.0"
|
||||
}
|
28
tests/resources/functions/php/index.php
Normal file
28
tests/resources/functions/php/index.php
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
include './vendor/autoload.php';
|
||||
|
||||
use Appwrite\Client;
|
||||
use Appwrite\Services\Storage;
|
||||
|
||||
$client = new Client();
|
||||
|
||||
$client
|
||||
->setEndpoint($_ENV['APPWRITE_ENDPOINT']) // Your API Endpoint
|
||||
->setProject($_ENV['APPWRITE_PROJECT']) // Your project ID
|
||||
->setKey($_ENV['APPWRITE_SECRET']) // Your secret API key
|
||||
;
|
||||
|
||||
$storage = new Storage($client);
|
||||
|
||||
// $result = $storage->getFile($_ENV['APPWRITE_FILEID']);
|
||||
|
||||
echo $_ENV['APPWRITE_FUNCTION_ID']."\n";
|
||||
echo $_ENV['APPWRITE_FUNCTION_NAME']."\n";
|
||||
echo $_ENV['APPWRITE_FUNCTION_TAG']."\n";
|
||||
echo $_ENV['APPWRITE_FUNCTION_TRIGGER']."\n";
|
||||
echo $_ENV['APPWRITE_FUNCTION_ENV_NAME']."\n";
|
||||
echo $_ENV['APPWRITE_FUNCTION_ENV_VERSION']."\n";
|
||||
// echo $result['$id'];
|
||||
echo $_ENV['APPWRITE_FUNCTION_EVENT']."\n";
|
||||
echo $_ENV['APPWRITE_FUNCTION_EVENT_PAYLOAD']."\n";
|
Binary file not shown.
BIN
tests/resources/functions/python.tar.gz
Normal file
BIN
tests/resources/functions/python.tar.gz
Normal file
Binary file not shown.
23
tests/resources/functions/python/main.py
Normal file
23
tests/resources/functions/python/main.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
import json
|
||||
import os
|
||||
from appwrite.client import Client
|
||||
from appwrite.services.storage import Storage
|
||||
|
||||
# Setup appwrite client
|
||||
client = Client()
|
||||
client.set_endpoint(os.environ["APPWRITE_ENDPOINT"]) # PRIVATE IP OF YOUR APPWRITE CONTAINER
|
||||
client.set_project(os.environ["APPWRITE_PROJECT"]) # YOUR PROJECT ID
|
||||
client.set_key(os.environ["APPWRITE_SECRET"])
|
||||
|
||||
storage = Storage(client)
|
||||
# result = storage.get_file(os.environ["APPWRITE_FILEID"])
|
||||
|
||||
print(os.environ["APPWRITE_FUNCTION_ID"])
|
||||
print(os.environ["APPWRITE_FUNCTION_NAME"])
|
||||
print(os.environ["APPWRITE_FUNCTION_TAG"])
|
||||
print(os.environ["APPWRITE_FUNCTION_TRIGGER"])
|
||||
print(os.environ["APPWRITE_FUNCTION_ENV_NAME"])
|
||||
print(os.environ["APPWRITE_FUNCTION_ENV_VERSION"])
|
||||
# print(result["$id"])
|
||||
print(os.environ["APPWRITE_FUNCTION_EVENT"])
|
||||
print(os.environ["APPWRITE_FUNCTION_EVENT_PAYLOAD"])
|
1
tests/resources/functions/python/requirements.txt
Normal file
1
tests/resources/functions/python/requirements.txt
Normal file
|
@ -0,0 +1 @@
|
|||
appwrite
|
BIN
tests/resources/functions/ruby.tar.gz
Normal file
BIN
tests/resources/functions/ruby.tar.gz
Normal file
Binary file not shown.
5
tests/resources/functions/ruby/Gemfile
Normal file
5
tests/resources/functions/ruby/Gemfile
Normal file
|
@ -0,0 +1,5 @@
|
|||
source "https://rubygems.org"
|
||||
|
||||
ruby "~> 2.7.0"
|
||||
|
||||
gem 'appwrite', '~> 1.0', '>= 1.0.11'
|
16
tests/resources/functions/ruby/Gemfile.lock
Normal file
16
tests/resources/functions/ruby/Gemfile.lock
Normal file
|
@ -0,0 +1,16 @@
|
|||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
appwrite (1.0.11)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
appwrite (~> 1.0, >= 1.0.11)
|
||||
|
||||
RUBY VERSION
|
||||
ruby 2.7.2p137
|
||||
|
||||
BUNDLED WITH
|
||||
2.1.4
|
23
tests/resources/functions/ruby/app.rb
Normal file
23
tests/resources/functions/ruby/app.rb
Normal file
|
@ -0,0 +1,23 @@
|
|||
require 'appwrite'
|
||||
|
||||
client = Appwrite::Client.new()
|
||||
|
||||
client
|
||||
.set_endpoint(ENV["APPWRITE_ENDPOINT"]) # Your API Endpoint
|
||||
.set_project(ENV["APPWRITE_PROJECT"]) # Your project ID
|
||||
.set_key(ENV["APPWRITE_SECRET"]) # Your secret API key
|
||||
;
|
||||
|
||||
storage = Appwrite::Storage.new(client);
|
||||
|
||||
# result = storage.get_file(ENV["APPWRITE_FILEID"]);
|
||||
|
||||
puts ENV["APPWRITE_FUNCTION_ID"]
|
||||
puts ENV["APPWRITE_FUNCTION_NAME"]
|
||||
puts ENV["APPWRITE_FUNCTION_TAG"]
|
||||
puts ENV["APPWRITE_FUNCTION_TRIGGER"]
|
||||
puts ENV["APPWRITE_FUNCTION_ENV_NAME"]
|
||||
puts ENV["APPWRITE_FUNCTION_ENV_VERSION"]
|
||||
# puts result["$id"]
|
||||
puts ENV["APPWRITE_FUNCTION_EVENT"]
|
||||
puts ENV["APPWRITE_FUNCTION_EVENT_PAYLOAD"]
|
BIN
tests/resources/functions/timeout.tar.gz
Normal file
BIN
tests/resources/functions/timeout.tar.gz
Normal file
Binary file not shown.
3
tests/resources/functions/timeout/index.php
Normal file
3
tests/resources/functions/timeout/index.php
Normal file
|
@ -0,0 +1,3 @@
|
|||
<?php
|
||||
|
||||
sleep(10);
|
Loading…
Reference in a new issue