Overview
This document provides an overview of the main Eternaltwin repository.
Eternaltwin is a relatively complex project since it acts as a platform to support other games. In particular, it is designed to be easily embedded in other projects through different clients.
Repository layout
| Directory | Contents |
|---|---|
bin/ | The eternaltwin executable, the only Rust binary that ships |
crates/ | The Rust libraries, about forty of them |
xtask/ | Development tasks run with cargo xtask |
packages/ | The Node packages, including the Angular website |
sdk/node/ | The Node SDK published to npm |
sdk/php/ | The PHP SDK published to Packagist |
clients/ | Kotlin, Ruby and TypeScript clients for the Eternaltwin API |
examples/ | Small integrations, one per supported language |
db/, dns/ | Database and DNS support files |
docs/ | This documentation, in Markdown |
test-resources/ | Fixtures shared by the tests |
Dependencies
- Red (or purple): deployed in Eternaltwin
- Blue (or purple): deployed in the game
The graph is generated from the project structure by cargo xtask codegen structure, which writes
dependencies.dot; render.sh turns it into dependencies.svg with Graphviz. The committed
image is out of date. It predates seven crates, which are therefore missing along with their
edges: captcha_store, composer_metadata_minifier, discord_client, eternaltwin_app_client,
eternaltwin_app_store, gitlab_user_client and user_link_store. On the PHP side it is missing
eternaltwin/etwin and eternaltwin/test-server.
Rust crates
Every crate lives in crates/, except the executable (bin/) and the task runner (xtask/). The
directory name and the crate name differ in most cases: the directory is short (user_store), the
crate is prefixed (eternaltwin_user_store).
Types and interfaces
core(eternaltwin_core) is the crate everything else depends on. It defines the domain types and, for each domain, the traits the rest of the code is written against:UserStore,ForumStore,HammerfestClient,TwinoidStore, and so on. Its modules follow the domains:app,auth,captcha,dinoparc,dinorpg,discord,forum,gitlab,hammerfest,job,link,mailer,opentelemetry,popotamo,twinoid,user, plus cross-cutting helpers such asclock,password,temporal,tokenanduuid.constants(eternaltwin_constants) holds generated constant tables, such as the Dinoparc item and location lists.config(eternaltwin_config) defines the configuration schema, its per-profile defaults, and the file lookup order.password,logandserde_toolsare small shared utilities: password hashing, structured logging, andserdehelpers.
Most interfaces have several implementations and the right one is picked depending on context. For example, storage can either use memory or Postgres. Clients can use the network or a mock target.
Stores
Each store crate implements one core trait, usually twice: mem.rs for the in-memory version
and pg.rs for Postgres. Several also have a trace.rs wrapper that adds telemetry, and
test.rs holds the shared test suite both implementations must pass.
eternaltwin_app_store, auth_store, captcha_store, dinoparc_store, forum_store,
hammerfest_store, job_store, link_store, oauth_provider_store, token_store,
twinoid_store, user_link_store, user_store.
twinoid_store and eternaltwin_app_store also have a SQLite implementation.
Database plumbing
squirrel(eternaltwin_squirrel) manages SQL schema migrations. It is generic and reusable by other Eternaltwin projects.db_schema(eternaltwin_db_schema) holds the Eternaltwin schema itself, with thecreate,upgradeanddropscripts.postgres_tools(eternaltwin_postgres_tools) holds the Postgres helpers, in particular the macro building the snapshot upsertion query described in Archive.populate(eternaltwin_populate) inserts the seed data declared in the[seed]configuration sections.
Clients for external services
eternaltwin_app_clienttalks to an Eternaltwin server on behalf of a registered application.client(eternaltwin_client) is the generic client for the Eternaltwin API, used by the tests and by embedders.discord_clientandgitlab_user_clientread the profile of a user who signed in through Discord or GitLab.oauth_clientimplements the RFC 6749 client side, used for those sign-in flows.mt_dns(eternaltwin_mt_dns) resolves Motion Twin's domains, including the ones whose DNS records are gone (dead.rs) and the ones still live (live.rs).
Each of these follows the same shape as the stores: an http implementation, a mem one for
tests, and often a trace wrapper.
Services
services(eternaltwin_services) holds the shared high-level business logic, one module per domain, plus the background jobs injob/(archiving Twinoid users, scraping Hammerfest profiles, themes and threads).system(eternaltwin_system) is the assembly point: it reads the configuration and builds every store, client and service, picking the memory or Postgres implementation for each.mailerandemail_formatterrender and send the outbound emails.
HTTP transport
rest(eternaltwin_rest) implements the HTTP interfaces: the REST API under/api/v1(app,apps,archive,auth,captcha,clock,config,forum,job,oauth_clients,oauth_consent,outbound_email,users), the "backend-for-frontend" (BFF) API under/actions, and the telemetry intake under/v1/logsand/v1/traces.app(eternaltwin_app) packages the built web application files so an embedder can serve the Eternaltwin frontend from its own binary. It is published bycargo xtask publish, never by hand.
Tooling
cli(eternaltwin_cli) implements the command line interface:backend,config,db,dump,job,start,version.bin/is the thinmainthat calls into it, and produces theeternaltwinexecutable.cargo_client,npm_client,packagist_clientandgitlab_clientquery the registries during a release, to find out what is already published.composer_metadata_minifieris a Rust port of the Composer package of the same name, needed to read Packagist's responses.scraper_tools(eternaltwin_scraper_tools) holds helpers for thescraperHTML crate. It is still a workspace member, but no crate depends on it since the scraping clients were removed in 0.13.0. See Archive.
xtask
xtask is a support crate for scripts used during development. Run it with cargo xtask from the
repository root. Its subcommands are codegen, dns, docs, precompile, publish, release
and backend (which analyzes the project structure). See Publish for the release
and publication ones.
Node packages
packages/* and sdk/node/* are Yarn workspaces of the root package.json.
| Package | Directory | Role |
|---|---|---|
@eternaltwin/website | packages/website | The Angular frontend, and the only thing not in Rust |
@eternaltwin/core | packages/core | TypeScript types and interfaces for Eternaltwin |
@eternaltwin/cli | packages/cli | Node command line interface |
@eternaltwin/exe | packages/exe | Wrapper picking the right precompiled executable |
@eternaltwin/exe-* | packages/exe-* | One package per target, each with a precompiled binary |
@eternaltwin/koa-proxy | packages/koa-proxy | Proxy router for the Koa web framework |
@eternaltwin/mt-dns | packages/mt-dns | Custom DNS resolver for Motion Twin's websites |
@eternaltwin/oauth-client-http | packages/oauth-client-http | OAuth client for Eternaltwin and Twinoid |
@eternaltwin/pg-db | packages/pg-db | Helpers for Postgres databases |
@eternaltwin/client-node | sdk/node/client | Eternaltwin client for Node |
@eternaltwin/sdk | sdk/node/sdk | The SDK, without the executable |
PHP packages
sdk/php holds the Composer packages: eternaltwin/etwin (the client), eternaltwin/cli,
eternaltwin/exe, eternaltwin/path-tools and eternaltwin/test-server.
Other clients
clients/ holds the API clients maintained for languages without an SDK directory: kotlin,
ruby and typescript. examples/ holds a small integration per language.