Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
a94048d
@
pgodwin Jun 4, 2026
62f339a
@
pgodwin Jun 4, 2026
9b6bf8b
@
pgodwin Jun 4, 2026
25c09fb
@
pgodwin Jun 4, 2026
d1d8649
@
pgodwin Jun 4, 2026
8befa04
@
pgodwin Jun 4, 2026
b0211d0
@
pgodwin Jun 4, 2026
c33a705
webui: add live log viewer (ring buffer + SSE)
pgodwin Jun 4, 2026
4f73678
webui: daemon/service wrappers, restart-safe lifecycle, and config ed…
pgodwin Jun 5, 2026
77b29c0
webui: add MacIP lease diagnostics and live dashboard state
pgodwin Jun 5, 2026
a7606d8
webui: add log download and friendly Windows serial-port labels
pgodwin Jun 5, 2026
73aaf0d
webui: add an editor for the AFP extension map (type/creator conf)
pgodwin Jun 5, 2026
a23444b
webui: config editor for remaining MacIP options and MacIPX gateway
pgodwin Jun 5, 2026
b76d387
control: make AFP/MacIP/IPXGW individually start/stoppable from the UI
pgodwin Jun 5, 2026
3391100
webui: live per-port throughput on the dashboard
pgodwin Jun 5, 2026
398f7f6
webui: meter IPX and NetBEUI port throughput too
pgodwin Jun 5, 2026
fcf0c96
ci: fix golangci-lint failures on the web UI branch
pgodwin Jun 5, 2026
cdbf596
deps: bump Go to 1.25.11 and x/net to v0.55.0 to clear govulncheck CVEs
pgodwin Jun 5, 2026
1f5447d
ci: run the same vet/govulncheck/gosec gates locally; clear gosec fin…
pgodwin Jun 5, 2026
609b54c
webui: surface routing table and dynamic routing in the management plane
pgodwin Jun 7, 2026
f709087
Update readme.
pgodwin Jun 7, 2026
1d3b70a
Add GNU General Public License v3
pgodwin Jun 7, 2026
93420dd
Add AI warning shield
pgodwin Jun 7, 2026
b80ba12
Merge branch 'feat-webui' of https://github.com/ObsoleteMadness/OmniT…
pgodwin Jun 7, 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
22 changes: 10 additions & 12 deletions .github/workflows/pr-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,27 +48,25 @@ jobs:
sudo apt-get update
sudo apt-get install -y libpcap-dev

- name: go vet
run: go vet ./...

- name: Race-enabled tests
run: go test -tags all -race -count=1 ./...

# golangci-lint runs via its dedicated action (caching, problem matchers)
# rather than from quality.sh, so it can hook into the GitHub UI; the
# script tolerates it being absent so a local run still covers vet/vuln/
# gosec. The vet + govulncheck + gosec gates are shared with local
# development via scripts/ci/quality.sh / `make quality`.
- name: golangci-lint
uses: golangci/golangci-lint-action@v8
with:
version: latest
args: --build-tags=all

- name: govulncheck
run: |
go install golang.org/x/vuln/cmd/govulncheck@latest
govulncheck -tags all ./...

- name: gosec (untrusted-input paths)
run: |
go install github.com/securego/gosec/v2/cmd/gosec@latest
gosec -tags all ./service/macip/... ./service/macgarden/... ./service/afpfs/macgarden/...
- name: Quality gates (vet + govulncheck + gosec)
shell: bash
env:
SKIP_LINT: "1" # golangci-lint already ran via its action above
run: bash scripts/ci/quality.sh

build-tags:
name: Build-tag matrix
Expand Down
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
*.so
*.dylib

# Locally built command binaries (extensionless on Unix)
/classicstack
/classicstackd

# Test binary, built with `go test -c`
*.test

Expand Down Expand Up @@ -44,3 +48,5 @@ go.work.sum
.captures/
captures/

server.toml.[0-9]*

21 changes: 19 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ go test ./service/afp/...
### Core Data Flow

```
cmd/classicstack/main.go → Ports → Router → Services
cmd/classicstack/main.go → internal/app (run-core) → Ports → Router → Services
```

