Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
afe68d5
getting started with REST implementation
peerchemist Jun 12, 2026
6993d31
CLI args for REST
peerchemist Jun 12, 2026
0044c03
shelf and shelf_router deps
peerchemist Jun 12, 2026
0147dc3
Implement package logging
peerchemist Jun 15, 2026
e5178aa
Add CLI log level option
peerchemist Jun 15, 2026
67980f0
Enable REST API in Docker
peerchemist Jun 16, 2026
e521c4b
Add gRPC access debug logs
peerchemist Jun 16, 2026
3ae2ba2
Document REST deployment and logging
peerchemist Jun 16, 2026
614ac89
Slim dockerfile
peerchemist Jun 16, 2026
06611f8
Add debug logging for REST requests
peerchemist Jun 17, 2026
a9286f3
Create Docker output directory before compile
peerchemist Jun 17, 2026
f7da65b
Default gRPC config port to 50051
peerchemist Jun 17, 2026
cde17d0
Add SSE event propagation diagnostics
peerchemist Jun 17, 2026
2ecf987
Allow disabling REST CORS headers
peerchemist Jun 17, 2026
f2d4c59
Replace SSE event stream with websockets
peerchemist Jun 18, 2026
914039e
ran formatting
peerchemist Jun 18, 2026
b26a609
ran dart fix --apply
peerchemist Jun 18, 2026
bbbecc3
Inject server logger dependencies
peerchemist Jun 18, 2026
0ff1616
Merge branch 'master' of https://github.com/peercoin/noosphere_roast_…
peerchemist Jun 19, 2026
63e04a0
Require logger for server state
peerchemist Jun 19, 2026
7b42d17
Avoid redundant session list materialization
peerchemist Jun 19, 2026
4b4ad50
Simplify server API handler construction
peerchemist Jun 19, 2026
080a0cd
Don't need backward compatibility for the clients, SSE won't come back.
peerchemist Jun 21, 2026
4bc0726
Simplify REST transport helpers
peerchemist Jun 21, 2026
6f30870
Add this comment about the REST api
peerchemist Jun 21, 2026
3710679
refactor: simplify REST/gRPC transport layer
peerchemist Jun 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ RUN dart pub get

COPY . .
RUN dart pub get --offline
RUN dart compile exe bin/grpc_server.dart -o /out/noosphere_roast_server
RUN mkdir -p /out \
&& dart compile exe bin/grpc_server.dart -o /out/noosphere_roast_server

FROM docker.io/library/debian:bookworm-slim

Expand All @@ -91,7 +92,7 @@ COPY --from=frosty-build /out/libfrosty_rust.so /app/build/libfrosty_rust.so
COPY --from=secp256k1-build /out/libsecp256k1.so /app/build/libsecp256k1.so
ENV LD_LIBRARY_PATH="/app/build:/usr/local/lib"

EXPOSE 50051
EXPOSE 50051 8080

ENTRYPOINT ["/app/noosphere_roast_server", "--config"]
CMD ["/config/server.yaml"]
CMD ["/config/server.yaml", "--rest-address", "0.0.0.0", "--rest-port", "8080"]
164 changes: 160 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,34 @@ A server can be run from a given `GrpcConfig` YAML file using `dart run
noosphere_roast_server:grpc_server --config your_config_file_here.yaml`.
Alternatively a server may be created using the package as a library.

The server emits `info` logs by default. Use `--log-level` to choose one of
`trace`, `debug`, `info`, `warning`, `error`, `fatal`, or `off`:

```sh
dart run noosphere_roast_server:grpc_server \
--config your_config_file_here.yaml \
--log-level debug
```

REST/WebSocket can be enabled for browser clients with `--rest-port`:

```sh
dart run noosphere_roast_server:grpc_server \
--config your_config_file_here.yaml \
--rest-port 8080 \
--rest-allow-origin '*'
```

`--rest-allow-origin '*'` is convenient for local testing, but production
deployments should set `--rest-allow-origin` to the exact frontend origin that
will access the REST/WebSocket API, for example `https://app.example.com`.

Use `--rest-address 0.0.0.0` when the REST/WebSocket listener must be reachable from
outside the process namespace, such as from a container port mapping. The
default REST/WebSocket bind address is `localhost`.

The REST/WebSocket API shape is documented in [REST_API_SPEC.md](REST_API_SPEC.md).

## Podman / Docker

