| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
Scaffold appwrite-* library crates and apps/server health binary under 3.x.x, wire them into the Cargo workspace, and document the layout. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
Lock dependencies resolved while verifying appwrite crate stubs compile. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
Copy the utopia-* building-block crates from rust-poc under 3.x.x/crates/ alongside appwrite-* peers, plus Rust toolchain/clippy/deny/rustfmt config. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
Replace stub src/lib.rs with real, compiling ports of the
Appwrite\* PHP domains the Users API migration needs, across
seven crates plus the platform composition layer that wires them
together.
appwrite-exception: Exception { type_, message, code, version }
constructed from a type string looked up in a static ERRORS map
(src/Appwrite/Extend/Exception.php + app/config/errors.php). Ports
every GENERAL_*/USER_*/PROJECT_* constant PHP defines (plus a
documented PROJECT_UNKNOWN Rust-only addition), is_publishable(),
default_code()/default_message(), and to_json() matching the PHP
Error response model (message, code, type, version).
appwrite-response: data-driven Rule/ModelSpec/ListSpec model
catalog covering User, Session, Token, JWT, Preferences, Target,
Membership, Identity, and the MFA response models (+ list
variants), and dynamic(doc, model) porting Response::dynamic() --
filters a document to its model's rules, fills PHP-equivalent
defaults for missing optional fields, recurses into nested models,
and wraps lists as { total, <plural>: [...] }.
appwrite-hooks: Hooks registry (add/remove/has/trigger) mirroring
Appwrite\Hooks\Hooks, with the PASSWORD_VALIDATOR hook slot.
Deliberately instance-owned rather than PHP's static registry
(documented deviation).
appwrite-locale: GeoRecord { country_code, country, continent,
continent_code, eu, currency } with new()/unknown() constructors,
porting Appwrite\Locale\GeoRecord.
appwrite-auth: Key::decode_standard() porting Appwrite\Auth\Key's
API_KEY_STANDARD case (secret lookup + expiry check against a
project document's keys array); Password (length 8-256) and Phone
validators porting Appwrite\Auth\Validator\*; mfa module porting
Appwrite\Auth\MFA\Type factor constants; Hash/Argon2/Bcrypt
re-exported from utopia-auth behind feature flags plus
hash_password/verify_password wrappers.
appwrite-event: Event builder (set_project/set_user/set_event/
set_param/set_payload/set_context) with to_message() producing the
PHP queue payload shape; generate_events() porting
Event::generateEvents()'s placeholder/wildcard expansion for
patterns with up to one sub-resource level (every Users API event
fits this shape); DeleteMessage/AuditMessage porting
Appwrite\Event\Message\{Delete,Audit}::toArray(); DeletePublisher/
AuditPublisher traits with in-memory + callback implementations
ahead of a Redis-backed publisher in apps/server.
appwrite-database: CustomId validator (accepts "unique()" or any
Utopia\Database\Validator\Key-valid ID) porting
Appwrite\Utopia\Database\Validator\CustomId; resolve_id() porting
the "$id == 'unique()' ? ID::unique() : ID::custom($id)" pattern
used across Users/Targets/Sessions creation; queries module with
Query::equal/search helpers for the lookups those endpoints share.
appwrite-platform: composes the above into AppwritePlatform --
DI container, hook registry (with the default passwordValidator
hook registered), and in-memory delete/audit queue publishers --
replacing the previous stub()-touching placeholder. apps/server
updated to construct AppwritePlatform::new() directly.
Every crate: expanded/added unit + integration tests (PHP test
suites as the oracle where they exist), benches printing
ops_per_s=, updated Cargo.toml deps, and README API tables with
PHP-equivalent references and documented deviations.
cargo test -p appwrite-exception -p appwrite-response -p
appwrite-hooks -p appwrite-locale -p appwrite-auth -p
appwrite-event -p appwrite-database -p appwrite-platform: all
green. cargo clippy --all-targets and cargo fmt --check: clean.
Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
Implements the shared api-group Init/Error/Shutdown hooks and the full Users HTTP module on top of utopia-platform, so apps/server can serve /v1/users* while PHP remains the behavior oracle. - modules/core: Init hook resolves X-Appwrite-Project/X-Appwrite-Key (appwrite_auth::Key), checks the matched route's scope label, and binds project/apiKey/dbForProject on the request container; Error hook maps HttpError/Exception to the Response::MODEL_ERROR shape; Shutdown hook enqueues audits.event messages via publisherForAudits. - modules/users: all 41 Http/Users/**/*.php actions ported (CRUD, pre-hashed-password creates, property updates, prefs, targets, sessions/tokens/JWTs, memberships, identities, MFA), registered in services/http.rs under their PHP getName() ids. - state.rs: AppwriteState/ProjectStore/DatabasePool -- an in-memory stand-in for dbForPlatform's projects/keys plus a per-project dbForProject pool (utopia_database Memory adapter), including seed_dev_project for local/test bootstrapping. - apps/server: wires appwrite_platform::build() into main(), keeps /v1/health and /_health, adds _APP_RUST_SEED dev bootstrap. - utopia-http: share one request-scoped DI container across Init hooks, the route action, and Shutdown hooks so resources an Init hook binds stay visible downstream (mirrors Utopia\App's per-request Container). - tests/users_http.rs: end-to-end MemoryAdapter coverage of the auth flow (missing project, missing scope) and create/get/list/delete user round trip. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
- appwrite-platform: connect_from_env() wires dbForPlatform/dbForProject to Postgres when _APP_DB_ADAPTER=postgresql/postgres, matching PHP's Appwrite\\Database\\Factory namespace math (_console / _<sequence>). Falls back to the existing in-memory ProjectStore/DatabasePool on memory adapter or connect failure, so _APP_RUST_SEED unit tests stay green. New ProjectDb enum abstracts Database<Memory>/Database<Postgres> since utopia_database::Adapter is not dyn-compatible. - resolve_project()/project_sequence() load a project + its keys from dbForPlatform (projects + keys collections), replicating PHP's subQueryKeys filter by hand and shaping the JSON for appwrite_auth::Key::decode_standard. - appwrite-database: new encrypt filter (AES-128-GCM) matching PHP's openssl_encrypt envelope for users.password / keys.secret, keyed by _APP_OPENSSL_KEY_V1 with PHP's zero-pad/truncate key-length quirk. - utopia-database: fix Postgres row decoding to also try serde_json::Value (with-serde_json-1) for JSON/JSONB columns -- array attributes (keys.scopes, users.labels, ...) were silently decoding as Null over Postgres. - apps/server: call connect_from_env() at boot and log the active adapter; only auto-seed the dev project in memory mode. - Add an ignored end-to-end Postgres wiring test (state.rs) that provisions projects/keys/users against a real local Postgres and drives connect_from_env -> resolve_project -> dbForProject, plus an ignored postgres_smoke.rs template for validating against PHP-created fixtures once the compose stack is up. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
Cover property updates, prehashed creates, sessions/tokens/JWTs, targets CRUD, identities/memberships lists, and MFA recovery codes against the in-memory seeded project/key path. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
Add appwrite-rust compose service with PathPrefix(/v1/users) priority 100, in-process Users create+get microbench, and HTTP benchmark harness docs. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
✨ Benchmark resultsComparing main (before) → cursor/rupoc-bdfb (after).
Metrics below reflect the current branch (after). Δ P95 compares against the base.
Top API waits (after)
|
Sorry, something went wrong.
Wire `_APP_DB_ADAPTER` the same way PHP does (postgresql/mysql/mariadb/mongodb) so the Rust Users server can share whichever platform DB Appwrite is configured for, with Memory fallback for local tests. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
Wrap sync postgres PDO connect/query in block_in_place so Hyper workers do not panic on nested runtimes, connect before building the Tokio runtime in apps/server, wait for healthy Postgres/Redis before starting appwrite-rust, and ignore target/ in the Rust image context. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
Populate Request payload from application/json (and urlencoded) bodies so /v1/users create works with Content-Type JSON, matching PHP Utopia behavior. Also fix appwrite-rust depends_on to use a literal postgresql service name (compose rejects env-var map keys). Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
Token::generate sliced a hex string built from a floor-divided byte count, so any odd length (Users' createToken accepts 4..128) panicked and took the whole server process down. Round the byte count up like PHP's ceil() and truncate instead of slicing. The urlencoded parser also dropped http_build_query's queries[0]=..&queries[1]=.. form into a single stringly key, so array params never reached handlers, and percent-decoding widened raw bytes into Latin-1 code points. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
i64/f64/bool ToSql impls accept exactly one OID each, so binding an integer to any column narrower than bigint failed with "error serializing parameter N" -- tokens.type is INT4, which broke createUser tokens entirely. Route the scalars through the same type-directed conversion PgFlexible already does for strings. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
PHP's Database::updateDocument loads the stored document and merges the caller's partial update over it. The Rust port skipped that, so every sparse update returned a stub document and rewrote the permissions rows from an empty $permissions, which made PHP's authorized reads of a Rust-updated user come back empty. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
Ports the session half of request.php's user resource and api.php's admin branch: decode the session store, verify the secret against the user's sessions, and derive scopes from the confirmed team membership (admin mode) or the member role (project session). Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
The hyper adapter never populated Request::cookies, so the Console's a_session_console cookie was invisible to the api init hook and every SideConsole request fell back to a guest key. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
Rust kept its own in-process cache, so a session deleted through the Rust API left the PHP server serving a user document whose cached sessions relationship still listed it, and a JWT for that session went on passing sessionActive. Point the project and platform databases at the Redis PHP already uses. The cache key carries the adapter hostname, so the adapter now also carries the DSN host PHP's pooled PDO reports; without it the two servers would key the same document differently. Writing a child document leaves the parent user cached with a stale relationship, so the session, target, token and password handlers purge the user document where the PHP handlers do. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
Rename utopia-database's connection layer from pdo to SqlClient, connect through Postgres/Mysql/MariaDb/Sqlite adapters in platform wiring, and document that Appwrite 3.x keeps Utopia architecture while avoiding PHP runtime surfaces like PDO. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
* Fix Rust Postgres boot under Tokio and harden compose startup Wrap sync postgres PDO connect/query in block_in_place so Hyper workers do not panic on nested runtimes, connect before building the Tokio runtime in apps/server, wait for healthy Postgres/Redis before starting appwrite-rust, and ignore target/ in the Rust image context. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com> * Update Cargo.lock for utopia-database tokio (postgres) feature Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com> * Parse JSON request bodies in utopia-http Hyper adapter Populate Request payload from application/json (and urlencoded) bodies so /v1/users create works with Content-Type JSON, matching PHP Utopia behavior. Also fix appwrite-rust depends_on to use a literal postgresql service name (compose rejects env-var map keys). Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com> * Fix odd-length token generation panic and PHP-style query array parsing Token::generate sliced a hex string built from a floor-divided byte count, so any odd length (Users' createToken accepts 4..128) panicked and took the whole server process down. Round the byte count up like PHP's ceil() and truncate instead of slicing. The urlencoded parser also dropped http_build_query's queries[0]=..&queries[1]=.. form into a single stringly key, so array params never reached handlers, and percent-decoding widened raw bytes into Latin-1 code points. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com> * Bind Postgres scalars against the target column type i64/f64/bool ToSql impls accept exactly one OID each, so binding an integer to any column narrower than bigint failed with "error serializing parameter N" -- tokens.type is INT4, which broke createUser tokens entirely. Route the scalars through the same type-directed conversion PgFlexible already does for strings. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com> * Add query validation, search refresh, label validation for Users API Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com> * Merge stored document into partial updates in utopia-database PHP's Database::updateDocument loads the stored document and merges the caller's partial update over it. The Rust port skipped that, so every sparse update returned a stub document and rewrote the permissions rows from an empty $permissions, which made PHP's authorized reads of a Rust-updated user come back empty. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com> * Resolve session-authenticated users in the api init hook Ports the session half of request.php's user resource and api.php's admin branch: decode the session store, verify the secret against the user's sessions, and derive scopes from the confirmed team membership (admin mode) or the member role (project session). Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com> * Parse request cookies so console sessions authenticate The hyper adapter never populated Request::cookies, so the Console's a_session_console cookie was invisible to the api init hook and every SideConsole request fell back to a guest key. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com> * Share the PHP cache so Rust writes invalidate PHP reads Rust kept its own in-process cache, so a session deleted through the Rust API left the PHP server serving a user document whose cached sessions relationship still listed it, and a JWT for that session went on passing sessionActive. Point the project and platform databases at the Redis PHP already uses. The cache key carries the adapter hostname, so the adapter now also carries the DSN host PHP's pooled PDO reports; without it the two servers would key the same document differently. Writing a child document leaves the parent user cached with a stale relationship, so the session, target, token and password handlers purge the user document where the PHP handlers do. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com> * Fix formatting and clippy failures in the Rust workspace Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com> * Prefer Rust SQL engines over a PDO-shaped API Rename utopia-database's connection layer from pdo to SqlClient, connect through Postgres/Mysql/MariaDb/Sqlite adapters in platform wiring, and document that Appwrite 3.x keeps Utopia architecture while avoiding PHP runtime surfaces like PDO. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
Sync feature branch with latest base. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
Harness covers create/get/list, property updates, sessions, tokens, JWTs, targets, memberships, and delete against PHP direct, Rust direct, and Traefik→Rust. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
Replace find-all count with SQL COUNT(*), batch targets on list like PHP XList, fetch only the needed session for JWT, align delete with PHP (identities/targets only; sessions via worker), and use find_one for the email-identity uniqueness check. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
Split the combined http/{crud,hashes,properties,sessions,targets,mfa,
identities,memberships}.rs files into http/users/** matching PHP's
Http/Users/**/*.php tree. Each action file exposes create/get/update/delete/
xlist matching PHP Get/Create/Update/Delete/XList. Shared non-action helpers
live in hash_create.rs, helpers.rs, sessions/shared.rs, and mfa/shared.rs.
Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
Require one PHP action class per Rust action file under http/, matching
Modules/{Name}/Http nesting, and forbid collapsing actions into mega-files.
Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
Rust has no class inheritance, so shared create/MFA/session API lives on base.rs the way PHP subclasses call methods on Base. Remove the ad-hoc hash_create/helpers/shared modules beside HTTP actions. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
Connection::resource() previously returned a MutexGuard tied to the Connection's borrow, which can't be stored across a struct boundary. Add resource_owned() backed by parking_lot's arc_lock feature so callers can hold an owned, 'static guard to the pooled resource independent of the Connection it came from. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
MySQL's client performs blocking I/O directly on whatever thread calls it. Wrap connect/exec/exec_drop in mysql_blocking (mirrors the existing postgres_blocking) so a slow query yields the async worker thread back to the Tokio runtime instead of stalling it, matching how Postgres already behaves under load. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
Replace the single Arc<Mutex<ProjectDb>> per project (and the single Mutex<ProjectDb> for the platform DB) with a pooled ProjectDatabase backed by utopia_pools::Pool<ProjectDb> for live adapters. Every request previously serialized on one shared connection; now each project (and the platform DB) gets a pool of N connections sized from _APP_CONNECTIONS_MAX / _APP_POOL_CLIENTS / available parallelism, floored by _APP_WORKER_MAX_COROUTINES and clamped to [2, 32], mirroring PHP's app/init/registers.php pool sizing. - ProjectDb implements utopia_pools::Recover: reset/reconnect both ping the live connection so unhealthy connections are dropped and replaced instead of being handed back out. - ProjectDatabase::lock() checks a connection out of the pool synchronously (block_in_place, with a multi-thread fallback runtime for init-time callers outside Tokio) and returns a ProjectDbGuard that Derefs/DerefMuts to ProjectDb and reclaims on Drop, so existing handler call sites () don't change. - Memory adapter keeps a single Mutex<ProjectDb> (in-process, nothing to pool) via a Memory variant on ProjectDatabase/ProjectDbGuard. - warm_up_pool eagerly pops+reclaims a connection at pool creation so bad DB config fails fast at boot instead of on the first request. - state.rs / console.rs / tests updated for the new guard, which is infallible for Memory and panics with context on pool exhaustion for Pooled rather than returning a poison-recoverable Result. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
Argon2 hashing is CPU-bound and previously ran while a DB connection was checked out (create_user hashed inline while holding the lock), which, with a pool sized well below the request concurrency, would starve other requests waiting on a free connection. Introduce ResolvedPassword / base::resolve_password and call it before base::get_db()/lock() in the plaintext create-user path (http/users/create.rs) and the password update handler (http/users/password/update.rs). create_user now takes an already resolved password instead of a hasher, so it never hashes under the pool lock. create_hashed_user is unaffected: pre-hashed passwords have no hashing to move. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
ProjectDbGuard::lock() is infallible for Memory and panics with context on pool exhaustion for Pooled, so the old lock().unwrap_or_else(|e| e.into_inner()) mutex-poison recovery pattern no longer applies. Mechanical cleanup across every Users handler that touches dbForProject. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
Print the computed pool_size_from_env() next to the adapter name so operators can see how many concurrent connections dbForProject/ dbForPlatform actually have per project, instead of just the adapter name. Pin max_blocking_threads to 512 explicitly: block_in_place calls in utopia-database each borrow a blocking-pool thread for the query's duration, and with N concurrent pool checkouts across projects this headroom should not silently shrink if the Tokio default changes. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
Sync postgres Client::block_on/close panicked under Hyper's runtime, which serialized or crashed concurrent /v1/users traffic. Run connect/query/drop on OS threads without an ambient Tokio handle, size per-project pools for compose Postgres limits, raise Tokio worker_threads with the pool, and run Users handlers via finish_blocking. Adds a concurrent PHP vs Rust bench harness. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
…ase, and event helpers This commit adds three new crates: `appwrite-auth`, `appwrite-database`, and `appwrite-event`. The `appwrite-auth` crate provides authentication helpers, including API key decoding, password and phone validators, and MFA factor identifiers. The `appwrite-database` crate offers database helpers, including a custom ID validator and query helpers for common Users API lookups. The `appwrite-event` crate includes event payloads and helpers for building queue messages and generating event patterns. Each crate includes comprehensive documentation and tests to ensure functionality and compatibility with existing Appwrite features. Co-authored-by: Eldad A. Fux <eldadfux@users.noreply.github.com>
| Back | FazBrowse Home | New Git URL |
Summary
Implements the Users-first Rust migration under 3.x.x/ (long-lived secret branch rupoc). Tip: 833d0e2301.
Folded stack PRs
Database adapters
Uses the same _APP_DB_HOST / _PORT / _USER / _PASS / _SCHEMA / _APP_OPENSSL_KEY_V1 env as PHP.
Verification
Users CustomServerTest via Traefik → Rust: 50 tests green. Concurrent benches: 3.x.x/benchmarks/users/bench-concurrent.php.