1. **Entry point** (`cmd/classicstack/`) parses CLI flags and `server.toml`, constructs ports, wires them to the router, and starts services.
1. **Entry point** (`cmd/classicstack/`) is a thin `main()` that calls `internal/app`, which parses CLI flags and `server.toml`, constructs ports, wires them to the router, and starts services. Two sibling commands wrap the same run-core for background operation: `cmd/classicstack-svc` (Windows service) and `cmd/classicstackd` (Unix/macOS daemon).
2. **Router** (`router/`) receives DDP datagrams from all ports, maintains the `RoutingTable` and `ZoneInformationTable`, and dispatches to services by socket number or forwards to other ports.
3. **Ports** (`port/`) abstract network interfaces. All implement `port.Port` (Unicast/Broadcast/Multicast). Implementations: `ethertalk`, `localtalk/ltoudp`, `localtalk/tashtalk`, `localtalk/virtual`.
4. **Services** (`service/`) plug into the router by registering socket numbers. Each implements `service.Service`.
Expand All @@ -58,6 +58,10 @@ cmd/classicstack/main.go → Ports → Router → Services

| Package | Role |
|---|---|
| `internal/app/` | The run-core (formerly `cmd/classicstack` package `main`): flag/TOML parsing, the `Supervisor`, every `wireXxx` hook, control-plane + web UI wiring. Exposes `Main(Version)` and `Run(ctx, args, Version)` so the interactive binary and the service/daemon wrappers all share one runtime. |
| `cmd/classicstack/` | Thin interactive entry point (`main()` → `app.Main`); holds the link-time `Build*` vars (`-ldflags -X main.Build...`). |
| `cmd/classicstack-svc/` | Windows service wrapper (SCM via `golang.org/x/sys/windows/svc`); `install`/`uninstall`/`start`/`stop`/`status`/`run`. Stub on non-Windows. |
| `cmd/classicstackd/` | Unix/macOS background daemon (self-daemonize via fork+`Setsid`, PID file); `start`/`stop`/`status`/`run`, plus macOS LaunchAgent `install`/`uninstall`. Stub on Windows. |
| `appletalk/` | DDP datagram struct, encode/decode, MacRoman codec |
| `router/` | Core routing engine, routing table aging, zone info |
| `port/ethertalk/` | EtherTalk over raw Ethernet using libpcap/Npcap, includes AARP |
Expand All @@ -69,8 +73,21 @@ cmd/classicstack/main.go → Ports → Router → Services
| `service/atp/` | AppleTalk Transaction Protocol — reliable messaging |
| `service/dsi/` | Data Stream Interface — AFP transport over TCP |
| `service/macip/` | IP-over-AppleTalk gateway with NAT and DHCP relay |
| `service/webui/` | Management web UI (`-tags webui`): HTTPS adapter over `pkg/control` — JSON API, SSE stats stream, embedded SPA |
| `pkg/control/` | Transport-agnostic management API (status, config stage/apply/save, service start/stop/restart, diagnostics); the single contract every UI front-end shares |
| `pkg/status/` | In-process service-status registry read by the dashboard |
| `pkg/metrics/` | Streaming stats hub (expvar + SSE sinks) |
| `pkg/logbuf/` | In-memory log ring buffer + `slog.Handler` + broadcaster feeding the web UI log viewer (installed via `logging.Options.Extra`) |
| `pkg/serialport/` | Per-OS serial-port enumeration for the TashTalk dropdown |
| `config/` | Config loader plus `Model` (in-memory, editable, serialisable view of `server.toml` with numbered-backup Save) |
| `netlog/` | Structured logger with debug/info/warn levels |

The `cmd/classicstack` `Supervisor` owns the whole runtime: it builds ports, the
router (and its DDP service set), and the standalone hooks from the config
`Model`, and exposes per-service Start/Stop/Restart (dependency-aware) that the
web UI drives through `pkg/control`. `main.go` only parses flags / loads TOML,
builds the `Model`, and hands off to the supervisor.

### AFP Architecture

AFP supports two transport stacks simultaneously:
Expand Down
Loading
Loading