Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ Who publishes:

- **casaos** POSTs `casaos:system:utilization` every 5 seconds over loopback — CPU, memory, network, disks — plus `casaos:file:operate` while a file operation runs.
- **local-storage** publishes `local-storage:disk:added` and its siblings, built from kernel uevents as drives appear and disappear.
- **app-management** publishes `app:*` events — install progress, start, stop, errors — over the unix socket at `/tmp/message-bus.sock` rather than the TCP port.
- **app-management** publishes `app:*` events — install progress, start, stop, errors — over the unix socket at `/var/run/casaos/message-bus.sock` rather than the TCP port.

Who subscribes: the dashboard, over socket.io at `/v2/message_bus/socket.io/`. Its CPU, network and disk widgets redraw on each `casaos:system:utilization`; app cards follow `app:apply-changes-begin`, `app:start-end` and the rest. A plain websocket subscription to one source is also available at `GET /v2/message_bus/event/{source_id}`.

Delivery is fire and forget. An event nobody is subscribed to is dropped, not queued, and there is no replay — the 5-second telemetry makes a missed frame cheap.

The service also owns the YSK cards on the dashboard — task and notice cards — served at `/v2/message_bus/ysk`. That is the only state it keeps of its own.

Requests carry a CasaOS JWT. Loopback alone is not trusted. Three kinds of request skip the token: those on the unix socket, which only root can open; those from loopback with `Authorization: Internal <secret>`, the per-boot secret the gateway writes to `/var/run/casaos/internal.secret` (root only); and websocket upgrades on the four subscribe routes — `GET /event/{source_id}`, `GET /action/{source_id}`, `GET /socket.io` and `GET /socket.io/` — because the dashboard subscribes without a token. Whoever reaches those routes can read the event stream; every other route, socket.io polling included, needs the token.
Every request carries a CasaOS JWT in `Authorization`, subscriptions included. Loopback alone is not trusted. Two kinds of request skip the token: those on the unix socket, which only root can open, and those from loopback with `Authorization: Internal <secret>`, the per-boot secret the gateway writes to `/var/run/casaos/internal.secret` (root only) — how user-service subscribes. Browsers cannot set headers on a WebSocket, so the subscription routes — `GET /event/{source_id}`, `GET /action/{source_id}` and `GET`/`POST` on `/socket.io` and `/socket.io/`, websocket and polling alike — also take the JWT from the `token` query parameter, as the dashboard sends it. Every other route ignores that parameter. The access log records the request path without its query string, so the token never reaches the log.

## Where things live

Expand All @@ -32,7 +32,7 @@ Requests carry a CasaOS JWT. Loopback alone is not trusted. Three kinds of reque
| `/var/run/casaos/message-bus.db` | registered event and action types; runtime only, and services re-register on start |
| `/var/lib/casaos/db/message-bus.db` | YSK cards and settings, kept across reboots |
| `/var/run/casaos/message-bus.url` | the TCP address the gateway and other services read |
| `/tmp/message-bus.sock` | the unix socket, same API |
| `/var/run/casaos/message-bus.sock` | the unix socket, same API; root only |
| `/var/log/casaos/message-bus.log` | log |

The service picks a free loopback port at start, registers `/v2/message_bus` and `/doc/v2/message_bus` with the gateway, and writes its address to the file above. The API specification is [`api/message_bus/openapi.yaml`](api/message_bus/openapi.yaml), also served at `/doc/v2/message_bus`.
Expand All @@ -51,6 +51,8 @@ What a release contains, and how it is built, is described in [CasaOS-Install](h

**The access log no longer records host-side event publishes.** casaos's 5-second telemetry produced one JSON access-log line per publish, which systemd hands to journald: about 17 000 lines a day that buried every real request. The telemetry rate is unchanged — it is the dashboard's only realtime feed — and the log line is skipped instead. The skip is narrow: POST on the event publish route, and only from the unix socket or a loopback peer. Websocket subscribes, event-type registrations, actions and anything from the LAN stay logged ([CasaOS #2211](https://github.com/IceWhaleTech/CasaOS/issues/2211)).

**Subscriptions need a credential, and the unix socket left `/tmp`.** Upstream let any websocket upgrade on the subscribe routes through without a token, so whoever reached the dashboard's port could read every event; a subscription now needs a user JWT (header or `?token=`) or the internal secret. The socket moved out of `/tmp`, where any local user could take its name first and keep the bus from listening, to the runtime directory, which only root can write.

**The Go module is now `github.com/ReCasaOS/CasaOS-MessageBus`, built against `github.com/ReCasaOS/CasaOS-Common`,** so log lines, stack traces and `go version -m` on the shipped binary name the fork that ships them rather than upstream.

Packaging changed too, without touching the service: the release workflow builds and publishes the tarballs here instead of calling upstream's pipeline, which needed credentials this fork does not have and so never produced a release.
Expand Down
26 changes: 26 additions & 0 deletions api/message_bus/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ paths:

> `names` can be specified in the query string to subscribe to specific event types.
operationId: subscribeEventWS
security:
- access_token: []
- access_token_query: []
tags:
- WebSocket Endpoints
parameters:
Expand Down Expand Up @@ -278,6 +281,9 @@ paths:

> `names` can be specified in the query string to subscribe to specific action types.
operationId: subscribeActionWS
security:
- access_token: []
- access_token_query: []
tags:
- WebSocket Endpoints
parameters:
Expand All @@ -297,6 +303,9 @@ paths:
- SocketIO `room` should be either `event` or `action`

operationId: subscribeSIO
security:
- access_token: []
- access_token_query: []
tags:
- SocketIO Endpoints
responses:
Expand All @@ -312,6 +321,9 @@ paths:
description: |
Poll events and actions by via SocketIO.
operationId: pollSIO
security:
- access_token: []
- access_token_query: []
tags:
- SocketIO Endpoints
responses:
Expand All @@ -325,6 +337,9 @@ paths:
description: |
> Same as `/socket.io` except it comes with a trailing slash `/` - a workaround to maximize compatibility
operationId: subscribeSIO2
security:
- access_token: []
- access_token_query: []
responses:
"101":
description: |
Expand All @@ -338,6 +353,9 @@ paths:
description: |
> Same as `/socket.io` except it comes with a trailing slash `/` - a workaround to maximize compatibility
operationId: pollSIO2
security:
- access_token: []
- access_token_query: []
responses:
"200":
description: |
Expand Down Expand Up @@ -380,6 +398,14 @@ components:
type: apiKey
in: header
name: Authorization
description: |
A CasaOS user JWT. This box's own services send `Internal <secret>` instead, from loopback, with the per-boot secret the gateway writes to `/var/run/casaos/internal.secret`; requests on the unix socket need neither.
access_token_query:
type: apiKey
in: query
name: token
description: |
The same user JWT, in the query string, because browsers cannot set headers on a WebSocket. Read on the subscription routes only (the WebSocket and socket.io endpoints) and ignored everywhere else.

parameters:
SourceID:
Expand Down
128 changes: 73 additions & 55 deletions codegen/message_bus_api.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.26.8

require (
github.com/CorrectRoadH/go-socket.io v1.8.0-rc.5
github.com/ReCasaOS/CasaOS-Common v0.4.26
github.com/ReCasaOS/CasaOS-Common v0.4.27
github.com/glebarez/sqlite v1.7.0
github.com/gobwas/ws v1.1.0
github.com/json-iterator/go v1.1.12
Expand Down
Loading
Loading