mirror of
https://github.com/logos-messaging/chat-store.git
synced 2026-07-29 22:43:29 +00:00
feat: docker build for logos delivery deps
This commit is contained in:
parent
51664cdc53
commit
2239e3ab9d
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -227,6 +227,7 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
[[package]]
|
||||
name = "chat-proto"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/logos-messaging/chat_proto?rev=e05c21229a18bab655c9aec06409189447d24a6b#e05c21229a18bab655c9aec06409189447d24a6b"
|
||||
dependencies = [
|
||||
"prost",
|
||||
]
|
||||
@ -1013,6 +1014,7 @@ checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a"
|
||||
[[package]]
|
||||
name = "logos-delivery"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/logos-messaging/libchat?rev=5c55c2ee76bebd1dbd5eb4bfa95d9e71acd0fa14#5c55c2ee76bebd1dbd5eb4bfa95d9e71acd0fa14"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"crossbeam-channel",
|
||||
|
||||
16
Cargo.toml
16
Cargo.toml
@ -15,18 +15,16 @@ path = "src/main.rs"
|
||||
anyhow = "1.0"
|
||||
axum = "0.7"
|
||||
base64 = "0.22"
|
||||
# Wire schema for the delivery submissions, shared with libchat.
|
||||
# TODO: switch to `{ git = "https://github.com/logos-messaging/chat_proto", rev = "..." }`
|
||||
# once the store submission schemas land on chat_proto's main. Path dep only so
|
||||
# this builds ahead of that merge.
|
||||
chat-proto = { path = "../chat_proto/gen/rust" }
|
||||
# Wire schema for the delivery submissions, shared with libchat. Pinned to a rev
|
||||
# rather than a branch so the wire format can only change deliberately.
|
||||
chat-proto = { git = "https://github.com/logos-messaging/chat_proto", rev = "e05c21229a18bab655c9aec06409189447d24a6b" }
|
||||
clap = { version = "4", features = ["derive"] }
|
||||
ed25519-dalek = "2.2.0"
|
||||
hex = "0.4"
|
||||
# Embedded logos-delivery node for subscription-based ingestion. Path dep on
|
||||
# the sibling libchat checkout; links the native liblogosdelivery (enter the
|
||||
# libchat dev shell or set LOGOS_DELIVERY_LIB_DIR to build a runnable binary).
|
||||
logos-delivery = { path = "../libchat/extensions/logos-delivery-rust" }
|
||||
# Embedded logos-delivery node for subscription-based ingestion. Links the
|
||||
# native liblogosdelivery, which this repo's flake builds: `nix develop` exports
|
||||
# LOGOS_DELIVERY_LIB_DIR, without which the binary fails at link.
|
||||
logos-delivery = { git = "https://github.com/logos-messaging/libchat", rev = "5c55c2ee76bebd1dbd5eb4bfa95d9e71acd0fa14" }
|
||||
prost = "0.14"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
|
||||
53
Dockerfile
53
Dockerfile
@ -3,24 +3,55 @@
|
||||
########################################
|
||||
# Build stage
|
||||
########################################
|
||||
FROM rust:1-bookworm AS builder
|
||||
# Nix, not the `rust` image: the binary links the native liblogosdelivery, which
|
||||
# only nix builds. That library comes from nixpkgs' glibc (2.40), newer than
|
||||
# bookworm's, so cargo has to run against the same nixpkgs — mixing the two
|
||||
# libcs in one process does not work. Everything below therefore builds inside
|
||||
# the flake's dev shell.
|
||||
FROM nixos/nix:2.32.0 AS builder
|
||||
|
||||
WORKDIR /app
|
||||
# `filter-syscalls` off because the seccomp filter fails inside an emulated
|
||||
# (qemu) container, which is how this image gets built on arm64 hosts.
|
||||
RUN printf 'experimental-features = nix-command flakes\nfilter-syscalls = false\n' \
|
||||
>> /etc/nix/nix.conf
|
||||
|
||||
# Build dependencies first against a stub binary so the (slow) dependency
|
||||
# compilation — bundled libsqlite3 and the async stack — is cached and only
|
||||
# re-runs when Cargo.toml/Cargo.lock change.
|
||||
WORKDIR /src
|
||||
|
||||
# The native library first and on its own layer: it is by far the slowest part
|
||||
# of the build and only changes when the flake pins do.
|
||||
COPY flake.nix flake.lock ./
|
||||
RUN nix --accept-flake-config build .#logos-delivery --no-link
|
||||
|
||||
# Then the Rust dependency graph, against a stub binary, so the (also slow)
|
||||
# dependency compile is cached and only re-runs when Cargo.toml/Cargo.lock change.
|
||||
COPY Cargo.toml Cargo.lock ./
|
||||
RUN mkdir src \
|
||||
&& echo "fn main() {}" > src/main.rs \
|
||||
&& cargo build --release --locked \
|
||||
&& nix --accept-flake-config develop --command cargo build --release --locked \
|
||||
&& rm -rf src target/release/deps/chat_store* target/release/chat-store
|
||||
|
||||
# Now build the real binary; dependency artifacts above are reused. `migrations/`
|
||||
# is needed at build time too — `sqlx::migrate!()` embeds the .sql files.
|
||||
# Now the real binary; dependency artifacts above are reused. `migrations/` is
|
||||
# needed at build time too — `sqlx::migrate!()` embeds the .sql files.
|
||||
COPY src ./src
|
||||
COPY migrations ./migrations
|
||||
RUN cargo build --release --locked --bin chat-store
|
||||
RUN nix --accept-flake-config develop --command \
|
||||
cargo build --release --locked --bin chat-store
|
||||
|
||||
# Collect what the binary loads at runtime. logos-delivery's build.rs stamps
|
||||
# liblogosdelivery with an absolute store path as its soname, so the binary
|
||||
# names it — along with its ELF interpreter and rpath — by absolute /nix/store
|
||||
# path. Seeding the closure from those three is all the runtime image needs.
|
||||
RUN nix --accept-flake-config develop --command sh -c '\
|
||||
bin=target/release/chat-store; \
|
||||
{ patchelf --print-needed "$bin"; \
|
||||
patchelf --print-interpreter "$bin"; \
|
||||
patchelf --print-rpath "$bin" | tr ":" "\n"; } \
|
||||
| grep "^/nix/store/" \
|
||||
| sed "s|\(/nix/store/[^/]*\).*|\1|" | sort -u \
|
||||
| xargs nix-store --query --requisites | sort -u > /closure.txt' \
|
||||
&& mkdir -p /output/nix/store \
|
||||
&& cp target/release/chat-store /output/chat-store \
|
||||
&& cp -a $(cat /closure.txt) /output/nix/store/
|
||||
|
||||
########################################
|
||||
# Runtime stage
|
||||
@ -31,7 +62,9 @@ RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY --from=builder /app/target/release/chat-store /usr/local/bin/chat-store
|
||||
# The nix closure the binary resolves by absolute path, then the binary itself.
|
||||
COPY --from=builder /output/nix/store /nix/store
|
||||
COPY --from=builder /output/chat-store /usr/local/bin/chat-store
|
||||
|
||||
# Matches the default --bind 0.0.0.0:8080.
|
||||
EXPOSE 8080
|
||||
|
||||
41
README.md
41
README.md
@ -8,14 +8,14 @@ its own.
|
||||
Standalone service that caches MLS KeyPackages keyed by **`device_id`**, so a
|
||||
client can fetch a contact's keypackage without an out-of-band exchange.
|
||||
Throwaway by design: scheduled to be replaced by a λLEZ-based service in v0.3,
|
||||
with no libchat-core dependency (the embedded logos-delivery node comes from the
|
||||
sibling libchat checkout's transport crate).
|
||||
with no libchat-core dependency (the embedded logos-delivery node comes from
|
||||
libchat's transport crate, pulled in as a pinned git dependency).
|
||||
|
||||
Submissions arrive on either of two write paths feeding the same verification +
|
||||
storage pipeline:
|
||||
|
||||
- **HTTP POST** (`/v0/keypackage`, `/v0/account`) — synchronous and acknowledged;
|
||||
- **logos-delivery subscription** — clients publish the same JSON bodies on the
|
||||
- **logos-delivery subscription** — clients publish protobuf submissions on the
|
||||
store's content topics and the server picks them up from the network (see
|
||||
[Delivery ingestion](#delivery-ingestion)).
|
||||
|
||||
@ -56,11 +56,17 @@ exactly one way — no delimiter, even though `key_package` is arbitrary bytes.
|
||||
|
||||
## Building & running
|
||||
|
||||
Building a runnable binary links the native `liblogosdelivery`, which this
|
||||
repo's flake builds. The dev shell exports `LOGOS_DELIVERY_LIB_DIR` for you:
|
||||
|
||||
```bash
|
||||
nix develop # or set LOGOS_DELIVERY_LIB_DIR yourself
|
||||
cargo build --release
|
||||
./target/release/chat-store # binds 0.0.0.0:8080, db ./chat-store.db
|
||||
```
|
||||
|
||||
Without the library, `cargo check` and `clippy` still pass — only linking fails.
|
||||
|
||||
| Flag | Default | Description |
|
||||
|------|---------|-------------|
|
||||
| `--bind <addr>` | `0.0.0.0:8080` | HTTP bind address |
|
||||
@ -74,10 +80,6 @@ cargo build --release
|
||||
|
||||
Logs via `RUST_LOG` (default `info`).
|
||||
|
||||
Building a runnable binary links the native `liblogosdelivery`; enter the
|
||||
libchat dev shell (`nix develop` in the sibling checkout) or set
|
||||
`LOGOS_DELIVERY_LIB_DIR` to the directory containing the library.
|
||||
|
||||
## Delivery ingestion
|
||||
|
||||
Unless `--no-delivery` is given, the server runs an embedded logos-delivery
|
||||
@ -88,12 +90,17 @@ node and subscribes to two content topics:
|
||||
/logos-chat/1/store-account-v0/proto account device-list submissions
|
||||
```
|
||||
|
||||
Each received message is the same JSON body as the corresponding POST endpoint
|
||||
(below) and goes through identical signature verification and storage rules.
|
||||
Each received message is a protobuf `KeyPackageSubmissionV1` or
|
||||
`AccountSubmissionV1` — matching the `/proto` topic suffix — carrying the same
|
||||
fields as the corresponding POST body and going through identical signature
|
||||
verification and storage rules. The schemas live in
|
||||
[chat_proto](https://github.com/logos-messaging/chat_proto) (`protos/store.proto`),
|
||||
pinned by rev in `Cargo.toml` so the wire format only changes deliberately.
|
||||
|
||||
Publishing is fire-and-forget on the client side: rejected submissions are only
|
||||
logged by the server, which the trust model can afford because consumers verify
|
||||
every bundle on retrieval anyway. libchat's `DeliveryRegistry` publishes on
|
||||
these topics when its publish mode is set to delivery.
|
||||
every bundle on retrieval anyway. libchat's `ContactRegistry` publishes on these
|
||||
topics when constructed with `RegistryPublishMode::Delivery`.
|
||||
|
||||
## Docker
|
||||
|
||||
@ -105,6 +112,13 @@ docker build -t chat-store .
|
||||
docker run --rm -p 8080:8080 -v chat-store-data:/data chat-store
|
||||
```
|
||||
|
||||
The build runs inside nix, because the binary links `liblogosdelivery` and the
|
||||
nixpkgs glibc it is built against is newer than bookworm's — so cargo has to run
|
||||
against that same nixpkgs. The runtime image is still `debian:bookworm-slim`,
|
||||
carrying only the nix store closure the binary resolves by absolute path. The
|
||||
first build compiles the native library from source and takes a long time;
|
||||
afterwards it is a cached layer that only changes with `flake.lock`.
|
||||
|
||||
The image runs the binary with `--bind 0.0.0.0:8080 --db /data/chat-store.db`
|
||||
by default; override the `CMD` to change flags, e.g.:
|
||||
|
||||
@ -262,6 +276,11 @@ A non-zero exit from `chat-cli` means the server rejected the submission — e.g
|
||||
the signature failed verification. `GET /v0/keypackage/{device_id}` returns `200`
|
||||
for a registered device and `404` otherwise.
|
||||
|
||||
Add `--registry-publish delivery` to those `chat-cli` invocations to exercise
|
||||
the delivery write path instead of the HTTP POST API. Publishing is then
|
||||
fire-and-forget, so `chat-cli` exits `0` regardless and the bundles appear in
|
||||
the database only once the server has received and accepted them.
|
||||
|
||||
## Benchmark
|
||||
|
||||
The bundled [`benchmark`](examples/benchmark.rs) performs an end-to-end load
|
||||
|
||||
115
flake.lock
generated
Normal file
115
flake.lock
generated
Normal file
@ -0,0 +1,115 @@
|
||||
{
|
||||
"nodes": {
|
||||
"logos-delivery": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"rust-overlay": "rust-overlay",
|
||||
"zerokit": "zerokit"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1779915920,
|
||||
"narHash": "sha256-rcIgP6MVyUoNEH6xpdLrZtfd4OcvIcMUloX4IhRq5AA=",
|
||||
"owner": "logos-messaging",
|
||||
"repo": "logos-delivery",
|
||||
"rev": "74057c66224f43b4aa27b42033d4ed52eed5c7a7",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "logos-messaging",
|
||||
"repo": "logos-delivery",
|
||||
"rev": "74057c66224f43b4aa27b42033d4ed52eed5c7a7",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1782231800,
|
||||
"narHash": "sha256-AyPvq+cx3JFicSd687dhhIfUMryk9PUFmHnofBjalMg=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "6f5e2d2ea55618c5197ce40e346f205c35d2213e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "6f5e2d2ea55618c5197ce40e346f205c35d2213e",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"logos-delivery": "logos-delivery",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"logos-delivery",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1775099554,
|
||||
"narHash": "sha256-3xBsGnGDLOFtnPZ1D3j2LU19wpAlYefRKTlkv648rU0=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "8d6387ed6d8e6e6672fd3ed4b61b59d44b124d99",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"rust-overlay_2": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"logos-delivery",
|
||||
"zerokit",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1771211437,
|
||||
"narHash": "sha256-lcNK438i4DGtyA+bPXXyVLHVmJjYpVKmpux9WASa3ro=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "c62195b3d6e1bb11e0c2fb2a494117d3b55d410f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"zerokit": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"logos-delivery",
|
||||
"nixpkgs"
|
||||
],
|
||||
"rust-overlay": "rust-overlay_2"
|
||||
},
|
||||
"locked": {
|
||||
"owner": "vacp2p",
|
||||
"repo": "zerokit",
|
||||
"rev": "5e64cb8822bee65eed6cf459f95ae72b80c6ba63",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "vacp2p",
|
||||
"repo": "zerokit",
|
||||
"rev": "5e64cb8822bee65eed6cf459f95ae72b80c6ba63",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
62
flake.nix
Normal file
62
flake.nix
Normal file
@ -0,0 +1,62 @@
|
||||
{
|
||||
description = "chat-store - keypackage and account registry for Logos Chat";
|
||||
|
||||
# Repeated from the logos-delivery flake: only the top-level flake's nixConfig
|
||||
# is honoured, so an input's substituters do nothing for us.
|
||||
nixConfig = {
|
||||
extra-substituters = [ "https://nix-cache.status.im/" ];
|
||||
extra-trusted-public-keys = [
|
||||
"nix-cache.status.im-1:x/93lOfLU+duPplwMSBR+OlY4+mo+dCN7n0mr4oPwgY="
|
||||
];
|
||||
};
|
||||
|
||||
inputs = {
|
||||
# Both revs are exactly what libchat's flake.lock pins, and they only work
|
||||
# as a pair: logos-delivery's derivation wants `nim-2_2`, which newer
|
||||
# nixos-unstable-small no longer has. Bump the two together.
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/6f5e2d2ea55618c5197ce40e346f205c35d2213e";
|
||||
# `follows` keeps the library and the toolchain that links it on a single
|
||||
# glibc — the Docker build depends on that.
|
||||
logos-delivery = {
|
||||
url = "github:logos-messaging/logos-delivery/74057c66224f43b4aa27b42033d4ed52eed5c7a7";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, logos-delivery }:
|
||||
let
|
||||
systems = [ "aarch64-darwin" "x86_64-darwin" "aarch64-linux" "x86_64-linux" ];
|
||||
forAllSystems = f: nixpkgs.lib.genAttrs systems (system: f {
|
||||
inherit system;
|
||||
pkgs = import nixpkgs { inherit system; };
|
||||
});
|
||||
in
|
||||
{
|
||||
# The one thing this flake exists for: the native library the
|
||||
# `logos-delivery` crate links. Same override as libchat's flake — no
|
||||
# postgres archive driver, no Nim dlopen debug hooks, quiet logs.
|
||||
packages = forAllSystems ({ system, ... }: {
|
||||
logos-delivery = logos-delivery.packages.${system}.liblogosdelivery.override {
|
||||
enablePostgres = false;
|
||||
enableNimDebugDlOpen = false;
|
||||
chroniclesLogLevel = "FATAL";
|
||||
};
|
||||
default = self.packages.${system}.logos-delivery;
|
||||
});
|
||||
|
||||
devShells = forAllSystems ({ pkgs, system, ... }:
|
||||
let logosDeliveryLib = self.packages.${system}.logos-delivery;
|
||||
in {
|
||||
default = pkgs.mkShell {
|
||||
nativeBuildInputs = [ pkgs.cargo pkgs.rustc pkgs.pkg-config ]
|
||||
# logos-delivery's build.rs rewrites the shipped library's soname
|
||||
# with patchelf in its default (absolute-path) linking mode.
|
||||
++ pkgs.lib.optionals pkgs.stdenv.isLinux [ pkgs.patchelf ];
|
||||
buildInputs = [ logosDeliveryLib ];
|
||||
shellHook = ''
|
||||
export LOGOS_DELIVERY_LIB_DIR="${logosDeliveryLib}/lib"
|
||||
'';
|
||||
};
|
||||
});
|
||||
};
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user