Build the image from this repository:
Expand All @@ -16,6 +44,10 @@ Build the image from this repository:
podman build -t noosphere-roast-server .
```

Rebuild the image after changing local source. The Dockerfile copies this local
repository into the image with `COPY . .`, so an old image will not contain
recent CLI, logging, or REST changes.

The Dockerfile builds `libfrosty_rust.so` from `peercoin/frosty` `v3.0.0`,
matching the current `frosty` dependency, and `libsecp256k1.so` from
`peercoin/secp256k1-coinlib` `v0.7.0`, matching the current `coinlib`
Expand All @@ -33,10 +65,20 @@ Run the server with a mounted YAML configuration:
```sh
podman run --rm \
-p 50051:50051 \
-p 8080:8080 \
-v "$PWD/config.yaml:/config/server.yaml:ro,Z" \
noosphere-roast-server
```

The container starts both gRPC and REST/WebSocket by default. gRPC listens on the port
from the YAML config, or `50051` when `port` is omitted. REST/WebSocket listens on
container port `8080`.

Port mapping syntax is `host_port:container_port`. If the YAML config says
`port: 443`, the gRPC server listens on container port `443`, so map it with
`-p 50051:443` if clients should connect to host port `50051`. If the YAML
config omits `port` or says `port: 50051`, use `-p 50051:50051`.

The `:Z` suffix relabels the mounted config file so Podman can read it on
SELinux-enforcing hosts. Use `:z` instead if the same config file must be
shared by multiple containers.
Expand All @@ -46,13 +88,127 @@ To use a different in-container config path, pass it as the command:
```sh
podman run --rm \
-p 50051:50051 \
-p 8080:8080 \
-v "$PWD/config.yaml:/app/config.yaml:ro,Z" \
noosphere-roast-server /app/config.yaml
noosphere-roast-server \
/app/config.yaml --rest-address 0.0.0.0 --rest-port 8080
```

### REST/WebSocket With CORS

For local testing, allow any browser origin and enable debug logs:

```sh
podman run --rm \
-p 50051:50051 \
-p 8080:8080 \
-v "$PWD/config.yaml:/config/server.yaml:ro,Z" \
noosphere-roast-server \
/config/server.yaml \
--rest-address 0.0.0.0 \
--rest-port 8080 \
--rest-allow-origin '*' \
--log-level debug
```

For production, replace `'*'` with the frontend origin that loads the web app:

```sh
--rest-allow-origin https://app.example.com
```

Only one layer should emit CORS headers. If a reverse proxy such as Caddy is
already adding `Access-Control-Allow-Origin`, run the backend with
`--rest-disable-cors` instead. Otherwise browsers will reject responses with a
combined value such as `*, *`.

### Caddy Reverse Proxy

Bind container ports to localhost when Caddy runs on the same host:

```sh
podman run --rm \
-p 127.0.0.1:50051:50051 \
-p 127.0.0.1:8080:8080 \
-v "$PWD/config.yaml:/config/server.yaml:ro,Z" \
noosphere-roast-server \
/config/server.yaml \
--rest-address 0.0.0.0 \
--rest-port 8080 \
--rest-allow-origin https://app.example.com \
--log-level info
```

REST/WebSocket on a dedicated API hostname:

```caddyfile
api.example.com {
reverse_proxy 127.0.0.1:8080 {
flush_interval -1
}
}
```

Do not add CORS headers in both Caddy and the backend. Either let the backend
handle CORS with `--rest-allow-origin`, or let Caddy handle it and run the
backend with `--rest-disable-cors`.

If the browser frontend is served from the same hostname and REST is under a
prefix, strip the prefix before proxying:

```caddyfile
app.example.com {
handle_path /api/noosphere/* {
reverse_proxy 127.0.0.1:8080 {
flush_interval -1
}
}

root * /srv/app
file_server
}
```

### Ngrok For REST/WebSocket Testing

Expose the REST/WebSocket port, not the gRPC port:

```sh
ngrok http 8080
```

Use the printed HTTPS URL as the REST base URL in the frontend. The websocket
event stream will be under:

```text
wss://<ngrok-host>/sessions/<sid>/events
```

### Logging

Use `--log-level debug` when diagnosing frontend connectivity:

```sh
--log-level debug
```

At `info`, the server logs lifecycle and coordinator state changes such as
startup, auth challenges, participant login/logout, DKG requests, signature
completion, and shutdown.

At `debug`, the gRPC transport also logs request receipt/completion and event
stream lifecycle, for example:

```text
gRPC login received
gRPC login completed
gRPC fetchEventStream opened for participant ...
```

The image builds the `frosty` and `secp256k1-coinlib` native libraries during
the container build and copies `libfrosty_rust.so` and `libsecp256k1.so` into
`/app/build`.
If shared coordinator logs appear but no `gRPC ... received` logs appear while
running with `--log-level debug`, the frontend is probably using REST or the
gRPC request is not reaching this container. Check the configured client port,
container port mapping, firewall, and any reverse proxy.

The same commands also work with Docker by replacing `podman` with `docker`.

Expand Down
Loading
Loading