Architecture¶
OpenPak replaces the online side of many consoles with one network. The shape that makes that possible is simple: one console-agnostic core, a thin adapter per console family, and game servers that trust the core's identity.
consoles and emulators (each speaks its own native protocols)
Switch Wii U / 3DS Wii / DS Xbox / 360 PS3 phone app
│ │ │ │ │ │
┌────┴────┐ ┌─────┴─────┐ ┌─────┴────┐ ┌──────┴─────┐ ┌────┴─────┐ ┌────┴────┐
│ Switch │ │ Wii U/3DS │ │ WFC │ │ Xbox and │ │ PS3 │ │ website │
│ adapter │ │ adapters │ │ server │ │ 360 svcs │ │ adapter │ │ + API │
└────┬────┘ └─────┬─────┘ └─────┬────┘ └──────┬─────┘ └────┬─────┘ └────┬────┘
└─────────────┴──────────────┴───── internal gRPC ────────┴─────────────┘
│
┌───────────┴───────────┐
│ account core │ accounts, sessions, links,
│ (knows no consoles) │ friends, presence, invitations,
└───────────┬───────────┘ moderation, events
│
platform-neutral services: saves · news · mods · chat · voice · connectivity · status
│
game servers: NEX/PRUDP · NPLN · Photon-compatible · per-publisher backends
The account core knows nothing about consoles¶
The account core holds accounts, web sessions, email verification and recovery, two-step sign-in, the friend graph, presence, invitations, moderation and an event stream. It has no console protocol code at all, and a guard test fails the build if a console package is ever imported.
What it has instead is a generic link: a binding between an account and a subject in a
namespace (switch, wfc, and so on). The link moves through a small state machine (pending,
active, revoking, revoked). The core does not know what a Switch user id or a WFC profile is; it
stores the subject an adapter gives it.
That buys three things:
- Adding a console never touches the core. A new family is a new adapter.
- One identity everywhere. Friends, blocks, presence and bans live in one place, so a friend added on one console is a friend on all of them, and a ban applies on every platform.
- Every new account gets an identity on every network, created automatically, so a friend on one console can see you on another without extra steps.
The core is only reachable on the internal network. Its gRPC calls are authenticated with an internal key and fail closed without it.
Adapters¶
An adapter speaks one console family's native protocols on one side and the core's contracts on the other. It owns that family's identifiers (user ids, friend codes, tokens), mints them once per account, and never lets them migrate.
| Family | Adapter repositories |
|---|---|
| Switch | nx-baas (accounts, device auth, console link, friends), with nx-shop, nx-penne, nx-pctl, nx-bcat split out by service |
| Wii U and 3DS | nn-account, nn-friends, plus content services nn-boss, nn-juxtaposition, nn-soap |
| Wii and DS | nn-wfc |
| PS3 | np-account, np-trophy |
| Xbox 360 | x360-*, one repository per service |
| Original Xbox | xb-*, one repository per service |
Adapters answer in the console's own words. A console parses replies strictly and often reports a malformed reply with nothing more than an error code, so adapters keep recorded, value-stripped reply shapes in their tests and compare against them.
Platform-neutral services¶
| Service | What it does |
|---|---|
website |
openpak.org: the account portal, the title catalogue, the public mobile API (OpenAPI 3.1), the network profile and the admin pages. |
saves |
Cloud saves, with optional storage owned by the player. |
news |
News channels delivered to consoles. |
mods |
The mods catalogue. |
chat |
One neutral message store for every surface. |
voice |
Voice chat for the phone app. |
connectivity |
Multiplayer endpoint leases, TURN credentials and relay allocation. |
status |
The status page, run away from the machines it watches. |
Console-facing handlers from these services are mounted by the adapter that the console already talks to, rather than getting console-facing hostnames of their own.
Game servers¶
Game servers serve the online part of specific games. Most of them are one shared host per protocol family, with one small package per game:
- NEX/PRUDP (
nex,switch-nex): one image; a container runs one title. - NPLN (
npln): one image; a container runs one title. - Per-publisher backends (
photon,demonware,eos,t17,klei,playfaband others): one process for every title that uses that backend.
Game servers never keep their own accounts. They trust tokens signed for OpenPak identities, so a player is the same person on every server.
How a console finds OpenPak¶
- Network profile.
GET https://openpak.org/api/v1/network/profile?platform=<name>says which names a client should send to OpenPak. It is generated from the routing the server actually runs, so it cannot drift from reality. - Signed redirect ceiling. Clients only accept names inside a signed list of domain families, so a compromised server cannot widen what consoles redirect. See signed redirect ceiling.
- Console DNS. For consoles whose only setting is a DNS server, a resolver answers from the same profile, so real consoles and emulators cannot drift apart.
- Trust. Consoles trust an OpenPak certificate authority, installed by the console-side tool
(
openpak-nro, Inkay, nimbus) or by the emulator.
Events, not polling the database¶
The core emits durable events (friend_requested, friend_accepted, invitation_sent,
account_banned and others) inside the same transaction that commits the change, so a
notification is never promised for something that did not happen. Adapters follow the stream
to push notifications to online consoles and to revoke tokens when an account is banned or a
link is revoked.
Health¶
Every service answers "is it running" over HTTP (/healthz, and /readyz where it has
dependencies), so nothing has to infer health from a socket. UDP-only services expose a small
HTTP health port next to their game ports.
One repository per service¶
Each service is its own repository with its own README, changelog, tests, image and release.
Shared Go code is a library repository consumed with a replace directive and a committed
vendor/ tree, so every repository builds alone. See repositories.