Merge branch '1.6.x' of https://github.com/appwrite/appwrite into fix-redirect-validator-v2

This commit is contained in:
loks0n
2025-02-06 11:22:49 +00:00
54 changed files with 2447 additions and 2776 deletions
+12 -12
View File
@@ -19,7 +19,7 @@ use Utopia\DSN\DSN;
use Utopia\Logger\Log;
use Utopia\Platform\Service;
use Utopia\Pools\Group;
use Utopia\Queue\Connection;
use Utopia\Queue\Publisher;
use Utopia\Registry\Registry;
use Utopia\System\System;
@@ -160,18 +160,18 @@ CLI::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform
};
}, ['pools', 'dbForPlatform', 'cache']);
CLI::setResource('queue', function (Group $pools) {
return $pools->get('queue')->pop()->getResource();
CLI::setResource('publisher', function (Group $pools) {
return $pools->get('publisher')->pop()->getResource();
}, ['pools']);
CLI::setResource('queueForFunctions', function (Connection $queue) {
return new Func($queue);
}, ['queue']);
CLI::setResource('queueForDeletes', function (Connection $queue) {
return new Delete($queue);
}, ['queue']);
CLI::setResource('queueForCertificates', function (Connection $queue) {
return new Certificate($queue);
}, ['queue']);
CLI::setResource('queueForFunctions', function (Publisher $publisher) {
return new Func($publisher);
}, ['publisher']);
CLI::setResource('queueForDeletes', function (Publisher $publisher) {
return new Delete($publisher);
}, ['publisher']);
CLI::setResource('queueForCertificates', function (Publisher $publisher) {
return new Certificate($publisher);
}, ['publisher']);
CLI::setResource('logError', function (Registry $register) {
return function (Throwable $error, string $namespace, string $action) use ($register) {
$logger = $register->get('logger');
+1 -1
View File
@@ -564,7 +564,7 @@ return [
'default' => null,
'array' => false,
'filters' => [],
],
]
],
'indexes' => [
[
+28 -28
View File
@@ -4761,7 +4761,7 @@
},
"x-appwrite": {
"method": "listExecutions",
"weight": 306,
"weight": 305,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4846,7 +4846,7 @@
},
"x-appwrite": {
"method": "createExecution",
"weight": 305,
"weight": 304,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4960,7 +4960,7 @@
},
"x-appwrite": {
"method": "getExecution",
"weight": 307,
"weight": 306,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5033,7 +5033,7 @@
},
"x-appwrite": {
"method": "query",
"weight": 331,
"weight": 330,
"cookies": false,
"type": "graphql",
"deprecated": false,
@@ -5084,7 +5084,7 @@
},
"x-appwrite": {
"method": "mutation",
"weight": 330,
"weight": 329,
"cookies": false,
"type": "graphql",
"deprecated": false,
@@ -5543,7 +5543,7 @@
},
"x-appwrite": {
"method": "createSubscriber",
"weight": 376,
"weight": 375,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5625,7 +5625,7 @@
},
"x-appwrite": {
"method": "deleteSubscriber",
"weight": 380,
"weight": 379,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5699,7 +5699,7 @@
},
"x-appwrite": {
"method": "listFiles",
"weight": 208,
"weight": 207,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5784,7 +5784,7 @@
},
"x-appwrite": {
"method": "createFile",
"weight": 207,
"weight": 206,
"cookies": false,
"type": "upload",
"deprecated": false,
@@ -5881,7 +5881,7 @@
},
"x-appwrite": {
"method": "getFile",
"weight": 209,
"weight": 208,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5952,7 +5952,7 @@
},
"x-appwrite": {
"method": "updateFile",
"weight": 214,
"weight": 213,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6040,7 +6040,7 @@
},
"x-appwrite": {
"method": "deleteFile",
"weight": 215,
"weight": 214,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6106,7 +6106,7 @@
},
"x-appwrite": {
"method": "getFileDownload",
"weight": 211,
"weight": 210,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6172,7 +6172,7 @@
},
"x-appwrite": {
"method": "getFilePreview",
"weight": 210,
"weight": 209,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6388,7 +6388,7 @@
},
"x-appwrite": {
"method": "getFileView",
"weight": 212,
"weight": 211,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6461,7 +6461,7 @@
},
"x-appwrite": {
"method": "list",
"weight": 219,
"weight": 218,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6536,7 +6536,7 @@
},
"x-appwrite": {
"method": "create",
"weight": 218,
"weight": 217,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6620,7 +6620,7 @@
},
"x-appwrite": {
"method": "get",
"weight": 220,
"weight": 219,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6681,7 +6681,7 @@
},
"x-appwrite": {
"method": "updateName",
"weight": 222,
"weight": 221,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6754,7 +6754,7 @@
},
"x-appwrite": {
"method": "delete",
"weight": 224,
"weight": 223,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6817,7 +6817,7 @@
},
"x-appwrite": {
"method": "listMemberships",
"weight": 226,
"weight": 225,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6902,7 +6902,7 @@
},
"x-appwrite": {
"method": "createMembership",
"weight": 225,
"weight": 224,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7012,7 +7012,7 @@
},
"x-appwrite": {
"method": "getMembership",
"weight": 227,
"weight": 226,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7083,7 +7083,7 @@
},
"x-appwrite": {
"method": "updateMembership",
"weight": 228,
"weight": 227,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7169,7 +7169,7 @@
},
"x-appwrite": {
"method": "deleteMembership",
"weight": 230,
"weight": 229,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7242,7 +7242,7 @@
},
"x-appwrite": {
"method": "updateMembershipStatus",
"weight": 229,
"weight": 228,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7339,7 +7339,7 @@
},
"x-appwrite": {
"method": "getPrefs",
"weight": 221,
"weight": 220,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7399,7 +7399,7 @@
},
"x-appwrite": {
"method": "updatePrefs",
"weight": 223,
"weight": 222,
"cookies": false,
"type": "",
"deprecated": false,
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+28 -28
View File
@@ -4761,7 +4761,7 @@
},
"x-appwrite": {
"method": "listExecutions",
"weight": 306,
"weight": 305,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4846,7 +4846,7 @@
},
"x-appwrite": {
"method": "createExecution",
"weight": 305,
"weight": 304,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4960,7 +4960,7 @@
},
"x-appwrite": {
"method": "getExecution",
"weight": 307,
"weight": 306,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5033,7 +5033,7 @@
},
"x-appwrite": {
"method": "query",
"weight": 331,
"weight": 330,
"cookies": false,
"type": "graphql",
"deprecated": false,
@@ -5084,7 +5084,7 @@
},
"x-appwrite": {
"method": "mutation",
"weight": 330,
"weight": 329,
"cookies": false,
"type": "graphql",
"deprecated": false,
@@ -5543,7 +5543,7 @@
},
"x-appwrite": {
"method": "createSubscriber",
"weight": 376,
"weight": 375,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5625,7 +5625,7 @@
},
"x-appwrite": {
"method": "deleteSubscriber",
"weight": 380,
"weight": 379,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5699,7 +5699,7 @@
},
"x-appwrite": {
"method": "listFiles",
"weight": 208,
"weight": 207,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5784,7 +5784,7 @@
},
"x-appwrite": {
"method": "createFile",
"weight": 207,
"weight": 206,
"cookies": false,
"type": "upload",
"deprecated": false,
@@ -5881,7 +5881,7 @@
},
"x-appwrite": {
"method": "getFile",
"weight": 209,
"weight": 208,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5952,7 +5952,7 @@
},
"x-appwrite": {
"method": "updateFile",
"weight": 214,
"weight": 213,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6040,7 +6040,7 @@
},
"x-appwrite": {
"method": "deleteFile",
"weight": 215,
"weight": 214,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6106,7 +6106,7 @@
},
"x-appwrite": {
"method": "getFileDownload",
"weight": 211,
"weight": 210,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6172,7 +6172,7 @@
},
"x-appwrite": {
"method": "getFilePreview",
"weight": 210,
"weight": 209,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6388,7 +6388,7 @@
},
"x-appwrite": {
"method": "getFileView",
"weight": 212,
"weight": 211,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6461,7 +6461,7 @@
},
"x-appwrite": {
"method": "list",
"weight": 219,
"weight": 218,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6536,7 +6536,7 @@
},
"x-appwrite": {
"method": "create",
"weight": 218,
"weight": 217,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6620,7 +6620,7 @@
},
"x-appwrite": {
"method": "get",
"weight": 220,
"weight": 219,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6681,7 +6681,7 @@
},
"x-appwrite": {
"method": "updateName",
"weight": 222,
"weight": 221,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6754,7 +6754,7 @@
},
"x-appwrite": {
"method": "delete",
"weight": 224,
"weight": 223,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6817,7 +6817,7 @@
},
"x-appwrite": {
"method": "listMemberships",
"weight": 226,
"weight": 225,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6902,7 +6902,7 @@
},
"x-appwrite": {
"method": "createMembership",
"weight": 225,
"weight": 224,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7012,7 +7012,7 @@
},
"x-appwrite": {
"method": "getMembership",
"weight": 227,
"weight": 226,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7083,7 +7083,7 @@
},
"x-appwrite": {
"method": "updateMembership",
"weight": 228,
"weight": 227,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7169,7 +7169,7 @@
},
"x-appwrite": {
"method": "deleteMembership",
"weight": 230,
"weight": 229,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7242,7 +7242,7 @@
},
"x-appwrite": {
"method": "updateMembershipStatus",
"weight": 229,
"weight": 228,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7339,7 +7339,7 @@
},
"x-appwrite": {
"method": "getPrefs",
"weight": 221,
"weight": 220,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7399,7 +7399,7 @@
},
"x-appwrite": {
"method": "updatePrefs",
"weight": 223,
"weight": 222,
"cookies": false,
"type": "",
"deprecated": false,
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+28 -28
View File
@@ -4927,7 +4927,7 @@
},
"x-appwrite": {
"method": "listExecutions",
"weight": 306,
"weight": 305,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5009,7 +5009,7 @@
},
"x-appwrite": {
"method": "createExecution",
"weight": 305,
"weight": 304,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5127,7 +5127,7 @@
},
"x-appwrite": {
"method": "getExecution",
"weight": 307,
"weight": 306,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5198,7 +5198,7 @@
},
"x-appwrite": {
"method": "query",
"weight": 331,
"weight": 330,
"cookies": false,
"type": "graphql",
"deprecated": false,
@@ -5271,7 +5271,7 @@
},
"x-appwrite": {
"method": "mutation",
"weight": 330,
"weight": 329,
"cookies": false,
"type": "graphql",
"deprecated": false,
@@ -5768,7 +5768,7 @@
},
"x-appwrite": {
"method": "createSubscriber",
"weight": 376,
"weight": 375,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5852,7 +5852,7 @@
},
"x-appwrite": {
"method": "deleteSubscriber",
"weight": 380,
"weight": 379,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5924,7 +5924,7 @@
},
"x-appwrite": {
"method": "listFiles",
"weight": 208,
"weight": 207,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6006,7 +6006,7 @@
},
"x-appwrite": {
"method": "createFile",
"weight": 207,
"weight": 206,
"cookies": false,
"type": "upload",
"deprecated": false,
@@ -6097,7 +6097,7 @@
},
"x-appwrite": {
"method": "getFile",
"weight": 209,
"weight": 208,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6166,7 +6166,7 @@
},
"x-appwrite": {
"method": "updateFile",
"weight": 214,
"weight": 213,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6254,7 +6254,7 @@
},
"x-appwrite": {
"method": "deleteFile",
"weight": 215,
"weight": 214,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6325,7 +6325,7 @@
},
"x-appwrite": {
"method": "getFileDownload",
"weight": 211,
"weight": 210,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6396,7 +6396,7 @@
},
"x-appwrite": {
"method": "getFilePreview",
"weight": 210,
"weight": 209,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6595,7 +6595,7 @@
},
"x-appwrite": {
"method": "getFileView",
"weight": 212,
"weight": 211,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6666,7 +6666,7 @@
},
"x-appwrite": {
"method": "list",
"weight": 219,
"weight": 218,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6740,7 +6740,7 @@
},
"x-appwrite": {
"method": "create",
"weight": 218,
"weight": 217,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6831,7 +6831,7 @@
},
"x-appwrite": {
"method": "get",
"weight": 220,
"weight": 219,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6892,7 +6892,7 @@
},
"x-appwrite": {
"method": "updateName",
"weight": 222,
"weight": 221,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6966,7 +6966,7 @@
},
"x-appwrite": {
"method": "delete",
"weight": 224,
"weight": 223,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7029,7 +7029,7 @@
},
"x-appwrite": {
"method": "listMemberships",
"weight": 226,
"weight": 225,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7111,7 +7111,7 @@
},
"x-appwrite": {
"method": "createMembership",
"weight": 225,
"weight": 224,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7225,7 +7225,7 @@
},
"x-appwrite": {
"method": "getMembership",
"weight": 227,
"weight": 226,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7294,7 +7294,7 @@
},
"x-appwrite": {
"method": "updateMembership",
"weight": 228,
"weight": 227,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7379,7 +7379,7 @@
},
"x-appwrite": {
"method": "deleteMembership",
"weight": 230,
"weight": 229,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7450,7 +7450,7 @@
},
"x-appwrite": {
"method": "updateMembershipStatus",
"weight": 229,
"weight": 228,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7545,7 +7545,7 @@
},
"x-appwrite": {
"method": "getPrefs",
"weight": 221,
"weight": 220,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7605,7 +7605,7 @@
},
"x-appwrite": {
"method": "updatePrefs",
"weight": 223,
"weight": 222,
"cookies": false,
"type": "",
"deprecated": false,
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+28 -28
View File
@@ -4927,7 +4927,7 @@
},
"x-appwrite": {
"method": "listExecutions",
"weight": 306,
"weight": 305,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5009,7 +5009,7 @@
},
"x-appwrite": {
"method": "createExecution",
"weight": 305,
"weight": 304,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5127,7 +5127,7 @@
},
"x-appwrite": {
"method": "getExecution",
"weight": 307,
"weight": 306,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5198,7 +5198,7 @@
},
"x-appwrite": {
"method": "query",
"weight": 331,
"weight": 330,
"cookies": false,
"type": "graphql",
"deprecated": false,
@@ -5271,7 +5271,7 @@
},
"x-appwrite": {
"method": "mutation",
"weight": 330,
"weight": 329,
"cookies": false,
"type": "graphql",
"deprecated": false,
@@ -5768,7 +5768,7 @@
},
"x-appwrite": {
"method": "createSubscriber",
"weight": 376,
"weight": 375,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5852,7 +5852,7 @@
},
"x-appwrite": {
"method": "deleteSubscriber",
"weight": 380,
"weight": 379,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5924,7 +5924,7 @@
},
"x-appwrite": {
"method": "listFiles",
"weight": 208,
"weight": 207,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6006,7 +6006,7 @@
},
"x-appwrite": {
"method": "createFile",
"weight": 207,
"weight": 206,
"cookies": false,
"type": "upload",
"deprecated": false,
@@ -6097,7 +6097,7 @@
},
"x-appwrite": {
"method": "getFile",
"weight": 209,
"weight": 208,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6166,7 +6166,7 @@
},
"x-appwrite": {
"method": "updateFile",
"weight": 214,
"weight": 213,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6254,7 +6254,7 @@
},
"x-appwrite": {
"method": "deleteFile",
"weight": 215,
"weight": 214,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6325,7 +6325,7 @@
},
"x-appwrite": {
"method": "getFileDownload",
"weight": 211,
"weight": 210,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6396,7 +6396,7 @@
},
"x-appwrite": {
"method": "getFilePreview",
"weight": 210,
"weight": 209,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6595,7 +6595,7 @@
},
"x-appwrite": {
"method": "getFileView",
"weight": 212,
"weight": 211,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6666,7 +6666,7 @@
},
"x-appwrite": {
"method": "list",
"weight": 219,
"weight": 218,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6740,7 +6740,7 @@
},
"x-appwrite": {
"method": "create",
"weight": 218,
"weight": 217,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6831,7 +6831,7 @@
},
"x-appwrite": {
"method": "get",
"weight": 220,
"weight": 219,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6892,7 +6892,7 @@
},
"x-appwrite": {
"method": "updateName",
"weight": 222,
"weight": 221,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6966,7 +6966,7 @@
},
"x-appwrite": {
"method": "delete",
"weight": 224,
"weight": 223,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7029,7 +7029,7 @@
},
"x-appwrite": {
"method": "listMemberships",
"weight": 226,
"weight": 225,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7111,7 +7111,7 @@
},
"x-appwrite": {
"method": "createMembership",
"weight": 225,
"weight": 224,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7225,7 +7225,7 @@
},
"x-appwrite": {
"method": "getMembership",
"weight": 227,
"weight": 226,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7294,7 +7294,7 @@
},
"x-appwrite": {
"method": "updateMembership",
"weight": 228,
"weight": 227,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7379,7 +7379,7 @@
},
"x-appwrite": {
"method": "deleteMembership",
"weight": 230,
"weight": 229,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7450,7 +7450,7 @@
},
"x-appwrite": {
"method": "updateMembershipStatus",
"weight": 229,
"weight": 228,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7545,7 +7545,7 @@
},
"x-appwrite": {
"method": "getPrefs",
"weight": 221,
"weight": 220,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7605,7 +7605,7 @@
},
"x-appwrite": {
"method": "updatePrefs",
"weight": 223,
"weight": 222,
"cookies": false,
"type": "",
"deprecated": false,
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+41 -117
View File
@@ -13,8 +13,8 @@ use Utopia\Config\Config;
use Utopia\Database\Document;
use Utopia\Domains\Validator\PublicDomain;
use Utopia\Pools\Group;
use Utopia\Queue\Client;
use Utopia\Queue\Connection;
use Utopia\Queue\Publisher;
use Utopia\Queue\Queue;
use Utopia\Registry\Registry;
use Utopia\Storage\Device;
use Utopia\Storage\Device\Local;
@@ -188,69 +188,6 @@ App::get('/v1/health/cache')
]), Response::MODEL_HEALTH_STATUS_LIST);
});
App::get('/v1/health/queue')
->desc('Get queue')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk', new Method(
auth: [AuthType::KEY],
namespace: 'health',
name: 'getQueue',
description: '/docs/references/health/get-queue.md',
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_HEALTH_STATUS,
)
],
contentType: ContentType::JSON
))
->inject('response')
->inject('pools')
->action(function (Response $response, Group $pools) {
$output = [];
$configs = [
'Queue' => Config::getParam('pools-queue'),
];
foreach ($configs as $key => $config) {
foreach ($config as $database) {
$checkStart = \microtime(true);
try {
/** @var Connection $adapter */
$adapter = $pools->get($database)->pop()->getResource();
if ($adapter->ping()) {
$output[] = new Document([
'name' => $key . " ($database)",
'status' => 'pass',
'ping' => \round((\microtime(true) - $checkStart) / 1000)
]);
} else {
$output[] = new Document([
'name' => $key . " ($database)",
'status' => 'fail',
'ping' => \round((\microtime(true) - $checkStart) / 1000)
]);
}
} catch (\Throwable $th) {
$output[] = new Document([
'name' => $key . " ($database)",
'status' => 'fail',
'ping' => \round((\microtime(true) - $checkStart) / 1000)
]);
}
}
}
$response->dynamic(new Document([
'statuses' => $output,
'total' => count($output),
]), Response::MODEL_HEALTH_STATUS_LIST);
});
App::get('/v1/health/pubsub')
->desc('Get pubsub')
->groups(['api', 'health'])
@@ -396,13 +333,12 @@ App::get('/v1/health/queue/webhooks')
contentType: ContentType::JSON
))
->param('threshold', 5000, new Integer(true), 'Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.', true)
->inject('queue')
->inject('publisher')
->inject('response')
->action(function (int|string $threshold, Connection $queue, Response $response) {
->action(function (int|string $threshold, Publisher $publisher, Response $response) {
$threshold = \intval($threshold);
$client = new Client(Event::WEBHOOK_QUEUE_NAME, $queue);
$size = $client->getQueueSize();
$size = $publisher->getQueueSize(new Queue(Event::WEBHOOK_QUEUE_NAME));
if ($size >= $threshold) {
throw new Exception(Exception::HEALTH_QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
@@ -429,13 +365,12 @@ App::get('/v1/health/queue/logs')
contentType: ContentType::JSON
))
->param('threshold', 5000, new Integer(true), 'Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.', true)
->inject('queue')
->inject('publisher')
->inject('response')
->action(function (int|string $threshold, Connection $queue, Response $response) {
->action(function (int|string $threshold, Publisher $publisher, Response $response) {
$threshold = \intval($threshold);
$client = new Client(Event::AUDITS_QUEUE_NAME, $queue);
$size = $client->getQueueSize();
$size = $publisher->getQueueSize(new Queue(Event::AUDITS_QUEUE_NAME));
if ($size >= $threshold) {
throw new Exception(Exception::HEALTH_QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
@@ -518,13 +453,12 @@ App::get('/v1/health/queue/certificates')
contentType: ContentType::JSON
))
->param('threshold', 5000, new Integer(true), 'Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.', true)
->inject('queue')
->inject('publisher')
->inject('response')
->action(function (int|string $threshold, Connection $queue, Response $response) {
->action(function (int|string $threshold, Publisher $publisher, Response $response) {
$threshold = \intval($threshold);
$client = new Client(Event::CERTIFICATES_QUEUE_NAME, $queue);
$size = $client->getQueueSize();
$size = $publisher->getQueueSize(new Queue(Event::CERTIFICATES_QUEUE_NAME));
if ($size >= $threshold) {
throw new Exception(Exception::HEALTH_QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
@@ -551,13 +485,12 @@ App::get('/v1/health/queue/builds')
contentType: ContentType::JSON
))
->param('threshold', 5000, new Integer(true), 'Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.', true)
->inject('queue')
->inject('publisher')
->inject('response')
->action(function (int|string $threshold, Connection $queue, Response $response) {
->action(function (int|string $threshold, Publisher $publisher, Response $response) {
$threshold = \intval($threshold);
$client = new Client(Event::BUILDS_QUEUE_NAME, $queue);
$size = $client->getQueueSize();
$size = $publisher->getQueueSize(new Queue(Event::BUILDS_QUEUE_NAME));
if ($size >= $threshold) {
throw new Exception(Exception::HEALTH_QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
@@ -585,13 +518,12 @@ App::get('/v1/health/queue/databases')
))
->param('name', 'database_db_main', new Text(256), 'Queue name for which to check the queue size', true)
->param('threshold', 5000, new Integer(true), 'Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.', true)
->inject('queue')
->inject('publisher')
->inject('response')
->action(function (string $name, int|string $threshold, Connection $queue, Response $response) {
->action(function (string $name, int|string $threshold, Publisher $publisher, Response $response) {
$threshold = \intval($threshold);
$client = new Client($name, $queue);
$size = $client->getQueueSize();
$size = $publisher->getQueueSize(new Queue($name));
if ($size >= $threshold) {
throw new Exception(Exception::HEALTH_QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
@@ -618,13 +550,12 @@ App::get('/v1/health/queue/deletes')
contentType: ContentType::JSON
))
->param('threshold', 5000, new Integer(true), 'Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.', true)
->inject('queue')
->inject('publisher')
->inject('response')
->action(function (int|string $threshold, Connection $queue, Response $response) {
->action(function (int|string $threshold, Publisher $publisher, Response $response) {
$threshold = \intval($threshold);
$client = new Client(Event::DELETE_QUEUE_NAME, $queue);
$size = $client->getQueueSize();
$size = $publisher->getQueueSize(new Queue(Event::DELETE_QUEUE_NAME));
if ($size >= $threshold) {
throw new Exception(Exception::HEALTH_QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
@@ -651,13 +582,12 @@ App::get('/v1/health/queue/mails')
contentType: ContentType::JSON
))
->param('threshold', 5000, new Integer(true), 'Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.', true)
->inject('queue')
->inject('publisher')
->inject('response')
->action(function (int|string $threshold, Connection $queue, Response $response) {
->action(function (int|string $threshold, Publisher $publisher, Response $response) {
$threshold = \intval($threshold);
$client = new Client(Event::MAILS_QUEUE_NAME, $queue);
$size = $client->getQueueSize();
$size = $publisher->getQueueSize(new Queue(Event::MAILS_QUEUE_NAME));
if ($size >= $threshold) {
throw new Exception(Exception::HEALTH_QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
@@ -684,13 +614,12 @@ App::get('/v1/health/queue/messaging')
contentType: ContentType::JSON
))
->param('threshold', 5000, new Integer(true), 'Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.', true)
->inject('queue')
->inject('publisher')
->inject('response')
->action(function (int|string $threshold, Connection $queue, Response $response) {
->action(function (int|string $threshold, Publisher $publisher, Response $response) {
$threshold = \intval($threshold);
$client = new Client(Event::MESSAGING_QUEUE_NAME, $queue);
$size = $client->getQueueSize();
$size = $publisher->getQueueSize(new Queue(Event::MESSAGING_QUEUE_NAME));
if ($size >= $threshold) {
throw new Exception(Exception::HEALTH_QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
@@ -717,13 +646,12 @@ App::get('/v1/health/queue/migrations')
contentType: ContentType::JSON
))
->param('threshold', 5000, new Integer(true), 'Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.', true)
->inject('queue')
->inject('publisher')
->inject('response')
->action(function (int|string $threshold, Connection $queue, Response $response) {
->action(function (int|string $threshold, Publisher $publisher, Response $response) {
$threshold = \intval($threshold);
$client = new Client(Event::MIGRATIONS_QUEUE_NAME, $queue);
$size = $client->getQueueSize();
$size = $publisher->getQueueSize(new Queue(Event::MIGRATIONS_QUEUE_NAME));
if ($size >= $threshold) {
throw new Exception(Exception::HEALTH_QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
@@ -750,13 +678,12 @@ App::get('/v1/health/queue/functions')
contentType: ContentType::JSON
))
->param('threshold', 5000, new Integer(true), 'Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.', true)
->inject('queue')
->inject('publisher')
->inject('response')
->action(function (int|string $threshold, Connection $queue, Response $response) {
->action(function (int|string $threshold, Publisher $publisher, Response $response) {
$threshold = \intval($threshold);
$client = new Client(Event::FUNCTIONS_QUEUE_NAME, $queue);
$size = $client->getQueueSize();
$size = $publisher->getQueueSize(new Queue(Event::FUNCTIONS_QUEUE_NAME));
if ($size >= $threshold) {
throw new Exception(Exception::HEALTH_QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
@@ -783,13 +710,12 @@ App::get('/v1/health/queue/usage')
contentType: ContentType::JSON
))
->param('threshold', 5000, new Integer(true), 'Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.', true)
->inject('queue')
->inject('publisher')
->inject('response')
->action(function (int|string $threshold, Connection $queue, Response $response) {
->action(function (int|string $threshold, Publisher $publisher, Response $response) {
$threshold = \intval($threshold);
$client = new Client(Event::USAGE_QUEUE_NAME, $queue);
$size = $client->getQueueSize();
$size = $publisher->getQueueSize(new Queue(Event::USAGE_QUEUE_NAME));
if ($size >= $threshold) {
throw new Exception(Exception::HEALTH_QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
@@ -816,13 +742,12 @@ App::get('/v1/health/queue/usage-dump')
contentType: ContentType::JSON
))
->param('threshold', 5000, new Integer(true), 'Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.', true)
->inject('queue')
->inject('publisher')
->inject('response')
->action(function (int|string $threshold, Connection $queue, Response $response) {
->action(function (int|string $threshold, Publisher $publisher, Response $response) {
$threshold = \intval($threshold);
$client = new Client(Event::USAGE_DUMP_QUEUE_NAME, $queue);
$size = $client->getQueueSize();
$size = $publisher->getQueueSize(new Queue(Event::USAGE_DUMP_QUEUE_NAME));
if ($size >= $threshold) {
throw new Exception(Exception::HEALTH_QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
@@ -1005,12 +930,11 @@ App::get('/v1/health/queue/failed/:name')
]), 'The name of the queue')
->param('threshold', 5000, new Integer(true), 'Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.', true)
->inject('response')
->inject('queue')
->action(function (string $name, int|string $threshold, Response $response, Connection $queue) {
->inject('publisher')
->action(function (string $name, int|string $threshold, Response $response, Publisher $publisher) {
$threshold = \intval($threshold);
$client = new Client($name, $queue);
$failed = $client->countFailedJobs();
$failed = $publisher->getQueueSize(new Queue($name), failedJobs: true);
if ($failed >= $threshold) {
throw new Exception(Exception::HEALTH_QUEUE_SIZE_EXCEEDED, "Queue failed jobs threshold hit. Current size is {$failed} and threshold is {$threshold}.");
+3 -20
View File
@@ -1741,26 +1741,9 @@ App::post('/v1/projects/:projectId/platforms')
]
))
->param('projectId', '', new UID(), 'Project unique ID.')
->param('type', null, new WhiteList([
Origin::CLIENT_TYPE_WEB,
Origin::CLIENT_TYPE_FLUTTER_WEB,
Origin::CLIENT_TYPE_FLUTTER_IOS,
Origin::CLIENT_TYPE_FLUTTER_ANDROID,
Origin::CLIENT_TYPE_FLUTTER_LINUX,
Origin::CLIENT_TYPE_FLUTTER_MACOS,
Origin::CLIENT_TYPE_FLUTTER_WINDOWS,
Origin::CLIENT_TYPE_APPLE_IOS,
Origin::CLIENT_TYPE_APPLE_MACOS,
Origin::CLIENT_TYPE_APPLE_WATCHOS,
Origin::CLIENT_TYPE_APPLE_TVOS,
Origin::CLIENT_TYPE_ANDROID,
Origin::CLIENT_TYPE_UNITY,
Origin::CLIENT_TYPE_REACT_NATIVE_IOS,
Origin::CLIENT_TYPE_REACT_NATIVE_ANDROID,
Origin::CLIENT_TYPE_SCHEME,
], true), 'Platform type.')
->param('type', null, new WhiteList([Origin::CLIENT_TYPE_WEB, Origin::CLIENT_TYPE_FLUTTER_WEB, Origin::CLIENT_TYPE_FLUTTER_IOS, Origin::CLIENT_TYPE_FLUTTER_ANDROID, Origin::CLIENT_TYPE_FLUTTER_LINUX, Origin::CLIENT_TYPE_FLUTTER_MACOS, Origin::CLIENT_TYPE_FLUTTER_WINDOWS, Origin::CLIENT_TYPE_APPLE_IOS, Origin::CLIENT_TYPE_APPLE_MACOS, Origin::CLIENT_TYPE_APPLE_WATCHOS, Origin::CLIENT_TYPE_APPLE_TVOS, Origin::CLIENT_TYPE_ANDROID, Origin::CLIENT_TYPE_UNITY, Origin::CLIENT_TYPE_REACT_NATIVE_IOS, Origin::CLIENT_TYPE_REACT_NATIVE_ANDROID], true), 'Platform type.')
->param('name', null, new Text(128), 'Platform name. Max length: 128 chars.')
->param('key', '', new Text(256), 'Package name for Android or bundle ID for iOS or macOS or app scheme. Max length: 256 chars.', true)
->param('key', '', new Text(256), 'Package name for Android or bundle ID for iOS or macOS. Max length: 256 chars.', true)
->param('store', '', new Text(256), 'App store or Google Play store ID. Max length: 256 chars.', true)
->param('hostname', '', new Hostname(), 'Platform client hostname. Max length: 256 chars.', true)
->inject('response')
@@ -1785,7 +1768,7 @@ App::post('/v1/projects/:projectId/platforms')
'name' => $name,
'key' => $key,
'store' => $store,
'hostname' => $hostname,
'hostname' => $hostname
]);
$platform = $dbForPlatform->createDocument('platforms', $platform);
+52 -6
View File
@@ -52,6 +52,7 @@ use Utopia\Validator\HexColor;
use Utopia\Validator\Range;
use Utopia\Validator\Text;
use Utopia\Validator\WhiteList;
use Utopia\CLI\Console;
App::post('/v1/storage/buckets')
->desc('Create bucket')
@@ -944,17 +945,24 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
->inject('deviceForLocal')
->inject('queueForUsage')
->action(function (string $bucketId, string $fileId, int $width, int $height, string $gravity, int $quality, int $borderWidth, string $borderColor, int $borderRadius, float $opacity, int $rotation, string $background, string $output, Request $request, Response $response, Document $project, Database $dbForProject, string $mode, Device $deviceForFiles, Device $deviceForLocal, Usage $queueForUsage) {
// Start timer
$startTime = microtime(true);
Console::log("Preview generation started for file {$fileId} in bucket {$bucketId}");
if (!\extension_loaded('imagick')) {
Console::log("Imagick extension missing.");
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Imagick extension is missing');
}
// Retrieve bucket and log timing
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
Console::log("Bucket retrieval completed in " . (microtime(true) - $startTime) . " seconds.");
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) {
Console::log("Bucket not found or disabled.");
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
}
@@ -962,6 +970,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
$validator = new Authorization(Database::PERMISSION_READ);
$valid = $validator->isValid($bucket->getRead());
if (!$fileSecurity && !$valid) {
Console::log("Unauthorized access detected (fileSecurity off).");
throw new Exception(Exception::USER_UNAUTHORIZED);
}
@@ -970,8 +979,10 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
} else {
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
}
Console::log("File metadata retrieval completed in " . (microtime(true) - $startTime) . " seconds.");
if ($file->isEmpty()) {
Console::log("File not found.");
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
}
@@ -984,6 +995,8 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
$algorithm = $file->getAttribute('algorithm', Compression::NONE);
$cipher = $file->getAttribute('openSSLCipher');
$mime = $file->getAttribute('mimeType');
// Validate file type and size
if (!\in_array($mime, $inputs) || $file->getAttribute('sizeActual') > (int) System::getEnv('_APP_STORAGE_PREVIEW_LIMIT', 20000000)) {
if (!\in_array($mime, $inputs)) {
$path = (\array_key_exists($mime, $fileLogos)) ? $fileLogos[$mime] : $fileLogos['default'];
@@ -991,6 +1004,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
// it was an image but the file size exceeded the limit
$path = $fileLogos['default_image'];
}
Console::log("File size or mime type exceeds preview limits. Fallback to logo image: {$path}");
$algorithm = Compression::NONE;
$cipher = null;
@@ -1000,24 +1014,24 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
}
if (!$deviceForFiles->exists($path)) {
Console::log("File not found on device: {$path}");
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
}
if (empty($output)) {
// when file extension is provided but it's not one of our
// supported outputs we fallback to `jpg`
if (!empty($type) && !array_key_exists($type, $outputs)) {
$type = 'jpg';
}
// when file extension is not provided and the mime type is not one of our supported outputs
// we fallback to `jpg` output format
$output = empty($type) ? (array_search($mime, $outputs) ?? 'jpg') : $type;
Console::log("Output format determined as: {$output}");
}
// Read source file
$source = $deviceForFiles->read($path);
Console::log("File read from disk in " . (microtime(true) - $startTime) . " seconds.");
if (!empty($cipher)) { // Decrypt
// Decrypt file if needed
if (!empty($cipher)) {
$source = OpenSSL::decrypt(
$source,
$file->getAttribute('openSSLCipher'),
@@ -1026,71 +1040,103 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
\hex2bin($file->getAttribute('openSSLIV')),
\hex2bin($file->getAttribute('openSSLTag'))
);
Console::log("File decryption completed in " . (microtime(true) - $startTime) . " seconds.");
}
// Decompress if needed
switch ($algorithm) {
case Compression::ZSTD:
$compressor = new Zstd();
$source = $compressor->decompress($source);
Console::log("ZSTD decompression completed.");
break;
case Compression::GZIP:
$compressor = new GZIP();
$source = $compressor->decompress($source);
Console::log("GZIP decompression completed.");
break;
}
// Create image object and perform transformations
try {
$image = new Image($source);
Console::log("Image object created successfully.");
} catch (ImagickException $e) {
Console::log("Error creating image object: " . $e->getMessage());
throw new Exception(Exception::STORAGE_FILE_TYPE_UNSUPPORTED, $e->getMessage());
}
// Crop image
$image->crop((int) $width, (int) $height, $gravity);
Console::log("Image cropped to {$width}x{$height} using gravity {$gravity}.");
// Apply opacity if set
if (!empty($opacity) || $opacity === 0) {
$image->setOpacity($opacity);
Console::log("Opacity set to {$opacity}.");
}
// Set background if provided
if (!empty($background)) {
$image->setBackground('#' . $background);
Console::log("Background color set to #{$background}.");
}
// Apply border if needed
if (!empty($borderWidth)) {
$image->setBorder($borderWidth, '#' . $borderColor);
Console::log("Border set with width {$borderWidth} and color #{$borderColor}.");
}
// Apply border radius if needed
if (!empty($borderRadius)) {
$image->setBorderRadius($borderRadius);
Console::log("Border radius set to {$borderRadius}.");
}
// Rotate image if needed
if (!empty($rotation)) {
$image->setRotation(($rotation + 360) % 360);
Console::log("Image rotated by {$rotation} degrees.");
}
// Output final image data
$data = $image->output($output, $quality);
Console::log("Image output generated in format {$output} with quality {$quality}.");
$contentType = (\array_key_exists($output, $outputs)) ? $outputs[$output] : $outputs['jpg'];
// Record metrics
$queueForUsage
->addMetric(METRIC_FILES_TRANSFORMATIONS, 1)
->addMetric(str_replace('{bucketInternalId}', $bucket->getInternalId(), METRIC_BUCKET_ID_FILES_TRANSFORMATIONS), 1)
;
Console::log("Usage metrics recorded.");
// Update transformedAt attribute if needed
$transformedAt = $file->getAttribute('transformedAt', '');
if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_PROJECT_ACCESS)) > $transformedAt) {
$file->setAttribute('transformedAt', DateTime::now());
Authorization::skip(fn () => $dbForProject->updateDocument('bucket_' . $file->getAttribute('bucketInternalId'), $file->getId(), $file));
Console::log("File transformation timestamp updated.");
}
// Final response
$response
->addHeader('Cache-Control', 'private, max-age=2592000') // 30 days
->setContentType($contentType)
->file($data)
;
Console::log("Response sent with content type {$contentType}.");
// Log total processing time
$totalTime = microtime(true) - $startTime;
Console::log("Preview generation completed in {$totalTime} seconds.");
unset($image);
});
App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
->alias('/v1/storage/files/:fileId/download')
->desc('Get file for download')
+3 -5
View File
@@ -469,12 +469,12 @@ App::post('/v1/teams/:teamId/memberships')
->inject('queueForUsage')
->inject('plan')
->action(function (string $teamId, string $email, string $userId, string $phone, array $roles, string $url, string $name, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Mail $queueForMails, Messaging $queueForMessaging, Event $queueForEvents, callable $timelimit, Usage $queueForUsage, array $plan) {
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
$isAppUser = Auth::isAppUser(Authorization::getRoles());
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
$url = htmlentities($url);
if (empty($url)) {
if (!$isAPIKey && !$isPrivilegedUser) {
if (!$isAppUser && !$isPrivilegedUser) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'URL is required');
}
}
@@ -482,8 +482,6 @@ App::post('/v1/teams/:teamId/memberships')
if (empty($userId) && empty($email) && empty($phone)) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'At least one of userId, email, or phone is required');
}
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
$isAppUser = Auth::isAppUser(Authorization::getRoles());
if (!$isPrivilegedUser && !$isAppUser && empty(System::getEnv('_APP_SMTP_HOST'))) {
throw new Exception(Exception::GENERAL_SMTP_DISABLED);
@@ -638,7 +636,7 @@ App::post('/v1/teams/:teamId/memberships')
$dbForProject->purgeCachedDocument('users', $invitee->getId());
} else {
$url = Template::parseURL($url);
$url['query'] = Template::mergeQuery(((isset($url['query'])) ? $url['query'] : ''), ['membershipId' => $membership->getId(), 'userId' => $invitee->getId(), 'secret' => $secret, 'teamId' => $teamId]);
$url['query'] = Template::mergeQuery(((isset($url['query'])) ? $url['query'] : ''), ['membershipId' => $membership->getId(), 'userId' => $invitee->getId(), 'secret' => $secret, 'teamId' => $teamId, 'teamName' => $team->getAttribute('name')]);
$url = Template::unParseURL($url);
if (!empty($email)) {
$projectName = $project->isEmpty() ? 'Console' : $project->getAttribute('name', '[APP-NAME]');
+6 -6
View File
@@ -28,7 +28,7 @@ use Utopia\Database\DateTime;
use Utopia\Database\Document;
use Utopia\Database\Helpers\Role;
use Utopia\Database\Validator\Authorization;
use Utopia\Queue\Connection;
use Utopia\Queue\Publisher;
use Utopia\System\System;
use Utopia\Validator\WhiteList;
@@ -429,7 +429,7 @@ App::init()
->inject('response')
->inject('project')
->inject('user')
->inject('queue')
->inject('publisher')
->inject('queueForEvents')
->inject('queueForMessaging')
->inject('queueForAudits')
@@ -440,7 +440,7 @@ App::init()
->inject('dbForProject')
->inject('timelimit')
->inject('mode')
->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Connection $queue, Event $queueForEvents, Messaging $queueForMessaging, Audit $queueForAudits, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, Usage $queueForUsage, Database $dbForProject, callable $timelimit, string $mode) use ($usageDatabaseListener, $eventDatabaseListener) {
->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Publisher $publisher, Event $queueForEvents, Messaging $queueForMessaging, Audit $queueForAudits, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, Usage $queueForUsage, Database $dbForProject, callable $timelimit, string $mode) use ($usageDatabaseListener, $eventDatabaseListener) {
$route = $utopia->getRoute();
@@ -544,9 +544,9 @@ App::init()
// Clone the queues, to prevent events triggered by the database listener
// from overwriting the events that are supposed to be triggered in the shutdown hook.
$queueForEventsClone = new Event($queue);
$queueForFunctions = new Func($queue);
$queueForWebhooks = new Webhook($queue);
$queueForEventsClone = new Event($publisher);
$queueForFunctions = new Func($publisher);
$queueForWebhooks = new Webhook($publisher);
$queueForRealtime = new Realtime();
$dbForProject
+56 -59
View File
@@ -77,7 +77,6 @@ use Utopia\Logger\Logger;
use Utopia\Pools\Group;
use Utopia\Pools\Pool;
use Utopia\Queue;
use Utopia\Queue\Connection;
use Utopia\Registry\Registry;
use Utopia\Storage\Device;
use Utopia\Storage\Device\Backblaze;
@@ -890,8 +889,14 @@ $register->set('pools', function () {
'multiple' => false,
'schemes' => ['mariadb', 'mysql'],
],
'queue' => [
'type' => 'queue',
'publisher' => [
'type' => 'publisher',
'dsns' => $fallbackForRedis,
'multiple' => false,
'schemes' => ['redis'],
],
'consumer' => [
'type' => 'consumer',
'dsns' => $fallbackForRedis,
'multiple' => false,
'schemes' => ['redis'],
@@ -999,31 +1004,26 @@ $register->set('pools', function () {
};
$adapter->setDatabase($dsn->getPath());
break;
return $adapter;
case 'pubsub':
$adapter = match ($dsn->getScheme()) {
return match ($dsn->getScheme()) {
'redis' => new PubSub($resource()),
default => null
};
break;
case 'queue':
$adapter = match ($dsn->getScheme()) {
'redis' => new Queue\Connection\Redis($dsn->getHost(), $dsn->getPort()),
case 'publisher':
case 'consumer':
return match ($dsn->getScheme()) {
'redis' => new Queue\Broker\Redis(new Queue\Connection\Redis($dsn->getHost(), $dsn->getPort())),
default => null
};
break;
case 'cache':
$adapter = match ($dsn->getScheme()) {
return match ($dsn->getScheme()) {
'redis' => new RedisCache($resource()),
default => null
};
break;
default:
throw new Exception(Exception::GENERAL_SERVER_ERROR, "Server error: Missing adapter implementation.");
}
return $adapter;
});
$group->add($pool);
@@ -1146,48 +1146,51 @@ App::setResource('localeCodes', function () {
});
// Queues
App::setResource('queue', function (Group $pools) {
return $pools->get('queue')->pop()->getResource();
App::setResource('publisher', function (Group $pools) {
return $pools->get('publisher')->pop()->getResource();
}, ['pools']);
App::setResource('queueForMessaging', function (Connection $queue) {
return new Messaging($queue);
}, ['queue']);
App::setResource('queueForMails', function (Connection $queue) {
return new Mail($queue);
}, ['queue']);
App::setResource('queueForBuilds', function (Connection $queue) {
return new Build($queue);
}, ['queue']);
App::setResource('queueForDatabase', function (Connection $queue) {
return new EventDatabase($queue);
}, ['queue']);
App::setResource('queueForDeletes', function (Connection $queue) {
return new Delete($queue);
}, ['queue']);
App::setResource('queueForEvents', function (Connection $queue) {
return new Event($queue);
}, ['queue']);
App::setResource('queueForWebhooks', function (Connection $queue) {
return new Webhook($queue);
}, ['queue']);
App::setResource('consumer', function (Group $pools) {
return $pools->get('consumer')->pop()->getResource();
}, ['pools']);
App::setResource('queueForMessaging', function (Queue\Publisher $publisher) {
return new Messaging($publisher);
}, ['publisher']);
App::setResource('queueForMails', function (Queue\Publisher $publisher) {
return new Mail($publisher);
}, ['publisher']);
App::setResource('queueForBuilds', function (Queue\Publisher $publisher) {
return new Build($publisher);
}, ['publisher']);
App::setResource('queueForDatabase', function (Queue\Publisher $publisher) {
return new EventDatabase($publisher);
}, ['publisher']);
App::setResource('queueForDeletes', function (Queue\Publisher $publisher) {
return new Delete($publisher);
}, ['publisher']);
App::setResource('queueForEvents', function (Queue\Publisher $publisher) {
return new Event($publisher);
}, ['publisher']);
App::setResource('queueForWebhooks', function (Queue\Publisher $publisher) {
return new Webhook($publisher);
}, ['publisher']);
App::setResource('queueForRealtime', function () {
return new Realtime();
}, []);
App::setResource('queueForAudits', function (Connection $queue) {
return new Audit($queue);
}, ['queue']);
App::setResource('queueForFunctions', function (Connection $queue) {
return new Func($queue);
}, ['queue']);
App::setResource('queueForUsage', function (Connection $queue) {
return new Usage($queue);
}, ['queue']);
App::setResource('queueForCertificates', function (Connection $queue) {
return new Certificate($queue);
}, ['queue']);
App::setResource('queueForMigrations', function (Connection $queue) {
return new Migration($queue);
}, ['queue']);
App::setResource('queueForAudits', function (Queue\Publisher $publisher) {
return new Audit($publisher);
}, ['publisher']);
App::setResource('queueForFunctions', function (Queue\Publisher $publisher) {
return new Func($publisher);
}, ['publisher']);
App::setResource('queueForUsage', function (Queue\Publisher $publisher) {
return new Usage($publisher);
}, ['publisher']);
App::setResource('queueForCertificates', function (Queue\Publisher $publisher) {
return new Certificate($publisher);
}, ['publisher']);
App::setResource('queueForMigrations', function (Queue\Publisher $publisher) {
return new Migration($publisher);
}, ['publisher']);
App::setResource('platforms', function (Document $project, Document $console) {
return [
...$project->getAttribute('platforms', []),
@@ -1226,12 +1229,6 @@ App::setResource('schemes', function (array $platforms, Document $project) {
$schemes[] = 'appwrite-callback-' . $project->getId();
}
foreach ($platforms as $platform) {
if (!empty($platform['key']) && $platform['type'] === Origin::CLIENT_TYPE_SCHEME) {
$schemes[] = $platform['key'];
}
}
return \array_unique($schemes);
}, ['platforms', 'project']);
App::setResource('user', function ($mode, $project, $console, $request, $response, $dbForProject, $dbForPlatform) {
+46 -42
View File
@@ -31,8 +31,8 @@ use Utopia\Logger\Log;
use Utopia\Logger\Logger;
use Utopia\Platform\Service;
use Utopia\Pools\Group;
use Utopia\Queue\Connection;
use Utopia\Queue\Message;
use Utopia\Queue\Publisher;
use Utopia\Queue\Server;
use Utopia\Registry\Registry;
use Utopia\System\System;
@@ -224,57 +224,61 @@ Server::setResource('timelimit', function (\Redis $redis) {
Server::setResource('log', fn () => new Log());
Server::setResource('queueForUsage', function (Connection $queue) {
return new Usage($queue);
}, ['queue']);
Server::setResource('queueForUsageDump', function (Connection $queue) {
return new UsageDump($queue);
}, ['queue']);
Server::setResource('queue', function (Group $pools) {
return $pools->get('queue')->pop()->getResource();
Server::setResource('publisher', function (Group $pools) {
return $pools->get('publisher')->pop()->getResource();
}, ['pools']);
Server::setResource('queueForDatabase', function (Connection $queue) {
return new EventDatabase($queue);
}, ['queue']);
Server::setResource('consumer', function (Group $pools) {
return $pools->get('consumer')->pop()->getResource();
}, ['pools']);
Server::setResource('queueForMessaging', function (Connection $queue) {
return new Messaging($queue);
}, ['queue']);
Server::setResource('queueForUsage', function (Publisher $publisher) {
return new Usage($publisher);
}, ['publisher']);
Server::setResource('queueForMails', function (Connection $queue) {
return new Mail($queue);
}, ['queue']);
Server::setResource('queueForUsageDump', function (Publisher $publisher) {
return new UsageDump($publisher);
}, ['publisher']);
Server::setResource('queueForBuilds', function (Connection $queue) {
return new Build($queue);
}, ['queue']);
Server::setResource('queueForDatabase', function (Publisher $publisher) {
return new EventDatabase($publisher);
}, ['publisher']);
Server::setResource('queueForDeletes', function (Connection $queue) {
return new Delete($queue);
}, ['queue']);
Server::setResource('queueForMessaging', function (Publisher $publisher) {
return new Messaging($publisher);
}, ['publisher']);
Server::setResource('queueForEvents', function (Connection $queue) {
return new Event($queue);
}, ['queue']);
Server::setResource('queueForMails', function (Publisher $publisher) {
return new Mail($publisher);
}, ['publisher']);
Server::setResource('queueForAudits', function (Connection $queue) {
return new Audit($queue);
}, ['queue']);
Server::setResource('queueForBuilds', function (Publisher $publisher) {
return new Build($publisher);
}, ['publisher']);
Server::setResource('queueForFunctions', function (Connection $queue) {
return new Func($queue);
}, ['queue']);
Server::setResource('queueForDeletes', function (Publisher $publisher) {
return new Delete($publisher);
}, ['publisher']);
Server::setResource('queueForCertificates', function (Connection $queue) {
return new Certificate($queue);
}, ['queue']);
Server::setResource('queueForEvents', function (Publisher $publisher) {
return new Event($publisher);
}, ['publisher']);
Server::setResource('queueForMigrations', function (Connection $queue) {
return new Migration($queue);
}, ['queue']);
Server::setResource('queueForAudits', function (Publisher $publisher) {
return new Audit($publisher);
}, ['publisher']);
Server::setResource('queueForFunctions', function (Publisher $publisher) {
return new Func($publisher);
}, ['publisher']);
Server::setResource('queueForCertificates', function (Publisher $publisher) {
return new Certificate($publisher);
}, ['publisher']);
Server::setResource('queueForMigrations', function (Publisher $publisher) {
return new Migration($publisher);
}, ['publisher']);
Server::setResource('logger', function (Registry $register) {
return $register->get('logger');
@@ -386,7 +390,7 @@ try {
*/
$platform->init(Service::TYPE_WORKER, [
'workersNum' => System::getEnv('_APP_WORKERS_NUM', 1),
'connection' => $pools->get('queue')->pop()->getResource(),
'connection' => $pools->get('consumer')->pop()->getResource(),
'workerName' => strtolower($workerName) ?? null,
'queueName' => $queueName
]);
+5 -5
View File
@@ -45,13 +45,13 @@
"ext-sockets": "*",
"appwrite/php-runtimes": "0.16.*",
"appwrite/php-clamav": "2.0.*",
"utopia-php/abuse": "0.47.*",
"utopia-php/abuse": "0.49.*",
"utopia-php/analytics": "0.10.*",
"utopia-php/audit": "0.47.*",
"utopia-php/audit": "0.49.*",
"utopia-php/cache": "0.11.*",
"utopia-php/cli": "0.15.*",
"utopia-php/config": "0.2.*",
"utopia-php/database": "0.56.4",
"utopia-php/database": "0.58.4",
"utopia-php/domains": "0.5.*",
"utopia-php/dsn": "0.2.1",
"utopia-php/framework": "0.33.*",
@@ -62,10 +62,10 @@
"utopia-php/messaging": "0.14.*",
"utopia-php/migration": "0.6.*",
"utopia-php/orchestration": "0.9.*",
"utopia-php/platform": "0.7.1",
"utopia-php/platform": "0.7.3",
"utopia-php/pools": "0.5.*",
"utopia-php/preloader": "0.2.*",
"utopia-php/queue": "0.7.*",
"utopia-php/queue": "0.8.*",
"utopia-php/registry": "0.5.*",
"utopia-php/storage": "0.18.*",
"utopia-php/swoole": "0.8.*",
Generated
+324 -80
View File
@@ -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": "e8d26e7e836db255ba42cf55c3798c97",
"content-hash": "232691925e05350c7a3831a4e43d79d1",
"packages": [
{
"name": "adhocore/jwt",
@@ -1237,16 +1237,16 @@
},
{
"name": "open-telemetry/api",
"version": "1.2.1",
"version": "1.2.2",
"source": {
"type": "git",
"url": "https://github.com/opentelemetry-php/api.git",
"reference": "74b1a03263be8c5acb578f41da054b4bac3af4a0"
"reference": "8b925df3047628968bc5be722468db1b98b82d51"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/opentelemetry-php/api/zipball/74b1a03263be8c5acb578f41da054b4bac3af4a0",
"reference": "74b1a03263be8c5acb578f41da054b4bac3af4a0",
"url": "https://api.github.com/repos/opentelemetry-php/api/zipball/8b925df3047628968bc5be722468db1b98b82d51",
"reference": "8b925df3047628968bc5be722468db1b98b82d51",
"shasum": ""
},
"require": {
@@ -1303,7 +1303,7 @@
"issues": "https://github.com/open-telemetry/opentelemetry-php/issues",
"source": "https://github.com/open-telemetry/opentelemetry-php"
},
"time": "2025-01-20T23:35:16+00:00"
"time": "2025-02-03T21:49:11+00:00"
},
{
"name": "open-telemetry/context",
@@ -1493,16 +1493,16 @@
},
{
"name": "open-telemetry/sdk",
"version": "1.2.1",
"version": "1.2.2",
"source": {
"type": "git",
"url": "https://github.com/opentelemetry-php/sdk.git",
"reference": "96aeaee5b7cb8c0bc4af7ff4717b429f2d9f67e1"
"reference": "37eec0fe47ddd627911f318f29b6cd48196be0c0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/opentelemetry-php/sdk/zipball/96aeaee5b7cb8c0bc4af7ff4717b429f2d9f67e1",
"reference": "96aeaee5b7cb8c0bc4af7ff4717b429f2d9f67e1",
"url": "https://api.github.com/repos/opentelemetry-php/sdk/zipball/37eec0fe47ddd627911f318f29b6cd48196be0c0",
"reference": "37eec0fe47ddd627911f318f29b6cd48196be0c0",
"shasum": ""
},
"require": {
@@ -1579,24 +1579,24 @@
"issues": "https://github.com/open-telemetry/opentelemetry-php/issues",
"source": "https://github.com/open-telemetry/opentelemetry-php"
},
"time": "2025-01-09T23:17:14+00:00"
"time": "2025-01-29T21:40:28+00:00"
},
{
"name": "open-telemetry/sem-conv",
"version": "1.27.1",
"version": "1.30.0",
"source": {
"type": "git",
"url": "https://github.com/opentelemetry-php/sem-conv.git",
"reference": "1dba705fea74bc0718d04be26090e3697e56f4e6"
"reference": "4178c9f390da8e4dbca9b181a9d1efd50cf7ee0a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/opentelemetry-php/sem-conv/zipball/1dba705fea74bc0718d04be26090e3697e56f4e6",
"reference": "1dba705fea74bc0718d04be26090e3697e56f4e6",
"url": "https://api.github.com/repos/opentelemetry-php/sem-conv/zipball/4178c9f390da8e4dbca9b181a9d1efd50cf7ee0a",
"reference": "4178c9f390da8e4dbca9b181a9d1efd50cf7ee0a",
"shasum": ""
},
"require": {
"php": "^8.1"
"php": "^8.0"
},
"type": "library",
"extra": {
@@ -1636,7 +1636,7 @@
"issues": "https://github.com/open-telemetry/opentelemetry-php/issues",
"source": "https://github.com/open-telemetry/opentelemetry-php"
},
"time": "2024-08-28T09:20:31+00:00"
"time": "2025-02-06T00:21:48+00:00"
},
{
"name": "paragonie/constant_time_encoding",
@@ -1705,6 +1705,137 @@
},
"time": "2024-05-08T12:18:48+00:00"
},
{
"name": "paragonie/random_compat",
"version": "v9.99.100",
"source": {
"type": "git",
"url": "https://github.com/paragonie/random_compat.git",
"reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a",
"reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a",
"shasum": ""
},
"require": {
"php": ">= 7"
},
"require-dev": {
"phpunit/phpunit": "4.*|5.*",
"vimeo/psalm": "^1"
},
"suggest": {
"ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
},
"type": "library",
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Paragon Initiative Enterprises",
"email": "security@paragonie.com",
"homepage": "https://paragonie.com"
}
],
"description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
"keywords": [
"csprng",
"polyfill",
"pseudorandom",
"random"
],
"support": {
"email": "info@paragonie.com",
"issues": "https://github.com/paragonie/random_compat/issues",
"source": "https://github.com/paragonie/random_compat"
},
"time": "2020-10-15T08:29:30+00:00"
},
{
"name": "php-amqplib/php-amqplib",
"version": "v3.7.2",
"source": {
"type": "git",
"url": "https://github.com/php-amqplib/php-amqplib.git",
"reference": "738a73eb0019b6c99d9bc25d7a0c0dd8f56a5199"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-amqplib/php-amqplib/zipball/738a73eb0019b6c99d9bc25d7a0c0dd8f56a5199",
"reference": "738a73eb0019b6c99d9bc25d7a0c0dd8f56a5199",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"ext-sockets": "*",
"php": "^7.2||^8.0",
"phpseclib/phpseclib": "^2.0|^3.0"
},
"conflict": {
"php": "7.4.0 - 7.4.1"
},
"replace": {
"videlalvaro/php-amqplib": "self.version"
},
"require-dev": {
"ext-curl": "*",
"nategood/httpful": "^0.2.20",
"phpunit/phpunit": "^7.5|^9.5",
"squizlabs/php_codesniffer": "^3.6"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.0-dev"
}
},
"autoload": {
"psr-4": {
"PhpAmqpLib\\": "PhpAmqpLib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-2.1-or-later"
],
"authors": [
{
"name": "Alvaro Videla",
"role": "Original Maintainer"
},
{
"name": "Raúl Araya",
"email": "nubeiro@gmail.com",
"role": "Maintainer"
},
{
"name": "Luke Bakken",
"email": "luke@bakken.io",
"role": "Maintainer"
},
{
"name": "Ramūnas Dronga",
"email": "github@ramuno.lt",
"role": "Maintainer"
}
],
"description": "Formerly videlalvaro/php-amqplib. This library is a pure PHP implementation of the AMQP protocol. It's been tested against RabbitMQ.",
"homepage": "https://github.com/php-amqplib/php-amqplib/",
"keywords": [
"message",
"queue",
"rabbitmq"
],
"support": {
"issues": "https://github.com/php-amqplib/php-amqplib/issues",
"source": "https://github.com/php-amqplib/php-amqplib/tree/v3.7.2"
},
"time": "2024-11-21T09:21:41+00:00"
},
{
"name": "php-http/discovery",
"version": "1.20.0",
@@ -1865,6 +1996,116 @@
],
"time": "2023-11-25T22:23:28+00:00"
},
{
"name": "phpseclib/phpseclib",
"version": "3.0.43",
"source": {
"type": "git",
"url": "https://github.com/phpseclib/phpseclib.git",
"reference": "709ec107af3cb2f385b9617be72af8cf62441d02"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/709ec107af3cb2f385b9617be72af8cf62441d02",
"reference": "709ec107af3cb2f385b9617be72af8cf62441d02",
"shasum": ""
},
"require": {
"paragonie/constant_time_encoding": "^1|^2|^3",
"paragonie/random_compat": "^1.4|^2.0|^9.99.99",
"php": ">=5.6.1"
},
"require-dev": {
"phpunit/phpunit": "*"
},
"suggest": {
"ext-dom": "Install the DOM extension to load XML formatted public keys.",
"ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.",
"ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.",
"ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.",
"ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations."
},
"type": "library",
"autoload": {
"files": [
"phpseclib/bootstrap.php"
],
"psr-4": {
"phpseclib3\\": "phpseclib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jim Wigginton",
"email": "terrafrost@php.net",
"role": "Lead Developer"
},
{
"name": "Patrick Monnerat",
"email": "pm@datasphere.ch",
"role": "Developer"
},
{
"name": "Andreas Fischer",
"email": "bantu@phpbb.com",
"role": "Developer"
},
{
"name": "Hans-Jürgen Petrich",
"email": "petrich@tronic-media.com",
"role": "Developer"
},
{
"name": "Graham Campbell",
"email": "graham@alt-three.com",
"role": "Developer"
}
],
"description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.",
"homepage": "http://phpseclib.sourceforge.net",
"keywords": [
"BigInteger",
"aes",
"asn.1",
"asn1",
"blowfish",
"crypto",
"cryptography",
"encryption",
"rsa",
"security",
"sftp",
"signature",
"signing",
"ssh",
"twofish",
"x.509",
"x509"
],
"support": {
"issues": "https://github.com/phpseclib/phpseclib/issues",
"source": "https://github.com/phpseclib/phpseclib/tree/3.0.43"
},
"funding": [
{
"url": "https://github.com/terrafrost",
"type": "github"
},
{
"url": "https://www.patreon.com/phpseclib",
"type": "patreon"
},
{
"url": "https://tidelift.com/funding/github/packagist/phpseclib/phpseclib",
"type": "tidelift"
}
],
"time": "2024-12-14T21:12:59+00:00"
},
{
"name": "psr/container",
"version": "2.0.2",
@@ -2453,16 +2694,16 @@
},
{
"name": "symfony/http-client",
"version": "v7.2.2",
"version": "v7.2.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-client.git",
"reference": "339ba21476eb184290361542f732ad12c97591ec"
"reference": "7ce6078c79a4a7afff931c413d2959d3bffbfb8d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-client/zipball/339ba21476eb184290361542f732ad12c97591ec",
"reference": "339ba21476eb184290361542f732ad12c97591ec",
"url": "https://api.github.com/repos/symfony/http-client/zipball/7ce6078c79a4a7afff931c413d2959d3bffbfb8d",
"reference": "7ce6078c79a4a7afff931c413d2959d3bffbfb8d",
"shasum": ""
},
"require": {
@@ -2528,7 +2769,7 @@
"http"
],
"support": {
"source": "https://github.com/symfony/http-client/tree/v7.2.2"
"source": "https://github.com/symfony/http-client/tree/v7.2.3"
},
"funding": [
{
@@ -2544,7 +2785,7 @@
"type": "tidelift"
}
],
"time": "2024-12-30T18:35:15+00:00"
"time": "2025-01-28T15:51:35+00:00"
},
{
"name": "symfony/http-client-contracts",
@@ -3136,16 +3377,16 @@
},
{
"name": "utopia-php/abuse",
"version": "0.47.0",
"version": "0.49.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/abuse.git",
"reference": "2b52bb362234d4072b647ed57db1b3be030f57c2"
"reference": "76612c274b895aa3d4d1fa27557a6402463eea99"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/2b52bb362234d4072b647ed57db1b3be030f57c2",
"reference": "2b52bb362234d4072b647ed57db1b3be030f57c2",
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/76612c274b895aa3d4d1fa27557a6402463eea99",
"reference": "76612c274b895aa3d4d1fa27557a6402463eea99",
"shasum": ""
},
"require": {
@@ -3153,13 +3394,13 @@
"ext-pdo": "*",
"ext-redis": "*",
"php": ">=8.0",
"utopia-php/database": "0.56.*"
"utopia-php/database": "0.58.*"
},
"require-dev": {
"laravel/pint": "1.5.*",
"phpbench/phpbench": "^1.2",
"phpstan/phpstan": "^1.9",
"phpunit/phpunit": "^9.4"
"laravel/pint": "1.*",
"phpbench/phpbench": "1.*",
"phpstan/phpstan": "1.*",
"phpunit/phpunit": "9.*"
},
"type": "library",
"autoload": {
@@ -3181,9 +3422,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/abuse/issues",
"source": "https://github.com/utopia-php/abuse/tree/0.47.0"
"source": "https://github.com/utopia-php/abuse/tree/0.49.0"
},
"time": "2025-01-15T02:41:02+00:00"
"time": "2025-02-04T07:33:59+00:00"
},
{
"name": "utopia-php/analytics",
@@ -3233,26 +3474,26 @@
},
{
"name": "utopia-php/audit",
"version": "0.47.0",
"version": "0.49.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/audit.git",
"reference": "1ebd5784ba68645073426f2f04a67726a1bde4d7"
"reference": "9d5c5e0cf0f6d9157b911fc3971da4331d71c96d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/audit/zipball/1ebd5784ba68645073426f2f04a67726a1bde4d7",
"reference": "1ebd5784ba68645073426f2f04a67726a1bde4d7",
"url": "https://api.github.com/repos/utopia-php/audit/zipball/9d5c5e0cf0f6d9157b911fc3971da4331d71c96d",
"reference": "9d5c5e0cf0f6d9157b911fc3971da4331d71c96d",
"shasum": ""
},
"require": {
"php": ">=8.0",
"utopia-php/database": "0.56.*"
"utopia-php/database": "0.58.*"
},
"require-dev": {
"laravel/pint": "1.5.*",
"phpstan/phpstan": "^1.8",
"phpunit/phpunit": "^9.3"
"laravel/pint": "1.*",
"phpstan/phpstan": "1.*",
"phpunit/phpunit": "9.*"
},
"type": "library",
"autoload": {
@@ -3274,9 +3515,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/audit/issues",
"source": "https://github.com/utopia-php/audit/tree/0.47.0"
"source": "https://github.com/utopia-php/audit/tree/0.49.0"
},
"time": "2025-01-15T02:40:53+00:00"
"time": "2025-02-04T07:27:18+00:00"
},
{
"name": "utopia-php/cache",
@@ -3476,22 +3717,22 @@
},
{
"name": "utopia-php/database",
"version": "0.56.4",
"version": "0.58.4",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/database.git",
"reference": "240478a60797124a885ceac40046fe47c22415b7"
"reference": "ff3fd22e4fe757cc2a78f17169f6dcc45c96d0fe"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/database/zipball/240478a60797124a885ceac40046fe47c22415b7",
"reference": "240478a60797124a885ceac40046fe47c22415b7",
"url": "https://api.github.com/repos/utopia-php/database/zipball/ff3fd22e4fe757cc2a78f17169f6dcc45c96d0fe",
"reference": "ff3fd22e4fe757cc2a78f17169f6dcc45c96d0fe",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"ext-pdo": "*",
"php": ">=8.3",
"php": ">=8.1",
"utopia-php/cache": "0.11.*",
"utopia-php/framework": "0.33.*",
"utopia-php/mongo": "0.3.*"
@@ -3526,9 +3767,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/database/issues",
"source": "https://github.com/utopia-php/database/tree/0.56.4"
"source": "https://github.com/utopia-php/database/tree/0.58.4"
},
"time": "2025-01-20T09:22:08+00:00"
"time": "2025-02-05T02:51:02+00:00"
},
{
"name": "utopia-php/domains",
@@ -3929,35 +4170,35 @@
},
{
"name": "utopia-php/migration",
"version": "0.6.15",
"version": "0.6.17",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/migration.git",
"reference": "e849ec3e7ad38f5f5273ebb0132b112639cdf01c"
"reference": "677a5c4688d7f54d1631a91f76a35d51346cf96b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/migration/zipball/e849ec3e7ad38f5f5273ebb0132b112639cdf01c",
"reference": "e849ec3e7ad38f5f5273ebb0132b112639cdf01c",
"url": "https://api.github.com/repos/utopia-php/migration/zipball/677a5c4688d7f54d1631a91f76a35d51346cf96b",
"reference": "677a5c4688d7f54d1631a91f76a35d51346cf96b",
"shasum": ""
},
"require": {
"appwrite/appwrite": "11.1.*",
"appwrite/appwrite": "11.*",
"ext-curl": "*",
"ext-openssl": "*",
"php": "8.3.*",
"utopia-php/database": "0.56.*",
"php": ">=8.1",
"utopia-php/database": "0.58.*",
"utopia-php/dsn": "0.2.*",
"utopia-php/framework": "0.33.*",
"utopia-php/storage": "0.18.*"
},
"require-dev": {
"ext-pdo": "*",
"laravel/pint": "1.17.*",
"phpstan/phpstan": "1.11.*",
"phpunit/phpunit": "11.2.*",
"laravel/pint": "1.*",
"phpstan/phpstan": "1.*",
"phpunit/phpunit": "11.*",
"utopia-php/cli": "0.16.*",
"vlucas/phpdotenv": "5.6.*"
"vlucas/phpdotenv": "5.*"
},
"type": "library",
"autoload": {
@@ -3979,9 +4220,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/migration/issues",
"source": "https://github.com/utopia-php/migration/tree/0.6.15"
"source": "https://github.com/utopia-php/migration/tree/0.6.17"
},
"time": "2025-01-15T04:55:08+00:00"
"time": "2025-02-05T05:27:29+00:00"
},
{
"name": "utopia-php/mongo",
@@ -4095,16 +4336,16 @@
},
{
"name": "utopia-php/platform",
"version": "0.7.1",
"version": "0.7.3",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/platform.git",
"reference": "3433a0f1a54988f2a59c735f507745cb2c24638a"
"reference": "463c2d817c893d7dbb678c2eac7a8291f2710e25"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/platform/zipball/3433a0f1a54988f2a59c735f507745cb2c24638a",
"reference": "3433a0f1a54988f2a59c735f507745cb2c24638a",
"url": "https://api.github.com/repos/utopia-php/platform/zipball/463c2d817c893d7dbb678c2eac7a8291f2710e25",
"reference": "463c2d817c893d7dbb678c2eac7a8291f2710e25",
"shasum": ""
},
"require": {
@@ -4113,7 +4354,7 @@
"php": ">=8.0",
"utopia-php/cli": "0.15.*",
"utopia-php/framework": "0.33.*",
"utopia-php/queue": "0.7.*"
"utopia-php/queue": "0.8.*"
},
"require-dev": {
"laravel/pint": "1.2.*",
@@ -4139,9 +4380,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/platform/issues",
"source": "https://github.com/utopia-php/platform/tree/0.7.1"
"source": "https://github.com/utopia-php/platform/tree/0.7.3"
},
"time": "2024-10-22T10:27:49+00:00"
"time": "2025-02-04T15:09:00+00:00"
},
{
"name": "utopia-php/pools",
@@ -4249,25 +4490,28 @@
},
{
"name": "utopia-php/queue",
"version": "0.7.3",
"version": "0.8.2",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/queue.git",
"reference": "16074a98ee7d6212bc1228de200e13db470c098a"
"reference": "a6ec26a787e8292ca2d7b8f5a0ad179b46b2c4d0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/queue/zipball/16074a98ee7d6212bc1228de200e13db470c098a",
"reference": "16074a98ee7d6212bc1228de200e13db470c098a",
"url": "https://api.github.com/repos/utopia-php/queue/zipball/a6ec26a787e8292ca2d7b8f5a0ad179b46b2c4d0",
"reference": "a6ec26a787e8292ca2d7b8f5a0ad179b46b2c4d0",
"shasum": ""
},
"require": {
"php": ">=8.1",
"php": ">=8.3",
"php-amqplib/php-amqplib": "^3.7",
"utopia-php/cli": "0.15.*",
"utopia-php/framework": "0.*.*",
"utopia-php/fetch": "^0.3.0",
"utopia-php/framework": "0.33.*",
"utopia-php/telemetry": "0.1.*"
},
"require-dev": {
"ext-redis": "*",
"laravel/pint": "^0.2.3",
"phpstan/phpstan": "^1.8",
"phpunit/phpunit": "^9.5.5",
@@ -4305,9 +4549,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/queue/issues",
"source": "https://github.com/utopia-php/queue/tree/0.7.3"
"source": "https://github.com/utopia-php/queue/tree/0.8.2"
},
"time": "2024-11-13T12:47:48+00:00"
"time": "2025-02-06T11:01:15+00:00"
},
{
"name": "utopia-php/registry",
@@ -8503,7 +8747,7 @@
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {},
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
+3 -3
View File
@@ -2,7 +2,7 @@
namespace Appwrite\Event;
use Utopia\Queue\Connection;
use Utopia\Queue\Publisher;
class Audit extends Event
{
@@ -12,9 +12,9 @@ class Audit extends Event
protected string $ip = '';
protected string $hostname = '';
public function __construct(protected Connection $connection)
public function __construct(protected Publisher $publisher)
{
parent::__construct($connection);
parent::__construct($publisher);
$this
->setQueue(Event::AUDITS_QUEUE_NAME)
+3 -3
View File
@@ -3,7 +3,7 @@
namespace Appwrite\Event;
use Utopia\Database\Document;
use Utopia\Queue\Connection;
use Utopia\Queue\Publisher;
class Build extends Event
{
@@ -12,9 +12,9 @@ class Build extends Event
protected ?Document $deployment = null;
protected ?Document $template = null;
public function __construct(protected Connection $connection)
public function __construct(protected Publisher $publisher)
{
parent::__construct($connection);
parent::__construct($publisher);
$this
->setQueue(Event::BUILDS_QUEUE_NAME)
+3 -3
View File
@@ -3,16 +3,16 @@
namespace Appwrite\Event;
use Utopia\Database\Document;
use Utopia\Queue\Connection;
use Utopia\Queue\Publisher;
class Certificate extends Event
{
protected bool $skipRenewCheck = false;
protected ?Document $domain = null;
public function __construct(protected Connection $connection)
public function __construct(protected Publisher $publisher)
{
parent::__construct($connection);
parent::__construct($publisher);
$this
->setQueue(Event::CERTIFICATES_QUEUE_NAME)
+3 -3
View File
@@ -4,7 +4,7 @@ namespace Appwrite\Event;
use Utopia\Database\Document;
use Utopia\DSN\DSN;
use Utopia\Queue\Connection;
use Utopia\Queue\Publisher;
class Database extends Event
{
@@ -13,9 +13,9 @@ class Database extends Event
protected ?Document $collection = null;
protected ?Document $document = null;
public function __construct(protected Connection $connection)
public function __construct(protected Publisher $publisher)
{
parent::__construct($connection);
parent::__construct($publisher);
$this->setClass(Event::DATABASE_CLASS_NAME);
}
+3 -3
View File
@@ -3,7 +3,7 @@
namespace Appwrite\Event;
use Utopia\Database\Document;
use Utopia\Queue\Connection;
use Utopia\Queue\Publisher;
class Delete extends Event
{
@@ -15,9 +15,9 @@ class Delete extends Event
protected ?string $hourlyUsageRetentionDatetime = null;
public function __construct(protected Connection $connection)
public function __construct(protected Publisher $publisher)
{
parent::__construct($connection);
parent::__construct($publisher);
$this
->setQueue(Event::DELETE_QUEUE_NAME)
+6 -7
View File
@@ -4,8 +4,8 @@ namespace Appwrite\Event;
use InvalidArgumentException;
use Utopia\Database\Document;
use Utopia\Queue\Client;
use Utopia\Queue\Connection;
use Utopia\Queue\Publisher;
use Utopia\Queue\Queue;
class Event
{
@@ -58,10 +58,10 @@ class Event
protected bool $paused = false;
/**
* @param Connection $connection
* @param Publisher $publisher
* @return void
*/
public function __construct(protected Connection $connection)
public function __construct(protected Publisher $publisher)
{
}
@@ -345,12 +345,11 @@ class Event
}
/** The getter is required since events like Databases need to override the queue name depending on the project */
$client = new Client($this->getQueue(), $this->connection);
$queue = new Queue($this->getQueue());
// Merge the base payload with any trimmed values
$payload = array_merge($this->preparePayload(), $this->trimPayload());
return $client->enqueue($payload);
return $this->publisher->enqueue($queue, $payload);
}
/**
+3 -3
View File
@@ -3,7 +3,7 @@
namespace Appwrite\Event;
use Utopia\Database\Document;
use Utopia\Queue\Connection;
use Utopia\Queue\Publisher;
class Func extends Event
{
@@ -19,9 +19,9 @@ class Func extends Event
protected ?Document $function = null;
protected ?Document $execution = null;
public function __construct(protected Connection $connection)
public function __construct(protected Publisher $publisher)
{
parent::__construct($connection);
parent::__construct($publisher);
$this
->setQueue(Event::FUNCTIONS_QUEUE_NAME)
+3 -3
View File
@@ -2,7 +2,7 @@
namespace Appwrite\Event;
use Utopia\Queue\Connection;
use Utopia\Queue\Publisher;
class Mail extends Event
{
@@ -15,9 +15,9 @@ class Mail extends Event
protected string $bodyTemplate = '';
protected array $attachment = [];
public function __construct(protected Connection $connection)
public function __construct(protected Publisher $publisher)
{
parent::__construct($connection);
parent::__construct($publisher);
$this
->setQueue(Event::MAILS_QUEUE_NAME)
+3 -3
View File
@@ -3,7 +3,7 @@
namespace Appwrite\Event;
use Utopia\Database\Document;
use Utopia\Queue\Connection;
use Utopia\Queue\Publisher;
class Messaging extends Event
{
@@ -14,9 +14,9 @@ class Messaging extends Event
protected ?string $scheduledAt = null;
protected ?string $providerType = null;
public function __construct(protected Connection $connection)
public function __construct(protected Publisher $publisher)
{
parent::__construct($connection);
parent::__construct($publisher);
$this
->setQueue(Event::MESSAGING_QUEUE_NAME)
+3 -3
View File
@@ -3,16 +3,16 @@
namespace Appwrite\Event;
use Utopia\Database\Document;
use Utopia\Queue\Connection;
use Utopia\Queue\Publisher;
class Migration extends Event
{
protected string $type = '';
protected ?Document $migration = null;
public function __construct(protected Connection $connection)
public function __construct(protected Publisher $publisher)
{
parent::__construct($connection);
parent::__construct($publisher);
$this
->setQueue(Event::MIGRATIONS_QUEUE_NAME)
+3 -3
View File
@@ -3,16 +3,16 @@
namespace Appwrite\Event;
use Utopia\Database\Document;
use Utopia\Queue\Connection;
use Utopia\Queue\Publisher;
class Usage extends Event
{
protected array $metrics = [];
protected array $reduce = [];
public function __construct(protected Connection $connection)
public function __construct(protected Publisher $publisher)
{
parent::__construct($connection);
parent::__construct($publisher);
$this
->setQueue(Event::USAGE_QUEUE_NAME)
+3 -3
View File
@@ -2,15 +2,15 @@
namespace Appwrite\Event;
use Utopia\Queue\Connection;
use Utopia\Queue\Publisher;
class UsageDump extends Event
{
protected array $stats;
public function __construct(protected Connection $connection)
public function __construct(protected Publisher $publisher)
{
parent::__construct($connection);
parent::__construct($publisher);
$this
->setQueue(Event::USAGE_DUMP_QUEUE_NAME)
+3 -3
View File
@@ -2,13 +2,13 @@
namespace Appwrite\Event;
use Utopia\Queue\Connection;
use Utopia\Queue\Publisher;
class Webhook extends Event
{
public function __construct(protected Connection $connection)
public function __construct(protected Publisher $publisher)
{
parent::__construct($connection);
parent::__construct($publisher);
$this
->setQueue(Event::WEBHOOK_QUEUE_NAME)
@@ -23,7 +23,6 @@ class Origin extends Validator
public const CLIENT_TYPE_UNITY = 'unity';
public const CLIENT_TYPE_REACT_NATIVE_IOS = 'react-native-ios';
public const CLIENT_TYPE_REACT_NATIVE_ANDROID = 'react-native-android';
public const CLIENT_TYPE_SCHEME = 'scheme';
public const SCHEME_TYPE_HTTP = 'http';
@@ -93,8 +92,6 @@ class Origin extends Validator
case self::CLIENT_TYPE_APPLE_TVOS:
case self::CLIENT_TYPE_REACT_NATIVE_IOS:
case self::CLIENT_TYPE_REACT_NATIVE_ANDROID:
case self::CLIENT_TYPE_UNITY:
case self::CLIENT_TYPE_SCHEME:
$this->clients[] = (isset($platform['key'])) ? $platform['key'] : '';
break;
-2
View File
@@ -6,7 +6,6 @@ use Appwrite\Platform\Tasks\Doctor;
use Appwrite\Platform\Tasks\Install;
use Appwrite\Platform\Tasks\Maintenance;
use Appwrite\Platform\Tasks\Migrate;
use Appwrite\Platform\Tasks\QueueCount;
use Appwrite\Platform\Tasks\QueueRetry;
use Appwrite\Platform\Tasks\ScheduleExecutions;
use Appwrite\Platform\Tasks\ScheduleFunctions;
@@ -29,7 +28,6 @@ class Tasks extends Service
->addAction(Install::getName(), new Install())
->addAction(Maintenance::getName(), new Maintenance())
->addAction(Migrate::getName(), new Migrate())
->addAction(QueueCount::getName(), new QueueCount())
->addAction(QueueRetry::getName(), new QueueRetry())
->addAction(SDKs::getName(), new SDKs())
->addAction(SSL::getName(), new SSL())
@@ -1,57 +0,0 @@
<?php
namespace Appwrite\Platform\Tasks;
use Utopia\CLI\Console;
use Utopia\Platform\Action;
use Utopia\Queue\Client;
use Utopia\Queue\Connection;
use Utopia\Validator\Text;
use Utopia\Validator\WhiteList;
class QueueCount extends Action
{
public static function getName(): string
{
return 'queue-count';
}
public function __construct()
{
$this
->desc('Return the number of from a specific queue identified by the name parameter with a specific type')
->param('name', '', new Text(100), 'Queue name')
->param('type', '', new WhiteList([
'success',
'failed',
'processing',
]), 'Queue type')
->inject('queue')
->callback(fn ($name, $type, $queue) => $this->action($name, $type, $queue));
}
/**
* @param string $name The name of the queue to count the jobs from
* @param string $type The type of jobs to count
* @param Connection $queue
*/
public function action(string $name, string $type, Connection $queue): void
{
if (!$name) {
Console::error('Missing required parameter $name');
return;
}
$queueClient = new Client($name, $queue);
$count = match ($type) {
'success' => $queueClient->countSuccessfulJobs(),
'failed' => $queueClient->countFailedJobs(),
'processing' => $queueClient->countProcessingJobs(),
default => 0
};
Console::log("Queue: '{$name}' has {$count} {$type} jobs.");
}
}
+7 -16
View File
@@ -4,8 +4,8 @@ namespace Appwrite\Platform\Tasks;
use Utopia\CLI\Console;
use Utopia\Platform\Action;
use Utopia\Queue\Client;
use Utopia\Queue\Connection;
use Utopia\Queue\Publisher;
use Utopia\Queue\Queue;
use Utopia\Validator\Text;
use Utopia\Validator\Wildcard;
@@ -23,33 +23,24 @@ class QueueRetry extends Action
->desc('Retry failed jobs from a specific queue identified by the name parameter')
->param('name', '', new Text(100), 'Queue name')
->param('limit', 0, new Wildcard(), 'jobs limit', true)
->inject('queue')
->callback(fn ($name, $limit, $queue) => $this->action($name, $limit, $queue));
->inject('publisher')
->callback(fn ($name, $limit, $publisher) => $this->action($name, $limit, $publisher));
}
/**
* @param string $name The name of the queue to retry jobs from
* @param mixed $limit
* @param Connection $queue
* @param Publisher $publisher
*/
public function action(string $name, mixed $limit, Connection $queue): void
public function action(string $name, mixed $limit, Publisher $publisher): void
{
if (!$name) {
Console::error('Missing required parameter $name');
return;
}
$limit = (int)$limit;
$queueClient = new Client($name, $queue);
if ($queueClient->countFailedJobs() === 0) {
Console::error('No failed jobs found.');
return;
}
Console::log('Retrying failed jobs...');
$queueClient->retry($limit);
$publisher->retry(new Queue($name), $limit);
}
}
+9 -13
View File
@@ -11,7 +11,7 @@ use Utopia\Database\Exception;
use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use Utopia\Platform\Action;
use Utopia\Pools\Group;
use Utopia\Queue\Publisher;
use Utopia\System\System;
use function Swoole\Coroutine\run;
@@ -26,7 +26,7 @@ abstract class ScheduleBase extends Action
abstract public static function getName(): string;
abstract public static function getSupportedResource(): string;
abstract public static function getCollectionId(): string;
abstract protected function enqueueResources(Group $pools, Database $dbForPlatform, callable $getProjectDB): void;
abstract protected function enqueueResources(Publisher $publisher, Database $dbForPlatform, callable $getProjectDB): void;
public function __construct()
{
@@ -34,10 +34,10 @@ abstract class ScheduleBase extends Action
$this
->desc("Execute {$type}s scheduled in Appwrite")
->inject('pools')
->inject('publisher')
->inject('dbForPlatform')
->inject('getProjectDB')
->callback(fn (Group $pools, Database $dbForPlatform, callable $getProjectDB) => $this->action($pools, $dbForPlatform, $getProjectDB));
->callback(fn (Publisher $publisher, Database $dbForPlatform, callable $getProjectDB) => $this->action($publisher, $dbForPlatform, $getProjectDB));
}
protected function updateProjectAccess(Document $project, Database $dbForPlatform): void
@@ -56,7 +56,7 @@ abstract class ScheduleBase extends Action
* 2. Create timer that sync all changes from 'schedules' collection to local copy. Only reading changes thanks to 'resourceUpdatedAt' attribute
* 3. Create timer that prepares coroutines for soon-to-execute schedules. When it's ready, coroutine sleeps until exact time before sending request to worker.
*/
public function action(Group $pools, Database $dbForPlatform, callable $getProjectDB): void
public function action(Publisher $publisher, Database $dbForPlatform, callable $getProjectDB): void
{
Console::title(\ucfirst(static::getSupportedResource()) . ' scheduler V1');
Console::success(APP_NAME . ' ' . \ucfirst(static::getSupportedResource()) . ' scheduler v1 has started');
@@ -125,17 +125,15 @@ abstract class ScheduleBase extends Action
$latestDocument = \end($results);
}
$pools->reclaim();
Console::success("{$total} resources were loaded in " . (\microtime(true) - $loadStart) . " seconds");
Console::success("Starting timers at " . DateTime::now());
run(function () use ($dbForPlatform, &$lastSyncUpdate, $getSchedule, $pools, $getProjectDB) {
run(function () use ($dbForPlatform, &$lastSyncUpdate, $getSchedule, $publisher, $getProjectDB) {
/**
* The timer synchronize $schedules copy with database collection.
*/
Timer::tick(static::UPDATE_TIMER * 1000, function () use ($dbForPlatform, &$lastSyncUpdate, $getSchedule, $pools) {
Timer::tick(static::UPDATE_TIMER * 1000, function () use ($dbForPlatform, &$lastSyncUpdate, $getSchedule) {
$time = DateTime::now();
$timerStart = \microtime(true);
@@ -184,17 +182,15 @@ abstract class ScheduleBase extends Action
$lastSyncUpdate = $time;
$timerEnd = \microtime(true);
$pools->reclaim();
Console::log("Sync tick: {$total} schedules were updated in " . ($timerEnd - $timerStart) . " seconds");
});
Timer::tick(
static::ENQUEUE_TIMER * 1000,
fn () => $this->enqueueResources($pools, $dbForPlatform, $getProjectDB)
fn () => $this->enqueueResources($publisher, $dbForPlatform, $getProjectDB)
);
$this->enqueueResources($pools, $dbForPlatform, $getProjectDB);
$this->enqueueResources($publisher, $dbForPlatform, $getProjectDB);
});
}
}
@@ -5,7 +5,7 @@ namespace Appwrite\Platform\Tasks;
use Appwrite\Event\Func;
use Swoole\Coroutine as Co;
use Utopia\Database\Database;
use Utopia\Pools\Group;
use Utopia\Queue\Publisher;
class ScheduleExecutions extends ScheduleBase
{
@@ -27,11 +27,9 @@ class ScheduleExecutions extends ScheduleBase
return 'executions';
}
protected function enqueueResources(Group $pools, Database $dbForPlatform, callable $getProjectDB): void
protected function enqueueResources(Publisher $publisher, Database $dbForPlatform, callable $getProjectDB): void
{
$queue = $pools->get('queue')->pop();
$connection = $queue->getResource();
$queueForFunctions = new Func($connection);
$queueForFunctions = new Func($publisher);
$intervalEnd = (new \DateTime())->modify('+' . self::ENQUEUE_TIMER . ' seconds');
foreach ($this->schedules as $schedule) {
@@ -83,7 +81,5 @@ class ScheduleExecutions extends ScheduleBase
unset($this->schedules[$schedule['$internalId']]);
}
$queue->reclaim();
}
}
@@ -7,7 +7,7 @@ use Cron\CronExpression;
use Utopia\CLI\Console;
use Utopia\Database\Database;
use Utopia\Database\DateTime;
use Utopia\Pools\Group;
use Utopia\Queue\Publisher;
class ScheduleFunctions extends ScheduleBase
{
@@ -31,7 +31,7 @@ class ScheduleFunctions extends ScheduleBase
return 'functions';
}
protected function enqueueResources(Group $pools, Database $dbForPlatform, callable $getProjectDB): void
protected function enqueueResources(Publisher $publisher, Database $dbForPlatform, callable $getProjectDB): void
{
$timerStart = \microtime(true);
$time = DateTime::now();
@@ -70,12 +70,9 @@ class ScheduleFunctions extends ScheduleBase
}
foreach ($delayedExecutions as $delay => $scheduleKeys) {
\go(function () use ($delay, $scheduleKeys, $pools, $dbForPlatform) {
\go(function () use ($delay, $scheduleKeys, $publisher, $dbForPlatform) {
\sleep($delay); // in seconds
$queue = $pools->get('queue')->pop();
$connection = $queue->getResource();
foreach ($scheduleKeys as $scheduleKey) {
// Ensure schedule was not deleted
if (!\array_key_exists($scheduleKey, $this->schedules)) {
@@ -86,8 +83,7 @@ class ScheduleFunctions extends ScheduleBase
$this->updateProjectAccess($schedule['project'], $dbForPlatform);
$queueForFunctions = new Func($connection);
$queueForFunctions = new Func($publisher);
$queueForFunctions
->setType('schedule')
->setFunction($schedule['resource'])
@@ -96,8 +92,6 @@ class ScheduleFunctions extends ScheduleBase
->setProject($schedule['project'])
->trigger();
}
$queue->reclaim();
});
}
@@ -4,7 +4,7 @@ namespace Appwrite\Platform\Tasks;
use Appwrite\Event\Messaging;
use Utopia\Database\Database;
use Utopia\Pools\Group;
use Utopia\Queue\Publisher;
class ScheduleMessages extends ScheduleBase
{
@@ -26,7 +26,7 @@ class ScheduleMessages extends ScheduleBase
return 'messages';
}
protected function enqueueResources(Group $pools, Database $dbForPlatform, callable $getProjectDB): void
protected function enqueueResources(Publisher $publisher, Database $dbForPlatform, callable $getProjectDB): void
{
foreach ($this->schedules as $schedule) {
if (!$schedule['active']) {
@@ -40,13 +40,9 @@ class ScheduleMessages extends ScheduleBase
continue;
}
\go(function () use ($schedule, $pools, $dbForPlatform) {
$queue = $pools->get('queue')->pop();
$connection = $queue->getResource();
$queueForMessaging = new Messaging($connection);
\go(function () use ($schedule, $publisher, $dbForPlatform) {
$this->updateProjectAccess($schedule['project'], $dbForPlatform);
$queueForMessaging = new Messaging($publisher);
$queueForMessaging
->setType(MESSAGE_SEND_TYPE_EXTERNAL)
->setMessageId($schedule['resourceId'])
@@ -58,8 +54,6 @@ class ScheduleMessages extends ScheduleBase
$schedule['$id'],
);
$queue->reclaim();
unset($this->schedules[$schedule['$internalId']]);
});
}
@@ -370,6 +370,8 @@ class Certificates extends Action
/** Trigger Webhook */
$ruleModel = new Rule();
$queueForEvents
->setQueue(Event::WEBHOOK_QUEUE_NAME)
->setClass(Event::WEBHOOK_CLASS_NAME)
->setProject($project)
->setEvent('rules.[ruleId].update')
->setParam('ruleId', $rule->getId())
@@ -41,13 +41,13 @@ class Platform extends Model
])
->addRule('type', [
'type' => self::TYPE_STRING,
'description' => 'Platform type. Possible values are: web, flutter-web, flutter-ios, flutter-android, ios, android, react-native-android, react-native-ios, scheme and unity.',
'description' => 'Platform type. Possible values are: web, flutter-web, flutter-ios, flutter-android, ios, android, react-native-android, react-native-ios and unity.',
'default' => '',
'example' => 'web',
])
->addRule('key', [
'type' => self::TYPE_STRING,
'description' => 'Platform Key. iOS bundle ID or Android package name or app scheme. Empty string for other platforms.',
'description' => 'Platform Key. iOS bundle ID or Android package name. Empty string for other platforms.',
'default' => '',
'example' => 'com.company.appname',
])
@@ -2,6 +2,7 @@
namespace Tests\E2E\Services\GraphQL;
use Appwrite\Tests\Async;
use Tests\E2E\Client;
use Tests\E2E\Scopes\ProjectCustom;
use Tests\E2E\Scopes\Scope;
@@ -14,6 +15,7 @@ class FunctionsClientTest extends Scope
use ProjectCustom;
use SideClient;
use Base;
use Async;
public function testCreateFunction(): array
{
@@ -119,7 +121,7 @@ class FunctionsClientTest extends Scope
]
];
while (true) {
$this->assertEventually(function () use ($projectId, $gqlPayload, &$deployment) {
$deployment = $this->client->call(Client::METHOD_POST, '/graphql', [
'content-type' => 'application/json',
'x-appwrite-project' => $projectId,
@@ -130,18 +132,8 @@ class FunctionsClientTest extends Scope
$this->assertArrayNotHasKey('errors', $deployment['body']);
$deployment = $deployment['body']['data']['functionsGetDeployment'];
if (
$deployment['status'] === 'ready'
|| $deployment['status'] === 'failed'
) {
break;
}
\sleep(1);
}
$this->assertEquals('ready', $deployment['status']);
$this->assertEquals('ready', $deployment['status']);
});
return $deployment;
}
@@ -2,6 +2,7 @@
namespace Tests\E2E\Services\GraphQL;
use Appwrite\Tests\Async;
use Tests\E2E\Client;
use Tests\E2E\Scopes\ProjectCustom;
use Tests\E2E\Scopes\Scope;
@@ -14,6 +15,7 @@ class FunctionsServerTest extends Scope
use ProjectCustom;
use SideServer;
use Base;
use Async;
public function testCreateFunction(): array
{
@@ -117,7 +119,7 @@ class FunctionsServerTest extends Scope
]
];
while (true) {
$this->assertEventually(function () use ($projectId, $gqlPayload, &$deployment) {
$deployment = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $projectId,
@@ -127,19 +129,8 @@ class FunctionsServerTest extends Scope
$this->assertArrayNotHasKey('errors', $deployment['body']);
$deployment = $deployment['body']['data']['functionsGetDeployment'];
if (
$deployment['status'] === 'ready'
|| $deployment['status'] === 'failed'
) {
break;
}
\sleep(1);
}
$this->assertEquals('ready', $deployment['status']);
$this->assertEquals('ready', $deployment['status']);
});
return $deployment;
}
@@ -67,24 +67,6 @@ class HealthCustomServerTest extends Scope
return [];
}
public function testQueueSuccess(): array
{
/**
* Test for SUCCESS
*/
$response = $this->client->call(Client::METHOD_GET, '/health/queue', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals('pass', $response['body']['statuses'][0]['status']);
$this->assertIsInt($response['body']['statuses'][0]['ping']);
$this->assertLessThan(100, $response['body']['statuses'][0]['ping']);
return [];
}
public function testPubSubSuccess(): array
{
/**
@@ -4,6 +4,7 @@ namespace Tests\E2E\Services\Projects;
use Appwrite\Auth\Auth;
use Appwrite\Extend\Exception;
use Appwrite\Tests\Async;
use Tests\E2E\Client;
use Tests\E2E\General\UsageTest;
use Tests\E2E\Scopes\ProjectConsole;
@@ -19,6 +20,7 @@ class ProjectsConsoleClientTest extends Scope
use ProjectsBase;
use ProjectConsole;
use SideClient;
use Async;
/**
* @group smtpAndTemplates
@@ -1411,18 +1413,20 @@ class ProjectsConsoleClientTest extends Scope
/**
* List sessions
*/
$response = $this->client->call(Client::METHOD_GET, '/account/sessions', [
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $id,
'Cookie' => $sessionCookie,
]);
$this->assertEventually(function () use ($id, $sessionCookie, $sessionId2) {
$response = $this->client->call(Client::METHOD_GET, '/account/sessions', [
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $id,
'Cookie' => $sessionCookie,
]);
$this->assertEquals(200, $response['headers']['status-code']);
$sessions = $response['body']['sessions'];
$this->assertEquals(200, $response['headers']['status-code']);
$sessions = $response['body']['sessions'];
$this->assertEquals(1, count($sessions));
$this->assertEquals($sessionId2, $sessions[0]['$id']);
$this->assertEquals(1, count($sessions));
$this->assertEquals($sessionId2, $sessions[0]['$id']);
});
/**
* Reset Limit
@@ -223,6 +223,8 @@ trait TeamsBaseClient
$this->assertEquals($email, $lastEmail['to'][0]['address']);
$this->assertEquals($name, $lastEmail['to'][0]['name']);
$this->assertEquals('Invitation to ' . $teamName . ' Team at ' . $this->getProject()['name'], $lastEmail['subject']);
$this->assertEquals($response['body']['teamId'], substr($lastEmail['text'], strpos($lastEmail['text'], '&teamId=', 0) + 8, 20));
$this->assertEquals($teamName, substr($lastEmail['text'], strpos($lastEmail['text'], '&teamName=', 0) + 10, 7));
$secret = substr($lastEmail['text'], strpos($lastEmail['text'], '&secret=', 0) + 8, 256);
$membershipUid = substr($lastEmail['text'], strpos($lastEmail['text'], '?membershipId=', 0) + 14, 20);
@@ -290,6 +292,8 @@ trait TeamsBaseClient
$this->assertEquals($secondEmail, $lastEmail['to'][0]['address']);
$this->assertEquals($secondName, $lastEmail['to'][0]['name']);
$this->assertEquals('Invitation to ' . $teamName . ' Team at ' . $this->getProject()['name'], $lastEmail['subject']);
$this->assertEquals($response['body']['teamId'], substr($lastEmail['text'], strpos($lastEmail['text'], '&teamId=', 0) + 8, 20));
$this->assertEquals($teamName, substr($lastEmail['text'], strpos($lastEmail['text'], '&teamName=', 0) + 10, 7));
// test for resending invitation
$response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([
+6 -8
View File
@@ -5,7 +5,7 @@ namespace Tests\Unit\Event;
use Appwrite\Event\Event;
use InvalidArgumentException;
use PHPUnit\Framework\TestCase;
use Utopia\Queue\Client;
use Utopia\Queue\Publisher;
require_once __DIR__ . '/../../../app/init.php';
@@ -13,13 +13,14 @@ class EventTest extends TestCase
{
protected ?Event $object = null;
protected string $queue = '';
protected Publisher $publisher;
public function setUp(): void
{
global $register;
$connection = $register->get('pools')->get('queue')->pop()->getResource();
$this->publisher = new MockPublisher();
$this->queue = 'v1-tests' . uniqid();
$this->object = new Event($connection);
$this->object = new Event($this->publisher);
$this->object->setClass('TestsV1');
$this->object->setQueue($this->queue);
}
@@ -51,10 +52,7 @@ class EventTest extends TestCase
$this->assertEquals('eventValue1', $this->object->getParam('eventKey1'));
$this->assertEquals('eventValue2', $this->object->getParam('eventKey2'));
$this->assertEquals(null, $this->object->getParam('eventKey3'));
global $register;
$pools = $register->get('pools');
$client = new Client($this->object->getQueue(), $pools->get('queue')->pop()->getResource());
$this->assertEquals($client->getQueueSize(), 1);
$this->assertCount(1, $this->publisher->getEvents($this->object->getQueue()));
}
public function testReset(): void
+35
View File
@@ -0,0 +1,35 @@
<?php
namespace Tests\Unit\Event;
use Utopia\Queue\Publisher;
use Utopia\Queue\Queue;
class MockPublisher implements Publisher
{
private $events = [];
public function enqueue(Queue $queue, array $payload): bool
{
if (!isset($this->events[$queue->name])) {
$this->events[$queue->name] = [];
}
$this->events[$queue->name][] = $payload;
return true;
}
public function getEvents(string $queue)
{
return $this->events[$queue] ?? null;
}
public function retry(Queue $queue, int $limit = null): void
{
// TODO: Implement retry() method.
}
public function getQueueSize(Queue $queue, bool $failedJobs = false): int
{
return count($this->events[$queue->name]);
}
}
-41
View File
@@ -1,41 +0,0 @@
<?php
namespace Tests\Unit\Usage;
use PHPUnit\Framework\TestCase;
use Utopia\Queue\Client;
use Utopia\Queue\Connection;
class StatsTest extends TestCase
{
protected ?Connection $connection = null;
protected ?Client $client = null;
protected const QUEUE_NAME = 'usage-test-q';
public function setUp(): void
{
global $register;
$connection = $register->get('pools')->get('queue')->pop()->getResource();
$this->connection = $connection;
$this->client = new Client(self::QUEUE_NAME, $this->connection);
}
public function tearDown(): void
{
}
public function testSamePayload(): void
{
$inToQueue = [
'key_1' => 'value_1',
'key_2' => 'value_2',
];
$result = $this->client->enqueue($inToQueue);
$this->assertTrue($result);
$outFromQueue = $this->connection->leftPopArray('utopia-queue.queue.' . self::QUEUE_NAME, 0)['payload'];
$this->assertNotEmpty($outFromQueue);
$this->assertSame($inToQueue, $outFromQueue);
}
}